mirror of
https://github.com/ohmyzsh/ohmyzsh.git
synced 2026-01-02 02:19:06 +01:00
feat(plugins): add zsh-vi-man plugin for smart man page lookup in vi mode
This commit is contained in:
parent
0f45f82c0a
commit
93de73a77a
3 changed files with 182 additions and 0 deletions
67
plugins/zsh-vi-man/README.md
Normal file
67
plugins/zsh-vi-man/README.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# zsh-vi-man plugin
|
||||
|
||||
Smart man page lookup for zsh vi mode. Press `K` (Shift-K) on any command or option to instantly open its man page.
|
||||
|
||||
To use it, add `zsh-vi-man` to the plugins array in your zshrc file:
|
||||
|
||||
```zsh
|
||||
plugins=(... zsh-vi-man)
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **Smart Detection**: Automatically finds the right man page for subcommands (e.g., `git commit` → `man git-commit`)
|
||||
- **Option Jumping**: Opens man page directly at the option definition (e.g., `grep -r` → jumps to `-r` entry)
|
||||
- **Combined Options**: Works with combined short options (e.g., `rm -rf` → finds both `-r` and `-f`)
|
||||
- **Value Extraction**: Handles options with values (e.g., `--color=always` → searches `--color`)
|
||||
- **Pipe Support**: Detects correct command in pipelines (e.g., `cat file | grep -i` → opens `man grep`)
|
||||
- **Multiple Formats**: Supports various man page styles (GNU, jq, find, etc.)
|
||||
|
||||
## Usage
|
||||
|
||||
1. Type a command (e.g., `ls -la` or `git commit --amend`)
|
||||
2. Press `Escape` to enter vi normal mode
|
||||
3. Move cursor to any word
|
||||
4. Press **`K`** to open the man page
|
||||
|
||||
### Examples
|
||||
|
||||
| Command | Cursor On | Result |
|
||||
| :--------------------- | :------------- | :----------------------------------- |
|
||||
| `ls -la` | `ls` | Opens `man ls` |
|
||||
| `ls -la` | `-la` | Opens `man ls`, jumps to `-l` |
|
||||
| `git commit --amend` | `commit` | Opens `man git-commit` |
|
||||
| `grep --color=auto` | `--color=auto` | Opens `man grep`, jumps to `--color` |
|
||||
| `cat file \| sort -r` | `-r` | Opens `man sort`, jumps to `-r` |
|
||||
| `find . -name "*.txt"` | `-name` | Opens `man find`, jumps to `-name` |
|
||||
|
||||
## Configuration
|
||||
|
||||
Set these variables **before** sourcing oh-my-zsh:
|
||||
|
||||
```zsh
|
||||
# Change the trigger key (default: K)
|
||||
ZVM_MAN_KEY='?'
|
||||
|
||||
# Use a different pager (default: less)
|
||||
ZVM_MAN_PAGER='bat'
|
||||
```
|
||||
|
||||
## Integration with zsh-vi-mode
|
||||
|
||||
This plugin works seamlessly with [zsh-vi-mode](https://github.com/jeffreytse/zsh-vi-mode). It automatically detects zsh-vi-mode and hooks into its lazy keybindings system.
|
||||
|
||||
For best results, ensure zsh-vi-mode is loaded before this plugin:
|
||||
|
||||
```zsh
|
||||
plugins=(... zsh-vi-mode zsh-vi-man)
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- zsh with vi mode enabled (built-in or via `vi-mode` plugin)
|
||||
- `man` command available
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see [LICENSE](https://github.com/TunaCuma/zsh-vi-man/blob/main/LICENSE) for details.
|
||||
7
plugins/zsh-vi-man/zsh-vi-man.plugin.zsh
Normal file
7
plugins/zsh-vi-man/zsh-vi-man.plugin.zsh
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# According to the standard:
|
||||
# https://zdharma-continuum.github.io/Zsh-100-Commits-Club/Zsh-Plugin-Standard.html
|
||||
0="${ZERO:-${${0:#$ZSH_ARGZERO}:-${(%):-%N}}}"
|
||||
0="${${(M)0:#/*}:-$PWD/$0}"
|
||||
|
||||
source "${0:h}/zsh-vi-man.zsh"
|
||||
|
||||
108
plugins/zsh-vi-man/zsh-vi-man.zsh
Normal file
108
plugins/zsh-vi-man/zsh-vi-man.zsh
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# zsh-vi-man.zsh -- Smart man page viewer for zsh vi mode
|
||||
# https://github.com/TunaCuma/zsh-vi-man
|
||||
#
|
||||
# Press K in vi normal mode to open the man page for the current command.
|
||||
# If your cursor is on an option (like -r or --recursive), it will jump
|
||||
# directly to that option in the man page.
|
||||
#
|
||||
# MIT License - Copyright (c) 2025 Tuna Cuma
|
||||
|
||||
# Configuration variables (can be set before sourcing)
|
||||
# ZVM_MAN_KEY: the key to trigger man page lookup (default: K)
|
||||
# ZVM_MAN_PAGER: the pager to use (default: less)
|
||||
|
||||
: ${ZVM_MAN_KEY:=K}
|
||||
: ${ZVM_MAN_PAGER:=less}
|
||||
|
||||
function zvm-man() {
|
||||
# Get the word at cursor position
|
||||
local left="${LBUFFER##*[[:space:]]}"
|
||||
local right="${RBUFFER%%[[:space:]]*}"
|
||||
local word="${left}${right}"
|
||||
|
||||
# Find the current command segment (handles pipes: tree | grep -A)
|
||||
# Get everything after the last pipe before cursor
|
||||
local current_segment="${LBUFFER##*|}"
|
||||
# Trim leading whitespace
|
||||
current_segment="${current_segment#"${current_segment%%[![:space:]]*}"}"
|
||||
# Extract the command (first word of segment)
|
||||
local cmd="${current_segment%%[[:space:]]*}"
|
||||
|
||||
if [[ -z "$cmd" ]]; then
|
||||
zle -M "No command found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Determine the man page to open
|
||||
local man_page="$cmd"
|
||||
local rest="${current_segment#*[[:space:]]}"
|
||||
local potential_subcommand="${rest%%[[:space:]]*}"
|
||||
|
||||
# Check for subcommand man pages (e.g., git-commit, docker-run)
|
||||
if [[ -n "$potential_subcommand" && ! "$potential_subcommand" =~ ^- ]]; then
|
||||
if man -w "${cmd}-${potential_subcommand}" &>/dev/null; then
|
||||
man_page="${cmd}-${potential_subcommand}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Build the search pattern for the current word
|
||||
# Patterns match option definitions: lines starting with whitespace then dash
|
||||
# Supports comma-separated (GNU style) and slash-separated (jq style) options
|
||||
local pattern=""
|
||||
if [[ -n "$word" ]]; then
|
||||
# Long option with value: --color=always -> search for --color
|
||||
if [[ "$word" =~ ^--[^=]+= ]]; then
|
||||
local opt="${word%%=*}"
|
||||
pattern="^[[:space:]]*${opt}([,/=:[[:space:]]|$)|^[[:space:]]*-.*[,/][[:space:]]+${opt}([,/=:[[:space:]]|$)"
|
||||
# Combined short options: -rf -> search for -[rf] to find individual options
|
||||
# Also includes fallback for single-dash long options like find's -name, -type
|
||||
elif [[ "$word" =~ ^-[a-zA-Z]{2,}$ ]]; then
|
||||
local chars="${word:1}"
|
||||
# Pattern 1: individual chars (e.g., -r or -f from -rf)
|
||||
# Pattern 2: the full word as-is (e.g., -name for find)
|
||||
pattern="^[[:space:]]*-[${chars}][,/:[:space:]]|^[[:space:]]*-.*[,/][[:space:]]+-[${chars}][,/:[:space:]]|^[[:space:]]*${word}([,/:[:space:]]|$)|^[[:space:]]*-.*[,/][[:space:]]+${word}([,/:[:space:]]|$)"
|
||||
# Single short option: -r -> match at start of option definition line
|
||||
elif [[ "$word" =~ ^-[a-zA-Z]$ ]]; then
|
||||
pattern="^[[:space:]]*${word}[,/:[:space:]]|^[[:space:]]*-.*[,/][[:space:]]+${word}([,/:[:space:]]|$)"
|
||||
# Long option without value: --recursive
|
||||
elif [[ "$word" =~ ^-- ]]; then
|
||||
pattern="^[[:space:]]*${word}([,/=:[[:space:]]|$)|^[[:space:]]*-.*[,/][[:space:]]+${word}([,/=:[[:space:]]|$)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Clear screen and open man page
|
||||
zle -I
|
||||
|
||||
if [[ -n "$pattern" ]]; then
|
||||
man "$man_page" 2>/dev/null | ${ZVM_MAN_PAGER} -p "${pattern}" 2>/dev/null || \
|
||||
man "$man_page" 2>/dev/null | ${ZVM_MAN_PAGER}
|
||||
else
|
||||
man "$man_page" 2>/dev/null || zle -M "No manual entry for ${man_page}"
|
||||
fi
|
||||
|
||||
zle reset-prompt
|
||||
}
|
||||
|
||||
# Register the widget and bind the key
|
||||
zle -N zvm-man
|
||||
|
||||
function _zvm_man_bind_key() {
|
||||
bindkey -M vicmd "${ZVM_MAN_KEY}" zvm-man
|
||||
}
|
||||
|
||||
# Support both immediate binding and lazy loading with zsh-vi-mode
|
||||
if (( ${+functions[zvm_after_lazy_keybindings]} )); then
|
||||
# zsh-vi-mode is loaded with lazy keybindings, hook into it
|
||||
if [[ -z "${ZVM_LAZY_KEYBINDINGS}" ]] || [[ "${ZVM_LAZY_KEYBINDINGS}" == true ]]; then
|
||||
zvm_after_lazy_keybindings_commands+=(_zvm_man_bind_key)
|
||||
else
|
||||
_zvm_man_bind_key
|
||||
fi
|
||||
elif (( ${+functions[zvm_after_init]} )); then
|
||||
# zsh-vi-mode without lazy keybindings
|
||||
zvm_after_init_commands+=(_zvm_man_bind_key)
|
||||
else
|
||||
# Standalone or other vi-mode setups
|
||||
_zvm_man_bind_key
|
||||
fi
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue