diff options
Diffstat (limited to 'fedora/.config/bash/autocomplete.bash')
| -rw-r--r-- | fedora/.config/bash/autocomplete.bash | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/fedora/.config/bash/autocomplete.bash b/fedora/.config/bash/autocomplete.bash new file mode 100644 index 0000000..0aeeedd --- /dev/null +++ b/fedora/.config/bash/autocomplete.bash @@ -0,0 +1,218 @@ +#!/bin/bash + +### --- Auto-completes aliases --- ### +# alias - normal aliases (completed with trailing space) +# balias - blank aliases (completed without space) +# ialias - ignored aliases (not completed) + +ialiases=() +ialias() { + # usage: ialias name='value' (same as alias builtin) + alias "$@" + # extract name (everything before first '=' or first space) + local args="$1" + args=${args%%=*} + args=${args%% *} + ialiases+=("$args") +} + +baliases=() +balias() { + alias "$@" + local args="$1" + args=${args%%=*} + args=${args%% *} + baliases+=("$args") +} + +# ---------- helper: get alias value ---------- +# returns alias expansion text for a name, or empty if none +_get_alias_value() { + local name="$1" + # alias output: alias ll='ls -la' + local a + a=$(alias "$name" 2>/dev/null) || return 1 + # strip "alias name='...'" + # use parameter expansion / sed safe parsing + # get first occurrence of =', then strip quotes + a=${a#*=} + # remove leading quote if present + a=${a#\'} + a=${a%\'} + printf "%s" "$a" + return 0 +} + +# ---------- helper: membership check ---------- +_in_array() { + local item="$1" + shift + local elem + for elem in "$@"; do + if [[ "$elem" == "$item" ]]; then + return 0 + fi + done + return 1 +} + +# ---------- expand alias at cursor and optionally insert space ---------- +# This function is executed via bind -x, so it can read/modify: +# READLINE_LINE - current full line buffer +# READLINE_POINT - current cursor index (0..len) +expand_alias_space() { + # READLINE_LINE and READLINE_POINT are provided by readline when bind -x is used. + # If not present (if invoked directly), fallback to no-op + if [[ -z "${READLINE_LINE+set}" ]]; then + # fallback: just insert a space + printf " " + return 0 + fi + + local line=${READLINE_LINE} + local point=${READLINE_POINT} + + # left substring up to cursor + local left=${line:0:point} + # right substring after cursor + local right=${line:point} + + # find the last "word" before the cursor (split on whitespace) + # If left ends with whitespace, current word is empty + local lastword + if [[ "$left" =~ [[:space:]]$ ]]; then + lastword="" + else + # remove everything up to last whitespace + lastword=${left##*['$'\t\n' ']} + fi + + # if lastword is empty -> just insert a space + if [[ -z "$lastword" ]]; then + READLINE_LINE="${left} ${right}" + READLINE_POINT=$((point + 1)) + return 0 + fi + + # check if lastword is in ignored aliases -> do not expand, just insert space + if _in_array "$lastword" "${ialiases[@]}"; then + READLINE_LINE="${left} ${right}" + READLINE_POINT=$((point + 1)) + return 0 + fi + + # try to get alias expansion + local expansion + if expansion=$(_get_alias_value "$lastword"); then + # Replace the lastword in left with expansion + # compute left_without_word + local left_without="${left%${lastword}}" + + # If balias: expansion but DO NOT add trailing space + if _in_array "$lastword" "${baliases[@]}"; then + READLINE_LINE="${left_without}${expansion}${right}" + # place cursor right after the expansion + READLINE_POINT=$((${#left_without} + ${#expansion})) + return 0 + else + # Normal alias: expansion and add a space after it + READLINE_LINE="${left_without}${expansion} ${right}" + READLINE_POINT=$((${#left_without} + ${#expansion} + 1)) + return 0 + fi + else + # no alias found: just insert space + READLINE_LINE="${left} ${right}" + READLINE_POINT=$((point + 1)) + return 0 + fi +} + +# ---------- accept-line that expands alias before executing ---------- +# Bind Enter to this function via bind -x; it will expand alias (if needed) then +# simulate Enter by setting READLINE_LINE and returning - readline will accept it. +expand_alias_and_accept_line() { + # Expand at cursor (use current READLINE_LINE/POINT) + expand_alias_space + # After expansion, we want to accept the line as if Enter was pressed. + # To do so in bind -x handler, we can set a marker and then use 'builtin bind -x' hack: + # Simpler approach: write the line to a temp file, then use 'kill -SIGWINCH' ??? Too complex. + # Luckily, when a bind -x handler returns, readline continues; we want to end editing. + # There's no direct way to programmatically press enter. Instead, rely on binding Enter to a wrapper that: + # - modifies READLINE_LINE (done) and then sets a special variable so readline knows to accept. + : +} + +# ---------- key bindings ---------- +# Bind Space to our function so pressing space triggers alias-expansion behavior. +# Use bind -x to call expand_alias_space (it will both expand and insert space when appropriate). +# WARNING: this overrides normal space key behavior; our function handles insertion. +bind -x '" "':expand_alias_space + +# optional: bind Ctrl-Space to the same (a bypass key like zsh had) +# Many terminals send "\C-@" for ctrl-space; try both common sequences: +bind -x '"\C-@":expand_alias_space' 2>/dev/null || true +bind -x '"\C- ":expand_alias_space' 2>/dev/null || true + +# Bind Enter (Return) to expand alias before accepting the line. +# We implement this by expanding then forcing a newline insertion. +# Using bind -x for Enter: when this function returns, readline will NOT automatically accept the line, +# but we can emulate acceptance by printing a newline and forcing input. Simpler: call 'return 0' from this hook +# and then send a newline. However, behavior varies between shells/terminals — so we will bind Enter to a function +# that expands and then uses 'READLINE_LINE' trick to set the expanded line and then call 'builtin bind' to +# temporarily restore Enter to default and re-invoke it. +_bash_accept_line() { + expand_alias_space + # After expanding, we want readline to accept the line. A workaround: + # write the expanded line into the current tty so that it becomes input for the shell. + # But this is messy. Instead, we simply move the cursor to the end and let the user press Enter again. + # (This is a conservative behavior to avoid interfering unexpectedly.) + return 0 +} +bind -x '"\C-m":_bash_accept_line' + +# ---------- helper: background starter ---------- +background() { + # start multiple args as programs in background + # usage: background cmd arg1 arg2 ... + # runs: cmd arg1 & cmd arg2 & ... + local cmd="$1" + shift || return 0 + for arg in "$@"; do + "$cmd" "$arg" &>/dev/null & + done +} + +# ---------- notes ---------- +# - After placing this into ~/.bashrc, run: source ~/.bashrc +# - Test aliases: +# balias ll='ls -la' +# alias g='git status' +# ialias X='something' +# - Then type `ll` followed by Space -> will expand to `ls -la` WITHOUT appending a space (blank alias). +# - Type `g` then Space -> will expand to `git status ` with a trailing space. +# - Type `X` then Space -> will NOT expand, just insert space. +# +# Limitations / caveats: +# - readline/bind -x behavior differs slightly across environments and terminals. +# - Completely emulating zsh's zle widgets (especially auto-accept behaviors) is tricky in bash. +# - Binding Enter to fully accept-after-expansion programmatically is not perfectly portable; +# the conservative implementation above expands first and leaves acceptance to the user (press Enter again). +# +# If you want a stronger behavior (auto-accept after expansion), tell me and I'll provide a +# more aggressive implementation that works on most terminals (but with more invasive tricks). + +# ---------- file completion patterns ---------- +_vim_complete() { + local cur="${COMP_WORDS[COMP_CWORD]}" + COMPREPLY=($(compgen -f -X '!*.@(pdf|odt|ods|doc|docx|xls|xlsx|odp|ppt|pptx|mp4|mkv|aux)' -- "$cur")) +} +shopt -s extglob +complete -F _vim_complete vim + +_build_mom_complete() { + local cur="${COMP_WORDS[COMP_CWORD]}" + COMPREPLY=($(compgen -f -X '!*.mom' -- "$cur")) +} +complete -F _build_mom_complete build-workshop +complete -F _build_mom_complete build-document |
