-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Create new screencast automatically on docs build #339
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
15a989a
Create new screencast automatically on docs build
pjbull 0bf008f
dev reqs
pjbull 12deb90
Remove tree from replay
pjbull b973f0f
Update docs/scripts/generate-termynal.py
pjbull eafed9c
Update docs/scripts/generate-termynal.py
pjbull 255e0e9
Apply suggestions from code review
pjbull 22178ff
Apply suggestions from code review
pjbull File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,17 @@ | ||
| -e . | ||
|
|
||
| ansi2html | ||
| black | ||
| chardet | ||
| flake8 | ||
| isort | ||
| mkdocs | ||
| mkdocs-cinder | ||
| mkdocs-gen-files | ||
| mkdocs-include-markdown-plugin | ||
| pexpect | ||
| pipenv | ||
| pytest | ||
| termynal | ||
| virtualenvwrapper; sys_platform != 'win32' | ||
| virtualenvwrapper-win; sys_platform == 'win32' |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,24 @@ | ||
| h1, h2, h3 { | ||
| margin-top: 77px; | ||
| } | ||
|
|
||
| #termynal { | ||
| height: 80ex !important; /* 40 lines of 2ex */ | ||
| min-height: 80ex !important; | ||
| max-height: 80ex !important; | ||
| overflow: scroll !important; | ||
| font-size: 1.5ex !important; | ||
| } | ||
|
|
||
| [data-ty] { | ||
| line-height: 2ex !important; | ||
| white-space: pre; | ||
| } | ||
pjbull marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| .newline { | ||
| line-height: 0 !important; | ||
| } | ||
|
|
||
pjbull marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| .inline-input, .default-text { | ||
| display: inline-block !important; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| /* Smooth scrolling for termynal replay */ | ||
|
|
||
| function scrollToBottomOfContainer(container, element) { | ||
| var positionToScroll = element.offsetTop + element.offsetHeight - container.offsetHeight; | ||
| container.scrollTo({ | ||
| top: positionToScroll, | ||
| behavior: 'smooth' | ||
| }); | ||
| } | ||
|
|
||
| // Select the node that will be observed for mutations | ||
| const targetNode = document.getElementById("termynal"); | ||
|
|
||
| // Options for the observer (which mutations to observe) | ||
| const config = { attributes: false, childList: true, subtree: false }; | ||
|
|
||
| // Callback function to execute when mutations are observed | ||
| const callback = (mutationList, observer) => { | ||
| for (const mutation of mutationList) { | ||
| scrollToBottomOfContainer(targetNode, mutation.target); | ||
| } | ||
| }; | ||
|
|
||
| // Create an observer instance linked to the callback function | ||
| const observer = new MutationObserver(callback); | ||
|
|
||
| // Start observing the target node for configured mutations | ||
| observer.observe(targetNode, config); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| import shutil | ||
| from pathlib import Path | ||
|
|
||
| import pexpect | ||
| from ansi2html import Ansi2HTMLConverter | ||
|
|
||
| CCDS_ROOT = Path(__file__).parents[2].resolve() | ||
|
|
||
|
|
||
| def execute_command_and_get_output(command, input_script): | ||
| input_script = iter(input_script) | ||
| child = pexpect.spawn(command, encoding="utf-8") | ||
|
|
||
| interaction_history = [f"$ {command}\n"] | ||
|
|
||
| prompt, user_input = next(input_script) | ||
|
|
||
| try: | ||
| while True: | ||
| index = child.expect([prompt, pexpect.EOF, pexpect.TIMEOUT]) | ||
|
|
||
| if index == 0: | ||
| output = child.before + child.after | ||
| interaction_history += [line.strip() for line in output.splitlines()] | ||
|
|
||
| child.sendline(user_input) | ||
|
|
||
| try: | ||
| prompt, user_input = next(input_script) | ||
| except StopIteration: | ||
| pass | ||
|
|
||
| elif index == 1: # The subprocess has exited. | ||
| output = child.before | ||
| interaction_history += [line.strip() for line in output.splitlines()] | ||
| break | ||
| elif index == 2: # Timeout waiting for new data. | ||
| print("\nTimeout waiting for subprocess response.") | ||
| continue | ||
|
|
||
| finally: | ||
| return interaction_history | ||
|
|
||
|
|
||
| ccds_script = [ | ||
| ("project_name", "My Analysis"), | ||
| ("repo_name", "my_analysis"), | ||
| ("module_name", ""), | ||
| ("author_name", "Dat A. Scientist"), | ||
| ("description", "This is my analysis of the data."), | ||
| ("python_version_number", "3.12"), | ||
| ("Choose from", "3"), | ||
| ("bucket", "s3://my-aws-bucket"), | ||
| ("aws_profile", ""), | ||
| ("Choose from", "2"), | ||
| ("Choose from", "1"), | ||
| ("Choose from", "2"), | ||
| ("Choose from", "2"), | ||
| ("Choose from", "1"), | ||
| ] | ||
|
|
||
|
|
||
| def run_scripts(): | ||
| try: | ||
| output = [] | ||
| output += execute_command_and_get_output(f"ccds {CCDS_ROOT}", ccds_script) | ||
| return output | ||
|
|
||
| finally: | ||
| # always cleanup | ||
| if Path("my_analysis").exists(): | ||
| shutil.rmtree("my_analysis") | ||
|
|
||
|
|
||
| def render_termynal(): | ||
| # actually execute the scripts and capture the output | ||
| results = run_scripts() | ||
|
|
||
| # watch for inputs and format them differently | ||
| script = iter(ccds_script) | ||
| _, user_input = next(script) | ||
|
|
||
| conv = Ansi2HTMLConverter(inline=True) | ||
| html_lines = [ | ||
| '<div id="termynal" data-termynal class="termy" data-ty-macos data-ty-lineDelay="100" data-ty-typeDelay="50" title="Cookiecutter Data Science">' | ||
| ] | ||
| result_collector = [] | ||
|
|
||
pjbull marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| for line_ix, result in enumerate(results): | ||
| # style bash user inputs | ||
| if result.startswith("$"): | ||
| result = conv.convert(result.strip("$"), full=False) | ||
| html_lines.append( | ||
| f'<span data-ty="input" data-ty-prompt="$">{result}</span>' | ||
| ) | ||
|
|
||
| # style inline cookiecutter user inputs | ||
| elif ":" in result and user_input in result: | ||
| # treat all the options that were output as a single block | ||
| if len(result_collector) > 1: | ||
| prev_results = conv.convert( | ||
| "\n".join(result_collector[:-1]), full=False | ||
| ) | ||
| html_lines.append(f"<span data-ty>{prev_results}</span>") | ||
|
|
||
| # split the line up into the prompt text with options, the default, and the user input | ||
| prompt, user_input = result.strip().split(":", 1) | ||
| prompt = conv.convert(prompt, full=False) | ||
| prompt = f'<span data-ty class="inline-input">{result_collector[-1].strip()} {prompt}:</span>' | ||
| user_input = conv.convert(user_input.strip(), full=False) | ||
|
|
||
| # treat the cookiecutter prompt as a shell prompt | ||
| out_line = f"{prompt}" | ||
pjbull marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| out_line += f'<span class="inline-input" data-ty="input" data-ty-delay="500" data-ty-prompt="">{user_input}</span>' | ||
| html_lines.append(out_line) | ||
| html_lines.append('<span data-ty class="newline"></span>') | ||
| result_collector = [] | ||
|
|
||
pjbull marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| try: | ||
| _, user_input = next(script) | ||
| except StopIteration: | ||
| user_input = "STOP ITER" # never true so we just capture the remaining rows after the script | ||
|
|
||
| # collect all the other lines for a single output | ||
| else: | ||
| result_collector.append(result) | ||
|
|
||
| html_lines.append("</div>") | ||
| output = "\n".join(html_lines) | ||
|
|
||
| # replace local directory in ccds call with URL so it can be used for documentation | ||
| output = output.replace( | ||
| str(CCDS_ROOT), "https://github.com/drivendata/cookiecutter-data-science" | ||
| ) | ||
| return output | ||
|
|
||
|
|
||
| # script entry point for debugging | ||
| if __name__ == "__main__": | ||
| print(render_termynal()) | ||
|
|
||
| # mkdocs build entry point | ||
| else: | ||
| import mkdocs_gen_files | ||
|
|
||
| with mkdocs_gen_files.open( | ||
| Path(CCDS_ROOT / "docs" / "docs" / "_partials" / "termynal.md"), "w" | ||
| ) as f: | ||
| f.write(render_termynal()) | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.