Today I Learned

A Hashrocket project

236 posts about #vim

Check that an executable exists on the $PATH

When writing a vim plugin interacting with different programs on the server might be necessary. For instance you might want to use ruby to make a network request or perform some file management. But first, the vim plugin should check to see if the program ruby exists which can be accomplished with the executable() vimscript function.

:echo executable('ruby')
1
:echo executable('doesnotexist')
0

This can be used in a condition before running the ruby command.

if executable('ruby')
  system('ruby -e "puts YAML"')
endif

Elixir Static Code Analysis in Vim

Today I learned how to set up Credo, a static analysis tool for Elixir, to run on every Vim buffer write, using Neomake.

To start, I added Credo to my project:

# mix.exs
defp deps do
  {:credo, "~> 0.8", only: [:dev, :test], runtime: false}
end

Including it with:

$ mix deps.get

Next, I loaded and sourced the Neomake plugin with Pathogen:

" ~/.vimbundle
neomake/neomake

Next, I told Neomake to run on every file, enabling Credo for Elixir files:

" ~/.vimrc
let g:neomake_elixir_enabled_makers = ['credo']
autocmd! BufWritePost * Neomake

Now I have Credo style recommendations right in my text editor.

Resize vim window to the size of its content

If you’re writing a vim plugin and in that plugin you are opening a new window to display some content, you may want to resize that window so that it is only the size of the content within. For instance, if you have 10 lines of content but the window is half the screen, then you want to resize the window to 10 lines.

Resizing a window is accomplished with the resize command like:

:resize 10

Getting the number of content lines is accomplished by getting the line number of the last last:

:echo line('$')

Putting the two together is tricky because the argument to the resize command is interpreted literally. :resize line('$') does not work. You have to combine the two into a string and then pass it to the execute command.

:execute('resize ' . line('$'))

Complete a Whole Line in Vim

This week I picked up an excellent Vim command: CTRL-X CTRL-L. This command searches backwards through your project and inserts a matching line after the cursor.

So, if there’s a line in your project like this:

defimpl Phoenix.Param, for: Tilex.Developer do

And I type defimpl (which is unique enough to match only a few functions), Vim will suggest matching options, letting choose a match and complete it:

defimpl Phoenix.Param, for: Tilex.Developer do
defimpl Phoenix.Param, for: Tilex.Developer do

This is useful when importing items into a framework like React.js, where the head of the file often includes a group of common import statements.

See ‘Insert mode completion’ inside insert.txt in the Vim help for more information.

h/t Dorian Karter

Quickly Switch To A Buffer By Number

There are a number of different commands you can use for switching to a buffer by its number. For example, if you want to switch to the buffer assigned 7, you can do :7b or :e #7. However, there is a quicker way than typing out either of those commands.

You may already be familiar with CTRL-^ for switching to the alternate file which is generally the previous buffer. If you precede that command with a number, you will switch to the buffer with that number instead of the alternate file.

From normal mode

7 Ctrl-^

will switch to buffer 7.

See :h Ctrl-^ for more details.

Detect If You Are On A Mac

There are a couple ways of detecting with vimscript if you are on a mac. This can be useful if you are writing a plugin with OS-specific functionality. Here are two ways to make that check.

if has('macunix') || has('mac') || has('osx')
  ...
endif

Alternatively, you can use Vim’s system() function to execute unix’s uname command. This command will give you the name of the operating system. In the event you are using a Mac, the result of uname should be Darwin. The following regex match is a good way to make this check.

if system('uname') =~ "Darwin"
  ...
endif

See :h has(), :h system(), and man uname for more details.

Suppress errors when substituting in vim

The substitute (or s) command in vim throws an error the search pattern is not found.

:substitute/banana/apple
E486: Pattern not found: banana

This error can be suppressed with the e flag at the end of the statement.

:substitute/banana/apple/e

When operating in just one file or on just one line the error is a minor annoyance but when combining the substitute command with :argdo you receive an error for every file in the args list that does not contain the pattern in question.

A typical argdo command would look like this.

:argdo s/banana/apple/gec

The flags are:

g - global

e - suppress errors

c - confirm

Check For An Executable

Sometimes Vim needs to reach outside of itself to use an existing program. For example, wiring up auto-formatting of JavaScript code requires Vim to call out to the prettier binary.

We want our .vimrc files and plugins to, generally, be as portable as possible. What happens if you haven’t yet installed a particular program? Vim will likely experience a runtime exception. One way to get around this is to check for the presence of that program on the path. If it isn’t there, don’t do the thing. We can use the executable() function for this.

if executable('prettier')
  ...
endif

It will return 1 (true) if prettier is an executable on the path, otherwise it will return 0 (false).

See :help executable() for more details.

Vim move cursor within a visual selection

When expanding a visual selection you might want to increase both sides. For instance, if you have made a selection from line 20 to line 40 you may want to expand the selection to line 18 to line 42. The visual selection can only be expanded with the cursor and the cursor is only on one side, but the cursor can be moved to the other side of the selection with o.

Read more about it with: :help visual-change.

Set filetype/settings for a specific file in Vim

Given a file with a weird extension but an underlying known filetype e.g. yaml file with a .config extension. It is possible to force vim to set the filetype to yaml for that file:

At the top/bottom of the file add a comment (with the filetypes acceptable comment syntax - for yaml it is #):

# vi: ft=yaml
baz:
  foo: 'bar'

Re-open the file and vim will automatically set the filetype to yaml for that file.

This can also be used for setting other setting such as shiftwidth, tabstop etc

I’ve been using this trick for a while but keep forgetting it the exact syntax, usually using # vim: instead of # vi:. Hopefully my wording will make it more easily duckduckgoable.

Typing card suits in vim ♢♡♣♠

Digraphs are two letter combinations that provide a easy way to type and remember non-ascii characters in vim. In insert mode you can type a digraph with Ctrl-k and then two letters that map to the unicode character.

For card suits the pneumonic is lower case c for card and upper case C for clubs, D for diamonds, H for hearts, and S for spades.

cD ♢
cC ♣
cH ♡
cS ♠

You can see all the digraphs with :digraphs.

Now you have all the necessary unicode characters to easily create card games in the terminal!

What file is this?

If you are working in an environment where the status line is not displayed and you don’t know what file you are currently editing, you can use the :file command to give you that information.

:file
"app/models/post.rb" line 43 of 139 --30%-- col 4

:f is the abbreviated version

What Is On The Runtime Path?

All of the plugins, syntax highlighting, language-specific indentation that extend the default behavior of Vim are on the runtime path. If something isn’t on Vim’s runtime path, then Vim won’t know about and as a result will not load it at runtime.

How do we see what is on the runtime path?

The rtp option is the shorthand for runtimepath. Calling set on either of these will show us the list of runtime paths, or at least some of them.

:set rtp

This will generally be a truncated list if you have a lot of plugins. To be sure you are seeing all of them, use echo instead.

:echo &rtp

See :h rtp for more details.

h/t Chris Erin

Add files with matches to the args list

If I want to change all instances of the word Apple to Orange across my entire project I can use the vim command:

:argdo %s/Apple/Orange/gc

But only if the files that have the word Apple are in the args list. To populate the args list you can use the args command in combination with shelling out to git grep with the -l flag.

:args `git grep -l Apple`

Then, when you see the list of files with :args, you’ll see all the files with the word Apple.

Netrw Special Command

Building off this previous post, today I learned a new command in Netrw: the ‘special command’.

When navigating, enter x over any file, and your operating system will open it with its tool of choice (Preview for images and Finder for directories on a Mac, etc.). This is great for exploring a directory.

From the Netrw help:

Certain files, such as html, gif, jpeg, (word/office) doc, etc, files, are
best seen with a special handler (ie. a tool provided with your computer's
operating system).  Netrw allows one to invoke such special handlers by:

        * when Exploring, hit the "x" key
        * when editing, hit gx with the cursor atop the special filename
          (latter not available if the g:netrw_nogx variable exists)

Send SQL to a Tmux Window

Hashrocket.vim provides a mapping that is awesome:

autocmd FileType sql nmap <buffer> <leader>t :<C-U>w \| call Send_to_Tmux("\\i ".expand("%")."\n")<CR>

With this command, if you’re editing an SQL file in a Tmux session, run <leader>t from normal mode, and your file will be read into the session and window of your choice. If there’s a psql session listening there, you’ve got a fast way to iterate on an SQL statement from Vim.

The command even writes the file for you before sending the SQL.

Related File in Rails.vim

Rails.vim is a staple of our Hashrocket workstations. It continues to surprise me.

Today I discovered the :R (related) command, which is a counterpart to the :A (alternate) command. :R looks for the file related to your current buffer.

This command is sophisticated. Assuming you’re following Rails conventions for file organization, :R over most templates will open the associated controller, with your cursor on the line where the action that corresponds with the view name (show for a template called show.html.erb) is defined. The same thing works in reverse; :R over the show method leads you back to show.html.erb.

Re-mark a Word as Bad

Vim’s spell checking feature is pretty great. I use it as a default for .md and .rdoc files on my machine.

Sometimes it incorrectly marks technical words like ‘ExUnit’ as bad (misspelled). To fix this, I type zg over the word in normal mode, which adds it to a list of white-listed words that are no longer considered bad.

The opposite of that command is zw, which comments out the line in the dictionary file. Run :runtime spell/cleanadd.vim to clean up those comments.

Determine the type of buffer

The :set <option> command will show the value of an option. In the case of :set buftype this is generally set to nothing. It’s empty. This is because we’re usually working with a normal buffer. The exception is the quick window. Generally, the buftype of the quick window is quickwindow. The help window also has its own buftype, help.

These values are used programmatically to help create features with vimscript.

See more with: :help buftype

Making your JS files prettier on Vim

We all use VIM at Hashrocket and we can run prettier everytime we save a JS file:

yarn global add prettier
autocmd FileType javascript set formatprg=prettier\ --single-quote\ --trailing-comma\ es5\ --stdin
autocmd BufWritePre *.js :normal gggqG
autocmd BufWritePre *.js exe "normal! gggqG\<C-o>\<C-o>"

And yes. I like trailing comma,

** Update: There is an open issue on Github when prettier fails to parse the JS file but there is a workaround for it.

yank full line without new line character

I am often in a scenario where I want to take all the contents of the current line and paste them into the middle of another line, perhaps into some parentheses or quotation marks.

If I’m in the middle of a line I can type ^y$ which will goto the first character of the line and then yank to the end without the newline.

This is the rare palindramic vim command. It works the same backwards as it does forwards ($y^).

There is also a plugin that treats the line as a vim object called vim-textobj-line. Check it out!

Matching on directories for vim's autocmd

Generally, vim users use the autocmd command to set specific options for filetypes. Like, if you want all Ruby files to have the shiftwidth option set to 2 then you would include an autocmd line like this in your ~/.vimrc file:

autocmd BufRead *.rb set shiftwidth=2

I wanted to do something a bit different. I wanted to set the color scheme for each file in a directory rather than for a file type, and I tried this:

autocmd BufRead *writing* color shine

Nothing happened.

Via :help autocmd-patterns I was able to learn that if there isn’t a slash char (/) anywhere in the pattern then it just tries to match on the filename. If a slash is included however, the whole path for that file is matched. All I needed was to add a slash:

autocmd BufRead */writing* color shine

Shine On.

Selected Text Character Count

When highlighting a word in vim (Visual Mode), type:

g<CTRL-g>

In the command section of vim you’ll see something like this:

Selected 1 of 90 Lines; 2 of 715 Words; 15 of 4171 Chars; 15 of 4173 Bytes

In this case, 15 of 4171 Chars is the number of total characters and the number of characters selected.

Its not as straight forward or as easy to parse as you might expect, but when you know what to look for it becomes easy to read.

Default netrw To Tree Liststyle

The built-in netrw plugin is a great way to browse files and directories within a Vim session. netrw supports four ways of displaying files and directories. That is, there are four liststyles. You can toggle through these by hitting i.

I prefer the tree liststyle, which is not the default. I can set the tree liststyle as the default by adding the following line to my .vimrc file.

let g:netrw_liststyle = 3

Now, every time I visit or revisit a netrw window, I’ll see everything nicely displayed as a tree.

Use Mkdir! to create dir of present file in vim

In vim its easy to :edit, :write, or :saveas a file to a path that doesn’t yet exist. Such as:

:edit non/existant/path/file.txt

Vim will let you have a buffer with that path, but when you try to write the file vim will throw an error:

E212: Can't open file for writing

Enter the Mkdir! command. The Mkdir command has been added by the eunuch.vim plugin to make creating directories easier from vim. The bang (!) variant takes the path of the current buffer and creates the directory from that path.

When we get the E212 error we can type:

:Mkdir!

And walla! The path will be created. No more errors when writing the file.

Break Up Lines with Splitjoin

One style-guide idea I try to maintain is sticking to a reasonable line length. 72 characters, 80 characters, whatever your preference; long lines are hard to read. They’re a code smell. They need to have a reason for existing.

A task I find myself repeating a lot to achieve this is breaking apart Ruby blocks and hashes into multiple lines, with a combination of jumping forward, entering insert mode, and hitting enter. Turning this:

FactoryGirl.create(:developer, username: 'jake_skid', superpower: 'technical writing and style-guide compliance')

into this:

FactoryGirl.create(:developer, {
  username: 'jake_skid',
  superpower: 'technical writing and style-guide compliance'
})

This task has been automated for me by the Splitjoin plugin for Vim, which is included in the Hashrocket dotfiles. Typing gS in normal mode over the first example turns it into the second example. It’s opinionated, and probably won’t satisfy every tangent of your personal style (I’d leave off the curly braces and add a trailing comma, for instance). But it’s already saved me a lot of time.

h/t Dorian Karter

Open images in vim with iTerm 🖼

iTerm 3 has a built in shell script called imgcat for displaying images in the terminal. With one simple autocmd in my vim configuration I can open images*:

:autocmd BufEnter *.png,*.jpg,*gif exec "! ~/.iterm2/imgcat ".expand("%") | :bw

In my command I wipe the image buffer(:bw) because I don’t want large images sitting around in buffers, but this is easy to change.

imgcat

*imgcat does not work with tmux

Vimscript String Coercion

An unique feature of Vimscript is coercion of strings into integers.

Here’s an example:

:echom "six" + 6
:echom "6six" + 6
:messages
6
12

Our messages show that the first string was coerced to 0 (0 + 6 = 6), and the second string was coerced to 6 (6 + 6 = 12).

Following this logic a little further, because 0 is falsey and 1 (or greater than 1) is truthy, our first string is falsey and our second string is truthy.

Spellcheck Certain Filetypes

I don’t like misspellings in my documentation, yet make a lot of them. Spelling is disabled in all my buffers by default; I turn it on when reading or editing docs. When I forget to do so, it’s easy to miss typos.

While reading Learn VimScript The Hard Way I figured out a better solution to this problem. This now lives in my ~/.vimrc.local:

augroup spellcheck_documentation
  autocmd BufNewFile,BufRead *.md setlocal spell
  autocmd BufNewFile,BufRead *.rdoc setlocal spell
augroup END

Anytime a markdown or RDoc file is created or read, I set a local configuration to turn spelling on. This has already proved invaluable after only a day or two.

Close All Other Splits

If you have a couple other splits open, but you only want the window in focus, you may find yourself doing some finger gymnastics to navigate to those other split windows to close out of them.

There is an easier way.

The Ex command :only will close all other splits, excluding the window that is currently in focus.

See :h :only for more details.

Set persistent font in MacVim

Like many, I have MacVim installed through Homebrew Cask. When I first started using MacVim, I had to change the font to a powerline supported font so that my Airline looks spiffy.

To do that I went to Edit -> Font -> Show Fonts and selected a font.

Unfortunately this setting gets wiped out with each update of MacVim, and since it updates often, which is great, having to set the font over and over is not.

To have your font setting persisted in MacVim add this to your .gvimrc:

set guifont=Source\ Code\ Pro\ for\ Powerline:h24

You can set what ever font you like, just make sure to escape the spaces with a slash.

To get powerline (and Airline) patched fonts go here: https://github.com/powerline/fonts

List Your Leader Vim Mappings

[Mapping your Vim leader][l] is a great way to customize Vim without clobbering keys that are already mapped. By default your Vim leader is \, but you can change it to another key - many people suggest , since it’s so easy to type but I just use the default. In any event, if you want to add a leader mapping how can you be sure that it’s not already taken?? Easy, try this: :map <leader> Behold - a list of all mappings that involve your leader key. [l]: http://learnvimscriptthehardway.stevelosh.com/chapters/06.html

Vim Asterisk Search 🔎

My favorite thing about Vim is how deep it goes. I learn new things every day, even after several years of daily use. Asterisk (*) search was one such example from this week.

Typing * over any word initiates a search of the current buffer for the next instance of that word. It actually transfers the folllowing into the command bar, with word boundaries included (hovering over the word foo):

/\<foo\>

This is vanilla Vim, from the patterns library.

Chaining Vim Commands ⛓

You can chain Vim commands together using |. Here’s an example:

:help fugitive | resize 10

This will open the help page for Vim-Fugitive, and then resize the current window.

Here’s some real-life code I execute frequently:

:Gread | w

This empties the buffer and reads it at the last git revision, then writes the file. Very useful for rapid experimentation.

See :help :bar for more information.

Move to column in Vim

Jumping to a specific line in Vim is something I do all the time:

10G
# move to line number 10

In the last couple days I’ve wanted to jump to a specific character in a line. I did a quick Google search and found that you use pipe:

10|
# move to character number 10 in your current line

I wondered if there was anything else to know, so I hit the help file:

:he |

Which gives you:

To screen column [count] in the current line. exclusive motion. Ceci n’est pas une pipe.

And I was like, whaaa? A little more Googling and I found this:

https://en.wikipedia.org/wiki/The_Treachery_of_Images

And that there is a list of Vim help easter eggs:

http://vim.wikia.com/wiki/Best_Vim_Tips#Easter_eggs

It was like a TIL three-for-one!!