Chapter 03 changes

- Modified ch03, fixed typos and a few grammar issues. Fixed root directory mistakenly taken for the home directory. A few parts rewritten for clarity. The plugin part of this chapter is less thoroughly reviewed since I use Vim without plugins and intend to keep it this way.
This commit is contained in:
HattDroid 2021-10-18 23:12:22 +01:00
parent a6233663cf
commit f0db3a2446

View file

@ -1,6 +1,6 @@
# Ch03. Searching Files
The goal of this chapter is to introduce you to how to search quickly in Vim. Being able to search quickly is a great way to jump-start your Vim productivity. When I figured out how to search files quickly, I made the switch to use Vim full-time.
The goal of this chapter is to give you an introduction on how to search quickly in Vim. Being able to search quickly is a great way to jump-start your Vim productivity. When I figured out how to search files quickly, I made the switch to use Vim full-time.
This chapter is divided into two parts: how to search without plugins and how to search with [fzf.vim](https://github.com/junegunn/fzf.vim) plugin. Let's get started!
@ -61,7 +61,7 @@ You may notice that `:find` looks like `:edit`. What's the difference?
## Find and Path
The difference is that `:find` finds file in `path`, `:edit` doesn't. Let's learn a little bit about this `path`. Once you learn how to modify your paths, `:find` can become a powerful searching tool. To check what your paths are, do:
The difference is that `:find` finds file in `path`, `:edit` doesn't. Let's learn a little bit about `path`. Once you learn how to modify your paths, `:find` can become a powerful searching tool. To check what your paths are, do:
```
:set path?
@ -73,11 +73,11 @@ By default, yours probably look like this:
path=.,/usr/include,,
```
- `.` means to search relative to the directory of the current file.
- `.` means to search in the directory of the currently opened file.
- `,` means to search in the current directory.
- `/usr/include` is the directory for C compilers header files.
- `/usr/include` is the typical directory for C libraries header files.
The first two are important and the third one can be ignored for now. The takeaway here is that you can modify your own paths. Let's assume this is your project structure:
The first two are important in our context and the third one can be ignored for now. The takeaway here is that you can modify your own paths, where Vim will look for files. Let's assume this is your project structure:
```
app/
@ -99,7 +99,7 @@ You need to add the `app/controllers/` to the current `path`. Here is how you ca
Now that your path is updated, when you type `:find u<Tab>`, Vim will now search inside `app/controllers/` directory for files starting with "u".
If you have a nested `controllers/` directory, like `app/controllers/account/users_controller.rb`, Vim won't find `users_controllers`. You need to instead add `:set path+=app/controllers/**` so autocomplete will find `users_controller.rb`. This is great! Now you can find the users controller with 1 press of tab instead of 3.
If you have a nested `controllers/` directory, like `app/controllers/account/users_controller.rb`, Vim won't find `users_controllers`. Instead, you need to add `:set path+=app/controllers/**` in order for autocompletion will find `users_controller.rb`. This is great! Now you can find the users controller with 1 press of tab instead of 3.
You might be thinking to add the entire project directories so when you press `tab`, Vim will search everywhere for that file, like this:
@ -109,7 +109,7 @@ You might be thinking to add the entire project directories so when you press `t
`$PWD` is the current working directory. If you try to add your entire project to `path` hoping to make all files reachable upon a `tab` press, although this may work for a small project, doing this will slow down your search significantly if you have a large number of files in your project. I recommend adding only the `path` of your most visited files / directories.
You can add the `set path+={your-path-here}` in your vimrc. Updating `path` takes only a few seconds and doing this will save you a lot of time.
You can add the `set path+={your-path-here}` in your vimrc. Updating `path` takes only a few seconds and doing so can save you a lot of time.
## Searching in Files With Grep
@ -125,7 +125,7 @@ Let's go through internal grep first. `:vim` has the following syntax:
```
- `/pattern/` is a regex pattern of your search term.
- `file` is the file arguments. You can pass multiple arguments. Vim will search for the pattern inside the file arguments. Similar to `:find`, you can pass it `*` and `**` wildcards.
- `file` is the file argument. You can pass multiple arguments. Vim will search for the pattern inside the file argument. Similar to `:find`, you can pass it `*` and `**` wildcards.
For example, to look for all occurrences of "breakfast" string inside all ruby files (`.rb`) inside `app/controllers/` directory:
@ -146,7 +146,7 @@ After running that, you will be redirected to the first result. Vim's `vim` sear
To learn more about quickfix, check out `:h quickfix`.
You may notice that running internal grep (`:vim`) can get slow if you have a large number of matches. This is because Vim reads the searches into memory. Vim loads each matching file as if it is being edited. If Vim checks a large number of files, it will consume a large amount of memory.
You may notice that running internal grep (`:vim`) can get slow if you have a large number of matches. This is because Vim loads each matching file into memory, as if it were being edited. If Vim finds a large number of files matching your search, it will load them all and therefore consume a large amount of memory.
Let's talk about external grep. By default, it uses `grep` terminal command. To search for "lunch" inside a ruby file inside `app/controllers/` directory, you can do this:
@ -156,18 +156,18 @@ Let's talk about external grep. By default, it uses `grep` terminal command. To
Note that instead of using `/pattern/`, it follows the terminal grep syntax `"pattern"`. It also displays all matches using `quickfix`.
Vim uses `grepprg` variable to determine which external program to run when running `:grep` so you don't have to always use the terminal `grep` command. Later I will show you how to change default the grep external program.
Vim defines the `grepprg` variable to determine which external program to run when running the `:grep` Vim command so that you don't have to close Vim and invoke the terminal `grep` command. Later, I will show you how to change the default program invoked when using the `:grep` Vim command.
## Browsing Files With Netrw
`netrw` is Vim's built-in file explorer. It is useful to see a project's structural hierarchy. To run `netrw`, you need these two settings in your `.vimrc`:
`netrw` is Vim's built-in file explorer. It is useful to see a project's hierarchy. To run `netrw`, you need these two settings in your `.vimrc`:
```
set nocp
filetype plugin on
```
Since `netrw` is a vast topic, I will only cover the basic usage, but it should be enough to get you started. You can start `netrw` when you launch Vim and passing it a directory instead of a file. For example:
Since `netrw` is a vast topic, I will only cover the basic usage, but it should be enough to get you started. You can start `netrw` when you launch Vim by passing it a directory as a parameter instead of a file. For example:
```
vim .
@ -175,7 +175,7 @@ vim src/client/
vim app/controllers/
```
To launch `netrw` from inside Vim, you can use the `:edit` command and pass it a directory instead of a filename:
To launch `netrw` from inside Vim, you can use the `:edit` command and pass it a directory parameter instead of a filename:
```
:edit .
@ -191,7 +191,7 @@ There are other ways to launch `netrw` window without passing a directory:
:Vexplore Starts netrw on split left half of the screen
```
You can navigate `netrw` with Vim motions (motions will be covered in depth in a later chapter). If you need to create, delete, and rename file/directory, here is a list of useful `netrw` commands:
You can navigate `netrw` with Vim motions (motions will be covered in depth in a later chapter). If you need to create, delete, or rename a file or directory, here is a list of useful `netrw` commands:
```
% Create a new file
@ -208,7 +208,7 @@ If you find `netrw` too bland and need more flavor, [vim-vinegar](https://github
Now that you've learned how to search files in Vim with built-in tools, let's learn how to do it with plugins.
One thing that modern text editors get right that Vim didn't is how easy it is to find files and to find in files using fuzzy search. In this second half of the chapter, I will show you how to use [fzf.vim](https://github.com/junegunn/fzf.vim) to make searching in Vim easy and powerful.
One thing that modern text editors get right and that Vim didn't is how easy it is to find files, especially via fuzzy search. In this second half of the chapter, I will show you how to use [fzf.vim](https://github.com/junegunn/fzf.vim) to make searching in Vim easy and powerful.
## Setup
@ -216,7 +216,7 @@ First, make sure you have [fzf](https://github.com/junegunn/fzf) and [ripgrep](h
Ripgrep is a search tool much like grep (hence the name). It is generally faster than grep and has many useful features. Fzf is a general-purpose command-line fuzzy finder. You can use it with any commands, including ripgrep. Together, they make a powerful search tool combination.
Fzf does not use ripgrep by default, so we need to tell fzf to use ripgrep with `FZF_DEFAULT_COMMAND` variable. In my `.zshrc` (`.bashrc` if you use bash), I have these:
Fzf does not use ripgrep by default, so we need to tell fzf to use ripgrep by defining a `FZF_DEFAULT_COMMAND` variable. In my `.zshrc` (`.bashrc` if you use bash), I have these:
```
if type rg &> /dev/null; then
@ -225,7 +225,7 @@ if type rg &> /dev/null; then
fi
```
Pay attention to `-m` in `FZF_DEFAULT_OPTS`. This option allows us to make multiple selections with `<Tab>` or `<Shift-Tab>`. You don't have to have this line to make fzf to work with Vim, but I think it is a useful option to have. It will come in handy when you want to perform search and replace in multiple files which I'll cover in just a little bit. The fzf command accepts many more flags, but I won't cover them here. To learn more, check out [fzf's repo](https://github.com/junegunn/fzf#usage) or `man fzf`. At minimum you should have `export FZF_DEFAULT_COMMAND='rg'`.
Pay attention to `-m` in `FZF_DEFAULT_OPTS`. This option allows us to make multiple selections with `<Tab>` or `<Shift-Tab>`. You don't need this line to make fzf work with Vim, but I think it is a useful option to have. It will come in handy when you want to perform search and replace in multiple files which I'll cover in just a little. The fzf command accepts many more options, but I won't cover them here. To learn more, check out [fzf's repo](https://github.com/junegunn/fzf#usage) or `man fzf`. At minimum you should have `export FZF_DEFAULT_COMMAND='rg'`.
After installing fzf and ripgrep, let's set up the fzf plugin. I am using [vim-plug](https://github.com/junegunn/vim-plug) plugin manager in this example, but you can use any plugin managers.
@ -236,7 +236,7 @@ Plug 'junegunn/fzf.vim'
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
```
After you add them, you will need to open `vim` and run `:PlugInstall`. It will install all plugins that are defined in your `vimrc` file and are not installed. In our case, it will install `fzf.vim` and `fzf`.
After adding these lines, you will need to open `vim` and run `:PlugInstall`. It will install all plugins that are defined in your `vimrc` file and are not installed. In our case, it will install `fzf.vim` and `fzf`.
For more info about this plugin, you can check out [fzf.vim repo](https://github.com/junegunn/fzf/blob/master/README-VIM.md).
@ -256,7 +256,7 @@ You can mix and match these options. For example, `^hello | ^welcome friends$` w
To search for files inside Vim using fzf.vim plugin, you can use the `:Files` method. Run `:Files` from Vim and you will be prompted with fzf search prompt.
Since you will be using this command frequently, it is good to have this mapped. I map mine to `Ctrl-f`. In my vimrc, I have this:
Since you will be using this command frequently, it is good to have this mapped to a keyboard shortcut. I map mine to `Ctrl-f`. In my vimrc, I have this:
```
nnoremap <silent> <C-f> :Files<CR>
@ -266,7 +266,7 @@ nnoremap <silent> <C-f> :Files<CR>
To search inside files, you can use the `:Rg` command.
Again, since you will probably use this frequently, let's map it. I map mine to `<Leader>f`.
Again, since you will probably use this frequently, let's map it to a keyboard shortcut. I map mine to `<Leader>f`.
```
nnoremap <silent> <Leader>f :Rg<CR>
@ -295,13 +295,13 @@ nnoremap <silent> <Leader>h/ :History/<CR>
As mentioned earlier, Vim has two ways to search in files: `:vim` and `:grep`. `:grep` uses external search tool that you can reassign using the `grepprg` keyword. I will show you how to configure Vim to use ripgrep instead of terminal grep when running the `:grep` command.
Now let's setup `grepprg` so `:grep` uses ripgrep. Add this in your vimrc:
Now let's setup `grepprg` so that the `:grep` Vim command uses ripgrep. Add this in your vimrc:
```
set grepprg=rg\ --vimgrep\ --smart-case\ --follow
```
Feel free to modify some of the options above! For more information what the options above mean, check out `man rg`.
Feel free to modify some of the options above! For more information on what the options above mean, check out `man rg`.
After you updated `grepprg`, now when you run `:grep`, it runs `rg --vimgrep --smart-case --follow` instead of `grep`. If you want to search for "donut" using ripgrep, you can now run a more succinct command `:grep "donut"` instead of `:grep "donut" . -R`
@ -325,11 +325,11 @@ The first method is to replace *all* matching phrases in your project. You will
Let's break down the commands:
1. `:grep pizza` uses ripgrep to search for all instances of "pizza" (by the way, this would still work even if you didn't reassign `grepprg` to use ripgrep. You would have to do `:grep "pizza" . -R` instead of `:grep "pizza"`).
2. `:cfdo` executes any command you pass to all files in your quickfix list. In this case, your command is the substitution command `%s/pizza/donut/g`. The pipe (`|`) is a chain operator. The `update` command saves each file after substitution. I will cover substitute command in more depth in a later chapter.
2. `:cfdo` executes any command you pass to all files in your quickfix list. In this case, your command is the substitution command `%s/pizza/donut/g`. The pipe (`|`) is a chain operator. The `update` command saves each file after substitution. I will cover the substitute command in more depth in a later chapter.
The second method is to search and replace in select files. With this method, you can manually choose which files you want to perform select and replace on. Here is what you do:
The second method is to search and replace in selected files. With this method, you can manually choose which files you want to perform select-and-replace on. Here is what you do:
1. Clear your buffers first. It is imperative that your buffer list contains only the files you need. You can either restart Vim or run `:%bd | e#` command (`%bd` deletes all the buffers and `e#` opens the file you were just on).
1. Clear your buffers first. It is imperative that your buffer list contains only the files you want to apply the replace on. You can either restart Vim or run `:%bd | e#` command (`%bd` deletes all the buffers and `e#` opens the file you were just on).
2. Run `:Files`.
3. Select all files you want to perform search-and-replace on. To select multiple files, use `<Tab>` / `<Shift-Tab>`. This is only possible if you have the multiple flag (`-m`) in `FZF_DEFAULT_OPTS`.
4. Run `:bufdo %s/pizza/donut/g | update`. The command `:bufdo %s/pizza/donut/g | update` looks similar to the earlier `:cfdo %s/pizza/donut/g | update` command. The difference is instead of substituting all quickfix entries (`:cfdo`), you are substituting all buffer entries (`:bufdo`).
@ -338,6 +338,6 @@ The second method is to search and replace in select files. With this method, yo
Searching is the bread-and-butter of text editing. Learning how to search well in Vim will improve your text editing workflow significantly.
Fzf.vim is a game-changer. I can't imagine using Vim without it. I think it is very important to have a good search tool when starting Vim. I've seen people struggling to transition to Vim because it is missing critical features modern text editors have, like an easy and powerful search feature. I hope this chapter will help you to make the transition to Vim easier.
Fzf.vim is a game-changer. I can't imagine using Vim without it. I think it is very important to have a good search tool when starting Vim. I've seen people struggling to transition to Vim because it seems to be missing critical features modern text editors have, like an easy and powerful search feature. I hope this chapter will help you to make the transition to Vim easier.
You also just saw Vim's extensibility in action - the ability to extend search functionality with a plugin and an external program. In the future, keep in mind of what other features you wish to extend in Vim. Chances are, someone has created a plugin or there is a program for it already. Next, you'll learn about a very important topic in Vim: Vim grammar.
You also just saw Vim's extensibility in action - the ability to extend search functionality with a plugin and an external program. In the future, keep in mind of what other features you wish to extend Vim with. Chances are, it's already in Vim, someone has created a plugin or there is a program for it already. Next, you'll learn about a very important topic in Vim: Vim grammar.