Articles

NoVIMber 09, 2014 - Using Windows (not the operating system)

In "yesterday's" post, we covered the basics of buffers. Today we're going to talk about windows in Vim. A window is basically a viewport that buffers can attach to. This gives us access to the buffer so that we can manipulate its contents. A buffer can be attached to mulitple windows or no windows. When you initially start Vim, a single window is created by default. If you're starting Vim with multiple files, you can use the "-o" or "-O" flags (on the commandline, not in Vim) to open all of the files in multiple windows:

-o  Open all files in windows split horizontally
-O  Open all files in windows split vertically

vim -o file1 file2 file2

As a general rule, window related commands will start with CTRL-W.

Creating & Closing Windows

There are lots of ways to create new windows:

:split    Split current window horizontally to create a new window. Both windows will be a viewport to the same file
CTRL-W s  Same as :split

:vsplit   Same as :split except split vertically
CTRL-W v  Same as :vsplit

:new      Same as :split except new window is an empty file
CTRL-W n  Same as :new

:vnew     Same as :new except split vertically

CTRL-W ^  Split current window and edit alternate file in new window

There are also several different ways to close windows. The most common would be :quit. That's right, the quit command that we all use regularly closes our current window. When there is only one window, this will exit Vim. Let's look at some more ways to close windows:

CTRL-W q  Same as :quit
:qall!    Closes all windows and exits Vim. Fails if any buffers are unmodified unless ! is given.

:close!   Closes the current window. If buffer is unchanged, hidden is set, or ! is given the buffer becomes hidden. Otherwise the command fails
CTRL-W c  Same as :close

:only!    Make current window the only window on the screen. Other buffers will be hidden. 
CTRL-W o  Same as :only

It's important to note that passing ! to :close and :only is "safe". If modified buffers would be closed, the buffers will become hidden and modifications will be preserved.

Moving Between Windows

The basic commands to move your cursor between multiple windows are the same as the default cursor movement keys - "h", "j", "k", and "l" - with CTRL-W in front of them. You can also use CTRL-W with the arrow keys.

CTRL-W h  Move cursor to window that is left of current window
CTRL-W j  Move cursor to window that is below current window
CTRL-W k  Move cursor to window that is above current window
CTRL-W l  Move cursor to window that is right of current window

CTRL-W t  Move cursor to top-left window
CTRL-W b  Move cursor to bottom-right window
CTRL-W p  Move cursor to previous window

Conclusion

There's a lot more that I'd like to cover (moving windows around, resizing windows, etc...) but I'll save those for another post. At this point, you should be able to reasonably use buffers and windows to edit multiple files inside of a single instance of Vim. As it stands, I'm not really sure if this would improve my workflow (multiple Vim instances inside of a screen/tmux session). Only time will tell! Happy Viming!

Reference Material

Vim documentation: windows


NoVIMber 08, 2014 - Introduction to Buffers

I got this out a little later than I had anticipated! Hopefully I'll have time to finish up my next post by the end of the day. I'd hate to perpetually be a day behind going forward! This is going to cover the very basics of buffers. Buffers can be a difficult concept to explain. A buffer is defined as the text of a file that is currently in memory. Think of it like this: when you open a file in Vim, it loads the contents of that file into memory and then displays that file to your current "window". A buffer does not have to be attached to a window though. We'll touch on windows a bit more in another post. For now we'll focus on buffers and the default single window that gets created when Vim starts.

Buffer Types

There are 3 different buffer types:

Active    Is displayed to a window and file contents have been loaded into the buffer
Hidden    Is not displayed to a window but file contents have been loaded into the buffer
Inactive  Is not displayed and does not contain any text

Buffer Basics

You can open a file in a new buffer with:

:edit /path/to/file

By default this will open /path/to/file into a new buffer and attach that buffer to your active window. If your current active buffer has been modified, you might see "E37: No write since last change (add ! to override)". By default an active buffer cannot become a hidden buffer if it has unsaved modifications. If you give it the ! to override, it will revert all of your modifications in the buffer. If you want to keep your modifications, you can do so with:

:set hidden  Allows a buffer to become hidden when on

It's useful to be able to see what buffers currently exist and to be able to switch between them at will. The next couple of commands will help with that:

:buffers  Displays a list of current buffers
:ls       Same as :buffers

Let's look at some example output of that:

:buffers
  1 #h   "file1"                        line 1
  2      "file2"                        line 0
  3 %a + "file3"                        line 2

Each buffer is assigned a unique number that will not change - the number in the first column. The values in the second column are "indicators". Here are a few of the indicators that are relevant to this example:

#  Alternate buffer (more on that below)
h  Hidden buffer
%  Buffer that is in the current window
a  Active buffer
+  Modified buffer
=  Readonly buffer

All of those are self-explanatory except for the alternate buffer.

The Alternate Buffer

The alternate buffer provides an easy way to flip between two buffers in Vim. In the above example, file3 is our active buffer attached to our current window. file1 is our alternate buffer. We can switch to the alternate buffer with:

:edit #  Edit the alternate buffer
CTRL-^   Same as :e #. On most keyboards ^ is on the 6 key, in that case this command would be CTRL-6

Once I've flipped to the alternate buffer, my previous buffer will become the new alternate buffer. I can get back to it by flipping a second time.

Moving Between Buffers

If you're editing more than two buffers, things get a little more complicated. There are several ways to switch between multiple buffers.

:buffer [N]  Edit buffer N
:bnext       Edit next buffer
:bNext       Edit previous buffer
:bprevious   Same as :bNext

All of these commands are referencing the buffer number. If you're on buffer 2 and you use :bn, that will put you on the next highest numbered buffer. If 2 is the highest numbered buffer, it will wrap you around to the lowest numbered buffer. As you'd imagine, :bp/:bN works the same way.

Conclusion

That's about all I'm going to cover in today's post. We'll cover more buffer related stuff after we've covered the basics of windows in Vim. Happy Viming!

Reference Material

Vim documentation: windows


NoVIMber 07, 2014 - Advanced searching

It's Friday night, I've got a glass of wine, an episode of Stargate SG-1 is playing in the background, and I'm ready to type some words about Vim! This little project has been way more rewarding than I could have expected!

Searching in an open file is an important aspect of efficiently editing in Vim. I briefly mentioned the basics of searching (forward and backward) in yesterday's post but let's see it again:

/searchstring  Forward search
?searchstring  Backward search

If you reach the end/beginning of a file, the default behavior is to "wrap" to the top/bottom of the file and start again. Sometimes this is really useful but sometimes it's annoying. Fortunately, it's easy to enable/disable:

:set nowrapscan  Disable search wrapping in a file
:set wrapscan    Enable search wrapping in a file

Case Sensitive Searching:

By default, search is case-sensitive. Searching for "thing" will not match "Thing", "THING", or "thinG". If you'd like to ignore casing you can do:

:set ignorecase            Ignore case when searching
:set ignorecase smartcase  Ignores case if pattern is all lower-case. Conforms to case if pattern contains any upper-case letters

Regex Searching:

You can also do some regex style searching, you just need to remember to escape certain things such as (), +, |, etc... For example:

/\(dog\)*        Matches empty string, dog, dogdog, dogdogdog, etc...
/dog\+           Matches dog, dogg, doggg, etc...
/dog\|cat        Matches dog or cat
/dogg\(y\|ies\)  Matches doggy and doggies
/[0-9]           Matches a number
/[^0-9]          Matches any non-number

There are also "predefined ranges" that you can use to match certain types of characters:

\a  Matches an alpha character [a-zA-z]
\d  Matches a digit
\D  Matches a non-digit
\s  Matches whitespace
\S  Matches non-whitespace

There are more of these predefined ranges that could be useful. I just found these to be the most useful!

Hopefully this will help you when you're searching for that special thing inside of a file! For more information and a more thorough explanation of the topics I mentioned here, check out the reference material below! Happy Viming!

Reference Material: Vim documentation: usr_27


NoVIMber 06, 2014 - The much neglected Command-line mode

Command-line mode allows you to execute "Ex" commands, searches, and filters. Ex is a line editor. Vi was originally written as a visual interface for Ex. I know a lot of people that use command-line mode exclusively for a few common things:

:w   Write a file
:q   Quit a file without saving (append ! if you have made changes)

:[range]s/search/replace/  Basic search & replace

/searchstring  Forward search
?searchstring  Backward search

Until recently, I was also one of those people. In previous posts we've touched on a few specific Ex commands (:retab, :set list, and :reg come to mind). For today's post, I'd like to cover a few additional commands that could be useful.

Help:

For starters, let's cover a very useful and surprisingly underused/under-known command:

:help  Display Vim's help documentation in a new window

:help {command/subject}  Same as :help except jump to relevant section in documentation. Can include wildcards *, ?, and [a-z].

You'd be surprised how often this could come in handy... but I know very few people (myself included) that actually use it with any regularity. If you're not exactly sure what you're searching for, just try searching for something. I have had good success with finding information this way.

History:

:history  Display the history of ":" Ex commands

: + CTRL-P/CTRL-N  Scroll through your history (CTRL-P is "previous" line and CTRL-N is "next" line... like Emacs!)

This one is a no-brainer as well but is very underused. Let's say that you've executed several search & replace commands but you're missing more data than you thought. The first place you should look is at the :history of your search & replace commands to make sure you typed them correctly. It's also really useful to be able to scroll through your history and execute Ex commands again (by pressing once you've selected your desired command).

Text Manipulation:

The next few commands are going to kinda be lumped together since they're mostly dealing with the processing of text. Most of these commands follow the same syntax pattern:

:[range] command [arguments ...]

Before we get into commands that follow this syntax pattern, let's see how we can represent different ranges:

.  The current line
$  The last line of your file
%  Every line of your file
7  Line 7 of your file

You can also represent ranges and do basic math in these ranges:

1,5  Every line from line 1 to line 5 including lines 1 and 5
+10  10th line below current line (. is assumed in this case)
$-8  8th line from the bottom

Global Actions

Global actions are so powerful! Let's look at the syntax and a few examples.

:[range]g/pattern/command  Find *pattern* within *range* and execute *command* on that line

:g/redhat/p  Print lines matching "redhat"
:g/suse/d    Delete all lines matching "suse" (no bias here at all)

Fun fact: this is where the command line utility "grep" got its name (:g/re/p). I can't count the number of times that I've (incorrectly) used the search & replace command to remove entire lines that match a pattern. This is so much easier! I've linked the Vim Wiki page for Global actions below in the reference material. Check it out to see more of the cool stuff you can do.

Filter Command

If search & replace and global actions aren't powerful enough, you can even leverage external command line utilities to help you out.

:range!command  Execute *command* on *range* lines

:%!sort  Uses the "sort" command line utility to sort all lines in your file

If you do not specify a range, the command will just be executed and the results will temporarily be displayed on your window. You could also see why it's a bad idea to grant users sudo access to Vim haha!

Well that about covers it for today! We're almost a week into NoVIMber and there's still so much to cover. I might eventually double-back and pull from previous posts to elaborate on certain subjects since a few things have been skimmed.

Until next time, Happy Viming!

Reference Material: Vim documentation: helphelp - :help

Reference Material: Vim Wiki - Power of g

Reference Material: Vim documentation: usr_20

Reference Material: Vim documentation: cmdline


NoVIMber 05, 2014 - Commands in insert mode

This post is going to cover commands that can be executed while in insert mode. There are a lot of these commands but I only plan on touching a few that were interesting to me.

First let's take a look at how you can get out of insert mode:

Getting out of Insert mode
<Esc>   End insert or replace mode finishing abbreviation
CTRL-[  Same as <Esc>
CTRL-C  Quit insert mode without checking for abbreviations. Does not trigger the "InsertLeave" autocommand.

If you don't like moving your hand to the key, you could use CTRL-[ as a replacement. CTRL-C would probably work just as well in most cases but if you have anything that depends on the InsertLeave autocmd, that will not trigger with CTRL-C. If CTRL-C (or any other sequence) is easier for you, you could always map that to . I personally map ndc> so that I can just mash the two together (in any order) and hop out of insert mode:

inoremap jk <esc>
inoremap kj <esc>

What if we want to delete some text without leaving insert mode?

Deleting text in Insert mode
CTRL-W  Deletes the word before your cursor
CTRL-U  Deletes all characters in the current line before your cursor

We can also insert the contents of a register without leaving insert mode!

Inserting text from a register in Insert mode
CTRL-R {register}         Insert the contents of a register. Once you press CTRL-R, a " (double quote) will appear under your cursor. Text is inserted as if you typed it with your keyboard.
CTRL-R CTRL-R {register}  Same as CTRL-R except the text will be inserted literally rather than as if you had typed it.

There are a couple of other CTRL-R variants. Check out the Vim documentation linked below for more details on those.

You can also manage line indentation without needing to go to command mode! I've already started using this one and it has made my life a lot better!

Managing indentation in Insert mode
CTRL-T    Insert a single "shiftwidth" size indent at the beginning of the current line
CTRL-D    Delete a single "shiftwidth" size indent from the beginning of the current line
0 CTRL-D  Delete all indentation in the current line

The last thing I'd like to cover is the ability to "literally" insert a character. For example, let's say that you have expandtab set but you want to insert a real tab character:

Inserting a "literal" character in Insert mode
CTRL-V  Insert follwing character literally
Example: CTRL-V <TAB> would insert a tab character at cursor location

There's a lot more that you can do inside of insert mode. I intentionally wanted to keep this post brief. I may touch on more of these commands in a later post.

Happy Viming!

Reference Material: Beautiful Vim Cheat-Sheet Poster

Reference Material: Vim Documentation: insert - Special keys