diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 2549ba9a1..98b24cd90 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - screen-recording-2026-07-12 # [DO NOT MERGE] temporary docs preview workflow_dispatch: permissions: @@ -30,6 +31,7 @@ jobs: - README.* docs: - 'docs/**' + - 'docs/_static/demos/asciinema/*.gif' - 'examples/**' python_files: - 'src/vcspull/**' @@ -37,7 +39,8 @@ jobs: - uv.lock - name: Should publish - if: github.event_name == 'workflow_dispatch' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.root_docs == 'true' || steps.changes.outputs.python_files == 'true' + # [DO NOT MERGE] force publish on the preview branch regardless of changed paths + if: github.ref == 'refs/heads/screen-recording-2026-07-12' || github.event_name == 'workflow_dispatch' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.root_docs == 'true' || steps.changes.outputs.python_files == 'true' run: echo "PUBLISH=$(echo true)" >> $GITHUB_ENV - name: Install uv diff --git a/README.md b/README.md index bc21d3f7a..bc56fb877 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ See the [documentation](https://vcspull.git-pull.com/), [configuration](https:// [myrepos]: http://myrepos.branchable.com/ [mu-repo]: http://fabioz.github.io/mu-repo/ +vcspull sync cloning a workspace of repositories + # How to ## Install @@ -109,6 +111,8 @@ $ vcspull add ~/projects/libs/my-lib yourself instead of having vcspull merge them automatically. - Follow with `vcspull sync my-lib` to clone or update the working tree after registration. +vcspull add registering a repository from its checkout + ### Discover local checkouts and add en masse Have a directory tree full of cloned Git repositories? Scan and append them to @@ -123,6 +127,8 @@ The scan shows each repository before import unless you opt into `--yes`. Add than the default `~/.vcspull.yaml`. Duplicate workspace roots are merged by default; include `--no-merge` to keep them separate while you review the log. +vcspull discover scanning a directory tree for repositories + ### Import from remote services Pull repository lists from GitHub, GitLab, Codeberg, Gitea, Forgejo, or AWS @@ -158,6 +164,8 @@ $ vcspull list --json | jq '.[].name' `--json` emits a single JSON array, while `--ndjson` streams newline-delimited objects that are easy to consume from shell pipelines. +vcspull list showing configured repositories + Search across repositories with an rg-like query syntax: ```console @@ -166,6 +174,8 @@ $ vcspull search name:django url:github $ vcspull search --fixed-strings 'git+https://github.com/org/repo.git' ``` +vcspull search narrowing a set of repositories to matches + ### Check repository status Get a quick health check for all configured workspaces: @@ -176,6 +186,8 @@ $ vcspull status --detailed $ vcspull status --ndjson | jq --slurp 'map(select(.reason == "summary"))' ``` +vcspull status reporting clean, dirty, and missing repositories + The status command respects `--workspace/-w` filters and the global `--color {auto,always,never}` flag. JSON and NDJSON output mirrors the list command for automation workflows. @@ -285,8 +297,6 @@ $ vcspull sync "$HOME/code/*" [libvcs]: https://github.com/vcs-python/libvcs -image - # Donations Your donations fund development of new features, testing and support. diff --git a/docs/AGENTS.md b/docs/AGENTS.md index 1f187d270..562218946 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -86,6 +86,39 @@ Two mechanical conventions, separate from voice: `.. automodule::`. Introduce them in prose; never paraphrase their content into sentences that will drift. +## Demo recordings + +The animated demos under `docs/_static/demos/asciinema/*.gif` — embedded +in the CLI pages, the homepage, and the README — come from the +`/screen-record` skill: asciinema casts rendered to GIF with `agg`, with +VHS tapes producing the MP4/WebM alternates. `setup-sandbox.sh`, committed +beside them, rebuilds the config and repositories every recording drives +against, so re-render from it rather than hand-editing a frame. + +One post-step the skill does not do: **crop each shipped GIF to its +content.** `agg` and VHS render the full terminal width, but a command's +output fills only part of it, leaving a wide horizontal band of dead space +that makes the demo read small once embedded. ffmpeg `cropdetect`, +ImageMagick `TrimBounds`, and `cropdetect=mode=mvedges` all fail on a +non-black, full-frame terminal capture — the background sits above the +black threshold, so every frame reads as content and nothing is trimmed. +The approach that holds is an ImageMagick union-trim that pads with the +terminal's *own* background: + +```console +$ magick demo.gif -coalesce -fuzz 4% -trim +repage \ + -bordercolor "$(magick demo.gif[0] -format '%[pixel:p{0,0}]' info:)" \ + -border 10 \ + -layers Optimize \ + demo-cropped.gif +``` + +`-fuzz 4% -trim` crops to the content bounding box. Sampling the pad colour +from the GIF's own corner pixel — the terminal background — makes the 10px +margin bit-identical to the terminal, so it reads as breathing room rather +than a frame. Each crop adapts to its command: wide output stays wide, +short output tightens, and `-layers Optimize` keeps the file small. + ## Cross-references Point the advanced reader at the deep-dive rather than inlining it, diff --git a/docs/_ext/aspect_ratio.py b/docs/_ext/aspect_ratio.py new file mode 100644 index 000000000..a6fd68800 --- /dev/null +++ b/docs/_ext/aspect_ratio.py @@ -0,0 +1,65 @@ +"""Reserve demo image space via aspect-ratio so pages don't shift on load (CLS). + +Sphinx's HTML writer renders image ``:width:`` as an inline pixel style, which +overrides the theme's ``height: auto`` and distorts responsive images. Instead +this stamps each demo ```` with ``width:px; max-width:100%; +aspect-ratio:W/H`` (computed from the source GIF): the gif shows at its real +size, shrinks on a narrow screen, never scales up, and the browser reserves the +correct box before it loads (no layout shift). +""" + +from __future__ import annotations + +import re +import typing as t +from pathlib import Path + +from sphinx.util.images import get_image_size + +if t.TYPE_CHECKING: + from docutils import nodes + from sphinx.application import Sphinx + +_IMG = re.compile(r']*?\bsrc="[^"]+?/([^"/]+?\.gif)"[^>]*?/?>') +_STYLE = re.compile(r'style="[^"]*"') +_sizes: dict[str, tuple[int, int]] = {} + + +def _index_sizes(app: Sphinx) -> None: + """Map each source GIF's basename to its intrinsic ``(width, height)``.""" + for path in Path(app.srcdir).rglob("*.gif"): + size = get_image_size(path) + if size is not None: + _sizes[path.name] = size + + +def _inject( + app: Sphinx, + pagename: str, + templatename: str, + context: dict[str, t.Any], + doctree: nodes.document | None, +) -> None: + """Rewrite demo ```` tags to carry ``width:100%; aspect-ratio:W/H``.""" + body = context.get("body") + if not body or "_images/" not in body: + return + + def repl(match: re.Match[str]) -> str: + tag, name = match.group(0), match.group(1) + size = _sizes.get(name) + if size is None or "aspect-ratio" in tag: + return tag + style = f"width:{size[0]}px;max-width:100%;aspect-ratio:{size[0]}/{size[1]}" + if 'style="' in tag: + return _STYLE.sub(f'style="{style}"', tag) + return tag[:-1].rstrip("/") + f' style="{style}" />' + + context["body"] = _IMG.sub(repl, body) + + +def setup(app: Sphinx) -> dict[str, t.Any]: + """Register the aspect-ratio injector.""" + app.connect("builder-inited", _index_sizes) + app.connect("html-page-context", _inject) + return {"parallel_read_safe": True, "parallel_write_safe": True} diff --git a/docs/_static/demos/asciinema/vcspull-add.cast b/docs/_static/demos/asciinema/vcspull-add.cast new file mode 100644 index 000000000..b1f26ab8c --- /dev/null +++ b/docs/_static/demos/asciinema/vcspull-add.cast @@ -0,0 +1,43 @@ +{"version":3,"term":{"cols":120,"rows":9},"timestamp":1783863920,"idle_time_limit":1.0,"command":"vcspull add ~/code/rust/ripgrep -y; sleep 2","title":"vcspull add","env":{"SHELL":"/bin/zsh"}} +[0.15,"o","\u001b[34m$\u001b[0m "] +[0.05,"o","v"] +[0.05,"o","c"] +[0.05,"o","s"] +[0.05,"o","p"] +[0.05,"o","u"] +[0.05,"o","l"] +[0.05,"o","l"] +[0.05,"o"," "] +[0.05,"o","a"] +[0.05,"o","d"] +[0.05,"o","d"] +[0.05,"o"," "] +[0.05,"o","~"] +[0.05,"o","/"] +[0.05,"o","c"] +[0.05,"o","o"] +[0.05,"o","d"] +[0.05,"o","e"] +[0.05,"o","/"] +[0.05,"o","r"] +[0.05,"o","u"] +[0.05,"o","s"] +[0.05,"o","t"] +[0.05,"o","/"] +[0.05,"o","r"] +[0.05,"o","i"] +[0.05,"o","p"] +[0.05,"o","g"] +[0.05,"o","r"] +[0.05,"o","e"] +[0.05,"o","p"] +[0.05,"o"," "] +[0.05,"o","-"] +[0.05,"o","y"] +[0.20,"o","\r\n"] +[0.121,"o","\u001b[32mFound new repository to import:\u001b[0m\r\n \u001b[32m+\u001b[0m \u001b[36mripgrep\u001b[0m (\u001b[33mhttps://github.com/BurntSushi/ripgrep.git\u001b[0m)\r\n \u001b[34m•\u001b[0m workspace: \u001b[35m~/code/rust/\u001b[0m"] +[0.000,"o","\r\n"] +[0.000,"o"," \u001b[34m↳\u001b[0m path: \u001b[34m~/code/rust/ripgrep\u001b[0m\r\n"] +[0.001,"o","\u001b[36m?\u001b[0m Import this repository? [y/N]: \u001b[32my (auto-confirm)\u001b[0m\r\n"] +[0.003,"o","\u001b[32m✓\u001b[0m Successfully added \u001b[36m'ripgrep'\u001b[0m (\u001b[33mgit+https://github.com/BurntSushi/ripgrep.git\u001b[0m) to \u001b[34m~/.vcspull.yaml\u001b[0m under '\u001b[35m~/code/rust/\u001b[0m'.\r\n"] +[2.027,"x","0"] diff --git a/docs/_static/demos/asciinema/vcspull-add.gif b/docs/_static/demos/asciinema/vcspull-add.gif new file mode 100644 index 000000000..85916d0f1 Binary files /dev/null and b/docs/_static/demos/asciinema/vcspull-add.gif differ diff --git a/docs/_static/demos/asciinema/vcspull-discover.cast b/docs/_static/demos/asciinema/vcspull-discover.cast new file mode 100644 index 000000000..cbbb561cc --- /dev/null +++ b/docs/_static/demos/asciinema/vcspull-discover.cast @@ -0,0 +1,54 @@ +{"version":3,"term":{"cols":120,"rows":14},"timestamp":1783863911,"idle_time_limit":1.0,"command":"vcspull discover ~/code --recursive --dry-run; sleep 2","title":"vcspull discover","env":{"SHELL":"/bin/zsh"}} +[0.15,"o","\u001b[34m$\u001b[0m "] +[0.05,"o","v"] +[0.05,"o","c"] +[0.05,"o","s"] +[0.05,"o","p"] +[0.05,"o","u"] +[0.05,"o","l"] +[0.05,"o","l"] +[0.05,"o"," "] +[0.05,"o","d"] +[0.05,"o","i"] +[0.05,"o","s"] +[0.05,"o","c"] +[0.05,"o","o"] +[0.05,"o","v"] +[0.05,"o","e"] +[0.05,"o","r"] +[0.05,"o"," "] +[0.05,"o","~"] +[0.05,"o","/"] +[0.05,"o","c"] +[0.05,"o","o"] +[0.05,"o","d"] +[0.05,"o","e"] +[0.05,"o"," "] +[0.05,"o","-"] +[0.05,"o","-"] +[0.05,"o","r"] +[0.05,"o","e"] +[0.05,"o","c"] +[0.05,"o","u"] +[0.05,"o","r"] +[0.05,"o","s"] +[0.05,"o","i"] +[0.05,"o","v"] +[0.05,"o","e"] +[0.05,"o"," "] +[0.05,"o","-"] +[0.05,"o","-"] +[0.05,"o","d"] +[0.05,"o","r"] +[0.05,"o","y"] +[0.05,"o","-"] +[0.05,"o","r"] +[0.05,"o","u"] +[0.05,"o","n"] +[0.20,"o","\r\n"] +[0.137,"o","\r\n\u001b[32mFound 4 new repositories to preview:\u001b[0m\r\n \u001b[32m+\u001b[0m \u001b[36mripgrep\u001b[0m (\u001b[33mhttps://github.com/BurntSushi/ripgrep.git\u001b[0m)\r\n \u001b[32m+\u001b[0m \u001b[36mflask\u001b[0m (\u001b[33mhttps://github.com/pallets/flask.git\u001b[0m)\r\n \u001b[34m•\u001b[0m shallow: \u001b[33mtrue\u001b[0m\r\n"] +[0.000,"o"," \u001b[32m+\u001b[0m \u001b[36mclick\u001b[0m (\u001b[33mhttps://github.com/pallets/click.git\u001b[0m)\r\n"] +[0.000,"o"," \u001b[34m•\u001b[0m shallow: \u001b[33mtrue\u001b[0m\r\n \u001b[32m+\u001b[0m \u001b[36mhttpx\u001b[0m (\u001b[33mhttps://github.com/encode/httpx.git\u001b[0m)\r\n"] +[0.000,"o"," \u001b[34m•\u001b[0m shallow: \u001b[33mtrue\u001b[0m\r\n"] +[0.000,"o","\r\n\u001b[33m→\u001b[0m Dry run complete. No changes made to \u001b[34m~/.vcspull.yaml\u001b[0m.\r\n"] +[2.026,"x","0"] diff --git a/docs/_static/demos/asciinema/vcspull-discover.gif b/docs/_static/demos/asciinema/vcspull-discover.gif new file mode 100644 index 000000000..f359337a1 Binary files /dev/null and b/docs/_static/demos/asciinema/vcspull-discover.gif differ diff --git a/docs/_static/demos/asciinema/vcspull-fmt.cast b/docs/_static/demos/asciinema/vcspull-fmt.cast new file mode 100644 index 000000000..79b98f1c8 --- /dev/null +++ b/docs/_static/demos/asciinema/vcspull-fmt.cast @@ -0,0 +1,16 @@ +{"version":3,"term":{"cols":120,"rows":9},"timestamp":1783863913,"idle_time_limit":1.0,"command":"vcspull fmt; sleep 2","title":"vcspull fmt","env":{"SHELL":"/bin/zsh"}} +[0.15,"o","\u001b[34m$\u001b[0m "] +[0.05,"o","v"] +[0.05,"o","c"] +[0.05,"o","s"] +[0.05,"o","p"] +[0.05,"o","u"] +[0.05,"o","l"] +[0.05,"o","l"] +[0.05,"o"," "] +[0.05,"o","f"] +[0.05,"o","m"] +[0.05,"o","t"] +[0.20,"o","\r\n"] +[0.116,"o","\u001b[36mi\u001b[0m Found \u001b[33m9\u001b[0m formatting issues in \u001b[34m~/.vcspull.yaml\u001b[0m\r\n \u001b[34m•\u001b[0m 5 repositories from compact to verbose format\r\n \u001b[34m•\u001b[0m 3 repositories from 'url' to 'repo' key\r\n \u001b[34m•\u001b[0m Directories will be sorted alphabetically\r\n\r\n\u001b[33m→\u001b[0m Run with \u001b[36m--write\u001b[0m to apply these formatting changes.\r\n"] +[2.027,"x","0"] diff --git a/docs/_static/demos/asciinema/vcspull-fmt.gif b/docs/_static/demos/asciinema/vcspull-fmt.gif new file mode 100644 index 000000000..34d44903d Binary files /dev/null and b/docs/_static/demos/asciinema/vcspull-fmt.gif differ diff --git a/docs/_static/demos/asciinema/vcspull-import.cast b/docs/_static/demos/asciinema/vcspull-import.cast new file mode 100644 index 000000000..ee615d92a --- /dev/null +++ b/docs/_static/demos/asciinema/vcspull-import.cast @@ -0,0 +1,95 @@ +{"version":3,"term":{"cols":120,"rows":20},"timestamp":1783863922,"idle_time_limit":1.0,"command":"vcspull import github pallets --mode org -w ~/code/python --limit 5 --https --dry-run; sleep 2","title":"vcspull import","env":{"SHELL":"/bin/zsh"}} +[0.15,"o","\u001b[34m$\u001b[0m "] +[0.05,"o","v"] +[0.05,"o","c"] +[0.05,"o","s"] +[0.05,"o","p"] +[0.05,"o","u"] +[0.05,"o","l"] +[0.05,"o","l"] +[0.05,"o"," "] +[0.05,"o","i"] +[0.05,"o","m"] +[0.05,"o","p"] +[0.05,"o","o"] +[0.05,"o","r"] +[0.05,"o","t"] +[0.05,"o"," "] +[0.05,"o","g"] +[0.05,"o","i"] +[0.05,"o","t"] +[0.05,"o","h"] +[0.05,"o","u"] +[0.05,"o","b"] +[0.05,"o"," "] +[0.05,"o","p"] +[0.05,"o","a"] +[0.05,"o","l"] +[0.05,"o","l"] +[0.05,"o","e"] +[0.05,"o","t"] +[0.05,"o","s"] +[0.05,"o"," "] +[0.05,"o","-"] +[0.05,"o","-"] +[0.05,"o","m"] +[0.05,"o","o"] +[0.05,"o","d"] +[0.05,"o","e"] +[0.05,"o"," "] +[0.05,"o","o"] +[0.05,"o","r"] +[0.05,"o","g"] +[0.05,"o"," "] +[0.05,"o","-"] +[0.05,"o","w"] +[0.05,"o"," "] +[0.05,"o","~"] +[0.05,"o","/"] +[0.05,"o","c"] +[0.05,"o","o"] +[0.05,"o","d"] +[0.05,"o","e"] +[0.05,"o","/"] +[0.05,"o","p"] +[0.05,"o","y"] +[0.05,"o","t"] +[0.05,"o","h"] +[0.05,"o","o"] +[0.05,"o","n"] +[0.05,"o"," "] +[0.05,"o","-"] +[0.05,"o","-"] +[0.05,"o","l"] +[0.05,"o","i"] +[0.05,"o","m"] +[0.05,"o","i"] +[0.05,"o","t"] +[0.05,"o"," "] +[0.05,"o","5"] +[0.05,"o"," "] +[0.05,"o","-"] +[0.05,"o","-"] +[0.05,"o","h"] +[0.05,"o","t"] +[0.05,"o","t"] +[0.05,"o","p"] +[0.05,"o","s"] +[0.05,"o"," "] +[0.05,"o","-"] +[0.05,"o","-"] +[0.05,"o","d"] +[0.05,"o","r"] +[0.05,"o","y"] +[0.05,"o","-"] +[0.05,"o","r"] +[0.05,"o","u"] +[0.05,"o","n"] +[0.20,"o","\r\n"] +[0.119,"o","\u001b[36m→\u001b[0m Fetching repositories from \u001b[35mGitHub\u001b[0m...\r\n"] +[0.626,"o","Showing 5 repositories; more may be available (use --limit 0 to fetch all)\r\n\r\n\u001b[32m✓\u001b[0m Found \u001b[36m5\u001b[0m repositories\r\n \u001b[32m+\u001b[0m \u001b[36mjinja\u001b[0m\u001b[34m [Python]\u001b[0m\u001b[34m ★11684\u001b[0m\r\n \u001b[32m+\u001b[0m \u001b[36mflask\u001b[0m\u001b[34m [Python]\u001b[0m\u001b[34m ★71941\u001b[0m\r\n \u001b[32m+\u001b[0m \u001b[36mclick\u001b[0m\u001b[34m [Python]\u001b[0m\u001b[34m ★17578\u001b[0m\r\n \u001b[32m+\u001b[0m \u001b[36mitsdangerous\u001b[0m\u001b[34m [Python]\u001b[0m\u001b[34m ★3125\u001b[0m\r\n \u001b[32m+\u001b[0m \u001b[36mwerkzeug\u001b[0m\u001b[34m [Python]\u001b[0m\u001b[34m ★6876\u001b[0m\r\n"] +[0.002,"o","[DRY-RUN] Would add: jinja → git+https://github.com/pallets/jinja.git\r\n[DRY-RUN] Would add: itsdangerous → git+https://github.com/pallets/itsdangerous.git\r\n[DRY-RUN] Would add: werkzeug → git+https://github.com/pallets/werkzeug.git\r\n"] +[0.000,"o","[DRY-RUN] Would add \u001b[36m3\u001b[0m repositories\r\n[DRY-RUN] Would tag \u001b[36m2\u001b[0m repositories with import provenance\r\n[DRY-RUN] \u001b[36m2\u001b[0m repositories unchanged\r\n"] +[0.000,"o","\r\n"] +[0.000,"o","\u001b[33m→\u001b[0m Dry run complete. Would write to \u001b[34m~/.vcspull.yaml\u001b[0m\r\n"] +[2.027,"x","0"] diff --git a/docs/_static/demos/asciinema/vcspull-import.gif b/docs/_static/demos/asciinema/vcspull-import.gif new file mode 100644 index 000000000..aabc24e97 Binary files /dev/null and b/docs/_static/demos/asciinema/vcspull-import.gif differ diff --git a/docs/_static/demos/asciinema/vcspull-list-tree.cast b/docs/_static/demos/asciinema/vcspull-list-tree.cast new file mode 100644 index 000000000..232dc6325 --- /dev/null +++ b/docs/_static/demos/asciinema/vcspull-list-tree.cast @@ -0,0 +1,25 @@ +{"version":3,"term":{"cols":120,"rows":17},"timestamp":1783863904,"idle_time_limit":1.0,"command":"vcspull list --tree; sleep 2","title":"vcspull list-tree","env":{"SHELL":"/bin/zsh"}} +[0.15,"o","\u001b[34m$\u001b[0m "] +[0.05,"o","v"] +[0.05,"o","c"] +[0.05,"o","s"] +[0.05,"o","p"] +[0.05,"o","u"] +[0.05,"o","l"] +[0.05,"o","l"] +[0.05,"o"," "] +[0.05,"o","l"] +[0.05,"o","i"] +[0.05,"o","s"] +[0.05,"o","t"] +[0.05,"o"," "] +[0.05,"o","-"] +[0.05,"o","-"] +[0.05,"o","t"] +[0.05,"o","r"] +[0.05,"o","e"] +[0.05,"o","e"] +[0.20,"o","\r\n"] +[0.125,"o","\r\n\u001b[35m~/code/c/\u001b[0m\r\n \u001b[34m•\u001b[0m \u001b[36mjq\u001b[0m \u001b[34m→\u001b[0m ~/code/c/jq\r\n \u001b[34m•\u001b[0m \u001b[36mtmux\u001b[0m \u001b[34m→\u001b[0m ~/code/c/tmux\r\n\r\n\u001b[35m~/code/go/\u001b[0m\r\n \u001b[34m•\u001b[0m \u001b[36mbubbletea\u001b[0m \u001b[34m→\u001b[0m ~/code/go/bubbletea\r\n \u001b[34m•\u001b[0m \u001b[36mfzf\u001b[0m \u001b[34m→\u001b[0m ~/code/go/fzf\r\n \u001b[34m•\u001b[0m \u001b[36mgin\u001b[0m \u001b[34m→\u001b[0m ~/code/go/gin\r\n\r\n\u001b[35m~/code/python/\u001b[0m\r\n \u001b[34m•\u001b[0m \u001b[36mclick\u001b[0m \u001b[34m→\u001b[0m ~/code/python/click\r\n \u001b[34m•\u001b[0m \u001b[36mflask\u001b[0m \u001b[34m→\u001b[0m ~/code/python/flask\r\n"] +[0.000,"o"," \u001b[34m•\u001b[0m \u001b[36mhttpx\u001b[0m \u001b[34m→\u001b[0m ~/code/python/httpx\r\n"] +[2.022,"x","0"] diff --git a/docs/_static/demos/asciinema/vcspull-list-tree.gif b/docs/_static/demos/asciinema/vcspull-list-tree.gif new file mode 100644 index 000000000..3f9c10a1b Binary files /dev/null and b/docs/_static/demos/asciinema/vcspull-list-tree.gif differ diff --git a/docs/_static/demos/asciinema/vcspull-list.cast b/docs/_static/demos/asciinema/vcspull-list.cast new file mode 100644 index 000000000..acea91433 --- /dev/null +++ b/docs/_static/demos/asciinema/vcspull-list.cast @@ -0,0 +1,18 @@ +{"version":3,"term":{"cols":120,"rows":11},"timestamp":1783863901,"idle_time_limit":1.0,"command":"vcspull list; sleep 2","title":"vcspull list","env":{"SHELL":"/bin/zsh"}} +[0.15,"o","\u001b[34m$\u001b[0m "] +[0.05,"o","v"] +[0.05,"o","c"] +[0.05,"o","s"] +[0.05,"o","p"] +[0.05,"o","u"] +[0.05,"o","l"] +[0.05,"o","l"] +[0.05,"o"," "] +[0.05,"o","l"] +[0.05,"o","i"] +[0.05,"o","s"] +[0.05,"o","t"] +[0.20,"o","\r\n"] +[0.129,"o","\u001b[34m•\u001b[0m \u001b[36mclick\u001b[0m \u001b[34m→\u001b[0m ~/code/python/click\r\n"] +[0.001,"o","\u001b[34m•\u001b[0m \u001b[36mflask\u001b[0m \u001b[34m→\u001b[0m ~/code/python/flask\r\n\u001b[34m•\u001b[0m \u001b[36mhttpx\u001b[0m \u001b[34m→\u001b[0m ~/code/python/httpx\r\n\u001b[34m•\u001b[0m \u001b[36mbubbletea\u001b[0m \u001b[34m→\u001b[0m ~/code/go/bubbletea\r\n\u001b[34m•\u001b[0m \u001b[36mfzf\u001b[0m \u001b[34m→\u001b[0m ~/code/go/fzf\r\n\u001b[34m•\u001b[0m \u001b[36mgin\u001b[0m \u001b[34m→\u001b[0m ~/code/go/gin\r\n\u001b[34m•\u001b[0m \u001b[36mjq\u001b[0m \u001b[34m→\u001b[0m ~/code/c/jq\r\n\u001b[34m•\u001b[0m \u001b[36mtmux\u001b[0m \u001b[34m→\u001b[0m ~/code/c/tmux\r\n"] +[2.024,"x","0"] diff --git a/docs/_static/demos/asciinema/vcspull-list.gif b/docs/_static/demos/asciinema/vcspull-list.gif new file mode 100644 index 000000000..9a0d0c202 Binary files /dev/null and b/docs/_static/demos/asciinema/vcspull-list.gif differ diff --git a/docs/_static/demos/asciinema/vcspull-migrate.cast b/docs/_static/demos/asciinema/vcspull-migrate.cast new file mode 100644 index 000000000..40cf39f22 --- /dev/null +++ b/docs/_static/demos/asciinema/vcspull-migrate.cast @@ -0,0 +1,38 @@ +{"version":3,"term":{"cols":120,"rows":8},"timestamp":1783863915,"idle_time_limit":1.0,"command":"vcspull migrate -f ~/legacy.yaml; sleep 2","title":"vcspull migrate","env":{"SHELL":"/bin/zsh"}} +[0.15,"o","\u001b[34m$\u001b[0m "] +[0.05,"o","v"] +[0.05,"o","c"] +[0.05,"o","s"] +[0.05,"o","p"] +[0.05,"o","u"] +[0.05,"o","l"] +[0.05,"o","l"] +[0.05,"o"," "] +[0.05,"o","m"] +[0.05,"o","i"] +[0.05,"o","g"] +[0.05,"o","r"] +[0.05,"o","a"] +[0.05,"o","t"] +[0.05,"o","e"] +[0.05,"o"," "] +[0.05,"o","-"] +[0.05,"o","f"] +[0.05,"o"," "] +[0.05,"o","~"] +[0.05,"o","/"] +[0.05,"o","l"] +[0.05,"o","e"] +[0.05,"o","g"] +[0.05,"o","a"] +[0.05,"o","c"] +[0.05,"o","y"] +[0.05,"o","."] +[0.05,"o","y"] +[0.05,"o","a"] +[0.05,"o","m"] +[0.05,"o","l"] +[0.20,"o","\r\n"] +[0.121,"o","\u001b[36mi\u001b[0m Migrating \u001b[33m2\u001b[0m entries in \u001b[34m~/legacy.yaml\u001b[0m\r\n \u001b[34m•\u001b[0m \u001b[36mclick\u001b[0m: moved rev/shallow/depth under options:\r\n \u001b[34m•\u001b[0m \u001b[36mflask\u001b[0m: moved rev/shallow/depth under options:\r\n\r\n"] +[0.000,"o","\u001b[33m→\u001b[0m Run with \u001b[36m--write\u001b[0m to apply these changes.\r\n"] +[2.023,"x","0"] diff --git a/docs/_static/demos/asciinema/vcspull-migrate.gif b/docs/_static/demos/asciinema/vcspull-migrate.gif new file mode 100644 index 000000000..6f6bd7a28 Binary files /dev/null and b/docs/_static/demos/asciinema/vcspull-migrate.gif differ diff --git a/docs/_static/demos/asciinema/vcspull-search.cast b/docs/_static/demos/asciinema/vcspull-search.cast new file mode 100644 index 000000000..1392563e4 --- /dev/null +++ b/docs/_static/demos/asciinema/vcspull-search.cast @@ -0,0 +1,30 @@ +{"version":3,"term":{"cols":120,"rows":9},"timestamp":1783863908,"idle_time_limit":1.0,"command":"vcspull search python; sleep 2","title":"vcspull search","env":{"SHELL":"/bin/zsh"}} +[0.15,"o","\u001b[34m$\u001b[0m "] +[0.05,"o","v"] +[0.05,"o","c"] +[0.05,"o","s"] +[0.05,"o","p"] +[0.05,"o","u"] +[0.05,"o","l"] +[0.05,"o","l"] +[0.05,"o"," "] +[0.05,"o","s"] +[0.05,"o","e"] +[0.05,"o","a"] +[0.05,"o","r"] +[0.05,"o","c"] +[0.05,"o","h"] +[0.05,"o"," "] +[0.05,"o","p"] +[0.05,"o","y"] +[0.05,"o","t"] +[0.05,"o","h"] +[0.05,"o","o"] +[0.05,"o","n"] +[0.20,"o","\r\n"] +[0.132,"o","\u001b[34m•\u001b[0m \u001b[36mclick\u001b[0m \u001b[34m→\u001b[0m ~/code/\u001b[35mpython\u001b[0m/click\r\n \u001b[34mworkspace:\u001b[0m ~/code/\u001b[35mpython\u001b[0m"] +[0.000,"o","\r\n"] +[0.000,"o","\u001b[34m•\u001b[0m \u001b[36mflask\u001b[0m \u001b[34m→\u001b[0m ~/code/\u001b[35mpython\u001b[0m/flask\r\n \u001b[34mworkspace:\u001b[0m ~/code/\u001b[35mpython\u001b[0m\r\n"] +[0.000,"o","\u001b[34m•\u001b[0m \u001b[36mhttpx\u001b[0m \u001b[34m→\u001b[0m ~/code/\u001b[35mpython\u001b[0m/httpx\r\n"] +[0.000,"o"," \u001b[34mworkspace:\u001b[0m ~/code/\u001b[35mpython\u001b[0m\r\n"] +[2.028,"x","0"] diff --git a/docs/_static/demos/asciinema/vcspull-search.gif b/docs/_static/demos/asciinema/vcspull-search.gif new file mode 100644 index 000000000..ea569d738 Binary files /dev/null and b/docs/_static/demos/asciinema/vcspull-search.gif differ diff --git a/docs/_static/demos/asciinema/vcspull-status.cast b/docs/_static/demos/asciinema/vcspull-status.cast new file mode 100644 index 000000000..8d85e7dfb --- /dev/null +++ b/docs/_static/demos/asciinema/vcspull-status.cast @@ -0,0 +1,26 @@ +{"version":3,"term":{"cols":120,"rows":14},"timestamp":1783863906,"idle_time_limit":1.0,"command":"vcspull status; sleep 2","title":"vcspull status","env":{"SHELL":"/bin/zsh"}} +[0.15,"o","\u001b[34m$\u001b[0m "] +[0.05,"o","v"] +[0.05,"o","c"] +[0.05,"o","s"] +[0.05,"o","p"] +[0.05,"o","u"] +[0.05,"o","l"] +[0.05,"o","l"] +[0.05,"o"," "] +[0.05,"o","s"] +[0.05,"o","t"] +[0.05,"o","a"] +[0.05,"o","t"] +[0.05,"o","u"] +[0.05,"o","s"] +[0.20,"o","\r\n"] +[0.125,"o","\rProgress: 1/8 \u001b[32m✓:0\u001b[0m \u001b[31m✗:1\u001b[0m"] +[0.001,"o","\rProgress: 2/8 \u001b[32m✓:0\u001b[0m \u001b[31m✗:2\u001b[0m\rProgress: 3/8 \u001b[32m✓:0\u001b[0m \u001b[31m✗:3\u001b[0m\rProgress: 4/8 \u001b[32m✓:0\u001b[0m \u001b[31m✗:4\u001b[0m"] +[0.000,"o","\rProgress: 5/8 \u001b[32m✓:0\u001b[0m \u001b[31m✗:5\u001b[0m"] +[0.003,"o","\rProgress: 6/8 \u001b[32m✓:1\u001b[0m \u001b[31m✗:5\u001b[0m"] +[0.001,"o","\rProgress: 7/8 \u001b[32m✓:2\u001b[0m \u001b[31m✗:5\u001b[0m"] +[0.006,"o","\rProgress: 8/8 \u001b[32m✓:3\u001b[0m \u001b[31m✗:5\u001b[0m"] +[0.001,"o","\r\n"] +[0.000,"o","\u001b[31m✗\u001b[0m \u001b[36mbubbletea\u001b[0m: \u001b[31mmissing\u001b[0m\r\n\u001b[31m✗\u001b[0m \u001b[36mgin\u001b[0m: \u001b[31mmissing\u001b[0m\r\n\u001b[31m✗\u001b[0m \u001b[36mjq\u001b[0m: \u001b[31mmissing\u001b[0m\r\n\u001b[31m✗\u001b[0m \u001b[36mtmux\u001b[0m: \u001b[31mmissing\u001b[0m\r\n\u001b[31m✗\u001b[0m \u001b[36mfzf\u001b[0m: \u001b[31mmissing\u001b[0m\r\n\u001b[32m✓\u001b[0m \u001b[36mclick\u001b[0m: \u001b[32mup to date\u001b[0m\r\n\u001b[32m✓\u001b[0m \u001b[36mflask\u001b[0m: \u001b[33mdirty\u001b[0m\r\n\u001b[32m✓\u001b[0m \u001b[36mhttpx\u001b[0m: \u001b[32mup to date\u001b[0m\r\n\r\n\u001b[36mSummary:\u001b[0m 8 repositories, \u001b[32m3\u001b[0m exist, \u001b[31m5\u001b[0m missing\r\n"] +[2.023,"x","0"] diff --git a/docs/_static/demos/asciinema/vcspull-status.gif b/docs/_static/demos/asciinema/vcspull-status.gif new file mode 100644 index 000000000..be770481e Binary files /dev/null and b/docs/_static/demos/asciinema/vcspull-status.gif differ diff --git a/docs/_static/demos/asciinema/vcspull-sync.cast b/docs/_static/demos/asciinema/vcspull-sync.cast new file mode 100644 index 000000000..383e9993b --- /dev/null +++ b/docs/_static/demos/asciinema/vcspull-sync.cast @@ -0,0 +1,83 @@ +{"version":3,"term":{"cols":120,"rows":9},"timestamp":1783863925,"idle_time_limit":1.0,"command":"vcspull sync -w ~/code/python --all; sleep 2","title":"vcspull sync","env":{"SHELL":"/bin/zsh"}} +[0.15,"o","\u001b[34m$\u001b[0m "] +[0.05,"o","v"] +[0.05,"o","c"] +[0.05,"o","s"] +[0.05,"o","p"] +[0.05,"o","u"] +[0.05,"o","l"] +[0.05,"o","l"] +[0.05,"o"," "] +[0.05,"o","s"] +[0.05,"o","y"] +[0.05,"o","n"] +[0.05,"o","c"] +[0.05,"o"," "] +[0.05,"o","-"] +[0.05,"o","w"] +[0.05,"o"," "] +[0.05,"o","~"] +[0.05,"o","/"] +[0.05,"o","c"] +[0.05,"o","o"] +[0.05,"o","d"] +[0.05,"o","e"] +[0.05,"o","/"] +[0.05,"o","p"] +[0.05,"o","y"] +[0.05,"o","t"] +[0.05,"o","h"] +[0.05,"o","o"] +[0.05,"o","n"] +[0.05,"o"," "] +[0.05,"o","-"] +[0.05,"o","-"] +[0.05,"o","a"] +[0.05,"o","l"] +[0.05,"o","l"] +[0.20,"o","\r\n"] +[0.122,"o","\u001b[?25l"] +[0.000,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠋\u001b[0m Syncing \u001b[36mclick\u001b[0m ... 0.0s\u001b[?2026l"] +[0.103,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠙\u001b[0m Syncing \u001b[36mclick\u001b[0m ... 0.1s\u001b[?2026l"] +[0.101,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠹\u001b[0m Syncing \u001b[36mclick\u001b[0m ... 0.2s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠸\u001b[0m Syncing \u001b[36mclick\u001b[0m ... 0.3s\u001b[?2026l"] +[0.101,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠼\u001b[0m Syncing \u001b[36mclick\u001b[0m ... 0.4s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\r\u001b[2Kremote: Compressing objects: 99% (171/172)\r\n\u001b[2Kremote: Compressing objects: 100% (172/172)\r\n\u001b[2Kremo\r\n\u001b[2K\u001b[36m⠴\u001b[0m Syncing \u001b[36mclick\u001b[0m ... 0.5s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\u001b[3A\r\u001b[2KReceiving objects: 46% (86/186)\r\n\u001b[2KReceiving objects: 47% (88/186)\r\n\u001b[2KReceiving objects: 48% (90/18\r\n\u001b[2K\u001b[36m⠦\u001b[0m Syncing \u001b[36mclick\u001b[0m ... 0.6s\u001b[?2026l"] +[0.101,"o","\u001b[?2026h\u001b[3A\r\u001b[2KResolving deltas: 76% (10/13)\r\n\u001b[2KResolving deltas: 84% (11/13)\r\n\u001b[2KResolving deltas: 92% (12/1\r\n\u001b[2K\u001b[36m⠧\u001b[0m Syncing \u001b[36mclick\u001b[0m ... 0.7s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\u001b[3A\r\u001b[2K3)\r\n\u001b[2KResolving deltas: 100% (13/13)\r\n\u001b[2KResolving deltas: 100% (13/13), done.\r\n\u001b[2K\u001b[36m⠇\u001b[0m Syncing \u001b[36mclick\u001b[0m ... 0.8s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\u001b[3A\r\u001b[2K3)\r\n\u001b[2KResolving deltas: 100% (13/13)\r\n\u001b[2KResolving deltas: 100% (13/13), done.\r\n\u001b[2K\u001b[36m⠏\u001b[0m Syncing \u001b[36mclick\u001b[0m ... 0.9s\u001b[?2026l"] +[0.101,"o","\u001b[?2026h\u001b[3A\r\u001b[2K3)\r\n\u001b[2KResolving deltas: 100% (13/13)\r\n\u001b[2KResolving deltas: 100% (13/13), done.\r\n\u001b[2K\u001b[36m⠋\u001b[0m Syncing \u001b[36mclick\u001b[0m ... 1.0s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\u001b[3A\r\u001b[2K3)\r\n\u001b[2KResolving deltas: 100% (13/13)\r\n\u001b[2KResolving deltas: 100% (13/13), done.\r\n\u001b[2K\u001b[36m⠙\u001b[0m Syncing \u001b[36mclick\u001b[0m ... 1.1s\u001b[?2026l"] +[0.096,"o","\u001b[?2026h\u001b[3A\r\u001b[3M\u001b[2K\u001b[32m✓\u001b[0m Synced \u001b[36mclick\u001b[0m \u001b[34m→\u001b[0m ~/code/python/click\r\n\u001b[?2026l"] +[0.004,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠹\u001b[0m Syncing \u001b[36mflask\u001b[0m ... 0.0s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠸\u001b[0m Syncing \u001b[36mflask\u001b[0m ... 0.1s\u001b[?2026l"] +[0.101,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠼\u001b[0m Syncing \u001b[36mflask\u001b[0m ... 0.2s\u001b[?2026l"] +[0.102,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠴\u001b[0m Syncing \u001b[36mflask\u001b[0m ... 0.3s\u001b[?2026l"] +[0.102,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠦\u001b[0m Syncing \u001b[36mflask\u001b[0m ... 0.4s\u001b[?2026l"] +[0.102,"o","\u001b[?2026h\r\u001b[2KReceiving objects: 2% (6/283)\r\n\u001b[2KReceiving objects: 3% (9/283)\r\n\u001b[2KReceiving objects: 4% (12/283)\r\n\u001b[2K\u001b[36m⠧\u001b[0m Syncing \u001b[36mflask\u001b[0m ... 0.5s\u001b[?2026l"] +[0.101,"o","\u001b[?2026h\u001b[3A\r\u001b[2KReceiving objects: 6% (17/283)\r\n\u001b[2KReceiving objects: 7% (20/283)\r\n\u001b[2KReceiving objects: 8% (23/2\r\n\u001b[2K\u001b[36m⠇\u001b[0m Syncing \u001b[36mflask\u001b[0m ... 0.6s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\u001b[3A\r\u001b[2KReceiving objects: 97% (275/283)\r\n\u001b[2KReceiving objects: 98% (278/283)\r\n\u001b[2KReceiving objects: 99% (281/283)\r\n\u001b[2K\u001b[36m⠏\u001b[0m Syncing \u001b[36mflask\u001b[0m ... 0.7s\u001b[?2026l"] +[0.101,"o","\u001b[?2026h\u001b[3A\r\u001b[2KResolving deltas: 100% (5/5)\r\n\u001b[2KResolving deltas: 100% (5/5)\r\n\u001b[2K, done.\r\n\u001b[2K\u001b[36m⠋\u001b[0m Syncing \u001b[36mflask\u001b[0m ... 0.8s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\u001b[3A\r\u001b[2KResolving deltas: 100% (5/5)\r\n\u001b[2KResolving deltas: 100% (5/5)\r\n\u001b[2K, done.\r\n\u001b[2K\u001b[36m⠙\u001b[0m Syncing \u001b[36mflask\u001b[0m ... 0.9s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\u001b[3A\r\u001b[2KResolving deltas: 100% (5/5)\r\n\u001b[2KResolving deltas: 100% (5/5)\r\n\u001b[2K, done.\r\n\u001b[2K\u001b[36m⠹\u001b[0m Syncing \u001b[36mflask\u001b[0m ... 1.0s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\u001b[3A\r\u001b[2KResolving deltas: 100% (5/5)\r\n\u001b[2KResolving deltas: 100% (5/5)\r\n\u001b[2K, done.\r\n\u001b[2K\u001b[36m⠸\u001b[0m Syncing \u001b[36mflask\u001b[0m ... 1.1s\u001b[?2026l"] +[0.101,"o","\u001b[?2026h\u001b[3A\r\u001b[2KResolving deltas: 100% (5/5)\r\n\u001b[2K, done.\r\n\u001b[2KAlready on 'main'\r\n\u001b[2K\u001b[36m⠼\u001b[0m Syncing \u001b[36mflask\u001b[0m ... 1.2s\u001b[?2026l"] +[0.010,"o","\u001b[?2026h\u001b[3A\r\u001b[3M\u001b[2K\u001b[32m✓\u001b[0m Synced \u001b[36mflask\u001b[0m \u001b[34m→\u001b[0m ~/code/python/flask\r\n\u001b[?2026l"] +[0.090,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠴\u001b[0m Syncing \u001b[36mhttpx\u001b[0m ... 0.1s\u001b[?2026l"] +[0.101,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠦\u001b[0m Syncing \u001b[36mhttpx\u001b[0m ... 0.2s\u001b[?2026l"] +[0.102,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠧\u001b[0m Syncing \u001b[36mhttpx\u001b[0m ... 0.3s\u001b[?2026l"] +[0.101,"o","\u001b[?2026h\r\u001b[2K\u001b[36m⠇\u001b[0m Syncing \u001b[36mhttpx\u001b[0m ... 0.4s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\r\u001b[2KReceiving objects: 17% (24/140)\r\n\u001b[2KReceiving objects: 18% (26/140)\r\n\u001b[2KRe\r\n\u001b[2K\u001b[36m⠏\u001b[0m Syncing \u001b[36mhttpx\u001b[0m ... 0.5s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\u001b[3A\r\u001b[2KReceiving objects: 24% (34/140)\r\n\u001b[2KReceiving objects: 25% (35/140)\r\n\u001b[2KReceiving objects: 26% (37\r\n\u001b[2K\u001b[36m⠋\u001b[0m Syncing \u001b[36mhttpx\u001b[0m ... 0.6s\u001b[?2026l"] +[0.101,"o","\u001b[?2026h\u001b[3A\r\u001b[2KReceiving objects: 28% (40/140)\r\n\u001b[2KReceiving objects: 29% (41/140)\r\n\u001b[2KReceiving objects: 30%\r\n\u001b[2K\u001b[36m⠙\u001b[0m Syncing \u001b[36mhttpx\u001b[0m ... 0.7s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\u001b[3A\r\u001b[2KResolving deltas: 0% (0/2)\r\n\u001b[2KResolving deltas: 50% (1/2)\r\n\u001b[2KResolvi\r\n\u001b[2K\u001b[36m⠹\u001b[0m Syncing \u001b[36mhttpx\u001b[0m ... 0.8s\u001b[?2026l"] +[0.101,"o","\u001b[?2026h\u001b[3A\r\u001b[2KResolvi\r\n\u001b[2Kng deltas: 100% (2/2)\r\n\u001b[2KResolving deltas: 100% (2/2), done.\r\n\u001b[2K\u001b[36m⠸\u001b[0m Syncing \u001b[36mhttpx\u001b[0m ... 0.9s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\u001b[3A\r\u001b[2KResolvi\r\n\u001b[2Kng deltas: 100% (2/2)\r\n\u001b[2KResolving deltas: 100% (2/2), done.\r\n\u001b[2K\u001b[36m⠼\u001b[0m Syncing \u001b[36mhttpx\u001b[0m ... 1.0s\u001b[?2026l"] +[0.101,"o","\u001b[?2026h\u001b[3A\r\u001b[2KResolvi\r\n\u001b[2Kng deltas: 100% (2/2)\r\n\u001b[2KResolving deltas: 100% (2/2), done.\r\n\u001b[2K\u001b[36m⠴\u001b[0m Syncing \u001b[36mhttpx\u001b[0m ... 1.1s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\u001b[3A\r\u001b[2KResolvi\r\n\u001b[2Kng deltas: 100% (2/2)\r\n\u001b[2KResolving deltas: 100% (2/2), done.\r\n\u001b[2K\u001b[36m⠦\u001b[0m Syncing \u001b[36mhttpx\u001b[0m ... 1.2s\u001b[?2026l"] +[0.100,"o","\u001b[?2026h\u001b[3A\r\u001b[2Kng deltas: 100% (2/2)\r\n\u001b[2KResolving deltas: 100% (2/2), done.\r\n\u001b[2KAlready on 'master'\r\n\u001b[2K\u001b[36m⠧\u001b[0m Syncing \u001b[36mhttpx\u001b[0m ... 1.3s\u001b[?2026l"] +[0.009,"o","\u001b[?2026h\u001b[3A\r\u001b[3M\u001b[2K\u001b[32m✓\u001b[0m Synced \u001b[36mhttpx\u001b[0m \u001b[34m→\u001b[0m ~/code/python/httpx\r\n\u001b[?2026l"] +[0.000,"o","\r\u001b[1M\u001b[?25h"] +[0.000,"o","\r\n\u001b[36mSummary:\u001b[0m \u001b[36m3\u001b[0m repos, \u001b[32m3\u001b[0m synced, \u001b[31m0\u001b[0m failed\r\n"] +[2.025,"x","0"] diff --git a/docs/_static/demos/asciinema/vcspull-sync.gif b/docs/_static/demos/asciinema/vcspull-sync.gif new file mode 100644 index 000000000..d14e9814a Binary files /dev/null and b/docs/_static/demos/asciinema/vcspull-sync.gif differ diff --git a/docs/_static/demos/asciinema/vcspull-worktree.cast b/docs/_static/demos/asciinema/vcspull-worktree.cast new file mode 100644 index 000000000..17ddb9dac --- /dev/null +++ b/docs/_static/demos/asciinema/vcspull-worktree.cast @@ -0,0 +1,27 @@ +{"version":3,"term":{"cols":120,"rows":7},"timestamp":1783863918,"idle_time_limit":1.0,"command":"vcspull worktree list; sleep 2","title":"vcspull worktree","env":{"SHELL":"/bin/zsh"}} +[0.15,"o","\u001b[34m$\u001b[0m "] +[0.05,"o","v"] +[0.05,"o","c"] +[0.05,"o","s"] +[0.05,"o","p"] +[0.05,"o","u"] +[0.05,"o","l"] +[0.05,"o","l"] +[0.05,"o"," "] +[0.05,"o","w"] +[0.05,"o","o"] +[0.05,"o","r"] +[0.05,"o","k"] +[0.05,"o","t"] +[0.05,"o","r"] +[0.05,"o","e"] +[0.05,"o","e"] +[0.05,"o"," "] +[0.05,"o","l"] +[0.05,"o","i"] +[0.05,"o","s"] +[0.05,"o","t"] +[0.20,"o","\r\n"] +[0.127,"o","\r\n\u001b[35mflask\u001b[0m (~/code/python/flask)\r\n \u001b[32m+\u001b[0m \u001b[36mtag:3.0.0\u001b[0m \u001b[34m~/code/flask-3.x\u001b[0m (\u001b[32mwill create tag worktree\u001b[0m)\r\n"] +[0.000,"o"," \u001b[32m+\u001b[0m \u001b[36mbranch:main\u001b[0m \u001b[34m~/code/flask-dev\u001b[0m (\u001b[32mwill create branch worktree\u001b[0m)\r\n"] +[2.028,"x","0"] diff --git a/docs/_static/demos/asciinema/vcspull-worktree.gif b/docs/_static/demos/asciinema/vcspull-worktree.gif new file mode 100644 index 000000000..755b3ad61 Binary files /dev/null and b/docs/_static/demos/asciinema/vcspull-worktree.gif differ diff --git a/docs/_static/demos/setup-sandbox.sh b/docs/_static/demos/setup-sandbox.sh new file mode 100755 index 000000000..1b2829670 --- /dev/null +++ b/docs/_static/demos/setup-sandbox.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +# Build the sandbox the demo tapes record against. +# +# Everything lives under /tmp/vcspull-demo, which the tapes point HOME and +# XDG_CONFIG_HOME at. That keeps the recordings off the real home directory and +# makes every path on screen render as ~/code/... instead of a developer's +# actual layout. +# +# Idempotent: wipes and rebuilds. Re-run before re-rendering any tape. +set -euo pipefail + +DEMO_DIR=/tmp/vcspull-demo + +# Resolve the vcspull under test. Override with VCSPULL_BIN to record against a +# working tree rather than an installed release. +REAL_VCSPULL="${VCSPULL_BIN:-$(command -v vcspull || true)}" +if [ -z "$REAL_VCSPULL" ]; then + echo "error: vcspull not found on PATH; set VCSPULL_BIN to its location" >&2 + exit 1 +fi + +rm -rf "$DEMO_DIR" +mkdir -p "$DEMO_DIR/.config/vcspull" "$DEMO_DIR/bin" + +# The tapes put $DEMO_DIR/bin first on PATH, so `vcspull` resolves here without +# any absolute developer path appearing in a committed tape. +printf '#!/usr/bin/env bash\nexec %q "$@"\n' "$REAL_VCSPULL" > "$DEMO_DIR/bin/vcspull" +chmod +x "$DEMO_DIR/bin/vcspull" + +# ---------------------------------------------------------------- main config +# Eight widely-recognized public repositories, grouped by language. The three +# Python entries pin depth: 1 so the sync demo clones shallowly and finishes +# inside a watchable window. +cat > "$DEMO_DIR/.vcspull.yaml" <<'YAML' +~/code/python/: + click: + url: git+https://github.com/pallets/click.git + options: + depth: 1 + flask: + url: git+https://github.com/pallets/flask.git + options: + depth: 1 + worktrees: + - dir: ../flask-3.x + tag: "3.0.0" + - dir: ../flask-dev + branch: main + httpx: + url: git+https://github.com/encode/httpx.git + options: + depth: 1 +~/code/go/: + bubbletea: git+https://github.com/charmbracelet/bubbletea.git + fzf: git+https://github.com/junegunn/fzf.git + gin: git+https://github.com/gin-gonic/gin.git +~/code/c/: + jq: git+https://github.com/jqlang/jq.git + tmux: git+https://github.com/tmux/tmux.git +YAML + +# -------------------------------------------------------------- legacy config +# Pre-v1.62 shape, with rev/shallow/depth at the entry root. Feeds `migrate`. +cat > "$DEMO_DIR/legacy.yaml" <<'YAML' +~/code/python/: + click: + url: git+https://github.com/pallets/click.git + shallow: true + flask: + url: git+https://github.com/pallets/flask.git + depth: 1 + rev: "3.0.0" +YAML + +# -------------------------------------------------------------- cloned repos +# Three of the eight are present on disk; the rest stay missing so `status` +# shows a mix rather than a uniform column of checkmarks. +mkdir -p "$DEMO_DIR/code/python" "$DEMO_DIR/code/rust" +for r in "pallets/click" "pallets/flask" "encode/httpx"; do + git clone --quiet --depth 1 "https://github.com/$r.git" \ + "$DEMO_DIR/code/python/${r#*/}" 2>/dev/null +done + +# `worktree list` plans a tag worktree. A --depth 1 clone carries no tags, so +# without this fetch the tag fails to resolve and libvcs prints the absolute +# sandbox path inside the error -- putting /tmp/vcspull-demo on screen. +git -C "$DEMO_DIR/code/python/flask" fetch --quiet --depth 1 origin tag 3.0.0 + +# One dirty tree, so `status` and `sync` have a non-clean state to report. +echo "scratch" >> "$DEMO_DIR/code/python/flask/README.md" + +# On disk but absent from the config, which gives `add` and `discover` +# something real to find. +git init --quiet "$DEMO_DIR/code/rust/ripgrep" +git -C "$DEMO_DIR/code/rust/ripgrep" remote add origin \ + https://github.com/BurntSushi/ripgrep.git +git -C "$DEMO_DIR/code/rust/ripgrep" \ + -c user.email=demo@example.com -c user.name=demo \ + commit --quiet --allow-empty -m "init" + +# ------------------------------------------------------------------- restore +# Mutative demos (add, sync, fmt, migrate) reset from these between takes. +cp "$DEMO_DIR/.vcspull.yaml" "$DEMO_DIR/.vcspull.yaml.bak" +cp "$DEMO_DIR/legacy.yaml" "$DEMO_DIR/legacy.yaml.bak" +tar -C "$DEMO_DIR" -czf "$DEMO_DIR/code.tar.gz" code + +echo "sandbox ready: $DEMO_DIR ($(du -sh "$DEMO_DIR/code" | cut -f1))" diff --git a/docs/_static/demos/vhs/vcspull-add.gif b/docs/_static/demos/vhs/vcspull-add.gif new file mode 100644 index 000000000..08449aad2 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-add.gif differ diff --git a/docs/_static/demos/vhs/vcspull-add.mp4 b/docs/_static/demos/vhs/vcspull-add.mp4 new file mode 100644 index 000000000..9e80243b5 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-add.mp4 differ diff --git a/docs/_static/demos/vhs/vcspull-add.tape b/docs/_static/demos/vhs/vcspull-add.tape new file mode 100644 index 000000000..14a176d7c --- /dev/null +++ b/docs/_static/demos/vhs/vcspull-add.tape @@ -0,0 +1,32 @@ +Output docs/_static/demos/vhs/vcspull-add.gif +Output docs/_static/demos/vhs/vcspull-add.mp4 +Output docs/_static/demos/vhs/vcspull-add.webm + +Set Shell "bash" +Set FontSize 18 +Set Theme "Catppuccin Mocha" +Set TypingSpeed 50ms +Set Padding 20 +Set Width 1400 +Set Height 212 + +# Wait syncs to the prompt returning, so the demo advances when the command +# actually finishes instead of after a guessed Sleep. +Set WaitPattern /[$#>]\s*$/ +Set WaitTimeout 90s + +# The sandbox from docs/_static/demos/setup-sandbox.sh. Redirecting HOME keeps real paths +# off screen: everything renders as ~/code/... instead of a developer's layout. +Env HOME "/tmp/vcspull-demo" +Env XDG_CONFIG_HOME "/tmp/vcspull-demo/.config" +Env PATH "/tmp/vcspull-demo/bin:/usr/local/bin:/usr/bin:/bin" + +Hide +Type "cd ~ && clear" +Enter +Show + +Type "vcspull add ~/code/rust/ripgrep -y" +Enter +Wait +Sleep 2s diff --git a/docs/_static/demos/vhs/vcspull-add.webm b/docs/_static/demos/vhs/vcspull-add.webm new file mode 100644 index 000000000..7dc07fe92 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-add.webm differ diff --git a/docs/_static/demos/vhs/vcspull-discover.gif b/docs/_static/demos/vhs/vcspull-discover.gif new file mode 100644 index 000000000..10cc009e0 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-discover.gif differ diff --git a/docs/_static/demos/vhs/vcspull-discover.mp4 b/docs/_static/demos/vhs/vcspull-discover.mp4 new file mode 100644 index 000000000..0d7edba1b Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-discover.mp4 differ diff --git a/docs/_static/demos/vhs/vcspull-discover.tape b/docs/_static/demos/vhs/vcspull-discover.tape new file mode 100644 index 000000000..34c3a7ff6 --- /dev/null +++ b/docs/_static/demos/vhs/vcspull-discover.tape @@ -0,0 +1,32 @@ +Output docs/_static/demos/vhs/vcspull-discover.gif +Output docs/_static/demos/vhs/vcspull-discover.mp4 +Output docs/_static/demos/vhs/vcspull-discover.webm + +Set Shell "bash" +Set FontSize 18 +Set Theme "Catppuccin Mocha" +Set TypingSpeed 50ms +Set Padding 20 +Set Width 1400 +Set Height 324 + +# Wait syncs to the prompt returning, so the demo advances when the command +# actually finishes instead of after a guessed Sleep. +Set WaitPattern /[$#>]\s*$/ +Set WaitTimeout 90s + +# The sandbox from docs/_static/demos/setup-sandbox.sh. Redirecting HOME keeps real paths +# off screen: everything renders as ~/code/... instead of a developer's layout. +Env HOME "/tmp/vcspull-demo" +Env XDG_CONFIG_HOME "/tmp/vcspull-demo/.config" +Env PATH "/tmp/vcspull-demo/bin:/usr/local/bin:/usr/bin:/bin" + +Hide +Type "cd ~ && clear" +Enter +Show + +Type "vcspull discover ~/code --recursive --dry-run" +Enter +Wait +Sleep 2s diff --git a/docs/_static/demos/vhs/vcspull-discover.webm b/docs/_static/demos/vhs/vcspull-discover.webm new file mode 100644 index 000000000..4dd24df83 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-discover.webm differ diff --git a/docs/_static/demos/vhs/vcspull-fmt.gif b/docs/_static/demos/vhs/vcspull-fmt.gif new file mode 100644 index 000000000..d9a7018c4 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-fmt.gif differ diff --git a/docs/_static/demos/vhs/vcspull-fmt.mp4 b/docs/_static/demos/vhs/vcspull-fmt.mp4 new file mode 100644 index 000000000..b7f2aeec7 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-fmt.mp4 differ diff --git a/docs/_static/demos/vhs/vcspull-fmt.tape b/docs/_static/demos/vhs/vcspull-fmt.tape new file mode 100644 index 000000000..2a42fc743 --- /dev/null +++ b/docs/_static/demos/vhs/vcspull-fmt.tape @@ -0,0 +1,32 @@ +Output docs/_static/demos/vhs/vcspull-fmt.gif +Output docs/_static/demos/vhs/vcspull-fmt.mp4 +Output docs/_static/demos/vhs/vcspull-fmt.webm + +Set Shell "bash" +Set FontSize 18 +Set Theme "Catppuccin Mocha" +Set TypingSpeed 50ms +Set Padding 20 +Set Width 1400 +Set Height 184 + +# Wait syncs to the prompt returning, so the demo advances when the command +# actually finishes instead of after a guessed Sleep. +Set WaitPattern /[$#>]\s*$/ +Set WaitTimeout 90s + +# The sandbox from docs/_static/demos/setup-sandbox.sh. Redirecting HOME keeps real paths +# off screen: everything renders as ~/code/... instead of a developer's layout. +Env HOME "/tmp/vcspull-demo" +Env XDG_CONFIG_HOME "/tmp/vcspull-demo/.config" +Env PATH "/tmp/vcspull-demo/bin:/usr/local/bin:/usr/bin:/bin" + +Hide +Type "cd ~ && clear" +Enter +Show + +Type "vcspull fmt" +Enter +Wait +Sleep 2s diff --git a/docs/_static/demos/vhs/vcspull-fmt.webm b/docs/_static/demos/vhs/vcspull-fmt.webm new file mode 100644 index 000000000..836820a77 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-fmt.webm differ diff --git a/docs/_static/demos/vhs/vcspull-import.gif b/docs/_static/demos/vhs/vcspull-import.gif new file mode 100644 index 000000000..f8bd382fd Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-import.gif differ diff --git a/docs/_static/demos/vhs/vcspull-import.mp4 b/docs/_static/demos/vhs/vcspull-import.mp4 new file mode 100644 index 000000000..14f405857 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-import.mp4 differ diff --git a/docs/_static/demos/vhs/vcspull-import.tape b/docs/_static/demos/vhs/vcspull-import.tape new file mode 100644 index 000000000..2606702e2 --- /dev/null +++ b/docs/_static/demos/vhs/vcspull-import.tape @@ -0,0 +1,32 @@ +Output docs/_static/demos/vhs/vcspull-import.gif +Output docs/_static/demos/vhs/vcspull-import.mp4 +Output docs/_static/demos/vhs/vcspull-import.webm + +Set Shell "bash" +Set FontSize 18 +Set Theme "Catppuccin Mocha" +Set TypingSpeed 50ms +Set Padding 20 +Set Width 1400 +Set Height 450 + +# Wait syncs to the prompt returning, so the demo advances when the command +# actually finishes instead of after a guessed Sleep. +Set WaitPattern /[$#>]\s*$/ +Set WaitTimeout 90s + +# The sandbox from docs/_static/demos/setup-sandbox.sh. Redirecting HOME keeps real paths +# off screen: everything renders as ~/code/... instead of a developer's layout. +Env HOME "/tmp/vcspull-demo" +Env XDG_CONFIG_HOME "/tmp/vcspull-demo/.config" +Env PATH "/tmp/vcspull-demo/bin:/usr/local/bin:/usr/bin:/bin" + +Hide +Type "cd ~ && clear" +Enter +Show + +Type "vcspull import github pallets --mode org -w ~/code/python --limit 5 --https --dry-run" +Enter +Wait +Sleep 2s diff --git a/docs/_static/demos/vhs/vcspull-import.webm b/docs/_static/demos/vhs/vcspull-import.webm new file mode 100644 index 000000000..1aaef5272 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-import.webm differ diff --git a/docs/_static/demos/vhs/vcspull-list-tree.gif b/docs/_static/demos/vhs/vcspull-list-tree.gif new file mode 100644 index 000000000..372584ecc Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-list-tree.gif differ diff --git a/docs/_static/demos/vhs/vcspull-list-tree.mp4 b/docs/_static/demos/vhs/vcspull-list-tree.mp4 new file mode 100644 index 000000000..93d072311 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-list-tree.mp4 differ diff --git a/docs/_static/demos/vhs/vcspull-list-tree.tape b/docs/_static/demos/vhs/vcspull-list-tree.tape new file mode 100644 index 000000000..216edacf5 --- /dev/null +++ b/docs/_static/demos/vhs/vcspull-list-tree.tape @@ -0,0 +1,32 @@ +Output docs/_static/demos/vhs/vcspull-list-tree.gif +Output docs/_static/demos/vhs/vcspull-list-tree.mp4 +Output docs/_static/demos/vhs/vcspull-list-tree.webm + +Set Shell "bash" +Set FontSize 18 +Set Theme "Catppuccin Mocha" +Set TypingSpeed 50ms +Set Padding 20 +Set Width 1400 +Set Height 380 + +# Wait syncs to the prompt returning, so the demo advances when the command +# actually finishes instead of after a guessed Sleep. +Set WaitPattern /[$#>]\s*$/ +Set WaitTimeout 90s + +# The sandbox from docs/_static/demos/setup-sandbox.sh. Redirecting HOME keeps real paths +# off screen: everything renders as ~/code/... instead of a developer's layout. +Env HOME "/tmp/vcspull-demo" +Env XDG_CONFIG_HOME "/tmp/vcspull-demo/.config" +Env PATH "/tmp/vcspull-demo/bin:/usr/local/bin:/usr/bin:/bin" + +Hide +Type "cd ~ && clear" +Enter +Show + +Type "vcspull list --tree" +Enter +Wait +Sleep 2s diff --git a/docs/_static/demos/vhs/vcspull-list-tree.webm b/docs/_static/demos/vhs/vcspull-list-tree.webm new file mode 100644 index 000000000..4ebea01d0 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-list-tree.webm differ diff --git a/docs/_static/demos/vhs/vcspull-list.gif b/docs/_static/demos/vhs/vcspull-list.gif new file mode 100644 index 000000000..80abce747 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-list.gif differ diff --git a/docs/_static/demos/vhs/vcspull-list.mp4 b/docs/_static/demos/vhs/vcspull-list.mp4 new file mode 100644 index 000000000..45001793f Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-list.mp4 differ diff --git a/docs/_static/demos/vhs/vcspull-list.tape b/docs/_static/demos/vhs/vcspull-list.tape new file mode 100644 index 000000000..8e5f05db8 --- /dev/null +++ b/docs/_static/demos/vhs/vcspull-list.tape @@ -0,0 +1,32 @@ +Output docs/_static/demos/vhs/vcspull-list.gif +Output docs/_static/demos/vhs/vcspull-list.mp4 +Output docs/_static/demos/vhs/vcspull-list.webm + +Set Shell "bash" +Set FontSize 18 +Set Theme "Catppuccin Mocha" +Set TypingSpeed 50ms +Set Padding 20 +Set Width 1400 +Set Height 240 + +# Wait syncs to the prompt returning, so the demo advances when the command +# actually finishes instead of after a guessed Sleep. +Set WaitPattern /[$#>]\s*$/ +Set WaitTimeout 90s + +# The sandbox from docs/_static/demos/setup-sandbox.sh. Redirecting HOME keeps real paths +# off screen: everything renders as ~/code/... instead of a developer's layout. +Env HOME "/tmp/vcspull-demo" +Env XDG_CONFIG_HOME "/tmp/vcspull-demo/.config" +Env PATH "/tmp/vcspull-demo/bin:/usr/local/bin:/usr/bin:/bin" + +Hide +Type "cd ~ && clear" +Enter +Show + +Type "vcspull list" +Enter +Wait +Sleep 2s diff --git a/docs/_static/demos/vhs/vcspull-list.webm b/docs/_static/demos/vhs/vcspull-list.webm new file mode 100644 index 000000000..b47029b8f Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-list.webm differ diff --git a/docs/_static/demos/vhs/vcspull-migrate.gif b/docs/_static/demos/vhs/vcspull-migrate.gif new file mode 100644 index 000000000..2311d2402 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-migrate.gif differ diff --git a/docs/_static/demos/vhs/vcspull-migrate.mp4 b/docs/_static/demos/vhs/vcspull-migrate.mp4 new file mode 100644 index 000000000..d52ceb9ea Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-migrate.mp4 differ diff --git a/docs/_static/demos/vhs/vcspull-migrate.tape b/docs/_static/demos/vhs/vcspull-migrate.tape new file mode 100644 index 000000000..1949c7efb --- /dev/null +++ b/docs/_static/demos/vhs/vcspull-migrate.tape @@ -0,0 +1,32 @@ +Output docs/_static/demos/vhs/vcspull-migrate.gif +Output docs/_static/demos/vhs/vcspull-migrate.mp4 +Output docs/_static/demos/vhs/vcspull-migrate.webm + +Set Shell "bash" +Set FontSize 18 +Set Theme "Catppuccin Mocha" +Set TypingSpeed 50ms +Set Padding 20 +Set Width 1400 +Set Height 156 + +# Wait syncs to the prompt returning, so the demo advances when the command +# actually finishes instead of after a guessed Sleep. +Set WaitPattern /[$#>]\s*$/ +Set WaitTimeout 90s + +# The sandbox from docs/_static/demos/setup-sandbox.sh. Redirecting HOME keeps real paths +# off screen: everything renders as ~/code/... instead of a developer's layout. +Env HOME "/tmp/vcspull-demo" +Env XDG_CONFIG_HOME "/tmp/vcspull-demo/.config" +Env PATH "/tmp/vcspull-demo/bin:/usr/local/bin:/usr/bin:/bin" + +Hide +Type "cd ~ && clear" +Enter +Show + +Type "vcspull migrate -f ~/legacy.yaml" +Enter +Wait +Sleep 2s diff --git a/docs/_static/demos/vhs/vcspull-migrate.webm b/docs/_static/demos/vhs/vcspull-migrate.webm new file mode 100644 index 000000000..5b6976008 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-migrate.webm differ diff --git a/docs/_static/demos/vhs/vcspull-search.gif b/docs/_static/demos/vhs/vcspull-search.gif new file mode 100644 index 000000000..520b983f2 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-search.gif differ diff --git a/docs/_static/demos/vhs/vcspull-search.mp4 b/docs/_static/demos/vhs/vcspull-search.mp4 new file mode 100644 index 000000000..a0e60643c Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-search.mp4 differ diff --git a/docs/_static/demos/vhs/vcspull-search.tape b/docs/_static/demos/vhs/vcspull-search.tape new file mode 100644 index 000000000..a17f535f6 --- /dev/null +++ b/docs/_static/demos/vhs/vcspull-search.tape @@ -0,0 +1,32 @@ +Output docs/_static/demos/vhs/vcspull-search.gif +Output docs/_static/demos/vhs/vcspull-search.mp4 +Output docs/_static/demos/vhs/vcspull-search.webm + +Set Shell "bash" +Set FontSize 18 +Set Theme "Catppuccin Mocha" +Set TypingSpeed 50ms +Set Padding 20 +Set Width 1400 +Set Height 184 + +# Wait syncs to the prompt returning, so the demo advances when the command +# actually finishes instead of after a guessed Sleep. +Set WaitPattern /[$#>]\s*$/ +Set WaitTimeout 90s + +# The sandbox from docs/_static/demos/setup-sandbox.sh. Redirecting HOME keeps real paths +# off screen: everything renders as ~/code/... instead of a developer's layout. +Env HOME "/tmp/vcspull-demo" +Env XDG_CONFIG_HOME "/tmp/vcspull-demo/.config" +Env PATH "/tmp/vcspull-demo/bin:/usr/local/bin:/usr/bin:/bin" + +Hide +Type "cd ~ && clear" +Enter +Show + +Type "vcspull search python" +Enter +Wait +Sleep 2s diff --git a/docs/_static/demos/vhs/vcspull-search.webm b/docs/_static/demos/vhs/vcspull-search.webm new file mode 100644 index 000000000..0a047e549 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-search.webm differ diff --git a/docs/_static/demos/vhs/vcspull-status.gif b/docs/_static/demos/vhs/vcspull-status.gif new file mode 100644 index 000000000..872819532 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-status.gif differ diff --git a/docs/_static/demos/vhs/vcspull-status.mp4 b/docs/_static/demos/vhs/vcspull-status.mp4 new file mode 100644 index 000000000..74da78b99 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-status.mp4 differ diff --git a/docs/_static/demos/vhs/vcspull-status.tape b/docs/_static/demos/vhs/vcspull-status.tape new file mode 100644 index 000000000..3776d5476 --- /dev/null +++ b/docs/_static/demos/vhs/vcspull-status.tape @@ -0,0 +1,32 @@ +Output docs/_static/demos/vhs/vcspull-status.gif +Output docs/_static/demos/vhs/vcspull-status.mp4 +Output docs/_static/demos/vhs/vcspull-status.webm + +Set Shell "bash" +Set FontSize 18 +Set Theme "Catppuccin Mocha" +Set TypingSpeed 50ms +Set Padding 20 +Set Width 1400 +Set Height 324 + +# Wait syncs to the prompt returning, so the demo advances when the command +# actually finishes instead of after a guessed Sleep. +Set WaitPattern /[$#>]\s*$/ +Set WaitTimeout 90s + +# The sandbox from docs/_static/demos/setup-sandbox.sh. Redirecting HOME keeps real paths +# off screen: everything renders as ~/code/... instead of a developer's layout. +Env HOME "/tmp/vcspull-demo" +Env XDG_CONFIG_HOME "/tmp/vcspull-demo/.config" +Env PATH "/tmp/vcspull-demo/bin:/usr/local/bin:/usr/bin:/bin" + +Hide +Type "cd ~ && clear" +Enter +Show + +Type "vcspull status" +Enter +Wait +Sleep 2s diff --git a/docs/_static/demos/vhs/vcspull-status.webm b/docs/_static/demos/vhs/vcspull-status.webm new file mode 100644 index 000000000..20b4f0975 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-status.webm differ diff --git a/docs/_static/demos/vhs/vcspull-sync.gif b/docs/_static/demos/vhs/vcspull-sync.gif new file mode 100644 index 000000000..6dbebd0cd Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-sync.gif differ diff --git a/docs/_static/demos/vhs/vcspull-sync.mp4 b/docs/_static/demos/vhs/vcspull-sync.mp4 new file mode 100644 index 000000000..97200e820 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-sync.mp4 differ diff --git a/docs/_static/demos/vhs/vcspull-sync.tape b/docs/_static/demos/vhs/vcspull-sync.tape new file mode 100644 index 000000000..7bc3435a0 --- /dev/null +++ b/docs/_static/demos/vhs/vcspull-sync.tape @@ -0,0 +1,32 @@ +Output docs/_static/demos/vhs/vcspull-sync.gif +Output docs/_static/demos/vhs/vcspull-sync.mp4 +Output docs/_static/demos/vhs/vcspull-sync.webm + +Set Shell "bash" +Set FontSize 18 +Set Theme "Catppuccin Mocha" +Set TypingSpeed 50ms +Set Padding 20 +Set Width 1400 +Set Height 212 + +# Wait syncs to the prompt returning, so the demo advances when the command +# actually finishes instead of after a guessed Sleep. +Set WaitPattern /[$#>]\s*$/ +Set WaitTimeout 90s + +# The sandbox from docs/_static/demos/setup-sandbox.sh. Redirecting HOME keeps real paths +# off screen: everything renders as ~/code/... instead of a developer's layout. +Env HOME "/tmp/vcspull-demo" +Env XDG_CONFIG_HOME "/tmp/vcspull-demo/.config" +Env PATH "/tmp/vcspull-demo/bin:/usr/local/bin:/usr/bin:/bin" + +Hide +Type "cd ~ && rm -rf ~/code && clear" +Enter +Show + +Type "vcspull sync -w ~/code/python --all" +Enter +Wait +Sleep 2s diff --git a/docs/_static/demos/vhs/vcspull-sync.webm b/docs/_static/demos/vhs/vcspull-sync.webm new file mode 100644 index 000000000..8e5799b86 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-sync.webm differ diff --git a/docs/_static/demos/vhs/vcspull-worktree.gif b/docs/_static/demos/vhs/vcspull-worktree.gif new file mode 100644 index 000000000..59298f577 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-worktree.gif differ diff --git a/docs/_static/demos/vhs/vcspull-worktree.mp4 b/docs/_static/demos/vhs/vcspull-worktree.mp4 new file mode 100644 index 000000000..3a15264dc Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-worktree.mp4 differ diff --git a/docs/_static/demos/vhs/vcspull-worktree.tape b/docs/_static/demos/vhs/vcspull-worktree.tape new file mode 100644 index 000000000..f0ab5be98 --- /dev/null +++ b/docs/_static/demos/vhs/vcspull-worktree.tape @@ -0,0 +1,32 @@ +Output docs/_static/demos/vhs/vcspull-worktree.gif +Output docs/_static/demos/vhs/vcspull-worktree.mp4 +Output docs/_static/demos/vhs/vcspull-worktree.webm + +Set Shell "bash" +Set FontSize 18 +Set Theme "Catppuccin Mocha" +Set TypingSpeed 50ms +Set Padding 20 +Set Width 1400 +Set Height 128 + +# Wait syncs to the prompt returning, so the demo advances when the command +# actually finishes instead of after a guessed Sleep. +Set WaitPattern /[$#>]\s*$/ +Set WaitTimeout 90s + +# The sandbox from docs/_static/demos/setup-sandbox.sh. Redirecting HOME keeps real paths +# off screen: everything renders as ~/code/... instead of a developer's layout. +Env HOME "/tmp/vcspull-demo" +Env XDG_CONFIG_HOME "/tmp/vcspull-demo/.config" +Env PATH "/tmp/vcspull-demo/bin:/usr/local/bin:/usr/bin:/bin" + +Hide +Type "cd ~ && clear" +Enter +Show + +Type "vcspull worktree list" +Enter +Wait +Sleep 2s diff --git a/docs/_static/demos/vhs/vcspull-worktree.webm b/docs/_static/demos/vhs/vcspull-worktree.webm new file mode 100644 index 000000000..9302519b7 Binary files /dev/null and b/docs/_static/demos/vhs/vcspull-worktree.webm differ diff --git a/docs/_static/vcspull-demo.gif b/docs/_static/vcspull-demo.gif deleted file mode 100644 index f8f2efea9..000000000 Binary files a/docs/_static/vcspull-demo.gif and /dev/null differ diff --git a/docs/cli/add.md b/docs/cli/add.md index 0c7777457..b77cc6a3b 100644 --- a/docs/cli/add.md +++ b/docs/cli/add.md @@ -15,6 +15,12 @@ For bulk import from remote services ([GitHub](https://github.com), [GitLab](https://gitlab.com), etc.), see {ref}`cli-import`. ``` +```{image} ../_static/demos/asciinema/vcspull-add.gif +:alt: vcspull add registering a repository from its checkout +:width: 100% +:loading: lazy +``` + ## Command ```{eval-rst} diff --git a/docs/cli/discover.md b/docs/cli/discover.md index f4ce319aa..63a9a3a1b 100644 --- a/docs/cli/discover.md +++ b/docs/cli/discover.md @@ -7,6 +7,12 @@ The `vcspull discover` command scans directories for existing {ref}`configuration `. This is ideal for importing existing workspaces or migrating from other tools. +```{image} ../_static/demos/asciinema/vcspull-discover.gif +:alt: vcspull discover scanning a directory tree for repositories +:width: 100% +:loading: lazy +``` + ## Command ```{eval-rst} diff --git a/docs/cli/fmt.md b/docs/cli/fmt.md index 9c46a2ebc..96dc93416 100644 --- a/docs/cli/fmt.md +++ b/docs/cli/fmt.md @@ -11,6 +11,12 @@ single section so repositories are never dropped. Prefer to review duplicates without rewriting them? Pass `--no-merge` to leave the original sections in place while still showing a warning. +```{image} ../_static/demos/asciinema/vcspull-fmt.gif +:alt: vcspull fmt previewing a normalized configuration +:width: 100% +:loading: lazy +``` + ## Command ```{eval-rst} diff --git a/docs/cli/import/index.md b/docs/cli/import/index.md index b0de6de32..70fdbe361 100644 --- a/docs/cli/import/index.md +++ b/docs/cli/import/index.md @@ -13,6 +13,12 @@ Supported services: **[GitHub](https://github.com)**, **[Gitea](https://about.gitea.com/)**, **[Forgejo](https://forgejo.org)**, and **[AWS CodeCommit](https://aws.amazon.com/codecommit/)**. +```{image} ../../_static/demos/asciinema/vcspull-import.gif +:alt: vcspull import fetching repositories from a remote service +:width: 100% +:loading: lazy +``` + ## Command ```{eval-rst} diff --git a/docs/cli/list.md b/docs/cli/list.md index 74c8ebbbe..67a899f64 100644 --- a/docs/cli/list.md +++ b/docs/cli/list.md @@ -7,6 +7,12 @@ The `vcspull list` command displays configured repositories from your vcspull verify your configuration, filter repositories by patterns, and export structured data for automation. +```{image} ../_static/demos/asciinema/vcspull-list.gif +:alt: vcspull list showing configured repositories +:width: 100% +:loading: lazy +``` + ## Command ```{eval-rst} @@ -62,6 +68,12 @@ $ vcspull list --tree • flask → ~/code/flask ``` +```{image} ../_static/demos/asciinema/vcspull-list-tree.gif +:alt: vcspull list grouping repositories by workspace +:width: 100% +:loading: lazy +``` + ## JSON output Export repository information as JSON for automation and tooling: diff --git a/docs/cli/migrate.md b/docs/cli/migrate.md index bfdb3bd32..0e3a3b481 100644 --- a/docs/cli/migrate.md +++ b/docs/cli/migrate.md @@ -12,6 +12,12 @@ These keys shipped at the entry root in vcspull v1.61.0. They are still read, but {ref}`cli-sync` warns when it encounters them. Migrating clears the warning and keeps configs on the supported shape. +```{image} ../_static/demos/asciinema/vcspull-migrate.gif +:alt: vcspull migrate previewing configuration schema changes +:width: 100% +:loading: lazy +``` + ## Command ```{eval-rst} diff --git a/docs/cli/search.md b/docs/cli/search.md index 9a53c43d9..b34560995 100644 --- a/docs/cli/search.md +++ b/docs/cli/search.md @@ -7,6 +7,12 @@ The `vcspull search` command looks up repositories across your vcspull [rg](https://github.com/BurntSushi/ripgrep)-like query syntax. Queries are regex by default, can scope to specific fields, and can emit structured JSON for automation. +```{image} ../_static/demos/asciinema/vcspull-search.gif +:alt: vcspull search narrowing a set of repositories to matches +:width: 100% +:loading: lazy +``` + ## Command ```{eval-rst} diff --git a/docs/cli/status.md b/docs/cli/status.md index 2034bd080..379bbc90a 100644 --- a/docs/cli/status.md +++ b/docs/cli/status.md @@ -7,6 +7,12 @@ showing which repositories exist on disk, which are missing, and their [Git](https://git-scm.com/) status. This introspection command helps verify your local workspace matches your {ref}`configuration `. +```{image} ../_static/demos/asciinema/vcspull-status.gif +:alt: vcspull status reporting clean, dirty, and missing repositories +:width: 100% +:loading: lazy +``` + ## Command ```{eval-rst} diff --git a/docs/cli/sync.md b/docs/cli/sync.md index 2e3b7837f..868999a15 100644 --- a/docs/cli/sync.md +++ b/docs/cli/sync.md @@ -8,6 +8,12 @@ The `vcspull sync` command clones and updates repositories defined in your vcspull {ref}`configuration `. It's the primary command for keeping your local workspace synchronized with remote repositories. +```{image} ../_static/demos/asciinema/vcspull-sync.gif +:alt: vcspull sync cloning a workspace of repositories +:width: 100% +:loading: lazy +``` + ## Command ```{eval-rst} diff --git a/docs/cli/worktree/index.md b/docs/cli/worktree/index.md index 002d6d7df..2250254cc 100644 --- a/docs/cli/worktree/index.md +++ b/docs/cli/worktree/index.md @@ -9,6 +9,12 @@ create, update, and prune them. [git worktrees]: https://git-scm.com/docs/git-worktree +```{image} ../../_static/demos/asciinema/vcspull-worktree.gif +:alt: vcspull worktree reporting configured worktree actions +:width: 100% +:loading: lazy +``` + ## Command ```{eval-rst} diff --git a/docs/conf.py b/docs/conf.py index b84e5050f..0882ccc5c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -38,6 +38,7 @@ extra_extensions=[ "sphinx_autodoc_api_style", "sphinx_autodoc_argparse.exemplar", + "aspect_ratio", ], intersphinx_mapping={ "py": ("https://docs.python.org/", None), @@ -48,8 +49,10 @@ html_extra_path=["manifest.json"], rediraffe_redirects="redirects.txt", # AGENTS.md is agent guidance, not a site page; keep Sphinx from - # treating it as an orphan document. - exclude_patterns=["_build", "AGENTS.md", "CLAUDE.md"], + # treating it as an orphan document. "demos/**" keeps the recorded + # demo sources in the repo but out of the published _static copy — + # the referenced GIFs still reach the build via _images/. + exclude_patterns=["_build", "AGENTS.md", "CLAUDE.md", "demos/**"], ) _gp_setup = conf.pop("setup") diff --git a/docs/index.md b/docs/index.md index 9eb9ba2af..08985b6ed 100644 --- a/docs/index.md +++ b/docs/index.md @@ -81,7 +81,8 @@ See {ref}`quickstart` for all installation methods and first steps. $ vcspull sync --all ``` -```{image} _static/vcspull-demo.gif +```{image} _static/demos/asciinema/vcspull-sync.gif +:alt: vcspull sync cloning a workspace of repositories :width: 100% :loading: lazy ```