mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-02 11:32:42 +00:00
373 lines
21 KiB
Plaintext
373 lines
21 KiB
Plaintext
---
|
||
title: Scripts
|
||
description: The shell-agnostic executables in ~/.local/bin — usage, behavior, and dependencies for each.
|
||
---
|
||
|
||
`dot_local/bin/` holds standalone `sh`, `bash`, and `python3` executables. The `executable_` prefix is a chezmoi attribute that sets the executable bit and is dropped from the target name, so `dot_local/bin/executable_pj` becomes `~/.local/bin/pj`. bash, zsh, and fish all put `~/.local/bin` on `PATH`, so every shell runs the same implementation.
|
||
|
||
This page covers the general-purpose scripts. The desktop scripts in the same directory are documented with their compositor:
|
||
|
||
- `niri-launch`, `niri-launch-ai`, `niri-launch-browser`, `niri-launch-terminal`, `niri-launch-webapp`, `cp-appid`: [niri](/desktop/niri)
|
||
- `omarchy-*`: [Hyprland](/desktop/hyprland)
|
||
|
||
## Why some helpers are shell functions
|
||
|
||
A script runs as a child process, and a child cannot change its parent shell's working directory or read the parent's in-memory history. Helpers that need to do either are therefore defined as shell functions, ported three times: `fish/functions/*.fish`, `bash/functions/*.bash`, and `zsh/functions/*.zsh`.
|
||
|
||
| Helper | Why it must be a function |
|
||
| --- | --- |
|
||
| `yy` (and fish's `y`) | cds into the directory yazi exited in |
|
||
| `c` | cds when given an argument |
|
||
| `cd` | Replaces the `cd` builtin with a zoxide fallback |
|
||
| `ghg`, `ghn`, `gho` | cd into a repo that was picked or cloned |
|
||
| `clip-last` | Reads the shell's own history (`$history[1]` in fish, `fc` in bash/zsh) |
|
||
|
||
For `ghg` and `ghn`, the work lives in a script that prints a directory on stdout (and everything else on stderr). The shell function captures that path and cds into it. `ghg`'s script is named `ghg-clone` because an unrelated cargo binary already uses the name `ghg`. `gho` has no script: the function reads the path from `tv ghq-repos` ([television](/tools/television#ghq-repos)).
|
||
|
||
Several scripts below also exist as fish functions of the same name (`ai`, `c2p`, `extract_agents`, `fab`, `gdc`, `git-summary`, `lc-elir`, `mdcp`, `mdp`, `launch_omp_livediff_overlay`, `gh-sonr-org-migrate`). In fish the function runs instead of the script. Both versions behave the same. See [fish functions](/shell/fish#functions).
|
||
|
||
## Overview
|
||
|
||
| Script | Language | One line |
|
||
| --- | --- | --- |
|
||
| [`ai`](#ai) | sh | Pick an AI CLI with gum and launch it |
|
||
| [`atuin-pick`](#atuin-pick) | python3 | atuin history picker for a kitty or tmux split |
|
||
| [`c2p`](#c2p) | sh | code2prompt with an fzf-picked template |
|
||
| [`extract_agents`](#extract_agents) | sh | Copy all `AGENTS.md` files into a directory tree |
|
||
| [`fab`](#fab) | sh | fzf picker for Fabric patterns |
|
||
| [`gdc`](#gdc) | sh | Discard all git changes after confirmation |
|
||
| [`gh-sonr-org-migrate`](#gh-sonr-org-migrate) | bash | Consolidate `*sonr*` GitHub orgs into `sonr-io` |
|
||
| [`ghg-clone`](#ghg-clone) | sh | `ghq get` and print the clone path |
|
||
| [`ghn`](#ghn) | sh | Create a private repo, clone it, print the path |
|
||
| [`git-summary`](#git-summary) | sh | Aggregate a repo's `AGENTS.md` files with code2prompt |
|
||
| [`gop`](#gop) | sh | Open the current repo's web page |
|
||
| [`kitty-day-save`](#kitty-day-save) | bash | Save kitty's daily session right before shutdown/reboot |
|
||
| [`launch_omp_livediff_overlay`](#launch_omp_livediff_overlay) | sh | omp overlay plus a livediff split in kitty |
|
||
| [`lc-elir`](#lc-elir) | sh | Run `/leetcode-eli5` via omp on picked solutions |
|
||
| [`mdcp`](#mdcp) | sh | Fetch a URL as Markdown, copy it, preview it |
|
||
| [`mdp`](#mdp) | sh | fzf Markdown picker with mdfried preview |
|
||
| [`mtime-sort`](#mtime-sort) | sh + perl | Sort path lines newest-first by mtime |
|
||
| [`omp-session`](#omp-session) | python3 | Resume or start omp for the current repo; backend of the `omp-sessions` cable |
|
||
| [`pj`](#pj) | bash | Task runner across every project task source, on a tv cable |
|
||
| [`pj-palette`](#pj-palette) | bash | pj's tasks plus quick actions as a tmux-palette source |
|
||
| [`yazi-nvim-open`](#yazi-nvim-open) | sh | yazi opener that targets the host Neovim |
|
||
|
||
## ai
|
||
|
||
```sh
|
||
ai
|
||
```
|
||
|
||
Shows `gum choose --header 'AI CLI'` with `claude`, `opencode`, `codex`, `hermes`, and `fractal`, then `exec`s the choice. `claude` runs as `claude --dangerously-skip-permissions`; the others run as the bare binary name. Esc or Ctrl-C exits 0.
|
||
|
||
**Needs:** `gum` and the chosen CLI.
|
||
|
||
## atuin-pick
|
||
|
||
```sh
|
||
atuin-pick
|
||
```
|
||
|
||
Opens atuin's interactive search (`atuin search -i --filter-mode directory`), limited to history from the current directory. It then `exec`s an interactive `fish`. If you picked a command, the new fish runs `echo '❯ <cmd>'; <cmd>` via `-C` (`--init-command`), so aliases resolve, a `cd` persists, and the prompt appears below the output. Esc starts a plain fish.
|
||
|
||
It is written for launch contexts where atuin's shell init never ran. It runs `atuin` from `PATH` and seeds `ATUIN_SESSION` from `atuin uuid` if unset.
|
||
|
||
**Launched by:** <kbd>ctrl+shift+p</kbd> in kitty. `kitty.conf` opens it in a horizontal split (`launch_hs atuin-pick`). Under the kitty-tmux profile, `tmux.conf` runs it with `tmux split-window -v -l 25%` in the current pane's directory. See [kitty](/terminal/kitty) and [atuin](/shell/atuin).
|
||
|
||
**Needs:** `python3`, `atuin`, `fish`.
|
||
|
||
## c2p
|
||
|
||
```sh
|
||
c2p
|
||
```
|
||
|
||
Lists `*.hbs` files under `~/.config/code2prompt` with `fd`, lets you pick one with fzf, and `exec`s `code2prompt --template <file>`.
|
||
|
||
**Needs:** `fd`, `fzf`, `code2prompt`.
|
||
|
||
## extract_agents
|
||
|
||
```sh
|
||
extract_agents <output-dir>
|
||
```
|
||
|
||
Creates `<output-dir>` and copies every `AGENTS.md` below the current directory into it with `cp --parents`, keeping the relative paths.
|
||
|
||
**Needs:** `fd`, GNU `cp` (`--parents`).
|
||
|
||
## fab
|
||
|
||
```sh
|
||
fab
|
||
some-command | fab
|
||
```
|
||
|
||
Reads `~/.config/fabric/pattern_explainations.json`. fzf lists pattern names, the preview pane (right, 60%, wrapped) shows each description, and <kbd>ctrl-/</kbd> toggles the preview. The picked pattern runs as `fabric-ai --pattern <name>`, falling back to `fabric` if `fabric-ai` is not installed. Piped stdin is buffered to a temp file and fed to the pattern; the temp file is removed on exit.
|
||
|
||
**Needs:** `jq`, `fzf`, `fabric-ai` or `fabric`, and the pattern JSON.
|
||
|
||
## gdc
|
||
|
||
```sh
|
||
gdc
|
||
```
|
||
|
||
Asks `gum confirm "Discard all uncommitted changes? This is irreversible."`. On yes, runs `git reset --hard HEAD` and `git clean -fd`.
|
||
|
||
**Needs:** `gum`, `git`.
|
||
|
||
## gh-sonr-org-migrate
|
||
|
||
```sh
|
||
gh-sonr-org-migrate
|
||
```
|
||
|
||
A bash port of `fish/functions/gh-sonr-org-migrate.fish`, with the same flow:
|
||
|
||
<Steps>
|
||
<Step title="Preflight">Checks that `gh`, `gum`, and `jq` exist and that `gh auth status` succeeds.</Step>
|
||
<Step title="Discover">Lists your GitHub orgs whose login contains `sonr`, excluding the target `sonr-io`. You pick which to migrate with `gum choose --no-limit`.</Step>
|
||
<Step title="Transfer">For each repo in each org, runs `gh api -X POST repos/<org>/<repo>/transfer -f new_owner=sonr-io`. If the name already exists in `sonr-io`, `gum input` asks for a new name (default `<org>-<repo>`). An empty name skips the repo.</Step>
|
||
<Step title="Settle">Waits 30 seconds (`gum spin`), because GitHub transfers are asynchronous.</Step>
|
||
<Step title="Delete">For every selected org that had no failed transfers and now has zero repos, asks `gum confirm` and then `gh api -X DELETE orgs/<org>`.</Step>
|
||
</Steps>
|
||
|
||
**Needs:** `gh` authenticated as owner of every org involved, `gum`, `jq`.
|
||
|
||
:::warning
|
||
In fish, run this script by its full path (`~/.local/bin/gh-sonr-org-migrate`). The fish file of the same name is a script body with no function in it, so typing just the name runs the fish flow and then this script. See [fish](/shell/fish#functions).
|
||
:::
|
||
|
||
## ghg-clone
|
||
|
||
```sh
|
||
ghg-clone <repo>
|
||
```
|
||
|
||
Runs `ghq get <repo>`, with its output sent to stderr. It then works out the on-disk path: it strips the scheme, any `user@`, the scp-style colon, and a trailing `.git`, and prefixes `github.com/` when the input has no host. It checks that `$(ghq root)/<host>/<user>/<repo>` exists, runs `zoxide add` on it if zoxide is installed, and prints the path.
|
||
|
||
Accepts `https://…`, `ssh://…`, `git@host:user/repo`, `host/user/repo`, or `user/repo`.
|
||
|
||
**Used by:** the `ghg` shell function, which cds into the path, clears the screen, and runs `onefetch`. The fish function `gtm` also uses it to clone migrated repos.
|
||
|
||
**Needs:** `ghq` (`GHQ_ROOT=~/Code`, exported by fish, zsh, and bash), optional `zoxide`.
|
||
|
||
## ghn
|
||
|
||
```sh
|
||
ghn <repo-name>
|
||
```
|
||
|
||
Creates a new **private** repo and clones it:
|
||
|
||
- **prad.codes** (Gitea): pick an org from `tea organizations list`, then `tea repos create --private` and `ghq get https://prad.codes/<org>/<name>`.
|
||
- **github.com**: pick the owner `prdlk` or `wltbs`, then `gh repo create <owner>/<name> --private` and `ghq get`.
|
||
|
||
You pick the host with `gum choose`. The script prints the clone directory, and the `ghn` shell function cds into it.
|
||
|
||
**Needs:** `gum`, `ghq`, and `tea` or `gh`.
|
||
|
||
## git-summary
|
||
|
||
```sh
|
||
git-summary [code2prompt flags…]
|
||
```
|
||
|
||
From anywhere inside a git repo, runs `code2prompt <repo-root> --include AGENTS.md --include "**/AGENTS.md" --template ~/.config/code2prompt/agents-md.hbs`. Extra flags such as `--output-file` or `--tokens` are passed through.
|
||
|
||
**Needs:** `git`, `code2prompt`, and the `agents-md.hbs` template.
|
||
|
||
## gop
|
||
|
||
```sh
|
||
gop # origin, else upstream, else first remote
|
||
gop upstream # a named remote
|
||
gop owner/repo # github.com/owner/repo
|
||
gop <url> # any https/ssh/scp remote URL
|
||
```
|
||
|
||
Opens a repo's web page for any forge whose URL layout is `https://<host>/<owner>/<repo>`, such as github.com and prad.codes. It reduces any remote form to `<host>/<owner>/<repo>`: it drops credentials, drops the port on `ssh://` and `git://` remotes, keeps the port and plain `http` on `http://` remotes, and strips `.git`. It then runs `$BROWSER` (default `xdg-open`) on the result.
|
||
|
||
**Needs:** `git`, a browser or `xdg-open`.
|
||
|
||
## kitty-day-save
|
||
|
||
```sh
|
||
kitty-day-save # hold a logind delay lock, flush on shutdown, exit
|
||
kitty-day-save --now # flush every running kitty immediately
|
||
```
|
||
|
||
Run by `kitty-day-save.service` (`dot_config/systemd/user/`, `WantedBy=graphical-session.target`, `Restart=always` after 10 s). It wraps itself in `systemd-inhibit --what=shutdown --mode=delay` and waits on `gdbus monitor` for login1's `PrepareForShutdown (true,)`. logind sends that before anything is killed and waits for the lock (`InhibitDelayMaxSec`, 5 s by default), so every kitty still has all its windows. It then sends `kitten day_session.py flush` over remote control to each `@kitty-<pid>` socket in `/proc/net/unix` (3 s timeout each) and exits, which releases the lock. The kitty that owns today's session saves it and holds further saves for 60 s; other kitties ignore the flush. See [kitty daily sessions](/terminal/kitty#daily-sessions).
|
||
|
||
**Needs:** `systemd-inhibit`, `gdbus`, `kitten`. Linux desktop/laptop roles only (`.chezmoiignore.tmpl`).
|
||
|
||
## launch_omp_livediff_overlay
|
||
|
||
```sh
|
||
launch_omp_livediff_overlay
|
||
```
|
||
|
||
Inside kitty with remote control enabled, runs `kitty @ launch --type=overlay-main --cwd=current omp`, then opens `livediff` in a `vsplit` next to that window with `--keep-focus`. It relies on `$KITTY_LISTEN_ON` rather than a hard-coded socket, because kitty appends `-PID` to `listen_on` socket names. It exits with an error if the variable is unset.
|
||
|
||
**Needs:** kitty with `allow_remote_control`/`listen_on` ([kitty](/terminal/kitty)), `omp` ([AI agents](/ai)), `livediff`.
|
||
|
||
## lc-elir
|
||
|
||
```sh
|
||
lc-elir [root]
|
||
```
|
||
|
||
Finds numbered LeetCode solution files (`^\d+\..+\.(js|ts)$`, for example `1365.some-slug.js`) under `root` (default `.`). fzf multi-selects them, showing the last three path segments with a `bat` preview of the first 40 lines. Each pick runs `omp -p "/leetcode-eli5 <file>"`.
|
||
|
||
**Needs:** `fd`, `fzf`, `bat`, `omp`, and the `/leetcode-eli5` omp command.
|
||
|
||
## mdcp
|
||
|
||
```sh
|
||
mdcp <url>
|
||
```
|
||
|
||
Fetches the URL as Markdown with `curl.md`, copies it with `wl-copy` or `pbcopy`, then pastes it back into `mdfried` for a rendered preview.
|
||
|
||
**Needs:** `curl.md`, `mdfried`, and `wl-clipboard` or `pbcopy`.
|
||
|
||
## mdp
|
||
|
||
```sh
|
||
mdp
|
||
```
|
||
|
||
Lists `*.md` files up to 3 directories deep with `fd`. fzf shows an `mdfried` preview (right, 60%, wrapped), and the pick opens in `mdfried`.
|
||
|
||
**Needs:** `fd`, `fzf`, `mdfried`.
|
||
|
||
## mtime-sort
|
||
|
||
```sh
|
||
… | mtime-sort [--repo]
|
||
```
|
||
|
||
Reads lines on stdin and prints them newest-first by the mtime of each line's last tab-separated field (the whole line when it has no tab). With `--repo`, it stats `<path>/.git/index` first, so a repo sorts by its last git activity. Lines whose path does not exist are dropped. Ties keep input order.
|
||
|
||
**Used by:** every custom [television](/tools/television) cable except `agents` and `omp-sessions`, and `pj --list`. tv layers match quality and frecency on top of this order.
|
||
|
||
**Needs:** `perl`.
|
||
|
||
## omp-session
|
||
|
||
```sh
|
||
omp-session
|
||
```
|
||
|
||
Starts or resumes omp for the current git repo by fixed rules, so <kbd>ctrl-a</kbd> never asks when the answer is obvious.
|
||
|
||
| HEAD | Does |
|
||
| --- | --- |
|
||
| Default branch | Resumes the newest session on it when that session was written less than 3 hours ago. Otherwise opens the `omp-sessions` [television](/tools/television#omp-sessions) cable over all of the repo's sessions; <kbd>enter</kbd> resumes the pick, <kbd>esc</kbd> returns to the prompt. With no sessions at all it starts a new one |
|
||
| Any other branch | Resumes the newest session on that branch, or starts a new one |
|
||
| Detached | Opens the `omp-sessions` cable (a new session when there are none) |
|
||
| Outside a git repo | Plain `omp` |
|
||
|
||
Resuming runs `omp --resume <session file>`; omp switches to the session's own cwd. `omp-session --new` runs plain `omp`; it is the cable's <kbd>ctrl-n</kbd> action and marks `OMP_SESSION_STATE` like a resume does, so the prompt is not moved after a new session.
|
||
|
||
**Sessions.** Every `*/*.jsonl` under `$PI_CODING_AGENT_DIR/sessions` (default `~/.omp/agent/sessions`) whose `session` header `cwd` is the worktree root or below it, excluding worktrees nested inside it. Session age is the file's mtime (the last write).
|
||
|
||
**Branches.** omp does not record the git branch. A session's branch is the one HEAD was on when the file was last written, replayed from the worktree's `git reflog` (`checkout: moving from A to B`, `Branch: renamed`, `rebase (finish): returning to`). Sessions older than the oldest reflog move belong to the branch that move left; with no moves they all belong to the current branch. The default branch is `origin/HEAD`, else `init.defaultBranch`, `main`, or `master`, whichever exists.
|
||
|
||
**Entry points.** The cable calls back into the script:
|
||
|
||
| Command | Does |
|
||
| --- | --- |
|
||
| `omp-session --list` | Prints `<age> <branch> <title>[ · <subdir>]<TAB><session file>` per session, newest first. The title is omp's session title, else the first user message |
|
||
| `omp-session --preview FILE` | Title, last-write time, cwd, then the text of every user and assistant message (thinking, tool calls, and tool results skipped) |
|
||
| `omp-session --resume FILE` | Writes `ran` to `$OMP_SESSION_STATE` when set, then `exec omp --resume FILE` (enter) |
|
||
|
||
**Prompt redraw.** The launcher runs `tv omp-sessions --inline` with `OMP_SESSION_STATE` set to a temp file. When the picker is cancelled (no `ran`), it prints `\033[A` to `/dev/tty` so the shell redraws the prompt in place; the key bindings just repaint.
|
||
|
||
**Launched by:** <kbd>ctrl-a</kbd> in fish and zsh. <kbd>ctrl-n</kbd> at the prompt runs `omp` directly, not this script.
|
||
|
||
**Needs:** `python3`, `git`, `omp`, `tv`.
|
||
|
||
## pj
|
||
|
||
```sh
|
||
pj [extra args…]
|
||
```
|
||
|
||
A task runner that searches every task source in the project and lets you pick one in the `pj` [television](/tools/television#pj) cable.
|
||
|
||
**Sources.** Each is listed only when its runner is installed:
|
||
|
||
| Source | Found in | Runner |
|
||
| --- | --- | --- |
|
||
| npm scripts | `package.json` | package manager from `packageManager`, else from the lockfile (`bun.lock[b]`, `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`, searched upward), else `npm`, then `<pm> run` |
|
||
| Make | `GNUmakefile`, `makefile`, `Makefile` | `make`. Targets come from a text parse of rules and `.PHONY`; `make -p` is avoided because it would run `$(shell …)` |
|
||
| just | `justfile`, `.justfile`, `Justfile`, `JUSTFILE` | `just` |
|
||
| mise | `mise.toml`, `.mise.toml`, `mise/config.toml`, `.mise/config.toml`, `.config/mise/config.toml`, or a `mise-tasks`/`.mise/tasks`/`mise/tasks` dir | `mise run`. Hidden tasks are skipped, and tasks inherited from parent directories are filtered out |
|
||
| devbox | `devbox.json` `shell.scripts` | `devbox run` |
|
||
| poe | `pyproject.toml` `[tool.poe.tasks]` | `poe`, else `uv run poe` |
|
||
| pdm | `[tool.pdm.scripts]` (skips `_*` and `post_*`) | `pdm run` |
|
||
| rye | `[tool.rye.scripts]` | `rye run` |
|
||
| taskipy | `[tool.taskipy.tasks]` | `task`, else `uv run task` |
|
||
| hatch | `[tool.hatch.envs.<env>.scripts]` as `env:name` | `hatch run` |
|
||
| console scripts | `[tool.poetry.scripts]`, `[project.scripts]` | `poetry run` for Poetry projects, else `uv run` |
|
||
|
||
**Scanning.** Walks from `$PWD` up to the git toplevel, inclusive. Outside a repo it stops at the first directory that produced tasks.
|
||
|
||
**Picker.** `pj` writes the records to a temp file and runs `tv pj --inline --source-command "cat <tmp>" --input-header <project root>`. Rows are tagged with the tool (`npm`, `pnpm`, `bun`, `make`, `just`, `mise`, `poe`, `py`, …), so typing a tool name filters to it. A directory column appears when more than one project contributed tasks. Tasks are sorted by their manifest's mtime, newest first, through `mtime-sort`. The preview shows the task body: the npm script string, the Make recipe, `just --show`, `mise tasks info`, the devbox script, or the pyproject entry.
|
||
|
||
**Entry points.** The cable calls back into the script:
|
||
|
||
| Command | Does |
|
||
| --- | --- |
|
||
| `pj --list` | Prints tab-separated records: display, kind, target, root, runner, manifest |
|
||
| `pj --preview KIND TARGET ROOT FILE` | Prints the task body for the preview pane |
|
||
| `pj --run KIND TARGET ROOT RUNNER` | Runs the task (enter) |
|
||
|
||
**Run.** cds into the task's directory and `exec`s the runner. Extra arguments given to `pj` travel to the task through `$PJ_EXTRA` (shell-quoted), with `--` inserted for `npm run`, `mise`, and `devbox`. Tasks named `dev`, `start`, `serve`, `watch`, or namespaced variants like `dev:web` are wrapped in `openlogs` (found on `PATH`, via `mise which`, or in mise's node installs) for a live log tail. Without openlogs they run unwrapped, with a note.
|
||
|
||
**Env.** `PJ_QUIET=1` suppresses the "no task sources found" error (exit status stays 1). The <kbd>down</kbd> bindings use it. `PJ_STATE=FILE` makes `pj` write `open` to `FILE` before launching the picker, and `pj --run` writes `ran`; the file stays empty when there are no task sources. The key bindings read it to tell no tasks, a cancelled picker, and a task that printed output apart and redraw the prompt to match. `pj` itself does no cursor handling, so typing `pj` behaves like any command.
|
||
|
||
**Launched by:** <kbd>ctrl-p</kbd>, and <kbd>down</kbd> on an empty prompt, in fish, zsh, and bash.
|
||
|
||
**Needs:** `bash`, `tv`, `mtime-sort`, `jq`, `python3` 3.11+ (for `tomllib`), plus whichever runners the project uses.
|
||
|
||
## pj-palette
|
||
|
||
```sh
|
||
pj-palette
|
||
pj-palette --run KIND TARGET ROOT RUNNER
|
||
pj-palette --cmd ROOT CMD…
|
||
```
|
||
|
||
The source of the **Project Tasks** [tmux command palette](/terminal/tmux#command-palette) (`palettes/tasks.json`). Open it with tmux `prefix t`, Ghostty <kbd>ctrl+shift+space</kbd>, or the "Project Tasks" item in the main palette.
|
||
|
||
With no arguments it reads the active pane's directory (`tmux display -p '#{pane_current_path}'`) and prints palette items as JSON, grouped by category:
|
||
|
||
| Group | Items | Shown when |
|
||
| --- | --- | --- |
|
||
| Quick | `<pm> install` (alias `install`, `i`), `<pm> run dev` (`dev`) | `package.json` at the project root. The package manager comes from `packageManager`, then the lockfile, as in `pj` |
|
||
| Quick | `uv sync` (`sync`), `uv run python` (`py`, `repl`) | `pyproject.toml` and `uv` installed |
|
||
| Quick | `make` (default target; `m`, `build`) | A Makefile and `make` |
|
||
| Quick | `go run .`, `cargo run` | `go.mod` / `Cargo.toml` and the toolchain |
|
||
| Tasks: `<tool>` | Every record from `pj --list`: npm/bun/pnpm/yarn scripts, Make, just, mise, devbox, pyproject task tables and console scripts | Whatever `pj` finds walking up to the git root |
|
||
|
||
The project root is the git toplevel, else the pane's directory.
|
||
|
||
**Run.** Every item opens a full-width split along the bottom of the window (`split-window -v -f -l 25%`), 25% of its height, in the task's directory. The command is passed to `split-window` as separate arguments, so no shell reparses it. `--run` calls `pj --run`, which keeps pj's `openlogs` wrapping of `dev`/`start`/`serve`/`watch` tasks, and `--cmd` runs a quick action. While the command runs, <kbd>ctrl-c</kbd> stops only the command (the script traps `SIGINT`), so the output stays. Once the command exits, the script prints `[exit N] enter or ctrl-c to close`, and <kbd>enter</kbd> or <kbd>ctrl-c</kbd> closes the pane; other keys are ignored.
|
||
|
||
**Needs:** `pj` and its dependencies, `jq`, tmux.
|
||
|
||
## yazi-nvim-open
|
||
|
||
```sh
|
||
yazi-nvim-open [vsplit|split|tabedit] <file>…
|
||
```
|
||
|
||
yazi's `edit` opener. When run inside a Neovim terminal (`$NVIM` set), each file's absolute path goes to the **host** Neovim through `nvim --server "$NVIM" --remote-expr 'v:lua.EditFromYazi(mode, path)'` (defined in the nvim config's `yazi_session.lua`). Outside Neovim it `exec`s a normal `nvim`, and the split modes do nothing. Set `YAZI_OPEN_TRACE=<file>` to log each call.
|
||
|
||
**Used by:** `yazi.toml` (the `edit` opener) and `keymap.toml` (<kbd>ctrl-v</kbd> vsplit, <kbd>ctrl-x</kbd> split). See [yazi](/tools/yazi).
|
||
|
||
**Needs:** `nvim`, `realpath`.
|