├── README.md
├── docs
├── config
│ ├── general.md
│ ├── history.md
│ ├── hooks.md
│ └── prompt.md
├── helpers
│ ├── aliases.md
│ ├── bindkey.md
│ ├── completions.md
│ ├── functions.md
│ ├── variables.md
│ └── widgets.md
├── misc
│ └── reference.md
└── usage
│ ├── file_management.md
│ ├── line_movement.md
│ └── navigation.md
└── img
├── autopair.gif
├── autosuggestions.gif
├── banner.png
├── bash-completion.gif
├── edit-command.gif
├── execute-named-cmd.gif
├── fc-example.gif
├── fzf-history.gif
├── globalias.gif
├── highlighting.gif
├── history-incremental-pattern-search-forward.gif
├── last-command.gif
├── prepend-sudo.gif
├── push-input.gif
└── tetris.gif
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | If you're already using zsh or want to start this tutorial will help you understand how zsh works and how you can customize it to your needs.
4 |
5 | We won't go into every feature of zsh (read the man pages for that).
6 | Did you know zsh has a built in ftp client and calendar?
7 | Instead we will focus on functions of zsh that improve your productivity and help you get more out of your shell.
8 |
9 | We also will not be using any frameworks to customize the shell.
10 | You're free to use [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh), [prezto](https://github.com/sorin-ionescu/prezto), or many other options. They help you get started fast but they don't help you understand zsh and some of its more advanced features.
11 |
12 | We will assume you are already familiar with basic command line usage.
13 | How to run a command, how to set a variable, what command history is, etc.
14 |
15 | This documentation will build on the basics to show you advanced usage, customizations, and practical examples to make you better.
16 |
17 | ## Table of Contents
18 |
19 | * Configuration
20 | * [general](docs/config/general.md)
21 | * [history](docs/config/history.md)
22 | * [prompt](docs/config/prompt.md)
23 | * [hooks](docs/config/hooks.md)
24 | * Helpers
25 | * [aliases](docs/helpers/aliases.md)
26 | * [variables](docs/helpers/variables.md)
27 | * [functions](docs/helpers/functions.md)
28 | * [widgets](docs/helpers/widgets.md)
29 | * [completions](docs/helpers/completions.md)
30 | * Usage
31 | * [line movement](docs/usage/line_movement.md)
32 | * [navigation](docs/usage/navigation.md)
33 | * [file management](docs/usage/file_management.md)
34 | * Misc
35 | * [reference](docs/misc/reference.md)
36 |
--------------------------------------------------------------------------------
/docs/config/general.md:
--------------------------------------------------------------------------------
1 | # Config
2 |
3 | Of course your shell needs to be configured to work.
4 | Here's some tips and advanced zsh config settings you might care about.
5 |
6 | If you're looking for config options like [ history ]( history.md ) and [ prompts ]( prompt.md ) please check out those sections directly.
7 |
8 | ## Files
9 |
10 | zsh allows basic configuration via a `.zshrc` file.
11 | There are other startup files but in general you don't need to create or edit them.
12 |
13 | If you want to change the location of your `.zshrc` and `.zhistory` files you can use `$HOME/.zshenv` to set a new path with the `$ZDOTDIR` environment variable.
14 |
15 | ```bash
16 | # $HOME/.zshenv
17 |
18 | export ZDOTDIR=$HOME/.dotfiles/zdotdir
19 | ```
20 |
21 |
25 |
26 | Something I've found to be successful is to have a `$ZDOTDIR/zsh.d` folder and drop plugins from other plugin managers (e.g. oh-my-zsh, prezto) there.
27 | You can then easily source the files in your `.zshrc` file with something like
28 |
29 | ```bash
30 | for ZSH_FILE in "${ZDOTDIR:-$HOME}"/zsh.d/*.zsh(N); do
31 | source "${ZSH_FILE}"
32 | done
33 | ```
34 |
35 | The `(N)` at the end of the pattern in the for loop above is called a glob qualifier.
36 | Its purpose is to set the `NULL_GLOB` option, which tells the loop not to error if that location is missing or empty. More information about glob qualifiers can be found in the [docs](http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers).
37 |
38 | ## fpath
39 |
40 | zsh's `$fpath` variable is kinda like `$PATH` but for search paths zsh uses.
41 | One of the main things zsh uses it for is shared [functions](../helpers/functions.md).
42 |
43 | > A shared function is different from functions you declare in your `.zshrc` file.
44 |
45 | One major difference with `$fpath` is that it's an array, instead of a string separated with `:`.
46 | Instead of saying `export fpath=$ZDOTDIR/fuctions:$fpath` you need to use array syntax like `export fpath=($ZDOTDIR/functions $fpath)` with a space between the entries.
47 | An even better option is to append to the array with `fpath+=('/some/directory')` so you don't delete existing paths.
48 |
49 | Shared functions are loaded into a shell with the `autoload` command.
50 |
51 | Shared function files in `$fpath` don't need to declare a function name or have a function definition.
52 | You should name the file for the name of the function you want to use.
53 |
54 | ```bash
55 | # Add our own functions folder to fpath
56 | export fpath=($ZDOTDIR/functions $fpath)
57 |
58 | # Create a file called blah in $ZDOTDIR/functions folder
59 | $ echo 'echo blah blah' > ${fpath[1]}/blah
60 |
61 | $ autoload -U blah
62 |
63 | $ blah
64 | blah blah
65 | ```
66 |
67 | > It's a good idea to put `emulate -L zsh` at the top of your function file to avoid user configuration or parameter expansion.
68 |
69 | There is more information about how files are searched in the [docs](http://zsh.sourceforge.net/Doc/Release/Functions.html).
70 |
71 | `fpath` is really only useful for making functions portable.
72 | You'll probably use some of them (examples in the functions section), but most functions you define can go in your `.zshrc` file.
73 |
74 | ---
75 |
76 | [home](../../README.md) | Next: [history](history.md)
77 |
78 |
--------------------------------------------------------------------------------
/docs/config/history.md:
--------------------------------------------------------------------------------
1 | # History
2 |
3 | If you work in the shell long enough your history will become your own personal reference.
4 | It's like automatic documentation which is the best kind of documentation.
5 |
6 | ## Configuration
7 |
8 | Unfortunately, the default configuration for history is not always great.
9 | You should already be familiar with variables such as `$HISTFILE` and `$HISTSIZE`.
10 |
11 | Here are a few shell options that can improve your history recording and usage.
12 | Drop this config in your `.zshrc` file to improve history recording.
13 |
14 | ```
15 | setopt EXTENDED_HISTORY # Write the history file in the ':start:elapsed;command' format.
16 | setopt INC_APPEND_HISTORY # Write to the history file immediately, not when the shell exits.
17 | setopt SHARE_HISTORY # Share history between all sessions.
18 | setopt HIST_EXPIRE_DUPS_FIRST # Expire a duplicate event first when trimming history.
19 | setopt HIST_IGNORE_DUPS # Do not record an event that was just recorded again.
20 | setopt HIST_IGNORE_ALL_DUPS # Delete an old recorded event if a new event is a duplicate.
21 | setopt HIST_FIND_NO_DUPS # Do not display a previously found event.
22 | setopt HIST_IGNORE_SPACE # Do not record an event starting with a space.
23 | setopt HIST_SAVE_NO_DUPS # Do not write a duplicate event to the history file.
24 | setopt HIST_VERIFY # Do not execute immediately upon history expansion.
25 | setopt APPEND_HISTORY # append to history file
26 | setopt HIST_NO_STORE # Don't store history commands
27 | ```
28 |
29 | ## Using Words from the Last Command
30 |
31 | For most people working with history means using `sudo !!` or occationally `ctrl+r` or `history | grep`.
32 | To master working with your history we should look at a few other commonly used shortcuts instead.
33 | First of all, you should know `!!` is essentially the same as
34 | ```bash
35 | # Note: this doesn't actually work but the fc command is effectively the same
36 | alias !!='fc -ln -1'
37 | ```
38 | _More on `fc` later_
39 |
40 | But there are lots of other aliases that start with `!`.
41 | Here are some.
42 |
43 | * `!*` or `!:*` = All **arguments** (minus command)
44 | * `!$` or `!:$` = Last argument/word
45 | * `!^` or `!:1` = First argument (doesn't include command name)
46 | * `!foo` = The last command that started with `foo`
47 |
48 | If you want to use words from commands earlier in your history you can also use the `!-n` format.
49 |
50 | * `!-3:$` = Use last word from 3 commands ago
51 | * `!-2:*` = Use all arguments from 2 commands ago
52 | * `!-2; !-1` = Combine last two commands into a single line
53 |
54 | You can also make this better with `bindkey` and the insert-last-word zle widget.
55 | More on what this means can be found in the [widgets section](../helpers/widgets.md).
56 |
57 | ```bash
58 | # press Alt+. to insert the last word from the previous command
59 | autoload -U smart-insert-last-word
60 | zle -N smart-insert-last-word
61 | bindkey "\e." smart-insert-last-word
62 | ```
63 |
64 | ## Modifying the Last Command
65 |
66 | It's great to be able to use parts from the last command, but what if you want to rerun the last command with edits?
67 | You have a few options.
68 |
69 | ```bash
70 | echo foo foo
71 | # using the above style !! we can do a single substitution with
72 | !!:s/foo/bzz # bzz foo
73 | # global substitutions need g
74 | echo foo foo
75 | !!:sg/foo/bzz # bzz bzz
76 | # be careful though because global replace happen for the entire line
77 | echo foo foo
78 | !!:sg/o/z # echz: command not found...
79 | ```
80 |
81 | > There are a ton of other history [modifiers](http://zsh.sourceforge.net/Doc/Release/Expansion.html#Modifiers) if you read through the posix history man page.
82 | > For me they're all hard to remember and I don't use them enough to list them here.
83 |
84 | Sometimes `!!:s/` is hard to type so there's also the shorthand replace with `^`
85 |
86 | ```bash
87 | systemctl status sshd
88 | # replace status with restart
89 | ^status^restart # systemctl restart sshd
90 | # use ^:G for global replace
91 | echo foo foo
92 | ^foo^bzz^:G # bzz bzz
93 | ```
94 |
95 | If you can't remember any of these formats (I don't blame you) then try `fc`.
96 | `fc` by default will edit your last command in a visual editor.
97 | This is great for long or multi-line commands.
98 | It can also be used to list commands from history and do substitution.
99 |
100 | > Bash `fc` is a little different than zsh's `fc` so be careful which man page you read.
101 | > `apropos fc` to find the specific version and then `man 1p fc`.
102 |
103 | ```bash
104 | echo 'foo
105 | bar'
106 |
107 | # edit last command in a visual editor and execute it
108 | fc
109 | ```
110 |
111 | 
112 |
113 | For global string replacement you can use `string=replace` syntax.
114 | If you want to run the command without using an editor override `$EDITOR` with `-e -`.
115 |
116 | ```bash
117 | echo foo bar baz foo
118 |
119 | fc -e - foo=boo # echo boo bar baz boo
120 | ```
121 |
122 | This works great as an alias `alias r='fc -e -'` so running `r foo=bar` will replace the string for you!
123 |
124 | ## Searching and Executing History
125 |
126 | We've already discussed using `ctrl+r` and `fc -l` to search through your history.
127 | By default the `history` command in zsh only shows the past 16 entries.
128 | If you want to list all of your history you can use `history 1`.
129 |
130 | Listing your entire history on its own is not very useful.
131 | Most often you want to search for something, to do that we can make a function to handle our searching.
132 |
133 | ```bash
134 | function h() {
135 | # check if we passed any parameters
136 | if [ -z "$*" ]; then
137 | # if no parameters were passed print entire history
138 | history 1
139 | else
140 | # if words were passed use it as a search
141 | history 1 | egrep --color=auto "$@"
142 | fi
143 | }
144 |
145 | # search entire history for "foo" with
146 | h foo
147 | ```
148 |
149 | This will print a list of commands with numbers.
150 | You can immediately re-execute any of the commands with `!n` where `n` is the command number.
151 |
152 | ```bash
153 | h foo
154 | 100 echo foo
155 | 101 echo foo foo
156 | 102 echo foobar
157 | ```
158 |
159 | Our command substitution from before works too!
160 |
161 | ```bash
162 | !101:s/foo/bar # echo bar foo
163 | ```
164 |
165 | Sometimes I want to combine multiple commands from my history into a single line.
166 | We can do that with a function and zle
167 |
168 | ```bash
169 | # add the ability to print >> << for the portion of the cli we'll be using
170 | autoload -Uz narrow-to-region
171 |
172 | # define our function
173 | function _history-incremental-preserving-pattern-search-backward
174 | {
175 | local state
176 | MARK=CURSOR
177 | narrow-to-region -p "$LBUFFER${BUFFER:+>>}" -P "${BUFFER:+<<}$RBUFFER" -S state
178 | zle end-of-history
179 | zle history-incremental-pattern-search-backward
180 | narrow-to-region -R state
181 | }
182 |
183 | # load the function into zle
184 | zle -N _history-incremental-preserving-pattern-search-backward
185 |
186 | # bind it to ctrl+r
187 | bindkey "^R" _history-incremental-preserving-pattern-search-backward
188 | bindkey -M isearch "^R" history-incremental-pattern-search-backward
189 | bindkey "^S" history-incremental-pattern-search-forward
190 | ```
191 |
192 | If you load the above configuration then `ctrl+r` will still work for normal history searching, but if instead of pushing `` you push `Alt+;` then a `;` will be added to the line and you can push `ctrl+r` again to insert another command.
193 |
194 | 
195 |
196 | Another way to use your history is with interactive searching.
197 | This is most useful when you can remember exactly what command you wanted but remember some of the words.
198 |
199 | To do this [`fzf`](https://github.com/junegunn/fzf) is a great tool.
200 | Install the binary in your `$PATH` and use a function like the one below to search command history.
201 |
202 | ```bash
203 | function fh() {
204 | eval $( ([ -n "$ZSH_NAME" ] && fc -l 1 || history) | fzf +s --tac | sed 's/ *[0-9]* *//')
205 | }
206 | ```
207 |
208 | 
209 |
210 | ---
211 |
212 | Previous: [general](general.md) | [home](../../README.md) | Next: [prompt](prompt.md)
213 |
--------------------------------------------------------------------------------
/docs/config/hooks.md:
--------------------------------------------------------------------------------
1 | # Hooks
2 |
3 | [ Hooks ](http://zsh.sourceforge.net/Doc/Release/Functions.html#Hook-Functions) are arrays of functions that happen automatically when events occur in your shell.
4 | The hooks that are frequently used are `chpwd`, `precmd`, `preexec`, and `zshaddhistory`.
5 |
6 | `precmd` is executed before your prompt is displayed and is often used to set values in your [`$PROMPT`](prompt.md).
7 | `preexec` is executed between when you press `enter` on a command prompt but before the command is executed.
8 |
9 | Each hook is an array of [widgets](../helpers/widgets.md) which are executed by zsh.
10 | To display what widgets are in each of your hooks you can use the [zhooks function](https://github.com/agkozak/zhooks).
11 |
12 | ## Set $PROMPT in precmd
13 |
14 | One example of using a hook is by changing your `$PROMPT` using `precmd` hook.
15 | `precmd` runs before each prompt which makes it a perfect candidate for setting your `$PROMPT`.
16 |
17 | If you want to create a custom function that sets your `$RPROMPT` variable to your last command exit code you can use this.
18 |
19 | ```bash
20 | # allows parameter expansion, arithmatic, and shell substitution in prompts
21 | setopt prompt_subst
22 |
23 | function check_last_exit_code() {
24 | local LAST_EXIT_CODE=$?
25 | if [[ $LAST_EXIT_CODE -ne 0 ]]; then
26 | local EXIT_CODE_PROMPT=' '
27 | EXIT_CODE_PROMPT+="%{$fg[red]%}-%{$reset_color%}"
28 | EXIT_CODE_PROMPT+="%{$fg_bold[red]%}$LAST_EXIT_CODE%{$reset_color%}"
29 | EXIT_CODE_PROMPT+="%{$fg[red]%}-%{$reset_color%}"
30 | RPROMPT="$EXIT_CODE_PROMPT"
31 | else
32 | RPROMPT=' '
33 | fi
34 | }
35 |
36 | typeset -a precmd_functions
37 | # append the function to our array of precmd functions
38 | precmd_functions+=(check_last_exit_code)
39 | ```
40 | This will run the `precmd_functions` each time you execute a command and get a new prompt.
41 | Notice how we set `RPROMPT` in the function
42 |
43 | Likewise you can also use the function directly to set `RPROMPT` via a subshell but you'll need to make sure your function `echo`s the text instead of setting the variable directly.
44 |
45 | ```bash
46 | setopt prompt_subst
47 |
48 | function check_last_exit_code() {
49 | local LAST_EXIT_CODE=$?
50 | if [[ $LAST_EXIT_CODE -ne 0 ]]; then
51 | local EXIT_CODE_PROMPT=' '
52 | EXIT_CODE_PROMPT+="%{$fg[red]%}-%{$reset_color%}"
53 | EXIT_CODE_PROMPT+="%{$fg_bold[red]%}$LAST_EXIT_CODE%{$reset_color%}"
54 | EXIT_CODE_PROMPT+="%{$fg[red]%}-%{$reset_color%}"
55 | echo "$EXIT_CODE_PROMPT"
56 | fi
57 | }
58 |
59 | # set RPROMT directly. Will override other functions where it gets set
60 | RPROMPT='$(check_last_exit_code)'
61 | ```
62 |
63 | ## Add Function to Hook
64 |
65 | If you want to extend your hooks you can easily do it with the [`add-zsh-hook`](https://github.com/zsh-users/zsh/blob/master/Functions/Misc/add-zsh-hook) which should be available in most zsh packages.
66 |
67 | ```bash
68 | # create a do-ls function
69 | # Make sure to use emulate -L zsh or
70 | # your shell settings and a directory
71 | # named 'rm' could be deadly
72 | do-ls() {emulate -L zsh; ls;}
73 |
74 | # add do-ls to chpwd hook
75 | add-zsh-hook chpwd do-ls
76 |
77 | cd ~/
78 | Desktop Music
79 | Documents Pictures
80 | Downloads Public
81 | ```
82 |
83 | You may need to play with which hook to use and your function definition to get it just right.
84 | Many prompt themes will automatically install hooks for you.
85 |
86 | ## Adding Custom Hooks
87 |
88 | Sometimes it would be helpful if a widget was a hook.
89 | This would allow the widget to run multiple functions when invoked.
90 |
91 | You could redefine widgets like zle-line-init and zle-keymap-select with user widgets but that makes it hard to combine smaller functions.
92 |
93 | Instead, you can create a custom hook and redefine the widget to invoke your hook.
94 | Then you can add/remove functions to the hook as needed.
95 |
96 | For that you can use [`hooks-define-hook`](https://github.com/willghatch/zsh-hooks) and `hooks-add-hook` from the same plugin.
97 |
98 | ---
99 |
100 | Previous: [prompt](prompt.md) | [home](../../README.md) | Next: [aliases](../helpers/aliases.md)
101 |
--------------------------------------------------------------------------------
/docs/config/prompt.md:
--------------------------------------------------------------------------------
1 | # Prompt
2 |
3 | Your terminal prompt is your best guide to passive productivity gains.
4 | It's also a very opinionated part of any shell.
5 | Some people like multiple lines.
6 | Some people love minimal prompts without distractions.
7 |
8 | Whatever you prefer, you should probably start with an existing prompt and customize it rather than writing one from scratch.
9 |
10 | One setting you probably want is `setopt PROMPT_SUBST` which will let you expand parameters and substitute commands in your prompt.
11 |
12 | ## $PROMPT
13 |
14 | zsh can use the `$PS1` variable like bash for your prompt but you should use `$PROMPT` instead.
15 | In most cases they should have the same value.
16 |
17 | You can export it just like any variable and your current prompt should change.
18 | Be careful you don't have a function in your `precmd` hook that overrides this variable.
19 |
20 | The zsh prompt expansion uses cryptic variables like `%n` and `%#` which you should never try to memorize.
21 | It's a waste of brain resource and you're better off looking them up if you want to use them to extend a prompt theme.
22 |
23 | Here's a link to the available variables and what they do—[Prompt Expansion](http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html).
24 | The prompt can also handle special colors with things like `%{orange}`, `%{limegreen}`, and `${PR_RST}`.
25 | Seriously, why are you still reading this section?
26 | You shouldn't be creating a prompt from scratch.
27 |
28 | Look below to use a pre-made prompt theme.
29 |
30 | ## $RPROMPT
31 |
32 | One of the cool features about zsh is the ability to have a "right prompt".
33 | Export `$RPROMPT` or `$RPS1` to start using it.
34 | No one ever said you could only have information on the left side of your terminal.
35 |
36 | It works the same way as `$PROMPT` but it's right aligned.
37 |
38 | Export it using one of those archaic variables and give it a try.
39 |
40 | ```bash
41 | # Show time on the right side of the screen
42 | $ export RPROMPT='%t'
43 |
44 | # show git repo info in your prompt
45 | export RPROMPT='$vcs_info_msg_0_'
46 | ```
47 |
48 | If you don't like these there are a million other options.
49 | Search your favorite search engine to find something to your liking.
50 |
51 | > Some prompt themes will export `$PROMPT` and `$RPROMPT`
52 |
53 | ## `prompt` command
54 |
55 | The `prompt` command is provided as a [standard zsh widget](https://github.com/zsh-users/zsh/blob/master/Functions/Prompts/promptinit)
56 | You can load it into your shell with
57 |
58 | ```bash
59 | autoload -Uz promptinit; promptinit
60 | ```
61 |
62 | Now you can list installed prompts with `prompt -p`.
63 | This will give you the theme name and an example of what it looks like rendered.
64 |
65 | Select the theme you want with `prompt $THEME`.
66 |
67 | If you want to save the prompt theme you should add that command to your `.zshrc`.
68 | Make sure you also `autoload` the widget in the config before using `prompt`.
69 |
70 | ### Install custom theme
71 |
72 | If you want to install a custom zsh theme that the `prompt` command can use you need to add a `prompt_*_setup` file to your `$fpath`.
73 | The file can be any standard zsh script and can use existing variables and functions available in the environment.
74 |
75 | On Linux the standard prompts are available in `/usr/share/zsh`.
76 | You should be able to find a prompt setup example in there, but you probably want to keep your own prompts somewhere in your home directory.
77 |
78 | ```bash
79 | fpath=($ZDOTDIR/prompts $fpath)
80 |
81 | autoload -Uz promptinit; promptinit
82 | prompt MyAwesomePrompt # Looks for $ZDOTDIR/promts/prompt_MyAwesomePrompt_setup
83 | ```
84 |
85 | Prompt setup files can export both `$PROMPT` and `$RPROMPT` if you want them to.
86 |
87 | ## Creating your own theme
88 |
89 | If you refused to listen to all my other advice you can create your own theme.
90 | I still recommend you start from one of the many theme examples available by default, in a zsh manager like [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh/tree/master/themes), or standalone prompt projects like [ spaceship ]( https://github.com/denysdovhan/spaceship-prompt ) or [alien](https://github.com/eendroroy/alien).
91 |
92 | Once you create a prompt you like put it in a `prompt_MyPrompt_setup` file and put it in a folder in your `$fpath`.
93 | Follow the instructions above to load the prompt in your `.zshrc` file.
94 |
95 | ---
96 |
97 | Previous: [history](history.md) | [home](../../README.md) | Next: [hooks](hooks.md)
98 |
--------------------------------------------------------------------------------
/docs/helpers/aliases.md:
--------------------------------------------------------------------------------
1 | # Aliases
2 |
3 | A good place to start is to list all of your shell aliases with the `alias` command.
4 | When passed no parameters it will list the current aliases as defined in your configuration or explicitly defined in the shell.
5 |
6 | ## Defining Aliases
7 |
8 | Aliases in zsh share the common `alias` builtin command from other shells.
9 | Aliases are handy for saving time when typing commands.
10 | If they are not "global aliases" then they only work at the beginning of a command prompt (more below).
11 | Typical aliases are used for commands such as:
12 |
13 | ```bash
14 | alias g=git
15 | ```
16 |
17 | Aliases can be single commands or expand to multiple words.
18 |
19 | ```bash
20 | alias gc='git commit'
21 | ```
22 |
23 | If you define your alias with a space after the definition it will allow the following word to be interpreted as an alias.
24 |
25 | ```bash
26 | # notice the space inside the quotes
27 | alias ss='sudo '
28 | ```
29 |
30 | This will allow you to use an alias after `ss`.
31 |
32 | ```bash
33 | # Without the space you would receive an error that the `g` command is not found
34 | ss g
35 | ^^ runs `sudo git`
36 | ```
37 |
38 | If an alias conflicts with the name of a command you can escape it with quotes `''`.
39 |
40 | ```bash
41 | alias grep='grep --color=auto'
42 |
43 | echo foo | grep fo
44 | # ^^^^ uses grep --color=auto alias
45 |
46 | echo foo | 'grep' fo
47 | # ^^^^ will not colorize match
48 | ```
49 |
50 | Aliases don't have to only be letters and numbers.
51 |
52 | ```bash
53 | alias :q=exit
54 | alias ..='cd ..'
55 | alias ....='cd ../..'
56 | alias --='cd -'
57 | ```
58 |
59 | > You can also alias escape special characters such as `\` so be careful
60 |
61 | ## Global Aliases
62 |
63 | zsh has an additional option for global aliases with the `-g` option which allows aliases at any part of the command line.
64 | Without the `-g` option aliases will only be matched at the beginning of a line or after an alias ending with a space.
65 |
66 | Global aliases can be helpful for aliasing any text you frequently write at the command line.
67 | ```bash
68 | # pipe output to grep
69 | alias -g G='| grep'
70 | # pipe output to less
71 | alias -g L='| less'
72 | # pipe output to `wc` with option `-l`
73 | alias -g W='| wc -l'
74 | # convert multiline output to single line and copy it to the system clipboard
75 | alias -g C='| tr -d ''\n'' | xclip -selection clipboard'
76 | ```
77 |
78 | Because global aliases can be used anywhere in the command line they can also be chained together.
79 | ```bash
80 | echo -e 'zsh\nis\n\great\nhello\ngoodbye' G -A1 hello C
81 | # grep for hello and include 1 line after ^^^^^^^^^ ^
82 | |
83 | # trim new lines and copy 'hello goodbye' to the ---|
84 | # system clipboard
85 | ```
86 |
87 | Aliases can also be used inside definitions of other aliases!
88 | ```bash
89 | alias -g G='| grep'
90 | alias -g W='| wc -l'
91 | alias -g GfooW='G foo W'
92 | ```
93 |
94 | ## Automatically Expand Aliases
95 |
96 | Aliases are great for typing but sometimes they can be confusing to remember what aliases you have defined or when searching your command [history](../config/history.md).
97 | Trying to remember if you ran a command with `git` or `g` can make it hard to find the command you need.
98 |
99 | It's also helpful to show full commands if you are pair programming or giving a presentation.
100 |
101 | For that you can use a function that will automatically exand your aliases on your current command line after you press space.
102 |
103 | ```bash
104 | # don't worry about zle. We'll go over it later in the zle section.
105 | globalias() {
106 | zle _expand_alias
107 | zle expand-word
108 | zle self-insert
109 | }
110 | zle -N globalias
111 |
112 | # space expands all aliases, including global
113 | bindkey -M emacs " " globalias
114 | bindkey -M viins " " globalias
115 |
116 | # control-space to make a normal space
117 | bindkey -M emacs "^ " magic-space
118 | bindkey -M viins "^ " magic-space
119 |
120 | # normal space during searches
121 | bindkey -M isearch " " magic-space
122 | ```
123 |
124 | 
125 |
126 | ## Advanced Aliases
127 |
128 | Because aliases expand to any text they can get quite complex.
129 | The expanded text can include subshells, variables, and additional quoted text.
130 |
131 | > Advanced aliases can also be implemented as shell functions or widgets.
132 |
133 | Here are a few examples
134 | ```bash
135 | # Search through your command history and print the top 10 commands
136 | alias history-stat='history 0 | awk ''{print $2}'' | sort | uniq -c | sort -n -r | head'
137 |
138 | # Use `which` to find aliases and functions including binaries
139 | which='(alias; declare -f) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot'
140 |
141 | ```
142 |
143 | # Conclusion
144 |
145 | Aliases are great for replacing text at an interactive shell.
146 | For more options on powering up your interactive shell check out [functions](functions.md) and [widgets](widgets.md).
147 |
148 | ---
149 |
150 | Previous: [hooks](hooks.md) | [home](../../README.md) | Next: [variables](variables.md)
151 |
--------------------------------------------------------------------------------
/docs/helpers/bindkey.md:
--------------------------------------------------------------------------------
1 | # Bindkey
2 |
3 | The `bindkey` key mappings can be very confusing to decipher.
4 | It can use multiple different notations but it's smart to use the same key notation throughout your configuration.
5 |
6 | You can print all of your current key bindings in the current keymap with `bindkey`.
7 | To print the full `bindkey` command to add to your `.zshrc` file use `bindkey -L`.
8 |
9 | In general you'll bind a widget so a key sequence or a key with modifier.
10 | This can be declared in [caret notation](https://en.wikipedia.org/wiki/Caret_notation) using `^`, using [escape sequences](https://en.wikipedia.org/wiki/Escape_sequence) using `\`, in octal (`\NNN`), hex (`\xNN`), or unicode (`\uNNNN`).
11 | None of these are particularly great for people to read.
12 |
13 | This is also tricky because it depends on your keyboard, operating system, and shell.
14 | Here are some basics
15 |
16 | * `\e`, `\E`, = Escape
17 | * `^[` = Alt key (on some keyboards this is the same as escape)
18 | * `^?` = Delete
19 | * `^X`, `^` = Control
20 |
21 | The keys that come after the modifier can add more confusion.
22 |
23 | ## Delete key binding
24 |
25 | To delete a key binding you can use `bindkey -d $KEYS`.
26 | Make sure you don't delete characters you need for typing.
27 |
28 | I have got myself in trouble more than once with `bindkey -d ' '`.
29 | As a thought experiement, how would you remedy the pickle you get yourself in if you do that?
30 |
--------------------------------------------------------------------------------
/docs/helpers/completions.md:
--------------------------------------------------------------------------------
1 | # Completions
2 |
3 | zsh has very comprehensive completions which is one of the main reasons to switch to zsh for your interactive shell.
4 | Under the covers it works similarly to other shell completion engines (completions are read from files and functions on disc) but there are a few features that make it better.
5 |
6 | > Some of the completion features have been ported to other shells and some have been stolen from other shells.
7 | > Many of the sections below are optional to enhance your shell experience.
8 |
9 | One nice difference is the way completions are displayed and how tab works when at a completion menu.
10 | Here is a comparison with how `bash` and `zsh` differ.
11 |
12 | 
13 |
14 | There are lots of commands that have built in tab completion for zsh.
15 | If a command you use doesn't support tab completion by default have a look at [zsh-users/zsh-completions](https://github.com/zsh-users/zsh-completions).
16 | You can install it with the various zsh plugin managers or download the repo and add the src directory to your `$fpath`.
17 |
18 | ## Autosuggestions
19 |
20 | Autosuggestions are like a preemptive tab complete for your .zhistory file.
21 | The autosuggestion plugin will look at your current command, what commands you typically type, and suggest possibilities for you to use and save key strokes.
22 |
23 | Installation instructions can be found in the [zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) repo.
24 |
25 | 
26 |
27 | ## Highlighting
28 |
29 | Syntax highlighting works similarly to an IDE but at your terminal.
30 | It can highlight everything from brackets to cursor position.
31 |
32 | Under the covers it works like all the other things in zsh with zle widgets.
33 | Have a look at the [zsh-syntax-highlighting](https://github.com/zsh-users/zsh-syntax-highlighting) repo for installation instructions
34 |
35 | 
36 |
37 | ## zstyle
38 |
39 | List your current styles by invoking `zstyle` by itself.
40 |
41 | The rest of this section will have to come at a later date.
42 |
43 | ---
44 |
45 | Previous: [widgets](widgets.md) | [home](../../README.md) | Next: [line movement](../usage/line_movement.md)
46 |
--------------------------------------------------------------------------------
/docs/helpers/functions.md:
--------------------------------------------------------------------------------
1 | # Functions
2 |
3 | User defined functions allow you to take snippets of code and reuse them.
4 | This is similar to any programming language and has the following benefits over aliases.
5 |
6 | Functions can:
7 |
8 | * accept parameters (e.g. `$1`, `$2`...)
9 | * have control logic (e.g. `case` and `if`)
10 | * spawn subshells
11 | * have error codes and traps
12 |
13 | Functions are a building block for a lot of zsh.
14 | Two major aspects of zsh are [widgets](widgets.md) and [hooks](../config/hooks.md) which are both uses of functions.
15 |
16 | We'll only show some basics and examples here because it's assumed you know how create shell functions.
17 |
18 | ## Basics
19 |
20 | Hopefully you know the dozen different ways to declare a function.
21 |
22 | ```bash
23 | # declare ffoo function
24 | function ffoo() { echo foo; }
25 |
26 | # declare fbar function
27 | fbar() { echo bar; }
28 |
29 | # Anonymous function
30 | () { echo baz; }
31 | ```
32 |
33 | Nothing goes between the `()` and nothing is returned in traditional function definitions.
34 | You can set a global variable from within the function or `echo` a value in the function and use a subshell to store its value.
35 |
36 | ```bash
37 | function to-lower() {
38 | echo ${1:l}
39 | }
40 |
41 | var=$(to-lower FOO)
42 |
43 | echo $var
44 | foo
45 | ```
46 |
47 | ## Print a Function
48 |
49 | Sometimes you can't remember what's in a function or where it's sourced from.
50 | To print a shell function to stdout you can use `type -f` or `whence -f`.
51 | Both are zsh builtin commands.
52 |
53 | ```bash
54 | echo 'do-ls() { emulate -L zsh; \ls; }' > do-ls
55 |
56 | source ./do-ls
57 |
58 | whence -f do-ls
59 | do-ls () {
60 | emulate -L zsh
61 | \ls
62 | }
63 | ```
64 |
65 | It's also handy to know where a function comes from.
66 | Sometimes you can't remember what file it was sourced in if you need to edit it.
67 |
68 | To print the file it came from use `whence -v`
69 |
70 | ```
71 | whence -v do-ls
72 | do-ls is a shell function from ./do-ls
73 |
74 | # if you declare the function directly you won't
75 | # see the path with -v
76 | do-ls() { emulate -L zsh; \ls; }
77 |
78 | whence -v do-ls
79 | do-ls is a shell function
80 | ```
81 |
82 | ## Examples
83 |
84 | Here are some examples of functions I have found fun or handy.
85 |
86 | > Many of these functions require external programs like `fzf`.
87 | > Make sure you have them installed in your `$PATH` if you want to use them.
88 |
89 | ### Show website certificate from hostname
90 |
91 | ```bash
92 | function curl-cert() {
93 | openssl s_client -showcerts -connect "${1}":443 -servername ${1}
94 | }
95 | ```
96 |
97 | ### Interactively export AWS_PROFILE
98 |
99 | ```bash
100 | function awsp() {
101 | export AWS_PROFILE=$(grep profile ${HOME}/.aws/config \
102 | | awk '{print $2}' | sed 's,],,g' \
103 | | fzf --layout reverse --height=10% --border)
104 | }
105 | ```
106 |
107 | ### Interactive man search
108 |
109 | ```bash
110 | function mans(){
111 | man -k . \
112 | | fzf -n1,2 --preview "echo {} \
113 | | cut -d' ' -f1 \
114 | | sed 's# (#.#' \
115 | | sed 's#)##' \
116 | | xargs -I% man %" --bind "enter:execute: \
117 | (echo {} \
118 | | cut -d' ' -f1 \
119 | | sed 's# (#.#' \
120 | | sed 's#)##' \
121 | | xargs -I% man % \
122 | | less -R)"
123 | }
124 | ```
125 |
126 | ### Interactive git diff
127 |
128 | ```bash
129 | function fshow() {
130 | git log --graph --color=always \
131 | --format="%C(auto)%h%d %s %C(black)%C(bold)%cr" "$@" \
132 | | fzf --ansi --preview "echo {} \
133 | | grep -o '[a-f0-9]\{7\}' \
134 | | head -1 \
135 | | xargs -I % sh -c 'git show --color=always %'" \
136 | --bind "enter:execute:
137 | (grep -o '[a-f0-9]\{7\}' \
138 | | head -1 \
139 | | xargs -I % sh -c 'git show --color=always % \
140 | | less -R') << 'FZF-EOF'
141 | {}
142 | FZF-EOF"
143 | }
144 | ```
145 |
146 | ### The most important functions
147 |
148 | ```bash
149 | disappointed() { echo -n " ಠ_ಠ " |tee /dev/tty| xclip -selection clipboard; }
150 |
151 | flip() { echo -n "(╯°□°)╯ ┻━┻" |tee /dev/tty| xclip -selection clipboard; }
152 |
153 | shrug() { echo -n "¯\_(ツ)_/¯" |tee /dev/tty| xclip -selection clipboard; }
154 |
155 | matrix() { echo -e "\e[1;40m" ; clear ; while :; do echo $LINES $COLUMNS $(( $RANDOM % $COLUMNS)) $(( $RANDOM % 72 )) ;sleep 0.05; done|awk '{ letters="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*()"; c=$4; letter=substr(letters,c,1);a[$3]=0;for (x in a) {o=a[x];a[x]=a[x]+1; printf "\033[%s;%sH\033[2;32m%s",o,x,letter; printf "\033[%s;%sH\033[1;37m%s\033[0;0H",a[x],x,letter;if (a[x] >= $1) { a[x]=0; } }}' }
156 | ```
157 |
158 | ---
159 |
160 | Previous: [variables](variables.md) | [home](../../README.md) | Next: [widgets](widgets.md)
161 |
--------------------------------------------------------------------------------
/docs/helpers/variables.md:
--------------------------------------------------------------------------------
1 | # Variables
2 |
3 | If you've used a shell for any amount of time you know what variables are.
4 | zsh uses `$` to denote a variable just like other shells.
5 |
6 | Variables are a subset of shell [parameters](http://zsh.sourceforge.net/Doc/Release/Parameters.html) which have lots of different values and types.
7 | You probably mostly care about variables when writing functions or scripts to handle positional parameters or arguments.
8 |
9 | Some notable special parameters are:
10 |
11 | * `!` = The pid of the last backgrounded command (e.g. `echo $!`)
12 | * `$` = The pid of this shell (e.g. `cat /proc/$$/cmdline`)
13 | * `?` = The exit status returned by the last command (e.g. `echo $?`)
14 | * `_` = The last argument to the previous command (e.g. `echo $_`)
15 | * `$RANDOM` = Pseudo-random integer from 0 to 32767
16 | * `$PWD` = Same output as `pwd`
17 | * `$n` = Positional parameter passed to script (e.g. `echo $1`)
18 |
19 | > There are a lot of odd behaviors to variables in any shell.
20 | > You shouldn't try to memorize all of them and we won't cover them here.
21 |
22 | ## Parameter Substitution
23 |
24 | Variable substitution in zsh works the same as most other shells and has been covered many other places.
25 | There are lots of options for how and what you need to substitute inside a variable so I won't go over most of it here.
26 |
27 | Variable substitute uses `${variable action value}` syntax where a punctuation mark denotes an action and a string, variable, or command for value.
28 | Things like this are completely valid syntax
29 |
30 | ```bash
31 | # echo YYYY-MM-DD if $foo and $datestring are not set or an empty string
32 | ${foo:-$(date +${datestring-"%Y-%m-%d"})}
33 |
34 | # if foo not declared use the value of $bar and upper case it
35 | ${${foo-$bar}:u}`.
36 | ```
37 |
38 | This can be very powerful and also very confusing to read, use it sparingly.
39 | Check out `man zshexpn` for more information.
40 |
41 | The substitutions I generally find useful are:
42 |
43 | * `${var:-foo}` = substitute var with foo if it is unset or set to an empty string
44 | * `${var:s/foo/bar}` = replace foo for bar (same as `${var/foo/bar}` in bash)
45 | * `${var:h}` = leave "head" of variable path (same as `dirname ${var}` or `${str%/*}` in bash)
46 | * `${var:t}` = leave "tail" of variable path (same as `basename` or `${str##*/}` in bash)
47 | * `${var:l}` = convert variable to lowercase (this is `${var,,}` in bash)
48 | * `${var:u}` = convert variable to UPPERCASE (this is `${var^^}` in bash)
49 |
50 | One neat thing about these is they can be combined.
51 | Say you want to rename all file extensions in the current directory to lower case.
52 | You can do
53 |
54 | ```bash
55 | for FILE in $(ls -1); do
56 | # :r takes filename and removes extension
57 | # :e takes extension without filename
58 | # :l lowercases text
59 | mv ${FILE} ${FILE:r}.${FILE:e:l}
60 | done
61 | ```
62 |
63 | As I said before, use these sparingly.
64 | In general I still write all of my scripts in bash so I only use these substitutions in functions declared in `.zshrc` or at an interactive shell.
65 |
66 | ---
67 |
68 | Previous: [aliases](aliases.md) | [home](../../README.md) | Next: [functions](functions.md)
69 |
--------------------------------------------------------------------------------
/docs/helpers/widgets.md:
--------------------------------------------------------------------------------
1 | # Widgets
2 |
3 | Widgets are how zsh performs actions in your terminal.
4 | Everything from moving the cursor to command completion to executing commands.
5 |
6 | There are built in widgets for a majority of shell functionality and you can have user defined widgets to add your own functionality.
7 | User widgets are used by binding them to keyboard shortcuts using the `bindkey` command.
8 | More about defining widgets can be found in the zle section.
9 |
10 | Widgets have descriptive names such as `vi-backward-kill-word` and `beginning-of-history`.
11 | User defined widgets have no standard naming convention but you should stick with something meaningful for troubleshooting if things go wrong.
12 |
13 | You can list all available widgets with
14 | ```bash
15 | zle -al
16 | ```
17 |
18 | If you want to list your current keybindings and widgets use the `bindkey` command by itself.
19 | To see a list of bindings and a command you can run to set the key binding in your `.zshrc` file use `bindkey -L`
20 |
21 | The widgets with `.` at the begining of the name are read-only system widgets that cannot be changed.
22 |
23 | An example of binding a built in widget to a keyboard shortcut is
24 |
25 | > When you bind a key to a widget any previous key binding will be overridden.
26 |
27 | ```bash
28 | bindkey '^a' begining-of-line
29 | ```
30 |
31 | This binds `ctrl+a` to jump to the begining of the current line at a prompt.
32 | For a map of bindkey key representations have a look at [this table](bindkey.md)
33 |
34 | > `bindkey` works for typing strings at the terminal too!
35 | > Try `bindkey -s '^[s' '^Qsudo '` to enter sudo when your cursor is at a new command prompt.
36 |
37 | A majority of widgets are included by default in zsh but additional widgets are available to load from modules.
38 | User widgets will also need to use `autoload -U $WIDGET_NAME` and `zle -N $WIDGET_NAME` to be available for `bindkey`.
39 |
40 | Widgets are generally broken up into different categories.
41 | This includes
42 | * Movement
43 | * History Control
44 | * Modifying Text
45 | * Arguments
46 | * Completion
47 | * Miscellaneous
48 | * Text Objects
49 |
50 | We already have sections in this workshop for [ line movement ]( ../usage/line_movement.md ) and [ history ]( ../config/history.md ) so in this section we'll look at some widgets in other categories.
51 |
52 | ## User Widgets
53 |
54 | Some user widgets will be included by your system in your `$fpath` and others you can declare yourself as functions in `.zshrc`.
55 | You've already seen examples of using widgets in your `$fpath` in the history section.
56 |
57 | The basic commands are:
58 |
59 | ```bash
60 | autoload -U $WIDGET
61 | zle -N $WIDGET
62 | bindkey $KEY_SEQUENCE $WIDGET
63 | ```
64 |
65 | `autoload -U` (`-U` is for user) will find a file in your `$fpath` named `$WIDGET` and makes it available to `zle`.
66 | `zle -N` (`-N` is for new) will make the widget available to the command line.
67 |
68 | `bindkey` also uses keymaps for different keyboard shortcuts but we won't worry about that here.
69 |
70 | ## Test widgets
71 |
72 | You can also test a widget interactively at a command line.
73 | Of course there's a widget `execute-named-cmd` for that.
74 |
75 | To invoke a widget first find which one you want to try with `zle -la` and then enter some text on a command prompt.
76 |
77 | Now either execute `alt+x` in emacs mode or `:` in vimcmd mode.
78 | Type the name of the widget you want to test and press enter.
79 |
80 | 
81 |
82 | ## Examples
83 |
84 | You might be thinking, what's the big deal with widgets?
85 | They're just functions with keyboard mappings.
86 |
87 | The best way to show their power is with some examples.
88 |
89 | > Most of these examples use vi keymaps.
90 | > Modify them as you wish for other keymaps.
91 |
92 | ### Prepend `sudo` to a command and put your cursor back to the previous location with `esc,s`
93 |
94 | 
95 |
96 | ```bash
97 | function prepend-sudo {
98 | if [[ $BUFFER != "sudo "* ]]; then
99 | BUFFER="sudo $BUFFER"; CURSOR+=5
100 | fi
101 | }
102 | zle -N prepend-sudo
103 |
104 | bindkey -M vicmd s prepend-sudo
105 | ```
106 |
107 | ### Get output from last command with `ctrl+q,ctrl+l`
108 |
109 | 
110 |
111 | ```bash
112 | zmodload -i zsh/parameter
113 |
114 | insert-last-command-output() {
115 | LBUFFER+="$(eval $history[$((HISTCMD-1))])"
116 | }
117 | zle -N insert-last-command-output
118 |
119 | bindkey "^Q^L" insert-last-command-output
120 | ```
121 |
122 | ### Edit the current command in your `$EDITOR` with `esc,v`
123 |
124 | 
125 |
126 | ```bash
127 | autoload -U edit-command-line
128 | zle -N edit-command-line
129 | bindkey -M vicmd v edit-command-line
130 | ```
131 |
132 | ### Tetris
133 |
134 | Of course there are some less useful widgets available too.
135 |
136 | ```bash
137 | autoload -Uz tetris
138 | zle -N tetris
139 | bindkey '^T' tetris
140 | ```
141 |
142 | 
143 |
144 | If you want to get really fancy you can check out [`tetriscurses`](https://github.com/zsh-users/zsh/blob/master/Functions/Misc/tetriscurses) too.
145 |
146 | ---
147 |
148 | Previous: [functions](functions.md) | [home](../../README.md) | Next: [completions](completions.md)
149 |
--------------------------------------------------------------------------------
/docs/misc/reference.md:
--------------------------------------------------------------------------------
1 | # Reference Material
2 |
3 | * [Zsh Users](https://github.com/zsh-users)
4 | * [Terminals are sexy](https://terminalsare.sexy/)
5 | * [Zsh docs](http://zsh.sourceforge.net/Doc/Release/index.html#Top)
6 | * [Awesome zsh plugins](https://github.com/unixorn/awesome-zsh-plugins)
7 |
8 | ## Tools I Used
9 |
10 | * [Screenkey](https://gitlab.com/wavexx/screenkey) - Keyboard overlay
11 | * [Peek](https://github.com/phw/peek) - Gif recorder
12 | * [Kitty](https://sw.kovidgoyal.net/kitty/) - terminal
13 |
--------------------------------------------------------------------------------
/docs/usage/file_management.md:
--------------------------------------------------------------------------------
1 | # File Management
2 |
3 | If you use a POSIX operating system where "everything is a file™" you'll likely be managing files frequently.
4 |
5 | zsh of course adds some nice file management functions.
6 |
7 | ## Listing and Globbing
8 |
9 | ```bash
10 | $ ls ~/*/*/*.txt
11 |
12 | $ ls ~/**/tmp/*
13 | ```
14 |
15 | ## zmv
16 |
17 | `zmv` is a user contributed function included with most zsh distributions.
18 | It allows you to move, copy, or link files based on pattern matching.
19 | You can read more in the functions section.
20 |
21 | First load zmv in your .zshrc file or local shell with.
22 |
23 | ```bash
24 | $ autoload -U zmv
25 | ```
26 |
27 | Example usage:
28 |
29 | ```bash
30 | # rename all .JPEG extensions to .jpg
31 | $ zmv '(*).JPEG' '$1.jpg'
32 |
33 | # replace all spaces in file and folder names with underscore
34 | # notice parameter replacement is available from the variables section
35 | $ zmv '(* *)' '${1// /_}'
36 | ```
37 |
38 | The `zmv` widget can also handy copying and symlinking.
39 | You can use it with `alias zcp='zmv -C'` and `alias zln='zmv -L'` or you can symlink files names `zcp` and `zln` in your `$fpath` to `zmv`.
40 |
41 | ---
42 |
43 | Previous: [navigation](navigation.md) | [home](../../README.md)
44 |
--------------------------------------------------------------------------------
/docs/usage/line_movement.md:
--------------------------------------------------------------------------------
1 | # Line Movement
2 |
3 | Effectively moving around on the command line might be the single biggest time saver.
4 | Most of the time you're typing but you'll also be doing a fair deal of line editing and movement.
5 |
6 | If you're using arrows to move back and forth you can save a lot of time learning some basic line movement keyboard shortcuts.
7 |
8 | Your line movement will depend on your loaded keymaps and the widgets you have bound to different keys.
9 | More information about custom widgets can be found in the zle section.
10 |
11 | You can manually set your keymap mode with
12 |
13 | ```bash
14 | # emacs mode
15 | bindkey -e
16 |
17 | # vi mode
18 | bindkey -v
19 | ```
20 |
21 | For the examples below I'll be using vi mode for movement.
22 |
23 | > If your `$EDITOR` or `$VISUAL` environment variables start with `vi` when the shell starts your keymap mode is automatically set to vi
24 |
25 | Keybindings have special characters to represent them.
26 | More info can be found in [bindkey](bindkey.md).
27 |
28 | For reference:
29 |
30 | * `^` = Ctrl
31 | * `^[` = Alt
32 | * `\e` or `\E` = Escape
33 |
34 | If you want to figure out how a key sequence should be represented you can try `xxd` or `echo " $keypress"`.
35 | The key letter you press is not case sensitive.
36 | So `^a` is the same as `^A`.
37 |
38 | ## Basic movement
39 |
40 | I may like vi mode for my keymap but I'm not a monster.
41 | Let's set the emacs begining and end of line keyboard shortcuts and reverse search.
42 |
43 | > `bindkey` works by default on your main keymap.
44 | > In vi mode that is `viins` so these keybindings work when typing but not in `vimcmd` mode.
45 | > To explicitly set a keymap mode use `bindkey -M $mode`.
46 |
47 | ```bash
48 | bindkey '^r' history-incremental-search-backward
49 | bindkey '^a' beginning-of-line
50 | bindkey '^e' end-of-line
51 | # Also fix annoying vi backspace
52 | bindkey '^?' backward-delete-char
53 | ```
54 |
55 | Now I have four ways to get to the begining and end of a command line.
56 | I can press `Escape`,`^` or `Ctrl`+`a` for the begining of the line, and `Escape`,`$` or `Ctrl`+`e` for the end of the line.
57 |
58 | > With vi mode you have to press escape to enter vicmd mode to enter standard vi commands.
59 | > The `^` and `$` are standard vi commands for beginning and end of a line.
60 |
61 | We also probably want some other useful keyboard shortcuts so we don't have to go back and forth between (vicmd) and vi-insert (viins) modes.
62 | I personally like these.
63 |
64 | ```bash
65 | bindkey '^[b' vi-backward-blank-word
66 | bindkey '^[w' vi-forward-blank-word
67 | ```
68 |
69 | To find widgets you can use, remember to use `zle -la` to list all widgets and `alt+x` or `esc,:` to try the widget with `execute-named-cmd`.
70 |
71 | ## Modifying Text
72 |
73 | Remember, you can use any emacs or vi commands depending on what keymap you're using.
74 | You don't have to bind keys to use them.
75 |
76 | If you want some additional functionallity check out the examples below.
77 |
78 | In general you'll be binding widgets to keyboard shortcuts.
79 | There are many `*-kill-*` widgets available that will let you kill words, lines, or letters.
80 |
81 | If you don't want to feel like a murderer you can also try the `*-yank-*` and `*-push-*` widgets too.
82 |
83 | ### Advance Word Movements and Modifications
84 | When jumping between words (for example `[^f` and `[^b` for forward and backwards in emacs mode). The shell uses a few different
85 | things to define what a "word" is. By default you can `echo $WORDCHARS` to see all the special characters the shell will include
86 | as a single word. For example the default is:
87 | ```
88 | $ echo $WORDCHARS
89 | *?_-.[]~=/&;!#$%^(){}<>
90 | ```
91 | This means that any alphanumeric character plus any of the above will be combined to be a single word. Notice how `/` is
92 | included in the above. This means `foo/bar-bazz` will be one word to be acted upon.
93 |
94 | If you are coming from bash and want your jump/delete word functions to stop at `/` and `-` you can add this in
95 | your .zshrc:
96 | ```
97 | autoload -U select-word-style
98 | select-word-style bash
99 | ```
100 | Without it `[^D` will delete a full directory path. For example:
101 | ```
102 | ## Without
103 | $ cd /project/example/delete
104 | ## Press [^D from front beginning of line
105 | $ /project/example/delete
106 | ## Press [^D again
107 | $
108 |
109 | ## With select-word-style bash
110 | $ cd /project/example/delete
111 | ## Press [^D from front beginning of line
112 | $ /project/example/delete
113 | ## Press [^D again
114 | $ /example/delete
115 | ```
116 | You can learn about the available word styles and their behavior [here](https://linux.die.net/man/1/zshcontrib) (search for `select-word-syle`).
117 | But here is a quick explanation:
118 | ```
119 | $ select-word-style
120 | Usage: select-word-style word-style
121 | where word-style is one of the characters in parentheses:
122 | (b)ash: Word characters are alphanumerics only
123 | (n)ormal: Word characters are alphanumerics plus $WORDCHARS
124 | (s)hell: Words are command arguments using shell syntax
125 | (w)hitespace: Words are whitespace-delimited
126 | (d)efault: Use default, no special handling (usually same as `n')
127 | (q)uit: Quit without setting a new style
128 | ```
129 | One important thing to note is that any `select-word-style` that is not `normal` will may not respect `$WORDCHARS`.
130 | When in `normal` select-word-style all alphanumeric characters plus anything in `$WORDCHARS` is used by zsh to determine
131 | when to stop its action. If you want even more control feel free to set the var directly. This can then be used to make your
132 | backwards jump different than your forwards jump.
133 | For example if I want my backward delete to delete a whole directory path I can set this:
134 | ```
135 | ## with word-style set to `normal` but $WORDCHARS=''
136 | default-backward-delete-word () {
137 | local WORDCHARS="*?_[]~=/&;!#$%^(){}<>"
138 | zle backward-delete-word
139 | }
140 | zle -N default-backward-delete-word
141 | bindkey '^W' default-backward-delete-word
142 | ```
143 |
144 | ### Yank current command and paste
145 |
146 | For example, let's say you have a long command line typed up but you forgot you needed to run a command first or look up some information.
147 | Normally you would push `ctrl+c` to cancel the command, run your command, and then use your mouse to select, copy, and paste the long command to the next prompt.
148 | Or maybe you open a new terminal, run your command, and come back.
149 |
150 | What if I told you there was a better way?
151 | Check out the `push-input` widget.
152 |
153 | Let's bind it to `ctrl+q` and see what it does.
154 |
155 | 
156 |
157 | You can also use `yank-pop` widget to keep a ring of yanked commands you can cycle through.
158 |
159 | ```bash
160 | # re-sets yank and kill shortcuts to bash/emacs mode
161 | bindkey -M viins '^P' push-line-or-edit
162 | bindkey -M viins '^Y' yank
163 | # in order to use the below you must first yank without hitting enter
164 | # subsequent alt-y combos will cycle through
165 | # kill ring
166 | bindkey -M viins '\ey' yank-pop
167 | bindkey -M viins '^U' backward-kill-line
168 | ```
169 |
170 | ### Matching deliminators
171 |
172 | There's a handy plugin called [autopair](https://github.com/hlissner/zsh-autopair) that can automatically match your brackets and quotes in your terminal.
173 | It works similarly to an IDE and loads an autopair-insert, autopair-close, and autopair-delete widget.
174 |
175 | 
176 |
177 | There's also an included [`surround`](https://github.com/zsh-users/zsh/blob/master/Functions/Zle/surround) widget but I had difficulty using it. YMMV.
178 |
179 | ---
180 |
181 | Previous: [completions](../helpers/completions.md) | [home](../../README.md) | Next: [navigation](navigation.md)
182 |
--------------------------------------------------------------------------------
/docs/usage/navigation.md:
--------------------------------------------------------------------------------
1 | # Navigation
2 |
3 | Navigating your filesystem is likely something you do on a regular basis.
4 | zsh knows this and has added some helpers to help you move quickly from one folder to another.
5 |
6 | ## `cd` basics
7 |
8 | Just to make sure we're all on the same page, here are some quick `cd` tips that should work in any shell.
9 |
10 | ```bash
11 | # change directory to your $HOME with just the cd command
12 | cd
13 |
14 | # change directory to the previous directory with
15 | cd -
16 | ```
17 |
18 | Now let's set the `cdpath` variable.
19 | This variable will do automatic searching for a folder within folders specified in variable.
20 |
21 | If you're familiar with bash's `CDPATH` it works the same way but in zsh instead of being a colon separated string (e.g. `.:~:~/src`) it's an array.
22 |
23 | ```bash
24 | # make some temporary folders
25 | $ mkdir -p ~/test ~/src/foo/bar
26 |
27 | $ export cdpath=(. ~ ~/src/)
28 |
29 | # cd to $HOME
30 | $ cd
31 |
32 | # cd to ~/src/foo
33 | $ cd foo
34 |
35 | # cd to ./bar
36 | $ cd bar
37 |
38 | # cd to ~/test
39 | $ cd test
40 |
41 | # cd back to ~/src/foo/bar
42 | $ cd -
43 | ```
44 |
45 | That's pretty powerful!
46 | Add more search directories you frequent and jump right to them.
47 |
48 | zsh also allows more powerful directory movement.
49 | `AUTO_CD` will automatically change into a directory even without `cd` if that directory is not the name of a command.
50 |
51 | ```bash
52 | $ ls
53 | foo/ bar/ some.txt
54 |
55 | $ setopt auto_cd
56 |
57 | # cd into foo
58 | $ foo
59 |
60 | $ pwd
61 | ~/foo
62 |
63 | # change directory to other parts of the filesystem with full paths
64 | $ ls /var/log/
65 | apache docker
66 |
67 | $ /var/log/apache
68 | ```
69 |
70 | That's cool but doesn't save a lot of time.
71 | You can also cd into unique paths with using partial words
72 |
73 | ```
74 | # assume this directory exists /var/log/apache/errors/
75 | # cd into it with
76 | $ /v/l/a/e
77 |
78 | $ pwd
79 | /var/log/apache/errors/
80 |
81 | # if /var/log/aero/errors exists you can use the minimal unique names
82 | $ /v/l/ae/e
83 |
84 | $ pwd
85 | /var/log/aero/errors
86 | ```
87 |
88 | You can also swap any part of your current path.
89 | If you have two directories with similar structures it makes moving between them much faster.
90 |
91 | ```bash
92 | $ mkdir -p foo/bar/baz/{today,tomorrow,jan-01,jan-02}/{folder1,folder2}
93 |
94 | $ tree -F foo
95 | foo
96 | └── bar/
97 | └── baz/
98 | ├── today/
99 | │ ├── folder1/
100 | │ └── folder2/
101 | ├── tomorrow/
102 | │ ├── folder1/
103 | │ └── folder2/
104 | ├── jan-01/
105 | │ ├── folder1/
106 | │ └── folder2/
107 | └── jan-02/
108 | ├── folder1/
109 | └── folder2/
110 |
111 | $ f/b/b/tom/folder2
112 |
113 | $ pwd
114 | foo/bar/baz/tomorrow/folder2
115 |
116 | # cd into foo/bar/baz/today/folder2
117 | $ cd tomorrow today
118 |
119 | $ pwd
120 | foo/bar/baz/today/folder2
121 |
122 | # this also works for partial names
123 | $ cd today jan-01
124 |
125 | $ pwd
126 | foo/bar/baz/jan-01/folder2
127 |
128 | $ cd 01 02
129 |
130 | $ pwd
131 | foo/bar/baz/jan-02/folder2
132 | ```
133 |
134 | This is about as good as it's going to get without using an external tool.
135 |
136 | ## External Tools
137 |
138 | Now that we've covered some of what zsh can do built in it's up to you to take it one step further with external tools.
139 | These tools will keep track of files and directories you frequently use and allow you to interactively search for them or automatically jump to them.
140 |
141 | Some additional homework for the reader is to install and setup one of the following
142 | * [fasd](https://github.com/clvv/fasd): All in one jump and edit tool with fuzzy matching
143 | * [autojump](https://github.com/wting/autojump): Jump to directories with frequency tracking
144 | * [z](https://github.com/rupa/z): Jump to most used directories based on 'frecency'
145 | * [v](https://github.com/rupa/v): Like `z` but for editing files with `vim`
146 |
147 | ---
148 |
149 | Previous: [line movement](line_movement.md) | [home](../../README.md) | Next: [file management](file_management.md)
150 |
--------------------------------------------------------------------------------
/img/autopair.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/autopair.gif
--------------------------------------------------------------------------------
/img/autosuggestions.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/autosuggestions.gif
--------------------------------------------------------------------------------
/img/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/banner.png
--------------------------------------------------------------------------------
/img/bash-completion.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/bash-completion.gif
--------------------------------------------------------------------------------
/img/edit-command.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/edit-command.gif
--------------------------------------------------------------------------------
/img/execute-named-cmd.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/execute-named-cmd.gif
--------------------------------------------------------------------------------
/img/fc-example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/fc-example.gif
--------------------------------------------------------------------------------
/img/fzf-history.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/fzf-history.gif
--------------------------------------------------------------------------------
/img/globalias.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/globalias.gif
--------------------------------------------------------------------------------
/img/highlighting.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/highlighting.gif
--------------------------------------------------------------------------------
/img/history-incremental-pattern-search-forward.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/history-incremental-pattern-search-forward.gif
--------------------------------------------------------------------------------
/img/last-command.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/last-command.gif
--------------------------------------------------------------------------------
/img/prepend-sudo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/prepend-sudo.gif
--------------------------------------------------------------------------------
/img/push-input.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/push-input.gif
--------------------------------------------------------------------------------
/img/tetris.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rothgar/mastering-zsh/921766e642bcf02d0f1be8fc57d0159a867299b0/img/tetris.gif
--------------------------------------------------------------------------------