Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I define an exception for line breaks in Vim?

I edit files in Vim were I log terminal command lines along with descriptions of what I did. All my command lines start with $, so my files look like this:

This is a description of what this
command does, it can be quite long and
should have line breaks.

$ ./the_command.sh

These are actually Viki files, but I guess this question should apply to any file type. I have filetype detection on and the files are correctly identified.

The question now is:

I want (hard) line breaks to be inserted into all the text except for the actual copies of command lines, which could be easily identified by the leading $.

Is it possible in Vim to define an exception for applying the line break rule based on a pattern? Would I do that in the syntax file for viki files?

UPDATE Using a combination of what Herbert and Jefromi suggested, I now have this in my .vimrc:

au CursorMovedI *.viki call SetTextWidth()

function! SetTextWidth()
    if getline(".")=~'^\$'
        set textwidth=1000
    else
        set textwidth=80
    endif
endfunction

It does exactly what I want. Thanks guys!

like image 995
tospo Avatar asked Nov 10 '10 11:11

tospo


2 Answers

I gather when you say you want "hard line breaks" you mean you want Vim to break a line automatically, as when it reaches a textwidth column. The best way to do this, I think, is to define an 'au' command that sets textwidth to a high number (higher than longest possible line) when it's on a line that begins with a "$".

So something like this would change textwidth whenever you enter or exit insert mode on a line:

au InsertEnter call SetTextWidth()
au InsertLeave call SetTextWidth()

function! SetTextWidth()
    if getline(line('.')) =~ '^\$'
        " [edit: 'set textwidth = 0' is preferable to line below]
        set textwidth =1000
    else
        set textwidth=78
    endif
endfunction

You might want to use the CursorMoved/CursorMovedI groups instead of InsertEnter/Leave since they're more fine-grained. They get triggered whenever you move the cursor, so the function ends up getting called lots more times, but function is simple enough that it's probably not going to introduce any noticeable degradation in performance.

For doing without a function at all you could probably use something like this:

au InsertEnter exec "set tw=" . getline(line('.'))=~'^\$' ? 1000 : 78
au InsertLeave exec "set tw=" . getline(line('.'))=~'^\$' ? 1000 : 78
like image 122
Herbert Sitz Avatar answered Sep 29 '22 06:09

Herbert Sitz


I believe this would meet your criteria:

set textwidth=78
v/^$/normal gq/^$\|\%$^M

^M is ctrl-v followed by enter

Lets break this down into smaller peices

/^$\|\%$ is a pattern that matches every line not starting with a $. The \%$ will include the lines between the last $ started line and the end of file.

gq/^$\|\%$ formats from the current line up to the pattern /^$\|\%$

:normal {cmd} executes a normal mode commands on current line.

:v/pattern/ is equivalent to :g!/pattern/ which executes a command on every line lot matching /pattern/

This solution does not format as you type as @Herbert Sitz solution does. Instead formats the text in one fell swoop at the end.

You could of course apply this before each write with

au BufWritePre filename-pattern-here set textwidth=78 | v/^$/normal gq/^$\|\%$^M
au BufWritePost filename-pattern-here set textwidth=0
like image 24
Peter Rincker Avatar answered Sep 29 '22 07:09

Peter Rincker