feat(fish): add some useful plugins

This commit is contained in:
Stefan Imhoff
2023-01-05 11:23:13 +01:00
parent 1191898414
commit c86a65bf2b
16 changed files with 530 additions and 1 deletions

View File

@@ -0,0 +1,10 @@
function __abbr_tips_bind_newline
if test $__abbr_tips_used != 1
if abbr -q -- (string trim -- (commandline))
set -g __abbr_tips_used 1
else
set -g __abbr_tips_used 0
end
end
commandline -f 'execute'
end

View File

@@ -0,0 +1,11 @@
function __abbr_tips_bind_space
commandline -i " "
if test $__abbr_tips_used != 1
if abbr -q -- (string trim -- (commandline))
set -g __abbr_tips_used 1
else
set -g __abbr_tips_used 0
end
end
commandline -f 'expand-abbr'
end

View File

@@ -0,0 +1,24 @@
function __abbr_tips_init -d "Initialize abbreviations variables for fish-abbr-tips"
set -e __ABBR_TIPS_KEYS
set -e __ABBR_TIPS_VALUES
set -Ux __ABBR_TIPS_KEYS
set -Ux __ABBR_TIPS_VALUES
set -l i 1
set -l abb (string replace -r '.*-- ' '' -- (abbr -s))
while test $i -le (count $abb)
set -l current_abb (string split -m1 -- ' ' "$abb[$i]")
set -a __ABBR_TIPS_KEYS "$current_abb[1]"
set -a __ABBR_TIPS_VALUES (string trim -c '\'' -- "$current_abb[2]")
set i (math $i + 1)
end
set -l i 1
set -l abb (string replace -r '.*-- ' '' -- (alias -s))
while test $i -le (count $abb)
set -l current_abb (string split -m2 -- ' ' "$abb[$i]")
set -a __ABBR_TIPS_KEYS "a__$current_abb[2]"
set -a __ABBR_TIPS_VALUES (string trim -c '\'' -- "$current_abb[3]")
set i (math $i + 1)
end
end

138
fish/functions/__bass.py Normal file
View File

@@ -0,0 +1,138 @@
"""
To be used with a companion fish function like this:
function refish
set -l _x (python /tmp/bass.py source ~/.nvm/nvim.sh ';' nvm use iojs); source $_x; and rm -f $_x
end
"""
from __future__ import print_function
import json
import os
import signal
import subprocess
import sys
import traceback
BASH = 'bash'
FISH_READONLY = [
'PWD', 'SHLVL', 'history', 'pipestatus', 'status', 'version',
'FISH_VERSION', 'fish_pid', 'hostname', '_', 'fish_private_mode'
]
IGNORED = [
'PS1', 'XPC_SERVICE_NAME'
]
def ignored(name):
if name == 'PWD': # this is read only, but has special handling
return False
# ignore other read only variables
if name in FISH_READONLY:
return True
if name in IGNORED or name.startswith("BASH_FUNC"):
return True
return False
def escape(string):
# use json.dumps to reliably escape quotes and backslashes
return json.dumps(string).replace(r'$', r'\$')
def escape_identifier(word):
return escape(word.replace('?', '\\?'))
def comment(string):
return '\n'.join(['# ' + line for line in string.split('\n')])
def gen_script():
# Use the following instead of /usr/bin/env to read environment so we can
# deal with multi-line environment variables (and other odd cases).
env_reader = "%s -c 'import os,json; print(json.dumps({k:v for k,v in os.environ.items()}))'" % (sys.executable)
args = [BASH, '-c', env_reader]
output = subprocess.check_output(args, universal_newlines=True)
old_env = output.strip()
pipe_r, pipe_w = os.pipe()
if sys.version_info >= (3, 4):
os.set_inheritable(pipe_w, True)
command = 'eval $1 && ({}; alias) >&{}'.format(
env_reader,
pipe_w
)
args = [BASH, '-c', command, 'bass', ' '.join(sys.argv[1:])]
p = subprocess.Popen(args, universal_newlines=True, close_fds=False)
os.close(pipe_w)
with os.fdopen(pipe_r) as f:
new_env = f.readline()
alias_str = f.read()
if p.wait() != 0:
raise subprocess.CalledProcessError(
returncode=p.returncode,
cmd=' '.join(sys.argv[1:]),
output=new_env + alias_str
)
new_env = new_env.strip()
old_env = json.loads(old_env)
new_env = json.loads(new_env)
script_lines = []
for k, v in new_env.items():
if ignored(k):
continue
v1 = old_env.get(k)
if not v1:
script_lines.append(comment('adding %s=%s' % (k, v)))
elif v1 != v:
script_lines.append(comment('updating %s=%s -> %s' % (k, v1, v)))
# process special variables
if k == 'PWD':
script_lines.append('cd %s' % escape(v))
continue
else:
continue
if k == 'PATH':
value = ' '.join([escape(directory)
for directory in v.split(':')])
else:
value = escape(v)
script_lines.append('set -g -x %s %s' % (k, value))
for var in set(old_env.keys()) - set(new_env.keys()):
script_lines.append(comment('removing %s' % var))
script_lines.append('set -e %s' % var)
script = '\n'.join(script_lines)
alias_lines = []
for line in alias_str.splitlines():
_, rest = line.split(None, 1)
k, v = rest.split("=", 1)
alias_lines.append("alias " + escape_identifier(k) + "=" + v)
alias = '\n'.join(alias_lines)
return script + '\n' + alias
script_file = os.fdopen(3, 'w')
if not sys.argv[1:]:
print('__bass_usage', file=script_file, end='')
sys.exit(0)
try:
script = gen_script()
except subprocess.CalledProcessError as e:
sys.exit(e.returncode)
except Exception:
print('Bass internal error!', file=sys.stderr)
raise # traceback will output to stderr
except KeyboardInterrupt:
signal.signal(signal.SIGINT, signal.SIG_DFL)
os.kill(os.getpid(), signal.SIGINT)
else:
script_file.write(script)

View File

@@ -0,0 +1,9 @@
function _autopair_backspace
set --local index (commandline --cursor)
set --local buffer (commandline)
test $index -ge 1 &&
contains -- (string sub --start=$index --length=2 -- "$buffer") $autopair_pairs &&
commandline --function delete-char
commandline --function backward-delete-char
end

View File

@@ -0,0 +1,13 @@
function _autopair_insert_left --argument-names left right
set --local buffer (commandline)
set --local before (commandline --cut-at-cursor)
commandline --insert -- $left
switch "$buffer"
case "$before"{," "\*,$autopair_right\*}
set --local index (commandline --cursor)
commandline --insert -- $right
commandline --cursor $index
end
end

View File

@@ -0,0 +1,11 @@
function _autopair_insert_right --argument-names key
set --local buffer (commandline)
set --local before (commandline --cut-at-cursor)
switch "$buffer"
case "$before$key"\*
commandline --cursor (math (commandline --cursor) + 1)
case \*
commandline --insert -- $key
end
end

View File

@@ -0,0 +1,20 @@
function _autopair_insert_same --argument-names key
set --local buffer (commandline)
set --local index (commandline --cursor)
set --local next (string sub --start=(math $index + 1) --length=1 -- "$buffer")
if test (math (count (string match --all --regex -- "$key" "$buffer")) % 2) = 0
test $key = $next && commandline --cursor (math $index + 1) && return
commandline --insert -- $key
if test $index -lt 1 ||
contains -- (string sub --start=$index --length=1 -- "$buffer") "" " " $autopair_left &&
contains -- $next "" " " $autopair_right
commandline --insert -- $key
commandline --cursor (math $index + 1)
end
else
commandline --insert -- $key
end
end

View File

@@ -0,0 +1,7 @@
function _autopair_tab
commandline --paging-mode && down-or-search && return
string match --quiet --regex -- '\$[^\s]*"$' (commandline --current-token) &&
commandline --function end-of-line --function backward-delete-char
commandline --function complete
end

29
fish/functions/bass.fish Normal file
View File

@@ -0,0 +1,29 @@
function bass
set -l bash_args $argv
set -l bass_debug
if test "$bash_args[1]_" = '-d_'
set bass_debug true
set -e bash_args[1]
end
set -l script_file (mktemp)
if command -v python3 >/dev/null 2>&1
command python3 -sS (dirname (status -f))/__bass.py $bash_args 3>$script_file
else
command python -sS (dirname (status -f))/__bass.py $bash_args 3>$script_file
end
set -l bass_status $status
if test $bass_status -ne 0
return $bass_status
end
if test -n "$bass_debug"
cat $script_file
end
source $script_file
command rm $script_file
end
function __bass_usage
echo "Usage: bass [-d] <bash-command>"
end

View File

@@ -0,0 +1,48 @@
function replay --description "Run Bash commands replaying changes in Fish"
switch "$argv"
case -v --version
echo "replay, version 1.2.1"
case "" -h --help
echo "Usage: replay <commands> Run Bash commands replaying changes in Fish"
echo "Options:"
echo " -v or --version Print version"
echo " -h or --help Print this help message"
case \*
set --local env
set --local sep @$fish_pid(random)(command date +%s)
set --local argv $argv[1] (string escape -- $argv[2..-1])
set --local out (command bash -c "
$argv
status=\$?
[ \$status -gt 0 ] && exit \$status
command compgen -e | command awk -v sep=$sep '{
gsub(/\n/, \"\\\n\", ENVIRON[\$0])
print \$0 sep ENVIRON[\$0]
}' && alias
") || return
string replace --all -- \\n \n (
for line in $out
if string split -- $sep $line | read --local --line name value
set --append env $name
contains -- $name SHLVL PS1 BASH_FUNC || test "$$name" = "$value" && continue
if test "$name" = PATH
echo set PATH (string split -- : $value | string replace --regex --all -- '(^.*$)' '"$1"')
else if test "$name" = PWD
echo builtin cd "\"$value\""
else
echo "set --global --export $name "(string escape -- $value)
end
else
set --query env[1] && string match --entire --regex -- "^alias" $line || echo "echo \"$line\""
end
end | string replace --all -- \$ \\\$
for name in (set --export --names)
contains -- $name $env || echo "set --erase $name"
end
) | source
end
end