<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Matthieu Cneude</title>
    <description>The latest articles on Forem by Matthieu Cneude (@phantas0s).</description>
    <link>https://forem.com/phantas0s</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F87901%2F3099dc70-8d96-41bb-845a-be6c1286e0b5.jpeg</url>
      <title>Forem: Matthieu Cneude</title>
      <link>https://forem.com/phantas0s</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/phantas0s"/>
    <language>en</language>
    <item>
      <title>Managing Local and Remote Filesystems with Vim and netrw</title>
      <dc:creator>Matthieu Cneude</dc:creator>
      <pubDate>Fri, 06 Jan 2023 06:22:00 +0000</pubDate>
      <link>https://forem.com/phantas0s/managing-local-and-remote-filesystems-with-vim-and-netrw-577i</link>
      <guid>https://forem.com/phantas0s/managing-local-and-remote-filesystems-with-vim-and-netrw-577i</guid>
      <description>&lt;p&gt;When I began to use Vim, everybody was using &lt;a href="https://github.com/preservim/nerdtree" rel="noopener noreferrer"&gt;NERDTree&lt;/a&gt;. So I followed: to navigate through my filesystem, NERDTree would be the answer for many years to come.&lt;/p&gt;

&lt;p&gt;Nowadays, I mostly use a &lt;a href="https://github.com/junegunn/fzf.vim" rel="noopener noreferrer"&gt;fuzzy finder&lt;/a&gt; to find the files I want, but a file explorer can still be useful in some situations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When I look at a new codebase. It helps to have a general overview of the filesystem, to understand the structure of the project.&lt;/li&gt;
&lt;li&gt;When I need to create, update or delete files and directories.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The more I use Vim, the more I try to get rid of my plugins, to use Vim's native functionalities as much as possible. It's easier  than keeping track of 39093209 plugins introducing breaking changes too often. That's why my interest for netrw grew overtime.&lt;/p&gt;

&lt;p&gt;What's netrw? It's the file explorer shipped with most Vim packages. It's still a Vim plugin, but if you didn't compile Vim yourself, it's likely that you have it, too.&lt;/p&gt;

&lt;p&gt;So we'll dive in netrw in this article. More specifically, we'll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Different ways to open netrw: in netrw's window, in a new window, or in a "project drawer".&lt;/li&gt;
&lt;li&gt;How to browse through your files and directories.&lt;/li&gt;
&lt;li&gt;How to change netrw's display, and filter your filetree.&lt;/li&gt;
&lt;li&gt;How to mark files and directories, and perform some actions on them.&lt;/li&gt;
&lt;li&gt;How to manage files and directory: create, open, rename, and delete.&lt;/li&gt;
&lt;li&gt;How to open files with external programs.&lt;/li&gt;
&lt;li&gt;How to bookmark specific directories.&lt;/li&gt;
&lt;li&gt;How to explore filetrees on remote servers from your local, comfy Vim.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I assume here that you're somehow proficient with Vim. If you don't understand what's happening in this article, you can look at my &lt;a href="https://thevaluable.dev/vim-commands-beginner/" rel="noopener noreferrer"&gt;series of articles to learn Vim&lt;/a&gt;. Also, &lt;a href="https://themouseless.dev/vim" rel="noopener noreferrer"&gt;I'm currently writing a book about Vim!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Are you ready to look at a different way of browsing your precious files? Let's go, then.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basics
&lt;/h2&gt;

&lt;p&gt;You can do many things with netrw, so let's look first at the very basics. First, for netrw to work, you need to set these options as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;nocp&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;filetype&lt;/span&gt; plugin &lt;span class="k"&gt;on&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use Neovim, the options above are already set correctly.&lt;/p&gt;

&lt;p&gt;If you want to disable netrw and never speak about it again, you can set these two variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:loaded_netrw&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:loaded_netrwPlugin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful if you want to use another file explorer, like NERDtree or similar.&lt;/p&gt;

&lt;p&gt;Also, if you want to read the help for a specific keystroke inside a netrw buffer, you can run &lt;code&gt;:help netrw-&amp;lt;keystroke&amp;gt;&lt;/code&gt;. For example: &lt;code&gt;:help netrw-%&lt;/code&gt;. It also works for Ex commands; for example, &lt;code&gt;:help netrw-:Sexplore&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I encourage you to read the help if some keystrokes don't work as intended. One of netrw's big strength is its flexibility: you can customize it as you see fit, most of the time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Vim's Help
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help netrw&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Opening netrw
&lt;/h2&gt;

&lt;p&gt;Let's first see how we can open our file explorer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Opening In the Current Window
&lt;/h3&gt;

&lt;p&gt;To open Vim directly in a netrw buffer, simply give a directory path as argument when you run &lt;code&gt;vim&lt;/code&gt; in your terminal. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vim /my/dir/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last slash &lt;code&gt;/&lt;/code&gt; is not mandatory for opening local directories, but it is for remote ones. It's also mandatory when you try to fetch a URL. To avoid confusion, I always add it.&lt;/p&gt;

&lt;p&gt;Inside Vim, you can also use the &lt;code&gt;:edit&lt;/code&gt; command followed by a directory name. For example, to open the directory of the file open in your current buffer, you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;e&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The netrw buffer would then open in the current window, like any other buffer.&lt;/p&gt;

&lt;p&gt;You can also use the command &lt;code&gt;:Explore &amp;lt;dir&amp;gt;&lt;/code&gt; to open the directory &lt;code&gt;&amp;lt;dir&amp;gt;&lt;/code&gt; in the current window. If you don't give a &lt;code&gt;&amp;lt;dir&amp;gt;&lt;/code&gt;, you'll open the current file's directory. This command would also open a split window if these two conditions are met:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the option "hidden" is not set.&lt;/li&gt;
&lt;li&gt;If you modified the current buffer, but you didn't save it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Opening In a Split Window
&lt;/h3&gt;

&lt;p&gt;If you don't want to open a netrw buffer in your current window, you can also summon it in a split window:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:&amp;lt;size&amp;gt;Sexplore &amp;lt;dir&amp;gt;&lt;/code&gt; - Create a horizontal split window  above the current window, of size &lt;code&gt;&amp;lt;size&amp;gt;&lt;/code&gt;, and open the &lt;code&gt;&amp;lt;dir&amp;gt;&lt;/code&gt; in a netrw buffer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:&amp;lt;size&amp;gt;Hexplore &amp;lt;dir&amp;gt;&lt;/code&gt; - Create a horizontal split window below the current window, of size &lt;code&gt;&amp;lt;size&amp;gt;&lt;/code&gt;, and open the &lt;code&gt;&amp;lt;dir&amp;gt;&lt;/code&gt; in a netrw buffer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:&amp;lt;size&amp;gt;Vexplore &amp;lt;dir&amp;gt;&lt;/code&gt; - Create a vertical split window on the left of the current window, of size &lt;code&gt;&amp;lt;size&amp;gt;&lt;/code&gt;, and open the &lt;code&gt;&amp;lt;dir&amp;gt;&lt;/code&gt; in a netrw buffer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:&amp;lt;size&amp;gt;Vexplore! &amp;lt;dir&amp;gt;&lt;/code&gt; - Create a vertical split window on the right of the current window, of size &lt;code&gt;&amp;lt;size&amp;gt;&lt;/code&gt;, and open the &lt;code&gt;&amp;lt;dir&amp;gt;&lt;/code&gt; in a netrw buffer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:Texplore &amp;lt;dir&amp;gt;&lt;/code&gt; - Open a window and a netrw buffer (browsing &lt;code&gt;&amp;lt;dir&amp;gt;&lt;/code&gt;) in a new tab.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don't give any directory &lt;code&gt;&amp;lt;dir&amp;gt;&lt;/code&gt; for the commands above, netrw will open the current file's directory.&lt;/p&gt;

&lt;p&gt;As you can see, you can specify the size of the window you want to open. For example, &lt;code&gt;:20Vex&lt;/code&gt; will open netrw in a new window on the right, with a size of 20. If you don't specify anything, the window will take half the current window. It's exactly the same behavior as regular Vim splits.&lt;/p&gt;

&lt;p&gt;If you want to open your netrw windows with a fixed size, you can set the global option &lt;code&gt;g:netrw_winsize&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:netrw_winsize&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, after opening a new file buffer using netrw, you can switch back and forth between netrw and the file buffer with the command &lt;code&gt;:Rexplore&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, if you want to open Vim's current working directory (the one displayed when you run &lt;code&gt;:pwd&lt;/code&gt;), you can use a simple user command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;command&lt;span class="p"&gt;!&lt;/span&gt; Oexplore exe &lt;span class="s1"&gt;'Explore'&lt;/span&gt; &lt;span class="nb"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to know more about Vim user commands, I covered that in &lt;a href="https://thevaluable.dev/vim-expert/" rel="noopener noreferrer"&gt;one of my article ;to learn Vim from the ground up&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Vim Help
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;:help netrw-explore&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Opening a Project Drawer
&lt;/h3&gt;

&lt;p&gt;Window splitting in Vim is a great feature. It's useful to copy and paste from one buffer to another, comparing two files, or... opening netrw.&lt;/p&gt;

&lt;p&gt;But when you compare the behavior of netrw to other "project drawer" from other editors, it might seem odd that the file selected opens in the file explorer's window. In most editors, this "project drawer" is a special, independent, and smaller window, often opened on the left side. Any file you'd open in there would then pop up in a new window, or in a new tab.&lt;/p&gt;

&lt;p&gt;The following commands try to replicate this behavior:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;:&amp;lt;size&amp;gt;Lexplore &amp;lt;dir&amp;gt;&lt;/code&gt; - Toggle a vertical netrw window of size &lt;code&gt;&amp;lt;size&amp;gt;&lt;/code&gt;. Add a bang &lt;code&gt;!&lt;/code&gt; to open it on the right end side.&lt;/p&gt;

&lt;p&gt;This command has some peculiar qualities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The window takes the full height of Vim, even if you have other horizontal split windows open.&lt;/li&gt;
&lt;li&gt;When you try to open a file, a buffer will be created in the window you called netrw from, not in the window where the netrw's buffer is.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, it behaves more like these "project drawers" I've mentioned above. But even if it looks tempting to replicate what you might already know from other editor, I would recommend you not to use this command.&lt;/p&gt;

&lt;p&gt;Vim has a specific window splitting system. The new window opened by &lt;code&gt;:Lexplore&lt;/code&gt; is different, and make things a bit more confusing. For example, if you have already multiple split windows, in what window should the file you've selected be displayed? The one you come from? What was it? Or should it be the closest one to the netrw window?&lt;/p&gt;

&lt;p&gt;Additionally, by trying to make this window special, it introduces some weird bugs, at least On My Machine™. For example, when moving from the netrw window to another window with another buffer, the netrw buffer would suddenly open there too, inexplicably.&lt;/p&gt;

&lt;p&gt;Another nasty side effect: after running &lt;code&gt;:Lexplore&lt;/code&gt;, any file you'll then try to open with netrw, whether you used &lt;code&gt;:Lexplore&lt;/code&gt; or not, will always open in the last window you came from, not in the netrw window. Internally, &lt;code&gt;:Lexplore&lt;/code&gt; set the global option &lt;code&gt;g:netrw_chgwin&lt;/code&gt; to the window you come from, &lt;em&gt;silently&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The mighty Drew Neil speaks about all of these inconveniences and more in one of his article, &lt;a href="http://vimcasts.org/blog/2013/01/oil-and-vinegar-split-windows-and-project-drawer/" rel="noopener noreferrer"&gt;Oil and Vinegar - split window and the project drawer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you really want to open your file in another window, you can use one of the following keystroke instead of relying on &lt;code&gt;:Lexplore&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;P&lt;/code&gt; - Open the file under the cursor in the previously accessed window.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;count&amp;gt;C&lt;/code&gt; - Open the file in the window with ID &lt;code&gt;&amp;lt;count&amp;gt;&lt;/code&gt;. Open in the current window if no &lt;code&gt;&amp;lt;count&amp;gt;&lt;/code&gt; specified.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also run a couple of Ex commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:NetrwC&lt;/code&gt; - Set &lt;code&gt;g:netrw_chgwin&lt;/code&gt; to the current window.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:NetrwC win#&amp;lt;number&amp;gt;&lt;/code&gt; - Set &lt;code&gt;g:netrw_chgwin&lt;/code&gt; to the window number &lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The easiest way to open your file in the window you come from is to use &lt;code&gt;P&lt;/code&gt;. You can also use &lt;code&gt;2C&lt;/code&gt; if you have only two window open, and you've opened netrw's window last.&lt;/p&gt;

&lt;p&gt;Finally, to reset the global variable &lt;code&gt;g:netrw_chgwin&lt;/code&gt;, you can run &lt;code&gt;let g:netrw_chgwin=-1&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Vim's Help
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help netrw-P&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help netrw-C&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Navigating in Vim
&lt;/h2&gt;

&lt;p&gt;Let's see now how we can effectively browse in our filesystem with netrw.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basics
&lt;/h3&gt;

&lt;p&gt;Here are the basic keystrokes we can use to browse our filesystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ENTER&lt;/code&gt; - Open a buffer with the file (or directory) under the cursor in netrw's window.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;o&lt;/code&gt; - &lt;code&gt;O&lt;/code&gt;pen the file (or directory) under the cursor in a new horizontally split window.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;v&lt;/code&gt; - Open the file (or directory) under the cursor in a new &lt;code&gt;v&lt;/code&gt;ertically split window.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;t&lt;/code&gt; - Open the file (or directory) under the cursor in a new &lt;code&gt;t&lt;/code&gt;ab.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&lt;/code&gt; - Go up one directory level.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;P&lt;/code&gt; - Open the file in the &lt;code&gt;p&lt;/code&gt;reviously focused window.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;p&lt;/code&gt; - Open the file in the &lt;code&gt;p&lt;/code&gt;review window.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Managing the Display
&lt;/h3&gt;

&lt;p&gt;Here are some useful NORMAL mode keystrokes to manage the display of your files and directories. You can make some of them global by setting the corresponding global variable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CTRL-l&lt;/code&gt; - Refresh the directory &lt;code&gt;l&lt;/code&gt;isting.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;i&lt;/code&gt; - Cycle through different listing display styles: "thin", "long", "wide", and "tree".&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I&lt;/code&gt; - Toggle the banner on top.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;s&lt;/code&gt; - Switch sorting between name, time, and size.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;r&lt;/code&gt; - Sort in &lt;code&gt;r&lt;/code&gt;everse order.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;qf&lt;/code&gt; - Display file's size and timestamp of last modification.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Filtering the Display
&lt;/h3&gt;

&lt;p&gt;What about keeping only what we need in our netrw window?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;gh&lt;/code&gt; - Toggle showing or hiding dotfiles.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;a&lt;/code&gt; - Cycle through three hiding modes determined by a regex.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want something more elaborate than &lt;code&gt;gh&lt;/code&gt;, the keystroke &lt;code&gt;a&lt;/code&gt; is here for you. It can hide or show files and directories using a regex; this regex is the value of the global variable &lt;code&gt;g:netrw_list_hide&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hitting &lt;code&gt;a&lt;/code&gt; will cycle through three different display:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Display everything.&lt;/li&gt;
&lt;li&gt;Hide the files matching the regex.&lt;/li&gt;
&lt;li&gt;Show only the files matching the regex.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, to hide all JPG and PDF images, you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:netrw_list_hide&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"\.pdf$,\.jpg$"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's also possible to hide every file specified in the &lt;code&gt;.gitignore&lt;/code&gt; file, by adding the return of the function &lt;code&gt;netrw_gitignore#Hide()&lt;/code&gt; to the hide list.&lt;/p&gt;

&lt;p&gt;For example, to hide all PDF files, MD files, and files specified in &lt;code&gt;.gitignore&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:netrw_list_hide&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"\.pdf$,\.jpg$,"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;netrw_gitignore#Hide&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last important thing: all marked files are considered part of the hide list. We'll speak about marked files just below in this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Listing the Browsing History
&lt;/h3&gt;

&lt;p&gt;The browsing history is updated when you... browse in a netrw buffer. What a surprise!&lt;/p&gt;

&lt;p&gt;You can move through the history of directories visited using these keystrokes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;u&lt;/code&gt; - Go to the preview directory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;U&lt;/code&gt; - Go to the next directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can control the count of history's entries by setting the global variable &lt;code&gt;g:netrw_dirhistmax&lt;/code&gt;. The default is 10.&lt;/p&gt;

&lt;p&gt;By default, netrw will write its history in the file &lt;code&gt;.netrwhist&lt;/code&gt;, in the first directory of the "runtimepath". If you want to change this directory, you can set a value to the variable &lt;code&gt;g:netrw_home&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Marking Files And Directories
&lt;/h2&gt;

&lt;p&gt;We saw that marked files are automatically part of the hide list when hitting the keystroke &lt;code&gt;a&lt;/code&gt; in a netrw window. But what are these marked files?&lt;/p&gt;

&lt;p&gt;They're simply files you've marked using specific marking keystrokes. Many netrw keystrokes and commands will act on the files marked.&lt;/p&gt;

&lt;p&gt;These marked files end up in two different lists:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In a global marked file list. There's only one marked file list available.&lt;/li&gt;
&lt;li&gt;In a local buffer marked file list. Each directory has one, so each directory has its own list of marked files.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, how to mark (or un-mark) files? Here are some keystrokes to do so manually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mf&lt;/code&gt; - Toggle the marking of the file or directory under the cursor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mF&lt;/code&gt; - Un-mark all the marked files in the current directory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mu&lt;/code&gt; - Un-mark all the marked files in every directory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mr&lt;/code&gt; - Open a prompt inviting you to enter a regex, and mark all the files matching it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also use the following command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:MF &amp;lt;pattern&amp;gt;&lt;/code&gt; - Mark a list of files depending on the pattern &lt;code&gt;&amp;lt;pattern&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice that these regexes accept shell-style globs.&lt;/p&gt;

&lt;p&gt;You can also mark the files which are already in another Vim list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;qL&lt;/code&gt; - Mark all the files part of the &lt;code&gt;l&lt;/code&gt;ocation list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;qF&lt;/code&gt; - Mark all the files part of the quick&lt;code&gt;f&lt;/code&gt;ix list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mA&lt;/code&gt; - Mark all the files part of the &lt;code&gt;a&lt;/code&gt;rgument list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ma&lt;/code&gt; - Move marked files to the &lt;code&gt;a&lt;/code&gt;rgument list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cb&lt;/code&gt; - Move marked files to the &lt;code&gt;b&lt;/code&gt;uffer list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cB&lt;/code&gt; - Mark all the files part of the &lt;code&gt;b&lt;/code&gt;uffer list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Weirdly enough, there's no keystroke available to display the list of all marked files. But you can run the following command to do so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;echo netrw#Expose&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"netrwmarkfilelist"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even better: you can create a user command you can then map to a keystroke, if you want to. If you wonder what's a user command, I've covered that in &lt;a href="https://dev.to/vim-expert/"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, here are some interesting keystrokes to act directly on the marked files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mv&lt;/code&gt; - Prompt the user to enter a Vimscript command operating on all marked files, one at a time. Use &lt;code&gt;%&lt;/code&gt; as filename placeholder.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mx&lt;/code&gt; - Prompt the user to enter a shell command operating on all marked files, one at a time. Use &lt;code&gt;%&lt;/code&gt; as filename placeholder.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mX&lt;/code&gt; - Apply a shell command on every file at once.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mz&lt;/code&gt; - Compress (or uncompress) marked files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mg&lt;/code&gt; - Apply Vimgrep to the marked files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ms&lt;/code&gt; - Source all marked files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll see many more ways to operate on marked files below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing Files and Directories
&lt;/h2&gt;

&lt;p&gt;We have now multiple options to open and display our files and directories using netrw. Next, let's see how to manage our filetree by adding or deleting elements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating and Deleting
&lt;/h3&gt;

&lt;p&gt;Here are the keystrokes you can use in a netrw window to add or delete files or directories. Under the hood, netrw will run specific shell commands to operate on the files of your liking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;d&lt;/code&gt; - Create a directory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%&lt;/code&gt; - Create a new file (when the buffer created is saved).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;D&lt;/code&gt; - Delete the file (or empty directory) under the cursor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default, you won't be able to remove non-empty directory. You can however decide to always delete directories recursively, by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:netrw_localrmdir&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'rm -r'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The keystroke &lt;code&gt;D&lt;/code&gt; will also delete all marked files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Renaming Files or Directory
&lt;/h3&gt;

&lt;p&gt;What about renaming what we already have?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;R&lt;/code&gt; - Rename (or move) files and directories. It's also possible to modify its path to move it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keystroke will also try to rename all marked files.&lt;/p&gt;

&lt;p&gt;There is no problem to use this keystroke locally, but there's a big caveat when used on remote files. In that case, it will copy the file first, and then delete it. The two operations are independent; if the copy fail and the delete succeed, you'll lose the file.&lt;/p&gt;

&lt;p&gt;We'll see the remote possibilities of netrw below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Copying Files
&lt;/h3&gt;

&lt;p&gt;Copying files or directories require three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select the target directory (where the files need to be copied) with the keystroke &lt;code&gt;mt&lt;/code&gt;. If the banner is visible, the target path will be displayed there.&lt;/li&gt;
&lt;li&gt;Mark the files you want to copy with &lt;code&gt;mf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Hit &lt;code&gt;mc&lt;/code&gt; to effectively &lt;code&gt;c&lt;/code&gt;opy the files.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By default, netrw use the command &lt;code&gt;cp&lt;/code&gt; under the hood. If it doesn't work, a message will point out what variable you need to set to use a different the command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Moving Files
&lt;/h3&gt;

&lt;p&gt;In netrw, moving files or copying them is a similar operation.&lt;/p&gt;

&lt;p&gt;Again, a word of caution: if you move remote files, they'll be first copied and then deleted. You'll lose your files if the copy operation fails and the delete operation succeed.&lt;/p&gt;

&lt;p&gt;Here are the three steps to move our files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select the target directory (where the files need to be copied) with the keystroke &lt;code&gt;mt&lt;/code&gt;. If the banner is visible, the target path will be displayed there.&lt;/li&gt;
&lt;li&gt;Mark the files you want to copy with &lt;code&gt;mf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Hit &lt;code&gt;mm&lt;/code&gt; to &lt;code&gt;m&lt;/code&gt;ove the files.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By default, netrw use the command &lt;code&gt;cp&lt;/code&gt; under the hood. If it doesn't work, a message will point out what variable you need to set to change this command.&lt;/p&gt;

&lt;h3&gt;
  
  
  File Permissions
&lt;/h3&gt;

&lt;p&gt;Using netrw, you can also change the file &lt;code&gt;p&lt;/code&gt;ermissions using the keystroke &lt;code&gt;gp&lt;/code&gt;. It uses the CLI "chmod" under the hood; if you want to change it, you need to give a value to the variable &lt;code&gt;g:netrw_chgperm&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opening Files with External Applications
&lt;/h2&gt;

&lt;p&gt;If you want to open a specific file using an external application, here are some keystrokes to do so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;x&lt;/code&gt; - Open the file under the cursor with the user's preferred application.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X&lt;/code&gt; - Prompt for arguments, then use your shell to call the executable file under the cursor with the arguments.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gx&lt;/code&gt; - Can be used in any type of buffer (netrw and file buffers) to open the file (or URL) under the cursor with the user's preferred application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The keystroke &lt;code&gt;gx&lt;/code&gt; is handy to open a URL from your buffer while editing. I use it all the time!&lt;/p&gt;

&lt;p&gt;By default, netrw uses an application which can open user's preferred applications, like &lt;a href="https://linux.die.net/man/1/xdg-open" rel="noopener noreferrer"&gt;xdg-open&lt;/a&gt; for example. You can change it by setting a value to &lt;code&gt;g:netrw_browsex_viewer&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:netrw_browsex_viewer&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"xdg-open"&lt;/span&gt;`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you set the value of this global variable to &lt;code&gt;-&lt;/code&gt; (&lt;code&gt;let g:netrw_browsex_viewer='-'&lt;/code&gt;), then netrw will try to run a function depending on the extension of the file. For example, if you try to open an HTML file, the function &lt;code&gt;NFH_html()&lt;/code&gt; will be invoked, with the filepath as argument. You can then write some code in the body of the function to specify how to open the file.&lt;/p&gt;

&lt;p&gt;You can find many examples in this file: &lt;code&gt;$VIMRUNTIME/autoload/netrwFileHandlers.vim&lt;/code&gt;. If you don't know where your Vim runtime is (or what's the Vim runtimepath), you can look &lt;a href="https://dev.to/vim-runtime-guide-example/"&gt;at this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Additionally, you can set different global variables to customize this functionality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;g:netrw_gx&lt;/code&gt; - Control how &lt;code&gt;gx&lt;/code&gt; picks up the text under the cursor. The default is &lt;code&gt;&amp;lt;cfile&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;g:netrw_nogx&lt;/code&gt; - Disable the &lt;code&gt;gx&lt;/code&gt; keystroke for non-netrw buffers.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;g:netrw_suppress_gx_mesg&lt;/code&gt; - Display messages from the browser open in Vim. Default is 0 (disabled).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bookmarking Files and Directories
&lt;/h2&gt;

&lt;p&gt;We also have the possibility to bookmark our favorite directories in netrw. Here are the most useful keystrokes to do so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mb&lt;/code&gt; - Bookmark the currently browsed directory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mB&lt;/code&gt; - Delete the last bookmark.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;qb&lt;/code&gt; - List all bookmarks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;count&amp;gt;gb&lt;/code&gt; - &lt;code&gt;G&lt;/code&gt;o back to the bookmark number &lt;code&gt;&amp;lt;count&amp;gt;&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the bookmarks are written in the file &lt;code&gt;.netrwbook&lt;/code&gt;. This file is located by default in the first directory of the &lt;a href="https://dev.to/vim-runtime-guide-example/"&gt;runtimepath&lt;/a&gt;. Similarly to the history, you can also set the variable &lt;code&gt;g:netrw_home&lt;/code&gt; to change the directory of &lt;code&gt;.netrwbook&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also use the following Ex commands to manage your bookmarks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:NetrwMB&lt;/code&gt; - Bookmark file or directory under the cursor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:NetrwMB &amp;lt;files_or_dirs&amp;gt;&lt;/code&gt; - Bookmark files and directories &lt;code&gt;&amp;lt;files_or_dirs&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you run &lt;code&gt;:NetrwMB&lt;/code&gt; with marked files, they'll also be all bookmarked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remote Operations and Protocols
&lt;/h2&gt;

&lt;p&gt;We've seen in details how to manage our files and directories using netrw on a local computer. We can also use it to explore and manage the file systems on remote computers, via SCP or FTP!&lt;/p&gt;

&lt;p&gt;There are two categories of operations we can do on these remote files and directories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read and write.&lt;/li&gt;
&lt;li&gt;Only read.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keep in mind that writing on a remote system is potentially destructive.&lt;/p&gt;

&lt;p&gt;Under the hood, netrw use the file &lt;code&gt;netrw.vim&lt;/code&gt; in &lt;code&gt;$VIMRUNTIME/autoload/netrw.vim&lt;/code&gt;. It uses autocommands to intercept read and write for URL-like filenames.&lt;/p&gt;

&lt;p&gt;This file &lt;code&gt;netrw.vim&lt;/code&gt; is mainly a wrapper sending commands to external program, like &lt;code&gt;ftp&lt;/code&gt; or &lt;code&gt;scp&lt;/code&gt;. You can also read using other protocols (like HTTP), but writing and browsing a remote filesystem is always done via FTP or SCP.&lt;/p&gt;

&lt;p&gt;Our netrw will read and write from temporary files copied from the remote system on the local computer. For Unix-like system (including Linux), these files will end up in the &lt;code&gt;/tmp&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;We can use all the commands we've seen until now on remote files, too. There are two important differences, however:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;As I mentioned already, if you want to move remote files or directories, you'll need to do a copy first and then a delete. If the copy fails and the delete succeed, the file or directory will be deleted from the system. Copying manually the file first, and then deleting the files in a second step is safer.&lt;/li&gt;
&lt;li&gt;If you want to overwrite the command used by the keystroke &lt;code&gt;d&lt;/code&gt; (to create a directory), you need to assign a value to &lt;code&gt;g:netrw_mkdir_cmd&lt;/code&gt;, not &lt;code&gt;g:netrw_localmkdir&lt;/code&gt;. The same logic apply for other operations; for example, to remove a directory: &lt;code&gt;g:netrw_rmdir_cmd&lt;/code&gt; for a remote system, &lt;code&gt;g:netrw_localrmdir&lt;/code&gt; for a local one.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To open a remote directory, you can use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vim &amp;lt;protocol&amp;gt;://&amp;lt;user&amp;gt;@&amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/&amp;lt;path&amp;gt;/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we said earlier, the &lt;code&gt;&amp;lt;protocol&amp;gt;&lt;/code&gt; can be "scp", "ftp", "http"...&lt;/p&gt;

&lt;p&gt;As often, depending on the protocol you're using, netrw will internally call a shell command to access the directory.&lt;/p&gt;

&lt;h4&gt;
  
  
  Vim's Help
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;:help netrw-protocol&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Using SCP
&lt;/h3&gt;

&lt;p&gt;What's SCP? It's a protocol to exchange files between clients and servers using SSH. As a result, the exchanges are authenticated and encrypted.&lt;/p&gt;

&lt;p&gt;Using the pattern we've seen just above, if I want to open my home directory on my remote server from my local computer, I can simply run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vim scp://hypnos@185.193.160.40/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A netrw window will then open, browsing the home directory of the user &lt;code&gt;hypnos&lt;/code&gt; on my server with IP &lt;code&gt;185.183.160.40&lt;/code&gt;. Even better: if you use OpenSSH, you can write this kind of configuration in your &lt;code&gt;$HOME/.ssh/config&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host server
     HostName 185.193.160.40
     User hypnos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't want to enter your password 3892 times while browsing, you can log to your remote server using one of your local SSH key. If you're on a Unix/Linux machine, look at &lt;code&gt;man ssh-copy-id&lt;/code&gt; for more details.&lt;/p&gt;

&lt;p&gt;We can also directly open a file with, for example, the command &lt;code&gt;vim scp://server/myfile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Speaking of files, we can also use the usual Ex commands inside Vim to edit, read or write them. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:e scp://user@ip/myfile&lt;/code&gt; - Edit the file &lt;code&gt;myfile&lt;/code&gt; in the current window.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:r scp://user@ip/myfile&lt;/code&gt; - Insert the content of &lt;code&gt;myfile&lt;/code&gt; in the current buffer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:w scp://user@ip/myfile&lt;/code&gt; - Write the content of the current buffer into &lt;code&gt;myfile&lt;/code&gt;. Useful to copy a file from your local to your remote server!&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Vim's Help
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help netrw-externapp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help netrw-transparent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help netrw-ex&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:netrw-ssh-hack&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using FTP
&lt;/h3&gt;

&lt;p&gt;You can also open files using the FTP protocol. Since this protocol is not secure at all (a third party can intercept the data, including username and password), I'd recommend you to use the SFTP protocol (for SSH FTP) instead.&lt;/p&gt;

&lt;p&gt;On the surface it works similarly than the &lt;code&gt;SCP&lt;/code&gt; protocol. Just call a URL like &lt;code&gt;vim sftp://user@ip/myfile&lt;/code&gt; for example, and you're good to go.&lt;/p&gt;

&lt;p&gt;There are two potential drawbacks, however:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's significantly slower than SCP.&lt;/li&gt;
&lt;li&gt;Some FTP implementations are noisy and add some junk to the filenames. You'll need to write a function &lt;code&gt;NetReadFixup&lt;/code&gt; to clean them up automatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The benefit? You can do many more operations on files using SFTP compared to SCP.&lt;/p&gt;

&lt;p&gt;You can also write a &lt;code&gt;.netrc&lt;/code&gt; file (probably located in your home directory) to specify your favorite way to connect to a remote via FTP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Obtaining a File
&lt;/h3&gt;

&lt;p&gt;While browsing, you can use the &lt;code&gt;O&lt;/code&gt; keystroke to fetch the remote file under the cursor. Vim won't open it in a new buffer. If some files are marked, they'll all be fetched.&lt;/p&gt;

&lt;p&gt;These files are copied to the Vim's working directory. To display the &lt;code&gt;p&lt;/code&gt;ath of this &lt;code&gt;w&lt;/code&gt;orking &lt;code&gt;d&lt;/code&gt;irectory, you can run &lt;code&gt;:pwd&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading via HTTP
&lt;/h3&gt;

&lt;p&gt;Using netrw, we can also fetch some content from HTTP. For example, try to run the following in Vim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;e&lt;/span&gt; http&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;www&lt;span class="p"&gt;.&lt;/span&gt;google&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;com&lt;/span&gt;/`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulation! You're reading Google's HTML.&lt;/p&gt;

&lt;p&gt;If you try to write the file, netrw will try to upload it back to the remote URL. On my machine, it runs the command &lt;code&gt;curl -T http://www.google.com&lt;/code&gt;, but it might be different on yours.&lt;/p&gt;

&lt;p&gt;You can also use &lt;code&gt;:r &amp;lt;URL&amp;gt;/&lt;/code&gt; to insert in the current buffer, instead of opening a new one&lt;/p&gt;

&lt;h2&gt;
  
  
  Customizing netrw's Mapping
&lt;/h2&gt;

&lt;p&gt;The easiest way to customize netrw keystrokes is to declare your new mapping in the folder &lt;code&gt;ftplugin&lt;/code&gt;. Again, if you wonder what it is, I've written about the &lt;a href="https://dev.to/vim-runtime-guide-example/"&gt;Vim's runtimepath here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, if you want to toggle the netrw banner by hitting &lt;code&gt;B&lt;/code&gt; instead of &lt;code&gt;I&lt;/code&gt;, you can add the following to the file &lt;code&gt;$HOME/.vim/ftplugin/netrw.vim&lt;/code&gt; (or &lt;code&gt;$XDG_CONFIG_HOME/nvim/ftplugin/netrw.vim&lt;/code&gt; for Neovim):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; B I
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works because all netrw buffers have the filetype "netrw".&lt;/p&gt;

&lt;h2&gt;
  
  
  Master of Browsing
&lt;/h2&gt;

&lt;p&gt;There are many other ways to customize netrw, but I think I've covered enough here to answer most needs.&lt;/p&gt;

&lt;p&gt;What did we see in this article?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can open the help for specific netrw &lt;code&gt;&amp;lt;keystroke&amp;gt;&lt;/code&gt; by running the Ex command &lt;code&gt;:help netrw-&amp;lt;keystroke&amp;gt;&lt;/code&gt;. It also works for Ex commands.&lt;/li&gt;
&lt;li&gt;There is a command to open Netrw wherever you want, depending of the current window: on the side or on top of it.&lt;/li&gt;
&lt;li&gt;You can go back and forth in netrw's browsing history using &lt;code&gt;u&lt;/code&gt;  and &lt;code&gt;U&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It's possible to mark files and directories. The usual keystrokes will then act on these files.&lt;/li&gt;
&lt;li&gt;Using netrw, we can create, delete, rename, or move files and directories.&lt;/li&gt;
&lt;li&gt;It's also possible to open files using external applications or commands.&lt;/li&gt;
&lt;li&gt;Bookmarking directories can be a good way to open quickly whatever you need.&lt;/li&gt;
&lt;li&gt;One of the most powerful feature of netrw allows us to open remote filesystems using SCP or FTP.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The native plugin netrw might not be the most stable or the most complete file manager out there, but, to me, it's enough for the daily operations we all do on our precious files.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://vimcasts.org/blog/2013/01/oil-and-vinegar-split-windows-and-project-drawer/" rel="noopener noreferrer"&gt;Oil and Vinegar - split window and project drawer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://vimcasts.org/episodes/the-file-explorer/" rel="noopener noreferrer"&gt;vimcast - The file explorer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Learning to Play Vim: A Fun Guide to Learn the Best Editor
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://themouseless.dev/vim" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuq360tbdh77u7noxyrzy.webp" alt="Learning to Play Vim" width="800" height="1131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I began to write a very ambitious guide to learn Vim from the ground up. Thanks to great feedback from my readers, I'll be able to address the problems many beginners complain about when learning Vim. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to navigate in multiple files and projects in Vim?&lt;/li&gt;
&lt;li&gt;How to debug in Vim?&lt;/li&gt;
&lt;li&gt;How to search, find, and replace?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide will explain the most useful vanilla functionalities as well as some powerful plugins which will enrich your experience.&lt;/p&gt;

&lt;p&gt;Help me make an impact in the Vim world! You can subscribe to the newsletter and tell me everything you want to see in the book. Early bird discount guarantees!&lt;/p&gt;

&lt;p&gt;I reply to every email personally, so don't hesitate to ask as many questions as you want. It's always a pleasure to help.&lt;/p&gt;

&lt;p&gt;Last but not least: I've also written a book about building your own Mouseless Development Environment, so if you're interested by that too, &lt;a href="https://themouseless.dev" rel="noopener noreferrer"&gt;click on this shiny link&lt;/a&gt;.&lt;/p&gt;




</description>
      <category>vim</category>
      <category>terminal</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Create Vim Text-Objects in Lua</title>
      <dc:creator>Matthieu Cneude</dc:creator>
      <pubDate>Sat, 23 Jul 2022 10:48:43 +0000</pubDate>
      <link>https://forem.com/phantas0s/how-to-create-vim-text-objects-in-lua-e7f</link>
      <guid>https://forem.com/phantas0s/how-to-create-vim-text-objects-in-lua-e7f</guid>
      <description>&lt;p&gt;"You don't get it. Vim is like a language! You'll speak Vim when you write! When you go to the market! You'll speak Vim with your cat! When you think, it will be the Word of Vim™ in your head! You'll see! It will change your life!"&lt;/p&gt;

&lt;p&gt;This is the kind of argument any Vim hippy would sing to the poor heretics, trying to convert them to The Eternal Editor. A hippy like me, who's now writing an article about one of the main component of this "language", the &lt;em&gt;text-object&lt;/em&gt;. Repeat after me: glory to the text-object!&lt;/p&gt;

&lt;p&gt;It's powerful to use them, that's true; but we can do better. We could create new text-objects, like a god creating life! We could shape the Chaos to bring order in the galaxy!&lt;/p&gt;

&lt;p&gt;The Greek god &lt;a href="https://en.wikipedia.org/wiki/Hephaestus" rel="noopener noreferrer"&gt;Hephaestus&lt;/a&gt; created the fire in his legendary forge. Like him, we also need some tools to create our own text-objects. What on Earth can we use? Vimscript?&lt;/p&gt;

&lt;p&gt;With Neovim, we can use Lua to customize our favorite editor; we can also &lt;a href="https://gist.github.com/leolord/bb51bdee3f199c2a6cfe2d57a42a2c26" rel="noopener noreferrer"&gt;compile Vim with Lua support&lt;/a&gt;. To me, one of the best way to learn how to customize Vim is to take already written functions in Vimscript and transform them in Lua.&lt;/p&gt;

&lt;p&gt;The benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you don't know Vimscript, analyzing the code to transform it in Lua will show you useful functions you can use for more customization. It's essential for harnessing Vim's power.&lt;/li&gt;
&lt;li&gt;If you don't know Lua, you can learn it this way, too. It's a great programming language, used by many other tools, like the fantastic &lt;a href="https://www.youtube.com/watch?v=-S8-a_YS6tc" rel="noopener noreferrer"&gt;Pandoc&lt;/a&gt; for example.&lt;/li&gt;
&lt;li&gt;You'll get a deeper understanding how Vim works, allowing your to improve your workflow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So let's taste the power of Vimscript functions combined with Lua constructs, by implementing useful text-objects. More specificaly, we'll see in this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The general principles governing text-objects.&lt;/li&gt;
&lt;li&gt;How to create a text-object representing a line.&lt;/li&gt;
&lt;li&gt;How to create text-objects delimited by a pair of characters, like two commas.&lt;/li&gt;
&lt;li&gt;How to create a very useful - and quite universal - text-object matching some level of indentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The text-objects we'll create are inspired by other authors from The Great Internet™. You'll find the sources of this inspiration at the end of the article.&lt;/p&gt;

&lt;p&gt;I assume here that you're somehow proficient with Vim. If you don't understand what's happening in this article, you can look at my &lt;a href="https://thevaluable.dev/vim-commands-beginner/" rel="noopener noreferrer"&gt;series of articles to learn Vim&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If it's the first time you write some Lua, I would encourage you to customize things further by modifying the examples we'll see in this article. To use the correct syntax, you should keep a quick reference on side, like &lt;a href="https://learnxinyminutes.com/docs/lua/" rel="noopener noreferrer"&gt;this one&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Are you ready to dive into Vimscript, Lua, and text-objects? I'm sure you are! Let's go!&lt;/p&gt;

&lt;h2&gt;
  
  
  What's a Text-Object?
&lt;/h2&gt;

&lt;p&gt;Before jumping into Vim to create our new delightful text-objects, let's first do what any developer should do when she needs to solve a problem: thinking. Let's &lt;a href="https://thevaluable.dev/single-responsibility-principle-revisited/#decomposition" rel="noopener noreferrer"&gt;decompose&lt;/a&gt; what a text-object is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Text-objects are NORMAL mode keystrokes using two keys; the first one can only be an "a" (for "&lt;code&gt;a&lt;/code&gt;round") or an "i" (for "&lt;code&gt;i&lt;/code&gt;nside").&lt;/li&gt;
&lt;li&gt;A text-object represents a specific string of characters, with a beginning and an end.&lt;/li&gt;
&lt;li&gt;It can only be used after an operator, or after switching to VISUAL mode character-wise (using "v" in NORMAL mode).&lt;/li&gt;
&lt;li&gt;The operator will act on the text-object, VISUAL mode will select the text-object itself.&lt;/li&gt;
&lt;li&gt;To apply an operator on some text-objects, the cursor doesn't have to be on the text-object itself. In that case, the operator will act on the &lt;em&gt;next&lt;/em&gt; text-object of the line.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you never heard of the rule 5, it can change your life, and bring you glory and fortune in a couple of days. Nothing less! If you type &lt;code&gt;di(&lt;/code&gt; in NORMAL mode, and your cursor is &lt;em&gt;before&lt;/em&gt; a pair of parentheses, you'll move inside them. The operator &lt;code&gt;d&lt;/code&gt; will then delete everything inside. Neat!&lt;/p&gt;

&lt;p&gt;As I was saying just above, a text-object can begin with an "a" or an "i". I understand text-objects beginning with "a" as "&lt;code&gt;a&lt;/code&gt;round", even if Vim's help will refer to them as the indefinite article &lt;code&gt;a&lt;/code&gt;, like &lt;code&gt;d&lt;/code&gt;elete &lt;code&gt;a&lt;/code&gt; &lt;code&gt;w&lt;/code&gt;ord. I prefer "around" because this kind of text-objects often include some characters around the "inside" text-object. It's a good mnemonic to remember the difference between the two.&lt;/p&gt;

&lt;p&gt;Motions are looking a lot like text-objects, but they're not the same. Using an operator before a motion will perform an action from the cursor position to the end result of the motion. A text-object doesn't necessarily start at the cursor position; that's the biggest difference.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;daw&lt;/code&gt; will &lt;code&gt;d&lt;/code&gt;elete &lt;code&gt;a&lt;/code&gt;round a &lt;code&gt;w&lt;/code&gt;ord, whatever the letter of the word your cursor is on. Using a motion, &lt;code&gt;dw&lt;/code&gt; will delete from the cursor position to the next &lt;code&gt;w&lt;/code&gt;ord.&lt;/p&gt;

&lt;p&gt;Now that we explored the problem space, let's enter the solution space. To create a text-object with a start and an end, we could simply:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select the characters we want.&lt;/li&gt;
&lt;li&gt;Apply whatever operator on the selection.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's great, because Vim has some mapping allowing us to do that easily.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help text-object&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help motion&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Operator-Pending Mapping
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Basics
&lt;/h3&gt;

&lt;p&gt;When we hit an operator in NORMAL mode (like &lt;code&gt;d&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, or &lt;code&gt;c&lt;/code&gt;, for example), we switch silently to the OPERATOR-PENDING mode. It's in this mode that we'll input our motion (or text-object) we want to operate on. Then, we switch back to NORMAL mode, automagically.&lt;/p&gt;

&lt;p&gt;To define new text-objects (or motions) which can be used in OPERATOR-PENDING mode, you can use an operator-pending mapping: &lt;code&gt;omap&lt;/code&gt; or, if you don't want a recursive mapping, &lt;code&gt;onoremap&lt;/code&gt;. Thanks to them, we only need to worry about selecting the characters included in our text-objects; we don't care about the operators themselves.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Line: Our New Text-Object
&lt;/h3&gt;

&lt;p&gt;Let's now create the first text-object of this article: a line.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The text-object &lt;code&gt;al&lt;/code&gt; ("&lt;code&gt;a&lt;/code&gt;round the &lt;code&gt;l&lt;/code&gt;ine) will delete everything, including the possible indentations at the beginning.&lt;/li&gt;
&lt;li&gt;The text-object &lt;code&gt;il&lt;/code&gt; (&lt;code&gt;i&lt;/code&gt;nside the &lt;code&gt;l&lt;/code&gt;ine) won't delete the indentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a first mapping for &lt;code&gt;il&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;onoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;il&lt;/span&gt; &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;u&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;normal&lt;span class="p"&gt;!&lt;/span&gt; $&lt;span class="k"&gt;v&lt;/span&gt;^&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case you're not sure what that means, here are some explanations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;silent&amp;gt;&lt;/code&gt; - Don't echo the Ex-command executed in the command-line window.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;c-u&amp;gt;&lt;/code&gt; - Delete everything already written in COMMAND-LINE mode (like the selection markers &lt;code&gt;'&amp;lt;,'&amp;gt;&lt;/code&gt; for example).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;normal!&lt;/code&gt; - This Ex-command allow executing NORMAL mode keystrokes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$v^&lt;/code&gt; - Go to the end of the line, switch to VISUAL mode, and select till the beginning of the line (without the eventual white spaces).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if you hit &lt;code&gt;yil&lt;/code&gt; or &lt;code&gt;dil&lt;/code&gt;, your operators &lt;code&gt;y&lt;/code&gt;ank and &lt;code&gt;d&lt;/code&gt;elete will operate on our new text-object. If we only want to select it, we need another mapping for VISUAL mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;xnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;il&lt;/span&gt; &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;u&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;normal&lt;span class="p"&gt;!&lt;/span&gt; $&lt;span class="k"&gt;v&lt;/span&gt;^&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now hit &lt;code&gt;vil&lt;/code&gt; and admire the potential of your infinite skills.&lt;/p&gt;

&lt;p&gt;We have now the "inside" version of our text-object; what about the "around" one?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;xnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;al&lt;/span&gt; &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;u&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;normal&lt;span class="p"&gt;!&lt;/span&gt; $v0&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
onoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;al&lt;/span&gt; &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;u&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;normal&lt;span class="p"&gt;!&lt;/span&gt; $v0&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These mappings follow the same principles, except that we select everything this time, including the eventual whitespaces at the beginning of the line. We could also use &lt;code&gt;V&lt;/code&gt; instead of &lt;code&gt;$v0&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help omap-info&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Missing Text-Objects
&lt;/h2&gt;

&lt;p&gt;Our new text-objects are great, but we can do better. This time, we'll create a whole series, delimited by different pair of characters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Between Two Characters
&lt;/h3&gt;

&lt;p&gt;It's easy to delete a pair of parentheses: &lt;code&gt;a(&lt;/code&gt;, &lt;code&gt;a)&lt;/code&gt;, or even &lt;code&gt;ab&lt;/code&gt; are there for you. As always, there are some "inside" variants, too. But what about deleting everything between two dots? Between two hyphens? Between two commas?&lt;/p&gt;

&lt;p&gt;What about creating text-objects delimited by these characters: &lt;code&gt;,&lt;/code&gt;,&lt;code&gt;.&lt;/code&gt;,&lt;code&gt;;&lt;/code&gt;,&lt;code&gt;:&lt;/code&gt;,&lt;code&gt;+&lt;/code&gt;,&lt;code&gt;-&lt;/code&gt;,&lt;code&gt;=&lt;/code&gt;,&lt;code&gt;~&lt;/code&gt;,&lt;code&gt;_&lt;/code&gt;,&lt;code&gt;*&lt;/code&gt;,&lt;code&gt;#&lt;/code&gt;,&lt;code&gt;/&lt;/code&gt;,&lt;code&gt;|&lt;/code&gt;,&lt;code&gt;\&lt;/code&gt;,&lt;code&gt;&amp;amp;&lt;/code&gt;,&lt;code&gt;$&lt;/code&gt;,&lt;code&gt;?&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;To solve this problem, we could look at a simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hello, how are you, you?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we want to change the characters between the two commas, we could:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Move the cursor to the first comma.&lt;/li&gt;
&lt;li&gt;Select everything till the second comma.&lt;/li&gt;
&lt;li&gt;Whether including the commas in the selection or not will be the difference between the "around" and the "inside" text-object.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This scenario requires our cursor to be between the two commas, at least for now. We'll improve this soon.&lt;/p&gt;

&lt;p&gt;To move our cursor to the first or second comma, we can use &lt;code&gt;f&lt;/code&gt;, &lt;code&gt;F&lt;/code&gt;, &lt;code&gt;t&lt;/code&gt;, and &lt;code&gt;T&lt;/code&gt; in NORMAL mode. Here's a possible solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;xnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;u&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;normal&lt;span class="p"&gt;!&lt;/span&gt; T&lt;span class="p"&gt;,&lt;/span&gt;vt&lt;span class="p"&gt;,&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
onoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;u&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;normal&lt;span class="p"&gt;!&lt;/span&gt; T&lt;span class="p"&gt;,&lt;/span&gt;vt&lt;span class="p"&gt;,&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
xnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;u&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;normal&lt;span class="p"&gt;!&lt;/span&gt; F&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;,&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
onoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;u&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;normal&lt;span class="p"&gt;!&lt;/span&gt; F&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;,&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could repeat these mappings for every character we want to include. But it would be quite difficult to read and maintain. Taking some inspiration from a Zsh snippet I've already covered in &lt;a href="https://dev.to/zsh-install-configure-mouseless/#adding-text-objects"&gt;this article&lt;/a&gt;, we could:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Loop through all the different characters.&lt;/li&gt;
&lt;li&gt;Loop through all the different modes we want to map (OPERATOR-PENDING mode and VISUAL mode).&lt;/li&gt;
&lt;li&gt;Create the different mappings for each iteration.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a possible implementation in Vimscript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;s:chars&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'_'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;':'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;';'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;bar&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;bslash&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'+'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'%'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'`'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'?'&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; char &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;s:chars&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;mode&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'xnoremap'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'onoremap'&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'%s &amp;lt;silent&amp;gt; i%s :&amp;lt;C-u&amp;gt;normal! T%svt%s&amp;lt;CR&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; char&lt;span class="p"&gt;,&lt;/span&gt; char&lt;span class="p"&gt;,&lt;/span&gt; char&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'%s &amp;lt;silent&amp;gt; a%s :&amp;lt;C-u&amp;gt;normal! F%svf%s&amp;lt;CR&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; char&lt;span class="p"&gt;,&lt;/span&gt; char&lt;span class="p"&gt;,&lt;/span&gt; char&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;endfor&lt;/span&gt;
&lt;span class="k"&gt;endfor&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I like to use Vimscript for simple configurations, but as soon as I need to reach for loops or conditionals (I hate the equality-operators-mess in Vimscript), I switch to Lua. If you use Neovim, or if you have Vim compiled with Lua, you can use the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;basic_text_objects&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'_'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;':'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;';'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'|'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'+'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'%'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'`'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'?'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;ipairs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;ipairs&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'o'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
            &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_set_keymap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"i"&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;string.format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;':&amp;lt;C-u&amp;gt;normal! T%svt%s&amp;lt;CR&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;noremap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;silent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_set_keymap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"a"&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;string.format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;':&amp;lt;C-u&amp;gt;normal! F%svf%s&amp;lt;CR&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;noremap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;silent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;basic_text_objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;basic_text_objects&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I would advise you to keep your Lua scrips in a &lt;code&gt;lua/&amp;lt;namespace&amp;gt;&lt;/code&gt; folder; &lt;code&gt;&amp;lt;namespace&amp;gt;&lt;/code&gt; could be your username, or anything else you'd like. For example, my scripts are in &lt;code&gt;$XDG_CONFIG_HOME/nvim/lua/hypnos&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, you can call directly your new functions in your vimrc. If it's a Vimscript file, you'll need the prefix &lt;code&gt;lua&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;lua&lt;/span&gt; require&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;namespace&amp;gt;/text_objects'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;basic_text_objects&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  To The Next Text-Object
&lt;/h3&gt;

&lt;p&gt;Right now, we need our cursor between the two characters to act on our new text-objects. It would also be nice to be able to operate on the first pair of these characters when our cursor is &lt;em&gt;before&lt;/em&gt; them. As we saw above in this article, it's already what we can do with parenthesis or quotes.&lt;/p&gt;

&lt;p&gt;Let's consider the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;She felt, suddenly, deeply in love with Vim.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could try to end up on the first comma of the pair whether the cursor is before them or between them. From there, we would select everything till the second comma. Here's a possible mapping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;onoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;u&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; normal&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="k"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;F&lt;span class="p"&gt;,&lt;/span&gt;lvt&lt;span class="p"&gt;,&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's imagine that the cursor is on the first &lt;code&gt;d&lt;/code&gt; of &lt;code&gt;suddenly&lt;/code&gt;, between the commas.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;f,&lt;/code&gt; - Move to the second comma.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;F,&lt;/code&gt; - Move to the first comma.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;l&lt;/code&gt; - Move one character to the right (on the space after the comma).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vt,&lt;/code&gt; - Visually select everything till the next comma.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, let's imagine that our cursor is on the &lt;code&gt;S&lt;/code&gt; of &lt;code&gt;She&lt;/code&gt;, before the commas.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;f,&lt;/code&gt; - Move to the first comma.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;F,&lt;/code&gt; - There is no comma before the cursor to be found, so the Ex-command &lt;code&gt;normal!&lt;/code&gt; fails.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;l&lt;/code&gt; - Move one character to the right (on the space after the comma).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vt,&lt;/code&gt; - Visually select everything till the next comma&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that the Ex-command &lt;code&gt;normal!&lt;/code&gt; fails at the second step. By default, it would stop there, not executing the steps 3 and 4. That's why we add the Ex-command &lt;code&gt;:silent!&lt;/code&gt; here; it will force &lt;code&gt;normal!&lt;/code&gt; to execute till the end.&lt;/p&gt;

&lt;p&gt;For the "around" text-object, we can follow the same principles. The only difference: we also select the two commas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;onoremap &lt;span class="k"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;u&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; normal&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="k"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;F&lt;span class="p"&gt;,&lt;/span&gt;vf&lt;span class="p"&gt;,&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the final result, in Lua:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;basic_text_objects&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'_'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;':'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;';'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'|'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'+'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'%'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'`'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'?'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;ipairs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;ipairs&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'o'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
            &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_set_keymap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"i"&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;string.format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;':&amp;lt;C-u&amp;gt;silent! normal! f%sF%slvt%s&amp;lt;CR&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;noremap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;silent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_set_keymap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"a"&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;string.format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;':&amp;lt;C-u&amp;gt;silent! normal! f%sF%svf%s&amp;lt;CR&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;noremap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;silent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind that it's a naive approach. First, making the &lt;code&gt;normal!&lt;/code&gt; command fails feels a bit like a hack. Additionally, it's quite difficult to understand. That said, sometimes a hack is good enough to answer our needs and move forward. I wouldn't use that in a plugin which could be used by others, but for my own use it's good enough.&lt;/p&gt;

&lt;p&gt;Each time we've created our text-objects, we first stated the problem, and then tried to find a way toward a solution. That's a good iterative approach, but it also means that our text-objects might not cover all the possible scenario. We can still improve things afterward, if we see that our text-objects don't behave as expected in specific situations.&lt;/p&gt;

&lt;p&gt;This is different from installing a plugin: you often have no idea how it works, and you can't modify them iteratively to answer your specific needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Text-Objects Based On Indentations
&lt;/h2&gt;

&lt;p&gt;Let's create one more text-object, more complex this time. It can be useful for any developer.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Basics
&lt;/h3&gt;

&lt;p&gt;If you look at the text-objects already available in vanilla Vim, their boundaries are based on specific characters. There are other important elements you'll find in most codebases which can be used for a text-object: indentations.&lt;/p&gt;

&lt;p&gt;Here's how to select our new text-objects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the starting indentation of the current line. This will be the indentation of reference we'll compare every other line to.&lt;/li&gt;
&lt;li&gt;Move up line by line, as long as the indentation is equal or higher to the starting indentation.&lt;/li&gt;
&lt;li&gt;Stop when the next line doesn't fulfill the rule 2 anymore, and begin VISUAL mode line-wise.&lt;/li&gt;
&lt;li&gt;Move down till the indentation is equal or higher to the starting indentation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It means that our text-objects include all the lines having the same indentation as the one you start with, or higher. Since the behavior is more complex than other text-objects we've created, let's implement a function we'll call in our mappings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; IndentTextObject&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; startindent &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="c"&gt;" Move up till we are at the top of the buffer&lt;/span&gt;
  &lt;span class="c"&gt;" or till the indentation is less than the starting one&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; prevline &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; prevline &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="nb"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;prevline&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; startindent
    &lt;span class="p"&gt;-&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; prevline &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;endwhile&lt;/span&gt;

  &lt;span class="c"&gt;" Begin linewise-visual selection&lt;/span&gt;
  normal&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;V

  &lt;span class="c"&gt;" Move down till we are at the bottom of the buffer&lt;/span&gt;
  &lt;span class="c"&gt;" or till the indentation is less than the starting one&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; nextline &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; lastline &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'$'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; nextline &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; lastline &amp;amp;&amp;amp; &lt;span class="nb"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;nextline&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; startindent
    &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; nextline &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;endwhile&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;

onoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;ai&lt;/span&gt; &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;U&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt; IndentTextObject&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
onoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;ii &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;U&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt; IndentTextObject&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
xnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;ai&lt;/span&gt; &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;U&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt; IndentTextObject&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
xnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;ii &lt;span class="p"&gt;:&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;U&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt; IndentTextObject&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, I always prefer using Lua when things get slightly complex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;select_indent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;prev_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;prev_line&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev_line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;prev_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'normal! 0V'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;next_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;last_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'$'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;next_line&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;last_line&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'+'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;next_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;indent_text_objects&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;ipairs&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'o'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_set_keymap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'ii'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;':&amp;lt;c-u&amp;gt;lua select_indent()&amp;lt;cr&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;noremap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;silent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_set_keymap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'ai'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;':&amp;lt;c-u&amp;gt;lua select_indent()&amp;lt;cr&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;noremap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;silent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;indent_text_objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;indent_text_objects&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The core of the functions are the two &lt;code&gt;while&lt;/code&gt; loops. They will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Move the cursor up till the previous line has less indentation than the starting one.&lt;/li&gt;
&lt;li&gt;Begin VISUAL mode line-wise (with &lt;code&gt;normal! 0V&lt;/code&gt;) and go down line by line, selecting the ones at the same level of indentation or higher.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that we use the Ex-command &lt;code&gt;-&lt;/code&gt; and &lt;code&gt;+&lt;/code&gt; to move up and down. Yes, they're Ex-command: try &lt;code&gt;:+&lt;/code&gt; for example. You could also use &lt;code&gt;normal! k&lt;/code&gt; or &lt;code&gt;normal! &amp;lt;up&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improving the Implementation
&lt;/h3&gt;

&lt;p&gt;Our little function works great, but it shows quickly its limits. Perhaps the most obvious: the "inside" and "around" text-objects have the exact same behavior. Horror and damnation!&lt;/p&gt;

&lt;p&gt;Let's say that the "around" the text-object should select two more lines, the first lines having fewer indentations when we move up and down.&lt;/p&gt;

&lt;p&gt;To illustrate, consider the following code. The symbol "┃" represents the cursor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Comment&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;super_function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="err"&gt;┃&lt;/span&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
       &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'youpi'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'wuhu'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="c1"&gt;-- Comment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hitting &lt;code&gt;dii&lt;/code&gt; would delete the whole &lt;code&gt;if&lt;/code&gt; block but let everything else untouched. Hitting &lt;code&gt;dai&lt;/code&gt; would delete everything, except the two comments.&lt;/p&gt;

&lt;p&gt;From there, we have two solutions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create two different functions: one for the "around" text-object, one for the "inside".&lt;/li&gt;
&lt;li&gt;Pass a boolean flag to use the "around" or "inside" text-object in the same function.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If we go with the first solution, we would have almost identical functions; it's likely we would need to change both each time we want to improve our text-objects. So let's go with the second solution. That said, if there are too many conditionals creeping in because there are more and more differences between the two text-objects, I would definitely split the function.&lt;/p&gt;

&lt;p&gt;Here's a possible implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;select_indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;around&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;prev_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;prev_line&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev_line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;prev_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;around&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'normal! 0V'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;next_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;last_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'$'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;next_line&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;last_line&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'+'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;next_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;around&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'+'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;indent_text_objects&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;ipairs&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'o'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_set_keymap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'ii'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;':&amp;lt;c-u&amp;gt;lua select_indent()&amp;lt;cr&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;noremap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;silent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_set_keymap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'ai'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;':&amp;lt;c-u&amp;gt;lua select_indent(true)&amp;lt;cr&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;noremap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;silent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;indent_text_objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;indent_text_objects&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we could ignore the blank lines. Right now, we don't really care about them; but they will inevitably stop our moves up and down because their level of indentation will always be less than the starting one. That is, if your cursor wasn't on a line without indentation from the start, in which case you would select the entire buffer.&lt;/p&gt;

&lt;p&gt;We can define a blank line as a line only containing white space (spaces, tabs, and newlines). To find out if the previous or next line is indeed blank, we could use a regex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;blank_line_pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'^%s*$'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Regexes in Lua are a bit odd: where you would have &lt;code&gt;\s&lt;/code&gt; for representing white spaces in many other regex engines, you have &lt;code&gt;%s&lt;/code&gt; in Lua.&lt;/p&gt;

&lt;p&gt;We now need to verify at each iteration if the next line is blank. We could create a small function for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;prev_blank_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;string.match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;blank_line_pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to modify the conditions for our two while loops. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;prev_line&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev_blank_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev_line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev_line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A last detail which might suits you. When your cursor is on a blank line while summoning your text-object with your agile fingers, you could ignore the keystroke. If you find the idea appealing, you could add the following before the first while loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;string.match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;blank_line_pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've now patched the most obvious defects of our text-object. But we can do better! What about being able to give a count to select lower levels of indentation?&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;dai&lt;/code&gt; would work as it does now, but &lt;code&gt;d2ai&lt;/code&gt; would select a lower level of indentation, and &lt;code&gt;d3ai&lt;/code&gt; would select even more.&lt;/p&gt;

&lt;p&gt;To do so, we simply need to increase our starting indentation depending on the count given. Right now, we only know what's the level of indentation of the current line with our variable &lt;code&gt;start_indent&lt;/code&gt;, but we don't know the &lt;em&gt;amount&lt;/em&gt; of indentations for each level.&lt;/p&gt;

&lt;p&gt;To get this information, we can look at the value of the option &lt;code&gt;shiftwidth&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's the implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shiftwidth&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might wonder about the calculation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shiftwidth&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, &lt;code&gt;vim.v.count&lt;/code&gt; is the count given to the text-object. In Vimscript, it would be &lt;code&gt;v:count&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Regarding the calculation itself, we need to multiply the count given by the amount of indentations per level (the &lt;code&gt;shiftwidth&lt;/code&gt; option), and subtract it to the indentations of the current line. It gives us the amount of indentations one level above.&lt;/p&gt;

&lt;p&gt;We decide that a count of &lt;code&gt;1&lt;/code&gt; shouldn't change anything (&lt;code&gt;dai&lt;/code&gt; is the same as &lt;code&gt;d1ai&lt;/code&gt;), that's why we subtract &lt;code&gt;1&lt;/code&gt; from the count. We also verify if our starting indentation is lower than 0, which could happen if we enter a count on a line without any indentation. In that case, We force the starting indentation to 0.&lt;/p&gt;

&lt;p&gt;Here's the final function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;select_indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;around&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;blank_line_pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'^%s*$'&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;string.match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;blank_line_pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shiftwidth&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;start_indent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;prev_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;prev_blank_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;string.match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;blank_line_pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;prev_line&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev_blank_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev_line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev_line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;prev_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;around&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'normal! 0V'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;next_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;next_blank_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;string.match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;blank_line_pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;last_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'$'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;next_line&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;last_line&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_blank_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;start_indent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'+'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;next_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;around&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'+'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! We've created a wonderful text-object with the power of our linked spirits. It's with joy and proud that I dub you Godly Blacksmith of the Text-Object©.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mapping a Lua Function
&lt;/h2&gt;

&lt;p&gt;Till now, we've used some Vimscript strings to map our Lua functions to our new text-objects. Neovim 0.7, which came out a couple of days before this article was published, allows us to directly map Lua functions without using any Vimscript.&lt;/p&gt;

&lt;p&gt;You can try to look at &lt;code&gt;:help vim.keymap.set&lt;/code&gt; for example to improve our code even further.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Power of the Text-Object
&lt;/h2&gt;

&lt;p&gt;As always, coming up with new ideas of text-objects depend on your needs. I always prefer solving the pain points I notice when writing in Vim, instead of trying to come up with ideas of improvements out of nothing. For example, I always wanted to have a text-object to manipulate functions; at the same time, I wanted something which could work with most programming languages. Having a text-object based on indentation levels is the best compromise to me.&lt;/p&gt;

&lt;p&gt;So, what did we see in this article?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you hit an operator in NORMAL mode, you switch to OPERATOR-PENDING mode. From there, you can give a motion or a text-object to operate on what your want.&lt;/li&gt;
&lt;li&gt;A text-object is only a set of characters which can be acted upon, using operators.&lt;/li&gt;
&lt;li&gt;It's easy to build basic text-objects thanks to the operator-pending mappings, &lt;code&gt;omap&lt;/code&gt; and &lt;code&gt;onoremap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It's easier to write a function when you need more complex text-objects. You can then rely on the rich set of Vimscript functions to move your cursor and select what you want.&lt;/li&gt;
&lt;li&gt;Vimscript is a language with many weird design decisions. I prefer using Lua as soon as my data flow goes on multiple branches.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do you want more articles where we use Vimscript and Lua, to improve your customization power in Vim? Don't hesitate to give your thoughts, feedback, and improvements in the comment section. Like, share, and love.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vim.fandom.com/wiki/Indent_text_object" rel="noopener noreferrer"&gt;Vim wiki - Indent text-object&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vim.fandom.com/wiki/Creating_new_text_objects" rel="noopener noreferrer"&gt;Vim wiki - Creating new text-objects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vimways.org/2018/transactions-pending/" rel="noopener noreferrer"&gt;Transactions Pending&lt;/a&gt; - Dylan McClure&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/nanotee/nvim-lua-guide" rel="noopener noreferrer"&gt;Getting started using Lua in Neovim&lt;/a&gt; - Timothée Sterle&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learnxinyminutes.com/docs/lua/" rel="noopener noreferrer"&gt;Learn X in Y minutes - Lua&lt;/a&gt; - Tyler Neylon&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Learning to Play Vim: A Fun Guide to Learn the Best Editor
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://themouseless.dev/vim" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthemouseless.dev%2Fimages%2Fvim%2Fbook_cover_900.webp" alt="Learning to Play Vim"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I began to write a very ambitious guide to learn Vim from the ground up. Thanks to great feedback from my readers, I'll be able to address the problems many beginners complain about when learning Vim. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to navigate in multiple files and projects in Vim?&lt;/li&gt;
&lt;li&gt;How to debug in Vim?&lt;/li&gt;
&lt;li&gt;How to search, find, and replace?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide will explain the most useful vanilla functionalities as well as some powerful plugins which will enrich your experience.&lt;/p&gt;

&lt;p&gt;Help me make an impact in the Vim world! You can subscribe to the newsletter and tell me everything you want to see in the book. Early bird discount guarantees!&lt;/p&gt;

&lt;p&gt;I reply to every email personally, so don't hesitate to ask as many questions as you want. It's always a pleasure to help.&lt;/p&gt;

&lt;p&gt;Last but not least: I've also written a book about building your own Mouseless Development Environment, so if you're interested by that too, &lt;a href="https://themouseless.dev" rel="noopener noreferrer"&gt;click on this shiny link&lt;/a&gt;.&lt;/p&gt;




</description>
      <category>vim</category>
      <category>terminal</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A Guide to the Zsh Line Editor with Examples</title>
      <dc:creator>Matthieu Cneude</dc:creator>
      <pubDate>Sun, 22 May 2022 13:04:35 +0000</pubDate>
      <link>https://forem.com/phantas0s/a-guide-to-the-zsh-line-editor-with-examples-5595</link>
      <guid>https://forem.com/phantas0s/a-guide-to-the-zsh-line-editor-with-examples-5595</guid>
      <description>&lt;p&gt;Like every morning, you switch on your computer, launch your terminal, and begin to type weakly the first commands of the day. With a sigh of despair, you launch the 12938 docker containers of your 29374 coupled microservices with a simple &lt;code&gt;docker compose up&lt;/code&gt;. Your misery accentuating your tiredness, you mistype the command three times, going back and forth between the NORMAL and INSERT Vi mode of your Zsh instance.&lt;/p&gt;

&lt;p&gt;Did you ever ask yourself how the Zsh editor was able to give you an Emacs or a Vi mode? Have you ever wonder how to customize the editor to ease your tedious work? Well, me neither, for a long time. But we'll fix that together: in this article, we'll explore the capabilities of the Zsh Line Editor (ZLE), and how to customize it to increase our efficiency.&lt;/p&gt;

&lt;p&gt;More precisely, we'll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's ZLE and its keymaps.&lt;/li&gt;
&lt;li&gt;How to bind any keystroke to any Zsh widget.&lt;/li&gt;
&lt;li&gt;A glimpse of the TTY subsystem and why binding special keys can be such a challenge.&lt;/li&gt;
&lt;li&gt;Some interesting Zsh built-in widgets.&lt;/li&gt;
&lt;li&gt;How to create your own widgets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I encourage you to fire Zsh while reading this article, and try the different commands we'll discuss. It's time: are you ready to uncover the veil of mystery surrounding the Zsh Line Editor?&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the Zsh Line Editor?
&lt;/h2&gt;

&lt;p&gt;The Zsh Line Editor (ZLE) is simply your command prompt. It's your interface to the shell interpreter, allowing you to write and edit your mind-blowing commands.&lt;/p&gt;

&lt;p&gt;It also allows you to use keystrokes to execute ZLE commands, more commonly called &lt;em&gt;widgets&lt;/em&gt;. That's great, because the term "command" is so overloaded that it doesn't mean anything anymore. Like "scalable", and of course "&lt;a href="https://www.reddit.com/r/AskScienceFiction/comments/3wgrj8/futurama_in_what_circumstances_does_bender_say/"&gt;daffodil&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;We've already seen some of the ZLE built-in widgets in the &lt;a href="https://thevaluable.dev/zsh-install-configure-mouseless/"&gt;first part of this series of article&lt;/a&gt;, like &lt;code&gt;vi-backward&lt;/code&gt; for example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zsh Keymaps
&lt;/h2&gt;

&lt;p&gt;To understand how ZLE works, we first need to understand the concept of keymap.&lt;/p&gt;

&lt;p&gt;A keymap is a set of keystrokes executing ZLE widgets. For each keymap, the mapping of keystrokes to widgets can be completely different.&lt;/p&gt;

&lt;p&gt;Here are the most interesting keymaps available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;emacs&lt;/code&gt; - Emacs emulation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;viins&lt;/code&gt; - Vi mode - INSERT mode&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vicmd&lt;/code&gt; - Vi mode - NORMAL mode (also confusingly called COMMAND mode)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;viopp&lt;/code&gt; - Vi mode - OPERATOR-PENDING mode&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;visual&lt;/code&gt; - Vi mode - VISUAL mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, the ZLE widget &lt;code&gt;vi-join&lt;/code&gt; (to join the current line with the next one) is bound to the keystroke &lt;code&gt;CTRL+x CTRL+j&lt;/code&gt; in the &lt;code&gt;emacs&lt;/code&gt; keymap, and to &lt;code&gt;J&lt;/code&gt; in the &lt;code&gt;vicmd&lt;/code&gt; keymap.&lt;/p&gt;

&lt;p&gt;When we use  our prompt, we use the &lt;em&gt;global keymap&lt;/em&gt;. This is the current keymap loaded, for us to use its delightful keystrokes. This global keymap is often aliased to the &lt;em&gt;main keymap&lt;/em&gt;, which is the keymap Zsh load by default when it launches. If you didn't specify any main keymap in your configuration, it will use the &lt;code&gt;emacs&lt;/code&gt; one.&lt;/p&gt;

&lt;p&gt;As a Vim Missionary, I would qualify this choice as "unforgivable heresy". Fortunately, We can alias this main keymap to &lt;code&gt;viins&lt;/code&gt; (Vi INSERT mode) instead. We'll see how below.&lt;/p&gt;

&lt;p&gt;Some other keymaps are sometimes used in specific Zsh modes. In that case, they are called &lt;em&gt;local keymaps&lt;/em&gt;. For example, we've seen &lt;a href="https://thevaluable.dev/zsh-install-configure-mouseless/"&gt;in the first article&lt;/a&gt; of this series how to bind keystrokes to the local keymap &lt;code&gt;menuselect&lt;/code&gt;. It's only available when selecting something in a list, like selecting a completion for example.&lt;/p&gt;

&lt;p&gt;If we define the same keystroke both in a local and in a global keymap, the first overwrite the second.&lt;/p&gt;

&lt;h2&gt;
  
  
  Binding Keystrokes to Zsh Widgets: the bindkey Command
&lt;/h2&gt;

&lt;p&gt;That's nice to have many keymaps to choose from, but it's not enough. How do we bind custom keystrokes to these Zsh widgets?&lt;/p&gt;

&lt;h3&gt;
  
  
  Managing the Bindings
&lt;/h3&gt;

&lt;p&gt;To manage our custom keystrokes, we need to use the &lt;code&gt;bindkey&lt;/code&gt; command. First, let's see how we can display what was already bound by using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bindkey&lt;/code&gt; - Output all the key bindings for the global keymap.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bindkey &amp;lt;keystroke&amp;gt;&lt;/code&gt; - Output the widgets bound to a specific keystroke &lt;code&gt;&amp;lt;keystroke&amp;gt;&lt;/code&gt; in the global keymap. For example: &lt;code&gt;bindkey '^l'&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bindkey -r &amp;lt;keystroke&amp;gt;&lt;/code&gt; - Delete the binding mapped to the keystroke &lt;code&gt;&amp;lt;keystroke&amp;gt;&lt;/code&gt;. For example: &lt;code&gt;bindkey -r '^l'&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you find that your keystroke is bound to the widget &lt;code&gt;undefined-key&lt;/code&gt;, it means that it won't have any effect. This widget is the incarnation of pure void. When you gaze long into the &lt;code&gt;undefined-key&lt;/code&gt;, the &lt;code&gt;undefined-key&lt;/code&gt; also gazes into you.&lt;/p&gt;

&lt;p&gt;The two keys &lt;code&gt;CTRL&lt;/code&gt; and &lt;code&gt;ALT&lt;/code&gt; are often used for keystrokes; therefore, it's useful to know how to tell Zsh to use one or the other in our key binding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;^&lt;/code&gt; - Represent the &lt;code&gt;CTRL&lt;/code&gt; key. For example: &lt;code&gt;^c&lt;/code&gt; for &lt;code&gt;CTRL+c&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\e&lt;/code&gt; - Represent the &lt;code&gt;ALT&lt;/code&gt; key. For example: &lt;code&gt;\ec&lt;/code&gt; for &lt;code&gt;ALT+c&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that it's true for most modern terminals out there, but not all. We'll come back to the joys of the escape characters soon.&lt;/p&gt;

&lt;p&gt;One of the most common use of &lt;code&gt;bindkey&lt;/code&gt; is, of course, to bind some custom keystrokes to some widget. To do so, you can follow this syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bindkey &amp;lt;keystroke&amp;gt; &amp;lt;widget&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, if we want to clear the screen with &lt;code&gt;CTRL+g&lt;/code&gt;, we would need to bind the widget &lt;code&gt;clear-screen&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bindkey &lt;span class="s1"&gt;'^g'&lt;/span&gt; clear-screen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We don't have to bind keystrokes to widgets, however. We can bind them to whole series of keystrokes, as we were typing them in ZLE. To do so, we can use the bindkey's option &lt;code&gt;-s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, if we want to bind &lt;code&gt;ALT+h&lt;/code&gt; to the series of keystrokes &lt;code&gt;CTRL+L&lt;/code&gt; (which clear the screen by default) and then writes "hello" because we're excessively polite, we can run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bindkey &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;'\eh'&lt;/span&gt; &lt;span class="s1"&gt;'^l hello'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How lovely!&lt;/p&gt;

&lt;h3&gt;
  
  
  Using bindkey with Specific Keymaps
&lt;/h3&gt;

&lt;p&gt;What if you want to manage the bindings for precise keymaps? Here's a bunch of commands to do so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bindkey -l&lt;/code&gt; - Output the &lt;code&gt;l&lt;/code&gt;ist of all available keymaps.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bindkey -M &amp;lt;keymap&amp;gt;&lt;/code&gt; - Output all the keybindings for the keymap &lt;code&gt;&amp;lt;keymap&amp;gt;&lt;/code&gt;. For example: &lt;code&gt;bindkey -M viins&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bindkey -M &amp;lt;keymap&amp;gt; &amp;lt;keystroke&amp;gt;&lt;/code&gt; - Output the widget bound to the keystroke &lt;code&gt;&amp;lt;keystroke&amp;gt;&lt;/code&gt; for the keymap &lt;code&gt;&amp;lt;keymap&amp;gt;&lt;/code&gt;. For example: &lt;code&gt;bindkey -M vicmd u&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bindkey -M &amp;lt;keymap&amp;gt; -r &amp;lt;keystroke&amp;gt;&lt;/code&gt; - Delete the binding mapped to the keystroke &lt;code&gt;&amp;lt;keystroke&amp;gt;&lt;/code&gt; for the keymap &lt;code&gt;&amp;lt;keymap&amp;gt;&lt;/code&gt;. For example: &lt;code&gt;bindkey -M vicmd -r '^l'&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What about aliasing the main keymap, for Zsh to launch with the one you want to use by default? Here are two handy commands you can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bindkey -e&lt;/code&gt; - Alias the main keymap to the &lt;code&gt;emacs&lt;/code&gt; keymap (the default).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bindkey -v&lt;/code&gt; - Alias the main keymap to the &lt;code&gt;viins&lt;/code&gt; keymap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These commands are aliases; they are respectively equivalent to the following commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bindkey -A emacs main&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bindkey -A viins main&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that you can't bind the main keymap to the &lt;code&gt;vicmd&lt;/code&gt; keymap, the equivalent of  Vi NORMAL mode.&lt;/p&gt;

&lt;p&gt;You can also uses &lt;code&gt;bindkey -lL main&lt;/code&gt; to find out what keymap is aliased to the main one.&lt;/p&gt;

&lt;p&gt;Fun fact: the &lt;code&gt;viins&lt;/code&gt; keymap (Vi INSERT mode) has the keystroke &lt;code&gt;ESC&lt;/code&gt; bound to the widget &lt;code&gt;vi-cmd-mode&lt;/code&gt;. In this context, when you hit &lt;code&gt;ESC&lt;/code&gt;, you'll switch the global keymap from &lt;code&gt;viins&lt;/code&gt; to &lt;code&gt;vicmd&lt;/code&gt; (Vi NORMAL mode). That's how you get the Zsh Vi mode.&lt;/p&gt;

&lt;p&gt;Even funnier fact: the &lt;code&gt;emacs&lt;/code&gt; keymap has also the keystroke &lt;code&gt;CTRL+x CTRL+v&lt;/code&gt; (&lt;code&gt;^X^V&lt;/code&gt;) bound to &lt;code&gt;vi-cmd-mode&lt;/code&gt;. You can switch to Vi NORMAL mode from the &lt;code&gt;emacs&lt;/code&gt; keymap! It finally proves, without any doubt, the superiority of Vi (and, by extension, Vim and Neovim) against Emacs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Binding All The Keys!
&lt;/h2&gt;

&lt;p&gt;We've seen quickly how to represent the special key &lt;code&gt;CTRL&lt;/code&gt; or &lt;code&gt;ALT&lt;/code&gt; to use them in our keystrokes. But what about the others?&lt;/p&gt;

&lt;h3&gt;
  
  
  Terminal and Escape Sequence
&lt;/h3&gt;

&lt;p&gt;If you use the &lt;code&gt;emacs&lt;/code&gt; keymap, you'll have most special keys bound to some sensible widgets, like the &lt;code&gt;HOME&lt;/code&gt; key bound to &lt;code&gt;beginning-of-line&lt;/code&gt;, or the &lt;code&gt;END&lt;/code&gt; key bound to &lt;code&gt;end-of-line&lt;/code&gt;. But, if you're a Vim Believer like I am, you'll reject this keymap with all the strength of your soul.&lt;/p&gt;

&lt;p&gt;A question arise, then: how to bound these special keys to these widgets for the &lt;code&gt;viins&lt;/code&gt; keymap? Or to other widgets, if we want to? How to represent these special keys for ZLE to know what we want to do?&lt;/p&gt;

&lt;p&gt;It's where we enter the muddy swamp of the TTY subsystem. I don't want to drown us into too many details, so I'll try to keep it brief. You can always play with my sanity by asking me to write an article about that in the comment section, at the end of this article.&lt;/p&gt;

&lt;p&gt;When you type some special keys, like &lt;code&gt;BACKSPACE&lt;/code&gt;, &lt;code&gt;HOME&lt;/code&gt;, or &lt;code&gt;ENTER&lt;/code&gt; for example, the terminal receives a &lt;a href="https://en.wikipedia.org/wiki/ANSI_escape_code"&gt;control character (or escape sequence)&lt;/a&gt;. This is how the terminal "see" the key you've harshly hit.&lt;/p&gt;

&lt;p&gt;The good news: most modern terminal emulators out there will translate your keystrokes with the same control characters (or escape sequence), which mean that we could directly bind these representations to the widgets we want.&lt;/p&gt;

&lt;p&gt;In practice, for you to display these sequences and use them in your bindings, you can use &lt;code&gt;CTRL+v&lt;/code&gt; in your terminal followed by the special key you want to bind. It will output verbatim the control character sent, without interpreting it.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When I hit &lt;code&gt;CTRL+v&lt;/code&gt; in my terminal followed by the &lt;code&gt;HOME&lt;/code&gt; key, I get the delightful escape sequence &lt;code&gt;^[[7~&lt;/code&gt; (I would love to have that on a T-shirt, by the way).&lt;/li&gt;
&lt;li&gt;I then bind it to the widget &lt;code&gt;beginning-of-line&lt;/code&gt; for the keymap &lt;code&gt;viins&lt;/code&gt; as follows: &lt;code&gt;bindkey -M viins '^[[7~' beginning-of-line&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, when I hit the &lt;code&gt;HOME&lt;/code&gt; key in Zsh while using the &lt;code&gt;viins&lt;/code&gt; keymap, my cursor moves at the beginning of the line. Incredible feat the world will remember!&lt;/p&gt;

&lt;p&gt;If you want to display multiple escape sequences without having to hit &lt;code&gt;CTRL+v&lt;/code&gt; again and again, you can also run &lt;code&gt;cat &amp;gt; /dev/null&lt;/code&gt; and hit whatever keystrokes you like.&lt;/p&gt;

&lt;p&gt;This approach has one major drawback. Even if it's true that most modern terminal emulators receive the same escape sequences, the world is not only made with modern terminal emulators. These sequences might differ for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your TTYs (what you open when you hit &lt;code&gt;CTRL+ALT+&amp;lt;FKEY&amp;gt;&lt;/code&gt; in Linux, &lt;code&gt;&amp;lt;FKEY&amp;gt;&lt;/code&gt; being the keys from &lt;code&gt;F1&lt;/code&gt; to &lt;code&gt;F12&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Your terminal multiplexer (like &lt;a href="https://thevaluable.dev/tmux-config-mouseless/"&gt;tmux&lt;/a&gt; or screen).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because of these differences, there is another approach praised by many out there (even advised by the venerable &lt;a href="https://wiki.archlinux.org/title/zsh#Key_bindings"&gt;Arch Linux Wiki&lt;/a&gt;): using terminfo.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Common Terminal Interface
&lt;/h3&gt;

&lt;p&gt;This "terminfo" is a common database aimed to provide an unified interface between the different terminals available. It's often used by CLIs to intercept the different escape sequences and perform some action. For example, Vi uses terminfo under the hood.&lt;/p&gt;

&lt;p&gt;There is a problem with this approach, however: to use terminfo, we need to switch ZLE to "application mode", only used normally by some CLIs and TUIs running in the shell (but not all). Since the command line editor of ZSH does not run in application mode by default, we need to switch to it before using terminfo.&lt;/p&gt;

&lt;p&gt;It means that any CLI running in the terminal will run in this application mode too. If some of these CLIs are not meant to run in this mode, some keystrokes might not work.&lt;/p&gt;

&lt;p&gt;Because it feels more like a hack than a proper solution, I personally try to avoid this method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automatically Mapping Escape Sequences with zkbd
&lt;/h3&gt;

&lt;p&gt;We can also use "zkbd" from Zsh contrib. You can do so by following this workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Autoload zkbd by adding &lt;code&gt;autoload -Uz zkbd&lt;/code&gt; to your &lt;code&gt;zshrc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Start a new Zsh process and run &lt;code&gt;zkbd&lt;/code&gt; in your shell.&lt;/li&gt;
&lt;li&gt;Answer the questions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After answering all questions, &lt;code&gt;zkbd&lt;/code&gt; will create a bunch of files with all the escape sequences bound to the good widgets. I never really used &lt;code&gt;zkbd&lt;/code&gt; to be honest, but it might help to get you started.&lt;/p&gt;

&lt;h3&gt;
  
  
  Personal Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/Phantas0s/.dotfiles/blob/master/zsh/bindings.zsh"&gt;I've written a piece of configuration&lt;/a&gt; showing both solutions proposed above (the one involving terminfo is commented out because I don't use it). You can try it, I'm pretty sure it will work quite well if you don't use some exotic terminal.&lt;/p&gt;

&lt;p&gt;A last advice: if you use &lt;a href="https://thevaluable.dev/tmux-config-mouseless/"&gt;tmux&lt;/a&gt;, make sure that you have the line &lt;code&gt;set -g default-terminal "tmux-256color"&lt;/code&gt; in your tmux configuration file for this config to work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Zsh Widgets
&lt;/h2&gt;

&lt;p&gt;We've spoken a lot about keymaps and keybindings. What about the other side of the equation, the Zsh widgets themselves?&lt;/p&gt;

&lt;h3&gt;
  
  
  Built-in Widgets
&lt;/h3&gt;

&lt;p&gt;There are many built-in widgets you can bind with the keystrokes of your dreams. Here are the different ways to get a complete list of these widgets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You can run &lt;code&gt;zle -la&lt;/code&gt; in your shell.&lt;/li&gt;
&lt;li&gt;You can look at the manual page for ZLE by running &lt;code&gt;man zshzle&lt;/code&gt;. Search for "Standard Widgets".&lt;/li&gt;
&lt;li&gt;You can install the package &lt;code&gt;zsh-doc&lt;/code&gt; and use a command for each widget, to find out its powers. For example: &lt;code&gt;info zsh beginning-of-line&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You can &lt;a href="https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html#Standard-Widgets"&gt;look online&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But reading is cheap, trying is the way to enlightenment. How to try a widget directly, to see what it does?&lt;/p&gt;

&lt;p&gt;To call the widget &lt;code&gt;&amp;lt;widget&amp;gt;&lt;/code&gt;, we need to use the command &lt;code&gt;zle &amp;lt;widget&amp;gt;&lt;/code&gt;. You can try to run &lt;code&gt;zle end-of-line&lt;/code&gt; for example, to see that it doesn't work. How deceitful!&lt;/p&gt;

&lt;p&gt;You'll be indeed rewarded with a voluptuous &lt;code&gt;zle: widgets can only be called when ZLE is active&lt;/code&gt;. It means that widgets can be called only when you write and edit your commands in the editor, not when you send them to your TTY by hitting &lt;code&gt;ENTER&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As a result, we can call widgets inside widgets, because widgets are always called when ZLE is available. And since we can call widgets using specific keystrokes, what about a widget which can run any widget? That's exactly the purpose of &lt;code&gt;execute-named-cmd&lt;/code&gt;. It's bound by default to the keystrokes &lt;code&gt;ESC x&lt;/code&gt; for the &lt;code&gt;emacs&lt;/code&gt; keymap and &lt;code&gt;:&lt;/code&gt; for the &lt;code&gt;vicmd&lt;/code&gt; keymap (Vi NORMAL mode).&lt;/p&gt;

&lt;p&gt;If you hit the good keystrokes depending of the global keymap you're using, a new prompt will appear. There, you can call any widget you want; they will act on whatever command you've began to type in your editor, if any. Even better: you can complete the widget's name you want to run in this new prompt by using &lt;code&gt;TAB&lt;/code&gt;, as always.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;execute-named-cmd&lt;/code&gt;, you can then run two other useful widgets if you want to know what widget is bound to what keystroke (and vice-versa):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;where-is&lt;/code&gt; - Open yet another prompt where you can type the name of a widget. It will then output its keybinding (if any).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;describe-key-briefly&lt;/code&gt; - Open yet another prompt where you can hit a keystroke. It will then output the widget bound to that keystroke (if any).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Widgets from Zsh User Contributions
&lt;/h3&gt;

&lt;p&gt;There are also more widgets available via Zsh contrib (&lt;code&gt;man zshcontrib&lt;/code&gt;), like the wonderful &lt;code&gt;edit-command-line&lt;/code&gt;, allowing you to edit your commands in &lt;del&gt;Vim&lt;/del&gt; your favorite editor, or &lt;code&gt;select-quoted&lt;/code&gt;, useful to create Vi text-object representing quoted substring. More on that below.&lt;/p&gt;

&lt;p&gt;I've covered many of these widgets in the &lt;a href="https://thevaluable.dev/zsh-install-configure-mouseless/"&gt;first article of this series&lt;/a&gt;. Don't forget that you need to autoload them before using them. They are not always documented, but you can directly look at what you can use on the &lt;a href="https://github.com/zsh-users/zsh/tree/master/Functions/Zle"&gt;Zsh mirror repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, if you want to use the widget &lt;code&gt;incarg&lt;/code&gt; from Zsh contrib to increment a number using a keystroke, you can add to your &lt;code&gt;zshrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;autoload &lt;span class="nt"&gt;-Uz&lt;/span&gt; incarg
zle &lt;span class="nt"&gt;-N&lt;/span&gt; incarg
bindkey &lt;span class="nt"&gt;-M&lt;/span&gt; vicmd &lt;span class="s1"&gt;'^a'&lt;/span&gt; incarg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when your cursor is on a number and you hit &lt;code&gt;CTRL+a&lt;/code&gt;, it will be incremented by the power of your spirit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing your Own Widget
&lt;/h3&gt;

&lt;p&gt;Using built-in widgets is definitely useful, but we can push the customization even further: what about widgets designed by your talented creativity?&lt;/p&gt;

&lt;h4&gt;
  
  
  Executing A Command While Writing Another
&lt;/h4&gt;

&lt;p&gt;As we saw just above, we can create our own widget using &lt;code&gt;zle -N &amp;lt;shell_function&amp;gt;&lt;/code&gt;. If an existing widget has already the same name, it will be overwritten. That's why built-in widgets have two names: one with a dot &lt;code&gt;.&lt;/code&gt; prefix, and one without. If you overwrite the built-in widget &lt;code&gt;end-of-line&lt;/code&gt; for example, you can still access the original one by using &lt;code&gt;.end-of-line&lt;/code&gt;. As a result, it's considered good practice to never prefix your own widgets with a dot; it should be reserved to the most important widgets, the built-in ones.&lt;/p&gt;

&lt;p&gt;Enough rambling. Let's build our first widget!&lt;/p&gt;

&lt;p&gt;We can imagine that you're writing a command in your shell, and suddenly you wonder what you've modified in your project. The best would be to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;git diff&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Go back to the command you were writing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's the widget:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;_git-diff &lt;span class="o"&gt;{&lt;/span&gt;
    zle .kill-whole-line
    zle &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="s2"&gt;"git diff
&lt;/span&gt;&lt;span class="nv"&gt;$CUTBUFFER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

zle &lt;span class="nt"&gt;-N&lt;/span&gt; _git-diff
bindkey &lt;span class="s1"&gt;'^Xd'&lt;/span&gt; _git-diff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens in there?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We use &lt;code&gt;zle&lt;/code&gt; to run the widget &lt;code&gt;.kill-whole-line&lt;/code&gt; (we use the dot-prefixed name in case &lt;code&gt;kill-whole-line&lt;/code&gt; was overwritten somewhere else). It will remove the command you were crafting with enthusiasm and love.&lt;/li&gt;
&lt;li&gt;We run &lt;code&gt;zle -U&lt;/code&gt;. This command inserts some string in ZLE, exactly like you would type them in the editor.&lt;/li&gt;
&lt;li&gt;We declare the function &lt;code&gt;_git-diff&lt;/code&gt; as a widget. We can run it in ZLE by hitting &lt;code&gt;CTRL+x&lt;/code&gt; and then &lt;code&gt;d&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's worthwhile to explain further the second point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The character between &lt;code&gt;git diff&lt;/code&gt; and &lt;code&gt;$CUTBUFFER&lt;/code&gt; is actually a carriage return, the control character &lt;code&gt;^M&lt;/code&gt;. I've made it by hitting &lt;code&gt;CTRL+v&lt;/code&gt; and then &lt;code&gt;ENTER&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The variable &lt;code&gt;$CUTBUFFER&lt;/code&gt; contains whatever was deleted when using a widget beginning with &lt;code&gt;kill-&lt;/code&gt;. It allows us to bring back the command previously deleted with &lt;code&gt;.kill-whole-line&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The underscore &lt;code&gt;_&lt;/code&gt; prefixing the function's name indicates that the function is a widget. It's just a personal convention to know what shell function is a widget, and what isn't; you don't have to do the same with your widgets.&lt;/p&gt;

&lt;p&gt;And voila! We've our first marvelous and useless little widget.&lt;/p&gt;

&lt;p&gt;It's not the only implementation possible: we could try to run &lt;code&gt;git diff&lt;/code&gt; first, and then bring back the command deleted as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zle &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="s2"&gt;"git diff"&lt;/span&gt;
zle &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CUTBUFFER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm afraid I've to deceive you once again; at the point, it's a miracle you're sill reading this article. The commands above won't do what we want them to do.&lt;/p&gt;

&lt;p&gt;In fact, &lt;code&gt;zle -U&lt;/code&gt; put strings on the stack of ZLE, and pull them back in the editor &lt;em&gt;when the widget terminates&lt;/em&gt;. And since it's a stack (LIFO, Last In, First Out), &lt;code&gt;$CUTBUFFER&lt;/code&gt; would be inserted in the editor &lt;em&gt;before&lt;/em&gt; &lt;code&gt;git diff&lt;/code&gt;! To fix that, you could swap the two declarations above, but it makes the widget more difficult to understand.&lt;/p&gt;

&lt;p&gt;Here's another, cleaner solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;_git-diff &lt;span class="o"&gt;{&lt;/span&gt;
    zle push-input
    &lt;span class="nv"&gt;BUFFER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git diff"&lt;/span&gt;
    zle accept-line
&lt;span class="o"&gt;}&lt;/span&gt;

zle &lt;span class="nt"&gt;-N&lt;/span&gt; _git-diff
bindkey &lt;span class="s1"&gt;'^Xd'&lt;/span&gt; _git-diff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens there?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We use the widget &lt;code&gt;push-input&lt;/code&gt;. It pushes the command on the edit buffer stack, and pull it back the next time ZLE is available.&lt;/li&gt;
&lt;li&gt;We change the current buffer to &lt;code&gt;git diff&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We use the widget &lt;code&gt;accept-line&lt;/code&gt; which runs whatever command written in ZLE (in that case, &lt;code&gt;git diff&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The widget &lt;code&gt;push-input&lt;/code&gt; pull back the command from the buffer stack. It even keeps the cursor position!&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  A Widget to Prefix Your Commands
&lt;/h4&gt;

&lt;p&gt;Let's take another example. Let's say that you want a widget to prepend "vim" to any command. A noble idea! Here's a possible solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;_vim &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;$BUFFER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ &lt;span class="s1"&gt;'^vi.*'&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;BUFFER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"vim &lt;/span&gt;&lt;span class="nv"&gt;$BUFFER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; zle end-of-line
&lt;span class="o"&gt;}&lt;/span&gt;

zle &lt;span class="nt"&gt;-N&lt;/span&gt; _vim
bindkey &lt;span class="nt"&gt;-M&lt;/span&gt; vicmd &lt;span class="s1"&gt;'^Xv'&lt;/span&gt; _vim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the regular expression &lt;code&gt;^vi.*&lt;/code&gt; is not matched, it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inserts &lt;code&gt;vim&lt;/code&gt; at the beginning of the command.&lt;/li&gt;
&lt;li&gt;Moves the cursor to the end of the line.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Quite easy, isn't it?&lt;/p&gt;

&lt;h4&gt;
  
  
  Managing Surrounding
&lt;/h4&gt;

&lt;p&gt;I mentioned, &lt;a href="https://thevaluable.dev/zsh-install-configure-mouseless/"&gt;in the first article of this series&lt;/a&gt;, a way to create new Vi text-objects and bind them to some specific widgets with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;autoload &lt;span class="nt"&gt;-Uz&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="nt"&gt;-bracketed&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="nt"&gt;-quoted&lt;/span&gt;
zle &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="nt"&gt;-quoted&lt;/span&gt;
zle &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="nt"&gt;-bracketed&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;km &lt;span class="k"&gt;in &lt;/span&gt;viopp visual&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  for &lt;/span&gt;c &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;a,i&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(s..)^&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="s1"&gt;'\"\`\|,./:;=+@}; do
    bindkey -M $km -- $c select-quoted
  done
  for c in {a,i}${(s..)^:-'&lt;/span&gt;&lt;span class="p"&gt;()[]{&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;bB&lt;span class="s1"&gt;'}; do
    bindkey -M $km -- $c select-bracketed
  done
done
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're now able to understand what's going on in there:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We loop through the two keymaps &lt;code&gt;viopp&lt;/code&gt; (Vi OPERATOR-PENDING mode) and &lt;code&gt;visual&lt;/code&gt; (Vi VISUAL mode).&lt;/li&gt;
&lt;li&gt;We loop through a whole bunch of signs we want to consider as quotes (or brackets), and we add to each of them the prefix &lt;code&gt;i&lt;/code&gt; or &lt;code&gt;a&lt;/code&gt; (for &lt;code&gt;i&lt;/code&gt;nside and &lt;code&gt;a&lt;/code&gt;round, respectively).&lt;/li&gt;
&lt;li&gt;We use the &lt;code&gt;bindkey&lt;/code&gt; command to bind these new text-objects to both keymaps.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're not sure what's the Vi OPERATOR-PENDING mode, I've written about it in &lt;a href="https://thevaluable.dev/vim-expert/"&gt;this article about Vim&lt;/a&gt;. It's can be used to create new text-objects. Here are the ones we bind to the &lt;code&gt;select-bracketed&lt;/code&gt; widget: &lt;code&gt;a(&lt;/code&gt;,&lt;code&gt;i(&lt;/code&gt;,&lt;code&gt;a)&lt;/code&gt;,&lt;code&gt;i)&lt;/code&gt;,&lt;code&gt;a[&lt;/code&gt;,&lt;code&gt;i[&lt;/code&gt;,&lt;code&gt;a]&lt;/code&gt;,&lt;code&gt;i]&lt;/code&gt;,&lt;code&gt;a{&lt;/code&gt;,&lt;code&gt;i{&lt;/code&gt;,&lt;code&gt;a}&lt;/code&gt;,&lt;code&gt;i}&lt;/code&gt;,&lt;code&gt;a&amp;lt;&lt;/code&gt;,&lt;code&gt;i&amp;lt;&lt;/code&gt;,&lt;code&gt;a&amp;gt;&lt;/code&gt;,&lt;code&gt;i&amp;gt;&lt;/code&gt;,&lt;code&gt;ab&lt;/code&gt;,&lt;code&gt;ib&lt;/code&gt;,&lt;code&gt;aB&lt;/code&gt;,&lt;code&gt;iB&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want to know exactly what text-objects are created, you can add &lt;code&gt;echo $c&lt;/code&gt; in both nested loops before the command &lt;code&gt;bindkey&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Power of the Zsh Line Editor
&lt;/h2&gt;

&lt;p&gt;Well, that was quite a trip! Thanks to custom keybidings and widgets, the Zsh Line Editor is a valuable tool, allowing us to make our shell experience an effective one.&lt;/p&gt;

&lt;p&gt;What did we see in this article?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Zsh Line Editor (ZLE) is the command prompt where you can write and edit your commands.&lt;/li&gt;
&lt;li&gt;The main keymap is the set of keystrokes which is loaded by default when Zsh is launched.&lt;/li&gt;
&lt;li&gt;The global keymap is the one used to edit commands in Zsh. Local keymaps can be used in some specific Zsh modes, like selecting elements in a list.&lt;/li&gt;
&lt;li&gt;A widget is a shell function which can be executed after hitting specific keystrokes. They can call other widgets, and they have access to special variables to manipulate the line editor.&lt;/li&gt;
&lt;li&gt;We can look at the keystrokes already bound, and bind new ones to specific widgets with the &lt;code&gt;bindkey&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;The terminal will interpret special keys with specific escape sequences. We can map them directly to some widgets, or use terminfo in application mode.&lt;/li&gt;
&lt;li&gt;We can create our own widgets to customize even more what we can do in ZLE.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you're annoyed by some functionalities which should be implemented while typing your commands in Zsh, it's a good opportunity to write a widget to answer your need. That's how you create a &lt;a href="https://themouseless.dev"&gt;highly customized Mouseless Development Environment&lt;/a&gt;: by solving one little problem at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html"&gt;Zsh Line Editor&lt;/a&gt; - Zsh Documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html#Standard-Widgets"&gt;ZLE Standard Widgets&lt;/a&gt; - Zsh Documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://web.archive.org/web/20180704181216/http://zshwiki.org/home/zle/bindkeys"&gt;Zsh Keybindings&lt;/a&gt; - Zsh Wiki&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tldp.org/HOWTO/Text-Terminal-HOWTO-16.html"&gt;terminfo and termcap&lt;/a&gt; - David S. Lawyer&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html#User_002dDefined-Widgets"&gt;User defined widgets&lt;/a&gt; - Zsh Documentation&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Becoming Mouseless
&lt;/h2&gt;

&lt;p&gt;Do you want to build a &lt;a href="https://themouseless.dev"&gt;Mouseless Development Environment&lt;/a&gt; where the Linux shell has a central role?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://themouseless.dev"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gkZumQAJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://themouseless.dev/images/small_cover.webp" alt="building your mouseless development environment" width="300" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Switching between the keyboard and the mouse costs cognitive energy. This book will guide you step by step to set up a Linux-based development environment that keeps your hands on your keyboard.&lt;/p&gt;

&lt;p&gt;Take the brain power you've been using to juggle input devices and focus it where it belongs: on what you create.&lt;/p&gt;




</description>
      <category>zsh</category>
      <category>terminal</category>
      <category>productivity</category>
      <category>shell</category>
    </item>
    <item>
      <title>A Guide to Zsh Expansion with Examples</title>
      <dc:creator>Matthieu Cneude</dc:creator>
      <pubDate>Wed, 23 Mar 2022 16:58:29 +0000</pubDate>
      <link>https://forem.com/phantas0s/a-guide-to-zsh-expansion-with-examples-n5j</link>
      <guid>https://forem.com/phantas0s/a-guide-to-zsh-expansion-with-examples-n5j</guid>
      <description>&lt;p&gt;What would we do if we couldn't use the wonderful &lt;code&gt;TAB&lt;/code&gt; key to expand our commands, filenames, or variables in our lovely shell? Not much, I'm afraid. We would still live in dark caves, hunting some dangerous Mammoth with knives made of stones!&lt;/p&gt;

&lt;p&gt;Zsh is particularly powerful when you need some good old expansions. It supports common ones used by Bash too, and add many flags and modifiers on top. It comes in handy to manipulate quickly your commands without writing boring shell scripts.&lt;/p&gt;

&lt;p&gt;We'll see, in this article, what we can do with Zsh expansions, and more specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to use glob operators and globbing flags.&lt;/li&gt;
&lt;li&gt;What glob qualifiers we can use to expand filenames.&lt;/li&gt;
&lt;li&gt;How to expand the Zsh history and how to modify these expansions.&lt;/li&gt;
&lt;li&gt;How to expand parameters, using modifiers and flags.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the examples of this article,  the character &lt;code&gt;&amp;gt;&lt;/code&gt; represents the shell's prompt. If you want to run the commands in your terminal (which I warmly recommend you to do), don't copy these &lt;code&gt;&amp;gt;&lt;/code&gt; characters. Why not using the dollar character &lt;code&gt;$&lt;/code&gt; for the prompt, like every other articles out there? Because it's my article, I do what I want.&lt;/p&gt;

&lt;p&gt;There are many, many ways to expand your filenames, history entries, or parameters with Zsh. I won't cover everything here, only what I find the most useful. The amount of information can still be overwhelming, however; that's why I recommend the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Take two or three useful tips from this article and try to apply them in your daily work.&lt;/li&gt;
&lt;li&gt;When you're confident with your new knowledge, come back to this article and pick two or three more tips.&lt;/li&gt;
&lt;li&gt;Rinse and repeat.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Last bit of information before diving in: I used Zsh 5.8 and GNU Bash 5.1.8 for testing the different examples. With that out of the way, let's begin to expand our souls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Glob Operators
&lt;/h2&gt;

&lt;p&gt;We can't use regular expressions with Bash or Zsh to expand our filenames. Instead, we can use glob operators to expand various filenames.&lt;/p&gt;

&lt;p&gt;If you use the shell for long enough, I'm sure you're already familiar with some of them. Here's the list of glob operators for Zsh: &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;(&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;[&lt;/code&gt;, and &lt;code&gt;?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We'll see in this section how to use these glob operators. The examples given here follow this set of rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first line is the non-expanded version of the command.&lt;/li&gt;
&lt;li&gt;The second line is the expanded version of the command, after typing the non-expanded version and hitting the &lt;code&gt;TAB&lt;/code&gt; key.&lt;/li&gt;
&lt;li&gt;Each example uses the following directory structure:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── a_dir_with_a_file
│   └── a_file
├── A_FILE_WITH_UPPERCASE
├── another_file
├── empty_dir
├── file_1
└── file_2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I encourage you to create the exact same file tree with these commands and try the examples in your shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;a_dir_with_a_file empty_dir &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;touch &lt;/span&gt;a_dir_with_a_file/a_file A_FILE_WITH_UPPERCASE another_file file_1 file_2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trying by yourself will let you feel the power of Zsh under your fingertips. Nothing less!&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Glob Operators
&lt;/h3&gt;

&lt;p&gt;These two basic glob operators work in Bash and Zsh:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;*&lt;/code&gt; - Matches any string.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;?&lt;/code&gt; - Matches any character.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;fil&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;file_1 file_2

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;file_?
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;file_1 file_2

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; ./&lt;span class="k"&gt;*&lt;/span&gt;file&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; ./a_dir_with_a_file ./another_file ./file_1 ./file_2 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Character classes
&lt;/h3&gt;

&lt;p&gt;Beyond the useful &lt;code&gt;*&lt;/code&gt; and &lt;code&gt;?&lt;/code&gt;, we can also use character classes in both Bash and Zsh:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[]&lt;/code&gt; - Matches one of the enclosed character, or a range of characters separated with &lt;code&gt;-&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[:&amp;lt;set&amp;gt;:]&lt;/code&gt; - Matches a specific set of characters.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[^&amp;lt;set&amp;gt;]&lt;/code&gt; or &lt;code&gt;[!&amp;lt;set&amp;gt;]&lt;/code&gt; - Match any character which is &lt;em&gt;not&lt;/em&gt; in the set &lt;code&gt;&amp;lt;set&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Match every filename beginning with "f", "l", or "e"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;fle]&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;empty_dir file_1 file_2 

&lt;span class="c"&gt;# Match every filename not beginning with "a"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;^a]&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;A_FILE_WITH_UPPERCASE empty_dir file_1 file_2 

&lt;span class="c"&gt;# Match every filename beginning with "a"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;a]&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;a_dir_with_a_file another_file 

&lt;span class="c"&gt;# Match a filename beginning with any letter from "a" to "z"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;a-z]&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;a_dir_with_a_file another_file empty_dir file_1 file_2

&lt;span class="c"&gt;# Match a filename beginning with lowercase, followed by an underscore, and any other character&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;^[:upper:]]_&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;a_dir_with_a_file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Grouping
&lt;/h3&gt;

&lt;p&gt;Grouping is only available in Zsh. To group, we can use the following characters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;()&lt;/code&gt; - Matches the enclosed pattern.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;|&lt;/code&gt; - Equivalent of the boolean operator "OR". It needs to be used inside groups.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Match any filename beginning with "fi" or "an"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;|an&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;another_file file_1 file_2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Globbing Flags
&lt;/h3&gt;

&lt;p&gt;Globbing flags are only available in Zsh. They need to be added before any glob operator, and they need to have this syntax: &lt;code&gt;(#&amp;lt;flag&amp;gt;)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here are the three most useful flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;i - Case insensitive.&lt;/li&gt;
&lt;li&gt;I - Case sensitive.&lt;/li&gt;
&lt;li&gt;l - Lowercase match lower case or uppercase; uppercase match only uppercase.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;a&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;a_dir_with_a_file another_file

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="c"&gt;#i)a*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;a_dir_with_a_file A_FILE_WITH_UPPERCASE another_file

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="c"&gt;#l)a*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;a_dir_with_a_file A_FILE_WITH_UPPERCASE another_file 

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="c"&gt;#l)A*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;A_FILE_WITH_UPPERCASE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Recursive Globbing
&lt;/h3&gt;

&lt;p&gt;You can also use the recursive glob operator &lt;code&gt;**&lt;/code&gt; to expand the files in the working directory (like &lt;code&gt;*&lt;/code&gt;) &lt;em&gt;and&lt;/em&gt; every file in every subdirectory, recursively.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Search filenames including the substring "file" in the working directory and its subdirectories&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; ./&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;file&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; ./a_dir_with_a_file ./a_dir_with_a_file/a_file ./another_file ./file_1 ./file_2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The depth of the directory tree doesn't matter: Zsh will go through the whole tree and find whatever you want. You can also use the alternative glob operator &lt;code&gt;***&lt;/code&gt; if you also want to parse symlink's targets.&lt;/p&gt;

&lt;p&gt;The recursive glob operator can be used in Bash too, but it will only expand files on the first level below the working directory. If you want it to behave like its Zsh counterpart, you need to set the option &lt;code&gt;globstar&lt;/code&gt; with the following command &lt;code&gt;shopt -s globstar&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Glob Qualifiers
&lt;/h3&gt;

&lt;p&gt;Glob qualifiers are only available in Zsh. They are added after the glob operators to filter even further the filenames expanded. They are always between parenthesis.&lt;/p&gt;

&lt;p&gt;You can use multiple qualifiers inside the parenthesis, separated with a colon &lt;code&gt;:&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Basic Qualifiers
&lt;/h4&gt;

&lt;p&gt;Here are some basic qualifiers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;^&lt;/code&gt; - Negate all qualifiers following it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&lt;/code&gt; - The qualifier works on the target of the symbolic link (and not the symbolic link itself).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[&amp;lt;beginning&amp;gt;, &amp;lt;end&amp;gt;]&lt;/code&gt; - Choose what filenames should be expanded, depending on their positions. Can be negative to count from last match backward.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;a_dir_with_a_file A_FILE_WITH_UPPERCASE another_file empty_dir file_1 file_2 

&lt;span class="c"&gt;# Only expand the second and third file&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;([&lt;/span&gt;2,3]&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;A_FILE_WITH_UPPERCASE another_file 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Directory Expansion
&lt;/h4&gt;

&lt;p&gt;These qualifiers will only expand to directories, except if they're negated with &lt;code&gt;^&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;F&lt;/code&gt; - Expand to non-empty directories.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;^F&lt;/code&gt; - Expand to empty directories and non-directories (plain files).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/^F&lt;/code&gt; - Expand to empty directories.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Only expand non-empty directory&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;F&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;a_dir_with_a_file

&lt;span class="c"&gt;# Only expand plain files and empty directories&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;^F&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;A_FILE_WITH_UPPERCASE another_file empty_dir file_1 file_2 

&lt;span class="c"&gt;# Only expand empty directories&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;/^F&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;empty_dir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Expanding By Filetype
&lt;/h4&gt;

&lt;p&gt;We can also use qualifiers to expand specific file types (plain files or directory):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.&lt;/code&gt; - Expand to plain files&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/&lt;/code&gt; - Expand to directories
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Only expand plain files&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;.&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;A_FILE_WITH_UPPERCASE another_file file_1 file_2 

&lt;span class="c"&gt;# Only expand directories&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;/&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;a_dir_with_a_file empty_dir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Expansions Depending On the Permissions
&lt;/h4&gt;

&lt;p&gt;To only expand files with specific permissions, we can use the following qualifiers:&lt;/p&gt;

&lt;p&gt;Depending on the owner:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;*&lt;/code&gt; - Expand to executable plain files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;r&lt;/code&gt; - Expand to owner readable files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;w&lt;/code&gt; - Expand to owner writable files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;x&lt;/code&gt; - Expand to owner executable files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;U&lt;/code&gt; - Expand to files or directories owned by the current user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depending on the world:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;R&lt;/code&gt; - Expand to world readable files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;W&lt;/code&gt; - Expand to world writable files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X&lt;/code&gt; - Expand to world executable files&amp;gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depending on the group:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;A&lt;/code&gt; - Expand to group readable files&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I&lt;/code&gt; - Expand to group writable files&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;E&lt;/code&gt; - Expand to group executable files&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;G&lt;/code&gt; - File or directory owned by the current user's group.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For even more control, we can specify the precise permissions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;f&amp;lt;spec&amp;gt;&lt;/code&gt; - Expand the files with access right matching the octal number &lt;code&gt;&amp;lt;spec&amp;gt;&lt;/code&gt;. If &lt;code&gt;&amp;lt;spec&amp;gt;&lt;/code&gt; is preceded by:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;=&lt;/code&gt; (default when none given) - &lt;code&gt;&amp;lt;spec&amp;gt;&lt;/code&gt; must match the exact file-mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;+&lt;/code&gt; - At least one bit needs to be in the file-mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&lt;/code&gt; - The bits must not be set.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Set the permissions for "file_1" to 777 (world can read, write, execute)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;777 file_1

&lt;span class="c"&gt;# Expand files the user can read&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;w&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;a_dir_with_a_file A_FILE_WITH_UPPERCASE another_file empty_dir file_1 file_2 

&lt;span class="c"&gt;# Only expand the files with permission 777&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;f777&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;file_1

&lt;span class="c"&gt;# Only expand files when the permissions are always more than executable:&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;f-1&lt;span class="o"&gt;)&lt;/span&gt; 
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;A_FILE_WITH_UPPERCASE another_file file_2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Expansions Depending on Date or Size
&lt;/h4&gt;

&lt;p&gt;It's also possible to expand files depending on some dates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;m&amp;lt;unit&amp;gt;&amp;lt;operator&amp;gt;&amp;lt;n&amp;gt;&lt;/code&gt; - Expand to files modified &lt;code&gt;&amp;lt;n&amp;gt;&lt;/code&gt; time ago.

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;unit&amp;gt;&lt;/code&gt; can be &lt;code&gt;M&lt;/code&gt; for month of 30 days, &lt;code&gt;w&lt;/code&gt; for &lt;code&gt;w&lt;/code&gt;eeks, &lt;code&gt;d&lt;/code&gt; for &lt;code&gt;d&lt;/code&gt;ays (default when nothing is given),&lt;code&gt;h&lt;/code&gt; for &lt;code&gt;h&lt;/code&gt;our, &lt;code&gt;m&lt;/code&gt; for &lt;code&gt;m&lt;/code&gt;inute, or &lt;code&gt;s&lt;/code&gt; for &lt;code&gt;s&lt;/code&gt;econd.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;operator&amp;gt;&lt;/code&gt; can be:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;+&lt;/code&gt; - Files accessed more than &lt;code&gt;&amp;lt;n&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;lt;unit&amp;gt;&lt;/code&gt; ago&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&lt;/code&gt; - Files accessed less than &lt;code&gt;&amp;lt;n&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;lt;unit&amp;gt;&lt;/code&gt; ago.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The qualifier to expand only files with a specific size is similar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;L&amp;lt;unit&amp;gt;&amp;lt;operator&amp;gt;&amp;lt;n&amp;gt;&lt;/code&gt; - Expand to file with a certain size &lt;code&gt;&amp;lt;n&amp;gt;&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;The unit can be &lt;code&gt;K&lt;/code&gt; (Kilobyte), &lt;code&gt;M&lt;/code&gt; (Megabyte), &lt;code&gt;G&lt;/code&gt; (gigabyte), &lt;code&gt;T&lt;/code&gt; (terrabyte).&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;&amp;lt;operator&amp;gt;&lt;/code&gt; is:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;+&lt;/code&gt; - Files more than &lt;code&gt;&amp;lt;n&amp;gt;&lt;/code&gt; bytes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&lt;/code&gt; - Files less than &lt;code&gt;&amp;lt;n&amp;gt;&lt;/code&gt; bytes.&lt;/li&gt;
&lt;li&gt;To match exactly the size, don't give an &lt;code&gt;&amp;lt;operator&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Delete every files greater than 1Gb recursively&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;LG+1&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Delete all empty files recursively&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;L0&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Delete all files modified in the last hour&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mh-1&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Delete all files modified more than one hour ago &lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mh+1&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Expanding A Precise Number of Files
&lt;/h3&gt;

&lt;p&gt;Let's say that you had a vision: you &lt;em&gt;know&lt;/em&gt; that you only want to expand a precise number of files. The following qualifier will grant your crazy wish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Y&amp;lt;n&amp;gt;&lt;/code&gt; - Limit the expansion to &lt;code&gt;&amp;lt;n&amp;gt;&lt;/code&gt; number of files
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Only expand two files&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Y2&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;A_FILE_WITH_UPPERCASE empty_dir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Expanding and Sorting
&lt;/h3&gt;

&lt;p&gt;We can also sort our files if we want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;o&amp;lt;sort&amp;gt;&lt;/code&gt; - Sort files depending on the value of &lt;code&gt;&amp;lt;sort&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;O&amp;lt;sort&amp;gt;&lt;/code&gt; - Like &lt;code&gt;o&lt;/code&gt;, but sort in descending order&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The value of &lt;code&gt;&amp;lt;sort&amp;gt;&lt;/code&gt; can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;n&lt;/code&gt; - Sort by name (the default).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;L&lt;/code&gt; - Sort by size.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;l&lt;/code&gt; - Sort by number of links.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;a&lt;/code&gt; - Sort by last access.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;m&lt;/code&gt; - Sort by last modification.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;c&lt;/code&gt; - Sort by last inode change.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;d&lt;/code&gt; - Files in subdirectories appear before.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;N&lt;/code&gt; - Don't sort anything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Sort files from the smallest to the largest&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;oL&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Sort files from the largest to the smallest&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;OL&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Output the three biggest files (excluding directories) in the whole filetree&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;.OL[1,3]&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Expanding Depending on a Predicate
&lt;/h3&gt;

&lt;p&gt;As far as I know, a predicate is not a dinosaur, but a command (or a function) returning a boolean. Here's a qualifier to filter the expansion depending on a predicate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;e:'&amp;lt;cmd&amp;gt;'&lt;/code&gt; - The estring will filter the files depending on a command returning true or false. The filename being tested is available via the special variable REPLY. You can also change the value of REPLY to generate new filenames.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are two examples to help you understand my complicated rambling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Expand every file except the ones called "file_2"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;e:&lt;span class="s1"&gt;'[[ $REPLY != file_2 ]]'&lt;/span&gt;:&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;a_dir_with_a_file A_FILE_WITH_UPPERCASE another_file empty_dir file_1

&lt;span class="c"&gt;# Expand only plain files (with the qualifier "."), except the ones called "file_2"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;e:&lt;span class="s1"&gt;'[[ $REPLY != file_2 ]]'&lt;/span&gt;:.&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;A_FILE_WITH_UPPERCASE another_file file_1 

&lt;span class="c"&gt;# Expand only plain files, and reassign the REPLY variable to expand even more files (even if they don't exist)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;touch&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;e:&lt;span class="s1"&gt;'reply=(${REPLY}_{1..3})'&lt;/span&gt;:.&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;touch &lt;/span&gt;A_FILE_WITH_UPPERCASE_1 A_FILE_WITH_UPPERCASE_2 A_FILE_WITH_UPPERCASE_3 another_file_1 another_file_2 another_file_3 file_1_1 file_1_2 file_1_3 file_2_1 file_2_2 file_2_3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The form &lt;code&gt;e:'&amp;lt;cmd&amp;gt;'&lt;/code&gt; can take the form &lt;code&gt;+&amp;lt;cmd&amp;gt;&lt;/code&gt; if you need to call a function instead of using a command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create the function "condition"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; condition&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$REPLY&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; file_2 &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Only expand file named "file_2"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;+condition&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;file_2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was quite a ride! Let's now abandon the glob operators, their flags, and their qualifiers, to focus on the history of Zsh.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expanding the Zsh History
&lt;/h2&gt;

&lt;p&gt;To me, the best way to manage the shell's history is to use a fuzzy finder like &lt;a href="https://github.com/junegunn/fzf"&gt;fzf&lt;/a&gt;. That said, if you want to use vanilla Zsh to manipulate your history, you can use these three special characters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;!&lt;/code&gt; - The history character.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;^&lt;/code&gt; - The modification character.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#&lt;/code&gt; - The command character.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These characters are defined in the special variable &lt;code&gt;$HISTCHARS&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;It means that you can't use these three characters in your commands without properly escaping them. For example, If you run &lt;code&gt;echo hello!!&lt;/code&gt; or &lt;code&gt;echo "hello!!"&lt;/code&gt;, the shell will expand the &lt;code&gt;!!&lt;/code&gt;. In that case, you would need to use simple quotes (&lt;code&gt;echo 'hello!!'&lt;/code&gt;) or escaping the special characters with backslashes (&lt;code&gt;echo "hello\!\!"&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  The Event Designators
&lt;/h3&gt;

&lt;p&gt;The event designator is used to expand a command (or part of a command) from the history. &lt;/p&gt;

&lt;p&gt;First, to display your shell's history, you can run the command &lt;code&gt;history&lt;/code&gt;, or &lt;code&gt;history -&amp;lt;number&amp;gt;&lt;/code&gt; (&lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt; indicating how many commands you want to output). For example,&lt;code&gt;history -100&lt;/code&gt; will display the last 100 commands you've executed in your shell.&lt;/p&gt;

&lt;p&gt;Here are some nice and sweet event designators:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;!&amp;lt;number&amp;gt;&lt;/code&gt; - Expand the &lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt;th entry from the history.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;!-&amp;lt;number&amp;gt;&lt;/code&gt; - Expand the &lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt;th entry from the history, beginning by the most recent command. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;!!&lt;/code&gt; - Expand the previous command executed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;!&amp;lt;string&amp;gt;&lt;/code&gt; - Expand the most recent command executed, starting with &lt;code&gt;&amp;lt;string&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;!#&lt;/code&gt; - Expand to the current command you're typing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Expand the history's entry 123&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;123

&lt;span class="c"&gt;# Expand the second most recent command.&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nt"&gt;-2&lt;/span&gt;

&lt;span class="c"&gt;# Run a command for the following examples&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"first"&lt;/span&gt; &lt;span class="s2"&gt;"second"&lt;/span&gt; &lt;span class="s2"&gt;"third"&lt;/span&gt;

&lt;span class="c"&gt;# Expand to the last echo command executed&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"first"&lt;/span&gt; &lt;span class="s2"&gt;"second"&lt;/span&gt; &lt;span class="s2"&gt;"third"&lt;/span&gt;

&lt;span class="c"&gt;# Expand to the last command executed&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"first"&lt;/span&gt; &lt;span class="s2"&gt;"second"&lt;/span&gt; &lt;span class="s2"&gt;"third"&lt;/span&gt;

&lt;span class="c"&gt;# try to read install Neovim&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; pacman &lt;span class="nt"&gt;-S&lt;/span&gt; neovim
error: you cannot perform this operation unless you are root.

&lt;span class="c"&gt;# Repeat the previous command with sudo (super handy!)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;pacman &lt;span class="nt"&gt;-S&lt;/span&gt; neovim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Word Designators
&lt;/h3&gt;

&lt;p&gt;Going down to the rabbit hole, we can add word designators to our event designator. The goal is to only expand parts of the command from the history.&lt;/p&gt;

&lt;p&gt;The word designator needs to be separated from the event designator with a color &lt;code&gt;:&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Here are my favorites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;0&lt;/code&gt; - Expand the first input word of the command.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt; - Expand the &lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt;th argument.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;^&lt;/code&gt; - Expand the first argument or option.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$&lt;/code&gt; - Expand the last argument or option.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;*&lt;/code&gt; - Expand to all the arguments or options. If there is none, expand to the NULL value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You know what will follow? Yes! Examples! More of them!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"first"&lt;/span&gt; &lt;span class="s2"&gt;"second"&lt;/span&gt; &lt;span class="s2"&gt;"third"&lt;/span&gt;

&lt;span class="c"&gt;# Expand to the first word of the last command&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;:0
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;

&lt;span class="c"&gt;# Expand to the second argument of the last command&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;:2
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"second"&lt;/span&gt;

&lt;span class="c"&gt;# Expand to the first argument of the last command&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;:^
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"first"&lt;/span&gt;

&lt;span class="c"&gt;# Expand to the last argument of the last command&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;:&lt;span class="err"&gt;$&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"third"&lt;/span&gt;

&lt;span class="c"&gt;# Expand to all the arguments of the last command&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; print &lt;span class="o"&gt;!!&lt;/span&gt;:&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; print &lt;span class="s2"&gt;"first"&lt;/span&gt; &lt;span class="s2"&gt;"second"&lt;/span&gt; &lt;span class="s2"&gt;"third"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  History Modifiers
&lt;/h3&gt;

&lt;p&gt;Believe it or not, there's more. Additionally, you can add some modifiers to the word designator, again separated with &lt;code&gt;:&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As always, here are my favorites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;a&lt;/code&gt; - Transform a file name into an absolute path.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;A&lt;/code&gt; - Transform a file name into an absolute path and resolve the eventual symlinks.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;h&amp;lt;number&amp;gt;&lt;/code&gt; - Keep the &lt;code&gt;head&lt;/code&gt; of the path: everything except the last component of the path. Use &lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt; to keep the &lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt; of component of the pathname. In absolute path, the root directory &lt;code&gt;/&lt;/code&gt; is the first component.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;t&amp;lt;number&amp;gt;&lt;/code&gt; - Remove all leading path components except the final one (the tail). Add a &lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt; to keep a precise amount of trailing components.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;r&lt;/code&gt; - Remove the filename extension.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;l&lt;/code&gt; - Convert everything to lowercase.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;u&lt;/code&gt; - Convert everything to uppercase.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run a command&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; ~/a_dir_with_a_file/a_dir/a_file

&lt;span class="c"&gt;# Expand to the absolute path&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;:^:a
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; /home/user/a_dir_with_a_file/a_dir/a_file

&lt;span class="c"&gt;# Expand only the head (delete the tail) - similar to dirname&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;:^:h
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; a_dir_with_a_file/a_dir

&lt;span class="c"&gt;# Expand only the first part of the head&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;:^:h1
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; a_dir_with_a_file

&lt;span class="c"&gt;# Expand only the tail (delete the head) - similar to basename&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;:^:t
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; a_file

&lt;span class="c"&gt;# Expand only the tail and one element before&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;:^:t2
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; a_dir/a_file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Substitution Modifier
&lt;/h3&gt;

&lt;p&gt;We can also substitute one substring with another using the substitution modifier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;s/&amp;lt;string&amp;gt;/&amp;lt;replacement&amp;gt;/&amp;lt;flag&amp;gt;&lt;/code&gt; - Substitute &lt;code&gt;&amp;lt;string&amp;gt;&lt;/code&gt; with &lt;code&gt;&amp;lt;replacement&amp;gt;&lt;/code&gt; using an optional &lt;code&gt;&amp;lt;flag&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gs/&amp;lt;string&amp;gt;/&amp;lt;replacement&amp;gt;/&lt;/code&gt; or &lt;code&gt;s/&amp;lt;string&amp;gt;/&amp;lt;replacement&amp;gt;/:g&lt;/code&gt; - Substitute globally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we use the &lt;a href="https://en.wikipedia.org/wiki/Metacharacter"&gt;metacharacter&lt;/a&gt; &lt;code&gt;&amp;amp;&lt;/code&gt; in the replacement, it will be expanded with &lt;code&gt;&amp;lt;string&amp;gt;&lt;/code&gt;. If you want to use the literal symbol &lt;code&gt;&amp;amp;&lt;/code&gt; and not the metacharacter, you need to escape it with a backslash.&lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;&amp;lt;string&amp;gt;&lt;/code&gt; is empty, it uses the previous &lt;code&gt;&amp;lt;string&amp;gt;&lt;/code&gt; from the previous substitution.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"hello"&lt;/span&gt; &lt;span class="s2"&gt;"hello"&lt;/span&gt; &lt;span class="s2"&gt;"bonjour"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;:s/hello/bonjour
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"bonjour"&lt;/span&gt; &lt;span class="s2"&gt;"hello"&lt;/span&gt; &lt;span class="s2"&gt;"bonjour"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;:gs/hello/bonjour
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"bonjour"&lt;/span&gt; &lt;span class="s2"&gt;"bonjour"&lt;/span&gt; &lt;span class="s2"&gt;"bonjour"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;:gs/hello/&amp;amp; dear friend
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"hello dear friend"&lt;/span&gt; &lt;span class="s2"&gt;"hello dear friend"&lt;/span&gt; &lt;span class="s2"&gt;"bonjour"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all for expanding the history. Next steps: expanding variables and parameters!&lt;/p&gt;

&lt;h2&gt;
  
  
  Parameters Expansion
&lt;/h2&gt;

&lt;p&gt;Again, Zsh gives us many tools to expand variables and parameters.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Dollar Character
&lt;/h3&gt;

&lt;p&gt;As you probably know, the dollar character &lt;code&gt;$&lt;/code&gt; is used for variable expansion in Bash and Zsh. For example, if you define a wonderful variable &lt;code&gt;var=hello&lt;/code&gt;, you can expand its value with &lt;code&gt;$var&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Zsh, unlike Bash, can also expand arrays using the good old dollar. &lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a variable "var" and assign the value "hello". Spaces between `=` are not authorized (don't do "var = hello").&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hello

&lt;span class="c"&gt;# Expand the variable "var"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$var&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;hello

&lt;span class="c"&gt;# Create an array with three elements&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"one"&lt;/span&gt; &lt;span class="s2"&gt;"two"&lt;/span&gt; &lt;span class="s2"&gt;"three"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Expand the values of the array (only in Zsh)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$array&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;one two three
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Parameters Expansion: Adding Braces
&lt;/h3&gt;

&lt;p&gt;If the name of your variable is a substring of a word, you need to add braces to specify to the shell what's the name of the variable and what's some common string to display. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a variable "size"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;12

&lt;span class="c"&gt;# The shell tries to expand the variable "sizeGb"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This is &lt;/span&gt;&lt;span class="nv"&gt;$sizeGb&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;This&lt;span class="se"&gt;\ &lt;/span&gt;is&lt;span class="se"&gt;\&lt;/span&gt;

&lt;span class="c"&gt;# The shell knows that it needs to expand the variable "size" (and not "sizeGb")&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This is &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;Gb"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;This&lt;span class="se"&gt;\ &lt;/span&gt;is&lt;span class="se"&gt;\ &lt;/span&gt;12Gb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's not all: we can add modifiers to these braces, to manipulate the expansion of the variable (and not the value itself). Here's a list of the most useful ones, all available for Bash and Zsh :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;${var:-default}&lt;/code&gt; - If &lt;code&gt;var&lt;/code&gt; is not null, the value is expanded. Otherwise, &lt;code&gt;default&lt;/code&gt; is expanded. Useful when you need a default value when the variable (or parameter) is empty.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;${var:+default}&lt;/code&gt; - If &lt;code&gt;var&lt;/code&gt; is not null, &lt;code&gt;default&lt;/code&gt; is expanded. Otherwise, nothing is expanded.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;${var#pattern}&lt;/code&gt; - If the pattern match the beginning of the value of &lt;code&gt;var&lt;/code&gt;, the match is deleted and the rest is expanded. Use &lt;code&gt;##&lt;/code&gt; to match larger matching pattern.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;${var%pattern}&lt;/code&gt; - If the pattern match the end of the value of &lt;code&gt;var&lt;/code&gt;, the match is removed and the rest is expanded. Use &lt;code&gt;%%&lt;/code&gt; to match larger matching pattern.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;${var/&amp;lt;pattern&amp;gt;/&amp;lt;replacement&amp;gt;}&lt;/code&gt; - Replace the first pattern in &lt;code&gt;var&lt;/code&gt; with &lt;code&gt;replacement&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;${var//&amp;lt;pattern&amp;gt;/&amp;lt;replacement&amp;gt;}&lt;/code&gt; - Replace all occurrences of &lt;code&gt;pattern&lt;/code&gt; in &lt;code&gt;var&lt;/code&gt; with &lt;code&gt;replacement&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You guessed it already: I like examples. So here you go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a variable&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;new-value

&lt;span class="c"&gt;# Remove the prefix "new"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;#new&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-value&lt;/span&gt;

&lt;span class="c"&gt;# Change the value of the variable&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/home/user"&lt;/span&gt;

&lt;span class="c"&gt;# Delete the first slash and everything before&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;#*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; home/user

&lt;span class="c"&gt;# Delete the last slash and everything before&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;##*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls &lt;/span&gt;user

&lt;span class="c"&gt;# Create a new variable "image"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;file.png

&lt;span class="c"&gt;# Delete everything after the first dot&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;image&lt;/span&gt;&lt;span class="p"&gt;%.*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;file

&lt;span class="c"&gt;# Delete everything before the first dot&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;image&lt;/span&gt;&lt;span class="p"&gt;#*.&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;png

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"hello hello hello"&lt;/span&gt;

&lt;span class="c"&gt;# Replace the first word "hello" by "bonjour"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;/hello/bonjour&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;bonjour&lt;span class="se"&gt;\ &lt;/span&gt;hello&lt;span class="se"&gt;\ &lt;/span&gt;hello

&lt;span class="c"&gt;# Replace every word "hello" by "bonjour"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;//hello/bonjour&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;bonjour&lt;span class="se"&gt;\ &lt;/span&gt;bonjour&lt;span class="se"&gt;\ &lt;/span&gt;bonjour
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following ones are only available with Zsh:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;${var:/&amp;lt;pattern&amp;gt;/&amp;lt;replacement&amp;gt;}&lt;/code&gt; - Substitute &lt;code&gt;&amp;lt;pattern&amp;gt;&lt;/code&gt; with &lt;code&gt;&amp;lt;replacement&amp;gt;&lt;/code&gt;. The substitution only happens when &lt;code&gt;pattern&lt;/code&gt; match the whole value of &lt;code&gt;var&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;${^array}&lt;/code&gt; - Substitute every element of the &lt;code&gt;array&lt;/code&gt; with whatever comes before or after.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;${=array}&lt;/code&gt; - Split a string to an array using the internal field separators. These separators are the values of the variable &lt;code&gt;$IFS&lt;/code&gt;, by default whitepaces (spaces, tabs, and new lines characters).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# The pattern matches the entire value of the variable var, so everything is replaced with "bonjour"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;:/hello&lt;span class="p"&gt; hello hello/bonjour&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;bonjour

&lt;span class="c"&gt;# Create a new variable "array"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"one"&lt;/span&gt; &lt;span class="s2"&gt;"two"&lt;/span&gt; &lt;span class="s2"&gt;"three"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Expand the whole array and add the suffix ".png" to the last element&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.png"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;one&lt;span class="se"&gt;\ &lt;/span&gt;two&lt;span class="se"&gt;\ &lt;/span&gt;three.png

&lt;span class="c"&gt;# Expand every element of the array with the suffix ".png".&lt;/span&gt;
&lt;span class="c"&gt;# This command needs to be executed, not expanded (pressing the key "ENTER", not "TAB").&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;^array&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.png
one.png two.png three.png

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"a big var"&lt;/span&gt;

&lt;span class="c"&gt;# Assign the whole value of var to the array&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Expand the first element of the array&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$arr&lt;/span&gt;&lt;span class="s2"&gt;[1]"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;a&lt;span class="se"&gt;\ &lt;/span&gt;big&lt;span class="se"&gt;\ &lt;/span&gt;var

&lt;span class="c"&gt;# Cut the value of var and assign it to the array&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;=var&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$arr&lt;/span&gt;&lt;span class="s2"&gt;[1]"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;a

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$arr&lt;/span&gt;&lt;span class="s2"&gt;[2]"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;big
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's also possible to nest the pair of braces. Everything will be expanded from in out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/home/user/woupi/"&lt;/span&gt;

&lt;span class="c"&gt;# 1. "${var#/home}" is expanded, output: "/user/woupi"&lt;/span&gt;
&lt;span class="c"&gt;# 2. The output is expanded as follows: "&amp;lt;output&amp;gt;%woupi/"&lt;/span&gt;
&lt;span class="c"&gt;# 3. The final output is "/user/"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;#/home&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;%woupi/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; /user/

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"prefix-image.png"&lt;/span&gt;

&lt;span class="c"&gt;# 1. "${var#prefix-}" is expanded, output: image.png &lt;/span&gt;
&lt;span class="c"&gt;# 2. "${output%.*}" is expanded, output: image&lt;/span&gt;
&lt;span class="c"&gt;# 3. ".jpg" is added to the output, final output: image.jpg&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;#prefix-&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;%.*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.jpg"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;image.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Flags
&lt;/h4&gt;

&lt;p&gt;You want more? That's not a problem. With Zsh, you can also add flags to parameter expansions. These flags are surrounded by parenthesis &lt;code&gt;()&lt;/code&gt;, just after the opening curly braces &lt;code&gt;{&lt;/code&gt;. You can use as many as you want, as your heart's content.&lt;/p&gt;

&lt;p&gt;As always, here are the most interesting ones, with examples of course. For these examples, the expansion is not the result of hitting the key &lt;code&gt;TAB&lt;/code&gt;, but by hitting the key &lt;code&gt;ENTER&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;C&lt;/code&gt; - Capitalise (first letter uppercase) every word.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"hello i like zsh"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(C)var&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
Hello I Like Zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;f&lt;/code&gt; - Join strings separated with newlines.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;F&lt;/code&gt; - Split array with each element separated with newline.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Assign all the files of the current directories and subdirectories to the variable "files"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;find&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$files&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt;
./file1
./file2

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(f)files&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt; ./file1 ./file2

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(f)files&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# First index of array is 1&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;1]
&lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;2]
./file1

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(F)arr&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt;
./file1
./file2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;i&lt;/code&gt; - Sort an array (case-insensitive).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;file_02 file_01 B_FILE a_file 02_file 01_file&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(i)arr&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
01_file 02_file a_file file_01 file_02
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;O&lt;/code&gt; - Sort an array in descending order. Useful when combined with &lt;code&gt;i&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;file_02 file_01 a_file 02_file 01_file&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(Oi)arr&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
file_02 file_01 a_file 02_file 01_file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;L&lt;/code&gt; - Convert all letters to lowercase&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;U&lt;/code&gt; - Convert all letters to uppercase
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"file_1 FILE_2"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(U)var&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
FILE_1 FILE_2

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(L)var&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
file_1 file_2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;t&lt;/code&gt; - Describe the type of the variable. It can be: 

&lt;ul&gt;
&lt;li&gt;scalar&lt;/li&gt;
&lt;li&gt;array&lt;/li&gt;
&lt;li&gt;integer&lt;/li&gt;
&lt;li&gt;float&lt;/li&gt;
&lt;li&gt;association
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"one"&lt;/span&gt; &lt;span class="s2"&gt;"two"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(t)arr&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
array

&lt;span class="c"&gt;# Create an associative array&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="nv"&gt;assoc&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"key"&lt;/span&gt; &lt;span class="s2"&gt;"value"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(t)assoc&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
association
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;u&lt;/code&gt; - Only expand the unique words in an array, even if these words are repeated multiple times.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"one"&lt;/span&gt; &lt;span class="s2"&gt;"two"&lt;/span&gt; &lt;span class="s2"&gt;"two"&lt;/span&gt; &lt;span class="s2"&gt;"three"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(u)arr&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
one two three
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;k&lt;/code&gt; - Expand the keys instead of the values from an associative array.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;v&lt;/code&gt; - Used with k, expand both key and value from an associative array
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="nv"&gt;assoc&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"key"&lt;/span&gt; &lt;span class="s2"&gt;"value"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;assoc&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
value

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(k)assoc&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
key

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(kv)assoc&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
key value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;S&lt;/code&gt; - Adding this flag with &lt;code&gt;#&lt;/code&gt;, &lt;code&gt;##&lt;/code&gt;, &lt;code&gt;%&lt;/code&gt;, or &lt;code&gt;%%&lt;/code&gt; will match a substring.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/home/user/workspace/tvd"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;#home*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
/home/user/workspace/tvd

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(S)var#home*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
//user/workspace/tvd

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(S)var##home*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
/

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(S)var%work*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
/home/user/space/tvd

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(S)var%%work*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
/home/user/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;M&lt;/code&gt; - Adding this flag with &lt;code&gt;#&lt;/code&gt;, &lt;code&gt;##&lt;/code&gt;, &lt;code&gt;%&lt;/code&gt;, or &lt;code&gt;%%&lt;/code&gt; will output the matched portion.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/home/user"&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;#*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
home/user

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(M)var#*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
/

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="p"&gt;##*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
user

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(M)var##*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
/home/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  You Can Now Become a Zsh Godly Figure
&lt;/h2&gt;

&lt;p&gt;You can do many things with Zsh, even if it's not always easy to figure out what. With what we've seen in this article, we're now able to manipulate our expansions in more straightforward ways. No need to use annoying for loops anymore!&lt;/p&gt;

&lt;p&gt;To summarize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Glob operators can help you expand filenames, even recursively through a whole file tree. You can also add globbing qualifiers and flags to expand specific filenames.&lt;/li&gt;
&lt;li&gt;Being able to run commands you've run in the past is really useful. Being able to modify the expansion of these commands on the fly is even better.&lt;/li&gt;
&lt;li&gt;With Zsh, we can also expand parameters and variables easily using the famous dollar &lt;code&gt;$&lt;/code&gt;, curly braces &lt;code&gt;{}&lt;/code&gt;, and flags.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If it's not enough for you, I invite you to read the part of the Zsh's manual about expansion (&lt;code&gt;man zshexpn&lt;/code&gt;). There's everything we've covered here, and much more, if your brain can handle it. Mine was on a strike after going through it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Becoming Mouseless
&lt;/h2&gt;

&lt;p&gt;Do you want to build a &lt;a href="https://themouseless.dev"&gt;Mouseless Development Environment&lt;/a&gt; where the Linux shell has a central role?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://themouseless.dev"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gkZumQAJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://themouseless.dev/images/small_cover.webp" alt="building your mouseless development environment" width="300" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Switching between the keyboard and the mouse costs cognitive energy. This book will guide you step by step to set up a Linux-based development environment that keeps your hands on your keyboard.&lt;/p&gt;

&lt;p&gt;Take the brain power you've been using to juggle input devices and focus it where it belongs: on what you create.&lt;/p&gt;




</description>
      <category>zsh</category>
      <category>terminal</category>
      <category>productivity</category>
      <category>shell</category>
    </item>
    <item>
      <title>A Guide to the Zsh Completion With Examples</title>
      <dc:creator>Matthieu Cneude</dc:creator>
      <pubDate>Sat, 11 Dec 2021 13:07:28 +0000</pubDate>
      <link>https://forem.com/phantas0s/a-guide-to-the-zsh-completion-with-examples-2jhe</link>
      <guid>https://forem.com/phantas0s/a-guide-to-the-zsh-completion-with-examples-2jhe</guid>
      <description>&lt;p&gt;"The completion offered by Zsh is great, but could it be better? Why not trying to understand how it works? I could then configure it for my own needs!"&lt;/p&gt;

&lt;p&gt;This was my thinking a couple of months ago, after waking up a Monday morning full of energy and will to eat my breakfast. I was young and innocent, unaware of the consequences of this thought making its nest in my brain. What could go wrong? After all, it's only a completion system.&lt;/p&gt;

&lt;p&gt;While reading the page of the Zsh manual concerning the completion, I saw the Demon of Complexity™ showing its nose. A dozen of questions were popping up, a twisted configuration syntax was unleashed, nonsensical descriptions were unfolding before my eyes.&lt;/p&gt;

&lt;p&gt;When I see something complex, I can't stop myself trying to simplify it. It took me hours to begin to understand this completion system, but now I think I've a good grasp on the Beast.&lt;/p&gt;

&lt;p&gt;This article is the result of my efforts. It aims to explain the Zsh completion system in a simple way; more precisely, we'll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to enable the Zsh completion.&lt;/li&gt;
&lt;li&gt;How does the completion system work.&lt;/li&gt;
&lt;li&gt;What's the purpose of the zstyle module.&lt;/li&gt;
&lt;li&gt;How to use styles to configure the Zsh completion.&lt;/li&gt;
&lt;li&gt;What are the most useful styles we can use to customize the completion.&lt;/li&gt;
&lt;li&gt;How to trigger a precise completion using keystrokes.&lt;/li&gt;
&lt;li&gt;How to customize the completion menu using the module &lt;em&gt;complist&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;What are the Zsh options we can set to configure the completion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As I explain in a &lt;a href="https://thevaluable.dev/zsh-install-configure-mouseless/" rel="noopener noreferrer"&gt;previous article&lt;/a&gt;, I don't use any Zsh framework (like oh-my-zsh or prezto) to have a full control on my config.&lt;/p&gt;

&lt;p&gt;Enough rambling! Let's dive into the fantastic and dangerous Zsh completion system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enabling the Zsh Completion System
&lt;/h2&gt;

&lt;p&gt;To initialize the completion for the current session, you need to &lt;em&gt;autoload&lt;/em&gt; the function &lt;code&gt;compinit&lt;/code&gt; and to call it. To do so, add the following in your file &lt;code&gt;.zshrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;autoload &lt;span class="nt"&gt;-U&lt;/span&gt; compinit&lt;span class="p"&gt;;&lt;/span&gt; compinit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you wonder what's this &lt;code&gt;autoload&lt;/code&gt;, I already wrote about it &lt;a href="https://thevaluable.dev/zsh-install-configure-mouseless/" rel="noopener noreferrer"&gt;in this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also configure your completion with the shell command &lt;code&gt;compinstall&lt;/code&gt;. It asks a series of question to decide what kind of completion you need, and it writes automatically your preferences in your &lt;code&gt;.zshrc&lt;/code&gt;. In that case, you don't need to autoload and run &lt;code&gt;compinit&lt;/code&gt; manually.&lt;/p&gt;

&lt;p&gt;But I find this tool very limited, and the questions it asks are quite obscure. I prefer writing my own config for the completion system in a separate file and source it in my &lt;code&gt;.zshrc&lt;/code&gt;. More on that below.&lt;/p&gt;

&lt;p&gt;It's where things become slightly complicated. If you don't care about the details, you can copy and paste &lt;a href="https://github.com/Phantas0s/.dotfiles/blob/master/zsh/completion.zsh" rel="noopener noreferrer"&gt;my simple config&lt;/a&gt; in a file and source it in your &lt;code&gt;.zshrc&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does the Zsh Completion System Work
&lt;/h2&gt;

&lt;p&gt;Zsh has two completion systems, the old &lt;em&gt;compctl&lt;/em&gt; and the more recent &lt;em&gt;compsys&lt;/em&gt;. We only look at compsys in this article.&lt;/p&gt;

&lt;p&gt;Concretely, compsys is a collection of Zsh functions. You can find them in the &lt;a href="https://github.com/zsh-users/zsh/tree/master/Completion" rel="noopener noreferrer"&gt;official repository of Zsh&lt;/a&gt;. Three folders are specifically important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Base - The core of the completion system, defining the basic completers.&lt;/li&gt;
&lt;li&gt;Zsh - Functions for completing built-in Zsh commands (like &lt;code&gt;cd&lt;/code&gt; for example).&lt;/li&gt;
&lt;li&gt;Unix - Function for completing external commands.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also folders for commands only available in some systems, like Solaris, Redhat, or Mandrive for example.&lt;/p&gt;

&lt;p&gt;When you type a command in Zsh and hit the &lt;code&gt;TAB&lt;/code&gt; key, a completion is attempted depending on the &lt;em&gt;context&lt;/em&gt;. This context includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What command and options have been already typed at the command-line prompt.&lt;/li&gt;
&lt;li&gt;Where the cursor is.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The context is then given to one or more &lt;em&gt;completer&lt;/em&gt; functions which will attempt to complete what you've typed. Each of these completers are tried in order and, if the first one can't complete the context, the next one will try. When the context can be completed, some possible &lt;em&gt;matches&lt;/em&gt; will be displayed and you can choose whatever you want.&lt;/p&gt;

&lt;p&gt;A warning is thrown if none of the completers are able to match the context.&lt;/p&gt;

&lt;p&gt;There are two more things to know about completers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The names of completers are prefixed with an underscore, like &lt;code&gt;_complete&lt;/code&gt; or &lt;code&gt;_expand_alias&lt;/code&gt; for example.&lt;/li&gt;
&lt;li&gt;A few completers return a special value 0 which will stop the completion, even if more completers are defined afterward.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuring Zsh Completion With zstyle
&lt;/h2&gt;

&lt;p&gt;You can configure many aspects of the completion system using the zsh module &lt;em&gt;zstyle&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Modules are part of Zsh but optional, detached from the core of the shell. They can be linked to the shell at build time or dynamically linked while the shell is running.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's zstyle?
&lt;/h3&gt;

&lt;p&gt;You might think that zstyle is used to configure some display styles, but it's much more than that. It's easier to see it as a flexible way to modify the default settings of Zsh scripts (modules, widgets, functions, and so on). &lt;br&gt;
The authors of these scripts need to define what are these settings, what &lt;em&gt;pattern&lt;/em&gt; a user can use to modify them, and how these modifications can affect their code.&lt;/p&gt;

&lt;p&gt;Here's the general way you can use zstyle to configure a Zsh module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &amp;lt;pattern&amp;gt; &amp;lt;style&amp;gt; &amp;lt;values&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;pattern&lt;/em&gt; act as a namespace. It's divided by colons &lt;code&gt;:&lt;/code&gt; and each value between these colons have a precise meaning.&lt;/p&gt;

&lt;p&gt;In the case of the Zsh completion system, the context we saw earlier (what you've already typed in your command-line) is compared with this pattern. If there's a match, the style will be applied.&lt;/p&gt;

&lt;p&gt;Don't worry if all of that sounds confusing: bare with me, I'll give some examples soon. For now, let's look a bit closer to the zstyle patterns we can use to configure our completion system.&lt;/p&gt;

&lt;p&gt;See &lt;code&gt;man zshcompsys&lt;/code&gt; for the list of styles for the completion system (search for "Standard Styles").&lt;/p&gt;

&lt;h3&gt;
  
  
  General zstyle Patterns for Completion
&lt;/h3&gt;

&lt;p&gt;To configure the completion system, you can use zstyle patterns following this template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:completion:&amp;lt;function&amp;gt;:&amp;lt;completer&amp;gt;:&amp;lt;command&amp;gt;:&amp;lt;argument&amp;gt;:&amp;lt;tag&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The substring separated with colons &lt;code&gt;:&lt;/code&gt; are called &lt;em&gt;components&lt;/em&gt;. Let's look at the ones used for the completion system in details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;completion&lt;/code&gt; - String acting as a namespace, to avoid pattern collisions with other scripts also using zstyle.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;function&amp;gt;&lt;/code&gt; - Apply the style to the completion of an external function or widget.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;completer&amp;gt;&lt;/code&gt; - Apply the style to a specific completer. We need to drop the underscore from the completer's name here.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;command&amp;gt;&lt;/code&gt; - Apply the style to a specific command, like &lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;rm&lt;/code&gt;, or &lt;code&gt;sed&lt;/code&gt; for example.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;argument&amp;gt;&lt;/code&gt; - Apply the style to the nth option or the nth argument. It's not available for many styles.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;tag&amp;gt;&lt;/code&gt; - Apply the style to a specific tag.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can think of a tag as a &lt;em&gt;type of match&lt;/em&gt;. For example "files", "domains", "users", or "options" are tags.&lt;/p&gt;

&lt;p&gt;For the list of tags, see &lt;code&gt;man zshcompsys&lt;/code&gt; (search for "Standard Tags")&lt;/p&gt;

&lt;p&gt;You don't have to define every component of the pattern. Instead, you can replace each of them with a star &lt;code&gt;*&lt;/code&gt;. The more specific the pattern will be, the more precedence it will have over less specific patterns. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*:*:cp:*'&lt;/span&gt; file-sort size
zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; file-sort modification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens if you set these styles?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you hit &lt;code&gt;TAB&lt;/code&gt; after typing &lt;code&gt;cp&lt;/code&gt;, the possible files matched by the completion system will be ordered by size.&lt;/li&gt;
&lt;li&gt;When you match files using the completion, they will be ordered by date of modification.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The pattern &lt;code&gt;:completion:*:*:cp:*&lt;/code&gt; has precedence over &lt;code&gt;:completion:*&lt;/code&gt; because it's considered more precise.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;*&lt;/code&gt; replace any character &lt;em&gt;including the colon&lt;/em&gt; &lt;code&gt;:&lt;/code&gt;. That's why the pattern &lt;code&gt;:completion:*:*:cp:*&lt;/code&gt; is equivalent to &lt;code&gt;:completion:*:cp:*&lt;/code&gt;. That said, I find the second form confusing: it's not clear what &lt;code&gt;cp&lt;/code&gt; is. Is it a command? A function? A tag? In that case it's pretty obvious, but it's not always &lt;code&gt;cp&lt;/code&gt; in the pattern. Personally, I always try to use the first form.&lt;/p&gt;

&lt;p&gt;You can run &lt;code&gt;zstyle&lt;/code&gt; in your shell to display the styles set in your current session as well as their patterns.&lt;/p&gt;

&lt;h3&gt;
  
  
  Examples of zstyles for the Zsh Completion
&lt;/h3&gt;

&lt;p&gt;All of that is quite verbose and not very self-explanatory, so let's look at more examples. Here's a simple one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; verbose &lt;span class="nb"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This zstyle command is composed of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A pattern: &lt;code&gt;:completion:*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A style: &lt;code&gt;verbose&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A value: &lt;code&gt;yes&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is only one value given here, because the style &lt;code&gt;verbose&lt;/code&gt; only accept one. But you can set more than one for some styles. Each of these values would be separated by a space. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zstyle ':completion:*:*:cp:*' file-sort modification reverse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We give here two values to the style &lt;code&gt;file-sort&lt;/code&gt;: &lt;code&gt;modification&lt;/code&gt; (to order the matches by date of modification) and &lt;code&gt;reverse&lt;/code&gt; (to reverse the order). As we saw before, the pattern &lt;code&gt;:completion:*:*:cp:*&lt;/code&gt; indicates that we only set the style &lt;code&gt;file-sort&lt;/code&gt; to the command &lt;code&gt;cp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's see now a couple of styles we can set to improve our Zsh completion.&lt;/p&gt;

&lt;p&gt;For more zstyle, see &lt;code&gt;man zshmodules&lt;/code&gt; (search for "zstyle").&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Style for the Zsh Completion System
&lt;/h2&gt;

&lt;p&gt;I would recommend creating a new file &lt;code&gt;completion.zsh&lt;/code&gt; somewhere and sourcing it directly in your file &lt;code&gt;.zshrc&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; /path/to/my/completion.zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every style defined here should be called after autoloading and calling compinit. If you don't want a separate file, you can throw all this configuration into your &lt;code&gt;.zshrc&lt;/code&gt; too.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Essential
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Defining the Completers
&lt;/h4&gt;

&lt;p&gt;Let's first define the completer we'll use for our completion system. Here are some interesting ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;_complete&lt;/code&gt; - This is the main completer we need to use for our completion.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_approximate&lt;/code&gt; - This one is similar to &lt;code&gt;_complete&lt;/code&gt;, except that it will try to correct what you've typed already (the context) if no match is found.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_expand_alias&lt;/code&gt; - Expand an alias you've typed. It needs to be declared before &lt;code&gt;_complete&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_extensions&lt;/code&gt; - Complete the glob &lt;code&gt;*.&lt;/code&gt; with the possible file extensions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that you can use &lt;code&gt;_expand_alias&lt;/code&gt; with the keystroke &lt;code&gt;CTRL+x a&lt;/code&gt; by default, without the need to use it as a completer. Simply type one of your alias in Zsh and try to use the keystroke.&lt;/p&gt;

&lt;p&gt;You need to set the zstyle &lt;code&gt;completer&lt;/code&gt; to define the completer you want to use. The order matter: the completion system will try each of these completer one after the other. The completion stop when some matches are found or when the completer stop it by itself.&lt;/p&gt;

&lt;p&gt;For example, here are the completers I use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; completer _extensions _complete _approximate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we're dabbling into the completion system, the completer &lt;code&gt;_complete_help&lt;/code&gt; might come in handy. You can use it as a function you can call with &lt;code&gt;CTRL+x h&lt;/code&gt; by default.&lt;/p&gt;

&lt;p&gt;When you're not sure why you end up with some matches and not others, you can hit &lt;code&gt;CTRL+x h&lt;/code&gt; (for &lt;code&gt;h&lt;/code&gt;elp) before completing your command. It will display some information about what the completion system will do to complete your context.&lt;/p&gt;

&lt;h4&gt;
  
  
  Caching the Completion
&lt;/h4&gt;

&lt;p&gt;Using a cache for the completion can speed up some commands, like &lt;code&gt;apt&lt;/code&gt; for example. Let's add the following in our file to enable it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; use-cache on
zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; cache-path &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_CACHE_HOME&lt;/span&gt;&lt;span class="s2"&gt;/zsh/.zcompcache"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you might have guessed, the style &lt;code&gt;cache-path&lt;/code&gt; allows you to set the filename and location of the cache.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Completion Menu
&lt;/h4&gt;

&lt;p&gt;Instead of going through each match blindly to add what you want to your command, you can use a &lt;em&gt;completion menu&lt;/em&gt;. For that, you need to set the style &lt;code&gt;menu&lt;/code&gt; with the value &lt;code&gt;select&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; menu &lt;span class="k"&gt;select&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use this menu only if a precise &lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt; of matches is found with &lt;code&gt;select=&amp;lt;number&amp;gt;&lt;/code&gt;. It's even possible to start the menu selection only if the list of matches doesn't fit the screen, by using the value &lt;code&gt;select=long&lt;/code&gt;. Using both values &lt;code&gt;select=&amp;lt;number&amp;gt;&lt;/code&gt; and &lt;code&gt;select=long&lt;/code&gt; is possible too.&lt;/p&gt;

&lt;p&gt;Having the values &lt;code&gt;select&lt;/code&gt; and &lt;code&gt;interactive&lt;/code&gt; allows you to filter the completion menu itself using the completion system. You can also configure a keystroke to switch this &lt;em&gt;interactive mode&lt;/em&gt; when the completion menu is displayed. More on that later in this article.&lt;/p&gt;

&lt;p&gt;Adding the value &lt;code&gt;search&lt;/code&gt; to the style will allow you to fuzzy-search the completion menu. Again, a keystroke can be configured to have this functionality on demand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Formatting The Display
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Colors and Decoration
&lt;/h4&gt;

&lt;p&gt;Let's now improve the display of our completion menu using the style &lt;code&gt;format&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Each completer can define different &lt;em&gt;sequences&lt;/em&gt; (beginning with &lt;code&gt;%&lt;/code&gt;) for different tags. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*:*:*:*:descriptions'&lt;/span&gt; format &lt;span class="s1"&gt;'%F{green}-- %d --%f'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we saw quickly above, a tag is &lt;em&gt;most of the time&lt;/em&gt; a type of match. More generally, you can see it as a type of information displayed during completion. Here, the &lt;code&gt;descriptions&lt;/code&gt; tag is specific to the &lt;code&gt;format&lt;/code&gt; style. It generates descriptions depending on the type of match. For example, if you have files displayed in the completion menu, the description for the tag "files" will be displayed too.&lt;/p&gt;

&lt;p&gt;The value of &lt;code&gt;format&lt;/code&gt; is used for displaying these descriptions. Here, we use in the style's value the sequence &lt;code&gt;%d&lt;/code&gt; which will be replaced by the description itself.&lt;/p&gt;

&lt;p&gt;Here's the result for local directories:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthevaluable.dev%2Fimages%2F2021%2Fzsh_completion_system%2Fformat_description.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthevaluable.dev%2Fimages%2F2021%2Fzsh_completion_system%2Fformat_description.png" alt="Zsh format style with description for completion system"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're using the completer &lt;code&gt;_approximate&lt;/code&gt;, you can set the format of the possible corrections too. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*:*:*:*:corrections'&lt;/span&gt; format &lt;span class="s1"&gt;'%F{yellow}!- %d (errors: %e) -!%f'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthevaluable.dev%2Fimages%2F2021%2Fzsh_completion_system%2Fformat_correction.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthevaluable.dev%2Fimages%2F2021%2Fzsh_completion_system%2Fformat_correction.png" alt="Zsh format style with correction for completion system"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To format messages or warnings (for example when no match is found), you can add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*:messages'&lt;/span&gt; format &lt;span class="s1"&gt;' %F{purple} -- %d --%f'&lt;/span&gt;
zstyle &lt;span class="s1"&gt;':completion:*:warnings'&lt;/span&gt; format &lt;span class="s1"&gt;' %F{red}-- no matches found --%f'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use the escape sequence &lt;code&gt;%F %f&lt;/code&gt; in the style's value to use a foreground color. Here's a summary of sequences you can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;%F{&amp;lt;color&amp;gt;} %f&lt;/code&gt; - Change the foreground color with &lt;code&gt;&amp;lt;color&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%K{&amp;lt;color&amp;gt;} %k&lt;/code&gt; - Change the background color with &lt;code&gt;&amp;lt;color&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%B %b&lt;/code&gt; - Bold.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%U %u&lt;/code&gt; - Underline.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, you can create a horrible display as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*:descriptions'&lt;/span&gt; format &lt;span class="s1"&gt;'%U%K{yellow} %F{green}-- %F{red} %BNICE!1! %b%f %d --%f%k%u'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your descriptions are now a piece of art.&lt;/p&gt;

&lt;h4&gt;
  
  
  Grouping Results
&lt;/h4&gt;

&lt;p&gt;To group the different type of matches under their descriptions, you can add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; group-name &lt;span class="s1"&gt;''&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this style, all the descriptions will be at the top and the matches at the bottom:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthevaluable.dev%2Fimages%2F2021%2Fzsh_completion_system%2Fbefore_group.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthevaluable.dev%2Fimages%2F2021%2Fzsh_completion_system%2Fbefore_group.jpg" alt="Before setting the style group-name in Zsh"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the value of this style set with an empty string, the matches will be grouped under the descriptions depending on their types:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthevaluable.dev%2Fimages%2F2021%2Fzsh_completion_system%2Fafter_group.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthevaluable.dev%2Fimages%2F2021%2Fzsh_completion_system%2Fafter_group.jpg" alt="after setting the style group-name in Zsh"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're not satisfied by the order these descriptions are displayed, you can modify it too. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*:*:-command-:*:*'&lt;/span&gt; group-order &lt;span class="nb"&gt;alias &lt;/span&gt;builtins functions commands
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;-command-&lt;/code&gt; means any word in the "command position". It means that we want the matches tagged &lt;code&gt;alias&lt;/code&gt; to appear before &lt;code&gt;builtins&lt;/code&gt;, &lt;code&gt;functions&lt;/code&gt;, and &lt;code&gt;commands&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Detailed List of Files and Folders
&lt;/h4&gt;

&lt;p&gt;The style &lt;code&gt;file-list&lt;/code&gt; can display the list of files and folder matched with more details, similar to the information you can display with &lt;code&gt;ls -l&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; file-list all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthevaluable.dev%2Fimages%2F2021%2Fzsh_completion_system%2Flong_list_file.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthevaluable.dev%2Fimages%2F2021%2Fzsh_completion_system%2Flong_list_file.jpg" alt="Before setting the style group-name in Zsh"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Colorful Completion List
&lt;/h4&gt;

&lt;p&gt;To have nice colors for your directories and file in the completion menu, you can add the style &lt;code&gt;list-colors&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*:default'&lt;/span&gt; list-colors &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(s.&lt;/span&gt;:.&lt;span class="p"&gt;)LS_COLORS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will set the value with the content of the environment variable &lt;code&gt;LS_COLORS&lt;/code&gt;, normally used by the command &lt;code&gt;ls --color=auto&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You apparently need to have the module &lt;code&gt;zsh/complist&lt;/code&gt; loaded, but it worked without it on my system. I describe a bit more the module complist later in this article.&lt;/p&gt;

&lt;p&gt;You can configure the colors of any completion menu even further using the environment variable &lt;code&gt;ZLS_COLORS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To configure the colors, search &lt;code&gt;man zshmodules&lt;/code&gt; (search "Colored completion listings").&lt;/p&gt;

&lt;h3&gt;
  
  
  Smarter Completion System
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Squeezing Slashes
&lt;/h4&gt;

&lt;p&gt;By default, the completion system will expand &lt;code&gt;//&lt;/code&gt; to &lt;code&gt;/*/&lt;/code&gt;. For example, &lt;code&gt;cd ~//Documents&lt;/code&gt; will be expanded to &lt;code&gt;cd ~/*/Documents&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Usually, on Unix systems, &lt;code&gt;//&lt;/code&gt; is expanded to &lt;code&gt;/&lt;/code&gt;. If you prefer this behavior, you can set the style &lt;code&gt;squeeze-slashes&lt;/code&gt; to true as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; squeeze-slashes &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Directory Stack Completion
&lt;/h4&gt;

&lt;p&gt;For the command &lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;chdir&lt;/code&gt; and &lt;code&gt;pushd&lt;/code&gt;, you can use a hyphen &lt;code&gt;-&lt;/code&gt; not only for options but for a directory stack entry.&lt;/p&gt;

&lt;p&gt;By default, the Zsh completion system will try to complete for a directory stack entry when you hit tab after a hyphen &lt;code&gt;-&lt;/code&gt; while using one of these commands. If you prefer completing for an option, you can set the style &lt;code&gt;complete-options&lt;/code&gt; to true as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; complete-options &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're interested to learn more about the directory stack, I described a nice way to navigate through it &lt;a href="https://thevaluable.dev/zsh-install-configure-mouseless/" rel="noopener noreferrer"&gt;in this article&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Sorting Matched Files
&lt;/h4&gt;

&lt;p&gt;You can sort the files appearing in the completion menu as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; file-sort dummyvalue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this style is not set (or set with a dummy value like in the example above), the files will be sorted alphabetically. You can use one of these values if you prefer another ordering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;size&lt;/code&gt; - Order files by size.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;links&lt;/code&gt; - Order files depending on the links pointing to them.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;modification&lt;/code&gt; or &lt;code&gt;date&lt;/code&gt; or &lt;code&gt;time&lt;/code&gt; - Order files by date of modification.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;access&lt;/code&gt; - Order files by time of access.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;change&lt;/code&gt; or &lt;code&gt;inode&lt;/code&gt; - Order files by the time of change.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also add &lt;code&gt;reverse&lt;/code&gt; to the values to reverse the order. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; file-sort change reverse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you add the value &lt;code&gt;follow&lt;/code&gt;, the timestamp of the targets for symlinks will be used instead of the timestamp of the symlinks themselves.&lt;/p&gt;

&lt;h4&gt;
  
  
  Completion Matching Control
&lt;/h4&gt;

&lt;p&gt;Setting the style &lt;code&gt;matcher-list&lt;/code&gt; allows you to filter the matches of the completion with even more patterns.&lt;/p&gt;

&lt;p&gt;For example, you can set this style for the completion to first try the usual completion and, if nothing matches, to try a case-insensitive completion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; matcher-list &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="s1"&gt;'m:{a-zA-Z}={A-Za-z}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The completion can also try to complete partial words you've typed with the following style:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s1"&gt;':completion:*'&lt;/span&gt; matcher-list &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="s1"&gt;'m:{a-zA-Z}={A-Za-z}'&lt;/span&gt; &lt;span class="s1"&gt;'r:|[._-]=* r:|=*'&lt;/span&gt; &lt;span class="s1"&gt;'l:|=* r:|=*'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This style would allow you, for example, to complete the file &lt;code&gt;_DSC1704.JPG&lt;/code&gt; if you only try to complete its substring &lt;code&gt;1704&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The patterns themselves are quite... obscure. If you want a good intellectual challenge, you can look at the manual. I wish you good luck.&lt;/p&gt;

&lt;p&gt;See &lt;code&gt;man zshcompwid&lt;/code&gt; for patterns for the style matcher list (search for "COMPLETION MATCHING CONTROL").&lt;/p&gt;

&lt;h2&gt;
  
  
  Completion via Keystrokes
&lt;/h2&gt;

&lt;p&gt;You can bind any completion style to a keystroke instead of using it with the general completion. For that, you need to use the completer &lt;code&gt;_generic&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, if you want to expand aliases each time you hit &lt;code&gt;CTRL+a&lt;/code&gt;, you can add the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zle &lt;span class="nt"&gt;-C&lt;/span&gt; alias-expension complete-word _generic
bindkey &lt;span class="s1"&gt;'^a'&lt;/span&gt; alias-expension
zstyle &lt;span class="s1"&gt;':completion:alias-expension:*'&lt;/span&gt; completer _expand_alias
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can replace &lt;code&gt;alias-expension&lt;/code&gt; by the name of your choice. The behavior depends of the completer you use; for expanding aliases, we use &lt;code&gt;_expand_alias&lt;/code&gt;. Feel free to use whatever completer you want for your own needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Module complist
&lt;/h2&gt;

&lt;p&gt;I wrote already about the module "complist" &lt;a href="https://thevaluable.dev/zsh-install-configure-mouseless/" rel="noopener noreferrer"&gt;in this article&lt;/a&gt;. We saw there how to move around in the completion menu using the keys "hjkl":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zmodload zsh/complist
bindkey &lt;span class="nt"&gt;-M&lt;/span&gt; menuselect &lt;span class="s1"&gt;'h'&lt;/span&gt; vi-backward-char
bindkey &lt;span class="nt"&gt;-M&lt;/span&gt; menuselect &lt;span class="s1"&gt;'k'&lt;/span&gt; vi-up-line-or-history
bindkey &lt;span class="nt"&gt;-M&lt;/span&gt; menuselect &lt;span class="s1"&gt;'j'&lt;/span&gt; vi-down-line-or-history
bindkey &lt;span class="nt"&gt;-M&lt;/span&gt; menuselect &lt;span class="s1"&gt;'l'&lt;/span&gt; vi-forward-char
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can configure many more keystrokes related to the completion menu using these commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;accept-line&lt;/code&gt; - Validate the selection and leave the menu.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;send-break&lt;/code&gt; - Leaves the menu selection and restore the previous command.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;clear-screen&lt;/code&gt; - Clear the screen without leaving the menu selection.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;accept-and-hold&lt;/code&gt; - Insert the match in your command and let the completion menu open to insert another match.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;accept-and-infer-next-history&lt;/code&gt; - Insert the match and, in case of directories, open completion menu to complete its children.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;undo&lt;/code&gt; - Undo.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vi-forward-blank-word&lt;/code&gt; - Move cursor to next group of match.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vi-backward-blank-word&lt;/code&gt; - Move cursor to previous group of match.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;beginning-of-buffer-or-history&lt;/code&gt; - Move the cursor to the leftmost column.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;end-of-buffer-or-history&lt;/code&gt; - Move the cursor to the rightmost column.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vi-insert&lt;/code&gt; - Toggle between normal and interactive mode. We've seen the interactive mode above.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;history-incremental-search-forward&lt;/code&gt; and &lt;code&gt;history-incremental-search-backward&lt;/code&gt; - Begin incremental search.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, I've configured &lt;code&gt;CTRL+x i&lt;/code&gt; to switch to the interactive mode in the completion menu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bindkey &lt;span class="nt"&gt;-M&lt;/span&gt; menuselect &lt;span class="s1"&gt;'^xi'&lt;/span&gt; vi-insert
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;code&gt;man zshmodules&lt;/code&gt; to configure complist (search for "THE ZSH/COMPLIST MODULE").&lt;/p&gt;

&lt;h2&gt;
  
  
  Completion Options
&lt;/h2&gt;

&lt;p&gt;You can also use options to modify the Zsh completion system. To set an option, you need to use the command &lt;code&gt;setopt&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;setopt MENU_COMPLETE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a small selection of useful options for configuring the completion system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ALWAYS_TO_END&lt;/code&gt; - Always place the cursor to the end of the word completed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LIST_PACKED&lt;/code&gt; - The completion menu takes less space.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AUTO_MENU&lt;/code&gt; - Display the completion menu after two use of the &lt;code&gt;TAB&lt;/code&gt; key.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AUTO_COMPLETE&lt;/code&gt; - Select the first match given by the completion menu. Override &lt;code&gt;AUTO_MENU&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AUTO_PARAM_SLASH&lt;/code&gt; - When a directory is completed, add a trailing slash instead of a space.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;COMPLETE_IN_WORD&lt;/code&gt; - By default, the cursor goes at the end of the word when completion start. Setting this will not move the cursor and the completion will happen on both end of the word completed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GLOB_COMPLETE&lt;/code&gt; - Trigger the completion after a glob &lt;code&gt;*&lt;/code&gt; instead of expanding it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LIST_ROWS_FIRST&lt;/code&gt; - Matches are sorted in rows instead of columns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See &lt;code&gt;man zshoptions&lt;/code&gt; for the completion options (search for "Completion").&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready to Complete?
&lt;/h2&gt;

&lt;p&gt;The Zsh completion system is a complex beast, but I tried to do my best to simplify it. I hope it didn't cause any headache on your side.&lt;/p&gt;

&lt;p&gt;What did we learn together in this article?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The completion system go through a series of &lt;em&gt;completers&lt;/em&gt; first. They'll try to find matches depending on the context (the command you've typed) using different completion functions.&lt;/li&gt;
&lt;li&gt;The Zsh module "zstyle" allows you to configure settings for a specific Zsh module or widget. Don't let the name &lt;code&gt;style&lt;/code&gt; fools you: it can configure way more than visual styles.&lt;/li&gt;
&lt;li&gt;You can configure the Zsh completion system using options and the module complist, but using zstyle is the most flexible way to tune it following your craziest wishes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you see, the completion system of Zsh is far from being simple. I've covered some of the basics here, but there's much more. Let me know if you want a follow-up article to dive even deeper in this madness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://zsh.sourceforge.net/Doc/Release/Completion-System.html" rel="noopener noreferrer"&gt;Zsh Documentation - The Completion System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html#Visual-effects" rel="noopener noreferrer"&gt;Zsh Documentation - Visual Effects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Phantas0s/.dotfiles/blob/master/zsh/completion.zsh" rel="noopener noreferrer"&gt;Author's configuration for the Zsh completion system&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/sorin-ionescu/prezto/blob/master/modules/completion/init.zsh" rel="noopener noreferrer"&gt;Completions from the prezto framework&lt;/a&gt; - Robby Russell, Sorin Ionescu, and contributors&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Becoming Mouseless
&lt;/h2&gt;

&lt;p&gt;Do you want to build a &lt;a href="https://themouseless.dev" rel="noopener noreferrer"&gt;Mouseless Development Environment&lt;/a&gt; where the Linux shell has a central role?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://themouseless.dev" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthemouseless.dev%2Fimages%2Fsmall_cover.webp" alt="building your mouseless development environment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Switching between the keyboard and the mouse costs cognitive energy. This book will guide you step by step to set up a Linux-based development environment that keeps your hands on your keyboard.&lt;/p&gt;

&lt;p&gt;Take the brain power you've been using to juggle input devices and focus it where it belongs: on what you create.&lt;/p&gt;




</description>
      <category>zsh</category>
      <category>terminal</category>
      <category>productivity</category>
      <category>shell</category>
    </item>
    <item>
      <title>What's The Vim Runtime? A Guide With Examples</title>
      <dc:creator>Matthieu Cneude</dc:creator>
      <pubDate>Mon, 06 Dec 2021 10:46:37 +0000</pubDate>
      <link>https://forem.com/phantas0s/whats-the-vim-runtime-a-guide-with-examples-43id</link>
      <guid>https://forem.com/phantas0s/whats-the-vim-runtime-a-guide-with-examples-43id</guid>
      <description>&lt;p&gt;Have you ever wonder what was The Beginning of All Things™?&lt;/p&gt;

&lt;p&gt;In other words: have you ever wonder what Vim is doing when you start it? What files are sourced, why, and in what order? If you don't really care, I encourage you to reconsider your position. Knowing what Vim is doing at startup lets you speed it up, overwrites some defaults from the plugins you've installed, or even creates your own filetypes. In short, it gives you even more power to customize Vim to your precise needs.&lt;/p&gt;

&lt;p&gt;In this article, we'll look at two main ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What happens during Vim's startup.&lt;/li&gt;
&lt;li&gt;What are the runtime paths, what's sourced from there, and when.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article assumes that you have some advanced knowledge about Vim. If you don't, you can read my &lt;a href="https://thevaluable.dev/vim-beginner/"&gt;series of article to learn Vim from the ground up&lt;/a&gt;. More specifically, a lot of knowledge in this article is built on &lt;a href="https://thevaluable.dev/vim-expert/"&gt;Vim for Expert Users&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Take your headlamp and a good rope, we'll go exploring today many paths in our filesystems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vim's Startup
&lt;/h2&gt;

&lt;p&gt;When you start Vim, many things happen behind the curtain before your favorite cursor is displayed on the screen. I describe here a simplified version, trying to underline the most important steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Startup's Order
&lt;/h3&gt;

&lt;p&gt;Here's what Vim will do when you run it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set the shell options (useful for the command &lt;code&gt;:!&lt;/code&gt;, and for Vim's terminal).&lt;/li&gt;
&lt;li&gt;Process the arguments given to the CLI. Buffers are created for all files given as arguments.&lt;/li&gt;
&lt;li&gt;The value of the environment variable &lt;code&gt;$VIMINIT&lt;/code&gt; (an Ex command) is executed.&lt;/li&gt;
&lt;li&gt;Source the user's vimrc file.&lt;/li&gt;
&lt;li&gt;The value of the environment variable &lt;code&gt;$EXINIT&lt;/code&gt; (an Ex command) is executed.&lt;/li&gt;
&lt;li&gt;If the option "exrc" is set, Vim will try to find and load a vimrc in the working directory. Keep in mind however that setting "exrc" is not secure.&lt;/li&gt;
&lt;li&gt;Source filetypes, filetype plugins, and indent plugins. We'll see them below.&lt;/li&gt;
&lt;li&gt;Source syntax highligting scripts.&lt;/li&gt;
&lt;li&gt;Source plugin's scripts.&lt;/li&gt;
&lt;li&gt;Load runtime's and plugin's scripts from the "after" folder.&lt;/li&gt;
&lt;li&gt;Source the shada file (for Neovim) or the viminfo file (for Vim).&lt;/li&gt;
&lt;li&gt;Execute the options given to Vim affecting the startup.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's add more precisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you want to run more than one command using &lt;code&gt;$VIMINIT&lt;/code&gt;, you can separate them with the symbol &lt;code&gt;|&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Your vimrc file can be:

&lt;ul&gt;
&lt;li&gt;In Vimscript for Vim (located at &lt;code&gt;$HOME/.vimrc&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;In Lua &lt;strong&gt;or&lt;/strong&gt; Vimscript for Neovim (located in &lt;code&gt;$HOME/.config/nvim/init.vim&lt;/code&gt;, or &lt;code&gt;$XDG_CONFIG_HOME/nvim/init.vim&lt;/code&gt; if &lt;code&gt;$XDG_CONFIG_HOME&lt;/code&gt; is set).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Setting the option &lt;code&gt;exrc&lt;/code&gt; can be dangerous: Vim can load potentially unsecure vimrc files you might have downloaded with other files.&lt;/li&gt;
&lt;li&gt;You can use the option &lt;code&gt;-u &amp;lt;another_vimrc&amp;gt;&lt;/code&gt; when you run Vim in your terminal, to load another vimrc file instead of the default one. You can also use of of these value instead of a vimrc for debug purposes:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;NORC&lt;/code&gt; - Don't load any vimrc but load your plugins.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NONE&lt;/code&gt; - Don't load any vimrc nor plugins.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;You can run any command using the options &lt;code&gt;-c&lt;/code&gt; or &lt;code&gt;+&lt;/code&gt;. For example: &lt;code&gt;vim +"set shiftwidth=4|echo 'hello'"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Profiling Vim's Startup
&lt;/h3&gt;

&lt;p&gt;If Vim does terrible things at startup and you don't understand how to fix it, you can use the option &lt;code&gt;-V&lt;/code&gt; to have more details about the startup process.&lt;/p&gt;

&lt;p&gt;If you're startup is too slow and you want to find the bottleneck, you can profile it with &lt;code&gt;vim --startuptime &amp;lt;file&amp;gt;&lt;/code&gt;. It will write every files loaded (with timestamps) in the file &lt;code&gt;&amp;lt;file&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Special Environment Variables
&lt;/h3&gt;

&lt;p&gt;Two environment variables are only defined when Vim starts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$VIM&lt;/code&gt; - Used to locate various user files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$VIMRUNTIME&lt;/code&gt; - Used to locate various support files for Vim. We'll speak more about the runtime below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can look at the value of these variable with the command &lt;code&gt;:echo $VIM&lt;/code&gt; for example. If you define these environment variables in your shell, Vim won't overwrite them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help startup&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help slow-start&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help 'shell'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help $VIM&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help $VIMRUNTIME&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Runtime Path
&lt;/h2&gt;

&lt;p&gt;The runtime path is similar to the environment variable PATH in Unix-based systems. Vim will search in these paths to locate and source many different files during startup. To see all of these paths, you can look at the value of the option &lt;code&gt;runtimepath&lt;/code&gt;, by running the command &lt;code&gt;:set runtimepath?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you use Vim, it's likely that you'll see &lt;code&gt;$HOME/.vim&lt;/code&gt; as the first path of the list. If you're a Neovim adept, it will be &lt;code&gt;$HOME/.config/nvim&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The subdirectories of the runtime paths have different meanings according to their names. The Vimscript files inside these directories will be sourced at different times during startup, sometimes in different ways.&lt;/p&gt;

&lt;h3&gt;
  
  
  Important Runtime Paths
&lt;/h3&gt;

&lt;p&gt;Here are some important runtime paths. Vim will parse them in this order:&lt;/p&gt;

&lt;p&gt;For Vim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$HOME/.vim&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$VIM/vimfiles&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$VIM/vimfiles/after&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$HOME/.vim/after&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Neovim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$XDG_CONFIG_HOME/nvim&lt;/code&gt; (or &lt;code&gt;~/.config/nvim&lt;/code&gt; if &lt;code&gt;$XDG_CONFIG_HOME&lt;/code&gt; is not set)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$XDG_CONFIG_HOME/nvim/after&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Subdirectories of the Runtime Paths
&lt;/h3&gt;

&lt;p&gt;As I was writing above, the configuration files in the runtime paths contains different things depending of the subdirectory they're in. Here's an overview of the most useful of these subdirectories, and how you can use them to customize Vim even further.&lt;/p&gt;

&lt;p&gt;I encourage you to look at the default configuration files to understand the meaning of these subdirectories. They are in the directory set in the variable &lt;code&gt;$VIMRUNTIME&lt;/code&gt;. Don't forget that you can only read the value of &lt;code&gt;$VIMRUNTIME&lt;/code&gt; after launching Vim.&lt;/p&gt;

&lt;p&gt;You can also find examples in my &lt;a href="https://github.com/Phantas0s/.dotfiles/tree/master/nvim"&gt;own dotfiles&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  ftplugin
&lt;/h4&gt;

&lt;p&gt;The subdirectory &lt;em&gt;ftplugin&lt;/em&gt; (for &lt;code&gt;f&lt;/code&gt;ile&lt;code&gt;t&lt;/code&gt;ype &lt;code&gt;plugin&lt;/code&gt;) allow you to load pieces of configuration each time you open a buffer with a specific filetype.&lt;/p&gt;

&lt;p&gt;For example, let's say that you need a couple of mappings only for markdown files. You can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a markdown file and verify that the filetype is indeed markdown, by running the command &lt;code&gt;:set filetype?&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create the file &lt;code&gt;markdown.vim&lt;/code&gt; in &lt;code&gt;$HOME/.vim/ftplugin&lt;/code&gt; for Vim, or &lt;code&gt;$XDG_CONFIG_HOME/nvim/ftplugin&lt;/code&gt; for Neovim.&lt;/li&gt;
&lt;li&gt;Add options and mappings only for markdown files in there. For example: &lt;code&gt;setlocal spell&lt;/code&gt; will enable spelling each time you open a markdown file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You need to keep in mind, however, that each time a buffer with the filetype &lt;code&gt;markdown&lt;/code&gt; is created, the file &lt;code&gt;ftplugin/markdown.vim&lt;/code&gt; will be sourced. As a result, you need to make sure that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're resetting any autocommand each time the file is sourced (using an autocommand group and &lt;code&gt;:au!&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Every mapping you're creating have the special argument &lt;code&gt;&amp;lt;buffer&amp;gt;&lt;/code&gt;, for example &lt;code&gt;map &amp;lt;buffer&amp;gt; &amp;lt;leader&amp;gt;h echo "hello"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You're using &lt;code&gt;setlocal&lt;/code&gt; instead of &lt;code&gt;set&lt;/code&gt; to set options.&lt;/li&gt;
&lt;li&gt;You're using the &lt;code&gt;-buffer&lt;/code&gt; argument for any user command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don't respect these rules, your pieces of configuration won't only be loaded for the buffers with a precise filetype, but for every buffer, globally.&lt;/p&gt;

&lt;h4&gt;
  
  
  autoload
&lt;/h4&gt;

&lt;p&gt;The subdirectory autoload is also very useful. It lets you load your custom functions when you call them, instead of loading them when Vim starts. As a result, it can significantly speed up Vim's startup. These functions need to begin with the path of the file they're written in, for Vim to know where to find them when you call them. &lt;/p&gt;

&lt;p&gt;For example, you can create a new file &lt;code&gt;autoload/general.vim&lt;/code&gt; and use it to declare a new custom function &lt;code&gt;MyFunction&lt;/code&gt;. This function needs to be called &lt;code&gt;general#MyFunction&lt;/code&gt;, because it's declared in the file &lt;code&gt;general.vim&lt;/code&gt;. To call it, you can run &lt;code&gt;:call general#MyFunction&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also create subdirectories in the directory &lt;code&gt;autoload&lt;/code&gt;. For example, you can create the file &lt;code&gt;autoload/path/to/general.vim&lt;/code&gt;. In that case, you need to call your function &lt;code&gt;path#to#general#MyFunction&lt;/code&gt;, describing the location of the file itself.&lt;/p&gt;

&lt;p&gt;I encourage you to put all your custom functions in the "autoload" subdirectory.&lt;/p&gt;

&lt;h4&gt;
  
  
  syntax
&lt;/h4&gt;

&lt;p&gt;The subdirectory syntax lets you create your own syntax files. They're used for code highlighting for example. You can first create a syntax group matching some regex, and then you link your syntax group to highlight groups. These highlight groups will decide of the text's color displayed.&lt;/p&gt;

&lt;p&gt;Vim supports many syntaxes by default (you can see them in the directory &lt;code&gt;$VIMRUNTIME/syntax&lt;/code&gt;), I never had to create my own syntax groups. It's however good to know that you can do it in case you need it.&lt;/p&gt;

&lt;h4&gt;
  
  
  colors
&lt;/h4&gt;

&lt;p&gt;You can create highlight groups in the subdirectory colors. Each file represents a different color scheme. Again, you'll find different examples in the directory &lt;code&gt;$VIMRUNTIME/colors&lt;/code&gt;. To change the color scheme of your highlighting, you can use the command &lt;code&gt;:color &amp;lt;my_color_scheme&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  ftdetect
&lt;/h4&gt;

&lt;p&gt;Have you ever dreamed to create your own filetypes? That's great, because Vim is a dream machine. You can create your filetypes in the subdirectory "ftdetect".&lt;/p&gt;

&lt;p&gt;For example, if you have a bunch of file with the extension "new" and you want to create a filetype for them, you can: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the file &lt;code&gt;ftdetect/new.vim&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Write &lt;code&gt;au BufRead,BufNewFile *.new set filetype=new&lt;/code&gt; in it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also link some filetypes with other ones. For example, I wanted the files with the extension &lt;code&gt;.yaml.dist&lt;/code&gt; to have the &lt;code&gt;yaml&lt;/code&gt; filetype. So I've:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Created the file &lt;code&gt;ftdetect/yaml.dist.vim&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Written &lt;code&gt;autocmd BufNewFile,BufRead *.yml.dist set filetype=yaml&lt;/code&gt; in it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  compiler
&lt;/h4&gt;

&lt;p&gt;In Vim, you can use the command &lt;code&gt;:make&lt;/code&gt; to run a specific compiler, depending of the filetype of your current buffer.&lt;/p&gt;

&lt;p&gt;Under the hood, Vim will search a file named after the filetype of your current buffer, in the "compiler" directory. For example, if if you want to run the Golang compiler with precise options, you can create the file &lt;code&gt;compiler/go.vim&lt;/code&gt; and add whatever you need.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Directory after
&lt;/h3&gt;

&lt;p&gt;The subdirectory "after" is a special one. You can think of it as another runtime path in the runtime path, where you can add the same subdirectories we saw above.&lt;/p&gt;

&lt;p&gt;Everything in the after directory will be loaded &lt;em&gt;after&lt;/em&gt; everything else. You can also see it when you look at the order of the most important runtime path at the beginning of this section.&lt;/p&gt;

&lt;p&gt;From there, you can override anything you want: indentation, filetype plugins, or even the external plugins you've installed. For example, I can override Lisp indentation by creating the file &lt;code&gt;after/indent/lisp.vim&lt;/code&gt; and setting whatever options or variables I want to modify.&lt;/p&gt;

&lt;p&gt;I didn't cover the subdirectory &lt;code&gt;indent&lt;/code&gt; by the way, but I'm sure you can figure out its purpose.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Runtime Command
&lt;/h3&gt;

&lt;p&gt;If you want to source manually some files from your runtime path, you can use the command &lt;code&gt;:runtime &amp;lt;file&amp;gt;&lt;/code&gt;. For example, if you want to load every files from the &lt;code&gt;colors&lt;/code&gt; subdirectory, you can run &lt;code&gt;:runtime colors/**/*.vim&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also use &lt;code&gt;:runtime!&lt;/code&gt; (with a bang &lt;code&gt;!&lt;/code&gt;) to source everything.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disabling Runtime Files
&lt;/h3&gt;

&lt;p&gt;Finally, if you want to debug one of your runtime files, you can disable some of them by sourcing these specific files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:source $VIMRUNTIME/ftoff.vim&lt;/code&gt; - Disable the detection of filetypes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:source $VIMRUNTIME/ftplugin.vim&lt;/code&gt; - Enable ftplugin&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:source $VIMRUNTIME/ftplugof.vim&lt;/code&gt; - Disable ftplugin&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:source $VIMRUNTIME/indent.vim&lt;/code&gt; - Enable indentation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:source $VIMRUNTIME/indoff.vim&lt;/code&gt; - Disable indentation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help 'runtimepath'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help autoload&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help ftplugin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help syntax&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help new-filetype&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help after-directory&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Startup Has Been Revealed
&lt;/h2&gt;

&lt;p&gt;Now that you know what Vim's doing when it's starting, you can add your pieces of configuration in the good runtime subdirectory for more flexibility. You can also try to speed up your startup if you find it too slow.&lt;/p&gt;

&lt;p&gt;What did we see in this article?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vim load specific configuration files and environment variables at startup&lt;/li&gt;
&lt;li&gt;You can use the options &lt;code&gt;-V&lt;/code&gt; or &lt;code&gt;--startuptime&lt;/code&gt; to get more details regarding Vim's startup.&lt;/li&gt;
&lt;li&gt;The environment variable &lt;code&gt;$VIM&lt;/code&gt; and &lt;code&gt;$VIMRUNTIME&lt;/code&gt; are set during startup.&lt;/li&gt;
&lt;li&gt;The subdirectories in the runtime path have a meaning, sometimes affecting directly how they're loaded at startup, and when.&lt;/li&gt;
&lt;li&gt;The runtime path subdirectory "after" is a special one: it's a runtime path too (accepting the same subdirectories), and you can overwrite every other loaded config files in there.&lt;/li&gt;
&lt;li&gt;The command &lt;code&gt;:runtime&lt;/code&gt; allows you to manually load config files from your runtime paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I encourage you to experiment with all these configuration files to improve your config. Personally, I find the subdirectories "autoload" and "ftplugin" especially handy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Learning to Play Vim: A Fun Guide to Learn the Best Editor
&lt;/h2&gt;

&lt;p&gt;I began to write &lt;a href="https://themouseless.dev/vim"&gt;a very ambitious guide to learn Vim&lt;/a&gt; from the ground up. Thanks to great feedback from my readers, I'll be able to address the problems many beginners complain about when learning Vim. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to navigate in multiple files and projects in Vim?&lt;/li&gt;
&lt;li&gt;How to debug in Vim?&lt;/li&gt;
&lt;li&gt;How to search, find, and replace?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide will explain the most useful vanilla functionalities as well as some powerful plugins which will enrich your experience.&lt;/p&gt;

&lt;p&gt;Help me make an impact in the Vim world! You can subscribe to the newsletter and tell me everything you want to see in the book. Early bird discount guarantees!&lt;/p&gt;

&lt;p&gt;I reply to every email personally, so don't hesitate to ask as many questions as you want. It's always a pleasure to help.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://themouseless.dev/vim"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TX-zoMCr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://themouseless.dev/images/vim/book_cover_900.webp" alt="Learning to Play Vim" width="880" height="1245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last but not least: I've also written a book about building your own Mouseless Development Environment, so if you're interested by that too, &lt;a href="https://themouseless.dev"&gt;click on this shiny link&lt;/a&gt;.&lt;/p&gt;




</description>
      <category>vim</category>
      <category>terminal</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Do we have to deal with too much complexity?</title>
      <dc:creator>Matthieu Cneude</dc:creator>
      <pubDate>Tue, 02 Nov 2021 16:08:52 +0000</pubDate>
      <link>https://forem.com/phantas0s/do-we-have-to-deal-with-too-much-complexity-3faj</link>
      <guid>https://forem.com/phantas0s/do-we-have-to-deal-with-too-much-complexity-3faj</guid>
      <description>&lt;p&gt;I've been coding for 10+ years professionally (20 as a hobby) and something strikes me hard: it seems that our job gets more and more complex.&lt;/p&gt;

&lt;p&gt;To be a software engineer, we need to know how databases work, trendy programming languages, the 39020 services proposed by the cloud, containerization and orchestration (docker &amp;amp; kubernetes), the command line, algorithms, good practices... the list goes on. On top, most opinions about software development are just that: opinions. Nobody really agree, we just speak forever about what to do without empirical arguments. &lt;/p&gt;

&lt;p&gt;Is it possible nowadays to have one server, put a monolith on it, and maintain it as long as possible?&lt;/p&gt;

&lt;p&gt;Is it possible to bring back simplicity in this ocean of tools, practices, workflow, and opinions?&lt;/p&gt;

</description>
      <category>watercooler</category>
      <category>discuss</category>
      <category>complexity</category>
    </item>
    <item>
      <title>A Vim Guide for Expert Users</title>
      <dc:creator>Matthieu Cneude</dc:creator>
      <pubDate>Sat, 16 Oct 2021 16:07:46 +0000</pubDate>
      <link>https://forem.com/phantas0s/a-vim-guide-for-expert-users-137b</link>
      <guid>https://forem.com/phantas0s/a-vim-guide-for-expert-users-137b</guid>
      <description>&lt;p&gt;This article is the sixth of the series aimed to teach Vim from the ground up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-beginner/" rel="noopener noreferrer"&gt;Vim for Beginners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-intermediate/" rel="noopener noreferrer"&gt;Vim for Intermediate Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-advanced/" rel="noopener noreferrer"&gt;Vim for Advanced Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-adept/" rel="noopener noreferrer"&gt;Vim for Adept Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-veteran/" rel="noopener noreferrer"&gt;Vim for Veteran Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-expert/" rel="noopener noreferrer"&gt;Vim for Expert Users&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You're now in your garden, sitting down in your favorite chair, contemplating a fabulous table full of the tastiest food. While delighted by your fantastic breakfast, a fresh breeze refresh your warm skin in this hot summer day. You hear the little birds singing in unison. The vivid smell of the young grass and the delicate and subtle aroma of your tea fill your nostrils. Everything is in perfect harmony; all your annoyances, problems, or negative thoughts are far away from this pure state of bliss.&lt;/p&gt;

&lt;p&gt;Suddenly, you hear a strong and imposing voice from the sky. The clouds move quickly. You're flabbergasted: almost falling from your chair, you recognize the logo of the Sacred Vim formed by the cloud!&lt;/p&gt;

&lt;p&gt;The voice, which was only a growl, begins to speak:&lt;/p&gt;

&lt;p&gt;"My sweet friend! The time has come. You are now ready to begin the final step of your enlightenment. You will receive the Word of Vim!"&lt;/p&gt;

&lt;p&gt;A bright and supernatural light break through the cloud and hit your table. You suddenly understand The Truth of Vim! Quickly, you take a bunch of napkins and begin to write (with some strawberry marmalade) all the knowledge which is given to you at this precise moment.&lt;/p&gt;

&lt;p&gt;This article is a transcript of what was called later the Napkins of Power™. It helps customize Vim even further. More precisely, we'll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Special arguments you can use for your mappings.&lt;/li&gt;
&lt;li&gt;How to create operator pending mappings.&lt;/li&gt;
&lt;li&gt;The command &lt;code&gt;:execute&lt;/code&gt; and its benefits when combined with the command &lt;code&gt;:normal&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;What are autocommands and autocommand groups.&lt;/li&gt;
&lt;li&gt;Why and how to create custom functions.&lt;/li&gt;
&lt;li&gt;What are user commands and how to use them.&lt;/li&gt;
&lt;li&gt;What special strings you can use in your commands.&lt;/li&gt;
&lt;li&gt;A complete example to illustrate most of the ideas described in this article.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We've covered many Vim functionalities since the beginning of this series of article, and this new one add even more on these foundations. But it can be daunting to try to add everything to your workflow at once; instead, it's better to add what can help you in your daily workflow. &lt;/p&gt;

&lt;p&gt;You can create a virtuous circle: pick a new and useful functionally, use it in your day-to-day workflow, and, when you feel comfortable with it, reiterate.&lt;/p&gt;

&lt;p&gt;Are your ready to receive The Expertise? The knowledge of this article is dangerous; use it with care, always to make the world a better place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verbose Commands
&lt;/h2&gt;

&lt;p&gt;The more pieces of configuration and plugins you'll add to Vim, the more you'll wonder where they've been created in your config files. The command &lt;code&gt;:verbose&lt;/code&gt; can help you: it will output at what line of what file a precise configuration have been declared.&lt;/p&gt;

&lt;p&gt;More precisely, &lt;code&gt;:verbose&lt;/code&gt; can output the declarations of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abbreviations&lt;/li&gt;
&lt;li&gt;Options&lt;/li&gt;
&lt;li&gt;Mapping&lt;/li&gt;
&lt;li&gt;User commands&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, I've set the option &lt;code&gt;undodir&lt;/code&gt; in my vimrc. If I run &lt;code&gt;:verbose set undodir?&lt;/code&gt;, I'll get the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Last set from ~/.config/nvim/init.vim line 354
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keeping your configuration well organized and simple is the best strategy. But everything gets messy overtime, especially when experimenting with new configuration or plugins. I don't use verbose often but, when I need it, I'm always happy to have it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help :verbose-cmd&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mapping Special Arguments
&lt;/h2&gt;

&lt;p&gt;We've seen the basics of mapping &lt;a href="https://dev.to/vim-intermediate/"&gt;in a previous article&lt;/a&gt;, but we didn't speak about the special arguments it can take. Most of them can be used for abbreviations, too.&lt;/p&gt;

&lt;p&gt;Here are the most useful ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;silent&amp;gt;&lt;/code&gt; - Doesn't output the mapping in the Vim command-line. If you want to also drop the output of the command linked to the mapping, add the command &lt;code&gt;:silent&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;buffer&amp;gt;&lt;/code&gt; - The mapping's scope is reduced to the current buffer only. These mappings have the priority on the global ones.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;expr&amp;gt;&lt;/code&gt; - The mapping executes a Vimscript expression instead of a Vim command.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;unique&amp;gt;&lt;/code&gt; - The mapping fails if it already exists. It's useful if you don't want to override any mapping defined previously.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;Cmd&amp;gt;&lt;/code&gt; - The mapping can run a command without quitting the current mode you're in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A special argument should be used as first argument for any mapping or abbreviation. The argument &lt;code&gt;&amp;lt;Cmd&amp;gt;&lt;/code&gt; is an exception: it should be used just before the command itself.&lt;/p&gt;

&lt;p&gt;To understand how it works, let's take some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:nnoremap &amp;lt;silent&amp;gt; &amp;lt;leader&amp;gt;&amp;lt;f6&amp;gt; :source $MYVIMRC&amp;lt;CR&amp;gt;&lt;/code&gt; - The command &lt;code&gt;:source $MYVIMRC&lt;/code&gt; won't be displayed in the Vim command-line when hitting &lt;code&gt;LEADER F6&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:iab &amp;lt;expr&amp;gt; cdate strftime('%Y-%m-%d')&lt;/code&gt; - The Vimscript function &lt;code&gt;strftime&lt;/code&gt; is executed when the abbreviation &lt;code&gt;cdate&lt;/code&gt; is used.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:inoremap &amp;lt;c-d&amp;gt; &amp;lt;Cmd&amp;gt;delete&amp;lt;cr&amp;gt;&lt;/code&gt; - Execute the command &lt;code&gt;:delete&lt;/code&gt; without leaving INSERT mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:nnoremap &amp;lt;leader&amp;gt;&amp;lt;f6&amp;gt; :silent :source $MYVIMRC&amp;lt;CR&amp;gt;&lt;/code&gt; - The output of the command &lt;code&gt;:source $MYVIMRC&lt;/code&gt; will be dropped, thanks to the command &lt;code&gt;:silent&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll see a use case for the special argument &lt;code&gt;&amp;lt;buffer&amp;gt;&lt;/code&gt; below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help map-arguments&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Operator Pending Map
&lt;/h2&gt;

&lt;p&gt;Operators are NORMAL mode keystrokes which need to be combined with motions or text-objects. For example, &lt;code&gt;d&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;, or &lt;code&gt;y&lt;/code&gt; are operators. I've written about them in &lt;a href="https://dev.to/vim-beginner/"&gt;the very first article&lt;/a&gt; of this series.&lt;/p&gt;

&lt;p&gt;Vim lets you set a new motion for all existing operator with the command &lt;code&gt;:onoremap&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;onoremap &lt;span class="nb"&gt;ic&lt;/span&gt; &lt;span class="k"&gt;i&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've created here a new motion &lt;code&gt;ic&lt;/code&gt; to use an operator &lt;code&gt;i&lt;/code&gt;nside &lt;code&gt;c&lt;/code&gt;urly brackets. You can try it out to delete the content between two curly brackets for example, by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Placing the cursor inside the curly brackets.&lt;/li&gt;
&lt;li&gt;Hitting &lt;code&gt;dic&lt;/code&gt; in NORMAL mode.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The motions created with &lt;code&gt;:onoremap&lt;/code&gt; always begins where your cursor is. That's why we need to place our cursor inside the curly brackets in our previous example. But it would be even better if we could act on the next curly brackets without worrying where the cursor is. The following command will make this dream a reality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;onoremap nc &lt;span class="p"&gt;:&lt;/span&gt;normal&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="k"&gt;f&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;{&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's look at this example more closely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:normal&lt;/code&gt; - Execute keystrokes as if you were in NORMAL mode (see &lt;a href="https://dev.to/vim-advanced/"&gt;Vim for Advanced Users&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;f{&lt;/code&gt; - &lt;code&gt;f&lt;/code&gt;ind the next curly bracket on the line (see &lt;a href="https://dev.to/vim-beginner/"&gt;Vim for Beginners&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vi{&lt;/code&gt; - Switch to VISUAL mode and select &lt;code&gt;i&lt;/code&gt;nside the curly brackets.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;cr&amp;gt;&lt;/code&gt; - Key notation for the &lt;code&gt;ENTER&lt;/code&gt; key (&lt;code&gt;c&lt;/code&gt;arriage &lt;code&gt;r&lt;/code&gt;eturn, see &lt;a href="https://dev.to/vim-intermediate/"&gt;Vim for Intermediate Users&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The operator will be applied on the selection made in VISUAL mode. To illustrate this idea, let's look at the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;My super┃&lt;span class="nb"&gt;line&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;with curly brackets&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The symbol &lt;code&gt;┃&lt;/code&gt; represents the cursor position. If you hit the keystroke &lt;code&gt;dnc&lt;/code&gt;, you'll &lt;code&gt;d&lt;/code&gt;elete what's inside the &lt;code&gt;n&lt;/code&gt;ext &lt;code&gt;c&lt;/code&gt;urly bracket. The result will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;My super &lt;span class="nb"&gt;line&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cursor will end up on the last curly bracket.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help omap-info&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Command Execute
&lt;/h2&gt;

&lt;p&gt;Let's look again at the mapping we've set above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;onoremap nc &lt;span class="p"&gt;:&lt;/span&gt;normal&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="k"&gt;f&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;{&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key notation &lt;code&gt;&amp;lt;cr&amp;gt;&lt;/code&gt; is considered a special character when you create a mapping. It works with mappings, but it won't work with the &lt;code&gt;:normal&lt;/code&gt; command by itself. &lt;/p&gt;

&lt;p&gt;For example, you can try to run the following to replace the next occurrence of "emacs" with "vim":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;normal /emacs&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;ciwvim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time, Vim doesn't recognize &lt;code&gt;&amp;lt;cr&amp;gt;&lt;/code&gt; as a special character, so the command won't work. To go around this limitation, you can use &lt;code&gt;CTRL+V&lt;/code&gt; (see &lt;a href="https://dev.to/vim-adept/"&gt;Vim for Adept Users&lt;/a&gt;). In that precise case, we would need to hit &lt;code&gt;CTRL+V ENTER&lt;/code&gt; while writing our command. We would end up with something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;normal&lt;span class="p"&gt;!&lt;/span&gt; /emacs^Miwvim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command &lt;code&gt;:execute&lt;/code&gt; can solve our problem in a more elegant way. It lets you execute a command from a string. You can then use &lt;em&gt;string constants&lt;/em&gt; for these special characters, all prefixed with a &lt;code&gt;\&lt;/code&gt;. Here's an equivalent of our silly example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s2"&gt;"normal! /emacs\&amp;lt;cr&amp;gt;ciwvim"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the key notations you can use with &lt;code&gt;:map&lt;/code&gt; or &lt;code&gt;:abbreviate&lt;/code&gt; have their string constant equivalents.&lt;/p&gt;

&lt;p&gt;When you give multiple arguments to execute, they're concatenated into one string and separated with spaces. If you don't want the spaces, use a dot instead. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;'echo "this" "is" "a" "str"."ing"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will be: "this is a string".&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help execute&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help expr-quote&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Autocommands
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Basics
&lt;/h3&gt;

&lt;p&gt;Autocommands can automatically run a command when a specific event happens. More precisely, it adds a command to a &lt;em&gt;list of command&lt;/em&gt; linked to a precise event. When this event is fired, every command of the list of commands are executed.&lt;/p&gt;

&lt;p&gt;An event can be opening Vim, reading any file, or writing a markdown file for example.&lt;/p&gt;

&lt;p&gt;Here are the basics to manipulate autocommands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:autocmd &amp;lt;event&amp;gt; &amp;lt;pattern&amp;gt; &amp;lt;cmd&amp;gt;&lt;/code&gt; or &lt;code&gt;:au &amp;lt;event&amp;gt; &amp;lt;pattern&amp;gt; &amp;lt;cmd&amp;gt;&lt;/code&gt; - Add the command &lt;code&gt;&amp;lt;cmd&amp;gt;&lt;/code&gt; to the list of commands executed automatically when the event &lt;code&gt;&amp;lt;event&amp;gt;&lt;/code&gt; is fired. The pattern &lt;code&gt;&amp;lt;pattern&amp;gt;&lt;/code&gt; filter the files where the autocommand should be applied.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:autocmd &amp;lt;event&amp;gt;&lt;/code&gt; or &lt;code&gt;:au &amp;lt;event&amp;gt;&lt;/code&gt; - Output the list of commands executed when the event &lt;code&gt;&amp;lt;event&amp;gt;&lt;/code&gt; is fired.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:autocmd! &amp;lt;event&amp;gt;&lt;/code&gt; or &lt;code&gt;:au! &amp;lt;event&amp;gt;&lt;/code&gt; - Delete the list of autocommands of the event &lt;code&gt;&amp;lt;event&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To clarify all this jargon, here are some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:autocmd BufWrite * echom "Write..."&lt;/code&gt; - Output "Write" each time any file is saved. The wildcard &lt;code&gt;*&lt;/code&gt; means "every file".&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:autocmd BufNew *.md echom "Read..."&lt;/code&gt; - Output "Read" each time a new markdown buffer is created. Unsurprisingly, The pattern &lt;code&gt;*.md&lt;/code&gt; means every filename finishing with &lt;code&gt;.md&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After running these commands, you can try to write a file (command &lt;code&gt;:w&lt;/code&gt;) to see if it works. If you don't see the message in the command-line, run &lt;code&gt;:messages&lt;/code&gt; to display them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multiple Events and Patterns
&lt;/h3&gt;

&lt;p&gt;You can also create an autocommand with more than one event or pattern, separated with a comma. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;autocmd &lt;span class="nb"&gt;BufNew&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;BufWrite&lt;/span&gt; *&lt;span class="p"&gt;.&lt;/span&gt;md&lt;span class="p"&gt;,&lt;/span&gt;*&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;js&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;*&lt;span class="p"&gt;.&lt;/span&gt;php &lt;span class="k"&gt;echom&lt;/span&gt; &lt;span class="s2"&gt;"Create or write md, js, or php..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command &lt;code&gt;echom "Create or write md, js or php..."&lt;/code&gt; will run when a markdown, JavaScript, or PHP buffer is created (&lt;code&gt;BufNew&lt;/code&gt;) or saved (&lt;code&gt;BufWrite&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Note that the pattern can be a bit different depending on the events you listen to. For a description of all events available, see &lt;code&gt;:help autocommand-events&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, if you want the scope of the autocmd to be limited to the current buffer, you can use the special pattern &lt;code&gt;&amp;lt;buffer&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Autocommand Groups
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Using Autocommand Groups?
&lt;/h3&gt;

&lt;p&gt;As the name indicates, an autocommand group is a group of one or more autocommands. When you create an autocommand as we did above, it's added automatically to a default autocommand group without a name. You can create autocommand groups with names and add autocommands to it, too. You can think of it as namespaces for autocommands.&lt;/p&gt;

&lt;p&gt;To understand this concept, let's see where it's useful to use autocommand groups. As we saw, each time you create an autocommand, it's added to the list of command triggered when a specific event occurs; &lt;em&gt;even if this command is already part of the list&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let's look at an example. First, let's add this autocommand to your vimrc:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;autocmd &lt;span class="nb"&gt;BufWritePre&lt;/span&gt; * &lt;span class="k"&gt;echom&lt;/span&gt; &lt;span class="s2"&gt;"Write..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then try the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Source your virmc twice (by running &lt;code&gt;:source $MYVIMRC&lt;/code&gt; twice).&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;:autocmd BufWrite&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This last command will output the list of commands executed when the event &lt;code&gt;BufWrite&lt;/code&gt; is triggered. It will output something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="nb"&gt;BufWritePre&lt;/span&gt;
    *         &lt;span class="k"&gt;echom&lt;/span&gt; &lt;span class="s2"&gt;"Write..."&lt;/span&gt;
              &lt;span class="k"&gt;echom&lt;/span&gt; &lt;span class="s2"&gt;"Write..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command &lt;code&gt;echom "Write..."&lt;/code&gt; appears two times in the command list for the pattern &lt;code&gt;*&lt;/code&gt;. As a result, each time the event occurs on any file, the command will run &lt;em&gt;two times&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;More often than not, we want to add our commands to the command list only once. Otherwise, it will impact performances each time the event is fired and, if the command is not &lt;a href="https://en.wikipedia.org/wiki/Idempotence" rel="noopener noreferrer"&gt;idempotent&lt;/a&gt;, nasty bugs will pop up.&lt;/p&gt;

&lt;p&gt;Using autocommand groups can solve this problem. Here are the basic commands you can use to manipulate these groups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:augroup&lt;/code&gt; - Output all autocommand groups.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:augroup &amp;lt;name&amp;gt;&lt;/code&gt; or &lt;code&gt;aug &amp;lt;name&amp;gt;&lt;/code&gt; - Call a new autocommand group named &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt;. All autocommands created after this command will be part of the group.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:augroup! &amp;lt;name&amp;gt;&lt;/code&gt; or &lt;code&gt;aug! &amp;lt;name&amp;gt;&lt;/code&gt; - Delete the group named &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:augroup END&lt;/code&gt; - End the autocommand group. If you define an autocommand after this one, it won't be part of the group.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As always, here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;augroup &lt;span class="k"&gt;messages&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;autocmd &lt;span class="nb"&gt;BufWrite&lt;/span&gt; * &lt;span class="k"&gt;echom&lt;/span&gt; &lt;span class="s2"&gt;"Write..."&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;augroup END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The autocmd is now part of the autocommand group &lt;code&gt;messages&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By itself, it doesn't solve our problem. If you add the three lines above in your vimrc and source multiple times, the autocommand in the group &lt;code&gt;messages&lt;/code&gt; will be added to the autocommand list each time.&lt;/p&gt;

&lt;p&gt;We saw above that you can delete autocommands with the command &lt;code&gt;au! &amp;lt;event&amp;gt;&lt;/code&gt;. This will work if the autocommand is not in a named group. If you run &lt;code&gt;au! BufWrite&lt;/code&gt; for example, it will delete every autocommand in the nameless autocommand group (the default one), but not the one in the group &lt;code&gt;messages&lt;/code&gt; we've created above.&lt;/p&gt;

&lt;p&gt;To solve our problem, we could delete every autocommand belonging to the group &lt;code&gt;messages&lt;/code&gt; after creating the group itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;augroup &lt;span class="k"&gt;messages&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;au&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="k"&gt;messages&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;autocmd &lt;span class="nb"&gt;BufWrite&lt;/span&gt; * &lt;span class="k"&gt;echom&lt;/span&gt; &lt;span class="s2"&gt;"Write..."&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;augroup END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If these lines are in your vimrc and you source it three times, every autocommand will be deleted from the group &lt;code&gt;messages&lt;/code&gt; each time, before being added again. In short, our problem is solved: the command &lt;code&gt;echom "Write..."&lt;/code&gt;  will always appear once and only once in our list of command.&lt;/p&gt;

&lt;p&gt;When we use &lt;code&gt;au!&lt;/code&gt; between the initialization of the group (&lt;code&gt;augroup messages&lt;/code&gt;) and the end of the initialization (&lt;code&gt;augroup END&lt;/code&gt;), we don't have to indicate the name of the group. Vim will understand, in that case, that we want to delete every autocommand of the group declared just before. In short, the following commands are equivalent to the ones above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;augroup &lt;span class="k"&gt;messages&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;au&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;autocmd &lt;span class="nb"&gt;BufWrite&lt;/span&gt; * &lt;span class="k"&gt;echom&lt;/span&gt; &lt;span class="s2"&gt;"Write..."&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;augroup END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Redeclaring an autocommand group won't recreate it, but it will add autocommands in the existing group instead. For example, you can do something like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;augroup vimrc
&lt;span class="k"&gt;au&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
augroup END

augroup vimrc
    autocmd &lt;span class="nb"&gt;BufWrite&lt;/span&gt; * &lt;span class="k"&gt;echom&lt;/span&gt; &lt;span class="s2"&gt;"Write..."&lt;/span&gt;
augroup END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things happen here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A group &lt;code&gt;vimrc&lt;/code&gt; is declared.&lt;/li&gt;
&lt;li&gt;Autocommands are declared and added to the group &lt;code&gt;vimrc&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In short, every autocommand added to the group &lt;code&gt;vimrc&lt;/code&gt; is merged with the command &lt;code&gt;:au!&lt;/code&gt;. You can even do better: when you create an autocommand, you can add it to an existing group directly. To do that, you can indicate the name of the group just between the command &lt;code&gt;autocmd&lt;/code&gt; and the event name as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;augroup vimrc
&lt;span class="k"&gt;au&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
augroup END

autocmd vimrc &lt;span class="nb"&gt;BufWrite&lt;/span&gt; * &lt;span class="k"&gt;echom&lt;/span&gt; &lt;span class="s2"&gt;"Write..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're now able to reload your vimrc as much as you want, your autocommands will only appear once in the autocommand list. It applies for other sourced files too, like the ones you might have in your folder &lt;code&gt;ftplugin&lt;/code&gt; for example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ignoring Events
&lt;/h3&gt;

&lt;p&gt;If you want to run a command without firing any event, you can use the command &lt;code&gt;:noautocmd&lt;/code&gt;. To take our previous example, if you want to ignore the event &lt;code&gt;BufWrite&lt;/code&gt; when running the command &lt;code&gt;:w&lt;/code&gt;, you can run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:noautocmd w
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help autocmd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help autocommand-events&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help autocmd-events-abc&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Custom Functions
&lt;/h2&gt;

&lt;p&gt;Writing custom functions for Vim to make your craziest dreams come true should be the goal of any Vim Follower out there. &lt;/p&gt;

&lt;p&gt;It's true that many functions are already available on the infinite Internet. You can simply copy and paste them without worrying how they work. That said, knowing the basics of Vimscript functions can allow you to adapt them to your needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking Existing Functions
&lt;/h3&gt;

&lt;p&gt;Let's see first how you can display the functions already available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:function&lt;/code&gt; or &lt;code&gt;:fu&lt;/code&gt; - List all declared function.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:function /&amp;lt;pattern&amp;gt;&lt;/code&gt; or &lt;code&gt;:fu /&amp;lt;pattern&amp;gt;&lt;/code&gt; - Filter all declared functions with the pattern &lt;code&gt;&amp;lt;pattern&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Creating Or Copying Functions
&lt;/h3&gt;

&lt;p&gt;Looking at a simple function will help us understand how they work. Here's one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; DeleteTrailingWS&lt;span class="p"&gt;()&lt;/span&gt; abort
    normal &lt;span class="k"&gt;mz&lt;/span&gt;
    %s&lt;span class="sr"&gt;/\v\s+$/&lt;/span&gt;/ge
    normal `z
endfunc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function delete trailing whitespaces in a whole buffer. Let's look at it in more details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;function&lt;/code&gt; - Keyword to declare a function. You can add a bang (&lt;code&gt;function!&lt;/code&gt;) to overwrite a previously declared function with the same name.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DeleteTrailingWS&lt;/code&gt; - Name of the function. It should always begin with an uppercase letter.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;abort&lt;/code&gt; - Stop the function when an error occurs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be careful if you use &lt;code&gt;function!&lt;/code&gt; (with a bang): you might overwrite a function from one of your plugin. It can open the door to random bugs difficult to fix.&lt;/p&gt;

&lt;p&gt;If you look at the body of our function, they are simply Vim commands. They are executed in order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;normal mz&lt;/code&gt; - Save the cursor position using the mark &lt;code&gt;z&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%s/\v\s+$//ge&lt;/code&gt; - Delete every whitespace in the current buffer, using the substitute command.

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;%&lt;/code&gt; - Range for the whole buffer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\v&lt;/code&gt; - Use the &lt;code&gt;v&lt;/code&gt;ery magic mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\s&lt;/code&gt; - Represent any whitespace.&lt;/li&gt;
&lt;li&gt;Flag &lt;code&gt;e&lt;/code&gt; - Doesn't output an error if the search pattern fail.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;normal&lt;/code&gt;&lt;code&gt;z&lt;/code&gt; - Go back to the mark &lt;code&gt;z&lt;/code&gt; (the cursor position when the function was invoked).&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;I've already written about all these commands in &lt;a href="https://dev.to/vim-advanced/"&gt;Vim for Advanced Users&lt;/a&gt;. For more details about Vim regexes, see &lt;a href="https://dev.to/vim-adept/"&gt;Vim for Adept Users&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can then call the function using the command &lt;code&gt;:call&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt; DeleteTrailingWS&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also create a new mapping for some of your function if you want to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;nnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;ds&lt;/span&gt; &lt;span class="k"&gt;call&lt;/span&gt; DeleteTrailingWS&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Autoloading Functions
&lt;/h3&gt;

&lt;p&gt;You can create function in your vimrc directly as we did above, but it might create some problems. Imagine that the name of the function conflict with a function from one of your plugin: the bugs occuring can be difficult to debug. &lt;/p&gt;

&lt;p&gt;Additionally, all the functions declared in your vimrc will be automatically loaded when you open Vim, even if you never use them. It would be more efficient to load them when you call them the first time.&lt;/p&gt;

&lt;p&gt;It's where the &lt;em&gt;autoload folder&lt;/em&gt; comes in handy. This folder is located in the Vim's runtime paths.&lt;/p&gt;

&lt;p&gt;When Vim needs to find something, it will look at the Vim's runtime paths. The folder containing your vimrc is one of these paths, for example. To display all of them, you can run the command &lt;code&gt;:set runtimepath?&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The folder autoload is one of these paths too. Any function created in this folder will have namespaces, and they will be loaded on demand. Exactly what we want!&lt;/p&gt;

&lt;p&gt;You can create the autoload folder where your vimrc is. Then, you can create Vimscript files in there; the name of the file will be the namespace for your functions.&lt;/p&gt;

&lt;p&gt;For example, you can create the file "general.vim" in the autoload folder. Then, you can write in the file the following function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; general#DeleteTrailingWS&lt;span class="p"&gt;()&lt;/span&gt; abort
    normal &lt;span class="k"&gt;mz&lt;/span&gt;
    %s&lt;span class="sr"&gt;/\v\s+$/&lt;/span&gt;/ge
    normal `z
endfunc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you call the function with &lt;code&gt;:call general#DeleteTrailingWS()&lt;/code&gt;, Vim will: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Look inside the autoload directory for a file called &lt;code&gt;general&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Search for a function called &lt;code&gt;DeleteTrailingWS&lt;/code&gt; inside this file.&lt;/li&gt;
&lt;li&gt;Load and execute the function.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Additionally, you can easily display every function for the namespace &lt;code&gt;&amp;lt;namespace&amp;gt;&lt;/code&gt; by running the command &lt;code&gt;:function /&amp;lt;namespace&amp;gt;&lt;/code&gt;. For example, if you want to display all the functions for the namespace &lt;code&gt;general&lt;/code&gt;, run &lt;code&gt;:function /general&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For more fine-grained namespaces, you can add sub-directories in the autoload directory. For example, you can create the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;autoload/my/super/namespace.vim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you'll need to add the namespace "my#super#namespace" to the functions you create in the file &lt;code&gt;namespace.vim&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; my#super#namespace#DeleteTrailingWS&lt;span class="p"&gt;()&lt;/span&gt; abort
    normal &lt;span class="k"&gt;mz&lt;/span&gt;
    %s&lt;span class="sr"&gt;/\v\s+$/&lt;/span&gt;/ge
    normal `z
endfunc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help functions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help autoload-function&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help call&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help 'runtimepath'&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  User Commands
&lt;/h2&gt;

&lt;p&gt;Now that we're able to create our own functions, what about increasing our power with our own custom Vim commands? We'll then be able to run these user commands using the COMMAND-LINE mode, like any other command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basics
&lt;/h3&gt;

&lt;p&gt;Like functions, custom user commands should always begin with an uppercase letter, to differentiate them from Vim's built-in commands.&lt;/p&gt;

&lt;p&gt;Continuing our ritual, here are three useful commands to manipulate user commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:command&lt;/code&gt; or &lt;code&gt;:com&lt;/code&gt; - Output all user commands.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:command &amp;lt;command&amp;gt;&lt;/code&gt; or &lt;code&gt;:com &amp;lt;command&amp;gt;&lt;/code&gt; - Output all user commands starting with &lt;code&gt;&amp;lt;command&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:command &amp;lt;attributes&amp;gt; &amp;lt;name&amp;gt; &amp;lt;cmd&amp;gt;&lt;/code&gt; or &lt;code&gt;:com &amp;lt;attributes&amp;gt; &amp;lt;name&amp;gt; &amp;lt;cmd&amp;gt;&lt;/code&gt; - Define a new user command with the name &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt; running the command &lt;code&gt;&amp;lt;cmd&amp;gt;&lt;/code&gt;. The attributes &lt;code&gt;&amp;lt;attributes&amp;gt;&lt;/code&gt; indicate the number of arguments (among other things).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Similarly to custom functions, you can add a bang when you declare a command (&lt;code&gt;:command!&lt;/code&gt;). In that case, if a command already exists with the same name, it will be overwritten.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attributes for User Commands
&lt;/h3&gt;

&lt;p&gt;There are four different categories of attribute you can use when creating a user command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Argument handling&lt;/li&gt;
&lt;li&gt;Range handling&lt;/li&gt;
&lt;li&gt;Completion behavior&lt;/li&gt;
&lt;li&gt;Special cases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll only cover the most important one in this article: the argument handling. It allows us to specify the number of argument a user command can take, with the attribute &lt;code&gt;-nargs&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-nargs=0&lt;/code&gt; - No argument allowed (default).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-nargs=1&lt;/code&gt; - One argument is required.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-nargs=*&lt;/code&gt; - Any number of arguments allowed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-nargs=?&lt;/code&gt; - 0 or 1 argument allowed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-nargs=+&lt;/code&gt; - One argument or more are required.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To indicate where the arguments should be inserted in the command, you need to use the placeholder &lt;code&gt;&amp;lt;args&amp;gt;&lt;/code&gt;. For example, you can write the following in your vimrc:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; IScream&lt;span class="p"&gt;(&lt;/span&gt;content&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;echom&lt;/span&gt; &lt;span class="nb"&gt;toupper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;a:content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;

command &lt;span class="p"&gt;-&lt;/span&gt;nargs&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; Scream &lt;span class="k"&gt;call&lt;/span&gt; IScream&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;args&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, you can call the arguments of a function in its body using &lt;code&gt;a:&amp;lt;arg_name&amp;gt;&lt;/code&gt;. To try your new user command, source your vimrc with &lt;code&gt;:source $MYVIMRC&lt;/code&gt; and run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;Scream &lt;span class="s2"&gt;"hello"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a user command call a function which can take multiple arguments, you need to separate them with whitespaces and use the placeholder &lt;code&gt;&amp;lt;f-args&amp;gt;&lt;/code&gt; instead of &lt;code&gt;&amp;lt;args&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If there is only one argument allowed, Vim will consider the whitespace as part of the argument itself.&lt;/p&gt;

&lt;p&gt;Finally, if you need your user command to be only available in the current buffer, you can also add the attribute &lt;code&gt;-buffer&lt;/code&gt;. It's mandatory if you create user commands in your runtime folder &lt;code&gt;ftplugin&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help user-commands&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Special Strings for Vim Commands
&lt;/h2&gt;

&lt;p&gt;Let's now look at special strings you can use in COMMAND-LINE mode. These placeholders will be replaced under the hood with their representations. Here's a list of the most useful ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;%&lt;/code&gt; - Relative path of the current file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;cword&amp;gt;&lt;/code&gt; - Word under the cursor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;cWORD&amp;gt;&lt;/code&gt; - WORD under the cursor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;cfile&amp;gt;&lt;/code&gt; - Filepath under the cursor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;afile&amp;gt;&lt;/code&gt; - File open in the buffer when executing autocommands.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;sfile&amp;gt;&lt;/code&gt; - Filename of sourced file when used with command &lt;code&gt;:source&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also use the following with &lt;code&gt;%&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:p&lt;/code&gt; - Output the absolute path instead of the relative one. Also expand the tilda &lt;code&gt;~&lt;/code&gt; to the home directory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:.&lt;/code&gt; - Make the file path relative to the working directory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:~&lt;/code&gt; - Make the file path relative to the home directory (if possible).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:h&lt;/code&gt; - Keep the &lt;code&gt;h&lt;/code&gt;ead of the file path (remove the last element).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:t&lt;/code&gt; - Keep the &lt;code&gt;t&lt;/code&gt;ail of the file path (remove everything except the last element).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:r&lt;/code&gt; - Keep the &lt;code&gt;r&lt;/code&gt;oot of the file name (remove its extension).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:e&lt;/code&gt; - Remove everything except the &lt;code&gt;e&lt;/code&gt;xtension of the filename.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:s?pat?sub?&lt;/code&gt; - Substitute the first occurrence of "pat" with "sub".&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:gs?pat?sub?&lt;/code&gt; - Substitute all occurrences of "pat" with "sub".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These special strings only work when a command expects a filename as argument; as a result, it makes this functionality quite limited. Fortunately, You can use the function &lt;code&gt;expand(&amp;lt;special_string&amp;gt;)&lt;/code&gt; to expand these placeholders in any command.&lt;/p&gt;

&lt;p&gt;For example, you can try to run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;echom&lt;/span&gt; &lt;span class="nb"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"%"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;echom&lt;/span&gt; &lt;span class="nb"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"%:p"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;echom&lt;/span&gt; &lt;span class="nb"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;cword&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a more useful example we already saw in the article &lt;a href="https://dev.to/vim-advanced/"&gt;Vim for Advanced Users&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;nnoremap gX &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;execute&lt;/span&gt;
&lt;span class="se"&gt;            \&lt;/span&gt; &lt;span class="s2"&gt;"!xdg-open"&lt;/span&gt; &lt;span class="nb"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'%:p:h'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"/"&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;cfile&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s2"&gt;" &amp;amp;"&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now be able to understand this command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;silent&amp;gt;&lt;/code&gt; - The mapping won't appear in the command line when used.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;execute&lt;/code&gt; - Execute a string as a Vim command.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;expand('%:p:h')&lt;/code&gt; - Output the head of the absolute path.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;expand("&amp;lt;cfile&amp;gt;")&lt;/code&gt; - Output the filepath under the cursor in the current buffer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, this mapping will open the relative filepath under the cursor using the CLI &lt;code&gt;xdg-open&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This command shouldn't take more than one line, but the backslash &lt;code&gt;\&lt;/code&gt; allows us to write it on two lines for a better readibility. Its fancy name is "line continuation symbol".&lt;/p&gt;

&lt;p&gt;If you're used to write shell scripts, remember that the line continuation symbol is not at the end of the line, but at the beginning of the next one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help cmdline-special&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help line-continuation&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Complete Example
&lt;/h2&gt;

&lt;p&gt;Let's summarize most of what we saw in this article with a final example. We want to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the user command &lt;code&gt;DevDocs&lt;/code&gt;. This command will automatically open the website &lt;a href="https://devdocs.io/" rel="noopener noreferrer"&gt;https://devdocs.io/&lt;/a&gt; and search the word under the cursor.&lt;/li&gt;
&lt;li&gt;Map the command to &lt;code&gt;&amp;lt;leader&amp;gt;D&lt;/code&gt; in NORMAL mode. This mapping will be available for python, ruby, JavaScript, go, html, and PHP filetypes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a possible solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;augroup vimrc
    autocmd&lt;span class="p"&gt;!&lt;/span&gt;
augroup END

command&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;nargs&lt;span class="p"&gt;=&lt;/span&gt;? DevDocs &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'xdg-open https://devdocs.io/#q=&amp;lt;args&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

autocmd vimrc &lt;span class="nb"&gt;FileType&lt;/span&gt; &lt;span class="k"&gt;python&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;ruby&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;javascript&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;html&lt;span class="p"&gt;,&lt;/span&gt;php nnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;D &lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s2"&gt;"DevDocs "&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;cword&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;We first declare an autocommand group &lt;code&gt;vimrc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We declare the user command &lt;code&gt;DevDocs&lt;/code&gt;, accepting 0 or 1 argument.&lt;/li&gt;
&lt;li&gt;We declare an autocommand linked to the event &lt;code&gt;FileType&lt;/code&gt;. We indicate the filetypes which will trigger the autocommand.&lt;/li&gt;
&lt;li&gt;We use the special argument &lt;code&gt;&amp;lt;buffer&amp;gt;&lt;/code&gt; to make the mapping only available in the current buffer. Without that, the mapping would be available in every buffer regardless of the filetype.&lt;/li&gt;
&lt;li&gt;The autocommand use &lt;code&gt;expand('&amp;lt;cword&amp;gt;')&lt;/code&gt;, which is replaced by the word under the cursor.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The event &lt;code&gt;FileType&lt;/code&gt; can be useful to assign precise mappings to a whole range of filetypes. We need, with this event, to give filetypes as autocommand patterns (like &lt;code&gt;python&lt;/code&gt; or &lt;code&gt;ruby&lt;/code&gt; for example). Remember that you can output the filetype of the current buffer with &lt;code&gt;:set filetype?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The binary &lt;code&gt;xdg-open&lt;/code&gt; is only available for Linux-based systems. If you want the autocommand to work on macOS too, you can use the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;command &lt;span class="p"&gt;-&lt;/span&gt;nargs&lt;span class="p"&gt;=&lt;/span&gt;? DevDocs &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'type open &amp;amp;&amp;gt;/dev/null &amp;amp;&amp;amp; open https://devdocs.io/#q=&amp;lt;args&amp;gt; || xdg-open https://devdocs.io/#q=&amp;lt;args&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The autocommand verifies if the binary &lt;code&gt;open&lt;/code&gt; exists (for macOS) and, if it doesn't, it uses &lt;code&gt;xdg-open&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take Control of Your Vim Destiny
&lt;/h2&gt;

&lt;p&gt;Creating your own functions, commands, and mapping for tedious operations will help you focus on more important tasks. Additionally, you'll bring more efficient in your whole workflow. How great is that?&lt;/p&gt;

&lt;p&gt;Let's summarize what we saw in this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can use the command &lt;code&gt;:verbose&lt;/code&gt; to output where an abbreviation, option, mapping, or user command, is defined.&lt;/li&gt;
&lt;li&gt;Special arguments are available for your mappings to extend its power.&lt;/li&gt;
&lt;li&gt;Operator pending map allow you to define motions for operators.&lt;/li&gt;
&lt;li&gt;The command &lt;code&gt;:execute&lt;/code&gt; can execute a string as if it was a command.&lt;/li&gt;
&lt;li&gt;Autocommands can run a defined command when an event is triggered.&lt;/li&gt;
&lt;li&gt;You can use autocommand groups to organize your autocommand.&lt;/li&gt;
&lt;li&gt;Autocommand groups are mandatory if you don't want to add multiple times the same command in the autocommand list. It can happen when a Vimscript file is loaded multiple time (like your vimrc).&lt;/li&gt;
&lt;li&gt;Custom functions can execute numerous Vim commands one after the other.&lt;/li&gt;
&lt;li&gt;It's better to autoload custom functions to be able to use namespaces and for Vim to start quicker.&lt;/li&gt;
&lt;li&gt;User commands are commands you can personalize for your own needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A last tip: if you want the list of Vimscript functions you can use, split in different category (like "Variables" or "Date and Time"), you can look at &lt;code&gt;:help function-list&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Learning to Play Vim: A Fun Guide to Learn the Best Editor
&lt;/h2&gt;

&lt;p&gt;I began to write &lt;a href="https://themouseless.dev/vim" rel="noopener noreferrer"&gt;a very ambitious guide to learn Vim&lt;/a&gt; from the ground up. Thanks to great feedback from my readers, I'll be able to address the problems many beginners complain about when learning Vim. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to navigate in multiple files and projects in Vim?&lt;/li&gt;
&lt;li&gt;How to debug in Vim?&lt;/li&gt;
&lt;li&gt;How to search, find, and replace?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide will explain the most useful vanilla functionalities as well as some powerful plugins which will enrich your experience.&lt;/p&gt;

&lt;p&gt;Help me make an impact in the Vim world! You can subscribe to the newsletter and tell me everything you want to see in the book. Early bird discount guarantees!&lt;/p&gt;

&lt;p&gt;I reply to every email personally, so don't hesitate to ask as many questions as you want. It's always a pleasure to help.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://themouseless.dev/vim" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthemouseless.dev%2Fimages%2Fvim%2Fbook_cover_900.webp" alt="Learning to Play Vim"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last but not least: I've also written a book about building your own Mouseless Development Environment, so if you're interested by that too, &lt;a href="https://themouseless.dev" rel="noopener noreferrer"&gt;click on this shiny link&lt;/a&gt;.&lt;/p&gt;




</description>
      <category>vim</category>
      <category>terminal</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A Vim Guide for Veteran Users</title>
      <dc:creator>Matthieu Cneude</dc:creator>
      <pubDate>Tue, 17 Aug 2021 15:10:46 +0000</pubDate>
      <link>https://forem.com/phantas0s/a-vim-guide-for-veteran-users-3p50</link>
      <guid>https://forem.com/phantas0s/a-vim-guide-for-veteran-users-3p50</guid>
      <description>&lt;p&gt;This article is the fifth of the series aimed to teach Vim from the ground up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-beginner/" rel="noopener noreferrer"&gt;Vim for Beginners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-intermediate/" rel="noopener noreferrer"&gt;Vim for Intermediate Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-advanced/" rel="noopener noreferrer"&gt;Vim for Advanced Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-adept/" rel="noopener noreferrer"&gt;Vim for Adept Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-veteran/" rel="noopener noreferrer"&gt;Vim for Veteran Users&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Can you picture an adventurer, going deeper and deeper into a mysterious cave, knowing what's waiting for her (mostly rocks and bats) but at the same time wishing to be surprised by some rare gems and abandoned treasures?&lt;/p&gt;

&lt;p&gt;This is how I feel when I'm adventuring deeper and deeper into Vim's world. I know that I'll always find something valuable: a new keystroke, a fierce command, or a little subtlety, increasing the control I have over my favorite editor.&lt;/p&gt;

&lt;p&gt;Over the last few articles, I tried to guide you in the Vim caves helping you discover the finest diamonds. We'll continue this endeavour in this article by exploring the following:b&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some keystrokes used for completion in INSERT mode.&lt;/li&gt;
&lt;li&gt;Useful keystrokes we can use in COMMAND-LINE mode.&lt;/li&gt;
&lt;li&gt;What are abbreviations and how to use them.&lt;/li&gt;
&lt;li&gt;How to save the global options and mappings of the current Vim instance into a file.&lt;/li&gt;
&lt;li&gt;How to save and restore Vim sessions.&lt;/li&gt;
&lt;li&gt;What's the purpose of the viminfo file (or the shada file for Neovim).&lt;/li&gt;
&lt;li&gt;How to redirect Vim command output into a file or a register.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Take your backpack, your headlamp, your rope, and let's go spot some new treasures for the mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Completion in Insert Mode
&lt;/h2&gt;

&lt;p&gt;We have already looked at useful keystrokes in INSERT mode &lt;a href="https://thevaluable.dev/vim-adept/" rel="noopener noreferrer"&gt;in the last article&lt;/a&gt;. There are other interesting ones you can use for completion. These keystrokes are all prefixed with another one, &lt;code&gt;CTRL+x&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Vim needs to be compiled with the &lt;code&gt;+insert_expand&lt;/code&gt; feature for these keystrokes to work.&lt;/p&gt;

&lt;p&gt;The first couple of them allow you to scroll up and down your buffer without leaving INSERT mode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CTRL+x CTRL+y&lt;/code&gt; - Scroll up&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+x CTRL+e&lt;/code&gt; - Scroll down&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The others are only useful if you want to complete what you've already typed. Here are, in my opinion, the most useful ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CTRL+x CTRL-l&lt;/code&gt; - Complete a whole line from the content of one of your buffer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+x CTRL-f&lt;/code&gt; - Complete the filepath under the cursor. It expands environment variables if it contains a filepath too.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+x s&lt;/code&gt; - Complete with spelling suggestions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+x CTRL+v&lt;/code&gt; - Complete with the command line history.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+x CTRL+i&lt;/code&gt; - Complete with the keywords in the current and included files. These files are in the option &lt;code&gt;path&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also use the completion from a thesaurus or a dictionary, or even the omni-completion to auto-complete programming languages. If you want to dive deeper in these ideas, Vim's help is waiting for your curiosity to be unleashed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help i_CTRL-x&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help ins-completion&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help compl-omni-filetypes&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Keystrokes in Command-Line Mode
&lt;/h2&gt;

&lt;p&gt;There was a lot of love poured into INSERT and VISUAL mode keystrokes in this series of article. What about COMMAND-LINE mode? It's time to pay some respect to this old chap. &lt;/p&gt;

&lt;p&gt;First, some good news: The keystrokes in INSERT mode will mostly work in COMMAND-LINE mode too. In one sentence, we already have a bunch of keys we can play with. How sweet is that?&lt;/p&gt;

&lt;h3&gt;
  
  
  Copying From the Buffers to the Command-Line
&lt;/h3&gt;

&lt;p&gt;Did you ever have the urge to copy something from your buffer in COMMAND-LINE mode? The boring way would be to come back to your buffer in NORMAL mode, copy what you want in a register, come back to COMMAND-LINE mode, and spit what you want. Like in INSERT mode, you can use &lt;code&gt;CTRL+r&lt;/code&gt; followed by the name of a register to copy its content in COMMAND-LINE mode.&lt;/p&gt;

&lt;p&gt;Or you can use these keystrokes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CTRL+r CTRL+f&lt;/code&gt; - Copy the &lt;code&gt;f&lt;/code&gt;ilename under the buffer's cursor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+r CTRL+w&lt;/code&gt; - Copy the &lt;code&gt;w&lt;/code&gt;ord under the buffer's cursor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+r CTRL+a&lt;/code&gt; - Copy the WORD under the buffer's cursor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+r CTRL+l&lt;/code&gt; - Copy the &lt;code&gt;l&lt;/code&gt;ine under the buffer's cursor.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Search
&lt;/h3&gt;

&lt;p&gt;If the option &lt;code&gt;incsearch&lt;/code&gt; is set, it will highlight the search you're doing while typing it. That's not all: you'll also be able to use &lt;code&gt;CTRL+g&lt;/code&gt; and &lt;code&gt;CTRL+t&lt;/code&gt; to go through every match without leaving COMMAND-LINE mode.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multiple Commands on One Line
&lt;/h3&gt;

&lt;p&gt;This one is not a keystroke but it can be useful nevertheless. You can run more than one command in one line if you separate them with a pipe. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:set filetype?|echo "it's done!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This won't work if the command accepts a pipe as an argument. For example: &lt;code&gt;:!ls | wc&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help Command-line-mode&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help ex−edit−index&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Abbreviations
&lt;/h2&gt;

&lt;p&gt;Let's now look at something totally different: Vim abbreviations. This feature can replace a word with another one automatically after pressing &lt;code&gt;SPACE&lt;/code&gt;. You can use abbreviations in INSERT and COMMAND-LINE modes.&lt;/p&gt;

&lt;p&gt;For example, if you often misspell "the" with "teh" (it happens to the best of us), you can automatically replace "teh" with "the".&lt;/p&gt;

&lt;p&gt;Let's see the commands you can use to output and manipulate abbreviations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:abbreviate&lt;/code&gt; or &lt;code&gt;:ab&lt;/code&gt; - List all the abbreviations created.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:abbreviate &amp;lt;string&amp;gt;&lt;/code&gt; or &lt;code&gt;:ab &amp;lt;string&amp;gt;&lt;/code&gt; - List abbreviations beginning with the string &lt;code&gt;&amp;lt;string&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:abbreviate &amp;lt;string&amp;gt; &amp;lt;replacement&amp;gt;&lt;/code&gt; or &lt;code&gt;:ab &amp;lt;string&amp;gt; &amp;lt;replacement&amp;gt;&lt;/code&gt; - Create a new abbreviation for every mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:unabbreviate &amp;lt;ab&amp;gt;&lt;/code&gt; or &lt;code&gt;:una &amp;lt;ab&amp;gt;&lt;/code&gt; - Remove the abbreviation &lt;code&gt;&amp;lt;ab&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:abclear&lt;/code&gt; or &lt;code&gt;:abc&lt;/code&gt; - Remove all abbreviations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you list abbreviations using &lt;code&gt;:ab&lt;/code&gt;, you'll see different letters in the first column of the output. They indicate in what mode you can use them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;i&lt;/code&gt; for &lt;code&gt;i&lt;/code&gt;nsert mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;c&lt;/code&gt; for &lt;code&gt;c&lt;/code&gt;ommand line mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;!&lt;/code&gt; for both.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to list or create abbreviations for one precise mode, you can use &lt;code&gt;i&lt;/code&gt; or &lt;code&gt;c&lt;/code&gt; at the beginning of the command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:iab&lt;/code&gt; - List every abbreviation available in INSERT mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:cab &amp;lt;string&amp;gt; &amp;lt;replacement&amp;gt;&lt;/code&gt; - Create a new abbreviation only available in COMMAND-LINE mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;iabc&lt;/code&gt; - Remove all abbreviations in INSERT mode.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It works a bit differently if you decide to use the long forms of the commands. For example, &lt;code&gt;:iabbreviate&lt;/code&gt; won't work; instead, use "abbrev", like in &lt;code&gt;:iabbrev&lt;/code&gt;, &lt;code&gt;:cabbrev&lt;/code&gt;, or &lt;code&gt;:iunabbrev&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can use abbreviations for different purposes as shown in these different examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:iab @@ myemail@email.com&lt;/code&gt; - Insert your email&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:iab BTW by the way&lt;/code&gt; - Expand an acronym&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:iab sign Jane Doe™&amp;lt;cr&amp;gt;jane@doe.com&lt;/code&gt; - Insert your signature&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:iab &amp;lt;expr&amp;gt; cdate strftime('%Y-%m-%d')&lt;/code&gt; - Insert the &lt;code&gt;c&lt;/code&gt;urrent date&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:cab uuidgen r! uuidgen&lt;/code&gt; - Insert a UUID when running the command &lt;code&gt;:uuidgen&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, if you've typed an abbreviation but you don't want to expand it when hitting &lt;code&gt;SPACE&lt;/code&gt;, use &lt;code&gt;CTRL+v&lt;/code&gt; and then &lt;code&gt;SPACE&lt;/code&gt; instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:help abbreviations&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Saving Vim's Options and Mapping in a File
&lt;/h2&gt;

&lt;p&gt;Let's now go into the crux of this article: persisting your current options, keystroke mappings, or your whole sessions into a file.&lt;/p&gt;

&lt;p&gt;If you were experimenting in Vim by changing a bunch of options and mappings but you don't remember what exactly, or if you wonder what command run when you hit a keystroke, you can output every option and global mappings (different from Vim's defaults) into a file.&lt;/p&gt;

&lt;p&gt;To do so, you can run the command &lt;code&gt;:mkexrc &amp;lt;filepath&amp;gt;&lt;/code&gt; or &lt;code&gt;:mk &amp;lt;file&amp;gt;&lt;/code&gt; to output these options and mappings into the file &lt;code&gt;&amp;lt;filepath&amp;gt;&lt;/code&gt;. If you use a relative path, it will be relative to the working directory you're in (to display it, use &lt;code&gt;:pwd&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;You can also add a bang &lt;code&gt;!&lt;/code&gt; to &lt;code&gt;:mk&lt;/code&gt; to overwrite a file. For example, &lt;code&gt;:mk! myfile&lt;/code&gt; will create the file &lt;code&gt;myfile&lt;/code&gt; or overwrite it if it already exists.&lt;/p&gt;

&lt;p&gt;From there, you can open the file you've written and copy whatever options or mapping you want in your vimrc. You can also source the file directly into another instance of Vim with the command &lt;code&gt;:source &amp;lt;filepath&amp;gt;&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;I've already written about the &lt;code&gt;:source&lt;/code&gt; command in &lt;a href="https://thevaluable.dev/vim-intermediate/" rel="noopener noreferrer"&gt;Vim for Intermediate Users&lt;/a&gt; in order to reload your vimrc. You can source any file containing some Vimscript with this command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vim Sessions
&lt;/h2&gt;

&lt;p&gt;If you want to save and restore much more than options and global mappings, you can use Vim sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating and Loading a Session
&lt;/h3&gt;

&lt;p&gt;A session is constituted of all the views (a view is a collection of settings attached to a window) and the global settings of your current Vim instance.&lt;/p&gt;

&lt;p&gt;Wouldn't it be fun to save your session in a file and open it later in another Vim instance? It would allow you to recover all your buffers, windows, and local settings! Life would be even more colorful then.&lt;/p&gt;

&lt;p&gt;To do so, you can use the commands &lt;code&gt;:mksession &amp;lt;filepath&amp;gt;&lt;/code&gt; or &lt;code&gt;:mks &amp;lt;filepath&amp;gt;&lt;/code&gt;. You can then source the session in another instance of Vim with &lt;code&gt;:source &amp;lt;filepath&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As usual, you can add a bang &lt;code&gt;!&lt;/code&gt; to the command to overwrite the file if it already exists.&lt;/p&gt;

&lt;p&gt;For example, here are some mappings I've written in my &lt;code&gt;vimrc&lt;/code&gt; to manipulate sessions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nnoremap &amp;lt;leader&amp;gt;ss :mksession! $VIMCONFIG/sessions/&lt;/code&gt; - Mapping to &lt;code&gt;s&lt;/code&gt;ave a &lt;code&gt;s&lt;/code&gt;ession&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nnoremap &amp;lt;leader&amp;gt;sl :source $VIMCONFIG/sessions/&lt;/code&gt; - Mapping to &lt;code&gt;l&lt;/code&gt;oad a &lt;code&gt;s&lt;/code&gt;ession&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each time I press &lt;code&gt;LEADER ss&lt;/code&gt;, I can type the name of the session and save it. All my sessions are gathered in the same directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fine Tuning Vim's Sessions
&lt;/h3&gt;

&lt;p&gt;The option &lt;code&gt;sessionoptions&lt;/code&gt; contains a bunch of values separated with comma &lt;code&gt;,&lt;/code&gt;. These values will decide what will be saved in your session file and, as a result, what will be restored when the file is sourced.&lt;/p&gt;

&lt;p&gt;Here are the most interesting values you can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;blank&lt;/code&gt; - Save windows containing buffers without names.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;buffers&lt;/code&gt; - Save hidden and unloaded buffers. Only buffers in windows are restored without this value.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;curdir&lt;/code&gt; - Save the current directory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;folds&lt;/code&gt; - Save folds information.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;globals&lt;/code&gt; - Save the global variables beginning with uppercase and containing at least one uppercase in their names.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;help&lt;/code&gt; - Save the help windows.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;localoptions&lt;/code&gt; - Save local options and mappings to a window or a buffer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;options&lt;/code&gt; - Save all options and mappings.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;resize&lt;/code&gt; - Save the size of your windows.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tabpages&lt;/code&gt; - Save all the tab open. Without this value, only the current tab is saved.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;terminal&lt;/code&gt; - Save the terminal window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that the default global options or global mappings are not saved in a session file. It means that if you have an instance of Vim open and you've already modified some default values, loading a session won't reset them to their defaults.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help :sessionoptions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help views-sessions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help :mksession&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The files viminfo or shada
&lt;/h2&gt;

&lt;p&gt;Vim also saves information automatically into a file when you close the editor. This file is different depending on what you're using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For Vim, it's the viminfo file.&lt;/li&gt;
&lt;li&gt;For Neovim, it's the shada file (for &lt;code&gt;sh&lt;/code&gt;ared &lt;code&gt;da&lt;/code&gt;ta). It can't be a symlink.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On Unix systems (Linux and macOS), each file can be found at these file paths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;viminfo - &lt;code&gt;$HOME/.viminfo&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;shada - &lt;code&gt;$XDG_DATA_HOME/nvim/shada/main.shada&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can change the name for your shada or viminfo file by setting the value of &lt;code&gt;shadafile&lt;/code&gt; or &lt;code&gt;viminfofile&lt;/code&gt; respectively. You can also set the value &lt;code&gt;NONE&lt;/code&gt; if you don't want to use these files.&lt;/p&gt;

&lt;p&gt;Each time you close a Vim instance, you can save the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The command-line history.&lt;/li&gt;
&lt;li&gt;The search history.&lt;/li&gt;
&lt;li&gt;The input-line history.&lt;/li&gt;
&lt;li&gt;Contents of non-empty registers.&lt;/li&gt;
&lt;li&gt;Lowercase marks for several files.&lt;/li&gt;
&lt;li&gt;File marks (uppercase marks).&lt;/li&gt;
&lt;li&gt;Last search or substitute pattern.&lt;/li&gt;
&lt;li&gt;The buffer list.&lt;/li&gt;
&lt;li&gt;The global variables (only if they're different from the default values).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can configure what to save more precisely by changing the values of the following option:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For Vim, the option &lt;code&gt;viminfo&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For Neovim, the option &lt;code&gt;shada&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The option's values are separated with a comma &lt;code&gt;,&lt;/code&gt;. Here are the most useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;!&lt;/code&gt; - Save and restore global variables (their names should be without lowercase letter).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can add a number after each of these values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;&lt;/code&gt; - Specify the maximum of lines saved for each register. All the lines are saved if this is not included. If you don't want to save your registers, use the value &lt;code&gt;&amp;lt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%&lt;/code&gt; - Save and restore the buffer list. You can specify the maximum number of buffer stored with a number.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;'&lt;/code&gt; - Specify the maximum number of marked files remembered. It also saves the jump list and the change list we saw in a &lt;a href="https://thevaluable.dev/vim-intermediate/" rel="noopener noreferrer"&gt;previous article&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/&lt;/code&gt; and &lt;code&gt;:&lt;/code&gt; - Number of search patterns and entries from the command-line history saved. The option &lt;code&gt;history&lt;/code&gt; is used if it's not specified.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;f0&lt;/code&gt; - Don't store any uppercase mark.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;s&lt;/code&gt; - Specify the maximum size of an item's content in KiB (kilobyte).

&lt;ul&gt;
&lt;li&gt;For the viminfo file, it only applies to register.&lt;/li&gt;
&lt;li&gt;For the shada file, it applies to all items except for the buffer list and header.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;For example, &lt;code&gt;:set shada=!,'100,&amp;lt;50,s100&lt;/code&gt; save global variables, a maximum of 100 files marked, a maximum of 50 lines per register, and a maximum of 100Kib for each item. The equivalent for vim would be &lt;code&gt;:set viminfo=!,'100,&amp;lt;50,s100&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Vim writes the viminfo file when you close the editor, and it's loaded when you open a new instance. That said, you can also output, save, or load the file with these commands:&lt;/p&gt;

&lt;p&gt;For Vim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:oldfiles&lt;/code&gt; or &lt;code&gt;:ol&lt;/code&gt; - Display all marked files stored in the viminfo file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:rviminfo&lt;/code&gt; or &lt;code&gt;:rv&lt;/code&gt; - Read the viminfo file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:wviminfo&lt;/code&gt; or &lt;code&gt;:wv&lt;/code&gt; - Write the viminfo file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Neovim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:oldfiles&lt;/code&gt; or &lt;code&gt;:o&lt;/code&gt; - Display all files with a mark stored in the shada file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:rshada&lt;/code&gt; or &lt;code&gt;:rs&lt;/code&gt; -  Read the shada file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:wshada&lt;/code&gt; or &lt;code&gt;:ws&lt;/code&gt; - Write the shada file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add a bang to these commands (&lt;code&gt;:rv!&lt;/code&gt; or &lt;code&gt;:rs!&lt;/code&gt; for example) to allow everything set in your file overwriting everything in your current Vim instance.&lt;/p&gt;

&lt;p&gt;The viminfo file is written in its one dialect. You can modify it directly if you feel even more adventurous. The shada file use the &lt;a href="https://msgpack.org/" rel="noopener noreferrer"&gt;messagepack&lt;/a&gt; format.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help viminfo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help 'viminfo'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help 'viminfofile'&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Neovim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help shada&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help 'shada'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help 'shadafile'&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Redirections
&lt;/h2&gt;

&lt;p&gt;What if you want to save the output of Vim commands in a file or in a register? The command &lt;code&gt;:redir&lt;/code&gt; is here to fulfill your desires. More precisely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:redir &amp;gt; &amp;lt;file&amp;gt;&lt;/code&gt; - Write every command's output to the file &lt;code&gt;&amp;lt;file&amp;gt;&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;:redir!&lt;/code&gt; (with a bang &lt;code&gt;!&lt;/code&gt;) to overwrite the file.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; instead of &lt;code&gt;&amp;gt;&lt;/code&gt; to append to the file.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;:redir @&amp;lt;reg&amp;gt;&lt;/code&gt; - Write every command's output to the register &lt;code&gt;&amp;lt;reg&amp;gt;&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;:redir @&amp;lt;reg&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; - Append every command's output to the register &lt;code&gt;&amp;lt;reg&amp;gt;&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;:redir =&amp;gt; &amp;lt;var&amp;gt;&lt;/code&gt; - Write every command's output to the variable &lt;code&gt;&amp;lt;var&amp;gt;&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;:redir END&lt;/code&gt; - End the redirection.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;For example, if you want to set the variable &lt;code&gt;sessionoptions&lt;/code&gt; in your &lt;code&gt;.vimrc&lt;/code&gt; with the current value, you can do something like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:redir &amp;gt;&amp;gt; $VIMCONFIG/.vimrc
:set sessionoptions?
:redir END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running &lt;code&gt;:redir END&lt;/code&gt;, nothing more will be written into the file. You can only have one redirection going on, so declaring a new one will automatically close the previous one.&lt;/p&gt;

&lt;p&gt;Let's look at another example. You can run the following to append the declaration of the option &lt;code&gt;sessionoptions&lt;/code&gt; with the current value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:redir @+&amp;gt;&amp;gt;
:set sessionoptions?
:redir END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the uppercase version of the named registers (the ones from &lt;code&gt;a&lt;/code&gt; to &lt;code&gt;z&lt;/code&gt;) will append the output of Vim's commands without the need to use &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;. For example, &lt;code&gt;:redir @A&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A final example, using a variable to store the output of the command this time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:redir =&amp;gt; my_var
:set sessionoptions?
:redir END
:echo my_var
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:help :redir&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Filtering Commands Output
&lt;/h2&gt;

&lt;p&gt;It's nice to be able to save command output in Vim, but what if we want to filter them?&lt;/p&gt;

&lt;p&gt;To do so, we can use the command &lt;code&gt;:filter /&amp;lt;pattern&amp;gt;/ &amp;lt;cmd&amp;gt;&lt;/code&gt;: it will filter the command &lt;code&gt;&amp;lt;cmd&amp;gt;&lt;/code&gt; according to the pattern &lt;code&gt;&amp;lt;pattern&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's take some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:filter /content/ buffers&lt;/code&gt; - Only output the buffers with part of the filepath matching &lt;code&gt;content&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:filter /archives/ oldfiles&lt;/code&gt; - Only output the marked files with part of the filepath matching &lt;code&gt;archives&lt;/code&gt;.
As you can see, the pattern doesn't have to match the whole line, only part of it. You can add a bang &lt;code&gt;!&lt;/code&gt; to the command &lt;code&gt;filter&lt;/code&gt; (&lt;code&gt;filter!&lt;/code&gt;) to inverse the match, that is, output everything which &lt;em&gt;doesn't match&lt;/em&gt; the pattern.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This command doesn't work with all Ex commands. For example, it won't work with the command &lt;code&gt;:register&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:help :filter&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Step: Vim for Expert Users
&lt;/h2&gt;

&lt;p&gt;What did we learn in this article?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can use a new INSERT mode submenu with the keystroke &lt;code&gt;CTRL+x&lt;/code&gt; followed by another keystroke.&lt;/li&gt;
&lt;li&gt;You can use most keystrokes for INSERT mode in COMMAND-LINE mode. You can also use &lt;code&gt;CTRL+r&lt;/code&gt; with a second keystroke to copy what's in your buffer directly in your command-line.&lt;/li&gt;
&lt;li&gt;Abbreviations are meant to stop beating your keyboard because you can't stop doing the same spelling mistakes. It's not the only use case; the sky's the limit.&lt;/li&gt;
&lt;li&gt;You can source any file containing Vimscript commands using the command &lt;code&gt;:source&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You can save the current settings of your Vim instance with &lt;code&gt;:mk &amp;lt;file&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You can also save your current Vim session with the command &lt;code&gt;:mks &amp;lt;file&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Every time you close Vim, your viminfo file is written (if the &lt;code&gt;viminfo&lt;/code&gt; options is not empty). If you use Neovim, the viminfo file is replaced with the shada file.&lt;/li&gt;
&lt;li&gt;Every time you open Vim, the viminfo file (or shada file) is read.&lt;/li&gt;
&lt;li&gt;You can use the redirection (command &lt;code&gt;:redir&lt;/code&gt;) to persist in files or registers the output of the different Vim commands.&lt;/li&gt;
&lt;li&gt;You can filter the output of some Vim commands using the command &lt;code&gt;:filter&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Throughout this series, we've seen many functionalities The Glorious Vanilla Vim offers us on a tasty platter. But the real power of Vim lies in its flexibility. That's why in the next article, Vim for Expert Users, we'll become Apprentice Gods (or Goddesses) and look at different ways to shape our Vim world according to our deeper needs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Becoming Mouseless
&lt;/h2&gt;

&lt;p&gt;Do you want to build a &lt;a href="https://themouseless.dev" rel="noopener noreferrer"&gt;Mouseless Development Environment&lt;/a&gt; where the Linux shell and Vim have a central role?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://themouseless.dev" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthemouseless.dev%2Fimages%2Fsmall_cover.webp" alt="building your mouseless development environment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Switching between the keyboard and the mouse costs cognitive energy. This book will guide you step by step to set up a Linux-based development environment that keeps your hands on your keyboard.&lt;/p&gt;

&lt;p&gt;Take the brain power you've been using to juggle input devices and focus it where it belongs: on what you create.&lt;/p&gt;




</description>
      <category>vim</category>
      <category>terminal</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A Vim Guide for Adept Users</title>
      <dc:creator>Matthieu Cneude</dc:creator>
      <pubDate>Sun, 11 Jul 2021 09:20:55 +0000</pubDate>
      <link>https://forem.com/phantas0s/a-vim-guide-for-adept-users-477i</link>
      <guid>https://forem.com/phantas0s/a-vim-guide-for-adept-users-477i</guid>
      <description>&lt;p&gt;This is the fourth part of this series to learn Vim from the ground up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-beginner/" rel="noopener noreferrer"&gt;Vim for Beginners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-intermediate/" rel="noopener noreferrer"&gt;Vim for Intermediate Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-advanced/" rel="noopener noreferrer"&gt;Vim for Advanced Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-adept/" rel="noopener noreferrer"&gt;Vim for Adept Users&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Dave, your colleague developer, just read Vim for Advanced Users before going to bed. He wonders what's next: Vim for Unstoppable Creators? Vim for Godlike Developers? On these reassuring thoughts, he falls into a deep sleep.&lt;/p&gt;

&lt;p&gt;He wakes up suddenly: he's not in his bed anymore! He's now in a massive room, probably a church, where hundreds of masked and hooded figures sing in unison. He's sitting in front of a desk, like everybody else. The smell of incense is powerful and, even if he's in an open space, it's warm and comfy.&lt;/p&gt;

&lt;p&gt;The singing stop. A tall individual, hooded too, wearing a wonderful golden robe and a silver mask, stands on a stage in front of the gathering, not far from you. &lt;/p&gt;

&lt;p&gt;She begins to speak:&lt;/p&gt;

&lt;p&gt;"My friends! You've been chosen as the most fervent follower of our Guide, the powerful Vim! For the Glory of Vim!"&lt;/p&gt;

&lt;p&gt;Everybody repeats the words of the hooded woman: "For the glory of Vim!"&lt;/p&gt;

&lt;p&gt;She continues. "Today, when your formation will be done, I will knight you Glorious Vim Adept™. You'll be then borderline unstoppable, but beware! The Power needs to be used for The Greater Good!"&lt;/p&gt;

&lt;p&gt;"The Greater Good!", repeats the gathering.&lt;/p&gt;

&lt;p&gt;"My friends! Look under your desk. You have the Vector of Power, a Lenovo x220, with The Highness Vim running on it. Take it, it will be the link between you and my unbearable teaching. You'll become soon The Builders of the New Sweet World!"&lt;/p&gt;

&lt;p&gt;"The Builder of the New Sweet World!", repeat the others.&lt;/p&gt;

&lt;p&gt;There is indeed a computer under Dave's desk. He takes it and begins to read the table of content blinking before his excited eyes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to manipulate multiple quickfix and location lists.&lt;/li&gt;
&lt;li&gt;What are digraphs and how to use them.&lt;/li&gt;
&lt;li&gt;Useful keystrokes in INSERT mode.&lt;/li&gt;
&lt;li&gt;Useful keystrokes in VISUAL mode.&lt;/li&gt;
&lt;li&gt;Vim regular expressions.&lt;/li&gt;
&lt;li&gt;Using shell commands in Vim.&lt;/li&gt;
&lt;li&gt;Folding content.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Suddenly, the course itself begins to poor in Dave's brain! Frenetically, his fingers type in Vim everything his telepathic connection is showing him.&lt;/p&gt;

&lt;p&gt;This article is a transcript of what Dave experienced in his own mind. It's not as powerful as telepathic teaching, but here are some tips and tricks you can use to remember what you'll read:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Try in Vim what's described while reading the article.&lt;/li&gt;
&lt;li&gt;Create your own cheatsheet. It will help you remember all the shenanigans and you can even refer to it in your daily work.&lt;/li&gt;
&lt;li&gt;Pick and choose new concepts from this article from time to time and try to integrate them to your own workflow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What did Dave learn in his adventure?&lt;/p&gt;

&lt;h2&gt;
  
  
  Multiple Quickfix and Locations Lists
&lt;/h2&gt;

&lt;p&gt;We saw in the &lt;a href="https://dev.to/vim-advanced/"&gt;last article&lt;/a&gt; how useful the quickfix lists are. But it didn't explain how to access the stack of these lists. &lt;/p&gt;

&lt;p&gt;Indeed, each time we create a quickfix list, it will be added to a stack and the previous one will be pushed down. This stack can contain 10 quickfix lists maximum; each time you create a quickfix list, the 10th on the stack will disappear forever in the Forgotten Pit of Quickfix Lists.&lt;/p&gt;

&lt;p&gt;This is true for location lists too: you'll have a stack containing 10 of them &lt;em&gt;per window open&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You can use these commands to manipulate this stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:chistory&lt;/code&gt; or &lt;code&gt;:chi&lt;/code&gt; - Show the stack of quickfix lists and point out the current one.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:colder&lt;/code&gt; or &lt;code&gt;:col&lt;/code&gt; - Change the current quickfix list to the next older one.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:cnewer&lt;/code&gt; or &lt;code&gt;:cnew&lt;/code&gt; - Change the current quickfix list to the next newer one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can add a count after &lt;code&gt;:colder&lt;/code&gt; and &lt;code&gt;:cnewer&lt;/code&gt;. For example, running &lt;code&gt;:colder 3&lt;/code&gt; will select the quickfix list which is 3 positions down the current one.&lt;/p&gt;

&lt;p&gt;To change your current location list, you can replace the first letter &lt;code&gt;c&lt;/code&gt; (qui&lt;code&gt;c&lt;/code&gt;kfix) of the commands above with a &lt;code&gt;l&lt;/code&gt; (&lt;code&gt;l&lt;/code&gt;ocation).&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:help quickfix-error-lists&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Digraphs
&lt;/h2&gt;

&lt;p&gt;Vim allows you to insert special characters easily using &lt;em&gt;digraphs&lt;/em&gt;. To insert these special characters, you need to know their &lt;em&gt;representations&lt;/em&gt;, always two "normal" characters. &lt;/p&gt;

&lt;p&gt;Here are some useful commands:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;:digraphs&lt;/code&gt; or &lt;code&gt;:dig&lt;/code&gt; - Display the digraphs available.&lt;br&gt;
&lt;code&gt;:digraphs &amp;lt;char1&amp;gt;&amp;lt;char2&amp;gt; &amp;lt;number&amp;gt;&lt;/code&gt; - Create a new digraph represented with the characters &lt;code&gt;&amp;lt;char1&amp;gt;&amp;lt;char2&amp;gt;&lt;/code&gt;. The &lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt; is its decimal representation (Unicode character).&lt;/p&gt;

&lt;p&gt;You can also use the following keystrokes in INSERT mode to spit these good digraphs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CTRL+K &amp;lt;char1&amp;gt;&amp;lt;char2&amp;gt;&lt;/code&gt; - Insert the digraph represented with the characters &lt;code&gt;&amp;lt;char1&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;char2&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;char1&amp;gt;&amp;lt;BS&amp;gt;&amp;lt;char2&amp;gt;&lt;/code&gt; - Insert the digraph represented with the characters &lt;code&gt;&amp;lt;char1&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;char2&amp;gt;&lt;/code&gt; (only if the option &lt;code&gt;digraph&lt;/code&gt; is set to true).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CTRL+K -&amp;gt;&lt;/code&gt;: →&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+K TM&lt;/code&gt;: ™&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+K Co&lt;/code&gt;: ©&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+K Rg&lt;/code&gt;: ®&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+K Eu&lt;/code&gt;: €&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+K +-&lt;/code&gt;: ±&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+K OK&lt;/code&gt;: ✓&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+K XX&lt;/code&gt;: ✗&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I owe my sanity to digraphs when I was trying to &lt;a href="https://raw.githubusercontent.com/Phantas0s/playground/master/cs/04-math/discrete-math-applications/1/1.3/1.3.md" rel="noopener noreferrer"&gt;solve some problems in propositional logic&lt;/a&gt; full of "∧" (&lt;code&gt;CTRL+k AN&lt;/code&gt;), "∨" (&lt;code&gt;CTRL+k OR&lt;/code&gt;) or "∈" (&lt;code&gt;CTRL+k (-&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;A last tip: you can use the keystroke &lt;code&gt;ga&lt;/code&gt; in NORMAL mode to display the digraph of the character under the cursor (if there is one).&lt;/p&gt;
&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help digraph&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help digraph-table&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Useful Keystrokes in Insert Mode
&lt;/h2&gt;

&lt;p&gt;We saw many keystrokes for NORMAL mode throughout this series, but what about INSERT mode? We need more equality between modes in this world. &lt;/p&gt;

&lt;p&gt;Keystrokes in INSERT mode are prefixed with &lt;code&gt;CTRL&lt;/code&gt;, specifying to Vim that we don't want to insert some text.&lt;/p&gt;
&lt;h3&gt;
  
  
  Inserting and Deleting
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CTRL+a&lt;/code&gt; - Insert the l&lt;code&gt;a&lt;/code&gt;st content inserted.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+@&lt;/code&gt; - Insert the l&lt;code&gt;a&lt;/code&gt;st content inserted and quit INSERT mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+h&lt;/code&gt; - Delete the character before the cursor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+w&lt;/code&gt; - Delete the &lt;code&gt;w&lt;/code&gt;ord under the cursor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+u&lt;/code&gt; - Delete everything before the c&lt;code&gt;u&lt;/code&gt;rsor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+t&lt;/code&gt; - Add one indenta&lt;code&gt;t&lt;/code&gt;ion.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+d&lt;/code&gt; - &lt;code&gt;D&lt;/code&gt;elete one indentation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Spitting Registers
&lt;/h3&gt;

&lt;p&gt;We saw already in the &lt;a href="https://dev.to/vim-advanced/"&gt;previous article&lt;/a&gt; how to spit the content of a register in INSERT mode. Let's introduce some subtleties here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CTRL+R &amp;lt;reg&amp;gt;&lt;/code&gt; - Spit the content of the register &lt;code&gt;&amp;lt;reg&amp;gt;&lt;/code&gt; &lt;em&gt;as if you typed it&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+R CTRL+R &amp;lt;reg&amp;gt;&lt;/code&gt; - Same as &lt;code&gt;CTRL+R&lt;/code&gt;, but insert the text literally.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+R CTRL+P &amp;lt;reg&amp;gt;&lt;/code&gt; - Spit the literal content of the register &lt;code&gt;&amp;lt;reg&amp;gt;&lt;/code&gt; with the correct indentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you look at the content of your registers, you might find some weird characters like &lt;code&gt;^M&lt;/code&gt; or &lt;code&gt;^I&lt;/code&gt;. You can think of them as &lt;code&gt;CTRL+m&lt;/code&gt; and &lt;code&gt;CTRL+i&lt;/code&gt;, which means, if you recorded some macros while being in INSERT more, end-of-line and tabulation respectively.&lt;/p&gt;

&lt;p&gt;The first keystroke &lt;code&gt;CTRL+R &amp;lt;reg&amp;gt;&lt;/code&gt; will insert these end-of-lines and tabulations. For example, if you have the characters &lt;code&gt;^M&lt;/code&gt; in your register when you display them via &lt;code&gt;:reg&lt;/code&gt;, it will become an end-of-line when you insert it.&lt;/p&gt;

&lt;p&gt;If you use &lt;code&gt;CTRL+R CTRL+R &amp;lt;reg&amp;gt;&lt;/code&gt;, you'll have the literal characters &lt;code&gt;^M&lt;/code&gt; inserted in your buffer. It's handy to spit a recording for a macro, modify it, and then save it back to your register &lt;code&gt;&amp;lt;reg&amp;gt;&lt;/code&gt;. From there, you can execute your modified macro.&lt;/p&gt;

&lt;p&gt;To know what the literal version of a key is, you can use &lt;code&gt;CTRL+V&lt;/code&gt; (or &lt;code&gt;CTRL+Q&lt;/code&gt;) in INSERT mode followed by the key. For example, &lt;code&gt;CTRL+V ENTER&lt;/code&gt; will display &lt;code&gt;^M&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since we're speaking about &lt;code&gt;CTRL+V&lt;/code&gt;, you can also use it followed by the decimal, octal, or hexadecimal value of a character. It's another way to insert special characters without using digraphs. You can run &lt;code&gt;man ascii&lt;/code&gt; to have access to the ASCII table in your shell and choose whatever character you want.&lt;/p&gt;

&lt;p&gt;The keystrokes &lt;code&gt;CTRL+V&lt;/code&gt; and the equivalent &lt;code&gt;CTRL+Q&lt;/code&gt; can be used in COMMAND-LINE mode too.&lt;/p&gt;
&lt;h3&gt;
  
  
  Back to NORMAL mode
&lt;/h3&gt;

&lt;p&gt;The keystroke &lt;code&gt;CTRL+o&lt;/code&gt; in INSERT mode allows you to come back to NORMAL mode for one keystroke (or one command in COMMAND-LINE mode). When it's done, you'll be automatically back in INSERT mode.&lt;/p&gt;
&lt;h3&gt;
  
  
  Undo in Insert Mode
&lt;/h3&gt;

&lt;p&gt;You can stop the undo sequence if you use &lt;code&gt;CTRL+G u&lt;/code&gt; in INSERT mode.&lt;/p&gt;

&lt;p&gt;For example, try to insert some text in INSERT mode and then undo your insertion with &lt;code&gt;u&lt;/code&gt; in NORMAL mode. Everything you've inserted is now gone.&lt;/p&gt;

&lt;p&gt;If you want to undo each word you've inserted instead of everything, you can use this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:inoremap &amp;lt;space&amp;gt; &amp;lt;C-G&amp;gt;u&amp;lt;space&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, each time you press &lt;code&gt;SPACE&lt;/code&gt; in INSERT mode, you'll stop the undo sequence. When you hit &lt;code&gt;u&lt;/code&gt; in NORMAL mode, it will undo what you've inserted after hitting the last &lt;code&gt;SPACE&lt;/code&gt;. If you undo again, it will undo another word, and so on. There is a drawback, however: abbreviations won't work anymore in insert mode.&lt;/p&gt;

&lt;p&gt;You can think of &lt;code&gt;CTRL+G u&lt;/code&gt; as creating chunks of undo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help ins-special-keys&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help insert−index&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Useful Keystrokes in Visual mode
&lt;/h2&gt;

&lt;p&gt;There are also interesting keystrokes you can hit in the different variants of VISUAL mode.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual Mode and Visual Mode Linewise
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;o&lt;/code&gt; - Move your cursor to the &lt;code&gt;o&lt;/code&gt;pposite side of the selection (or the &lt;code&gt;o&lt;/code&gt;ther end if you prefer). Doesn't work in VISUAL mode linewise.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;R&lt;/code&gt; or &lt;code&gt;S&lt;/code&gt; - Delete the selected lines and start INSERT mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;U&lt;/code&gt; - &lt;code&gt;U&lt;/code&gt;ppercase the selection.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gv&lt;/code&gt; - Switch back and forth between the previous selection and the current one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another tip: You can switch between VISUAL mode linewise and VISUAL mode blockwise &lt;em&gt;without coming back to NORMAL mode&lt;/em&gt; with &lt;code&gt;CTRL+v&lt;/code&gt; and &lt;code&gt;SHIFT+v&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual Mode Blockwise
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;o&lt;/code&gt; - Move to the &lt;code&gt;o&lt;/code&gt;pposite corner of the selection.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;O&lt;/code&gt; - Move to the &lt;code&gt;o&lt;/code&gt;pposite side of the selection.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I&lt;/code&gt; - &lt;code&gt;I&lt;/code&gt;nsert some content at the beginning of every line selected.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;A&lt;/code&gt; - &lt;code&gt;A&lt;/code&gt;ppend some content on every line selected after the highlighted area.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$A&lt;/code&gt; - &lt;code&gt;A&lt;/code&gt;ppend some content at the end of every line selected.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;c&lt;/code&gt; - Delete selected lines and begin INSERT mode &lt;em&gt;on every line&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help visual-index&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help blockwise-operators&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Vim Regular Expressions
&lt;/h2&gt;

&lt;p&gt;We're now at the crux of this article: Vim's regexes are really powerful for searching in your content or transforming it. As a Venerable Vim Adept, you need to harness its power.&lt;/p&gt;

&lt;p&gt;This section won't go into the details of regexes in general. I assume that you know your basic metacharacters. If not, I've recorded &lt;a href="https://www.youtube.com/watch?v=LIVBktatfQI&amp;amp;list=PLRU13thWaP5kNYXveE9iF8aoEOlp4lgwN&amp;amp;index=2" rel="noopener noreferrer"&gt;videos about the basic of regexes using Grep&lt;/a&gt; (with exercises) if you're interested to learn more about them. It's not that hard and the benefits are huge.&lt;/p&gt;

&lt;p&gt;If you know already some common regex engines like Perl, you won't be &lt;em&gt;too much&lt;/em&gt; surprised by Vim's regexes. The basics are the same, but Vim introduces original concepts which are... interesting? If you want to quickly see the difference between Perl's regexes and Vim's, you'll find a summary by running &lt;code&gt;:help perl-patterns&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I call "metacharacter" any character which has semantics: for example, the semantics for &lt;code&gt;^&lt;/code&gt; is "beginning of the line". &lt;/p&gt;

&lt;h3&gt;
  
  
  The Concept of Atom
&lt;/h3&gt;

&lt;p&gt;You'll see often this confusing notion of &lt;em&gt;atom&lt;/em&gt; in Vim's help. It's just any metacharacter or group of metacharacters matching one character. For example, &lt;code&gt;[A-Z]&lt;/code&gt; is an atom because it matches only one character from &lt;code&gt;A&lt;/code&gt; to &lt;code&gt;Z&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Magic and Nomagic
&lt;/h3&gt;

&lt;p&gt;As we saw quickly in the &lt;a href="https://dev.to/vim-advanced/"&gt;previous article&lt;/a&gt;, Vim's regexes can have four different levels of magic: &lt;em&gt;Very magic&lt;/em&gt;, &lt;em&gt;magic&lt;/em&gt;, &lt;em&gt;nomagic&lt;/em&gt;, and &lt;em&gt;very nomagic&lt;/em&gt;. My advice in this madness: remember that &lt;em&gt;very magic&lt;/em&gt; will allow you to use every regex metacharacter without escaping them, and that  &lt;em&gt;very nomagic&lt;/em&gt; oblige you to escape these metacharacters to use them.&lt;/p&gt;

&lt;p&gt;The level of magic is set with the option &lt;code&gt;magic&lt;/code&gt;. You might be tempted to change its value; please don't. Every plugin out there expect this option set to &lt;code&gt;magic&lt;/code&gt;. Instead, we'll see different ways to change the magic level for each regex.&lt;/p&gt;

&lt;p&gt;Because everybody has the level of magic set to "magic", you'll see many Vim regexes out there with a tonne of backslash to escape &lt;em&gt;some&lt;/em&gt; metacharacters. That's why Vim's regexes often look so ugly, confusing, and hard to read. I propose this simple rule:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you need a regex, use "very magic" by adding &lt;code&gt;\v&lt;/code&gt; before your pattern.&lt;/li&gt;
&lt;li&gt;When you don't need a regex, use "very nomagic" by adding &lt;code&gt;\V&lt;/code&gt; before your pattern.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, &lt;code&gt;:%s/\v(emacs)/\1 is bad/&lt;/code&gt; will work flawlessly.&lt;/p&gt;

&lt;p&gt;If you're curious what level of magic allows what metacharacter, take a look at &lt;code&gt;:help \magic&lt;/code&gt;. You'll be granted with a wonderful table nobody remembers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Character classes
&lt;/h3&gt;

&lt;p&gt;Similarly to other regex engines, you'll have access to many character classes in Vim. You'll need to use the backslash preceding them whatever the level of magic you use.&lt;/p&gt;

&lt;h4&gt;
  
  
  Useful Character Classes
&lt;/h4&gt;

&lt;p&gt;Here are the character classes I find the most useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;\s&lt;/code&gt; or &lt;code&gt;[:blank:]&lt;/code&gt; - whitespace characters.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[A-Z]&lt;/code&gt; or &lt;code&gt;\u&lt;/code&gt; or &lt;code&gt;[:upper:]&lt;/code&gt; - Uppercase.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[a-z]&lt;/code&gt; or &lt;code&gt;\l&lt;/code&gt; or &lt;code&gt;[:lower:]&lt;/code&gt; - Lowercase.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[0-9]&lt;/code&gt; or &lt;code&gt;\d&lt;/code&gt; or &lt;code&gt;[:digit:]&lt;/code&gt; - Digits.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\_&lt;/code&gt; - Character class with end of line included.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, to illustrate a bit more the last one, if you want to include uppercase characters &lt;em&gt;and&lt;/em&gt; line breaks in your regex, you can use &lt;code&gt;\_u&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Most of the time, you can use the uppercase version of the character class to negate it. For example, &lt;code&gt;\L&lt;/code&gt; is equivalent to &lt;code&gt;[^a-z]&lt;/code&gt; (every character except the characters in the range &lt;code&gt;a&lt;/code&gt; to &lt;code&gt;z&lt;/code&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  Character Classes Set Via Options
&lt;/h4&gt;

&lt;p&gt;These character classes are interesting because you can change the characters they can match by changing the value of an option:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;\f&lt;/code&gt; - Filename characters (option &lt;code&gt;isfname&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\i&lt;/code&gt; - Identifier characters (option &lt;code&gt;isident&lt;/code&gt; option)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\k&lt;/code&gt; - Keyword character (option &lt;code&gt;iskeyword&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\p&lt;/code&gt; - Printable character (option &lt;code&gt;isprint&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Changing these options can have consequences: they are sometimes used for other commands or keystrokes. For example, the keystroke &lt;code&gt;gf&lt;/code&gt; use &lt;code&gt;isfname&lt;/code&gt; under the hood. &lt;/p&gt;

&lt;p&gt;Another tip: if you see for example the value &lt;code&gt;48-57&lt;/code&gt; in these options, it means the ASCII characters from 48 to 57, which are the numbers from 0 to 9.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zero-width
&lt;/h3&gt;

&lt;p&gt;A zero-width lookaround assertion allows you to match a pattern looking forward of backward without adding it to the match. As a result, these metacharacters don't match any character by themselves. For example, &lt;code&gt;^&lt;/code&gt; and &lt;code&gt;$&lt;/code&gt; are zero-width. &lt;/p&gt;

&lt;p&gt;If you try to substitute them, you won't replace anything because there is nothing to replace. Instead, you'll insert some text. To understand that, you can try to run &lt;code&gt;:%s/^/-&amp;gt;&lt;/code&gt; in a buffer for example.&lt;/p&gt;

&lt;p&gt;You'll need to use the backslash for these metacharacters whatever the level of magic you're using. Here are the ones which might be useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;\zs&lt;/code&gt; - Only match your pattern if what's before the metacharacter &lt;code&gt;\zs&lt;/code&gt; match what's before your pattern.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\ze&lt;/code&gt; - Only match your pattern if what's after the metacharacter &lt;code&gt;\ze&lt;/code&gt; match what's after your pattern.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\&amp;lt;&lt;/code&gt; - Match the beginning of a word.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/&amp;gt;&lt;/code&gt; - Match the end of a word.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\%^&lt;/code&gt; - Match the beginning of the file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\%$&lt;/code&gt; - Match the end of the file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\%V&lt;/code&gt; - Match inside the visual selection (or the previous one if you're not in VISUAL mode).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, in COMMAND-LINE mode after hitting &lt;code&gt;/&lt;/code&gt; for searching:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;\v^\s+\zsfor&lt;/code&gt; - Only match &lt;code&gt;for&lt;/code&gt; if there are one or more whitespace before the pattern.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\&amp;lt;if\&amp;gt;&lt;/code&gt; - Only match the word &lt;code&gt;if&lt;/code&gt; and not the substring &lt;code&gt;if&lt;/code&gt; in &lt;code&gt;cliff&lt;/code&gt; for example.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;end\%$&lt;/code&gt; - Only match the pattern &lt;code&gt;end&lt;/code&gt; if it's just before the end of the current file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another concrete example: I'm using &lt;a href="https://dev.to/zsh-install-configure-mouseless/"&gt;Zsh&lt;/a&gt; to edit command lines in Vim and I often end up with the following when I want to rename a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mv my-file-name.jpg my-file-name.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is to replace the hyphen &lt;code&gt;-&lt;/code&gt; with underscores &lt;code&gt;_&lt;/code&gt; in the filename &lt;code&gt;my-file-name.jpg&lt;/code&gt;. I could: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Switch to VISUAL mode&lt;/li&gt;
&lt;li&gt;Select the second &lt;code&gt;my-file-name.jpg&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run the following:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:'&amp;lt;,'&amp;gt;s/-/_/g
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it doesn't work. My substitute will replace &lt;em&gt;every hyphen on the line&lt;/em&gt; thanks to the &lt;code&gt;g&lt;/code&gt; flag, and, if I don't use it, I only replace &lt;em&gt;the first hyphen on the line&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;To solve the problem, I can use &lt;code&gt;\%V&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:'&amp;lt;,'&amp;gt;s/\%V-/_/g
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works as expected because the pattern only match what's inside the selection I've made.&lt;/p&gt;

&lt;h3&gt;
  
  
  Regexes and Marks
&lt;/h3&gt;

&lt;p&gt;What about using marks in our regexes?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;\%&amp;lt;'m&lt;/code&gt; - Matches before the position of mark m.&lt;br&gt;
&lt;code&gt;\%&amp;gt;'m&lt;/code&gt; - Match after the position of mark m.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;/\%&amp;gt;'mcat\%&amp;lt;'a&lt;/code&gt; search the pattern &lt;code&gt;cat&lt;/code&gt; between the mark &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;a&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help regex&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help /magic&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:help holy-grail&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help pattern&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help pattern-atoms&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help pattern-overview&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Using Your Shell Commands in Vim
&lt;/h2&gt;

&lt;p&gt;Vim is powerful by itself, but coupling Vim with the shell is switching your life's GODLIKE mode. Additionally, if your development environment is built around the shell and your tools allow you to stay as much as you can on your keyboard, you'll be unstoppable.&lt;/p&gt;
&lt;h3&gt;
  
  
  Executing External Command
&lt;/h3&gt;

&lt;p&gt;Here are the commands you can use to summon the Unfathomable Power of The Shell®:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:! &amp;lt;cmd&amp;gt;&lt;/code&gt; - Execute the shell command &lt;code&gt;&amp;lt;cmd&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:!!&lt;/code&gt; - Repeat the last command executed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, We saw in this article that we can look at the ASCII table if we run &lt;code&gt;man ascii&lt;/code&gt; in a shell. Now, you can look at it directly in Vim with &lt;code&gt;:!man ascii&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What about inserting the output of a shell command in your buffer?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:read! &amp;lt;cmd&amp;gt;&lt;/code&gt; or &lt;code&gt;:r! &amp;lt;cmd&amp;gt;&lt;/code&gt; - Execute the command &lt;code&gt;&amp;lt;cmd&amp;gt;&lt;/code&gt; and insert the output in the current buffer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:read!!&lt;/code&gt; or &lt;code&gt;:r!!&lt;/code&gt;- Repeat the last command executed and insert the output in the current buffer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, everybody in the universe can feel your brain radiating with The Power.&lt;/p&gt;
&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help :!&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help :r!&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Filter
&lt;/h3&gt;

&lt;p&gt;Did you ever dream, during the warm summer nights, about feeding the lines of your Vim buffers into the input stream of your favorite command, and replace these lines with the resulting output?&lt;/p&gt;

&lt;p&gt;Your dream will become a reality. Using &lt;code&gt;:!&lt;/code&gt; with a range will help you fulfill your destiny. For example, you could:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select a couple of lines in VISUAL mode&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;:'&amp;lt;,'&amp;gt;!grep &amp;lt;pattern&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every line without the pattern &lt;code&gt;&amp;lt;pattern&amp;gt;&lt;/code&gt; will disappear in a magical cloud. Show that to your friends, your family, or your boss, and they'll respect you forever.&lt;/p&gt;

&lt;p&gt;This functionality is called "filter", but it's quite misleading to me. If I use &lt;code&gt;1,10:!sort&lt;/code&gt;, it won't filter anything,  it will replace the input I gave to &lt;code&gt;sort&lt;/code&gt; and it will replace it with the output.&lt;/p&gt;
&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:help filter&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Folding
&lt;/h2&gt;

&lt;p&gt;A good way to manage complexity is to hide what we don't need. In that regard, folding can be handy for complex codebases and long files.&lt;/p&gt;
&lt;h3&gt;
  
  
  Choosing Your Fold Method
&lt;/h3&gt;

&lt;p&gt;The value of the option &lt;code&gt;foldmethod&lt;/code&gt; will determine how you want to manage your folds. There are 6 in total:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;manual&lt;/code&gt; - You manually define folds with the commands below.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;indent&lt;/code&gt; - Folds are created depending on the indentation level.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;expr&lt;/code&gt; - Folds are created depending on a Vimscript expression defined in &lt;code&gt;foldexpr&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;syntax&lt;/code&gt; - Fold are created depending on the syntax highlighting (if the syntax highlighting defines them).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;diff&lt;/code&gt; -  Fold unchanged text.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;marker&lt;/code&gt; - Fold depending on markers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the foldmethod &lt;code&gt;marker&lt;/code&gt;, here's an example I use in my &lt;code&gt;.vimrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="c"&gt;" Install Plugins ---------------------- {{{&lt;/span&gt;
&lt;span class="c"&gt;"&lt;/span&gt;
&lt;span class="c"&gt;" Some config here&lt;/span&gt;
&lt;span class="c"&gt;"&lt;/span&gt;
&lt;span class="c"&gt;" }}}&lt;/span&gt;
&lt;span class="c"&gt;" Plugins Config ---------------------- {{{&lt;/span&gt;
&lt;span class="c"&gt;"&lt;/span&gt;
&lt;span class="c"&gt;" Some config here&lt;/span&gt;
&lt;span class="c"&gt;"&lt;/span&gt;
&lt;span class="c"&gt;" }}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you forgot how to set and unset options, I cover that in the &lt;a href="https://dev.to/vim-beginner/"&gt;first article of the series&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keystrokes
&lt;/h3&gt;

&lt;p&gt;All these keystrokes begins with &lt;code&gt;z&lt;/code&gt;. When you look at this wonderful letter, you can let your imagination going into foreign worlds and see a fold. Folded: &lt;code&gt;-&lt;/code&gt;. Unfolded: &lt;code&gt;z&lt;/code&gt;.  Think about unfolding an old manuscript full of hidden Vim knowledge. Impressed? Me too.&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating and deleting folds
&lt;/h4&gt;

&lt;p&gt;These keystrokes only work if your foldmethod is set to &lt;code&gt;manual&lt;/code&gt; or &lt;code&gt;marker&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;zf&lt;/code&gt; - Create a &lt;code&gt;f&lt;/code&gt;old. It can be used in VISUAL mode or with a motion. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;zd&lt;/code&gt; - &lt;code&gt;d&lt;/code&gt;elete the fold  under the cursor (but not the nested ones).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;zD&lt;/code&gt; - &lt;code&gt;D&lt;/code&gt;elete the fold under the cursor, including the nested ones.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;zE&lt;/code&gt; - &lt;code&gt;E&lt;/code&gt;liminate every fold in the window. It deletes the markers if your foldmethod is set to &lt;code&gt;marker&lt;/code&gt;. Brutal.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Opening and Closing Folds
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;zo&lt;/code&gt; - &lt;code&gt;o&lt;/code&gt;pen the fold under the cursor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;zc&lt;/code&gt; - &lt;code&gt;c&lt;/code&gt;lose the fold under the cursor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;za&lt;/code&gt; - Toggle the fold under the cursor (close it if it's open, open it if it's close).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;zx&lt;/code&gt; - Undo opened and closed folds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Uppercase variants of these keystrokes (&lt;code&gt;zO&lt;/code&gt; for example) can be used to propagate the action to every nested fold.&lt;/p&gt;

&lt;h4&gt;
  
  
  Opening and Closing All Folds
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;zM&lt;/code&gt; - Close all folds&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;zR&lt;/code&gt; - Open all folds&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;zi&lt;/code&gt; - Toggle the use of folds (option &lt;code&gt;foldenable&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Moving Through Folds
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[z&lt;/code&gt; - Move to the start of the current fold.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;]z&lt;/code&gt; - Move to the end of the current fold.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;zj&lt;/code&gt; - Move downward to the start of the next fold.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;zk&lt;/code&gt; - Move upward to the start of the next fold.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Commands
&lt;/h3&gt;

&lt;p&gt;You can also use these commands to manipulate folds. Each of them accept a range as prefix.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:foldopen&lt;/code&gt; or &lt;code&gt;foldo&lt;/code&gt; - Open folds.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:foldclose&lt;/code&gt; or &lt;code&gt;foldc&lt;/code&gt; - Close folds.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:folddoopen &amp;lt;cmd&amp;gt;&lt;/code&gt; or &lt;code&gt;:foldd &amp;lt;cmd&amp;gt;&lt;/code&gt; - Execute command &lt;code&gt;&amp;lt;cmd&amp;gt;&lt;/code&gt; on all opened fold.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:folddoclosed &amp;lt;cmd&amp;gt;&lt;/code&gt; or &lt;code&gt;:folddoc &amp;lt;cmd&amp;gt;&lt;/code&gt; - Execute command &lt;code&gt;&amp;lt;cmd&amp;gt;&lt;/code&gt; on all closed fold&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using a bang &lt;code&gt;!&lt;/code&gt; for the first two ones (&lt;code&gt;foldo!&lt;/code&gt; and &lt;code&gt;foldc!&lt;/code&gt;) will open or close all nested folds too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help Folding&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help fold-methods&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help fold-commands&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Are We There Yet?
&lt;/h2&gt;

&lt;p&gt;Suddenly, Dave woke up in his bed. This was all a dream! The hooded figures, the telepathic Vim course, everything! But he has now a lot of knowledge about Vim he didn't have before falling asleep. Was it real? Was it a dream? Is our reality just a dream? Are we part of a weird Sim-like simulation? Are raspberries better than strawberries?&lt;/p&gt;

&lt;p&gt;So many questions, so few answers! At least, we learned together the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can have access to 10 global quickfix lists, and 10 location lists per window.&lt;/li&gt;
&lt;li&gt;The NORMAL mode is powerful, but many useful keystrokes wait for our fingers to type them in INSERT and VISUAL modes.&lt;/li&gt;
&lt;li&gt;Vim regular expressions can be more or less "magic", deciding what metacharacter you can use in your patterns without escaping them.&lt;/li&gt;
&lt;li&gt;An atom in Vim regexes is any pattern matching one character.&lt;/li&gt;
&lt;li&gt;Zero-width metacharacters don't match any character but help you narrow down your match depending on its context.&lt;/li&gt;
&lt;li&gt;You can use marks in your regexes too.&lt;/li&gt;
&lt;li&gt;You can run any shell command with &lt;code&gt;:!&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You can spit output of shell commands in Vim with &lt;code&gt;:read&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Folding can be useful when you've too much content on your screen.&lt;/li&gt;
&lt;li&gt;Folding can also be used to apply a specific command on folded lines with &lt;code&gt;:foldd&lt;/code&gt; and &lt;code&gt;:folddoc&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not over. More discoveries will be made in the Name of Vim, and we'll all get Its Highest Power to build new applications which will save the world.&lt;/p&gt;




&lt;h2&gt;
  
  
  Becoming Mouseless
&lt;/h2&gt;

&lt;p&gt;Do you want to build a &lt;a href="https://themouseless.dev" rel="noopener noreferrer"&gt;Mouseless Development Environment&lt;/a&gt; where the Linux shell and Vim have a central role?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://themouseless.dev" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthemouseless.dev%2Fimages%2Fsmall_cover.webp" alt="building your mouseless development environment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Switching between the keyboard and the mouse costs cognitive energy. This book will guide you step by step to set up a Linux-based development environment that keeps your hands on your keyboard.&lt;/p&gt;

&lt;p&gt;Take the brain power you've been using to juggle input devices and focus it where it belongs: on what you create.&lt;/p&gt;




</description>
      <category>vim</category>
      <category>terminal</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A Vim Guide for Advanced Users</title>
      <dc:creator>Matthieu Cneude</dc:creator>
      <pubDate>Tue, 01 Jun 2021 13:27:48 +0000</pubDate>
      <link>https://forem.com/phantas0s/a-vim-guide-for-advanced-users-1ddk</link>
      <guid>https://forem.com/phantas0s/a-vim-guide-for-advanced-users-1ddk</guid>
      <description>&lt;p&gt;Welcome to the third part of this series aimed to help you unleash a power never seen on Earth using the Almighty Vim.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-beginner/" rel="noopener noreferrer"&gt;Vim for Beginners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-intermediate/" rel="noopener noreferrer"&gt;Vim for Intermediate Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-advanced/" rel="noopener noreferrer"&gt;Vim for Advanced Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thevaluable.dev/vim-adept/" rel="noopener noreferrer"&gt;Vim for Adept Users&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We'll see together in this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some nice keystrokes beginning with &lt;code&gt;g&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;What ranges are and how to use them.&lt;/li&gt;
&lt;li&gt;The quickfix list and the location lists.&lt;/li&gt;
&lt;li&gt;The marvelous substitute command.&lt;/li&gt;
&lt;li&gt;The crazy useful &lt;code&gt;:global&lt;/code&gt; (or &lt;code&gt;:g&lt;/code&gt;) command.&lt;/li&gt;
&lt;li&gt;What marks are and what you can do with them.&lt;/li&gt;
&lt;li&gt;How to increase and decrease numbers with a single keystroke.&lt;/li&gt;
&lt;li&gt;How to sort text with a nice command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But before going into the juicy content of this article, I've some recommendations for you, dear reader:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fire up your Vim and play around with the commands and keystrokes while reading. It's the best way for you to remember everything which blew you away. You'll then be able to be blown away whenever you like for the rest of your life.&lt;/li&gt;
&lt;li&gt;Don't use a cheatsheet; write your own as you read. It will allow you to come back easily to the commands you find the most useful for &lt;em&gt;your own needs&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Enough rambling. Let's begin!&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful "g" Keystrokes
&lt;/h2&gt;

&lt;p&gt;Let's begin gently with a mixed bag of keystrokes starting with &lt;code&gt;g&lt;/code&gt;. There are many of these "g" commands in Vim, and we already saw some of them in the previous articles. Can you recall them?&lt;/p&gt;

&lt;p&gt;You can use these keystrokes in NORMAL mode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;gf&lt;/code&gt; - Edit the file located at the filepath under your cursor. 

&lt;ul&gt;
&lt;li&gt;You can use &lt;code&gt;CTRL+W CTRL+F&lt;/code&gt; to open the file in a new window. &lt;/li&gt;
&lt;li&gt;It can open the URL under your cursor if you have the plugin &lt;code&gt;netrw&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;gx&lt;/code&gt; - Open the file located at the filepath under your cursor. 

&lt;ul&gt;
&lt;li&gt;It will use the default application used by your OS for this filetype. &lt;/li&gt;
&lt;li&gt;It works with URLs too. It will open your favorite browser and load the website.&lt;/li&gt;
&lt;li&gt;It only works if you have the plugin &lt;code&gt;netrw&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;gi&lt;/code&gt; - Move to the last insertion you did and switch to INSERT mode. 

&lt;ul&gt;
&lt;li&gt;Pretty useful if you stopped your editing to look at some other file. &lt;/li&gt;
&lt;li&gt;It uses marks under the hood: more on that later in this article.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;gv&lt;/code&gt; - Start VISUAL mode and use the selection made during the last VISUAL mode.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;gn&lt;/code&gt; - Select the match of your last search:

&lt;ol&gt;
&lt;li&gt;Move to the last searched match.&lt;/li&gt;
&lt;li&gt;Switch to VISUAL mode (if you weren't in VISUAL mode already).&lt;/li&gt;
&lt;li&gt;Select the match.&lt;/li&gt;
&lt;li&gt;You can continue to hit &lt;code&gt;n&lt;/code&gt; (or &lt;code&gt;gn&lt;/code&gt;) to select the area between the current match and the next match.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;gI&lt;/code&gt; - Insert text at the beginning of the line, no matter what the first characters are.

&lt;ul&gt;
&lt;li&gt;The keystroke &lt;code&gt;I&lt;/code&gt; insert text &lt;em&gt;just before the first non-blank characters&lt;/em&gt; of the line.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;ga&lt;/code&gt; - Print the &lt;code&gt;a&lt;/code&gt;scii value of the character under the cursor in decimal, hexadecimal or octal.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;gu&lt;/code&gt; - Lowercase using a motion (for example, &lt;code&gt;guiw&lt;/code&gt;).&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;gU&lt;/code&gt; - Uppercase using a motion (for example, &lt;code&gt;gUiw&lt;/code&gt;).&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;To try out &lt;code&gt;gf&lt;/code&gt; and &lt;code&gt;gx&lt;/code&gt;, you can write for example &lt;code&gt;https://www.google.com/&lt;/code&gt; in Vim, place your cursor on it, and hit the keystrokes. Don't forget the trailing slash in your URL.&lt;/p&gt;

&lt;p&gt;You'll soon discover an inconvenience with &lt;code&gt;gx&lt;/code&gt;: when you use it on a filepath, Vim will hang till you close the file. That's why I've created the following mapping you can add to your &lt;code&gt;.vimrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nnoremap gX :silent :execute
            \ "!xdg-open" expand('%:p:h') . "/" . expand("&amp;lt;cfile&amp;gt;") " &amp;amp;"&amp;lt;cr&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It maps the keystroke &lt;code&gt;gX&lt;/code&gt; to use &lt;code&gt;xdg-open&lt;/code&gt; with a relative filepath under your cursor. It will open the file with your favorite application &lt;em&gt;in the background&lt;/em&gt;. The program &lt;code&gt;xdg-open&lt;/code&gt; will only work on Linux-based systems; for MacOS, try &lt;code&gt;open&lt;/code&gt; instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help reference&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help g&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ranges
&lt;/h2&gt;

&lt;p&gt;Now that we're done with the appetizers, let's discover the first real dish of our Vim feast: the ranges. You can apply them to many commands, making them terribly powerful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basics
&lt;/h3&gt;

&lt;p&gt;In Vim's help, every command accepting a range will have the string of characters &lt;code&gt;[range]&lt;/code&gt; in front of them. Multiple line specifiers are possible, separated by commas &lt;code&gt;,&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here are the most interesting ranges you can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt; - Any number &lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt; in your range refers to a line number.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.&lt;/code&gt; - Represent the current line (often the default range).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$&lt;/code&gt; - Represent the last line of the current buffer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%&lt;/code&gt; - Represent the entire file (same as &lt;code&gt;1,$&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;*&lt;/code&gt; - Use the last selection you've made during the last VISUAL mode.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, using the command &lt;code&gt;:d&lt;/code&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:1,40d&lt;/code&gt; - Delete line 1 to 40 included.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:2,$d&lt;/code&gt; - Delete every line from the second one till the end of the file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:.,$d&lt;/code&gt; - Delete every line from the current one till the end of the file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:%d&lt;/code&gt; - Delete every line.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also do some arithmetic with ranges if you want. For example, let's imagine your cursor is on the line 60: the range &lt;code&gt;.,.+10&lt;/code&gt; will be equivalent to the range &lt;code&gt;60,70&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual Mode and Range
&lt;/h3&gt;

&lt;p&gt;If you switch to COMMAND-LINE mode after doing some selection in VISUAL mode, you'll see these two symbols appearing: &lt;code&gt;'&amp;lt;&lt;/code&gt; and &lt;code&gt;'&amp;gt;&lt;/code&gt; with a comma &lt;code&gt;,&lt;/code&gt; in between. This is a range too!&lt;/p&gt;

&lt;p&gt;The symbols &lt;code&gt;'&amp;lt;&lt;/code&gt; represents the first line you've selected and &lt;code&gt;'&amp;gt;&lt;/code&gt; the last line. Each of these are marks; again, we'll see more about marks below.&lt;/p&gt;

&lt;p&gt;In practice, the ranges &lt;code&gt;'&amp;lt;,'&amp;gt;&lt;/code&gt; and &lt;code&gt;*&lt;/code&gt; are synonym, but you'll have more flexibility with the first. For example, you can execute a command from the first line you've selected till the end of the file with the range &lt;code&gt;'&amp;lt;,$&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help [range]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help v_:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help '&amp;lt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help '&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Vim's Quickfix And Location List
&lt;/h2&gt;

&lt;p&gt;Now, let's talk about a very useful data structure available in Vim, the quickfix list. &lt;/p&gt;

&lt;p&gt;Don't confuse the quickfix list and the quickfix window: these are two different entities. The first is a data structure, the second can display this data structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quickfix Lists
&lt;/h3&gt;

&lt;p&gt;You can think of a quickfix list as a set of positions in one or multiple files.&lt;/p&gt;

&lt;h4&gt;
  
  
  Basics
&lt;/h4&gt;

&lt;p&gt;Let's take an example: what happens if you run the command &lt;code&gt;:vimgrep hello *&lt;/code&gt;?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It will search the pattern "hello" in every file of your working directory.&lt;/li&gt;
&lt;li&gt;It will populate a quickfix list with every position matching your pattern "hello".&lt;/li&gt;
&lt;li&gt;It will move your cursor to the first position of the quickfix list.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want to know more about vimgrep and other tools you can search with, I &lt;a href="https://thevaluable.dev/vim-search-find-replace/" rel="noopener noreferrer"&gt;wrote an article about that&lt;/a&gt;. Other commands (like &lt;code&gt;:make&lt;/code&gt; or &lt;code&gt;:grep&lt;/code&gt;) also populate automatically a quickfix list.&lt;/p&gt;

&lt;p&gt;Let's expand the mystery around marks: these positions in the quickfix list are in fact hidden mark!&lt;/p&gt;

&lt;p&gt;The quickfix list is often used to display specific errors in a codebase, often spit out from a compiler or a linter (via the command &lt;code&gt;:make&lt;/code&gt; for example), but not only, as we just saw. I call the entries of a quickfix list "positions" to be more general, but sometimes Vim's help will refer to them as "errors". Don't be confused: it's the same idea.&lt;/p&gt;

&lt;p&gt;Among other conditions, a quickfix list entry needs to have a filename for you to be able to jump to its position. Otherwise, the entry doesn't point to anything. Difficult to move to anything.&lt;/p&gt;

&lt;h4&gt;
  
  
  Useful Commands
&lt;/h4&gt;

&lt;p&gt;Here are the commands you can use to navigate through the current quickfix list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:cl&lt;/code&gt; or &lt;code&gt;:clist&lt;/code&gt; - Display all valid entries of the current quickfix list. You can add a range as argument (only numbers).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:cc &amp;lt;number&amp;gt;&lt;/code&gt; - Move to the &lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt;th entry of the current quickfix list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:cnext&lt;/code&gt; or &lt;code&gt;:cn&lt;/code&gt; - Move to the next entry of the current quickfix list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:cprevious&lt;/code&gt; or &lt;code&gt;:cp&lt;/code&gt; - Move to the previous entry of the current quickfix list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:cfirst&lt;/code&gt; or &lt;code&gt;:cfir&lt;/code&gt; - Move to the first entry of the current quickfix list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:clast&lt;/code&gt; or &lt;code&gt;:clas&lt;/code&gt; - Move to the last entry of the current quickfix list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are additional commands which make quickfix lists really powerful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:cdo &amp;lt;cmd&amp;gt;&lt;/code&gt; - Execute a command &lt;code&gt;&amp;lt;cmd&amp;gt;&lt;/code&gt; on each valid entry of the current quickfix list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:cexpr &amp;lt;expr&amp;gt;&lt;/code&gt; or &lt;code&gt;:cex &amp;lt;expr&amp;gt;&lt;/code&gt; - Create a quickfix list using the result of evaluating the Vimscript expression &lt;code&gt;&amp;lt;expr&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:caddexpr &amp;lt;expr&amp;gt;&lt;/code&gt; or &lt;code&gt;:cadde &amp;lt;expr&amp;gt;&lt;/code&gt; - Appends the result of evaluating the Vimscript expression &lt;code&gt;&amp;lt;expr&amp;gt;&lt;/code&gt; to the current quickfix list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have no clue how to use the last two commands, you can do for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:cex []&lt;/code&gt; - Empty the current quickfix list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:cex system("&amp;lt;cmd&amp;gt;")&lt;/code&gt; - Populate your quickfix list with any shell command &lt;code&gt;&amp;lt;cmd&amp;gt;&lt;/code&gt;. You can try it with &lt;code&gt;ls&lt;/code&gt; for example.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Quickfix Window
&lt;/h3&gt;

&lt;p&gt;What about displaying the current quickfix list in a new buffer? You can do that with the following command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:copen&lt;/code&gt; or &lt;code&gt;:cope&lt;/code&gt; - Open a window (with a special buffer) to show the current quickfix list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can only have one quickfix window open. To move to the position of the selected entry of the quickfix list in the quickfix window, hit &lt;code&gt;ENTER&lt;/code&gt; or &lt;code&gt;.cc&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Location Lists
&lt;/h3&gt;

&lt;p&gt;A location list is similar to a quickfix list, except that the first is local to a window and the second is global to your Vim instance. In other words, you can have multiple location lists available at the same time (one per window open), but you can only have access to one quickfix list.&lt;/p&gt;

&lt;p&gt;The commands for location lists are similar to the ones for the quickfix lists; often, you'll only have to replace the first &lt;code&gt;c&lt;/code&gt; (qui&lt;code&gt;c&lt;/code&gt;fix) of the command with &lt;code&gt;l&lt;/code&gt; (&lt;code&gt;l&lt;/code&gt;ocation). &lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:lli&lt;/code&gt; or &lt;code&gt;:llist&lt;/code&gt; - Display all valid entries of the current location list. You can add a range as argument (only numbers).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:ll &amp;lt;number&amp;gt;&lt;/code&gt; - Move to the entry &lt;code&gt;&amp;lt;number&amp;gt;&lt;/code&gt; of the current location list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:lnext&lt;/code&gt; or &lt;code&gt;:lne&lt;/code&gt; - Move to the next entry of the current quickfix list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To populate your location list you can also use the commands &lt;code&gt;:lvimgrep&lt;/code&gt; or &lt;code&gt;:lmake&lt;/code&gt; for example.&lt;/p&gt;

&lt;p&gt;Often, Vim users will use the quickfix list for anything related to errors in their codebase, and the location list for search results. But it's up to you at the end of the day. With Vim, you're the master of your destiny.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help quickfix&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help quickfix-window&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help location-list&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help location-list-window&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help expr&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help system()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Vim's Registers
&lt;/h2&gt;

&lt;p&gt;The registers are another big dish in our Vim feast. You can think of registers as places where you can read or write some text. I like to think about them as Vim's clipboards. &lt;/p&gt;

&lt;h3&gt;
  
  
  Specifying a Register
&lt;/h3&gt;

&lt;p&gt;Here's a command and a NORMAL mode keystroke to display and &lt;em&gt;specify&lt;/em&gt; registers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:registers&lt;/code&gt; or &lt;code&gt;:reg&lt;/code&gt; - Display the content of your registers.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"&amp;lt;reg&amp;gt;&lt;/code&gt; - This keystroke &lt;em&gt;specifies&lt;/em&gt; the register &lt;code&gt;&amp;lt;reg&amp;gt;&lt;/code&gt; to be read or written.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do you know when the register &lt;code&gt;&amp;lt;reg&amp;gt;&lt;/code&gt; is read or written using the keystroke &lt;code&gt;"&lt;/code&gt;? It depends of the keystroke you use afterward. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To write the register &lt;code&gt;a&lt;/code&gt;:

&lt;ol&gt;
&lt;li&gt;Hit &lt;code&gt;"a&lt;/code&gt; in NORMAL mode to specify what register you want to write on.&lt;/li&gt;
&lt;li&gt;Yank, change, or delete some content (for example by using &lt;code&gt;dd&lt;/code&gt; in NORMAL mode) to write it to &lt;code&gt;a&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;To read the register &lt;code&gt;a&lt;/code&gt;:

&lt;ol&gt;
&lt;li&gt;Hit &lt;code&gt;"a&lt;/code&gt; in NORMAL mode to specify what register you want to read.&lt;/li&gt;
&lt;li&gt;Use a put keystroke in NORMAL mode (for example &lt;code&gt;p&lt;/code&gt; or &lt;code&gt;P&lt;/code&gt;) to spit out the content of the register in your current buffer.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We take the example of register &lt;code&gt;a&lt;/code&gt; here, but it will work for any writable register. &lt;/p&gt;

&lt;h3&gt;
  
  
  The Types of Registers
&lt;/h3&gt;

&lt;p&gt;There are 10 different types of registers in Vim:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The unnamed register&lt;/strong&gt; (&lt;code&gt;"&lt;/code&gt;) - Contain the last deleted, changed, or yanked content, &lt;em&gt;even if&lt;/em&gt; one register was specified.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The numbered registers&lt;/strong&gt; (from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;9&lt;/code&gt;)

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;0&lt;/code&gt; contains the content of the last yank.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt; to &lt;code&gt;9&lt;/code&gt; is a stack containing the content you've deleted or changed.

&lt;ol&gt;
&lt;li&gt;Each time you delete or change some content, it will be added to the register &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The previous content of the register &lt;code&gt;1&lt;/code&gt; will be assigned to register &lt;code&gt;2&lt;/code&gt;, the previoius content of &lt;code&gt;2&lt;/code&gt; to &lt;code&gt;3&lt;/code&gt;...&lt;/li&gt;
&lt;li&gt;When something is added to the register &lt;code&gt;1&lt;/code&gt;, the content of the register &lt;code&gt;9&lt;/code&gt; is lost.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;None of these registers are written if you've specified one before with the keystroke &lt;code&gt;"&lt;/code&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;The small delete register&lt;/strong&gt; (&lt;code&gt;-&lt;/code&gt;)

&lt;ul&gt;
&lt;li&gt;Contains any deleted or changed content smaller than one line.&lt;/li&gt;
&lt;li&gt;It's not written if you specified a register with &lt;code&gt;"&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;The named registers&lt;/strong&gt; (range from &lt;code&gt;a&lt;/code&gt; to &lt;code&gt;z&lt;/code&gt;)

&lt;ul&gt;
&lt;li&gt;Vim will never write to them if you don't specify them with the keystroke &lt;code&gt;"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You can use the uppercase name of each register to append to it (instead of overwriting it).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;The read only registers&lt;/strong&gt; (&lt;code&gt;.&lt;/code&gt;, &lt;code&gt;%&lt;/code&gt; and &lt;code&gt;:&lt;/code&gt;) 

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.&lt;/code&gt; contains the last inserted text.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%&lt;/code&gt; contains the name of the current file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:&lt;/code&gt; contains the most recent command line executed.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;The alternate buffer register&lt;/strong&gt; (&lt;code&gt;#&lt;/code&gt;) - Contain the alternate buffer for the current window.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;The expression register&lt;/strong&gt; (&lt;code&gt;=&lt;/code&gt;) - Store the result of an expression. More about this register below.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;The selection registers&lt;/strong&gt; (&lt;code&gt;+&lt;/code&gt; and &lt;code&gt;*&lt;/code&gt;)

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;+&lt;/code&gt; is synchronized with the system clipboard.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;*&lt;/code&gt; is synchronized with the selection clipboard (only on *nix systems).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;The black hole register&lt;/strong&gt; (&lt;code&gt;_&lt;/code&gt;) - Everything written in there will disappear forever.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;The last search pattern register&lt;/strong&gt; (&lt;code&gt;/&lt;/code&gt;) - This register contains your last search.&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;As you can see, even if you don't specify any register with the keystroke &lt;code&gt;"&lt;/code&gt;, the content you delete, change, or yank will automatically overwrite one (or multiple) of them. So if you don't want the content you write to your registers to be silently overwritten by Vim, &lt;em&gt;always write in the named registers&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Using a put command without specifying any register will spit the content of the unnamed register by default. But you might have this line in your &lt;code&gt;vimrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clipboard+=unnamedplus
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In that case, the content you change, delete, or yank will go directly in the unnamed register &lt;em&gt;and&lt;/em&gt; the &lt;code&gt;+&lt;/code&gt; register. Using put commands will directly output the &lt;code&gt;+&lt;/code&gt; register too. Many find it useful (including me) to access your OS clipboard more easily, without the need to specify the &lt;code&gt;+&lt;/code&gt; register for reading or writing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Appending a Recording
&lt;/h3&gt;

&lt;p&gt;We've seen in the &lt;a href="https://dev.to/vim-intermediate/"&gt;previous article&lt;/a&gt; that you can record your keystrokes using &lt;code&gt;q&lt;/code&gt;. Now that you know how to use registers, you can manipulate these keystrokes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you made a mistake during the recording, you can spit the whole register, modify it, and save it back.&lt;/li&gt;
&lt;li&gt;You can append to your recording by using the uppercase variant of your register. For example:

&lt;ol&gt;
&lt;li&gt;Hit &lt;code&gt;qa&lt;/code&gt; and record whatever keystrokes you want. Stop the recording by hitting &lt;code&gt;q&lt;/code&gt; again.&lt;/li&gt;
&lt;li&gt;You realize that you forgot a couple of keystrokes.&lt;/li&gt;
&lt;li&gt;Execute your keystrokes to be sure you're at the last position of your recording.&lt;/li&gt;
&lt;li&gt;Hit &lt;code&gt;qA&lt;/code&gt; to &lt;em&gt;append&lt;/em&gt; to your register &lt;code&gt;a&lt;/code&gt;. When you're done, hit &lt;code&gt;q&lt;/code&gt; again.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You've just gained even more flexibility for your macros.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Registers in INSERT and COMMAND LINE modes
&lt;/h3&gt;

&lt;p&gt;The magical keystroke &lt;code&gt;"&lt;/code&gt; is great for NORMAL mode, but what about spitting the content of a register in INSERT mode or COMMAND LINE mode? For that, you can use &lt;code&gt;CTRL+R &amp;lt;reg&amp;gt;&lt;/code&gt; to put the content of register &lt;code&gt;&amp;lt;reg&amp;gt;&lt;/code&gt; in your current buffer.&lt;/p&gt;

&lt;p&gt;For example, if you hit &lt;code&gt;CTRL+R %&lt;/code&gt; in INSERT mode, you'll put the content of the register &lt;code&gt;%&lt;/code&gt;  in your current buffer.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Insane Expression Register
&lt;/h3&gt;

&lt;p&gt;If you don't know the expression register, I'm about to revolution your life. I hope you're ready.&lt;/p&gt;

&lt;p&gt;Try this: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Switch to INSERT mode and hit the keystroke &lt;code&gt;CTRL+r =&lt;/code&gt;. You'll move to Vim's command-line.&lt;/li&gt;
&lt;li&gt;From there, you can type any Vimscript expression you want, like &lt;code&gt;system("ls")&lt;/code&gt; we saw above, or &lt;code&gt;4+4&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Hit &lt;code&gt;ENTER&lt;/code&gt; to run the expression, and you'll see the output of the shell command &lt;code&gt;ls&lt;/code&gt; directly inserted in your buffer!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's useful to evaluate some custom functions you've defined while staying in insert mode. If you use Neovim, you can use the function &lt;code&gt;luaeval()&lt;/code&gt; to evaluate some Lua too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clearing a Register
&lt;/h3&gt;

&lt;p&gt;A last little trick about registers: if you want to empty one, you can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qaq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beginning a recording also deletes everything which is in this register. So you just need to stop the recording by hitting &lt;code&gt;q&lt;/code&gt; again to have an empty register.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help registers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help clipboard&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help clipboard-unnamed&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help clipboard-unnamedplus&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Substitute Commands
&lt;/h2&gt;

&lt;p&gt;Let's continue our ascension to become The Vim God (or Goddess). The substitute command is next on the menu.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basics
&lt;/h3&gt;

&lt;p&gt;If you're already familiar with the CLI &lt;code&gt;sed&lt;/code&gt;, this command will remind you some good old memories.&lt;/p&gt;

&lt;p&gt;A substitution is a way to replace some content with some other content, using a range and a count. The count will decide how many lines is affected by your substitution from the last line of your range.&lt;/p&gt;

&lt;p&gt;Like many other commands, the default range is the current line if you don't specify it.&lt;/p&gt;

&lt;p&gt;Here's the pattern of the command itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:s/pattern/replacement/flags
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What does this mean?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;pattern&lt;/code&gt; is the search you want to match.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;replacement&lt;/code&gt; will replace the &lt;em&gt;first match&lt;/em&gt; of the pattern on each line.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;flag&lt;/code&gt; modify the behavior of the command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's another element, represented here with a slash  &lt;code&gt;/&lt;/code&gt;: the separator. It doesn't have to be a slash, it can be any character except:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An alphanumerical character (a character included in the range &lt;code&gt;a-z&lt;/code&gt;, &lt;code&gt;A-Z&lt;/code&gt;, and &lt;code&gt;0-9&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;A double quote&lt;code&gt;"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A pipe &lt;code&gt;|&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;replacement&lt;/code&gt; is not mandatory: if you omit it, the substitute command will delete the pattern matched.&lt;/p&gt;

&lt;p&gt;You can also run &lt;code&gt;:s&lt;/code&gt; without any range, pattern, replacement, flags, or count. In that case, it will repeat the last substitution you've done without the flags; you can add new flags (except &lt;code&gt;&amp;amp;&lt;/code&gt;) and a count if you want to.&lt;/p&gt;

&lt;p&gt;Let's see some examples to understand how it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:s/pattern/replacement/&lt;/code&gt; - Substitute the first occurrence of &lt;code&gt;pattern&lt;/code&gt; on the current line with &lt;code&gt;replacement&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:s#pattern#replacement#&lt;/code&gt; - Equivalent substitution to the one just above. Handy if you have some URLs in your &lt;code&gt;pattern&lt;/code&gt; or your &lt;code&gt;replacement&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:s/pattern/&lt;/code&gt; - delete the first occurrence of &lt;code&gt;pattern&lt;/code&gt; on the current line.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:s/pattern/replacement/g&lt;/code&gt; - Substitute every occurrence of &lt;code&gt;pattern&lt;/code&gt; on the current line.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also add a range as prefix and a count as suffix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:%s/pattern/replacement/&lt;/code&gt; - Substitute every &lt;em&gt;first&lt;/em&gt; occurrence of &lt;code&gt;pattern&lt;/code&gt; on each line of the current buffer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:%s/pattern/replacement/g&lt;/code&gt; - Substitute every occurrence of &lt;code&gt;pattern&lt;/code&gt; on each line of the current buffer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:1,10s/pattern/replacement/&lt;/code&gt; - Substitute every &lt;em&gt;first&lt;/em&gt; occurrence of &lt;code&gt;pattern&lt;/code&gt; on the first ten lines of the current buffer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:s/pattern/replacement/ 10&lt;/code&gt; - Substitute every &lt;em&gt;first&lt;/em&gt; occurrence of &lt;code&gt;pattern&lt;/code&gt; for the current line and the 10 next lines.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:1,10s/pattern/replacement/ 5&lt;/code&gt; - Substitute every &lt;em&gt;first&lt;/em&gt; occurrence of &lt;code&gt;pattern&lt;/code&gt; on the first ten lines and on the five lines below the last line of the range.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:s g 10&lt;/code&gt; - Repeat the last substitution without its flag, and add a new flag &lt;code&gt;g&lt;/code&gt;. It will affect the 10 lines after the last line of the last substitute command. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Vim's "Magical" Patterns
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;pattern&lt;/code&gt; in that case is a regular expression. But it's not the good old regex engine you're familiar with from high level programming languages. Vim has its own regex engine (actually, it has two!) which can be quite confusing.&lt;/p&gt;

&lt;p&gt;Regexes in Vim are more or less magic. You think I'm kidding? I'm not. Here's what I find useful to remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To have access to &lt;em&gt;all&lt;/em&gt; regex metacharacters, you can prefix your pattern with &lt;code&gt;\v&lt;/code&gt; (&lt;code&gt;v&lt;/code&gt;ery magic).&lt;/li&gt;
&lt;li&gt;To have access to &lt;em&gt;almost all&lt;/em&gt; regex metacharacters (except &lt;code&gt;(&lt;/code&gt;, &lt;code&gt;)&lt;/code&gt; and &lt;code&gt;|&lt;/code&gt;), use the command &lt;code&gt;:sm&lt;/code&gt; instead of &lt;code&gt;:s&lt;/code&gt; (&lt;code&gt;s&lt;/code&gt;ubstitute &lt;code&gt;m&lt;/code&gt;agic).&lt;/li&gt;
&lt;li&gt;To have access to &lt;em&gt;none&lt;/em&gt; of the metacharacters (except &lt;code&gt;$&lt;/code&gt;), use &lt;code&gt;:sno&lt;/code&gt; instead of &lt;code&gt;:s&lt;/code&gt; (&lt;code&gt;s&lt;/code&gt;ubstitute &lt;code&gt;no&lt;/code&gt;magic).&lt;/li&gt;
&lt;li&gt;To have access to &lt;em&gt;none&lt;/em&gt; of the metacharacters, you can prefix your pattern with &lt;code&gt;\V&lt;/code&gt; (&lt;code&gt;V&lt;/code&gt;ery nomagic).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if I want to delete all opening parenthesis in my buffer, I can run one of these three equivalent commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:%s/\V(/
:%sm/(/
:%s/\(/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you know your regex metacharacters, you might wonder what's the metacharacter &lt;code&gt;~&lt;/code&gt;. It's the latest substituted string in Vim's world. In fact, you can use many more metacharacters (called &lt;em&gt;atoms&lt;/em&gt;) and character classes in your Vim's regex.&lt;/p&gt;

&lt;p&gt;If don't know you're regex metacharacters, &lt;a href="https://www.youtube.com/watch?v=LIVBktatfQI" rel="noopener noreferrer"&gt;I've recorded a couple of videos&lt;/a&gt; explaining the basics of regular expressions (using grep).&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://thevaluable.dev/vim-adept/" rel="noopener noreferrer"&gt;next article&lt;/a&gt; in this series dive into Vim's regexes a bit deeper.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Commands
&lt;/h3&gt;

&lt;p&gt;Here are two other commands I find useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:&amp;amp;&amp;amp;&lt;/code&gt; - Repeat the last substitute with its flags.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:~&lt;/code&gt; - Repeat the last substitute command with the same replacement, but with the last used &lt;em&gt;search&lt;/em&gt; pattern.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, let's say that you execute successively the following in Vim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:s/pattern/replacement/
/hello
:~
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last command will substitute &lt;code&gt;hello&lt;/code&gt; with &lt;code&gt;replacement&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also use these useful keystrokes in NORMAL mode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;amp;&lt;/code&gt; - Repeat the last substitute, without its range and its flags.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;g&amp;amp;&lt;/code&gt; - Repeat the last substitute, with its range as well as its flags, and replace its pattern with the last &lt;em&gt;search&lt;/em&gt; pattern.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Substitutes Flags
&lt;/h3&gt;

&lt;p&gt;Here are some flags which can be useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;amp;&lt;/code&gt; - Use the flag(s) from the previous substitute command.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;c&lt;/code&gt; - Ask you to confirm each substitution.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;g&lt;/code&gt; - Replace all occurrences in each line (not only the first one).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;i&lt;/code&gt; - The pattern is case-insensitive.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I&lt;/code&gt; - The pattern is case-sensitive.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;n&lt;/code&gt; - Only report the number of match without substitute.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can now substitute like crazy to your heart's content!&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help :substitute&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help :sm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help :sno&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help :s_flags&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Global Command
&lt;/h2&gt;

&lt;p&gt;You don't have enough? You want even more power? Behold the Holy Global Command! It works similarly to the substitute command, except that it will execute a command instead of replacing a pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basics
&lt;/h3&gt;

&lt;p&gt;Here's the pattern of the command itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:g/pattern/command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also prefix it with a range if you want to.&lt;/p&gt;

&lt;p&gt;As an example, let's imagine that you have the urge to delete all the lines of your current buffer containing the pattern "useless". To do that, you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:g/useless/d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice, but I can give you &lt;em&gt;even more&lt;/em&gt; power.&lt;/p&gt;

&lt;h3&gt;
  
  
  Normal mode Commands
&lt;/h3&gt;

&lt;p&gt;Do you know the command &lt;code&gt;:norm&lt;/code&gt;? You can give to it some NORMAL mode keystrokes and it will apply them for you, &lt;em&gt;as if you were hitting them in NORMAL mode&lt;/em&gt;. For example, the following will delete the word under the cursor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:norm daw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's now combine a normal mode command with the global command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:g/useless/norm gu$
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will lowercase every line containing the pattern &lt;code&gt;useless&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When I first heard about that, I saw the Universe, the Big Bang, the cycle of creation and destruction. I understood life and death. I became blessed, chanting the power of Vim in every free cities.&lt;/p&gt;

&lt;p&gt;A last tip: &lt;code&gt;:norm&lt;/code&gt; use the key mappings you've defined. If you only want to use Vim's default mapping, you can use &lt;code&gt;norm!&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;If you write a plugin, &lt;em&gt;always&lt;/em&gt; use &lt;code&gt;norm!&lt;/code&gt;. You don't know what mappings have your users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help :global&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help :normal&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Marks
&lt;/h2&gt;

&lt;p&gt;It's time to answer the question haunting your incredible mind: what are marks?&lt;/p&gt;

&lt;h3&gt;
  
  
  Basics
&lt;/h3&gt;

&lt;p&gt;You can think of a mark as a specific position in a buffer. To set one, you can use &lt;code&gt;m&lt;/code&gt; in NORMAL mode followed by a character in the following ranges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;a-z&lt;/code&gt; - These marks are local to one buffer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;A-Z&lt;/code&gt; - These marks are global to multiple buffers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have a "viminfo" file set via the option &lt;code&gt;viminfo&lt;/code&gt; in Vim, or if you have a "shada" file set via the option &lt;code&gt;shada&lt;/code&gt; in Neovim, these marks are persisted. This means that you can come back to them even if you closed the file.&lt;/p&gt;

&lt;p&gt;If you wonder what are Vim's options and how to display their values, &lt;a href="https://dev.to/vim-beginners/"&gt;I wrote about it in the first article of this series&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are also read-only marks in the range &lt;code&gt;0-9&lt;/code&gt;. They are only available when using a &lt;code&gt;viminfo&lt;/code&gt; file (for Vim) or a &lt;code&gt;shada&lt;/code&gt; file (for Neovim). They store the position of your cursor each time you quit a file: the mark &lt;code&gt;0&lt;/code&gt; has the last position, the mark &lt;code&gt;1&lt;/code&gt; has the position before the last one, and so on.&lt;/p&gt;

&lt;p&gt;To move to a mark, you can use these keystrokes in NORMAL mode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;'&amp;lt;mark&amp;gt;&lt;/code&gt; - Move to the &lt;em&gt;first non-blank character&lt;/em&gt; of the line where the mark &lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt; was set.&lt;/li&gt;
&lt;li&gt;`&lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt; - Move to the &lt;em&gt;exact position&lt;/em&gt; where the mark &lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt; was set.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;g' &amp;lt;mark&amp;gt;&lt;/code&gt; - Move to the mark &lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt; without changing the jump list (I've written about the jump list &lt;a href="https://thevaluable.dev/vim-intermediate/" rel="noopener noreferrer"&gt;in the previous article of this series&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Useful Commands
&lt;/h3&gt;

&lt;p&gt;As you might imagine, there are also some useful commands for displaying or manipulating marks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:marks&lt;/code&gt; - Display the marks set.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:marks &amp;lt;marks&amp;gt;&lt;/code&gt; - Display some specific marks &lt;code&gt;&amp;lt;marks&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:delmarks &amp;lt;mark&amp;gt;&lt;/code&gt; or &lt;code&gt;:delm &amp;lt;mark&amp;gt;&lt;/code&gt; - Delete the mark &lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:delmarks!&lt;/code&gt; or &lt;code&gt;delm!&lt;/code&gt; - Delete all the marks in the range &lt;code&gt;a-z&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, &lt;code&gt;:marks &amp;lt;&amp;gt;&lt;/code&gt; will display the two marks &lt;code&gt;&amp;lt;&lt;/code&gt; and &lt;code&gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also use marks as ranges. For example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;`&lt;br&gt;
:`a,`bs/pattern/replacement/&lt;br&gt;
`&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will substitute the first match of &lt;code&gt;pattern&lt;/code&gt; with &lt;code&gt;replacement&lt;/code&gt; from the exact position of the mark &lt;code&gt;a&lt;/code&gt; to the exact position of the mark &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Special Marks
&lt;/h3&gt;

&lt;p&gt;Let's now introduce special marks with these keystrokes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;m&amp;lt;&lt;/code&gt; or &lt;code&gt;m&amp;gt;&lt;/code&gt; - Set the marks &lt;code&gt;'&amp;lt;&lt;/code&gt; and &lt;code&gt;'&amp;gt;&lt;/code&gt; we saw above. It can be handy for the keystroke &lt;code&gt;gv&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;`&lt;code&gt;[&lt;/code&gt; - Move to the first character of the previously changed, deleted, or yanked content.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&lt;/code&gt;]` - Move to the last character of the previously changed, deleted, or yanked content.&lt;/li&gt;
&lt;li&gt;`&lt;code&gt;"&lt;/code&gt; - Move to the position were you've closed the current file for the last time.&lt;/li&gt;
&lt;li&gt;`&lt;code&gt;^&lt;/code&gt; - Move to the position where you've used INSERT mode for the last time (this mark is used by the keystroke &lt;code&gt;gi&lt;/code&gt; under the hood).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For every keystroke described above using a backtick, you can use a single quote &lt;code&gt;'&lt;/code&gt; instead with the differences we saw above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:help mark-motions&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Manipulating Numbers
&lt;/h2&gt;

&lt;p&gt;After these register, substitution, and mark shenanigans, here's a lighter subject: adding (or subtracting) numbers.&lt;/p&gt;

&lt;p&gt;Here's a bunch of NORMAL mode keystrokes to do exactly that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CTRL+a&lt;/code&gt; - Increase &lt;em&gt;the first digit or number&lt;/em&gt; on the line.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CTRL+x&lt;/code&gt; - Decrease &lt;em&gt;the first digit or number&lt;/em&gt; on the line.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also use these keystrokes in VISUAL mode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;g CTRL+a&lt;/code&gt; - Same as &lt;code&gt;CTRL+a&lt;/code&gt; unless you have several lines selected. In that case, the first number of each line will be &lt;em&gt;incremented sequentially&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;g CTRL+x&lt;/code&gt; - Same as &lt;code&gt;CTRL+x&lt;/code&gt; unless you have several lines selected. In that case, the first number of each line will be &lt;em&gt;decremented sequentially&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To illustrate a bit better the last two keystrokes, let's say that you have this amazing content in your beloved Vim:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Take some red flowers.&lt;/li&gt;
&lt;li&gt;Add some eggs.&lt;/li&gt;
&lt;li&gt;Forget about it and go back to your computer.
`&lt;code&gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you select in VISUAL mode the last two lines and hit &lt;code&gt;g CTRL+a&lt;/code&gt;, you'll get:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Take some red flowers.&lt;/li&gt;
&lt;li&gt;Add some eggs.&lt;/li&gt;
&lt;li&gt;Forget about it and go back to your computer.
`&lt;code&gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also prefix a count to the command to add a precise amount. For example, &lt;code&gt;12 CTRL+a&lt;/code&gt; will add 12 to the first number of the current line.&lt;/p&gt;

&lt;p&gt;An important note: these keystrokes can also work on unsigned binary, octal, and hexadecimal numbers, as well as &lt;em&gt;alphabetical characters&lt;/em&gt;. Their behaviors depend on the value of the option &lt;code&gt;nrformats&lt;/code&gt;. For these keystrokes to behave as described in this article, you shouldn't have &lt;code&gt;alpha&lt;/code&gt; as part of the value of &lt;code&gt;nrformats&lt;/code&gt;, or you'll increment (or decrement) the first &lt;em&gt;alphabetical character&lt;/em&gt; of the line.&lt;/p&gt;

&lt;p&gt;Personally, I think it's better to exclude alphabetical characters, but in any case, I would recommend you to read Vim's help to learn more about that. As always.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help CTRL-A&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help CTRL-X&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help nrformats&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sorting Text
&lt;/h2&gt;

&lt;p&gt;What about a little dessert? A nice command to sort text directly in Vim, perhaps? Here are the commands:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;:sort&lt;/code&gt; or &lt;code&gt;:sor&lt;/code&gt; - Sort lines depending on a range. If no range is given, all lines are sorted.&lt;br&gt;
&lt;code&gt;:sort!&lt;/code&gt; or &lt;code&gt;:sor!&lt;/code&gt; - Reverse the order.&lt;/p&gt;

&lt;p&gt;You can add some options to this command. Here are the most useful ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;i&lt;/code&gt; - Ignore Case.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;n&lt;/code&gt; - Sort depending on the first decimal on the line.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;f&lt;/code&gt; - Sort depending on the first float on the line.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/pattern/&lt;/code&gt; - Sort depending on what comes after the match.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;r&lt;/code&gt; - Combined with &lt;code&gt;/pattern/&lt;/code&gt;, the sort depending on the matching pattern.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if you have a CSV (with comma &lt;code&gt;,&lt;/code&gt; as separator) and you want to sort every line depending on the second column, you can run something like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
:sort /[^,]*,/&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;How about sorting the following list depending on the numbers of each line?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
Take some red flowers (1).&lt;br&gt;
Forget about it and go back to your computer (3).&lt;br&gt;
Add some eggs (2).&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;:sort n&lt;/code&gt; will have the following result:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
Take some red flowers (1).&lt;br&gt;
Add some eggs (2).&lt;br&gt;
Forget about it and go back to your computer (3).&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As always, there are many subtleties involved here. If you want to dig deeper, you know what you should do: fire up this Vim's help and enjoy the depth of its infinity!&lt;/p&gt;

&lt;h3&gt;
  
  
  Vim Help
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:help sort&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Are You a Vim Master Now?
&lt;/h2&gt;

&lt;p&gt;We can now make two assumptions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Compared to your old self, you might be more of a master than before.&lt;/li&gt;
&lt;li&gt;Compared to many, you still have a long road ahead of practice and learning. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But here's the most important: you shouldn't care about the second point. Always compare yourself to your past self, not to the others. Continue to walk on your own road, and you'll get your enlightenment. You'll then build your own Mouseless Development environment, you'll move to a comfy cave in the Himalaya, alone, living a life of vow, giving your whole soul to the study of the Almighty Vim.&lt;/p&gt;

&lt;p&gt;What did we learn in this article?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The letter "g" in Vim is a bit like a magic wand: 

&lt;ul&gt;
&lt;li&gt;There are many useful keystrokes which begin with "g".&lt;/li&gt;
&lt;li&gt;The flag &lt;code&gt;g&lt;/code&gt; is often used with the substitute command.&lt;/li&gt;
&lt;li&gt;The global command &lt;code&gt;:g&lt;/code&gt; is really powerful to apply a command to some precise content.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Ranges allow you to execute many commands on a bunch of contiguous lines.&lt;/li&gt;

&lt;li&gt;The quickfix list is a global list of positions in different files. You can apply any command to them with &lt;code&gt;:cdo&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;You can see the entries of a quickfix list using the quickfix window.&lt;/li&gt;

&lt;li&gt;Location lists are similar to quickfix lists, except that you can have one location list (and one location window) per window open.&lt;/li&gt;

&lt;li&gt;You can use the substitute command &lt;code&gt;:s&lt;/code&gt; to replace a pattern (regex) with a replacement. Prefer &lt;code&gt;:sm&lt;/code&gt; if you want to use a regex or &lt;code&gt;:sno&lt;/code&gt; if you don't.&lt;/li&gt;

&lt;li&gt;You can use marks to add some surgical precision in what you want to do.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;To reward your tenacity and resilience for reading the whole article, I've a last tip for you: &lt;code&gt;:help ex-cmd-index&lt;/code&gt; will list all the commands available in Vim.&lt;/p&gt;

&lt;p&gt;Vim is easy to learn but hard to master: that's great, because we never stop improving!&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.hillelwayne.com/post/intermediate-vim/" rel="noopener noreferrer"&gt;At least one Vim trick you might not know&lt;/a&gt; - Hillel Wayne&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.hillelwayne.com/vim-macro-trickz/" rel="noopener noreferrer"&gt;Vim Macro Trickz&lt;/a&gt; - Hillel Wayne&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/vim-search-find-replace/"&gt;Vim Search, Find and Replace: a Detailed Guide&lt;/a&gt; - Your obedient servant&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Becoming Mouseless
&lt;/h2&gt;

&lt;p&gt;Do you want to build a &lt;a href="https://themouseless.dev" rel="noopener noreferrer"&gt;Mouseless Development Environment&lt;/a&gt; where the Linux shell and Vim have a central role?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://themouseless.dev" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthemouseless.dev%2Fimages%2Fsmall_cover.webp" alt="building your mouseless development environment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Switching between the keyboard and the mouse costs cognitive energy. This book will guide you step by step to set up a Linux-based development environment that keeps your hands on your keyboard.&lt;/p&gt;

&lt;p&gt;Take the brain power you've been using to juggle input devices and focus it where it belongs: on what you create.&lt;/p&gt;




</description>
      <category>vim</category>
      <category>terminal</category>
      <category>productivity</category>
    </item>
    <item>
      <title>The Basics of grep - Filtering All The Content You Want</title>
      <dc:creator>Matthieu Cneude</dc:creator>
      <pubDate>Sun, 11 Apr 2021 12:10:09 +0000</pubDate>
      <link>https://forem.com/phantas0s/the-basics-of-grep-filtering-all-the-content-you-want-429m</link>
      <guid>https://forem.com/phantas0s/the-basics-of-grep-filtering-all-the-content-you-want-429m</guid>
      <description>&lt;p&gt;The tool grep is a fantastic CLI (Command-Line Interface) allowing you to filter any &lt;em&gt;pattern&lt;/em&gt; for a given &lt;em&gt;input&lt;/em&gt;, including a file.&lt;/p&gt;

&lt;p&gt;To know if you have GNU grep, you can run in your terminal &lt;code&gt;grep --version&lt;/code&gt;. If you don't have GNU grep, I would recommend installing it.&lt;/p&gt;

&lt;p&gt;This article is a summary of the following video I made. I would recommend you to watch it first, it's more complete with many examples and exercises:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/SEkdPKcws3s"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you find the videos I have on this channel helpful, don't hesitate to subscribe and to like them. It would then appear to other Youtubers to help even more!&lt;/p&gt;

&lt;p&gt;I also recommend you to: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download &lt;a href="https://github.com/Phantas0s/mouseless-dev-youtube/tree/master/01_grep" rel="noopener noreferrer"&gt;these files&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fire up your beautiful shell&lt;/li&gt;
&lt;li&gt;Try each command you'll see in this article&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You won't learn much if you only read (or watch a video) passively.&lt;/p&gt;

&lt;p&gt;In this article we'll see together how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Colorize grep output&lt;/li&gt;
&lt;li&gt;Case insensitive patters&lt;/li&gt;
&lt;li&gt;Output lines with pattern matched&lt;/li&gt;
&lt;li&gt;Output lines with pattern not matched&lt;/li&gt;
&lt;li&gt;Output only the pattern matched&lt;/li&gt;
&lt;li&gt;Output lines numbers&lt;/li&gt;
&lt;li&gt;Output the match count&lt;/li&gt;
&lt;li&gt;Hiding filenames&lt;/li&gt;
&lt;li&gt;Always output filenames&lt;/li&gt;
&lt;li&gt;Only output filenames&lt;/li&gt;
&lt;li&gt;Only output filenames without matches&lt;/li&gt;
&lt;li&gt;Output lines after the match&lt;/li&gt;
&lt;li&gt;Output lines before the match&lt;/li&gt;
&lt;li&gt;Output lines before and after the match&lt;/li&gt;
&lt;li&gt;Excluding files&lt;/li&gt;
&lt;li&gt;Piping grep&lt;/li&gt;
&lt;li&gt;Summary: a mindmap of grep&lt;/li&gt;
&lt;li&gt;Using grep in practice&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Colors!
&lt;/h2&gt;

&lt;p&gt;I would advise you to colorize the output of grep using the option &lt;code&gt;--color&lt;/code&gt; as following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;--color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;auto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it's a pain to use this option each time you use grep. You can define an alias to make grep always colorful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias grep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"grep --color=auto"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's now a firework machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Output Lines With Pattern Matched
&lt;/h2&gt;

&lt;p&gt;Here's the general way to use grep:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;pattern&amp;gt;"&lt;/span&gt; &amp;lt;input&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;&amp;lt;pattern&amp;gt;&lt;/code&gt; is a regular expression and the &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; can be what you enter in your terminal or a file. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"package"&lt;/span&gt; pacman.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see this output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthemouseless.dev%2Fimages%2F2021%2Fgrep%2F01_displaying_lines_pattern_matched.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthemouseless.dev%2Fimages%2F2021%2Fgrep%2F01_displaying_lines_pattern_matched.webp" alt="Displaying lines with pattern matched"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see that the pattern &lt;code&gt;package&lt;/code&gt; is part of these two lines; that's why they are output. Incredible! It would be nice if we could do that in our daily life. I already know what words I would filter.&lt;/p&gt;

&lt;p&gt;Note that the pattern wouldn't be colorized without the option &lt;code&gt;--color&lt;/code&gt; set to &lt;code&gt;auto&lt;/code&gt; as we saw above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Output Lines With Pattern Not Matched
&lt;/h2&gt;

&lt;p&gt;If you want to in&lt;code&gt;v&lt;/code&gt;ert the match, that is, only output the lines which &lt;em&gt;don't match&lt;/em&gt; the pattern, you can use the option &lt;code&gt;-v&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"package"&lt;/span&gt; pacman.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time, you'll output all the file except the two lines containing the pattern &lt;code&gt;package&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Output Only The Pattern Matched
&lt;/h2&gt;

&lt;p&gt;It can be useful to &lt;code&gt;o&lt;/code&gt;nly output the match and not the whole line. You can do that with the option &lt;code&gt;-o&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"package"&lt;/span&gt; pacman.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Output Line Numbers
&lt;/h2&gt;

&lt;p&gt;If you to output the lines and the line &lt;code&gt;n&lt;/code&gt;umbers, you need to use the option &lt;code&gt;-n&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"package"&lt;/span&gt; pacman.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The line numbers will be prefixed to each line of the output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Only Output Match Count
&lt;/h2&gt;

&lt;p&gt;You can also &lt;em&gt;only&lt;/em&gt; output the match &lt;code&gt;c&lt;/code&gt;ount with the option &lt;code&gt;-c&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"package"&lt;/span&gt; pacman.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Case Insensitive Patterns
&lt;/h2&gt;

&lt;p&gt;By default, to match a pattern, you'll need to know what letters of the pattern are uppercase or lowercase. You can match your pattern without worrying about the case if you use the option &lt;code&gt;-i&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"pacman"&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that grep can filter more than one file. The glob &lt;code&gt;*&lt;/code&gt; has a special meaning: it represents 0 or more character. Said differently, we want every file in our working directory ending up with &lt;code&gt;.log&lt;/code&gt;. The following is equivalent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"pacman"&lt;/span&gt; haskell.log pacman.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Filenames
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Hiding Filenames
&lt;/h3&gt;

&lt;p&gt;As you saw, grep will output the filenames of the occurrence matches if you use more than one file as input. To &lt;code&gt;h&lt;/code&gt;ide them, you can use the option &lt;code&gt;-h&lt;/code&gt;. An example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="s2"&gt;"package"&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Always Output Filenames
&lt;/h3&gt;

&lt;p&gt;If you want to output the filename where there's a match, even if you gave only one file as input, you can use the option &lt;code&gt;-H&lt;/code&gt;. As usual, here's an example you can run in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"package"&lt;/span&gt; pacman.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For some option, the uppercase variant will do the inverse of the lowercase one, like &lt;code&gt;-h&lt;/code&gt; and &lt;code&gt;-H&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Only Output Filenames
&lt;/h3&gt;

&lt;p&gt;To only output the filenames where the patterns match, you can use the option &lt;code&gt;-l&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s2"&gt;"package"&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Only Output Filenames Without Matches
&lt;/h3&gt;

&lt;p&gt;You might have guessed it: the option &lt;code&gt;-L&lt;/code&gt; only output the filename where the pattern &lt;em&gt;doesn't&lt;/em&gt; match:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="s2"&gt;"package"&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Output Lines Around The Match
&lt;/h2&gt;

&lt;p&gt;Outputing the lines before or after your match can be useful to get a bit of &lt;em&gt;context&lt;/em&gt; and understand the result of your filtering.&lt;/p&gt;

&lt;h3&gt;
  
  
  Output Lines After The Match
&lt;/h3&gt;

&lt;p&gt;To output a variable number of lines &lt;code&gt;A&lt;/code&gt;fter the line with a match, you can use the option &lt;code&gt;-A&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; 3 &lt;span class="s2"&gt;"package"&lt;/span&gt; pacman.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Output Lines Before The Match
&lt;/h3&gt;

&lt;p&gt;Similarly, if you want to output the lines &lt;code&gt;B&lt;/code&gt;efore the match, you can use the option &lt;code&gt;-B&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-B&lt;/span&gt; 3 &lt;span class="s2"&gt;"package"&lt;/span&gt; pacman.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Output Lines Before And After the Match
&lt;/h3&gt;

&lt;p&gt;You can even output some lines before &lt;em&gt;and&lt;/em&gt; after the match with the option &lt;code&gt;-C&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; 3 &lt;span class="s2"&gt;"package"&lt;/span&gt; pacman.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the second match of &lt;code&gt;package&lt;/code&gt; won't output the 3 lines after because it's the end of the file after the line containing the match.&lt;/p&gt;

&lt;p&gt;Did you see the pattern? &lt;code&gt;A&lt;/code&gt;fter, &lt;code&gt;B&lt;/code&gt;efore, &lt;code&gt;C&lt;/code&gt;ontext: it's &lt;code&gt;ABC&lt;/code&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Excluding Files
&lt;/h2&gt;

&lt;p&gt;We always gave the files we wanted to filter to grep's input, but what if we want everything &lt;em&gt;except&lt;/em&gt; a couple of files? For that, we can use the option &lt;code&gt;--exclude&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"package"&lt;/span&gt; &lt;span class="nt"&gt;--exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"pacman.log"&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Piping grep
&lt;/h2&gt;

&lt;p&gt;You can directly give the output of a command to the input of grep if you want to filter it. Actually, you can do that with every CLI accepting an input using pipes. &lt;/p&gt;

&lt;p&gt;For example, if I run &lt;code&gt;ps&lt;/code&gt; (a CLI to output the processes running on my machine), I get this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    PID TTY          TIME CMD
   2026 pts/9    00:11:36 nvim
   2431 pts/11   00:01:11 hugo
   2584 pts/10   00:00:01 tmuxp
   3009 pts/18   00:00:01 nvim
   3241 pts/20   00:00:17 taskell
   3484 pts/22   00:00:11 taskell
   3663 pts/21   00:00:00 nvim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What if I want only the lines containing the pattern &lt;code&gt;nvim&lt;/code&gt;? I can do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ps &lt;span class="nt"&gt;-a&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"nvim"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It means that I give to the input of grep the output of the command &lt;code&gt;ps -a&lt;/code&gt;. Here's the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   2026 pts/9    00:11:36 nvim
   3009 pts/18   00:00:01 nvim
   3663 pts/21   00:00:00 nvim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pipes are one of the reason why the command line is so powerful: you can pipe small CLIs doing one thing and you'll have crazy results!&lt;/p&gt;

&lt;h2&gt;
  
  
  In a Nutshell: a Mindmap of grep
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://themouseless.dev/images/2021/grep/grep.jpg" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthemouseless.dev%2Fimages%2F2021%2Fgrep%2Fgrep.jpg" alt="summary how to use grep in mind map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's nice to learn all of that, but how can you use grep in real life? Here's a video showing you a problem I had and I solved nicely using grep and other CLIs:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/N2YsWcyEpr8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Becoming Mouseless
&lt;/h2&gt;

&lt;p&gt;Do you want to build a &lt;a href="https://themouseless.dev" rel="noopener noreferrer"&gt;Mouseless Development Environment&lt;/a&gt; where the Linux shell has a central role?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://themouseless.dev" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthemouseless.dev%2Fimages%2Fsmall_cover.webp" alt="building your mouseless development environment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Switching between the keyboard and the mouse costs cognitive energy. This book will guide you step by step to set up a Linux-based development environment that keeps your hands on your keyboard.&lt;/p&gt;

&lt;p&gt;Take the brain power you've been using to juggle input devices and focus it where it belongs: on what you create.&lt;/p&gt;




</description>
      <category>mouseless</category>
      <category>commandline</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
