From 43be9196ebc8274f1dfb8c3b70568bda41754d3f Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sat, 18 May 2024 01:34:03 +0100 Subject: [PATCH] chore(shell): move interactive shell helpers to their own file --- zsh/util-funcs-interactive.zsh | 140 ++++++++++++++++++++++++++++++++ zshrc | 144 ++------------------------------- 2 files changed, 146 insertions(+), 138 deletions(-) create mode 100644 zsh/util-funcs-interactive.zsh diff --git a/zsh/util-funcs-interactive.zsh b/zsh/util-funcs-interactive.zsh new file mode 100644 index 0000000..1f0633c --- /dev/null +++ b/zsh/util-funcs-interactive.zsh @@ -0,0 +1,140 @@ +# +# Interactive Utility Functions +# +# Helpers designed for use during setup of interactive shell environments +# (~/.zshrc ). +# + +# setup-completions is a helper function to set up shell completions for a given +# command. It generates Zsh completion scripts and places them in the specified +# completions directory. If the completion file already exists, it checks if the +# source file has been updated and regenerates the completions if necessary. +# +# Arguments: +# +# $1 - cmd: The name of the command for which completions are being +# set up. +# $2 - source: The source file used to determine if completions need to +# be re-generated. For example, the binary file of the +# command (e.g., rustup). +# $@ - args: The command to run to generate the completions. This +# should produce Zsh completion scripts. +# +# Example usage: +# +# setup-completions rustup "$(command -v rustup)" rustup completions zsh +# +# This example sets up completions for the 'rustup' command by running +# 'rustup completions zsh', and places the generated completion script in the +# appropriate completions directory. If the source file is newer than the target +# completion file, the command is re-executed and the completion script is +# updated. +# +# The completions are placed in the directory specified by the ZSH_COMPLETIONS +# environment variable. If ZSH_COMPLETIONS is not set, the completions are +# placed in $HOME/.zsh/completions by default. +setup-completions() { + local cmd="$1" + local source="$2" + local setup_cmd="$3" + shift 3 + + local target_dir="${ZSH_COMPLETIONS:-$HOME/.zsh/completions}" + local target_file="${target_dir}/_${cmd}" + + if [[ -z "$(command -v "$cmd")" ]]; then + echo "setup-completions: Command not found: $cmd" >&2 + return 1 + fi + + if [[ -z "$(command -v "$setup_cmd")" ]]; then + echo "setup-completions: Command not found: $setup_cmd" >&2 + return 1 + fi + + if [[ -z "$cmd" || -z "$source" || -z "$setup_cmd" ]]; then + echo "setup-completions: Missing required arguments." >&2 + return 1 + fi + + # Check if the target completion file needs to be updated + if [[ ! -f "$target_file" || "$source" -nt "$target_file" ]]; then + echo "setup-completions: Setting up completion for $cmd --> $target_file" >&2 + mkdir -p "$target_dir" + "$setup_cmd" "$@" >| "$target_file" + chmod +x "$target_file" + + # Only run compinit if not already loaded + if ! (whence -w compinit &> /dev/null); then + autoload -U compinit && compinit + fi + fi +} + +# Convert a bash/zsh alias to a function. It prints the unalias command and the +# function definition, meaning the output needs to be evaluated to take effect. +# +# Arguments: +# $1: The alias to convert. Should be a single line like "alias ll='ls -alF'" +# or "ll='ls -alF'". +# +# Example: +# alias brew="op plugin run -- brew" +# convert_alias_to_function "$(alias brew)" +# +# This will print: +# unalias brew +# brew() { +# op plugin run -- brew "$@" +# } +convert-alias-source-to-function-source() { + local line="$1" + + # Remove Bash's "alias " prefix if present. + line=${line#alias } + + # Extract the alias name and the raw command. + local alias_name="$(echo "$line" | cut -d'=' -f1)" + local raw_command="$(echo "$line" | cut -d'=' -f2)" + + # Evaluate the raw command to ensure we get the correct command, with any + # quotes or shell escape characters handled correctly. + local command + eval "command=$raw_command" + + # Abort if the command is empty. + if [ -z "$command" ]; then + echo "Error: Empty command for alias $alias_name" >&2 + return 1 + fi + + # Print the unalias command and the function definition. + echo -e "unalias ${alias_name}" + echo -e "${alias_name}() {\n ${command} \"\$@\"\n}" +} + +# Convert a bash/zsh alias to a function. It replaces the alias with a function +# definition in the current shell that has the same behavior as the alias. +# +# Arguments: +# $1: The alias to convert. Should be the name of the alias. +# +# Example: +# alias brew="op plugin run -- brew" +# convert-alias-to-function brew +# +# This will replace the alias "brew" with a function that has the same behavior. +convert-alias-to-function() { + local alias_name="$1" + + # Get the alias source. + local alias_source="$(alias "$alias_name")" + + # Abort if the alias does not exist. + if [ -z "$alias_source" ]; then + echo "Error: Alias $alias_name does not exist" >&2 + return 1 + fi + + eval "$(convert-alias-source-to-function-source "$alias_source")" +} diff --git a/zshrc b/zshrc index 3712499..9d45cca 100644 --- a/zshrc +++ b/zshrc @@ -51,144 +51,6 @@ zinit light-mode wait lucid blockf \ zinit light-mode wait lucid atload"!_zsh_autosuggest_start" \ for @zsh-users/zsh-autosuggestions -# ============================================================================== -# Helpers -# ============================================================================== - -# setup-completions is a helper function to set up shell completions for a given -# command. It generates Zsh completion scripts and places them in the specified -# completions directory. If the completion file already exists, it checks if the -# source file has been updated and regenerates the completions if necessary. -# -# Arguments: -# -# $1 - cmd: The name of the command for which completions are being -# set up. -# $2 - source: The source file used to determine if completions need to -# be re-generated. For example, the binary file of the -# command (e.g., rustup). -# $@ - args: The command to run to generate the completions. This -# should produce Zsh completion scripts. -# -# Example usage: -# -# setup-completions rustup "$(command -v rustup)" rustup completions zsh -# -# This example sets up completions for the 'rustup' command by running -# 'rustup completions zsh', and places the generated completion script in the -# appropriate completions directory. If the source file is newer than the target -# completion file, the command is re-executed and the completion script is -# updated. -# -# The completions are placed in the directory specified by the ZSH_COMPLETIONS -# environment variable. If ZSH_COMPLETIONS is not set, the completions are -# placed in $HOME/.zsh/completions by default. -setup-completions() { - local cmd="$1" - local source="$2" - local setup_cmd="$3" - shift 3 - - local target_dir="${ZSH_COMPLETIONS:-$HOME/.zsh/completions}" - local target_file="${target_dir}/_${cmd}" - - if [[ -z "$(command -v "$cmd")" ]]; then - echo "setup-completions: Command not found: $cmd" >&2 - return 1 - fi - - if [[ -z "$(command -v "$setup_cmd")" ]]; then - echo "setup-completions: Command not found: $setup_cmd" >&2 - return 1 - fi - - if [[ -z "$cmd" || -z "$source" || -z "$setup_cmd" ]]; then - echo "setup-completions: Missing required arguments." >&2 - return 1 - fi - - # Check if the target completion file needs to be updated - if [[ ! -f "$target_file" || "$source" -nt "$target_file" ]]; then - echo "setup-completions: Setting up completion for $cmd --> $target_file" >&2 - mkdir -p "$target_dir" - "$setup_cmd" "$@" >| "$target_file" - chmod +x "$target_file" - - # Only run compinit if not already loaded - if ! (whence -w compinit &> /dev/null); then - autoload -U compinit && compinit - fi - fi -} - -# Convert a bash/zsh alias to a function. It prints the unalias command and the -# function definition, meaning the output needs to be evaluated to take effect. -# -# Arguments: -# $1: The alias to convert. Should be a single line like "alias ll='ls -alF'" -# or "ll='ls -alF'". -# -# Example: -# alias brew="op plugin run -- brew" -# convert_alias_to_function "$(alias brew)" -# -# This will print: -# unalias brew -# brew() { -# op plugin run -- brew "$@" -# } -convert-alias-source-to-function-source() { - local line="$1" - - # Remove Bash's "alias " prefix if present. - line=${line#alias } - - # Extract the alias name and the raw command. - local alias_name="$(echo "$line" | cut -d'=' -f1)" - local raw_command="$(echo "$line" | cut -d'=' -f2)" - - # Evaluate the raw command to ensure we get the correct command, with any - # quotes or shell escape characters handled correctly. - local command - eval "command=$raw_command" - - # Abort if the command is empty. - if [ -z "$command" ]; then - echo "Error: Empty command for alias $alias_name" >&2 - return 1 - fi - - # Print the unalias command and the function definition. - echo -e "unalias ${alias_name}" - echo -e "${alias_name}() {\n ${command} \"\$@\"\n}" -} - -# Convert a bash/zsh alias to a function. It replaces the alias with a function -# definition in the current shell that has the same behavior as the alias. -# -# Arguments: -# $1: The alias to convert. Should be the name of the alias. -# -# Example: -# alias brew="op plugin run -- brew" -# convert-alias-to-function brew -# -# This will replace the alias "brew" with a function that has the same behavior. -convert-alias-to-function() { - local alias_name="$1" - - # Get the alias source. - local alias_source="$(alias "$alias_name")" - - # Abort if the alias does not exist. - if [ -z "$alias_source" ]; then - echo "Error: Alias $alias_name does not exist" >&2 - return 1 - fi - - eval "$(convert-alias-source-to-function-source "$alias_source")" -} - # ============================================================================== # Completion # ============================================================================== @@ -217,6 +79,12 @@ autoload -z edit-command-line zle -N edit-command-line bindkey "^X^E" edit-command-line +# ============================================================================== +# Helpers +# ============================================================================== + +source "$DOTZSH/util-funcs-interactive.zsh" + # ============================================================================== # Private Dotfiles # ==============================================================================