pi-opener

extensionmaintained

Pi extension: open files in $EDITOR via herdr, with per-extension openers (pdf, images, …)

by · v0.1.0 · published 1w ago

$ pi install npm:pi-opener
downloads/mo
145
stars
1
last push
1w ago
open issues
0

Signals

license: MITtestspi manifest: missinginstall size: —deps: 0peer deps: 0

Download trend

145 downloads · last 12 weeks (weekly)

README

pi-opener

Pi extension that opens files in your real editor.

  • Terminal editors ($EDITOR / $VISUAL / nvim) open in a herdr split pane by default
  • Pane reuse — later /opens target the same editor pane (or drive nvim/vim/hx in-place)
  • Per-extension openers send PDFs, images, etc. to the OS handler (open on macOS, xdg-open on Linux)
  • Configurable wrapper — herdr-first, or tmux/wezterm/direct via wrapperCommand
  • Slash commands /open / /o (project files) and /recent / /rec (chat-mentioned paths)
  • LLM tool open_file

Install

From npm (recommended)

pi install npm:pi-opener

Or pin a version:

pi install npm:pi-opener@0.1.0

Project-local install (writes .pi/settings.json):

pi install -l npm:pi-opener

From git

pi install git:github.com/yzuyr/pi-opener
# or
pi install https://github.com/yzuyr/pi-opener

From a local checkout

pi install /absolute/path/to/pi-opener
# or, from this repo:
pi install .

Then /reload (or restart pi).

Note: Terminal splits work best inside herdr (HERDR_PANE_ID). Without herdr, set wrapperCommand or use external openers / direct launch.

Usage

/open                     # pick from project files (cwd, ignore-aware)
/o                        # alias for /open
/open src/ind<Tab>        # filesystem path completions
/open src/index.ts
/open src/index.ts:42     # jump to line when the editor supports it

/recent                   # pick from paths mentioned in this chat
/rec                      # alias for /recent
/recent src/foo.ts:10     # open a chat-mentioned path directly
CommandSource
/open, /oFiles under cwd (skips node_modules, .gitignore, etc.)
/recent, /recPaths scraped from this session that still exist on disk (including ignored paths if the chat referenced them)

Pi has no built-in command-alias API, so short names are registered as separate commands sharing handlers.

The agent can also call open_file.

Config

Primary configuration is loaded from ~/.config/pi-opener/config.yaml (or config.yml).

~/.config/pi-opener/config.yaml

wrapperCommand: herdr

opener:
  code: druk %p:%l # files (line optional → 0)
  dir: druk %p # directories — no %l
  pdf: xdg-open %p # extension keys: with or without leading dot
  md: glow -p %p

See config.example.yaml.

KeyMeaning
opener.codeDefault code editor (default / * / editor also accepted)
opener.dirDirectory opener (directory / folder aliases). Default: platform opener
opener.<ext>Opener for that extension (pdf, .pdf, md, …)
wrapperCommandHow terminal openers launch (see below). Aliases: wrapper, wrapper_command

Directories are detected via stat and never go through opener.code, so a file template like %p:%l will not produce dirpath:0 unless you put %l in opener.dir yourself.

wrapperCommand (herdr-first, not herdr-only)

Terminal openers (nvim, bunx druk, …) are launched through a wrapper. Default is herdr when HERDR_PANE_ID is set; otherwise the command runs directly.

Herdr pane reuse and right-split direction are built-in. If you want to change the split direction or force a new pane every time, set a custom wrapperCommand.

# default behavior (can omit)
wrapperCommand: herdr

# never use a wrapper — spawn the opener directly
wrapperCommand: none

# custom split / terminal launcher (e.g. tmux down split)
wrapperCommand: "tmux split-window -v %c"
wrapperCommand: ["wezterm", "cli", "split-pane", "--", "%@"]
ValueEffect
herdr (default)herdr pane split + run; falls back to direct if herdr is unavailable
none / direct / falserun opener argv directly (no split)
stringshell-ish command; %c = full opener command (quoted)
string arrayargv prefix; %@ or %c splices opener argv, else argv is appended

External openers (xdg-open, opener.dir default, media) never use the wrapper.

Placeholders

TokenValue
%pAbsolute file path
%lLine number, or 0 if none
%cColumn, or 0 if none

If %p is omitted, the path is appended automatically (with editor-specific line jumps when possible).

Platform default openers

OSCommand
macOSopen
Linux / otherxdg-open
Windowscmd /c start ""

Applied to common media extensions (pdf, images, audio, video). Override per-extension under opener:.

mode is auto-detected for xdg-open, open, start, gio, wslview, cmdexternal (detached). Everything else defaults to terminal (launched via wrapper).

Line numbers

EditorJump (when no %l in template)
nvim / vim / vi / nano / emacs+LINE
helixfile:LINE
vscode / cursor / zed--goto file:LINE
sublimefile:LINE
kate--line=LINE

Prefer explicit templates when you care: code: nvim +%l %p.

Development

bun install          # or: npm install
bun test
bun run typecheck
npm pack --dry-run   # verify publish contents

Pure logic lives in src/core.ts; the Pi extension entrypoint is src/index.ts.

Publish (maintainers)

# 1. ensure clean tree, tests green
bun test && bun run typecheck

# 2. bump version in package.json if needed
# 3. publish
npm publish --access public

# 4. users install with:
#    pi install npm:pi-opener

Pi installs packages with production deps only (npm install --omit=dev), so runtime deps must stay in dependencies (ignore, yaml). Pi-provided packages stay in peerDependencies (@earendil-works/pi-coding-agent, @earendil-works/pi-tui, typebox).