This is a read-only archive!

56 Posts Tagged 'Vim' RSS

Vim: Find lines longer than current line

Vim isn't just for editing source code. It's also a pretty good data editor.

Sometimes I'm editing dirty fixed-width data files, and some lines are incorrectly a bit too long because one or two fields overflowed. It's easy to search for lines that are too long, once you know how long lines should be. Say your lines should be 1000 characters; search like this:

/^.\{1001}

Now all the longer lines are highlighted (assuming :set hls).

That's tedious to type though. Put your cursor on a non-overflowing line and call this function, and Vim will find all the lines that are too long, and move you to the first one:

function! FindLongerLines()
    let @/ = '^.\{' . col('$') . '}'
    silent! norm n$
endfunction

That mess about manually setting @/ is because of this somewhat unfortunate fact (from :help :function):

        The last used search pattern and the redo command "."
        will not be changed by the function.  This also
        implies that the effect of |:nohlsearch| is undone
        when the function returns.

That is, using something like norm / inside functions doesn't affect the last-remembered search once the function returns, but that's exactly what we want to happen.

June 21, 2012 @ 3:29 AM PDT
Cateogory: Programming
Tags: Vim

cursorcolumn / cursorline slowdown

The cursorcol and cursorline options in Vim are great. Enabling them, and setting up your syntax highlighting correctly, will highlight the line and column that contains the cursor, drawing a sort of "crosshairs", to let you find the cursor easily.

This is especially useful when editing non-sourcecode files, like giant fixed-with data files. Or when you need to keep switching your attention back and forth from Vim to something else; the visual cue to draw your eyes back to the cursor can be useful to prevent a mental page fault.

Cursor crosshairs

Great. However, the help info for cursorcolumn says this, in part:

    Highlight the screen column of the cursor with CursorColumn
    |hl-CursorColumn|.  Useful to align text.  Will make screen redrawing
    slower.

"Will make screen redrawing slower" is an understatement, unfortunately. Over the past who-knows-how-long, I've noticed Vim slowing to a crawl when editing certain files, mostly big Ruby files. Moving the cursor around or scrolling the window became pretty painful. I could never quite figure out why, but today I got sick of it, and eventually found an old message on the Vim mailing list explaining the problem.

Apparently when you have cursorcolumn or cursorline enabled, the whole screen is redrawn every time you move the cursor. That explains a lot. When I disabled these options, editing complex Ruby files once again achieved notepad.exe-level speed.

I guess there's this:

function! CursorPing()
    set cursorline cursorcolumn
    redraw
    sleep 50m
    set nocursorline nocursorcolumn
endfunction

nmap <C-Space> :call CursorPing()<CR>

This will flash the cursor crosshairs for 50 milliseconds when I hit CTRL+Space in normal mode. Better than nothing.

April 30, 2012 @ 8:48 AM PDT
Cateogory: Programming
Tags: Vim

Shuffle lines in Vim

In a pinch, I needed to randomize the order of a few thousand lines of plain text. In Linux you can just pipe the file through sort, even right inside Vim:

:%!sort -R

But I was stuck on Windows. And I don't know how to randomize a file in native Vim script. But doing it in Ruby is pretty easy, and luckily, Vim has awesome Ruby support. Tne minutes' work and a few peeks at :h ruby and we have a successful, working kludge:

function! ShuffleLines()
ruby << EOF
    buf = VIM::Buffer.current
    firstnum =  VIM::evaluate('a:firstline')
    lastnum = VIM::evaluate('a:lastline')
    lines = []
    firstnum.upto(lastnum) do |lnum|
      lines << buf[lnum]
    end
    lines.shuffle!
    firstnum.upto(lastnum) do |lnum|
      buf[lnum] = lines[lnum-firstnum]
    end
EOF
endfunction

2011-07-07 23:32 - Edited to remove a superfluous line.

2011-07-09 21:33 - Wrong parameter for sort, oops.

July 07, 2011 @ 7:07 AM PDT
Cateogory: Programming
Tags: Ruby, Vim

org-mode is awesome

I've seen org-mode for Emacs mentioned very frequently around the interwebs, so it went into my mental queue of topics to learn. It finally bubbled to the top this week, so I took a look.

Organizer? Nah.

As an organizer/calendar, well, I doubt I'll need it. Enforced use of MS Outlook is mandated by work. My Post-it-notes-all-over-my-desk method of organization will also continue to serve me well.

There are some nice agenda-related shortcuts that are probably worth using though, like typing C-c . to enter a datestamp, like <2011-01-20 Thu>. Then you can increment or decrement it one year/month/day at a time via S-up and S-down. I like this.

Plaintext editor? Yes!

As a plaintext outline and table editor... wow. org-mode rocks. Do you know how many hours of my life could have been saved by having a good ASCII table/bullet-list editor? org-mode lines everything up and keeps it all nice and neat for you.

You can also make plaintext check boxes and check/uncheck them. And you can insert hyperlinks and footnotes, and click them to open web pages or jump back and forth between footnote and reference.

There are ways to collapse and expand outlines, search for items and only display those items, and so on. The documentation for org-mode is very clear and took me less than an hour to read through. All-in-all a pleasant experience.

* Agenda
** Things to learn
1. [X] Clojure
2. [X] org-mode (see [fn:diagram1])
3. [ ] Haskell
4. [ ] Japanese
   1. [X] Hiragana
   2. [X] Katakana
   3. [ ] Kanji
5. [ ] The true meaning of friendship

* Footnotes
[fn:diagram1]

| Task                              | Annoyance (1-10) |
|-----------------------------------+------------------|
| Making ASCII tables by hand       |              9.5 |
| Making ASCII bullet lists by hand |              7.2 |
| Using org-mode                    |              0.4 |

It looks nice plastered into my blog, but you don't get a real idea of how many cool things you can do with it until you open it in Emacs and start shuffling items around, bumping them up/down a level in headlines, creating properly-numbered bullet items with one key, and seeing the columns in the table auto-resize as you type.

I also highly recommend putting (setq org-startup-indented t) into .emacs to make everything look pretty on-screen. It still saves as the simple plaintext above, but it looks like this in Emacs:

org-mode

I can definitely see using org-mode for TODO files in some of my projects. (You can mark entries as TODO (just by typing TODO in front), and then toggle between TODO/DONE via C-c C-t.) I can also see using it as a general-purpose note-taker.

org-mode also has a mobile version for iPhone and Android, synced via WebDAV or Dropbox, so you can org-mode on your phone while you're driving to the grocery store1. Again I don't really need this, but there it is.

The joy of plaintext

Plaintext is awesome.

It's the universal file format. It's readable and writeable by scripting langauges, terminals, text editors, IDEs, word processors, web browsers, even lowly humans.

Plaintext's one shortcoming is its lack of structure. It's just a bunch of letters. It doesn't have a color, it doesn't have a style, it doesn't line up into columns without a lot of effort. There's nothing stopping you from opening a parenthesized list and forgetting the closing paren.

Computers don't care about these problems, but humans are bad at producting plaintext by hand, and bad at editing it once it's produced. Our clumsy, stumpy fingers and inconsistent, chaotic brains can't handle the freedom.

Emacs (and Vim) are awesome because they let you do magical things to plaintext. They enforce structure. They provide shortcuts so you can get your plainext right the first time.

[ ] is just two braces and a space, but org-mode lets me hit C-c C-c and turn the space into an X. This may seem banal, hardly worth caring about, but add to this shortcut thousands upon thousands of others. Things like org-mode, or paredit, or all of Vim's built-in magic... it all adds up to something wonderful.

And best of all, you always still have the option of manually keyboarding over and typing that X between the braces yourself. It's still just plaintext underneath. So you end up with the best of both worlds.

  1. I do not recommend using org-mode while driving, for public safety reasons.

January 20, 2011 @ 8:14 AM PST
Cateogory: Programming

Vim undo tree visualization

I wrote previously about an awsome plugin to give Emacs Vim-style undo trees.

Vim's undo trees are the best thing since sliced bread, but the interface for browsing through the tree is not pleasant. The Emacs undo-tree library has a way to visualize the tree and move through it with your keyboard, which solves this problem.

But now, thanks to Steve Losh, Vim has an undo-tree visualizer too. Delicious. Though it's still beta and promises to eat your babies, it seems to work pretty well. I think the diff view of the changes for the undo is a really good idea.

Thus continues the eternal Vim/Emacs arms race.

Vim undo tree

October 18, 2010 @ 8:21 AM PDT
Cateogory: Programming
Tags: Emacs, Vim, Undo

Vim :ruby and :rubydo scope

Note to self. In old Vim (tested in 7.2.320), I could do this:

:ruby x='foo'
:rubydo $_=x

Now every line in the file says foo. But in Vim 7.3 I get an error:

NameError: undefined local variable or method `x' for main:Object

The scoping rules for Ruby in Vim must have changed somewhere along the line. I was abusing this feature to do some handy things, so this is sad.

A workaround is to use global variables in Ruby instead. So this still works:

:ruby $x='foo'
:rubydo $_=$x

Phew.

August 31, 2010 @ 3:40 AM PDT
Cateogory: Programming
Tags: Ruby, Vim

Emacs undo trees

I've said it before: undo in Emacs is horrible. On the other hand, undo in Vim is awesome.

But this is true no longer. Now there are undo trees for Emacs! Yes, this news is so important I had to italicize and bold it. It's like Emacs has been punching me in the face for years, and today I got it to stop. I never thought I'd see the day.

And it works great too. You can even view the tree visually and navigate it with the cursor keys, which is a step up on what Vim offers out of the box.

Emacs undo trees

In other news, Vim 7.3 is out and it now has persistent undo across reloads. It's like an arms race, and gleeful hackers reap the benefits.

August 17, 2010 @ 7:06 AM PDT
Cateogory: Programming
Tags: Emacs, Vim, Undo

Vim and plaintext data files

I use Vim to work with plaintext datasets. Here are some habits and code snippets I've picked up which make data files a bit easier to deal with.

July 12, 2010 @ 3:42 AM PDT
Cateogory: Programming
Tags: Vim

Vim regex - remove kind-of-matching lines

I have a file where every line starts with a number (followed by whitespace and a bunch of other stuff). Every number appears on either one or two lines, and if two, the second line always has a b after the number.

I need to delete every line for which there's a corresponding b line. But if there's no corresponding b line I want to leave the original line there.

Before:

123 foo bar
456 blarg
789 quux
123b foo baz
789b quux blurble

After:

123b foo baz
456 blarg
789b quux blurble

Except in my real file, I have a thousand lines and it'd take a year to do by hand. Vim to the rescue:

:sort
:%s/^\v((\d+).*\n)(\2b.*)/\3/

And that is why Vim is awesome. Can you think of a shorter way to do this, in Vim or Emacs?

June 20, 2010 @ 3:49 PM PDT
Cateogory: Programming
Tags: Vim, Regex

Emacs: Yank lines as lines

One thing nice about Vim is manipulating whole lines at a time. dd deletes a line (including trailing newline), regardless of where the cursor is on the line. Then, p puts that line (with its newline) as a new line after the current line, and P puts it above the current line, again regardless of where your cursor is at the moment. (It also jumps the cursor to the beginning of the text you just inserted, which is nice.)

Emacs has kill-whole-line (C-S-Backspace) which is like Vim's dd. But I didn't find an equivalent of p and P. So here's my version:

(defun yank-with-newline ()
  "Yank, appending a newline if the yanked text doesn't end with one."
  (yank)
  (when (not (string-match "\n$" (current-kill 0)))
    (newline-and-indent)))

(defun yank-as-line-above ()
  "Yank text as a new line above the current line.

Also moves point to the beginning of the text you just yanked."
  (interactive)
  (let ((lnum (line-number-at-pos (point))))
    (beginning-of-line)
    (yank-with-newline)
    (goto-line lnum)))

(defun yank-as-line-below ()
  "Yank text as a new line below the current line.

Also moves point to the beginning of the text you just yanked."
  (interactive)
  (let* ((lnum (line-number-at-pos (point)))
         (lnum (if (eobp) lnum (1+ lnum))))
    (if (and (eobp) (not (bolp)))
        (newline-and-indent)
      (forward-line 1))
    (yank-with-newline)
    (goto-line lnum)))

(global-set-key "\M-P" 'yank-as-line-above)
(global-set-key "\M-p" 'yank-as-line-below)

Just one more step along the path to Vimmify my Emacs setup. Emacs has some weird edge cases because you can move the cursor one "line" past the last real line in the file. But I think I worked out something comfortable for myself.

PS: I've written about this before, but if you use C-S-Backspace a lot in Emacs on Linux, I highly recommend putting this into your X11 config:

Option "DontZap" "True"

It's really easy to mix up C-S-Backspace and C-M-Backspace (the latter of which kills your X server). It's not fun to mix those up. Not fun at all.

PPS: This thread on Stack Overflow has some Emacs equivalents of Vim's o and O which are pretty nice too.

May 21, 2010 @ 5:07 AM PDT
Cateogory: Programming
Tags: Emacs, Vim