Skip to content

Instantly share code, notes, and snippets.

@montasaurus
Last active April 20, 2024 21:32
Show Gist options
  • Star 29 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save montasaurus/5ccbe453ef863f702291e763b1b63daf to your computer and use it in GitHub Desktop.
Save montasaurus/5ccbe453ef863f702291e763b1b63daf to your computer and use it in GitHub Desktop.
AI Shell Command Generator
llmc() {
local system_prompt='Output a command that I can run in a ZSH terminal on macOS to accomplish the following task. Try to make the command self-documenting, using the long version of flags where possible. Output the command first enclosed in a "```zsh" codeblock followed by a concise explanation of how it accomplishes it.'
local temp_file=$(mktemp)
local capturing=true
local command_buffer=""
local first_line=true
local cleaned_up=false # Flag to indicate whether cleanup has been run
cleanup() {
# Only run cleanup if it hasn't been done yet
if [[ "$cleaned_up" == false ]]; then
cleaned_up=true # Set the flag to prevent duplicate cleanup
# Check if the temporary file exists before attempting to read from it
if [[ -f "$temp_file" ]]; then
while IFS= read -r line; do
if [[ "$line" == '```zsh' ]]; then
command_buffer=""
first_line=true
elif [[ "$line" == '```' && "$capturing" == true ]]; then
if [[ "$first_line" == true ]]; then
echo -n "$command_buffer" | pbcopy
else
echo -n "${command_buffer//$'\n'/\\n}" | pbcopy
fi
break
elif [[ "$capturing" == true ]]; then
if [[ "$first_line" == false ]]; then
command_buffer+=$'\n'
fi
command_buffer+="$line"
first_line=false
fi
done <"$temp_file"
fi
# Always attempt to remove the temporary file if it exists
[[ -f "$temp_file" ]] && rm "$temp_file"
# Reset the signal trap to the default behavior to clean up resources
trap - SIGINT
fi
}
# Set the trap for cleanup on SIGINT
trap cleanup SIGINT
llm -s "$system_prompt" "$1" | tee >(cat >"$temp_file")
# Ensure cleanup is performed if not already done by trap
cleanup
}

AI Shell Command Generator using LLM

  • Prompts llm to write you a simple shell command with an explanation.
  • Copies the command to your clipboard (even if you cancel generation before the explanation completes).

Usage

llmc 'revert the changes from the last two git commits'

Installation

Install and configure the llm CLI tool. Add the llmc function to your .zshrc.

Caveats

  • Prompts specifically for a ZSH command on a macOS machine
  • Obviously, be careful running commands you don't understand & use at your own risk.
@kamalmost
Copy link

Very good one, Any plans for bash? I can work on this but, I thought of asking first if you are planing for this.

@montasaurus
Copy link
Author

Very good one, Any plans for bash? I can work on this but, I thought of asking first if you are planing for this.

@kamalmost I think it should work in Bash as is, you’d just want to put it in .bashrc and change the prompt to say it’s a bash terminal instead

@kquinsland
Copy link

The cleanup() function may not work on all systems. I get this error:

cleanup:15: command not found: xsel

This is because pbcopy is aliased to xsel

❯ which pbcopy
pbcopy: aliased to xsel --clipboard --input

which is not (commonly) installed on newer "wayland only" linux distros but there is a helpful detect-clipboard() function for any oh-my-zsh user

Here is a revised function that will try to select the appropriate copy tool:

llmc() {
    local system_prompt='Output a command that I can run in a ZSH terminal on macOS to accomplish the following task. Try to make the command self-documenting, using the long version of flags where possible. Output the command first enclosed in a "```zsh" codeblock followed by a concise explanation of how it accomplishes it.'
    local temp_file=$(mktemp)
    local capturing=true
    local command_buffer=""
    local first_line=true
    local cleaned_up=false # Flag to indicate whether cleanup has been run
    local copy_command # Initialize without setting a default

    # Check if Oh-My-Zsh is installed, use clipcopy; otherwise, check for xsel
    if [[ -n "$ZSH" ]]; then
        copy_command="clipcopy" # Use clipcopy if Oh-My-Zsh is detected
    elif command -v xsel &>/dev/null; then
        copy_command="xsel --clipboard --input" # Fallback to xsel if available
    else
        echo "Neither clipcopy nor xsel is available for clipboard operations."
        return 1 # Exit the function with an error status if no suitable command is found
    fi

    cleanup() {
        # Only run cleanup if it hasn't been done yet
        if [[ "$cleaned_up" == false ]]; then
            cleaned_up=true # Set the flag to prevent duplicate cleanup

            # Check if the temporary file exists before attempting to read from it
            if [[ -f "$temp_file" ]]; then
                while IFS= read -r line; do
                    if [[ "$line" == '```zsh' ]]; then
                        command_buffer=""
                        first_line=true
                    elif [[ "$line" == '```' && "$capturing" == true ]]; then
                        if [[ "$first_line" == true ]]; then
                            echo -n "$command_buffer" | $copy_command
                        else
                            echo -n "${command_buffer//$'\n'/\\n}" | $copy_command
                        fi
                        break
                    elif [[ "$capturing" == true ]]; then
                        if [[ "$first_line" == false ]]; then
                            command_buffer+=$'\n'
                        fi
                        command_buffer+="$line"
                        first_line=false
                    fi
                done <"$temp_file"
            fi

            # Always attempt to remove the temporary file if it exists
            [[ -f "$temp_file" ]] && rm "$temp_file"

            # Reset the signal trap to the default behavior to clean up resources
            trap - SIGINT
        fi
    }

    # Set the trap for cleanup on SIGINT
    trap cleanup SIGINT

    llm -s "$system_prompt" "$1" | tee >(cat >"$temp_file")

    # Ensure cleanup is performed if not already done by trap
    cleanup
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment