mirror of
https://github.com/keanuplayz/dotfiles.git
synced 2024-08-15 02:33:12 +00:00
replace command palette with a snippet palette
This commit is contained in:
parent
3edacb8d37
commit
51bb000d6a
3 changed files with 108 additions and 80 deletions
107
lib/palette.zsh
Normal file
107
lib/palette.zsh
Normal file
|
@ -0,0 +1,107 @@
|
|||
#!/usr/bin/env zsh
|
||||
|
||||
# This file contains a ZLE widget called 'palette' that lets you select a
|
||||
# command snippet and fill in its placeholders. It uses "TLDR pages" as the
|
||||
# snippet database, so the widget will download them on the first invocation.
|
||||
# Or, you can also create a symlink to a local cache of a "TLDR pages" client,
|
||||
# e.g. for tealdeer (which is what I use):
|
||||
#
|
||||
# ln -sv ~/.cache/tealdeer/tldr-master/pages $ZSH_CACHE_DIR/tldr-pages
|
||||
#
|
||||
# Usage:
|
||||
# 1. press Alt+Shift+P (or Esc+Shift+P)
|
||||
# 2. select snippet in the fuzzy finder (fzf)
|
||||
# 3. Press Alt+Shift+P again, this time it'll take you to the first placeholder
|
||||
# 4. Enter some text
|
||||
# 5. Repeat steps 3 and 4 until there're no placeholders left
|
||||
#
|
||||
# Requirements/Dependencies:
|
||||
# 1. AWK (any implementation will probably work) for parsing "TLDR pages"
|
||||
# 2. the FZF fuzzy finder
|
||||
# 3. Tar (any implementation will probably work) and Curl for downloading
|
||||
# "TLDR pages"
|
||||
|
||||
PALETTE_TLDR_PAGES_DIR="$ZSH_CACHE_DIR/tldr-pages"
|
||||
|
||||
# strings which are used to mark placeholders (please don't modify)
|
||||
PALETTE_PLACEHOLDER_START="{{"
|
||||
PALETTE_PLACEHOLDER_END="}}"
|
||||
|
||||
# a string which is used to separate snippet from its description in the
|
||||
# fuzzy-finder
|
||||
PALETTE_SNIPPET_COMMENT=" ## "
|
||||
|
||||
# Main function of the widget
|
||||
_palette_widget() {
|
||||
# download "TLDR pages" if we don't have them
|
||||
if [[ ! -d "$PALETTE_TLDR_PAGES_DIR" ]]; then
|
||||
echo
|
||||
_palette_download_tldr_pages
|
||||
echo
|
||||
fi
|
||||
|
||||
# try to fill in a placeholder if there're any, otherwise pick a snippet
|
||||
if ! _palette_fill_in_placeholder; then
|
||||
local selected
|
||||
if selected="$(_palette_parse_tldr_pages | fzf --ansi --cycle --height 50% --reverse)"
|
||||
then
|
||||
# paste selected snippet without its description
|
||||
zle -U "${selected%%$PALETTE_SNIPPET_COMMENT*}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# immediately redraw
|
||||
zle redisplay
|
||||
}
|
||||
|
||||
# This function deletes the first placeholder from the buffer and places the
|
||||
# cursor at the beginning of that placeholder. If there're no placeholders in
|
||||
# the buffer, it exits with exit code 1.
|
||||
_palette_fill_in_placeholder() {
|
||||
# NOTE!!! indexes in ZSH arrays start at one!
|
||||
local start_index="${BUFFER[(i)$PALETTE_PLACEHOLDER_START]}"
|
||||
(( start_index == 0 || start_index > ${#BUFFER} )) && return 1
|
||||
local end_index="${BUFFER[(i)$PALETTE_PLACEHOLDER_END]}"
|
||||
# the CURSOR variable is zero-based while ZSH arrays are one-based
|
||||
(( CURSOR = start_index - 1 ))
|
||||
BUFFER="${BUFFER[1,start_index-1]}${BUFFER[end_index+2,${#BUFFER}]}"
|
||||
}
|
||||
|
||||
# This function parses "TLDR pages" for snippets using AWK. Fortunately, all
|
||||
# "TLDR pages" files are use the same Markdown-like syntax so they're very easy
|
||||
# to parse.
|
||||
_palette_parse_tldr_pages() {
|
||||
# I chose to use AWK here because it was designed specifically for text
|
||||
# processing and includes all basic utilities that I need here.
|
||||
awk '
|
||||
# when we find a "description" line...
|
||||
match($0, /^- (.+):$/, match_groups) {
|
||||
# ...get actual description from it...
|
||||
description = match_groups[1]
|
||||
# ...then skip any lines that are not actual commands, while saving RegEx
|
||||
# match groups...
|
||||
while (!match($0, /^`(.+)`$/, match_groups)) getline
|
||||
# ...after that we can get the command...
|
||||
command = match_groups[1]
|
||||
# ...and finally, we print command and description, separated by
|
||||
# PALETTE_SNIPPET_COMMENT, and with some colors!
|
||||
printf "%s\x1b[90m'"$PALETTE_SNIPPET_COMMENT"'%s\x1b[0m\n", command, description
|
||||
}
|
||||
' "$PALETTE_TLDR_PAGES_DIR"/**/*.md
|
||||
}
|
||||
|
||||
# This function downloads the "TLDR pages"
|
||||
_palette_download_tldr_pages() {
|
||||
mkdir -pv "$PALETTE_TLDR_PAGES_DIR"
|
||||
echo "Downloading tldr pages..."
|
||||
|
||||
if curl -Lf https://github.com/tldr-pages/tldr/archive/master.tar.gz |
|
||||
tar -C "$PALETTE_TLDR_PAGES_DIR" --gzip --strip-components 2 --extract tldr-master/pages
|
||||
then
|
||||
echo "Done!"
|
||||
fi
|
||||
}
|
||||
|
||||
# finally, bind the widget to Alt+Shift+P (or Esc+Shift+P)
|
||||
zle -N _palette_widget
|
||||
bindkey "^[P" _palette_widget
|
|
@ -1,79 +0,0 @@
|
|||
#!/usr/bin/env zsh
|
||||
|
||||
# define an associative array for widgets with their corresponding keybindings
|
||||
typeset -A widgets_list
|
||||
# get all widgets ('widgets' -> http://zsh.sourceforge.net/Doc/Release/Zsh-Modules.html#The-zsh_002fzleparameter-Module)
|
||||
for widget_name widget_info in ${(kv)widgets}; do
|
||||
# ignore built-in widgets starting with a dot because ZSH defines them both
|
||||
# with and without the dot
|
||||
[[ "$widget_name" == .* ]] && continue
|
||||
# ignore completion widgets
|
||||
[[ "$widget_info" == completion:* ]] && continue
|
||||
# by default, widgets don't have keybindings
|
||||
widgets_list[$widget_name]="none"
|
||||
done
|
||||
|
||||
# get keybindings for widgets (one widget can have multiple keybindings)
|
||||
|
||||
# iterate over existing keybindings (the 'f' flag splits output of the command
|
||||
# by the '\n' char)
|
||||
for line in "${(@f)$(bindkey)}"; do
|
||||
# parse line a string of command-line arguments (eval is required here!)
|
||||
eval "line_parts=($line)"
|
||||
# array indexes in ZSH start from 1 (o_O)
|
||||
widget_key="$line_parts[1]"
|
||||
widget_name="$line_parts[2]"
|
||||
|
||||
widget_keys="$widgets_list[$widget_name]"
|
||||
if [[ -z "$widget_keys" ]]; then
|
||||
continue
|
||||
else
|
||||
case "$widget_keys" in
|
||||
none) widget_keys="keys:" ;;
|
||||
keys:*) widget_keys+=" " ;;
|
||||
esac
|
||||
widgets_list[$widget_name]="$widget_keys{$widget_key}"
|
||||
fi
|
||||
done
|
||||
|
||||
# convert list of widgets into a string
|
||||
widgets_str=""
|
||||
for widget_name widget_keys in ${(kv)widgets_list}; do
|
||||
widgets_str+="$widget_name"
|
||||
if [[ "$widget_keys" == keys:* ]]; then
|
||||
# remove the 'keys:' prefix
|
||||
widgets_str+=" ${widget_keys#keys:}"
|
||||
fi
|
||||
widgets_str+=$'\n'
|
||||
done
|
||||
# remove the trailing newline from the string
|
||||
widgets_str="${widgets_str%$'\n'}"
|
||||
|
||||
unset widget_{name,info,key,keys}
|
||||
|
||||
# command palette allows you to search for widgets
|
||||
_command-palette() {
|
||||
# widget is selected with a fuzzy finder
|
||||
local widget="$(echo "$widgets_str" | fzf)"
|
||||
if [[ -n "$widget" ]]; then
|
||||
# parse widget name by cutting the selected string to the first space (which
|
||||
# may contain keybindings)
|
||||
widget="${widget%%$' '*}"
|
||||
# HACK: This small Python script is used to send simluated keystrokes to the
|
||||
# current TTY. It first executes the 'execute-named-cmd' widget, then
|
||||
# sends the widget name and finally types the 'Enter' key. (Python was
|
||||
# chosen because it supports required functionallity out of the box).
|
||||
# NOTE! This script may not work on all platforms (especially on Windows)!!!
|
||||
python -c "
|
||||
import fcntl, termios
|
||||
with open('$TTY') as tty:
|
||||
# ('\x1b' is the 'escape' char)
|
||||
for char in '\x1bx${widget}\n':
|
||||
# 'ioctl' is a syscall that can send special commands to file descriptors.
|
||||
# 'TIOCSTI' is one of these commands and can be used to simulate keypresses.
|
||||
fcntl.ioctl(tty, termios.TIOCSTI, char)
|
||||
"
|
||||
fi
|
||||
}
|
||||
zle -N command-palette _command-palette
|
||||
bindkey "^[P" command-palette # Esc-Shift-P or Alt-Shift-P
|
2
zshrc
2
zshrc
|
@ -2,7 +2,7 @@
|
|||
|
||||
DOTFILES_PATH="${0:h}"
|
||||
|
||||
for script in functions path exports zgen aliases widgets theme; do
|
||||
for script in functions path exports zgen aliases palette theme; do
|
||||
source "$DOTFILES_PATH/lib/$script.zsh"
|
||||
source_if_exists "$DOTFILES_PATH/custom/$script.zsh"
|
||||
done
|
||||
|
|
Loading…
Reference in a new issue