Skip to content

yemelgen/zhint

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

zhint

A Zsh module that lets you define meta commands - high-level actions like open, list, see, or copy that automatically resolve to the right shell command based on file type, MIME type, source patterns, and custom tests.

Instead of remembering dozens of commands for different file formats and protocols, you define rules once and use simple verbs everywhere.

zhint demo

Why?

Aliases are static. You can alias o to open, but what if you want open to behave differently for PDFs, archives, SSH hosts, and SQLite databases? zhint solves this with a rule engine:

# "open" a PDF -> opens in Preview (macOS) or converts to text
# "open" an SSH URI -> starts an SSH session
# "open" a .tar.gz -> opens in Finder
# "list" a .tar.gz -> lists archive contents
# "list" an SSH path -> runs ls on remote host
# "see" a text file -> cats it
# "see" a PDF -> extracts text with pdftotext

All through the same verbs: o, l, c, cp, etc.

Features

  • Define rules that match by action, source pattern, file type, MIME type, and custom tests
  • URI-aware: parses ssh://, http://, local paths, and more into components
  • Placeholder substitution: %F (filepath), %H (host), %P (port), conditional %(P.-p %P.%), etc.
  • Command fallbacks: list multiple commands, the first available one is used
  • Tab completion for actions, remote files (SSH), and archive contents
  • Comes with built-in hint collections for archives, remote access, media, and more

Installation

Manual

git clone https://github.com/yemelgen/zhint.git
cd zhint

# Copy functions to your zsh functions directory
mkdir -p ~/.zsh/functions
cp functions/* ~/.zsh/functions/

# Add to your .zshrc
echo 'fpath=(~/.zsh/functions $fpath)' >> ~/.zshrc
echo 'autoload -Uz zhint zrun' >> ~/.zshrc

# Load the built-in hint collections (optional)
echo 'for f in /path/to/zhint/hints/*.zsh; do source "$f"; done' >> ~/.zshrc

Then restart your shell or run source ~/.zshrc.

Verify

zhint -l    # Should list loaded rules
zrun -h     # Should show usage

Quick Start

Add the following to your .zshrc:

ZHINT_DIR="/path/to/zhint" # adjust to your install location
fpath=($ZHINT_DIR/functions $fpath)

autoload -Uz compinit && compinit
autoload -Uz zhint && zhint
autoload -Uz zrun && zrun

# Load built-in hint collections
for file in $ZHINT_DIR/hints/*.zsh; do
    source "$file"
done

# Short aliases for meta commands
if typeset -f zrun > /dev/null; then
    alias l='zrun l'        # list
    alias ll='zrun ll'      # long list
    alias c='zrun c'        # see (cat)
    alias o='zrun o'        # open
    alias e='zrun e'        # edit
    alias x='zrun x'        # examine
    alias s='zrun s'        # search
    alias cp='zrun cp'      # copy
    alias mv='zrun mv'      # move
    alias rm='zrun rm'      # remove
    alias cv='zrun cv'      # convert
fi

Then restart your shell or run source ~/.zshrc. Now you can just type:

l archive.tar.gz               # list archive contents
l archive.tar.gz#subdir/       # list inside archive subdirectory (with tab completion!)
c archive.tar.gz#path/file.txt # see a file inside an archive
o myfile.pdf                   # open with default app
c ssh://server/etc/hosts       # cat a remote file
cp report.json https://api.example.com/upload  # POST to HTTP endpoint

Rule Syntax

A rule has 9 colon-separated fields:

actions:sources:src_types:src_mimes:destinations:dst_types:dst_mimes:tests:commands
Field Description Example
actions Comma-separated meta command names open,o
sources Glob patterns for source inputs *.pdf, ssh:*
src_types File type: f d b c s (string) f
src_mimes MIME type patterns text/*, application/pdf
destinations Glob patterns for destination *.zip, ssh:*
dst_types Destination file type d
dst_mimes Destination MIME type .
tests Commands that must return 0 which jq
commands Comma-separated commands (first available is used) code %F,vim %F,less %F

Use . for "match anything" and * for "match any non-empty value".

Examples

# Open text files with code, fallback to open, then less
zhint 'open,o:*:f:text/*:.:.:.:.:code %F,open %F,less %F'

# List tar archive contents
zhint 'list,l:*:f:application/gzip:.:.:.:.:tar -tf %F'

# SSH into a remote host
zhint 'open,o:ssh\:*:.:.:.:.:.:.:ssh %(P.-p %P.%) %(U.%U@.%)%H'

# Copy files to remote via SCP
zhint 'copy,cp:*:f,d:.:ssh\:*:.:.:.:scp %(P0.-P %P0.%) %F %(U0.%U0@.%)%H0:%F0'

# POST JSON to an HTTP endpoint
zhint 'copy,cp:*:f:application/json:http*:.:.:.:curl -X POST -s %T -H "Content-Type: application/json" -d @%F | jq .'

Placeholders

Placeholders are substituted into the commands field at runtime:

Placeholder Description
%C The action name
%X All sources (quoted)
%T Destination
%F All parsed file paths
%A All source inputs
%S All parsed schemes
%U All parsed usernames
%W All parsed passwords
%H All parsed hostnames
%P All parsed ports
%Q All parsed queries
%R All parsed fragments

Access individual arguments with a digit suffix: %F0 (destination path), %F1 (first source), %F2 (second source), etc.

Conditional Substitution

%(placeholder.ifTrue.ifFalse%)

If the placeholder has a value, use ifTrue; otherwise use ifFalse. For example:

%(P.-p %P.%)     # Produces "-p 22" if port is set, empty otherwise
%(U.%U@.%)       # Produces "user@" if username is set, empty otherwise

Managing Rules

zhint -a 'rule...'    # Add a rule (or just: zhint 'rule...')
zhint -d 'rule...'    # Delete a rule
zhint -l              # List all rules

Running with Debug Output

zrun open -v myfile.pdf    # Verbose: shows rule matching and placeholder substitution
zrun open -t myfile.pdf    # Test mode: prints the resolved command without executing

License

MIT License. See LICENSE.txt.

About

ZSH Hint Manager

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages