Today I Learned

A Hashrocket project

220 posts about #vim

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!!

Disable a pathogen plugin

Let’s say I got this plugin that’s just messing my editor up all day and I want to disable it. Because pathogen just looks at the plugins dir and loads whatever is there I can’t just remove it from a manifest (or something similar).

There IS though a cool global vimscript var called g:pathogen_disabled that can be populated with all the vimscripts you’d like to disable.

It must be declared and populated before the call to pathogen#infect

let g:pathogen_disabled = []
call add(g:pathogen_disabled, 'vim-badplugin')
call pathogen#infect()

There ya go! Now vim-badplugin will not be included by pathogen!

Vim undo tree

Vim has an undo tree and there’s two different ways to iterate with your changes.

One way to undo/redo changes is with: u and <Ctrl>r. This moves the current state based on the current branch in the tree.

The other way is using g- and g+. In this case it moves based on the timestamp of that change.

So here’s an example to follow:

  1. add a line: added_line_1
  2. update this line: updated_line_1
  3. undo this change: u
  4. add another line: added_line_2

If you run through these steps your undo tree will be something like:

 o  [3] "added_line_2" <= "current_state"
 | *  [2] "updated_line_1"
 |/
 *  [1] "added_line_1"
 *  [0] "empty_file"

Now, if you undo with u will be in this state:

 *  [3] "added_line_2"
 | *  [2] "updated_line_1"
 |/
 o  [1] "added_line_1" <= "current_state"
 *  [0] "empty_file"

Otherwise if you undo with g- will be in this part of the tree:

 *  [3] "added_line_2"
 | o  [2] "updated_line_1" <= "current_state"
 |/
 *  [1] "added_line_1"
 *  [0] "empty_file"

You can check gundo vim plugin for tree visualization.

Vim Regex Word Boundaries

Today while writing a Vim regex to change every instance of it (ignoring larger matches like itemized), we stumbled upon Vim regex word boundary matching.

Given this file:

foo
foobar

The following Vim regex will match on both the first and second line:

:%s/foo/baz/g

But with word boundaries, we’ll only match (and change) the first line, because only the first foo is a standalone word:

:%s/\<foo\>/baz/g

Remove both scrollbars from MacVim

If you use MacVim you may encounter the gray Mac OS scrollbar on the right side.

When you split the window you may encounter two scrollbars, one on each side.

I find that to ruin the look of MacVim, especially with a dark colorscheme (I use Dracula).

example

To remove only the left one use

set guioptions=r

This will tell vim to always show the right scrollbar only. To remove only the right one use

set guioptions=l

To remove all scrollbars, remove everything after the equal sign

set guioptions=

example

Add this to your vimrc for a consistent experience.

Toggle CursorLine, CursorColumn w/Vim Unimpaired

Vim Unimpaired plugin by Tim Pope ships with a shortcut for quickly toggling CursorLine and CursorColumn. This is particularly useful on large files with plenty of syntax highlighting.

Turning CursorLine/CursorColumn off can speed buffer navigation by reducing the blocks being re-rendered on the screen, making Vim snappy again.

To use this shortcut type cox from NORMAL mode and Vim will toggle CursorLine and CursorColumn on and off.

h/t Chris Erin

DEMO: demo

Non-Greedy Vim Regex

Regex is by default greedy, meaning, if you used this regex /.*, on the following line:

a123,b123,c123,d123

You’d match everything up to the last comma a123,b123,c123. If you just want everything to the first comma you need to use a non-greedy matcher. In posix regex you could modify the * operator (match 0 or more) with the ? operator, like this: /.*?,/.

Vim however is a bit weird and doesn’t support making the * operator non-greedy in this manner. You can however use curly braces to tell vim to match 0 or more, but as few as possible like this: /.\{-}, which will match just a123,.

Remember, the leading curly needs to be escaped with a slash \. See :help pattern-overview for more!

Rotate Everything By 13 Letters

For some inane reason, Vim comes with a ROT-13 feature. So, if you are ever in need of rotating the letters of some portion of the file by 13, you can do that with the simple g? binding.

For example, if you hit g?? on the following line:

Six dollar eggs

you will get

Fvk qbyyne rttf

As you can see, casing is preserved.

The only practical uses of this are Vimgolf and convincing people at coffee shops that you are a hacker.

See :h g? for more details.

Show Matching Entries For Help

Looking up things with Vim’s :help command can be error prone if you don’t know exactly how to format what you are looking up. Bypass some of the guesswork by hitting Ctrl-d after writing part of the :help command. This will populate a wildmenu of possible matches.

For instance, if you know there is a command containing ?, but you aren’t sure how to look it up, try the following:

:help ?<Ctrl-d>

You can tab through to the one you want and hit enter to read up on it. Who knew there were so many Vim bindings involving a ?.

See :h help-context for more details.

Reset Target tslime Pane

The combination of tslime and turbux makes running tests from Vim in a tmux session as easy as a single key binding. One problem that can arise from time to time is having tslime focused on an undesired tmux window/pane combination. There is no binding to tell tslime that you’d like to re-select the target window and pane.

I’ve often resorted to closing out of Vim in order to reset the prompt. There is a better way and it doesn’t require you to wipe out your Vim session.

Just unlet the global Vim variable for the tslime plugin like so:

:unlet g:tslime

The next time you invoke turbux it will see that g:tslime isn’t set and will prompt you for a new window and pane combination.

h/t Josh Davey

Open Multiple Tabs with Vim

I like to use Vim to open many files at once. Today I discovered the -p flag to help with this process.

To open all the files in a directory in tab mode, use this command:

$ vim -p path/to/files/*

-o does the same thing in horizontal splits; -O in vertical splits.

When you’re finished reading, :qall is a nice way to close the book.

Share Highlighted Code

Today I learned a cool trick.

Select a range of code, enter command mode, and type Gbrowse:

:'<,'>Gbrowse

This opens Github in your browser with the range of code highlighted. Github support seems to be standard; I believe you can add other code hosting providers.

Here’s a link I made with this command:

https://github.com/hashrocket/hr-til/blob/1bc38b724bb620b1672a9f525a4450f6d4f68b3c/app/controllers/sessions_controller.rb#L15-L18

This also accepts a line number:

:10 Gbrowse

Window to Tab

Sometimes I like to use Windows in Vim, and sometimes tabs. But switching from windows to tabs? That’s pretty smooth.

If you have a bunch of windows open, CTRL-W_T moves the current window to a new tab.

Check out :help CTRL-W for a crazy list of similar Vim power tools.

h/t Brian Dunn