Skip to content

Commit

Permalink
Merge pull request #6 from cfoust/caleb/04-07-24/feat/docathon
Browse files Browse the repository at this point in the history
Docathon: lots of new documentation
  • Loading branch information
cfoust authored Jul 7, 2024
2 parents fef9cec + bdc2dc7 commit abe3126
Show file tree
Hide file tree
Showing 31 changed files with 579 additions and 88 deletions.
16 changes: 16 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,19 @@ jobs:

- name: Test
run: go test -v ./pkg/... ./cmd/...

- name: Install latest mdbook
run: |
tag=$(curl 'https://api.github.com/repos/rust-lang/mdbook/releases/latest' | jq -r '.tag_name')
url="https://github.com/rust-lang/mdbook/releases/download/${tag}/mdbook-${tag}-x86_64-unknown-linux-gnu.tar.gz"
mkdir mdbook
curl -sSL $url | tar -xz --directory=./mdbook
echo `pwd`/mdbook >> $GITHUB_PATH
- name: Build book
run: |
cd docs
# Building all of the assets for the docs site takes a while; we only
# build it on release. This is just to verify that this PR/commit did
# not break any documentation.
CY_SKIP_ASSETS=1 mdbook build
29 changes: 29 additions & 0 deletions cmd/stories/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,35 @@ func main() {
}(animation)
}

// A stories story
stories.Register(
"stories",
func(ctx context.Context) (mux.Screen, error) {
return ui.New(ctx, CLI.Prefix)
},
stories.Config{
Input: []interface{}{
stories.Type("ctrl+j"),
stories.Wait(stories.Some),
stories.Type("ctrl+j"),
stories.Wait(stories.Some),
stories.Type("ctrl+k"),
stories.Wait(stories.Some),
stories.Type("ctrl+k"),
stories.Wait(stories.Some),
stories.Type("input"),
stories.Type("ctrl+j"),
stories.Wait(stories.Some),
stories.Type("ctrl+j"),
stories.Wait(stories.Some),
stories.Type("ctrl+k"),
stories.Wait(stories.Some),
stories.Type("ctrl+k"),
stories.Wait(stories.Some),
},
},
)

haveCast := len(CLI.Cast) > 0
if len(CLI.Single) == 0 && haveCast {
panic(fmt.Errorf("to use --cast, you must provide a single story"))
Expand Down
4 changes: 2 additions & 2 deletions docs/book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ description = "A next-generation terminal multiplexer that records everything yo
authors = ["Caleb Foust"]

[output.html]
default-theme = "navy"
preferred-dark-theme = "navy"
default-theme = "ayu"
preferred-dark-theme = "ayu"
site-url = "/cy/"
git-repository-url = "https://github.com/cfoust/cy"
additional-css = ["./theme/asciinema-player.css"]
Expand Down
279 changes: 203 additions & 76 deletions docs/gendoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@
import argparse
import sys
from pathlib import Path
from typing import NamedTuple, Optional, Tuple, List, Any, Set

GENDOC_REGEX = re.compile("{{gendoc (.+)}}")
KEYS_REGEX = re.compile(r"{{keys (.+)}}")
API_REGEX = re.compile(r"{{api ([a-z0-9/-]+)}}")
from typing import (
NamedTuple,
Optional,
Tuple,
Dict,
List,
Any,
Set,
Callable,
)


class Symbol(NamedTuple):
Expand Down Expand Up @@ -157,6 +162,173 @@ def render_keys(bindings: List[Binding], args: List[str]) -> str:

return output

Error = Tuple[int, str]
Transformer = Callable[[str],Tuple[str, List[Error]]]
Replacement = Tuple[int, int, str]


def handle_pattern(
pattern: re.Pattern,
handler: Callable[
[re.Match],
Tuple[Optional[Replacement], Optional[Error]],
],
) -> Transformer:
"""
Given a regex pattern `pattern` and a function `handler` that turns matches
into in-text replacements, return a Transformer.
"""

def transform(content: str) -> Tuple[str, List[Error]]:
replace: List[Replacement] = []
errors: List[Error] = []

for match in pattern.finditer(content):
replacement, error = handler(match)
if not replacement:
if error: errors.append(error)
continue

replace.append(replacement)

replace = sorted(replace, key=lambda a: a[1])

for start, end, text in reversed(replace):
content = content[:start] + text + content[end:]

return content, errors

return transform


def transform_gendoc(
frames: List[str],
animations: List[str],
symbols: List[Symbol],
) -> Transformer:
def handler(match: re.Match) -> Tuple[
Optional[Replacement],
Optional[Error],
]:
command = match.group(1)
if len(command) == 0:
return None, None

output = ""
if command == "frames":
output = render_frames(frames)
elif command == "animations":
output = render_animations(animations)
elif command == "api":
output = render_api(symbols)

return (
match.start(0),
match.end(0),
output,
), None

return handle_pattern(re.compile("{{gendoc (.+)}}"), handler)


def transform_keys(
bindings: List[Binding],
) -> Transformer:
def handler(match: re.Match) -> Tuple[
Optional[Replacement],
Optional[Error],
]:
args = match.group(1)
if len(args) == 0:
return None, None

return (
match.start(0),
match.end(0),
render_keys(
bindings,
args.split(" "),
),
), None

return handle_pattern(re.compile(r"{{keys (.+)}}"), handler)


def transform_api(
symbol_lookup: Dict[str, Symbol],
) -> Transformer:
def handler(match: re.Match) -> Tuple[
Optional[Replacement],
Optional[Error],
]:
name = match.group(1)
if len(name) == 0:
return None, None

if not name in symbol_lookup:
return None, (
match.start(0),
f"missing symbol: {name}",
)

symbol = symbol_lookup[name]

return (
match.start(0),
match.end(0),
render_symbol_link(symbol),
), None

return handle_pattern(re.compile(r"{{api ([a-z0-9/-]+)}}"), handler)


def transform_packages() -> Transformer:
pkg_dir = os.path.join(os.path.dirname(__file__), "..", "pkg")

packages: List[Tuple[str, str]] = []

for dir, _, _ in os.walk(pkg_dir):
relative = os.path.relpath(dir, start=pkg_dir)
readme = os.path.join(dir, "README.md")
if not os.path.exists(readme): continue

with open(readme, 'r') as f:
packages.append((
relative,
f.read(),
))

packages = sorted(
packages,
key=lambda a: a[0],
)

docs = ""

for name, readme in packages:
lines = readme.split("\n")
# Skip the first line, usually #
lines = lines[1:]
# Increase header level
lines = list(map(
lambda line: "#" + line if line.startswith("#") else line,
lines,
))
readme = "\n".join(lines)
docs += f"""## {name}
[source](https://github.com/cfoust/cy/tree/main/pkg/{name})
{readme}"""

def handler(match: re.Match) -> Tuple[
Optional[Replacement],
Optional[Error],
]:
return (match.start(0), match.end(0), docs,), None

return handle_pattern(re.compile(r"{{packages}}"), handler)


if __name__ == '__main__':
args = sys.argv
Expand Down Expand Up @@ -187,81 +359,36 @@ def render_keys(bindings: List[Binding], args: List[str]) -> str:
binding['Function'] = symbol_lookup[func]
bindings.append(Binding(**binding))

errors: int = 0
def report_error(chapter, start, end, msg):
global errors
errors += 1
print(f"{chapter['name']}:{start}{end}: {msg}", file=sys.stderr)

def transform_chapter(chapter) -> None:
replace = []

content = chapter['content']
transformers: List[Transformer] = [
transform_packages(),
transform_keys(bindings),
transform_gendoc(
api['Frames'],
api['Animations'],
symbols,
),
transform_api(symbol_lookup),
]

for ref in GENDOC_REGEX.finditer(content):
command = ref.group(1)
if len(command) == 0:
continue
num_errors: int = 0

output = ""
if command == "frames":
output = render_frames(api['Frames'])
elif command == "animations":
output = render_animations(api['Animations'])
elif command == "api":
output = render_api(symbols)

replace.append(
(
ref.start(0),
ref.end(0),
output,
)
)

for ref in API_REGEX.finditer(content):
name = ref.group(1)
if len(name) == 0:
continue
def transform_chapter(chapter) -> None:
global num_errors
content: str = chapter['content']

if not name in symbol_lookup:
report_error(
chapter,
ref.start(0),
ref.end(0),
f"missing symbol: {name}",
)
continue
for transform in transformers:
content, errors = transform(content)

symbol = symbol_lookup[name]
for index, message in errors:
num_errors += 1
# not accurate since other transformers may have changed this,
# but whatever
line = len(content[:index].split("\n"))

replace.append(
(
ref.start(0),
ref.end(0),
render_symbol_link(symbol),
print(
f"{chapter['name']}:{line}: {message}",
file=sys.stderr,
)
)

for ref in KEYS_REGEX.finditer(content):
args = ref.group(1)
if len(args) == 0:
continue

replace.append(
(
ref.start(0),
ref.end(0),
render_keys(
bindings,
args.split(" "),
),
)
)

replace = sorted(replace, key=lambda a: a[1])
for start, end, text in reversed(replace):
content = content[:start] + text + content[end:]

chapter['content'] = content

Expand All @@ -277,8 +404,8 @@ def transform_chapter(chapter) -> None:

transform_chapter(section['Chapter'])

if errors > 0:
print(f"{errors} error(s) while preprocessing")
if num_errors > 0:
print(f"{num_errors} error(s) while preprocessing", file=sys.stderr)
exit(1)

print(json.dumps(book))
10 changes: 10 additions & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@

- [API](./api.md)

# Developer guide

- [Architecture](./architecture.md)

- [Packages](./packages.md)

- [Stories](./stories.md)

- [Documentation site](./documentation.md)

---

[Acknowledgments](./acknowledgments.md)
Loading

0 comments on commit abe3126

Please sign in to comment.