Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ env:
CARGO_TERM_COLOR: always

jobs:
version-badge:
name: Version Badge
version-check:
name: Version Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -26,6 +26,29 @@ jobs:
exit 1
fi
echo "Version badge matches: $CARGO_VERSION"
- name: Check demo GIF matches Cargo.toml version
run: |
CARGO_VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
DEMO_FILE="demo/demo-${CARGO_VERSION}.gif"
if [ ! -f "$DEMO_FILE" ]; then
echo "Demo GIF missing: $DEMO_FILE"
echo "Run: ./demo/generate.sh"
exit 1
fi
# Check only one demo GIF exists
DEMO_COUNT=$(find demo -name 'demo-*.gif' | wc -l)
if [ "$DEMO_COUNT" -ne 1 ]; then
echo "Expected exactly 1 demo GIF, found $DEMO_COUNT:"
find demo -name 'demo-*.gif'
echo "Remove old demo files before committing"
exit 1
fi
# Check README references the correct demo
if ! grep -q "demo/demo-${CARGO_VERSION}.gif" README.md; then
echo "README does not reference demo/demo-${CARGO_VERSION}.gif"
exit 1
fi
echo "Demo version matches: $CARGO_VERSION"

check:
name: Check
Expand Down
79 changes: 79 additions & 0 deletions .github/workflows/demo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Demo

on:
pull_request:
branches:
- main

permissions:
contents: write

jobs:
generate-demo:
name: Generate Demo
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
token: ${{ secrets.GITHUB_TOKEN }}

- name: Check if demo needs regeneration
id: check
run: |
VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
DEMO_FILE="demo/demo-${VERSION}.gif"
if [ -f "$DEMO_FILE" ]; then
echo "Demo already exists for version $VERSION"
echo "needs_regen=false" >> $GITHUB_OUTPUT
else
echo "Demo missing for version $VERSION"
echo "needs_regen=true" >> $GITHUB_OUTPUT
echo "version=$VERSION" >> $GITHUB_OUTPUT
fi

- name: Install dependencies
if: steps.check.outputs.needs_regen == 'true'
run: |
sudo apt-get update
sudo apt-get install -y ffmpeg ttyd

- name: Install vhs
if: steps.check.outputs.needs_regen == 'true'
run: |
curl -fsSL -o vhs.deb https://github.com/charmbracelet/vhs/releases/download/v0.10.0/vhs_0.10.0_amd64.deb
sudo dpkg -i vhs.deb

- name: Install Rust
if: steps.check.outputs.needs_regen == 'true'
uses: dtolnay/rust-toolchain@stable

- name: Build f
if: steps.check.outputs.needs_regen == 'true'
run: cargo build --release -p f

- name: Generate demo
if: steps.check.outputs.needs_regen == 'true'
run: |
VERSION=${{ steps.check.outputs.version }}
export PATH="$PWD/target/release:$PATH"

# Remove old demos
rm -f demo/demo-*.gif

# Generate new demo
cd demo
vhs demo.tape -o "demo-${VERSION}.gif"

# Update README
cd ..
sed -i "s|demo/demo-[0-9]*\.[0-9]*\.[0-9]*\.gif|demo/demo-${VERSION}.gif|g" README.md

- name: Commit and push
if: steps.check.outputs.needs_regen == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add demo/*.gif README.md
git commit -m "Generate demo for v${{ steps.check.outputs.version }}"
git push
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

A keyboard-driven git file manager for the terminal.

![demo](demo/demo-0.1.0.gif)

## The Problem

When working with git, common workflows like staging files, viewing diffs, and editing changed files require typing full file paths repeatedly. Tab completion helps, but with many changed files it's still slow.
Expand Down
15 changes: 13 additions & 2 deletions crates/f/src/f.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,13 @@ fn exec_git(args: &[&str]) -> ! {

fn exec_editor(path: &str, config: &Config) -> ! {
let editor = get_editor(config);
let err = Command::new(&editor).arg(path).exec();
// Run through shell to support EDITOR with arguments (e.g., "vim -u NONE")
let err = Command::new("sh")
.arg("-c")
.arg(format!("{} \"$1\"", editor))
.arg("sh") // $0
.arg(path) // $1
.exec();
eprintln!("Failed to exec {}: {}", editor, err);
process::exit(1);
}
Expand Down Expand Up @@ -512,7 +518,12 @@ mod interactive {
}
'e' => {
let editor = config.editor();
let _ = Command::new(&editor).arg(&file.abs_path).exec();
let _ = Command::new("sh")
.arg("-c")
.arg(format!("{} \"$1\"", editor))
.arg("sh")
.arg(&file.abs_path)
.exec();
}
_ => {}
}
Expand Down
Binary file added demo/demo-0.1.0.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
142 changes: 142 additions & 0 deletions demo/demo.tape
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# VHS Demo Tape for f
# Run with: vhs demo/demo.tape

Output demo.gif
Output demo.ascii
Set FontSize 16
Set Width 900
Set Height 500
Set Theme "Catppuccin Mocha"
Set TypingSpeed 50ms

# Setup: create a temp git repo with some changes
Hide
Type "export PS1='> '"
Enter
Sleep 100ms
Type "cd $(mktemp -d)"
Enter
Sleep 100ms
Type "git init -q && git config user.email 'demo@example.com' && git config user.name 'Demo'"
Enter
Sleep 100ms
Type "echo 'hello' > greeting.txt"
Enter
Type "git add . && git commit -q -m 'init'"
Enter
Sleep 100ms
Type "echo 'hello world' > greeting.txt"
Enter
Type "echo 'new file' > notes.txt"
Enter
Type "echo 'config' > config.toml"
Enter
Type "git add config.toml"
Enter
Sleep 100ms
Type "clear"
Enter
Sleep 300ms
Show

# Demo: List changed files
Type "# List changed files with stable IDs"
Enter
Sleep 500ms
Type "f"
Enter
Sleep 2s

Type "clear"
Enter
Sleep 300ms

# Demo: View diff by ID
Type "# View diff for a file"
Enter
Sleep 500ms
Type "f d d"
Enter
Sleep 2s

Type "clear"
Enter
Sleep 300ms

# Demo: Edit file by ID
Type "# Edit a file in $EDITOR"
Enter
Sleep 500ms
Type "export EDITOR='vi -u NONE'"
Enter
Sleep 300ms
Type "f d e"
Enter
Sleep 1s
# vim: Go to end, open line above, type, save
Type "G"
Sleep 300ms
Type "o"
Sleep 300ms
Type "some changes here"
Sleep 500ms
Escape
Sleep 300ms
Type ":wq"
Enter
Sleep 1s

# Show status after edit
Type "f"
Enter
Sleep 2s

Type "clear"
Enter
Sleep 300ms

# Demo: Stage a file using ID
Type "# Stage a file by ID"
Enter
Sleep 500ms
Type "f d a"
Enter
Sleep 1s

# Show updated status
Type "f"
Enter
Sleep 2s

Type "clear"
Enter
Sleep 300ms

# Demo: Stage remaining files
Type "# Stage another file (autoselect top of list)"
Enter
Sleep 500ms
Type "f a"
Enter
Sleep 1s

Type "f"
Enter
Sleep 2s

Type "clear"
Enter
Sleep 300ms

# Demo: Commit
Type "# Commit staged changes"
Enter
Sleep 500ms
Type "f c update greeting and add notes"
Enter
Sleep 1s

# Final status
Type "f"
Enter
Sleep 2s
37 changes: 37 additions & 0 deletions demo/generate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"

# Get version from Cargo.toml
VERSION=$(grep '^version = ' "$PROJECT_ROOT/Cargo.toml" | head -1 | sed 's/version = "\(.*\)"/\1/')

if [[ -z "$VERSION" ]]; then
echo "Error: Could not extract version from Cargo.toml"
exit 1
fi

OUTPUT_FILE="$SCRIPT_DIR/demo-${VERSION}.gif"

echo "Generating demo for version $VERSION..."
echo "Output: $OUTPUT_FILE"

# Remove old demo GIFs
find "$SCRIPT_DIR" -name 'demo-*.gif' -delete 2>/dev/null || true

# Build the project first so demo uses current version
cargo build --release -p f --quiet

# Add to PATH for vhs
export PATH="$PROJECT_ROOT/target/release:$PATH"

# Generate the demo
cd "$SCRIPT_DIR"
vhs demo.tape -o "demo-${VERSION}.gif"

# Update README to reference new demo
sed -i "s|demo/demo-[0-9]*\.[0-9]*\.[0-9]*\.gif|demo/demo-${VERSION}.gif|g" "$PROJECT_ROOT/README.md"

echo "Demo generated: $OUTPUT_FILE"
echo "README.md updated to reference demo/demo-${VERSION}.gif"