mirror of
https://github.com/prdlk/television.git
synced 2026-11-02 13:12:51 +00:00
Import from root chezmoi source
This commit is contained in:
commit
c8c8c9a000
77 files changed
+2443
No files matched your search
Whitespace-only changes.
@@ -0,0 +1,67 @@
|
||||
[metadata]
|
||||
name = "agents"
|
||||
description = """
|
||||
AI coding agent CLIs found on PATH. Enter starts the agent's TUI in the current
|
||||
directory.
|
||||
"""
|
||||
requirements = []
|
||||
|
||||
# Entries are "<name + description>\t<launch command>\t<binary>". Only agents
|
||||
# whose binary resolves on PATH are listed; add a row to the table to support
|
||||
# another one. The launch command may carry flags (claude, as in `ai`).
|
||||
[source]
|
||||
command = '''
|
||||
while IFS='|' read -r bin cmd desc; do
|
||||
command -v "$bin" >/dev/null 2>&1 &&
|
||||
printf '%-13s %s\t%s\t%s\n' "$bin" "$desc" "$cmd" "$bin"
|
||||
done <<'EOF'
|
||||
omp|omp|oh-my-pi coding agent
|
||||
claude|claude --dangerously-skip-permissions|Claude Code (Anthropic)
|
||||
codex|codex|Codex CLI (OpenAI)
|
||||
opencode|opencode|OpenCode (sst)
|
||||
crush|crush|Crush (Charm)
|
||||
pi|pi|pi coding agent
|
||||
cursor-agent|cursor-agent|Cursor Agent CLI
|
||||
copilot|copilot|GitHub Copilot CLI
|
||||
gemini|gemini|Gemini CLI (Google)
|
||||
agy|agy|Antigravity CLI (Google)
|
||||
grok|grok|Grok CLI (xAI)
|
||||
muse|muse|Muse Code (Meta)
|
||||
ori|ori|Ori (OpenRouter)
|
||||
hermes|hermes|Hermes Agent (Nous Research)
|
||||
amp|amp|Amp (Sourcegraph)
|
||||
droid|droid|Droid (Factory)
|
||||
qwen|qwen|Qwen Code (Alibaba)
|
||||
kimi|kimi|Kimi CLI (Moonshot)
|
||||
goose|goose|goose (Block)
|
||||
aider|aider|aider
|
||||
auggie|auggie|Auggie (Augment Code)
|
||||
kiro-cli|kiro-cli|Kiro CLI (AWS)
|
||||
cn|cn|Continue CLI
|
||||
fractal|fractal|fractal
|
||||
EOF
|
||||
'''
|
||||
shell = "bash"
|
||||
display = "{split:\\t:0}"
|
||||
output = "{split:\\t:1}"
|
||||
|
||||
[preview]
|
||||
command = '''
|
||||
p=$(command -v '{split:\t:2}')
|
||||
printf 'command %s\npath %s\n' '{split:\t:1}' "$p"
|
||||
r=$(readlink -f "$p")
|
||||
[ "$r" != "$p" ] && printf 'resolves %s\n' "$r"
|
||||
# ~/.local/bin wrappers install the agent through mise on first run.
|
||||
tool=$(grep -o 'mise x "[^"]*"' "$r" 2>/dev/null | cut -d'"' -f2)
|
||||
[ -n "$tool" ] && printf 'mise %s\n' "$tool"
|
||||
'''
|
||||
shell = "bash"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:launch"
|
||||
|
||||
[actions.launch]
|
||||
description = "Start the agent's TUI"
|
||||
command = "{split:\\t:1}"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,17 @@
|
||||
[metadata]
|
||||
name = "alias"
|
||||
description = "A channel to select from shell aliases"
|
||||
|
||||
[source]
|
||||
# you may need to adjust the command depending on your shell
|
||||
command = "$SHELL -ic 'alias'"
|
||||
output = "{split:=:0}"
|
||||
|
||||
[preview]
|
||||
command = "$SHELL -ic 'alias' | grep -E '^(alias )?{split:=:0}='"
|
||||
|
||||
[ui.preview_panel]
|
||||
border_type = "none"
|
||||
scrollbar = false
|
||||
padding = { left = 2, right = 1, top = 0, bottom = 0 }
|
||||
size = 30
|
||||
@@ -0,0 +1,9 @@
|
||||
[metadata]
|
||||
name = "bash-history"
|
||||
description = "A channel to select from your bash history"
|
||||
requirements = ["bash"]
|
||||
|
||||
[source]
|
||||
command = "sed '1!G;h;$!d' ${HISTFILE:-${HOME}/.bash_history} | awk '!seen[$0]++'"
|
||||
no_sort = true
|
||||
frecency = false
|
||||
@@ -0,0 +1,30 @@
|
||||
[metadata]
|
||||
name = "brew-packages"
|
||||
description = "List and manage Homebrew packages"
|
||||
requirements = ["brew"]
|
||||
|
||||
[source]
|
||||
command = [
|
||||
{ name = "Formulae", run = "brew list --formula" },
|
||||
{ name = "Casks", run = "brew list --cask" },
|
||||
]
|
||||
|
||||
[preview]
|
||||
command = "brew info '{}'"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
|
||||
[keybindings]
|
||||
ctrl-u = "actions:upgrade"
|
||||
ctrl-d = "actions:uninstall"
|
||||
|
||||
[actions.upgrade]
|
||||
description = "Upgrade the selected package"
|
||||
command = "brew upgrade {}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.uninstall]
|
||||
description = "Uninstall the selected package"
|
||||
command = "brew uninstall {}"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,22 @@
|
||||
[metadata]
|
||||
name = "cargo-commands"
|
||||
description = "List available cargo commands and extensions"
|
||||
requirements = ["cargo"]
|
||||
|
||||
[source]
|
||||
command = "cargo --list 2>/dev/null | tail -n +2 | awk '{print $1}'"
|
||||
|
||||
[preview]
|
||||
command = "cargo {} --help 2>/dev/null | head -50"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
preview_panel = { size = 60, border_type = "none", scrollbar = false, padding = { left = 2, right = 1, top = 0, bottom = 0 } }
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:run"
|
||||
|
||||
[actions.run]
|
||||
description = "Run the selected cargo command"
|
||||
command = "cargo {}"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,17 @@
|
||||
[metadata]
|
||||
name = "cargo-crates"
|
||||
description = "List installed cargo crates"
|
||||
requirements = ["cargo"]
|
||||
|
||||
[source]
|
||||
command = "cargo install --list 2>/dev/null | grep -v '^ ' | sed 's/:$//'"
|
||||
display = "{split: :0} {split: :1}"
|
||||
output = "{split: :0}"
|
||||
|
||||
[preview]
|
||||
command = "cargo install --list 2>/dev/null | sed -n '/^{split: :0} /,/^[^ ]/p' | head -20"
|
||||
|
||||
[actions.uninstall]
|
||||
description = "Uninstall the selected crate"
|
||||
command = "cargo uninstall '{split: :0}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,19 @@
|
||||
[metadata]
|
||||
name = "channels"
|
||||
description = "Select a television channel"
|
||||
requirements = ["tv", "bat"]
|
||||
|
||||
[source]
|
||||
command = ["tv list-channels"]
|
||||
|
||||
[preview]
|
||||
command = "bat -pn --color always ${TELEVISION_CONFIG:-${XDG_CONFIG_HOME:-$HOME/.config}/television}/cable/{}.toml"
|
||||
shell = "bash"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:channel-enter"
|
||||
|
||||
[actions.channel-enter]
|
||||
description = "Enter a television channel"
|
||||
command = "tv {} --inline"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,20 @@
|
||||
[metadata]
|
||||
name = "crontab"
|
||||
description = "List and manage crontab entries"
|
||||
|
||||
[source]
|
||||
command = "crontab -l 2>/dev/null | grep -v '^#' | grep -v '^$'"
|
||||
no_sort = true
|
||||
frecency = false
|
||||
|
||||
[preview]
|
||||
command = '''echo 'Schedule: {split: :..5}' && echo '' && echo 'Command:' && echo '{split: :5..}' '''
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
preview_panel = { size = 30, border_type = "none", scrollbar = false, padding = { left = 2, right = 1, top = 0, bottom = 0 } }
|
||||
|
||||
[actions.edit]
|
||||
description = "Open crontab for editing"
|
||||
command = "crontab -e"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,26 @@
|
||||
[metadata]
|
||||
name = "dirs"
|
||||
description = "A channel to select from directories"
|
||||
requirements = ["fd"]
|
||||
|
||||
[source]
|
||||
command = [
|
||||
{ name = "Default", run = "fd -t d" },
|
||||
{ name = "Hidden", run = "fd -t d --hidden" },
|
||||
]
|
||||
|
||||
[preview]
|
||||
command = "ls -la --color=always '{}'"
|
||||
|
||||
[keybindings]
|
||||
shortcut = "f2"
|
||||
|
||||
[actions.cd]
|
||||
description = "Open a shell in the selected directory"
|
||||
command = "cd {} && $SHELL"
|
||||
mode = "execute"
|
||||
|
||||
[actions.goto_parent_dir]
|
||||
description = "Re-opens tv in the parent directory"
|
||||
command = "tv dirs .. --inline"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,32 @@
|
||||
[metadata]
|
||||
name = "docker-compose"
|
||||
description = "Manage Docker Compose services"
|
||||
requirements = ["docker"]
|
||||
|
||||
[source]
|
||||
command = "docker compose ps --format '{{.Name}}\t{{.Service}}\t{{.Status}}'"
|
||||
display = "{split:\t:1} ({split:\t:2})"
|
||||
output = "{split:\t:1}"
|
||||
|
||||
[preview]
|
||||
command = "docker compose logs --tail=30 --no-log-prefix '{split:\t:1}'"
|
||||
|
||||
[actions.up]
|
||||
description = "Start the selected service"
|
||||
command = "docker compose up -d '{split:\t:1}'"
|
||||
mode = "fork"
|
||||
|
||||
[actions.down]
|
||||
description = "Stop and remove the selected service"
|
||||
command = "docker compose down '{split:\t:1}'"
|
||||
mode = "fork"
|
||||
|
||||
[actions.restart]
|
||||
description = "Restart the selected service"
|
||||
command = "docker compose restart '{split:\t:1}'"
|
||||
mode = "fork"
|
||||
|
||||
[actions.logs]
|
||||
description = "Follow logs of the selected service"
|
||||
command = "docker compose logs -f '{split:\t:1}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,56 @@
|
||||
[metadata]
|
||||
name = "docker-containers"
|
||||
description = "List and manage Docker containers"
|
||||
requirements = ["docker", "jq"]
|
||||
|
||||
[source]
|
||||
command = [
|
||||
{ name = "Running", run = "docker ps --format '{{.Names}}\\t{{.Image}}\\t{{.Status}}'" },
|
||||
{ name = "All", run = "docker ps -a --format '{{.Names}}\\t{{.Image}}\\t{{.Status}}'" },
|
||||
]
|
||||
display = "{split:\\t:0} ({split:\\t:2})"
|
||||
output = "{split:\\t:0}"
|
||||
|
||||
[preview]
|
||||
command = "docker inspect '{split:\\t:0}' | jq -C '.[0] | {Name, State, Config: {Image: .Config.Image, Cmd: .Config.Cmd}, NetworkSettings: {IPAddress: .NetworkSettings.IPAddress}}'"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
|
||||
[keybindings]
|
||||
ctrl-s = "actions:start"
|
||||
f2 = "actions:stop"
|
||||
ctrl-r = "actions:restart"
|
||||
ctrl-l = "actions:logs"
|
||||
ctrl-e = "actions:exec"
|
||||
ctrl-d = "actions:remove"
|
||||
|
||||
[actions.start]
|
||||
description = "Start the selected container"
|
||||
command = "docker start '{split:\\t:0}'"
|
||||
mode = "fork"
|
||||
|
||||
[actions.stop]
|
||||
description = "Stop the selected container"
|
||||
command = "docker stop '{split:\\t:0}'"
|
||||
mode = "fork"
|
||||
|
||||
[actions.restart]
|
||||
description = "Restart the selected container"
|
||||
command = "docker restart '{split:\\t:0}'"
|
||||
mode = "fork"
|
||||
|
||||
[actions.logs]
|
||||
description = "Follow logs of the selected container"
|
||||
command = "docker logs -f '{split:\\t:0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.exec]
|
||||
description = "Execute shell in the selected container"
|
||||
command = "docker exec -it '{split:\\t:0}' /bin/sh"
|
||||
mode = "execute"
|
||||
|
||||
[actions.remove]
|
||||
description = "Remove the selected container"
|
||||
command = "docker rm '{split:\\t:0}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,34 @@
|
||||
[metadata]
|
||||
name = "docker-images"
|
||||
description = "A channel to select from Docker images"
|
||||
requirements = ["docker", "jq"]
|
||||
|
||||
[source]
|
||||
command = "docker images --format '{{.Repository}}:{{.Tag}} {{.ID}}'"
|
||||
output = "{split: :-1}"
|
||||
|
||||
[preview]
|
||||
command = "docker image inspect '{split: :-1}' | jq -C"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
|
||||
[keybindings]
|
||||
ctrl-r = "actions:run"
|
||||
ctrl-d = "actions:remove"
|
||||
ctrl-s = "actions:shell"
|
||||
|
||||
[actions.run]
|
||||
description = "Run a container from the selected image"
|
||||
command = "docker run -it '{split: :-1}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.shell]
|
||||
description = "Run a shell in the selected image"
|
||||
command = "docker run -it '{split: :-1}' /bin/sh"
|
||||
mode = "execute"
|
||||
|
||||
[actions.remove]
|
||||
description = "Remove the selected image"
|
||||
command = "docker rmi '{split: :-1}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,20 @@
|
||||
[metadata]
|
||||
name = "docker-networks"
|
||||
description = "List and manage Docker networks"
|
||||
requirements = ["docker", "jq"]
|
||||
|
||||
[source]
|
||||
command = "docker network ls --format '{{.Name}}\t{{.Driver}}\t{{.Scope}}'"
|
||||
display = "{split:\t:0} ({split:\t:1}, {split:\t:2})"
|
||||
output = "{split:\t:0}"
|
||||
|
||||
[preview]
|
||||
command = "docker network inspect '{split:\t:0}' | jq -C '.[0] | {Name, Driver, Scope, IPAM, Containers: (.Containers // {} | to_entries | map({name: .value.Name, ipv4: .value.IPv4Address}))}'"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
|
||||
[actions.remove]
|
||||
description = "Remove the selected network"
|
||||
command = "docker network rm '{split:\t:0}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,25 @@
|
||||
[metadata]
|
||||
name = "docker-volumes"
|
||||
description = "List and manage Docker volumes"
|
||||
requirements = ["docker", "jq"]
|
||||
|
||||
[source]
|
||||
command = "docker volume ls --format '{{.Name}}\t{{.Driver}}'"
|
||||
display = "{split:\t:0} ({split:\t:1})"
|
||||
output = "{split:\t:0}"
|
||||
|
||||
[preview]
|
||||
command = "docker volume inspect '{split:\t:0}' | jq -C '.[0]'"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
|
||||
[actions.remove]
|
||||
description = "Remove the selected volume"
|
||||
command = "docker volume rm '{split:\t:0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.inspect]
|
||||
description = "Inspect the selected volume in a pager"
|
||||
command = "docker volume inspect '{split:\t:0}' | jq -C '.[0]' | less -R"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,19 @@
|
||||
[metadata]
|
||||
name = "dotfiles"
|
||||
description = "A channel to select from your user's dotfiles"
|
||||
requirements = ["fd", "bat"]
|
||||
|
||||
[source]
|
||||
command = "fd -t f . $HOME/.config"
|
||||
|
||||
[preview]
|
||||
command = "bat -n --color=always '{}'"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:edit"
|
||||
|
||||
[actions.edit]
|
||||
description = "Edit the selected dotfile"
|
||||
command = "${EDITOR:-vim} {}"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,31 @@
|
||||
[metadata]
|
||||
name = "downloads"
|
||||
description = "Browse recent files in Downloads folder"
|
||||
requirements = ["fd", "bat"]
|
||||
|
||||
[source]
|
||||
command = "fd -t f . ~/Downloads 2>/dev/null | head -200"
|
||||
|
||||
[preview]
|
||||
command = "bat -n --color=always '{}' 2>/dev/null || file '{}'"
|
||||
env = { BAT_THEME = "ansi" }
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:open"
|
||||
ctrl-d = "actions:delete"
|
||||
ctrl-m = "actions:move"
|
||||
|
||||
[actions.open]
|
||||
description = "Open the selected file with default application"
|
||||
command = "xdg-open {} 2>/dev/null || open {}"
|
||||
mode = "fork"
|
||||
|
||||
[actions.delete]
|
||||
description = "Delete the selected file"
|
||||
command = "rm -i {}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.move]
|
||||
description = "Move the selected file to current directory"
|
||||
command = "mv {} ."
|
||||
mode = "fork"
|
||||
@@ -0,0 +1,22 @@
|
||||
[metadata]
|
||||
name = "env"
|
||||
description = "A channel to select from environment variables"
|
||||
|
||||
[source]
|
||||
command = "printenv"
|
||||
output = "{split:=:1..}" # output the value
|
||||
|
||||
[preview]
|
||||
command = "echo '{split:=:1..}'"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
preview_panel = { size = 20, header = "{split:=:0}", border_type = "none", scrollbar = false, padding = { left = 2, right = 1, top = 0, bottom = 0 } }
|
||||
|
||||
[keybindings]
|
||||
shortcut = "f3"
|
||||
|
||||
[actions.name]
|
||||
description = "Output the variable name instead of the value"
|
||||
command = "echo '{split:=:0}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,33 @@
|
||||
[metadata]
|
||||
name = "files"
|
||||
description = "A channel to select files and directories"
|
||||
requirements = ["fd", "bat", "mtime-sort"]
|
||||
|
||||
# Most recently modified first; tv ranks matches and frecency on top.
|
||||
[source]
|
||||
command = [
|
||||
{ name = "Default", run = "fd -t f | mtime-sort" },
|
||||
{ name = "Hidden", run = "fd -t f -H | mtime-sort" },
|
||||
]
|
||||
shell = "bash"
|
||||
|
||||
[preview]
|
||||
command = "bat -n --color=always '{}'"
|
||||
env = { BAT_THEME = "ansi" }
|
||||
|
||||
# ctrl-e (edit) and ctrl-h (goto_parent_dir) are bound in config.toml.
|
||||
[keybindings]
|
||||
shortcut = "f1"
|
||||
[actions.edit]
|
||||
description = "Opens the selected entries in nvim"
|
||||
# Redirect to the tty: the fish ctrl-t binding runs tv inside a command
|
||||
# substitution, so stdout is a pipe there.
|
||||
command = "nvim {} </dev/tty >/dev/tty"
|
||||
shell = "bash"
|
||||
# use `mode = "fork"` if you want to return to tv afterwards
|
||||
mode = "execute"
|
||||
|
||||
[actions.goto_parent_dir]
|
||||
description = "Re-opens tv in the parent directory"
|
||||
command = "tv files .. --inline"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,9 @@
|
||||
[metadata]
|
||||
name = "fish-history"
|
||||
description = "A channel to select from your fish history"
|
||||
requirements = ["fish"]
|
||||
|
||||
[source]
|
||||
command = "fish -c 'history'"
|
||||
no_sort = true
|
||||
frecency = false
|
||||
@@ -0,0 +1,16 @@
|
||||
[metadata]
|
||||
name = "fonts"
|
||||
description = "List installed system fonts"
|
||||
requirements = ["fc-list"]
|
||||
|
||||
[source]
|
||||
command = "fc-list --format='%{family}\n' | sort -uf"
|
||||
|
||||
[preview]
|
||||
command = "fc-list '{}' --format='%{file}\n%{style}\n%{family}\n' | head -20"
|
||||
|
||||
[ui.preview_panel]
|
||||
border_type = "none"
|
||||
scrollbar = false
|
||||
padding = { left = 2, right = 1, top = 0, bottom = 0 }
|
||||
size = 70
|
||||
@@ -0,0 +1,47 @@
|
||||
[metadata]
|
||||
name = "gh-issues"
|
||||
description = "List GitHub issues for the current repo"
|
||||
requirements = ["gh", "jq"]
|
||||
|
||||
[source]
|
||||
command = '''gh issue list --state open --limit 100 --json number,title,createdAt,author,labels | jq -r 'sort_by(.createdAt) | reverse | .[] | " \u001b[32m#\(.number)\u001b[39m \(.title) \u001b[33m@\(.author.login)\u001b[39m" + (if (.labels | length) > 0 then " " + ([.labels[] | "\u001b[35m" + .name + "\u001b[39m"] | join(" ")) else "" end)'
|
||||
'''
|
||||
ansi = true
|
||||
output = "{strip_ansi|split:#:1|split: :0}"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
preview_panel = { header = '{strip_ansi|split:#:1|split: :0}', border_type = "none", scrollbar = false, padding = { left = 2, right = 1, top = 0, bottom = 0 } }
|
||||
|
||||
[preview]
|
||||
command = '''gh issue view '{strip_ansi|split:#:1|split: :0}' --json number,title,body,state,author,createdAt,updatedAt,labels,assignees | jq -r '
|
||||
" " + .title,
|
||||
" #" + (.number | tostring),
|
||||
"",
|
||||
" \u001b[36mStatus:\u001b[39m \u001b[32m" + .state + "\u001b[39m",
|
||||
" \u001b[36mAuthor:\u001b[39m \u001b[33m" + .author.login + "\u001b[39m",
|
||||
" \u001b[36mCreated:\u001b[39m " + (.createdAt | fromdateiso8601 | (now - .) | if . < 3600 then (./60|floor|tostring) + " minutes ago" elif . < 86400 then (./3600|floor|tostring) + " hours ago" else (./86400|floor|tostring) + " days ago" end),
|
||||
" \u001b[36mUpdated:\u001b[39m " + (.updatedAt | fromdateiso8601 | (now - .) | if . < 3600 then (./60|floor|tostring) + " minutes ago" elif . < 86400 then (./3600|floor|tostring) + " hours ago" else (./86400|floor|tostring) + " days ago" end),
|
||||
(if (.labels | length) > 0 then " \u001b[36mLabels:\u001b[39m " + ([.labels[] | "\u001b[35m" + .name + "\u001b[39m"] | join(" ")) else "" end),
|
||||
(if (.assignees | length) > 0 then " \u001b[36mAssignees:\u001b[39m " + ([.assignees[].login] | join(", ")) else "" end),
|
||||
"",
|
||||
" \u001b[90m────────────────────────────────────────────────────────────\u001b[39m",
|
||||
"",
|
||||
(.body // "")'
|
||||
'''
|
||||
|
||||
[actions.open]
|
||||
description = "Open the issue in the browser"
|
||||
command = "gh issue view {strip_ansi|split:#:1|split: :0} --web"
|
||||
mode = "fork"
|
||||
|
||||
[actions.close]
|
||||
description = "Close the selected issue"
|
||||
command = "gh issue close {strip_ansi|split:#:1|split: :0}"
|
||||
mode = "fork"
|
||||
|
||||
[actions.comment]
|
||||
description = "Add a comment to the selected issue"
|
||||
command = "gh issue comment {strip_ansi|split:#:1|split: :0}"
|
||||
mode = "execute"
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
[metadata]
|
||||
name = "gh-prs"
|
||||
description = "List GitHub PRs for the current repo"
|
||||
requirements = ["gh", "jq"]
|
||||
|
||||
[source]
|
||||
command = '''gh pr list --state open --limit 100 --json number,title,createdAt,author,labels | jq -r 'sort_by(.createdAt) | reverse | .[] | " \u001b[32m#\(.number)\u001b[39m \(.title) \u001b[33m@\(.author.login)\u001b[39m" + (if (.labels | length) > 0 then " " + ([.labels[] | "\u001b[35m" + .name + "\u001b[39m"] | join(" ")) else "" end)'
|
||||
'''
|
||||
output = '{strip_ansi|split:#:1|split: :0}'
|
||||
ansi = true
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
|
||||
[preview]
|
||||
command = '''gh pr view '{strip_ansi|split:#:1|split: :0}' --json number,title,body,state,headRefName,baseRefName,author,createdAt,updatedAt,mergeable,changedFiles,additions,deletions,labels,assignees,reviewDecision,headRepository,headRepositoryOwner | jq -r '
|
||||
" " + .title,
|
||||
" #" + (.number | tostring),
|
||||
"",
|
||||
" \u001b[36mStatus:\u001b[39m \u001b[32m" + .state + "\u001b[39m " + .baseRefName + " ← " + .headRefName,
|
||||
" \u001b[36mRepo:\u001b[39m \u001b[34m" + (.headRepositoryOwner.login) + "/" + (.headRepository.name) + "\u001b[39m",
|
||||
" \u001b[36mAuthor:\u001b[39m \u001b[33m" + .author.login + "\u001b[39m",
|
||||
" \u001b[36mCreated:\u001b[39m " + (.createdAt | fromdateiso8601 | (now - .) | if . < 3600 then (./60|floor|tostring) + " minutes ago" elif . < 86400 then (./3600|floor|tostring) + " hours ago" else (./86400|floor|tostring) + " days ago" end),
|
||||
" \u001b[36mUpdated:\u001b[39m " + (.updatedAt | fromdateiso8601 | (now - .) | if . < 3600 then (./60|floor|tostring) + " minutes ago" elif . < 86400 then (./3600|floor|tostring) + " hours ago" else (./86400|floor|tostring) + " days ago" end),
|
||||
(if (.labels | length) > 0 then " \u001b[36mLabels:\u001b[39m " + ([.labels[] | "\u001b[35m" + .name + "\u001b[39m"] | join(" ")) else "" end),
|
||||
" \u001b[36mMerge Status:\u001b[39m " + (if .mergeable == "MERGEABLE" then "\u001b[32m✓ Clean\u001b[39m" elif .mergeable == "CONFLICTING" then "\u001b[31m✗ Dirty\u001b[39m" else "\u001b[33m? Unknown\u001b[39m" end),
|
||||
" \u001b[36mChanges:\u001b[39m " + (.changedFiles | tostring) + " files \u001b[32m+" + (.additions | tostring) + "\u001b[39m \u001b[31m-" + (.deletions | tostring) + "\u001b[39m",
|
||||
"",
|
||||
" \u001b[90m────────────────────────────────────────────────────────────\u001b[39m",
|
||||
"",
|
||||
(.body // "")'
|
||||
'''
|
||||
|
||||
[actions.open]
|
||||
description = "Open the PR in the browser"
|
||||
command = "gh pr view {strip_ansi|split:#:1|split: :0} --web"
|
||||
mode = "execute"
|
||||
|
||||
[actions.checkout]
|
||||
description = "Checkout the PR branch locally"
|
||||
command = "gh pr checkout {strip_ansi|split:#:1|split: :0}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.merge]
|
||||
description = "Merge the selected PR"
|
||||
command = "gh pr merge {strip_ansi|split:#:1|split: :0}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.diff]
|
||||
description = "View the PR diff"
|
||||
command = "gh pr diff {strip_ansi|split:#:1|split: :0} | less"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,87 @@
|
||||
[metadata]
|
||||
name = "ghq-repos"
|
||||
description = """
|
||||
ghq repositories (plus the chezmoi source tree) and Obsidian vaults, newest
|
||||
git activity first. Enter prints the directory; the gho shell function (ctrl-o
|
||||
in fish, zsh and bash) cds into it.
|
||||
"""
|
||||
requirements = ["ghq", "fd", "git", "serie", "onefetch", "mtime-sort"]
|
||||
|
||||
# Entries are "<name>\t<absolute path>": the name is what you fuzzy-match, the
|
||||
# path is what enter prints. ctrl-s cycles repos → vaults.
|
||||
[source]
|
||||
command = [
|
||||
{ name = "Repos", run = '''
|
||||
root=$(ghq root)
|
||||
{
|
||||
# Checkouts living outside ghq root, listed first so they win over a ghq
|
||||
# clone of the same repo: chezmoi's source (github.com/prdlk/dotfiles) and
|
||||
# the nvim config (github.com/prdlk/nvim).
|
||||
c=$HOME/.local/share/chezmoi
|
||||
[ -d "$c/.git" ] && printf 'github.com/prdlk/dotfiles\t%s\n' "$c"
|
||||
n=$HOME/.config/nvim
|
||||
[ -d "$n/.git" ] && printf 'github.com/prdlk/nvim\t%s\n' "$n"
|
||||
ghq list | awk -v r="$root" '{ print $0 "\t" r "/" $0 }'
|
||||
} | awk -F '\t' '!seen[$1]++' | mtime-sort --repo
|
||||
''' },
|
||||
{ name = "Vaults", run = '''
|
||||
v=$HOME/Documents/Obsidian
|
||||
fd -H -t d -d 3 '^\.obsidian$' "$v" -x dirname |
|
||||
awk -v r="$v/" '{ print substr($0, length(r) + 1) "\t" $0 }' |
|
||||
mtime-sort
|
||||
''' },
|
||||
]
|
||||
shell = "bash"
|
||||
display = "{split:\\t:0}"
|
||||
output = "{split:\\t:1}"
|
||||
|
||||
# Two previews, ctrl-f cycles: commit graph (default), then onefetch. serie
|
||||
# itself cannot draw here -- it is a fullscreen TUI that paints the graph with
|
||||
# kitty images and has no print mode -- so ctrl-g (history) opens it.
|
||||
[preview]
|
||||
command = [
|
||||
'''
|
||||
d='{split:\t:1}'
|
||||
if [ -e "$d/.git" ]; then
|
||||
git -C "$d" log --graph --all --color=always --date=relative -n 300 \
|
||||
--format='%C(yellow)%h%C(reset) %C(blue)%<(12,trunc)%ad%C(reset) %s%C(auto)%d' 2>&1
|
||||
else
|
||||
eza --tree --level 2 --color=always "$d" 2>/dev/null || ls -la "$d"
|
||||
fi
|
||||
''',
|
||||
'''
|
||||
d='{split:\t:1}'
|
||||
if [ -e "$d/.git" ]; then
|
||||
onefetch --no-art "$d" 2>&1
|
||||
else
|
||||
eza --tree --level 2 --color=always "$d" 2>/dev/null || ls -la "$d"
|
||||
fi
|
||||
''',
|
||||
]
|
||||
shell = "bash"
|
||||
|
||||
# ctrl-e (edit) is bound globally in config.toml.
|
||||
[keybindings]
|
||||
ctrl-b = "actions:browse"
|
||||
ctrl-g = "actions:history"
|
||||
|
||||
[actions.edit]
|
||||
description = "Open the repository in nvim"
|
||||
# /dev/tty: the gho wrapper captures tv's stdout to read the picked path.
|
||||
command = "cd '{split:\\t:1}' && nvim . </dev/tty >/dev/tty"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
|
||||
[actions.browse]
|
||||
description = "Open the repository's web page (gop)"
|
||||
command = "cd '{split:\\t:1}' && gop >/dev/null 2>&1"
|
||||
shell = "bash"
|
||||
mode = "fork"
|
||||
|
||||
[actions.history]
|
||||
description = "Browse the commit graph in serie"
|
||||
# Fork: quitting serie (q) returns to the picker. /dev/tty for the same reason
|
||||
# as edit; serie also needs a real tty to detect kitty graphics.
|
||||
command = "cd '{split:\\t:1}' && [ -e .git ] && serie </dev/tty >/dev/tty"
|
||||
shell = "bash"
|
||||
mode = "fork"
|
||||
@@ -0,0 +1,37 @@
|
||||
[metadata]
|
||||
name = "git-branch"
|
||||
description = "A channel to select from git branches"
|
||||
requirements = ["git"]
|
||||
|
||||
[source]
|
||||
command = "git --no-pager branch --all --format=\"%(refname:short)\""
|
||||
output = "{split: :0}"
|
||||
|
||||
[preview]
|
||||
command = "git show -p --stat --pretty=fuller --color=always '{0}'"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:checkout"
|
||||
ctrl-d = "actions:delete"
|
||||
ctrl-m = "actions:merge"
|
||||
ctrl-r = "actions:rebase"
|
||||
|
||||
[actions.checkout]
|
||||
description = "Checkout the selected branch"
|
||||
command = "git checkout '{0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.delete]
|
||||
description = "Delete the selected branch"
|
||||
command = "git branch -d '{0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.merge]
|
||||
description = "Merge the selected branch into current branch"
|
||||
command = "git merge '{0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.rebase]
|
||||
description = "Rebase current branch onto the selected branch"
|
||||
command = "git rebase '{0}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,24 @@
|
||||
[metadata]
|
||||
name = "git-deletions"
|
||||
description = "A channel to list files which were deleted from the Git repository"
|
||||
requirements = ["git", "rg", "bat"]
|
||||
|
||||
[source]
|
||||
command = "git log --diff-filter=D --summary | rg 'delete mode \\d+' -r '' --trim"
|
||||
|
||||
[preview]
|
||||
command = ["git show \"$(git rev-list -n1 HEAD -- '{}')^:{}\" | bat -n --color always --file-name '{}'", "git show --summary \"$(git rev-list -n1 HEAD -- '{}')\""]
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:print_commit"
|
||||
ctrl-r = "actions:restore_file"
|
||||
|
||||
[actions.print_commit]
|
||||
description = "Print the latest commit where file was deleted"
|
||||
command = "echo \"$(git rev-list -n1 HEAD -- {})\""
|
||||
mode = "execute"
|
||||
|
||||
[actions.restore_file]
|
||||
description = "Restore the selected file"
|
||||
command = "git checkout \"$(git rev-list -n1 HEAD -- {})^\" -- {}"
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
[metadata]
|
||||
name = "git-diff"
|
||||
description = "A channel to select files from git diff commands"
|
||||
requirements = ["git"]
|
||||
|
||||
[source]
|
||||
command = "git diff --name-only HEAD"
|
||||
|
||||
[preview]
|
||||
command = "git diff HEAD --color=always -- '{}'"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
|
||||
[keybindings]
|
||||
ctrl-s = "actions:stage"
|
||||
ctrl-r = "actions:restore"
|
||||
ctrl-e = "actions:edit"
|
||||
|
||||
[actions.stage]
|
||||
description = "Stage the selected file"
|
||||
command = "git add {}"
|
||||
mode = "fork"
|
||||
|
||||
[actions.restore]
|
||||
description = "Discard changes in the selected file"
|
||||
command = "git restore {}"
|
||||
mode = "fork"
|
||||
|
||||
[actions.edit]
|
||||
description = "Open the selected file in editor"
|
||||
command = "${EDITOR:-vim} {}"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,35 @@
|
||||
[metadata]
|
||||
name = "git-files"
|
||||
description = """
|
||||
Files tracked in the current git repository, most recently modified first
|
||||
(all files under the cwd outside a repo). Enter opens the selection in nvim;
|
||||
bound to ctrl-e in fish, zsh and bash.
|
||||
"""
|
||||
requirements = ["git", "fd", "bat", "mtime-sort"]
|
||||
|
||||
[source]
|
||||
command = [
|
||||
{ name = "Tracked", run = '''
|
||||
if top=$(git rev-parse --show-toplevel 2>/dev/null); then
|
||||
git -c core.quotePath=false ls-files -- "$top"
|
||||
else
|
||||
fd -t f
|
||||
fi | mtime-sort
|
||||
''' },
|
||||
{ name = "All", run = "fd -t f -H -E .git | mtime-sort" },
|
||||
]
|
||||
shell = "bash"
|
||||
|
||||
[preview]
|
||||
command = "bat -n --color=always '{}'"
|
||||
env = { BAT_THEME = "ansi" }
|
||||
|
||||
# ctrl-e (edit) is bound globally in config.toml.
|
||||
[keybindings]
|
||||
enter = "actions:edit"
|
||||
|
||||
[actions.edit]
|
||||
description = "Opens the selected entries in nvim"
|
||||
command = "nvim {} </dev/tty >/dev/tty"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,34 @@
|
||||
[metadata]
|
||||
name = "git-log"
|
||||
description = "A channel to select from git log entries"
|
||||
requirements = ["git"]
|
||||
|
||||
[source]
|
||||
command = "git log --graph --pretty=format:'%C(yellow)%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --color=always"
|
||||
output = "{strip_ansi|split: :1}"
|
||||
ansi = true
|
||||
no_sort = true
|
||||
frecency = false
|
||||
|
||||
[preview]
|
||||
command = "git show -p --stat --pretty=fuller --color=always '{strip_ansi|split: :1}' | head -n 1000"
|
||||
|
||||
[keybindings]
|
||||
ctrl-y = "actions:cherry-pick"
|
||||
ctrl-r = "actions:revert"
|
||||
ctrl-o = "actions:checkout"
|
||||
|
||||
[actions.cherry-pick]
|
||||
description = "Cherry-pick the selected commit"
|
||||
command = "git cherry-pick '{strip_ansi|split: :1}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.revert]
|
||||
description = "Revert the selected commit"
|
||||
command = "git revert '{strip_ansi|split: :1}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.checkout]
|
||||
description = "Checkout the selected commit"
|
||||
command = "git checkout '{strip_ansi|split: :1}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,28 @@
|
||||
[metadata]
|
||||
name = "git-reflog"
|
||||
description = "A channel to select from git reflog entries"
|
||||
requirements = ["git"]
|
||||
|
||||
[source]
|
||||
command = "git reflog --decorate --color=always"
|
||||
output = "{0|strip_ansi}"
|
||||
ansi = true
|
||||
no_sort = true
|
||||
frecency = false
|
||||
|
||||
[preview]
|
||||
command = "git show -p --stat --pretty=fuller --color=always '{0|strip_ansi}'"
|
||||
|
||||
[keybindings]
|
||||
ctrl-o = "actions:checkout"
|
||||
ctrl-r = "actions:reset"
|
||||
|
||||
[actions.checkout]
|
||||
description = "Checkout the selected reflog entry"
|
||||
command = "git checkout '{0|strip_ansi}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.reset]
|
||||
description = "Reset --hard to the selected reflog entry"
|
||||
command = "git reset --hard '{0|strip_ansi}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,20 @@
|
||||
[metadata]
|
||||
name = "git-remotes"
|
||||
description = "List and manage git remotes"
|
||||
requirements = ["git"]
|
||||
|
||||
[source]
|
||||
command = "git remote"
|
||||
|
||||
[preview]
|
||||
command = "git remote show '{}'"
|
||||
|
||||
[actions.fetch]
|
||||
description = "Fetch from the selected remote"
|
||||
command = "git fetch {}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.remove]
|
||||
description = "Remove the selected remote"
|
||||
command = "git remote remove {}"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,31 @@
|
||||
[metadata]
|
||||
name = "git-repos"
|
||||
requirements = ["fd", "git"]
|
||||
description = """
|
||||
A channel to select from git repositories on your local machine.
|
||||
|
||||
This channel uses `fd` to find directories that contain a `.git` subdirectory, and then allows you to preview the git log of the selected repository.
|
||||
"""
|
||||
|
||||
[source]
|
||||
# this is a macos version of the command. While perfectly usable on linux, you may want to tweak it a bit.
|
||||
command = "fd -g .git -HL -t d -d 10 --prune ~ -E 'Library' -E 'Application Support' --exec dirname '{}'"
|
||||
display = "{split:/:-1}"
|
||||
|
||||
[preview]
|
||||
command = "cd '{}'; git log -n 200 --pretty=medium --all --graph --color"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:cd"
|
||||
ctrl-e = "actions:edit"
|
||||
|
||||
[actions.cd]
|
||||
description = "Open a new shell in the selected repository"
|
||||
command = "cd {} && $SHELL"
|
||||
mode = "execute"
|
||||
|
||||
[actions.edit]
|
||||
description = "Open the repository in editor"
|
||||
command = "${EDITOR:-vim} {}"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,37 @@
|
||||
[metadata]
|
||||
name = "git-stash"
|
||||
description = "Browse and manage git stash entries"
|
||||
requirements = ["git"]
|
||||
|
||||
[source]
|
||||
command = "git stash list --color=always"
|
||||
ansi = true
|
||||
output = "{strip_ansi|split:\\::0}"
|
||||
no_sort = true
|
||||
frecency = false
|
||||
|
||||
[preview]
|
||||
command = "git stash show -p --color=always '{strip_ansi|split:\\::0}'"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:apply"
|
||||
ctrl-p = "actions:pop"
|
||||
ctrl-d = "actions:drop"
|
||||
|
||||
[actions.apply]
|
||||
description = "Apply the selected stash"
|
||||
command = "git stash apply '{strip_ansi|split:\\::0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.pop]
|
||||
description = "Pop the selected stash (apply and remove)"
|
||||
command = "git stash pop '{strip_ansi|split:\\::0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.drop]
|
||||
description = "Drop the selected stash"
|
||||
command = "git stash drop '{strip_ansi|split:\\::0}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,20 @@
|
||||
[metadata]
|
||||
name = "git-submodules"
|
||||
description = "List and manage git submodules"
|
||||
requirements = ["git"]
|
||||
|
||||
[source]
|
||||
command = "git submodule status | awk '{print $2}'"
|
||||
|
||||
[preview]
|
||||
command = "git -C '{}' log --oneline -10 --color=always"
|
||||
|
||||
[actions.update]
|
||||
description = "Update the selected submodule"
|
||||
command = "git submodule update --init --recursive {}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.sync]
|
||||
description = "Sync the selected submodule URL"
|
||||
command = "git submodule sync {}"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,26 @@
|
||||
[metadata]
|
||||
name = "git-tags"
|
||||
description = "Browse and checkout git tags"
|
||||
requirements = ["git"]
|
||||
|
||||
[source]
|
||||
command = "git tag --sort=-creatordate"
|
||||
no_sort = true
|
||||
frecency = false
|
||||
|
||||
[preview]
|
||||
command = "git show --color=always '{}'"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:checkout"
|
||||
ctrl-d = "actions:delete"
|
||||
|
||||
[actions.checkout]
|
||||
description = "Checkout the selected tag"
|
||||
command = "git checkout {}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.delete]
|
||||
description = "Delete the selected tag"
|
||||
command = "git tag -d {}"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,24 @@
|
||||
[metadata]
|
||||
name = "git-worktrees"
|
||||
description = "List and switch between git worktrees"
|
||||
requirements = ["git"]
|
||||
|
||||
[source]
|
||||
command = "git worktree list --porcelain | grep '^worktree' | cut -d' ' -f2-"
|
||||
|
||||
[preview]
|
||||
command = "cd '{}' && git log --oneline -10 --color=always && echo && git status --short"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:cd"
|
||||
ctrl-d = "actions:remove"
|
||||
|
||||
[actions.cd]
|
||||
description = "Change to the selected worktree"
|
||||
command = "cd {} && $SHELL"
|
||||
mode = "execute"
|
||||
|
||||
[actions.remove]
|
||||
description = "Remove the selected worktree"
|
||||
command = "git worktree remove {}"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,21 @@
|
||||
[metadata]
|
||||
name = "images"
|
||||
description = "Browse image files with preview"
|
||||
requirements = ["fd", "chafa"]
|
||||
|
||||
[source]
|
||||
command = [
|
||||
{ name = "Default", run = "fd -t f -e png -e jpg -e jpeg -e gif -e webp -e bmp -e svg ." },
|
||||
{ name = "Hidden", run = "fd -t f -e png -e jpg -e jpeg -e gif -e webp -e bmp -e svg -H ." },
|
||||
]
|
||||
|
||||
[preview]
|
||||
command = "chafa -s 80x40 '{}' 2>/dev/null || file '{}'"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:open"
|
||||
|
||||
[actions.open]
|
||||
description = "Open the selected image with default viewer"
|
||||
command = "xdg-open {} 2>/dev/null || open {}"
|
||||
mode = "fork"
|
||||
@@ -0,0 +1,57 @@
|
||||
[metadata]
|
||||
name = "jobs"
|
||||
description = """
|
||||
The current fish shell's background jobs (stopped or running). tv runs in a
|
||||
child process and cannot see the shell's job table, so the ctrl-z binding
|
||||
(_jobs_bind) writes it to the file named by $TV_JOBS; enter prints the job id
|
||||
and the binding runs `fg %<id>`; ctrl-d kills the job. Opened any other way,
|
||||
the list is empty.
|
||||
"""
|
||||
requirements = ["ps"]
|
||||
|
||||
# Record: "%<id> <state> <command>", job id, process group (tab separated).
|
||||
# Newest job first, the order fish's `jobs` prints.
|
||||
[source]
|
||||
command = '[ -n "$TV_JOBS" ] && [ -r "$TV_JOBS" ] && cat "$TV_JOBS"'
|
||||
shell = "bash"
|
||||
display = "{split:\\t:0}"
|
||||
output = "{split:\\t:1}"
|
||||
|
||||
[preview]
|
||||
command = '''
|
||||
pg='{split:\t:2}'
|
||||
# No other braces in this script: tv would read them as templates. procps
|
||||
# `ps -g` matches sessions, not process groups, so filter on pgid by hand.
|
||||
pids=$(ps -e -o pgid=,pid= --sort=start_time | while read -r g p; do [ "$g" = "$pg" ] && echo "$p"; done)
|
||||
if [ -z "$pids" ]; then
|
||||
echo "process group $pg is gone"
|
||||
exit 0
|
||||
fi
|
||||
first=$(echo "$pids" | head -n1)
|
||||
printf '\033[1mcwd\033[0m %s\n' "$(readlink "/proc/$first/cwd" 2>/dev/null || echo '?')"
|
||||
printf '\033[1mstarted\033[0m %s\n\n' "$(ps -o lstart= -p "$first" | sed 's/^ *//')"
|
||||
# STAT T = stopped (ctrl-z), S/R = running in the background.
|
||||
ps -o pid,stat,etime,pcpu,rss,args --forest -p "$(echo $pids | tr ' ' ,)"
|
||||
'''
|
||||
shell = "bash"
|
||||
|
||||
[keybindings]
|
||||
ctrl-d = ["actions:kill", "reload_source"]
|
||||
|
||||
# SIGTERM to the whole process group, then SIGCONT: a stopped job holds TERM
|
||||
# until it runs again. The row leaves $TV_JOBS only once the group is gone
|
||||
# (up to 1 s), so reload_source keeps a job that ignored TERM. No braces: tv
|
||||
# would read them as templates.
|
||||
[actions.kill]
|
||||
description = "Kill the job (SIGTERM to its process group)"
|
||||
command = '''
|
||||
pg='{split:\t:2}'
|
||||
kill -TERM -- "-$pg" 2>/dev/null
|
||||
kill -CONT -- "-$pg" 2>/dev/null
|
||||
for i in 1 2 3 4 5 6 7 8 9 10; do kill -0 -- "-$pg" 2>/dev/null || break; sleep 0.1; done
|
||||
if ! kill -0 -- "-$pg" 2>/dev/null && [ -w "$TV_JOBS" ]; then
|
||||
awk -F '\t' -v g="$pg" '$3 != g' "$TV_JOBS" >"$TV_JOBS.new" && mv "$TV_JOBS.new" "$TV_JOBS"
|
||||
fi
|
||||
'''
|
||||
shell = "bash"
|
||||
mode = "fork"
|
||||
@@ -0,0 +1,24 @@
|
||||
[metadata]
|
||||
name = "journal"
|
||||
description = "Browse systemd journal log identifiers and their logs"
|
||||
requirements = ["journalctl"]
|
||||
|
||||
[source]
|
||||
command = "journalctl --field SYSLOG_IDENTIFIER 2>/dev/null | sort -f"
|
||||
|
||||
[preview]
|
||||
command = "journalctl -b --no-pager -o short-iso -n 50 SYSLOG_IDENTIFIER='{}' 2>/dev/null"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
preview_panel = { size = 70, border_type = "none", scrollbar = false, padding = { left = 2, right = 1, top = 0, bottom = 0 } }
|
||||
|
||||
[actions.logs]
|
||||
description = "Follow live logs for the selected identifier"
|
||||
command = "journalctl -f SYSLOG_IDENTIFIER={}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.full]
|
||||
description = "View all logs for the selected identifier in a pager"
|
||||
command = "journalctl -b --no-pager -o short-iso SYSLOG_IDENTIFIER={} | less"
|
||||
mode = "fork"
|
||||
@@ -0,0 +1,18 @@
|
||||
[metadata]
|
||||
name = "just-recipes"
|
||||
description = "A channel to select recipes from Justfiles"
|
||||
requirements = ["just"]
|
||||
|
||||
[source]
|
||||
command = ["just --summary | tr '[:blank:]' '\n'"]
|
||||
|
||||
[preview]
|
||||
command = "just -s {}"
|
||||
|
||||
[keybindings]
|
||||
f5 = "actions:execute-recipe"
|
||||
|
||||
[actions.execute-recipe]
|
||||
description = "Execute a justfile recipe"
|
||||
command = "just {}"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,75 @@
|
||||
[metadata]
|
||||
name = "kitty-days"
|
||||
description = """
|
||||
Daily kitty sessions saved by ~/.config/kitty/day_session.py, last modified
|
||||
first. The preview lists each tab's windows (cwd, the program restored in it)
|
||||
with the tail of its saved scrollback. Enter opens the day in a new kitty.
|
||||
"""
|
||||
requirements = ["kitty", "python3", "mtime-sort"]
|
||||
|
||||
# Entries are "<day> <weekday> week of <monday> <n> tabs\t<session file>".
|
||||
[source]
|
||||
command = '''
|
||||
for f in "$HOME"/.local/share/kitty-sessions/*/*.kitty-session; do
|
||||
[ -e "$f" ] || continue
|
||||
day=$(basename "$f" .kitty-session)
|
||||
printf '%s %s week of %s %s tabs\t%s\n' "$day" "$(date -d "$day" +%a)" \
|
||||
"$(basename "$(dirname "$f")")" "$(grep -c '^new_tab' "$f")" "$f"
|
||||
done | mtime-sort
|
||||
'''
|
||||
shell = "bash"
|
||||
display = "{split:\\t:0}"
|
||||
output = "{split:\\t:1}"
|
||||
|
||||
# The script avoids braces: tv would read them as templates.
|
||||
[preview]
|
||||
command = '''
|
||||
python3 - '{split:\t:1}' <<'PY'
|
||||
import json, os, shlex, sys
|
||||
|
||||
FLAG = 'kitty-unserialize-data='
|
||||
home = os.path.expanduser('~')
|
||||
tab, cwd = 0, ''
|
||||
for line in open(sys.argv[1]).read().splitlines():
|
||||
word, _, rest = line.partition(' ')
|
||||
if word == 'new_tab':
|
||||
tab += 1
|
||||
print('\x1b[1mtab %d\x1b[m' % tab)
|
||||
elif word == 'cd':
|
||||
cwd = shlex.split(rest)[0]
|
||||
elif word == 'launch':
|
||||
args = shlex.split(rest)
|
||||
data = json.loads(args.pop(0)[len(FLAG):]) if args and args[0].startswith(FLAG) else dict()
|
||||
wcwd = next((a.partition('=')[2] for a in args if a.startswith('--cwd=')), cwd)
|
||||
cmd = [a for a in args if not a.startswith('-')] # kitty writes every option as --opt=value
|
||||
dump, program = '', shlex.join(cmd)
|
||||
for step in data.get('cmd_at_shell_startup', '').split('; '):
|
||||
if step.startswith('cat '):
|
||||
dump = shlex.split(step)[1]
|
||||
elif step:
|
||||
program = step
|
||||
print(' \x1b[36m%s\x1b[m %s' % (wcwd.replace(home, '~', 1), program))
|
||||
if dump and os.path.exists(dump):
|
||||
for l in open(dump, errors='replace').read().splitlines()[-6:]:
|
||||
print(' ' + l + '\x1b[m')
|
||||
PY
|
||||
'''
|
||||
shell = "bash"
|
||||
|
||||
# ctrl-e (edit) is bound globally in config.toml.
|
||||
[keybindings]
|
||||
enter = "actions:open"
|
||||
|
||||
# Today's file, while no running kitty owns it, comes back as the live day
|
||||
# (saved again); any other day is a read-only snapshot.
|
||||
[actions.open]
|
||||
description = "Open the day in a new kitty"
|
||||
command = "setsid -f kitty --session '{split:\\t:1}' >/dev/null 2>&1"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
|
||||
[actions.edit]
|
||||
description = "Open the session file in nvim"
|
||||
command = "nvim '{split:\\t:1}' </dev/tty >/dev/tty"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,18 @@
|
||||
[metadata]
|
||||
name = "make-targets"
|
||||
description = "List and run Makefile targets"
|
||||
requirements = ["make", "awk"]
|
||||
|
||||
[source]
|
||||
command = "make -pRrq 2>/dev/null | awk -F: '/^[a-zA-Z0-9][^$#\\/\\t=]*:([^=]|$)/ {split($1,a,\" \"); print a[1]}' | sort -u | grep -v '^Makefile$'"
|
||||
|
||||
[preview]
|
||||
command = "awk '/^{}[[:space:]]*:/{found=1} found{print; if(/^[^\\t]/ && NR>1 && !/^{}[[:space:]]*:/) exit}' Makefile"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:run"
|
||||
|
||||
[actions.run]
|
||||
description = "Run the selected make target"
|
||||
command = "make {}"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,25 @@
|
||||
[metadata]
|
||||
name = "man-pages"
|
||||
description = "Browse and preview system manual pages"
|
||||
requirements = ["apropos", "man"]
|
||||
|
||||
[source]
|
||||
# List all man pages using apropos
|
||||
command = "apropos ."
|
||||
|
||||
[preview]
|
||||
# Show the man page for the selected entry
|
||||
command = "man '{0}'"
|
||||
env = { "MANWIDTH" = "80" }
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:open"
|
||||
|
||||
[actions.open]
|
||||
description = "Open the selected man page in the system pager"
|
||||
command = "man '{0}'"
|
||||
mode = "execute"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
preview_panel = { header = "{0}", border_type = "none", scrollbar = false, padding = { left = 2, right = 1, top = 0, bottom = 0 } }
|
||||
@@ -0,0 +1,19 @@
|
||||
[metadata]
|
||||
name = "mounts"
|
||||
description = "List mounted filesystems"
|
||||
requirements = ["df", "awk"]
|
||||
|
||||
[source]
|
||||
command = "df -h --output=target,fstype,size,used,avail,pcent 2>/dev/null | tail -n +2"
|
||||
display = "{split: :0}"
|
||||
|
||||
[preview]
|
||||
command = "df -h '{}' && echo && ls -la '{}' 2>/dev/null | head -20"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:cd"
|
||||
|
||||
[actions.cd]
|
||||
description = "Open a shell in the selected mount point"
|
||||
command = "cd {} && $SHELL"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,21 @@
|
||||
[metadata]
|
||||
name = "node-packages"
|
||||
description = "Browse local node_modules dependencies"
|
||||
requirements = ["node"]
|
||||
|
||||
[source]
|
||||
command = "ls -d node_modules/*/ 2>/dev/null | sed 's|node_modules/||;s|/$||' | grep -v '^\\.'"
|
||||
output = "{}"
|
||||
|
||||
[preview]
|
||||
command = "cat 'node_modules/{}/package.json' 2>/dev/null | jq -C '{name, version, description, license, homepage, main}'"
|
||||
|
||||
[actions.readme]
|
||||
description = "View the package README"
|
||||
command = "cat node_modules/{}/README.md 2>/dev/null | less"
|
||||
mode = "execute"
|
||||
|
||||
[actions.homepage]
|
||||
description = "Open the package homepage"
|
||||
command = "node -e \"const p=require('./node_modules/{}/package.json'); const u=p.homepage||'https://www.npmjs.com/package/'+p.name; require('child_process').exec('xdg-open '+u)\""
|
||||
mode = "fork"
|
||||
@@ -0,0 +1,20 @@
|
||||
[metadata]
|
||||
name = "npm-packages"
|
||||
description = "List globally installed npm packages"
|
||||
requirements = ["npm"]
|
||||
|
||||
[source]
|
||||
command = "npm list -g --depth=0 --parseable 2>/dev/null | tail -n +2 | xargs -I{} basename {}"
|
||||
|
||||
[preview]
|
||||
command = "npm info '{}' 2>/dev/null | head -30"
|
||||
|
||||
[actions.uninstall]
|
||||
description = "Uninstall the selected global package"
|
||||
command = "npm uninstall -g {}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.update]
|
||||
description = "Update the selected global package"
|
||||
command = "npm update -g {}"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,25 @@
|
||||
[metadata]
|
||||
name = "npm-scripts"
|
||||
description = "List and run npm scripts from package.json"
|
||||
requirements = ["jq"]
|
||||
|
||||
[source]
|
||||
command = "jq -r '.scripts | to_entries[] | \"\\(.key)\\t\\(.value)\"' package.json 2>/dev/null"
|
||||
display = "{split:\\t:0}"
|
||||
|
||||
[preview]
|
||||
command = "jq -r '.scripts[\"{split:\\t:0}\"]' package.json"
|
||||
|
||||
[ui.preview_panel]
|
||||
border_type = "none"
|
||||
scrollbar = false
|
||||
padding = { left = 2, right = 1, top = 0, bottom = 0 }
|
||||
size = 30
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:run"
|
||||
|
||||
[actions.run]
|
||||
description = "Run the selected npm script"
|
||||
command = "npm run '{split:\\t:0}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
[metadata]
|
||||
name = "nu-history"
|
||||
description = "A channel to select from your nu history"
|
||||
|
||||
[source]
|
||||
command = "nu -c 'open $nu.history-path | lines | uniq | reverse | to text'"
|
||||
no_sort = true
|
||||
frecency = false
|
||||
@@ -0,0 +1,66 @@
|
||||
[metadata]
|
||||
name = "obsidian"
|
||||
description = """
|
||||
Obsidian vaults under ~/Documents/Obsidian, most recently modified first.
|
||||
Enter opens the vault in Obsidian; vaults Obsidian has never opened are
|
||||
registered in obsidian.json first.
|
||||
"""
|
||||
requirements = ["fd", "jq", "eza", "obsidian", "xdg-open", "mtime-sort"]
|
||||
|
||||
# Entries are "<name>\t<absolute path>": the name is what you fuzzy-match, the
|
||||
# path is what the actions use.
|
||||
[source]
|
||||
command = '''
|
||||
v=$HOME/Documents/Obsidian
|
||||
fd -H -t d -d 3 '^\.obsidian$' "$v" -x dirname |
|
||||
awk -v r="$v/" '{ print substr($0, length(r) + 1) "\t" $0 }' |
|
||||
mtime-sort
|
||||
'''
|
||||
shell = "bash"
|
||||
display = "{split:\\t:0}"
|
||||
output = "{split:\\t:1}"
|
||||
|
||||
[preview]
|
||||
command = "eza --tree --level 2 --color=always '{split:\\t:1}' 2>/dev/null || ls -la '{split:\\t:1}'"
|
||||
shell = "bash"
|
||||
|
||||
# ctrl-e (edit) is bound globally in config.toml.
|
||||
[keybindings]
|
||||
enter = "actions:open"
|
||||
|
||||
# obsidian://open?path= only resolves vaults listed in obsidian.json, and
|
||||
# Obsidian reads that file once at startup and rewrites it from memory. An
|
||||
# unlisted vault is therefore added only while Obsidian is closed; while it
|
||||
# runs, the vault switcher opens instead.
|
||||
[actions.open]
|
||||
description = "Open the vault in Obsidian"
|
||||
command = '''
|
||||
d='{split:\t:1}'
|
||||
cfg=${XDG_CONFIG_HOME:-$HOME/.config}/obsidian/obsidian.json
|
||||
uri="obsidian://open?path=$(jq -rn --arg p "$d" '$p | @uri')"
|
||||
if ! jq -e --arg p "$d" 'any(.vaults[]?; .path == $p)' "$cfg" >/dev/null 2>&1; then
|
||||
# [o]: keep pgrep from matching this script's own command line.
|
||||
if pgrep -f '[o]bsidian/app.asar' >/dev/null; then
|
||||
msg="Vault not registered and Obsidian is running: use 'Open folder as vault' for $d"
|
||||
echo "$msg" >&2
|
||||
notify-send Obsidian "$msg" 2>/dev/null
|
||||
uri="obsidian://choose-vault"
|
||||
else
|
||||
mkdir -p "${cfg%/*}"
|
||||
[ -s "$cfg" ] || echo '{}' >"$cfg"
|
||||
tmp=$(mktemp "$cfg.XXXXXX") || exit 1
|
||||
jq --arg id "$(od -An -N8 -tx1 /dev/urandom | tr -d ' \n')" --arg p "$d" \
|
||||
--argjson ts "$(date +%s%3N)" '.vaults[$id] = {path: $p, ts: $ts}' \
|
||||
"$cfg" >"$tmp" && mv "$tmp" "$cfg" || rm -f "$tmp"
|
||||
fi
|
||||
fi
|
||||
setsid -f xdg-open "$uri" >/dev/null 2>&1
|
||||
'''
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
|
||||
[actions.edit]
|
||||
description = "Open the vault in nvim"
|
||||
command = "cd '{split:\\t:1}' && nvim . </dev/tty >/dev/tty"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,38 @@
|
||||
[metadata]
|
||||
name = "omp-sessions"
|
||||
description = """
|
||||
omp sessions of the current git repo, newest first: age, the branch HEAD was
|
||||
on when the session was last written, and the title. The preview is the
|
||||
conversation's message text; enter resumes the session, ctrl-n starts a new
|
||||
one instead. Listing, preview, resume and new live in ~/.local/bin/omp-session,
|
||||
whose launcher (ctrl-a in fish and zsh) opens this cable when it has no
|
||||
session to resume on the default branch.
|
||||
"""
|
||||
requirements = ["omp-session", "omp"]
|
||||
|
||||
# Record: display, session file (tab separated).
|
||||
[source]
|
||||
command = "omp-session --list"
|
||||
shell = "bash"
|
||||
display = "{split:\\t:0}"
|
||||
output = "{split:\\t:1}"
|
||||
|
||||
[preview]
|
||||
command = "omp-session --preview '{split:\\t:1}'"
|
||||
shell = "bash"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:resume"
|
||||
ctrl-n = "actions:new"
|
||||
|
||||
[actions.resume]
|
||||
description = "Resume the session"
|
||||
command = "omp-session --resume '{split:\\t:1}'"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
|
||||
[actions.new]
|
||||
description = "Start a new omp session"
|
||||
command = "omp-session --new"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,38 @@
|
||||
[metadata]
|
||||
name = "opencode-sessions"
|
||||
description = "Browse and resume OpenCode sessions"
|
||||
requirements = ["opencode", "jq"]
|
||||
|
||||
[source]
|
||||
# Use literal strings (''') to avoid escape sequence errors
|
||||
command = '''opencode session list --format json | jq -r '.[] | "\(.id)\t\(.title)\t\(.directory)"' '''
|
||||
display = "{split:\t:1} ({split:\t:2})"
|
||||
output = "{split:\t:0}"
|
||||
|
||||
[preview]
|
||||
# We use triple single quotes so we don't have to escape the backslashes for jq or the template engine
|
||||
command = '''opencode session list --format json | jq -r '.[] | select(.id == "{split:\t:0}") | "TITLE: \(.title)\nID: \(.id)\nPROJECT: \(.projectId)\nDIRECTORY: \(.directory)\nUPDATED: \((.updated / 1000) | strftime("%Y-%m-%d %H:%M:%S"))"' '''
|
||||
|
||||
[ui]
|
||||
layout = "landscape"
|
||||
[ui.preview_panel]
|
||||
size = 60
|
||||
header = "Session: {split:\t:1}"
|
||||
border_type = "none"
|
||||
scrollbar = false
|
||||
padding = { left = 2, right = 1, top = 0, bottom = 0 }
|
||||
|
||||
[keybindings]
|
||||
shortcut = "f4"
|
||||
enter = "actions:resume"
|
||||
ctrl-d = "actions:delete"
|
||||
|
||||
[actions.resume]
|
||||
description = "Resume session"
|
||||
command = "opencode -s {split:\t:0}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.delete]
|
||||
description = "Delete session"
|
||||
command = '''bash -c 'echo "Delete {split:\t:1}?" && read -p "[y/N]: " conf && [[ $conf == "y" ]] && opencode session delete {split:\t:0} ' '''
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,21 @@
|
||||
[metadata]
|
||||
name = "pacman-packages"
|
||||
description = "List and manage installed pacman packages"
|
||||
requirements = ["pacman"]
|
||||
|
||||
[source]
|
||||
command = "pacman -Q"
|
||||
output = "{split: :0}"
|
||||
|
||||
[preview]
|
||||
command = "pacman -Qi '{split: :0}' 2>/dev/null"
|
||||
|
||||
[actions.remove]
|
||||
description = "Remove the selected package"
|
||||
command = "sudo pacman -R '{split: :0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.files]
|
||||
description = "List files owned by the selected package"
|
||||
command = "pacman -Ql '{split: :0}' | less"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,15 @@
|
||||
[metadata]
|
||||
name = "path"
|
||||
description = "Investigate PATH contents"
|
||||
requirements = ["fd", "bat"]
|
||||
|
||||
[source]
|
||||
command = "printf '%s\n' \"$PATH\" | tr ':' '\n'"
|
||||
|
||||
[preview]
|
||||
command = "fd -tx -d1 . \"{}\" -X printf \"%s\n\" \"{/}\" | sort -f | bat -n --color=always"
|
||||
|
||||
[actions.cd]
|
||||
description = "Open a shell in the selected PATH directory"
|
||||
command = "cd {} && $SHELL"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,24 @@
|
||||
[metadata]
|
||||
name = "pdf-files"
|
||||
description = "Browse PDF files"
|
||||
requirements = ["fd", "pdftotext"]
|
||||
|
||||
[source]
|
||||
command = [
|
||||
{ name = "Default", run = "fd -t f -e pdf ." },
|
||||
{ name = "Hidden", run = "fd -t f -e pdf -H ." },
|
||||
]
|
||||
|
||||
[preview]
|
||||
command = "pdftotext -l 2 -layout '{}' - 2>/dev/null | head -100 || file '{}'"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:open"
|
||||
|
||||
[actions.open]
|
||||
description = "Open the selected PDF with default viewer"
|
||||
command = "xdg-open {} 2>/dev/null || open {}"
|
||||
mode = "fork"
|
||||
@@ -0,0 +1,27 @@
|
||||
[metadata]
|
||||
name = "pip-packages"
|
||||
description = "List installed Python packages"
|
||||
requirements = ["pip"]
|
||||
|
||||
[source]
|
||||
command = "pip list --format=freeze 2>/dev/null | cut -d= -f1"
|
||||
|
||||
[preview]
|
||||
command = "pip show '{}'"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
|
||||
[keybindings]
|
||||
ctrl-u = "actions:upgrade"
|
||||
ctrl-d = "actions:uninstall"
|
||||
|
||||
[actions.upgrade]
|
||||
description = "Upgrade the selected package"
|
||||
command = "pip install --upgrade {}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.uninstall]
|
||||
description = "Uninstall the selected package"
|
||||
command = "pip uninstall {}"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,29 @@
|
||||
[metadata]
|
||||
name = "pj"
|
||||
description = """
|
||||
Project tasks from every task source between the cwd and the git toplevel
|
||||
(package.json, Makefile, justfile, mise, devbox, pyproject), tasks of the most
|
||||
recently modified manifest first. Enter runs the task. Discovery, preview and
|
||||
run live in ~/.local/bin/pj; `pj` (ctrl-p, and down on an empty prompt in fish,
|
||||
zsh and bash) opens this cable with its own scan.
|
||||
"""
|
||||
requirements = ["pj", "mtime-sort"]
|
||||
|
||||
# Record: display, kind, target, root, runner, manifest (tab separated).
|
||||
[source]
|
||||
command = "pj --list 2>/dev/null"
|
||||
shell = "bash"
|
||||
display = "{split:\\t:0}"
|
||||
|
||||
[preview]
|
||||
command = "pj --preview '{split:\\t:1}' '{split:\\t:2}' '{split:\\t:3}' '{split:\\t:5}'"
|
||||
shell = "bash"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:run"
|
||||
|
||||
[actions.run]
|
||||
description = "Run the selected task"
|
||||
command = "pj --run '{split:\\t:1}' '{split:\\t:2}' '{split:\\t:3}' '{split:\\t:4}'"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,22 @@
|
||||
[metadata]
|
||||
name = "ports"
|
||||
description = "List listening ports and associated processes"
|
||||
requirements = ["ss", "awk"]
|
||||
|
||||
[source]
|
||||
command = "ss -tlnp 2>/dev/null | tail -n +2 | awk '{gsub(/.*:/,\"\",$4); print $4, $1, $6}' | sed 's/users:((\"//; s/\".*//'"
|
||||
display = "{split: :0} ({split: :2})"
|
||||
|
||||
[preview]
|
||||
command = "ss -tlnp 2>/dev/null | grep ':{split: :0} ' | head -20"
|
||||
|
||||
[ui.preview_panel]
|
||||
border_type = "none"
|
||||
scrollbar = false
|
||||
padding = { left = 2, right = 1, top = 0, bottom = 0 }
|
||||
size = 40
|
||||
|
||||
[actions.kill]
|
||||
description = "Kill the process listening on the selected port"
|
||||
command = "fuser -k {split: :0}/tcp"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,38 @@
|
||||
[metadata]
|
||||
name = "procs"
|
||||
description = "A channel to find and manage running processes"
|
||||
requirements = ["ps", "awk"]
|
||||
|
||||
[source]
|
||||
command = "ps -e -o pid=,ucomm= | awk '{print $1, $2}'"
|
||||
display = "{split: :1}"
|
||||
output = "{split: :0}"
|
||||
|
||||
[preview]
|
||||
command = "ps -p '{split: :0}' -o user,pid,ppid,state,%cpu,%mem,command | fold"
|
||||
|
||||
[keybindings]
|
||||
ctrl-k = "actions:kill"
|
||||
f2 = "actions:term"
|
||||
ctrl-s = "actions:stop"
|
||||
ctrl-c = "actions:cont"
|
||||
|
||||
[actions.kill]
|
||||
description = "Kill the selected process (SIGKILL)"
|
||||
command = "kill -9 {split: :0}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.term]
|
||||
description = "Terminate the selected process (SIGTERM)"
|
||||
command = "kill -15 {split: :0}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.stop]
|
||||
description = "Stop/pause the selected process (SIGSTOP)"
|
||||
command = "kill -STOP {split: :0}"
|
||||
mode = "fork"
|
||||
|
||||
[actions.cont]
|
||||
description = "Continue/resume the selected process (SIGCONT)"
|
||||
command = "kill -CONT {split: :0}"
|
||||
mode = "fork"
|
||||
@@ -0,0 +1,20 @@
|
||||
[metadata]
|
||||
name = "python-venvs"
|
||||
description = "Find Python virtual environments"
|
||||
requirements = ["find"]
|
||||
|
||||
[source]
|
||||
command = "find ~ -maxdepth 5 -type f -name 'pyvenv.cfg' 2>/dev/null | xargs -I{} dirname {}"
|
||||
|
||||
[preview]
|
||||
command = "cat '{}/pyvenv.cfg' 2>/dev/null && echo '' && echo 'Packages:' && '{}/bin/pip' list --format=columns 2>/dev/null | head -20"
|
||||
|
||||
[actions.activate]
|
||||
description = "Open a shell with the selected venv activated"
|
||||
command = "source '{}/bin/activate' && $SHELL"
|
||||
mode = "execute"
|
||||
|
||||
[actions.packages]
|
||||
description = "List all packages in the selected venv"
|
||||
command = "'{}/bin/pip' list | less"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,23 @@
|
||||
[metadata]
|
||||
name = "recent-files"
|
||||
description = "List recently modified files (via git or filesystem)"
|
||||
requirements = ["git", "bat"]
|
||||
|
||||
[source]
|
||||
command = [
|
||||
{ name = "Recent", run = "git diff --name-only HEAD~10 HEAD 2>/dev/null || find . -type f -mtime -7 -not -path '*/.*' 2>/dev/null | head -100" },
|
||||
{ name = "Last hour", run = "find . -type f -mmin -60 -not -path '*/.*' 2>/dev/null | head -100" },
|
||||
]
|
||||
|
||||
[preview]
|
||||
command = "bat -n --color=always '{}'"
|
||||
env = { BAT_THEME = "ansi" }
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:edit"
|
||||
|
||||
[actions.edit]
|
||||
description = "Open the selected file in editor"
|
||||
command = "${EDITOR:-vim} {}"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,20 @@
|
||||
[metadata]
|
||||
name = "rustup"
|
||||
description = "Manage Rust toolchains"
|
||||
requirements = ["rustup"]
|
||||
|
||||
[source]
|
||||
command = "rustup toolchain list"
|
||||
|
||||
[preview]
|
||||
command = "rustup run '{split: :0}' rustc --version --verbose 2>/dev/null"
|
||||
|
||||
[actions.default]
|
||||
description = "Set the selected toolchain as default"
|
||||
command = "rustup default '{split: :0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.uninstall]
|
||||
description = "Uninstall the selected toolchain"
|
||||
command = "rustup toolchain uninstall '{split: :0}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,18 @@
|
||||
[metadata]
|
||||
name = "ssh-hosts"
|
||||
description = "A channel to select hosts from your SSH config"
|
||||
requirements = ["grep", "tr", "cut", "awk"]
|
||||
|
||||
[source]
|
||||
command = "grep -E '^Host(name)? ' $HOME/.ssh/config | tr -s ' ' | cut -d' ' -f2- | tr ' ' '\n' | grep -v '^$'"
|
||||
|
||||
[preview]
|
||||
command = "awk '/^Host / { found=0 } /^Host (.*[[:space:]])?'{}'([[:space:]].*)?$/ { found=1 } found' $HOME/.ssh/config"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:connect"
|
||||
|
||||
[actions.connect]
|
||||
description = "SSH into the selected host"
|
||||
command = "ssh {}"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,49 @@
|
||||
[metadata]
|
||||
name = "systemd-units"
|
||||
description = "List and manage systemd services"
|
||||
requirements = ["systemctl"]
|
||||
|
||||
[source]
|
||||
command = [
|
||||
{ name = "Active", run = "systemctl list-units --type=service --no-pager --no-legend --plain" },
|
||||
{ name = "All", run = "systemctl list-units --type=service --all --no-pager --no-legend --plain" },
|
||||
]
|
||||
display = "{split: :0}"
|
||||
|
||||
[preview]
|
||||
command = "systemctl status '{split: :0}' --no-pager"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
|
||||
[keybindings]
|
||||
ctrl-s = "actions:start"
|
||||
f2 = "actions:stop"
|
||||
ctrl-r = "actions:restart"
|
||||
ctrl-e = "actions:enable"
|
||||
ctrl-d = "actions:disable"
|
||||
|
||||
[actions.start]
|
||||
description = "Start the selected service"
|
||||
command = "sudo systemctl start '{split: :0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.stop]
|
||||
description = "Stop the selected service"
|
||||
command = "sudo systemctl stop '{split: :0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.restart]
|
||||
description = "Restart the selected service"
|
||||
command = "sudo systemctl restart '{split: :0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.enable]
|
||||
description = "Enable the selected service"
|
||||
command = "sudo systemctl enable '{split: :0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.disable]
|
||||
description = "Disable the selected service"
|
||||
command = "sudo systemctl disable '{split: :0}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,18 @@
|
||||
[metadata]
|
||||
name = "tailscale-exit-node"
|
||||
description = "A channel to select a tailscale exit node"
|
||||
requirements = ["tailscale", "awk"]
|
||||
|
||||
[source]
|
||||
command = "tailscale exit-node list | awk '/^[[:space:]]*[0-9]+\\./ {gsub(/^[[:space:]]+/, \"\"); print $1}'"
|
||||
|
||||
[preview]
|
||||
command = "tailscale whois {}"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:connect"
|
||||
|
||||
[actions.connect]
|
||||
description = "Set selected host as exit node"
|
||||
command = "tailscale set --exit-node={}"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,36 @@
|
||||
[metadata]
|
||||
name = "tea-issues"
|
||||
description = "List Gitea issues for the current repo"
|
||||
requirements = ["tea", "jq"]
|
||||
|
||||
[source]
|
||||
command = '''tea issues list --output json --state open </dev/null | jq -r '.[] | "\u001b[32m#\(.index)\u001b[39m" + "\t\(.title) \u001b[33m@\(.author)\u001b[39m" + (if .labels != "" then " \u001b[35m" + .labels + "\u001b[39m" else "" end)'
|
||||
'''
|
||||
ansi = true
|
||||
output = "{strip_ansi|split:#:1|split:\t:0}"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
preview_panel = { header = '{strip_ansi|split:\t:1}', border_type = "none", scrollbar = false, padding = { left = 2, right = 1, top = 0, bottom = 0 } }
|
||||
|
||||
[preview]
|
||||
command = '''tea issues --output json {strip_ansi|split:#:1|split:\t:0} </dev/null | jq -r '
|
||||
.title,
|
||||
"#" + (.index | tostring),
|
||||
"",
|
||||
"\u001b[36mStatus:\u001b[39m \u001b[32m" + .state + "\u001b[39m",
|
||||
"\u001b[36mAuthor:\u001b[39m \u001b[33m" + .user + "\u001b[39m",
|
||||
"\u001b[36mCreated:\u001b[39m " + .created[:10],
|
||||
(if (.labels | length) > 0 then "\u001b[36mLabels:\u001b[39m " + ([.labels[] | "\u001b[35m" + .name + "\u001b[39m"]
|
||||
| join(" ")) else empty end),
|
||||
"",
|
||||
"\u001b[90m────────────────────────────────────────────────────────────\u001b[39m",
|
||||
"",
|
||||
(.body // "")
|
||||
'
|
||||
'''
|
||||
|
||||
[actions.close]
|
||||
description = "Close the selected issue"
|
||||
command = "tea issues close {strip_ansi|split:#:1|split:\t:0}"
|
||||
mode = "fork"
|
||||
@@ -0,0 +1,42 @@
|
||||
[metadata]
|
||||
name = "tea-prs"
|
||||
description = "List Gitea PRs for the current repo"
|
||||
requirements = ["tea", "jq"]
|
||||
|
||||
[source]
|
||||
command = '''tea pulls list --output json --state open </dev/null | jq -r '.[] | "\u001b[32m#\(.index)\u001b[39m" + "\t\(.title) \u001b[33m@\(.author)\u001b[39m" + (if .labels != "" then " \u001b[35m" + .labels + "\u001b[39m" else "" end)'
|
||||
'''
|
||||
ansi = true
|
||||
output = "{strip_ansi|split:#:1|split:\t:0}"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
preview_panel = { header = '{strip_ansi|split:\t:1}', border_type = "none", scrollbar = false, padding = { left = 2, right = 1, top = 0, bottom = 0 } }
|
||||
|
||||
[preview]
|
||||
command = '''tea pulls --output json {strip_ansi|split:#:1|split:\t:0} </dev/null | jq -r '
|
||||
.title,
|
||||
"#" + (.index | tostring),
|
||||
"",
|
||||
"\u001b[36mStatus:\u001b[39m \u001b[32m" + .state + "\u001b[39m " + .base + " ← " + .head,
|
||||
"\u001b[36mAuthor:\u001b[39m \u001b[33m" + .user + "\u001b[39m",
|
||||
"\u001b[36mCreated:\u001b[39m " + .created[:10],
|
||||
"\u001b[36mUpdated:\u001b[39m " + .updated[:10],
|
||||
(if (.labels | length) > 0 then "\u001b[36mLabels:\u001b[39m " + ([.labels[] | "\u001b[35m" + .name + "\u001b[39m"] | join(" ")) else empty end),
|
||||
"\u001b[36mMergeable:\u001b[39m " + (if .mergeable then "\u001b[32m✓ Clean\u001b[39m" else "\u001b[31m✗ Dirty\u001b[39m" end),
|
||||
"",
|
||||
"\u001b[90m────────────────────────────────────────────────────────────\u001b[39m",
|
||||
"",
|
||||
(.body // "")
|
||||
'
|
||||
'''
|
||||
|
||||
[actions.checkout]
|
||||
description = "Checkout the PR branch locally"
|
||||
command = "tea pulls checkout {strip_ansi|split:#:1|split:\t:0}"
|
||||
mode = "execute"
|
||||
|
||||
[actions.merge]
|
||||
description = "Merge the selected PR"
|
||||
command = "tea pulls merge {strip_ansi|split:#:1|split:\t:0}"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,29 @@
|
||||
[metadata]
|
||||
name = "text"
|
||||
description = "A channel to find and select text from files"
|
||||
requirements = ["rg", "bat"]
|
||||
|
||||
[source]
|
||||
command = [
|
||||
{ name = "Default", run = "rg . --no-heading --line-number --colors 'match:fg:white' --colors 'path:fg:blue' --color=always" },
|
||||
{ name = "Hidden", run = "rg . --no-heading --line-number --hidden --colors 'match:fg:white' --colors 'path:fg:blue' --color=always" },
|
||||
]
|
||||
ansi = true
|
||||
output = "{strip_ansi|split:\\::..2}"
|
||||
|
||||
[preview]
|
||||
command = "bat -n --color=always '{strip_ansi|split:\\::0}'"
|
||||
env = { BAT_THEME = "ansi" }
|
||||
offset = '{strip_ansi|split:\::1}'
|
||||
|
||||
[ui]
|
||||
preview_panel = { header = '{strip_ansi|split:\::..2}', border_type = "none", scrollbar = false, padding = { left = 2, right = 1, top = 0, bottom = 0 } }
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:edit"
|
||||
|
||||
[actions.edit]
|
||||
description = "Open file in editor at line"
|
||||
command = "${EDITOR:-vim} '+{strip_ansi|split:\\::1}' '{strip_ansi|split:\\::0}'"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,21 @@
|
||||
[metadata]
|
||||
name = "tldr"
|
||||
description = "Browse and preview TLDR help pages for command-line tools"
|
||||
requirements = ["tldr"]
|
||||
|
||||
[source]
|
||||
command = "tldr --list"
|
||||
|
||||
[preview]
|
||||
command = "tldr '{0}' --color always"
|
||||
|
||||
[ui]
|
||||
layout = "portrait"
|
||||
|
||||
[keybindings]
|
||||
ctrl-e = "actions:open"
|
||||
|
||||
[actions.open]
|
||||
description = "Open the selected TLDR page"
|
||||
command = "tldr '{0}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,22 @@
|
||||
[metadata]
|
||||
name = "tmux-sessions"
|
||||
description = "List and manage tmux sessions"
|
||||
requirements = ["tmux"]
|
||||
|
||||
[source]
|
||||
command = "tmux list-sessions -F '#{session_name}\t#{session_windows} windows\t#{session_created_string}'"
|
||||
display = "{split:\t:0} ({split:\t:1})"
|
||||
output = "{split:\t:0}"
|
||||
|
||||
[preview]
|
||||
command = "tmux capture-pane -t '{split:\t:0}' -p 2>/dev/null || echo 'No preview available'"
|
||||
|
||||
[actions.attach]
|
||||
description = "Attach to the selected session"
|
||||
command = "tmux attach-session -t '{split:\t:0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.kill]
|
||||
description = "Kill the selected session"
|
||||
command = "tmux kill-session -t '{split:\t:0}'"
|
||||
mode = "fork"
|
||||
@@ -0,0 +1,22 @@
|
||||
[metadata]
|
||||
name = "tmux-windows"
|
||||
description = "List and switch between tmux windows"
|
||||
requirements = ["tmux"]
|
||||
|
||||
[source]
|
||||
command = "tmux list-windows -a -F '#{session_name}:#{window_index}\t#{window_name}\t#{pane_current_command}'"
|
||||
display = "{split:\t:0} - {split:\t:1} ({split:\t:2})"
|
||||
output = "{split:\t:0}"
|
||||
|
||||
[preview]
|
||||
command = "tmux capture-pane -t '{split:\t:0}' -p 2>/dev/null || echo 'No preview available'"
|
||||
|
||||
[actions.select]
|
||||
description = "Switch to the selected window"
|
||||
command = "tmux select-window -t '{split:\t:0}'"
|
||||
mode = "execute"
|
||||
|
||||
[actions.kill]
|
||||
description = "Kill the selected window"
|
||||
command = "tmux kill-window -t '{split:\t:0}'"
|
||||
mode = "fork"
|
||||
@@ -0,0 +1,26 @@
|
||||
[metadata]
|
||||
name = "todo-comments"
|
||||
description = "Find TODO, FIXME, HACK, and XXX comments in codebase"
|
||||
requirements = ["rg", "bat"]
|
||||
|
||||
[source]
|
||||
command = "rg -n --color=always '(TODO|FIXME|HACK|XXX|BUG|WARN):?'"
|
||||
ansi = true
|
||||
output = "{strip_ansi|split:\\::..2}"
|
||||
|
||||
[preview]
|
||||
command = "bat -n --color=always --highlight-line '{strip_ansi|split:\\::1}' '{strip_ansi|split:\\::0}'"
|
||||
env = { BAT_THEME = "ansi" }
|
||||
offset = "{strip_ansi|split:\\::1}"
|
||||
|
||||
[ui]
|
||||
preview_panel = { header = "{strip_ansi|split:\\::..2}", border_type = "none", scrollbar = false, padding = { left = 2, right = 1, top = 0, bottom = 0 } }
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:edit"
|
||||
|
||||
[actions.edit]
|
||||
description = "Open file in editor at the comment"
|
||||
command = "${EDITOR:-vim} '+{strip_ansi|split:\\::1}' '{strip_ansi|split:\\::0}'"
|
||||
shell = "bash"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,43 @@
|
||||
[metadata]
|
||||
name = "unicode"
|
||||
description = '''Search and insert unicode characters
|
||||
|
||||
The UnicodeData.txt file is included by many packages.
|
||||
|
||||
In addition to:
|
||||
|
||||
Alpine Linux: unicode-character-database
|
||||
Arch: unicode-character-database
|
||||
Debian/Ubuntu: unicode-data
|
||||
Fedora / RHEL / CentOS unicode-ucd
|
||||
Gentoo: app-i18n/unicode-data
|
||||
NixOS: unicode/unicode-data
|
||||
openSUSE: unicode-ucd
|
||||
|
||||
UnicodData.txt may also aleady be provided by:
|
||||
|
||||
1) Many java packages
|
||||
2) Latex packages
|
||||
3) Still others
|
||||
|
||||
It may in some cases be necessary to alter UNICODE_FILE below.
|
||||
|
||||
'''
|
||||
requirements = ["awk", "perl"]
|
||||
|
||||
[source]
|
||||
command = '''
|
||||
UNICODE_FILE="/usr/share/unicode/ucd/UnicodeData.txt"
|
||||
awk -F';' '
|
||||
$2 !~ /^</ { print $1 "|" $2 }
|
||||
' "$UNICODE_FILE" \
|
||||
| perl -CS -F'\|' -lane '
|
||||
$code = $F[0];
|
||||
$desc = $F[1];
|
||||
$char = chr(hex($code));
|
||||
print "U+$code|$char|$desc" if $char =~ /\p{Print}/;
|
||||
'
|
||||
'''
|
||||
|
||||
display = "{split:|:0} {split:|:1} {split:|:2}"
|
||||
output = "{split:|:1}"
|
||||
@@ -0,0 +1,17 @@
|
||||
[metadata]
|
||||
name = "wifi"
|
||||
description = "Scan and connect to WiFi networks"
|
||||
requirements = ["nmcli"]
|
||||
|
||||
[source]
|
||||
command = "nmcli -t -f SSID,SIGNAL,SECURITY device wifi list 2>/dev/null | grep -v '^:' | sort -t: -k2 -rn"
|
||||
display = "{split:\\::0} ({split:\\::1}% {split:\\::2})"
|
||||
output = "{split:\\::0}"
|
||||
|
||||
[preview]
|
||||
command = "nmcli -t -f SSID,BSSID,MODE,FREQ,SIGNAL,SECURITY,ACTIVE device wifi list 2>/dev/null | grep '^{split:\\::0}:'"
|
||||
|
||||
[actions.connect]
|
||||
description = "Connect to the selected network"
|
||||
command = "nmcli device wifi connect '{split:\\::0}'"
|
||||
mode = "execute"
|
||||
@@ -0,0 +1,26 @@
|
||||
[metadata]
|
||||
name = "zoxide"
|
||||
description = "Browse zoxide directory history"
|
||||
requirements = ["zoxide"]
|
||||
|
||||
[source]
|
||||
command = "zoxide query -l"
|
||||
no_sort = true
|
||||
frecency = false
|
||||
|
||||
[preview]
|
||||
command = "ls -la --color=always '{}'"
|
||||
|
||||
[keybindings]
|
||||
enter = "actions:cd"
|
||||
ctrl-d = "actions:remove"
|
||||
|
||||
[actions.cd]
|
||||
description = "Change to the selected directory"
|
||||
command = "cd {} && $SHELL"
|
||||
mode = "execute"
|
||||
|
||||
[actions.remove]
|
||||
description = "Remove the selected directory from zoxide"
|
||||
command = "zoxide remove {}"
|
||||
mode = "fork"
|
||||
@@ -0,0 +1,16 @@
|
||||
[metadata]
|
||||
name = "zsh-history"
|
||||
description = "A channel to select from your zsh history"
|
||||
requirements = ["zsh"]
|
||||
|
||||
[source]
|
||||
command = "sed '1!G;h;$!d' ${HISTFILE:-${HOME}/.zsh_history}"
|
||||
display = "{split:;:1..}"
|
||||
output = "{split:;:1..}"
|
||||
no_sort = true
|
||||
frecency = false
|
||||
|
||||
[actions.execute]
|
||||
description = "Execute the selected command"
|
||||
command = "zsh -c '{split:;:1..}'"
|
||||
mode = "execute"
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
# CONFIGURATION FILE LOCATION ON YOUR SYSTEM:
|
||||
# -------------------------------------------
|
||||
# Defaults:
|
||||
# ---------
|
||||
# Linux: `$HOME/.config/television/config.toml`
|
||||
# macOS: `$HOME/.config/television/config.toml`
|
||||
# Windows: `%LocalAppData%\television\config\config.toml`
|
||||
#
|
||||
# XDG dirs:
|
||||
# ---------
|
||||
# You may use XDG_CONFIG_HOME if set on your system.
|
||||
# In that case, television will expect the configuration file to be in:
|
||||
# `$XDG_CONFIG_HOME/television/config.toml`
|
||||
#
|
||||
|
||||
# General settings
|
||||
# ----------------------------------------------------------------------------
|
||||
tick_rate = 50
|
||||
default_channel = "files"
|
||||
# Shell settings
|
||||
# --------------
|
||||
# Default shell used for executing commands (source, preview, actions).
|
||||
# Options: bash, zsh, fish, powershell, cmd, nu
|
||||
# If not specified, the shell is detected from the environment ($SHELL on Unix).
|
||||
# Channel-specific shell settings override this global setting.
|
||||
# shell = "bash"
|
||||
# History settings
|
||||
# ---------------
|
||||
# Maximum number of entries to keep in the global history (default: 100)
|
||||
# The history tracks search queries across all channels and sessions
|
||||
# Set to 0 to disable history functionality entirely
|
||||
history_size = 200
|
||||
# Whether to use global history (default: false)
|
||||
# When true: history navigation shows entries from all channels
|
||||
# When false: history navigation is scoped to the current channel
|
||||
global_history = false
|
||||
|
||||
[ui]
|
||||
# How much space to allocate for the UI (in percentage of the screen)
|
||||
# ┌─────────────────────────┐
|
||||
# │ Terminal screen │
|
||||
# │ ┌───────────────────┐ │
|
||||
# │ │ │ │
|
||||
# │ │ Television UI │ │
|
||||
# │ │ │ │
|
||||
# │ └───────────────────┘ │
|
||||
# │ │
|
||||
# └─────────────────────────┘
|
||||
ui_scale = 100
|
||||
# What orientation should tv be (landscape or portrait)
|
||||
orientation = "landscape"
|
||||
# The theme to use for the UI: themes/cyberdream-transparent.toml in this
|
||||
# config dir (a builtin theme shadows a user theme of the same name).
|
||||
theme = "cyberdream-transparent"
|
||||
|
||||
# Minimal UI: no borders, no status bar, no scrollbar — padding alone
|
||||
# separates the panels. tv 0.15 has no config key for inline
|
||||
# mode (--inline / --height are CLI-only), so every call site in the shells,
|
||||
# pj and the cables passes --inline. A channel that sets its own
|
||||
# [ui.preview_panel] resets these fields to tv's defaults (rounded border),
|
||||
# so cables leave that table alone.
|
||||
[ui.input_bar]
|
||||
# Where to place the input bar in the UI (top or bottom)
|
||||
position = "top"
|
||||
prompt = "❯"
|
||||
# header = "{}"
|
||||
border_type = "none"
|
||||
# a blank row between the query and the results
|
||||
padding = { left = 1, right = 1, top = 0, bottom = 1 }
|
||||
|
||||
[ui.status_bar]
|
||||
separator_open = ""
|
||||
separator_close = ""
|
||||
# f12 toggles it back
|
||||
hidden = true
|
||||
|
||||
[ui.results_panel]
|
||||
border_type = "none"
|
||||
padding = { left = 1, right = 1, top = 0, bottom = 0 }
|
||||
|
||||
[ui.preview_panel]
|
||||
# Preview panel size (percentage of screen width/height)
|
||||
size = 50
|
||||
#header = ""
|
||||
#footer = ""
|
||||
scrollbar = false
|
||||
border_type = "none"
|
||||
padding = { left = 2, right = 1, top = 0, bottom = 0 }
|
||||
hidden = false
|
||||
|
||||
[ui.help_panel]
|
||||
# Whether to split the help panel by categories
|
||||
show_categories = true
|
||||
hidden = true
|
||||
|
||||
[ui.remote_control]
|
||||
# Whether to show channel descriptions in remote control mode
|
||||
show_channel_descriptions = true
|
||||
# Whether to sort channels alphabetically
|
||||
sort_alphabetically = true
|
||||
# disabled = false
|
||||
|
||||
# Theme color overrides
|
||||
# ---------------------
|
||||
# You can override specific colors from the selected theme by adding them here.
|
||||
# This allows you to customize the appearance without creating a full theme file.
|
||||
# Colors can be specified as ANSI color names (e.g., "red", "bright-blue") or
|
||||
# as hex values (e.g., "#ff0000", "#1e1e2e").
|
||||
#
|
||||
# Example overrides:
|
||||
# [ui.theme_overrides]
|
||||
# background = "#000000"
|
||||
# text_fg = "#ffffff"
|
||||
# selection_bg = "#444444"
|
||||
# match_fg = "#ff0000"
|
||||
|
||||
# Keybindings and Events
|
||||
# ----------------------------------------------------------------------------
|
||||
#
|
||||
[keybindings]
|
||||
# Application control
|
||||
# ------------------
|
||||
esc = "quit"
|
||||
ctrl-c = "quit"
|
||||
|
||||
# Navigation and selection
|
||||
# -----------------------
|
||||
down = "select_next_entry"
|
||||
ctrl-n = "select_next_entry"
|
||||
ctrl-j = "select_next_entry"
|
||||
up = "select_prev_entry"
|
||||
ctrl-p = "select_prev_entry"
|
||||
ctrl-k = "select_prev_entry"
|
||||
|
||||
# History navigation
|
||||
# -----------------
|
||||
ctrl-up = "select_prev_history"
|
||||
ctrl-down = "select_next_history"
|
||||
|
||||
# Multi-selection
|
||||
# --------------
|
||||
tab = "toggle_selection_down"
|
||||
backtab = "toggle_selection_up"
|
||||
enter = "confirm_selection"
|
||||
|
||||
# Preview panel control
|
||||
# --------------------
|
||||
pagedown = "scroll_preview_half_page_down"
|
||||
pageup = "scroll_preview_half_page_up"
|
||||
ctrl-f = "cycle_previews"
|
||||
|
||||
# Data operations
|
||||
# --------------
|
||||
ctrl-y = "copy_entry_to_clipboard"
|
||||
ctrl-r = "reload_source"
|
||||
ctrl-s = "cycle_sources"
|
||||
|
||||
# UI Features
|
||||
# ----------
|
||||
ctrl-t = "toggle_remote_control"
|
||||
ctrl-x = "toggle_action_picker"
|
||||
ctrl-o = "toggle_preview"
|
||||
# ctrl-h/ctrl-e run the current channel's actions (files: goto_parent_dir,
|
||||
# edit in nvim — see cable/files.toml); `end` still jumps to input end.
|
||||
ctrl-h = "actions:goto_parent_dir"
|
||||
f12 = "toggle_status_bar"
|
||||
ctrl-l = "toggle_layout"
|
||||
|
||||
# Input field actions
|
||||
# ----------------------------------------
|
||||
backspace = "delete_prev_char"
|
||||
ctrl-w = "delete_prev_word"
|
||||
ctrl-u = "delete_line"
|
||||
delete = "delete_next_char"
|
||||
left = "go_to_prev_char"
|
||||
right = "go_to_next_char"
|
||||
home = "go_to_input_start"
|
||||
ctrl-a = "go_to_input_start"
|
||||
end = "go_to_input_end"
|
||||
ctrl-e = "actions:edit"
|
||||
|
||||
# Shell integration
|
||||
# ----------------------------------------------------------------------------
|
||||
#
|
||||
# The shell integration feature allows you to use television as a picker for
|
||||
# your shell commands (as well as your shell history with <CTRL-R>).
|
||||
# E.g. typing `git checkout <CTRL-T>` will open television with a list of
|
||||
# branches to choose from.
|
||||
|
||||
[shell_integration]
|
||||
# This specifies the default fallback channel if no other channel is matched.
|
||||
fallback_channel = "files"
|
||||
|
||||
[shell_integration.channel_triggers]
|
||||
# Add your channel triggers here. Each key is a channel that will be triggered
|
||||
# by the corresponding commands.
|
||||
# Example: say you want the following commands to trigger the following channels
|
||||
# when pressing <CTRL-T>:
|
||||
# `git checkout` should trigger the `git-branches` channel
|
||||
# `ls` should trigger the `dirs` channel
|
||||
# `cat` and `cp` should trigger the `files` channel
|
||||
#
|
||||
# You would add the following to your configuration file:
|
||||
# ```
|
||||
# [shell_integration.channel_triggers]
|
||||
# "git-branches" = ["git checkout"]
|
||||
# "dirs" = ["ls"]
|
||||
# "files" = ["cat", "cp"]
|
||||
# ```
|
||||
"alias" = ["alias", "unalias"]
|
||||
"env" = ["export", "unset"]
|
||||
"dirs" = ["cd", "ls", "rmdir", "z"]
|
||||
"files" = [
|
||||
"cat",
|
||||
"less",
|
||||
"head",
|
||||
"tail",
|
||||
"vim",
|
||||
"nano",
|
||||
"bat",
|
||||
"cp",
|
||||
"mv",
|
||||
"rm",
|
||||
"touch",
|
||||
"chmod",
|
||||
"chown",
|
||||
"ln",
|
||||
"tar",
|
||||
"zip",
|
||||
"unzip",
|
||||
"gzip",
|
||||
"gunzip",
|
||||
"xz",
|
||||
]
|
||||
"git-diff" = ["git add", "git restore"]
|
||||
"git-branch" = [
|
||||
"git checkout",
|
||||
"git switch",
|
||||
"git branch",
|
||||
"git merge",
|
||||
"git rebase",
|
||||
"git pull",
|
||||
"git push",
|
||||
]
|
||||
"git-log" = ["git log", "git show"]
|
||||
"docker-images" = ["docker run"]
|
||||
"git-repos" = ["nvim", "code", "hx", "git clone"]
|
||||
|
||||
|
||||
[shell_integration.keybindings]
|
||||
# controls which key binding should trigger tv
|
||||
# for shell autocomplete
|
||||
"smart_autocomplete" = "ctrl-t"
|
||||
# controls which keybinding should trigger tv
|
||||
# for command history
|
||||
"command_history" = "ctrl-r"
|
||||
@@ -0,0 +1,29 @@
|
||||
# cyberdream-transparent — https://github.com/scottmckendry/cyberdream.nvim
|
||||
# Same palette as the kitty, fish, atuin, bat and yazi cyberdream themes.
|
||||
# Differs from tv's builtin `cyberdream` (which shadows a user theme of that
|
||||
# name): no `background`, so tv draws on kitty's own translucent #16181a
|
||||
# (tv 0.15 rejects `background = 'none'` and falls back to the default theme).
|
||||
|
||||
# general
|
||||
border_fg = '#3c4048'
|
||||
text_fg = '#ffffff'
|
||||
dimmed_text_fg = '#7b8496'
|
||||
# input
|
||||
input_text_fg = '#ffffff'
|
||||
result_count_fg = '#ffbd5e'
|
||||
# results
|
||||
result_name_fg = '#5ea1ff'
|
||||
result_line_number_fg = '#f1ff5e'
|
||||
result_value_fg = '#ffffff'
|
||||
selection_fg = '#5eff6c'
|
||||
selection_bg = '#3c4048'
|
||||
match_fg = '#5ef1ff'
|
||||
# preview
|
||||
preview_title_fg = '#ffaecf'
|
||||
# modes
|
||||
channel_mode_fg = '#16181a'
|
||||
channel_mode_bg = '#5ef1ff'
|
||||
remote_control_mode_fg = '#16181a'
|
||||
remote_control_mode_bg = '#5eff6c'
|
||||
action_picker_mode_fg = '#16181a'
|
||||
action_picker_mode_bg = '#bd5eff'
|
||||
Reference in new issue
Block a user