Mastering Zsh

repository·master·Indexed 23 days ago

https://github.com/rothgar/mastering-zsh

A tutorial-based guide focused on advanced zsh customization and productivity features without relying on third-party frameworks like oh-my-zsh. The documentation covers core features including ZDOTDIR configuration, managing shared functions via $fpath, zsh hooks (chpwd, precmd, preexec), custom prompt themes, global aliases, ZLE key bindings with bindkey, and integration of completions and autosuggestions.

Tokens
7.2K
Snippets
28
Records
51
Agent score
82%

What's inside mastering-zsh

  1. Overview of Mastering Zsh

    master

    Mastering Zsh is a tutorial-based guide designed to help users understand how zsh works and how to customize it for productivity. Unlike framework-based approaches (such as oh-my-zsh or prezto), this project focuses on teaching the core features and advanced usage of zsh directly.

    It assumes the user is already familiar with basic command line usage, such as running commands, setting variables, and understanding command history. The guide covers configuration, helpers, usage patterns, and miscellaneous references.

  2. Manage shared functions using $fpath

    master

    The $fpath variable is an array used by Zsh to locate shared functions. Unlike $PATH (which is a colon-separated string), $fpath uses space-separated array syntax.

    Adding directories to fpath

    To add a new directory to the search path without overwriting existing entries, use the += operator:

    fpath+=('/some/directory')

    Or use the array assignment syntax:

    export fpath=($ZDOTDIR/functions $fpath)

    Creating and using shared functions

    1. File Naming: The filename must match the function name. For a function named blah, create a file named blah.
    2. File Content: Shared function files do not need a function definition wrapper. It is recommended to put emulate -L zsh at the top of the file to ensure consistent behavior.
    3. Loading: Use the autoload command to load the function into the shell.

    Example Workflow

    # 1. Add the functions folder to fpath
    export fpath=($ZDOTDIR/functions $fpath)
    
    # 2. Create a function file named 'blah'
    $ echo 'echo blah blah' > ${fpath[1]}/blah
    
    # 3. Autoload the function
    $ autoload -U blah
    
    # 4. Run the function
    $ blah
    blah blah
    # Add our own functions folder to fpath
    export fpath=($ZDOTDIR/functions $fpath)
    
    # Create a file called blah in $ZDOTDIR/functions folder
    $ echo 'echo blah blah' > ${fpath[1]}/blah
    
    $ autoload -U blah
    
    $ blah
    blah blah
  3. What are Zsh Hooks and how do they work

    master

    Hooks are arrays of functions that execute automatically when specific shell events occur. Zsh manages these as arrays of functions (widgets) that are triggered by the shell's lifecycle.

    Commonly used hooks include:

    • chpwd: Triggered when the current working directory is changed.
    • precmd: Executed before your prompt is displayed. Often used to update $PROMPT or $RPROMPT.
    • preexec: Executed after you press enter but before the command is actually executed.
    • zshaddhistory: Triggered when adding an item to the history.

    You can inspect which functions are currently assigned to a hook by using the zhooks function.

  4. Understand key notation for bindkey

    master

    When binding a widget to a key sequence or a key with a modifier, Zsh supports several notations. While notations like escape sequences, octal, hex, or unicode are supported, they can be difficult to read.

    Commonly used notation symbols include:

    • ^ (Caret notation): Used for modifiers.
    • \ (Escape sequences): Used for specific key sequences.

    Common modifier mappings:

    • \e or \E: Escape
    • ^[: Alt key (on some keyboards, this is equivalent to Escape)
    • ^?: Delete
    • ^X or ^: Control
  5. Define and use Global Aliases

    master

    Global aliases, defined using the -g flag, can be matched anywhere in a command line, not just at the start. This is particularly useful for aliasing common pipes or command fragments.

    Global aliases can be chained together and can even be used within the definitions of other aliases.

  6. Use parameter substitution for conditional values and transformations

    master

    zsh supports advanced parameter substitution using the ${variable action value} syntax. This allows you to perform logic or transformations directly within the variable expansion.

    Commonly used substitutions:

    • ${var:-foo}: Substitute var with foo if var is unset or empty.
    • ${var:s/foo/bar}: Replace foo with bar (similar to bash ${var/foo/bar}).
    • ${var:h}: Extract the "head" of a path (equivalent to dirname).
    • ${var:t}: Extract the "tail" of a path (equivalent to basename).
    • ${var:l}: Convert the variable to lowercase.
    • ${var:u}: Convert the variable to UPPERCASE.

    Note: These can be nested and combined for complex operations, but should be used sparingly to maintain readability. For exhaustive details, consult man zshexpn.

  7. What are ZLE widgets and how do they work

    master

    Widgets are the mechanism zsh uses to perform actions in the terminal, such as moving the cursor, completing commands, or executing specific logic. They can be built-in system widgets or user-defined widgets.

    • Built-in widgets: Most shell functionality is provided by default. Widgets starting with a . are read-only system widgets.
    • User widgets: Custom functions you define to add your own functionality. These must be registered with ZLE before they can be bound to keys.

    To see all available widgets, use zle -al. To see your current keybindings and the commands used to set them in your .zshrc, use bindkey -L.

  8. Create custom hooks for widgets

    master

    If you need a widget (like zle-line-init or zle-keymap-select) to execute multiple distinct functions, instead of redefining the widget itself, you can create a custom hook.

    By redefining the widget to invoke your custom hook, you can then use hooks-add-hook and hooks-remove-hook (from the zsh-hooks plugin) to manage which functions run when that widget is triggered. This allows for a modular approach to widget behavior.

  9. Set Zsh keymap mode (Emacs vs Vi)

    master

    You can manually switch between Emacs and Vi keymap modes using the bindkey command. If your $EDITOR or $VISUAL environment variables start with vi, Zsh will automatically set the keymap to vi mode upon startup.

    To set modes manually:

    • Use bindkey -e for Emacs mode.
    • Use bindkey -v for Vi mode.
    # emacs mode
    bindkey -e
    
    # vi mode
    bindkey -v
  10. Add a function to a hook using add-zsh-hook

    master

    The most reliable way to extend existing hooks without manually manipulating arrays is using the add-zsh-hook utility. This is available in most Zsh packages.

    Best Practice: When writing functions intended for hooks, always use emulate -L zsh at the start of your function. This ensures your function behaves predictably regardless of the user's global shell settings, preventing accidental side effects (like a misconfigured rm alias or option).

    # create a do-ls function
    # Make sure to use emulate -L zsh or
    # your shell settings and a directory
    # named 'rm' could be deadly
    do-ls() {emulate -L zsh; ls;}
    
    # add do-ls to chpwd hook
    add-zsh-hook chpwd do-ls