Soft wrap at 80 characters in Vim in window of arbitrary width - vim

I want to use Vim's soft wrap capability (:set wrap) to wrap some code at 80 characters, regardless of my actual window width.
I haven't been able to find a way to do this yet - all the soft wrapping seems tied to the width of the window
textwidth and wrapmargin are both for hard wrapping (they insert newline characters into the file)
vertical splitting into multiple windows and using :vertical resize 80 (possibly with :set breakat= to allow breaks on any character) on one of them sort of works (even though it's a bit hackish), but breaks when using :set number as the line numbers take up a variable number of columns (depending on the file length) and these are part of the 80.
Is there any way to do this in vim? It doesn't look promising, according to other sources.
Right now my approximation is just to have /^.\{80}\zs.\+ as my default search so it's at least highlighted. I thought about adding a :syntax item for it, but that broke when it overlapped other syntax items, so I dropped that idea.

You could
set a large minimum width for the line numbers column via :set numberwidth=6 and
then you could resize your window with :set columns=86 (or with the mouse) to the proper size.
If you edit a file with a million lines in it, you may have trouble, but that's unlikely. You're wasting 6 columns of screen real estate this way too. So there are still all kinds of problems.
You can highlight past the 80th column using :match like it says here and here.
Beyond that I can't see any way to do this. Seems like it'd be a nice feature though.

Try this:
set columns=80
autocmd VimResized * if (&columns > 80) | set columns=80 | endif
set wrap
set linebreak
set showbreak=+++
You can remove the if (&columns > 80) | if you always want 80 columns.

I don't have a solution to the soft wrap, but as for marking a column, as of Vim 7.3 (released 2010-08-15) :set colorcolumn=80 will highlight column 80. The color will depend on your syntax file.
See Vim 80 column layout concerns, :h colorcolumn.

Have you tried 'linebreak'?
*'linebreak'* *'lbr'* *'nolinebreak'* *'nolbr'*
'linebreak' 'lbr' boolean (default off)
local to window
{not in Vi}
{not available when compiled without the |+linebreak|
feature}
If on Vim will wrap long lines at a character in 'breakat' rather
than at the last character that fits on the screen. Unlike
'wrapmargin' and 'textwidth', this does not insert <EOL>s in the file,
it only affects the way the file is displayed, not its contents. The
value of 'showbreak' is used to put in front of wrapped lines.
This option is not used when the 'wrap' option is off or 'list' is on.
Note that <Tab> characters after an <EOL> are mostly not displayed
with the right amount of white space.

Combining eborisch's answer with some other answers I found here and things I had to work around, I came up with the following two-part solution:
This first part makes it easier to edit text with long lines:
" Allow enabling by running the command ":Freeform", or <leader>sw
command! Softwrap :call SetupSoftwrap()
map <Leader>sw :call SetupSoftwrap() <CR>
func! SetupFreeform()
" Use setlocal for all of these so they don't affect other buffers
" Enable line wrapping.
setlocal wrap
" Only break at words.
setlocal linebreak
" Turn on spellchecking
setlocal spell
" Make jk and 0$ work on visual lines.
nnoremap <buffer> j gj
nnoremap <buffer> k gk
nnoremap <buffer> 0 g0
nnoremap <buffer> $ g$
" Disable colorcolumn, in case you use it as a column-width indicator
" I use: let &colorcolumn = join(range(101, 300), ",")
" so this overrides that.
setlocal colorcolumn=
" cursorline and cursorcolumn don't work as well in wrap mode, so
" you may want to disable them. cursorline highlights the whole line,
" so if you write a whole paragraph on a single line, the whole
" paragraph will be highlighted. cursorcolumn only highlights the actual
" column number, not the visual line, so the highlighting will be broken
" up on wrapped lines.
setlocal nocursorline
setlocal nocursorcolumn
endfunc
With this alone you can get decent text wrapping for writing something like markdown, or a Readme.
As noted in other answers, getting wrapping at an exact column width requires telling vim exactly how many columns there are, and overwriting that each time vim gets resized:
command! -nargs=? Draft :call SetupDraftMode(<args>)
func! SetupDraftMode()
" I like 80 columns + 4 for line numbers
set columns=84
autocmd VimResized * if (&columns > 84) | set columns=84 | endif
:Softwrap
endfunc
There are still a couple of problems with this:
vim won't clear the screen outside of the columns you specify after calling set columns, and I can't figure out how to tell it to, so ideally you should call this immediately after opening vim
vim shows a prompt with the version number and some helpful commands when you open it, so these won't be cleared. You can add set shm+=I to disable that prompt
You can't open any vertical splits, because then both splits will be ~40 column. You would need to set columns to 2x your desired width and then always have a split open.
My vimscript is awful, but ideally someone could modify the Draft function above to take a column width as an argument, or use a global variable (g:explicit_vim_width?) that can be set manually if your window size changes.

There is no good way to do it. We can hack a makeshift setlocal softwrap with autocmd if we modify #eborisch answer. If we resize every time we enter a buffer, and we resize to a particular length when the local variable softwrap is set, we get the desired behaviour.
Let's suppose that we want to soft wrap to 80 columns, we can write the following in .vimrc.
augroup softwrap
autocmd VimResized * if (exists('b:softwrap') && &columns > 80) | set columns=80 | endif
autocmd BufEnter * set columns=999
augroup END
To turn on the mode for a particular buffer, use the following commands:
let b:softwrap=1
set columns=80

Related

Highlighting the 70th character of a current line in Vim

I like to keep a strict 70 character margin whenever possible. To help with this, I want to configure vim so that the 70th character of the current line is highlighted. I understand that
set cursorline
can be used to highlight the current line. I, however, would like just the
very end of the line (the 70th character) to be highlighted. How would I go about accomplishing this?
Edit: cursorcolumn isn't what I'm looking for. I just want a single character (the 70th one on the current line).
Edit 2: perhaps a picture will help.
You can use colorcolumn to set a "right margin" bar.
This did not exist before Vim 7.3, so it is wisest to only enable it if the feature is available.
if exists('&colorcolumn')
set colorcolumn=70
endif
I prefer that this only be shown in insert mode, so I use this:
if exists('&colorcolumn')
autocmd InsertEnter * set colorcolumn=80
autocmd InsertLeave * set colorcolumn=""
endif
That will set the option when you switch to insert mode, and turn it off when you leave insert mode.
:call matchadd('Todo', '\%70c')
and if you don't want to count one tab as a single character, but you want to take into account all the spaces it takes:
:call matchadd('Todo', '\%70v')
You can use any other highlight group (for example to change color) listed by :hi instead of Todo.
:autocmd CursorMoved * exe 'match IncSearch /\%70v\%' . line(".") . 'l./'
The highlight color will be determined by your color scheme.
You can change IncSearch to any of the highlight groups, which can be found by typing:
:hi
If you are using VIM 7.3 you can set the color of a certain column with:
set colorcolumn=70

Vim: disable word wrapping for specific lines

I am using :set textwidth=80 to make the Vim editor do hard wrapping automatically. However, sometimes for certain lines within a file (e.g. tables in LaTeX), I do not want Vim to do any hard wrapping automatically. Is there a way to mark certain lines to disable hard wrapping in Vim? Or automatically :set textwidth=0 just for specified lines?
There's nothing out-of-the-box, but you can build a solution with an :autocmd <buffer> on the CursorMoved,CursorMovedI events. On each move of the cursor, you have to check whether you're currently in one of those "certain lines", and modify the local 'textwidth' option accordingly:
autocmd CursorMoved,CursorMovedI <buffer> if IsSpecialLine() | setlocal textwidth=0 | else | setlocal textwidth=80 | endif
Put this into ~/.vim/after/ftplugin/tex.vim. (This requires that you have :filetype plugin on; use of the after directory allows you to override any default filetype settings done by $VIMRUNTIME/ftplugin/tex.vim.) Alternatively, you could define an :autocmd FileType tex autocmd ... directly in your ~/.vimrc, but this tends to become unwieldy once you have many customizations.
For the IsSpecialLine() function, you probably need to match a regular expression on the current line (getline('.') =~# "..."). If you can identify the "certain lines" through syntax highlighting, my OnSyntaxChange plugin can do all the work for you.
I've tried Ingo Karkat answer. Although it does work very well and does what the OP asks, I find it distracting (if I have long tables with row hundreds of characters long, there are a lot of shifts up and down when passing over tables) and can slow down a lot vim on big files (the textwidth and wrap are changed for the whole file, so running the autocmd for every cursor movement can be costly).
So I propose a static solution based on the idea that hopefully you have to modify a table as few times as possible. I've added the following to my ftplugin/tex.vim file:
" By default the text is
let s:textwidth = 90
let &l:textwidth=s:textwidth
" Toggle between "textwidth and wrap" and "textwidth=0 and nowrap".
" When editing a table, can be useful to have all the '&' aligned (using e.g.
" ':Tabularize /&') but without line brakes and wraps. Besides it's very
" annoying when line brakes "happen" while editing.
" As hopefully tables must be edited only from time to time, one can toggle
" wrap and textwidth by hand.
function! ToggleTwWrap() "{{{
" if textwidth and wrap is used, then disable them
if &textwidth > 0
let &l:textwidth=0
setlocal nowrap
else " otherwise re-enable them
let &l:textwidth=s:textwidth
setlocal wrap
endif
endfunction
So now if I want to edit manually a table I simply do
:call ToggleTwWrap()
to disable wrapping and textwidth and then again when I'm done with the table.
And of course you can create a command or a map
You can certainly set it for specific file types, but I don't think you can change those settings (or any, really) for individual lines.
Ingo Karat's answer works but setting textwidth on every single cursor move is too slow. This adapted version will only call setlocal textwidth= if the text width is actually going to change. This speeds things up considerably:
autocmd CursorMoved,CursorMovedI <buffer> if IsSpecialLine() | if &textwidth != 0 | setlocal textwidth=0 | endif | else | if &textwidth != 80 | setlocal textwidth=80 | endif | endif

Display relative and absolute line numbers simultaneously in Vim

Is there any way to display both relative and absolute line numbers simultaneously in Vim? Either side-by-side, or some other interesting presentation are fine.
Yes, you can. Use RltvNmbr.vim to display the relative numbers, and use Vim to display the absolute ones:
Vim 7.4 (Patch 7.3.787) will show the absolute line number instead of "0", when both "relativenumber" and "number" are set.
From :h relativenumber, 7.3
When setting this option, 'number' is reset.
From :h relativenumber, 7.4
The number in front of the cursor line also depends on the value of
'number', see |number_relativenumber| for all combinations of the two
options.
Reasonably speaking, you can't. Line numbering is one-per-buffer, controlled solely by the 'number' option.
One crazy notion I tried: :vertical diffsplit plus :setlocal relativenumber. This gets two copies of the buffer next to one another, linked in scroll position because they're in diff mode. However, it really doesn't work properly. The relative numbers aren't updated successfully (on 7.3.154, bug potentially fixed later, but I doubt it—it's scarcely worth it), and even if they did, you'd be stuck with a great eyesore and harder management and navigation.
You could do it with a plugin writing to a special buffer which you would keep on the left, but the implementation would be ugly, and it would still make navigation hard (because it's another buffer). I for one am certainly not going to spend time writing such a plugin, though I must confess I'd like to show both forms of line numbering.
Many years later and this feature is now part of Vim and known as hybrid numbers.
You can turn this feature on by entering:
:set number relativenumber
No speed penalty either. As far as I can tell.
Combining plnx and Macario answers with vim 7.4.
autocmd WinEnter,FocusGained * :setlocal number relativenumber
autocmd WinLeave,FocusLost * :setlocal number norelativenumber
This displays Relative Numbering (with current line in Absolute) in the focused window, and Absolute in the non-focused window.
This are my mappings related to relative and absolute line numbers
toggles between relative and absolute.
Entering a window sets the window to relative numbers, while leaving it set it to absolute.
Then if you do a vertical split of the window you would se the same buffer with relative and absoulte numbers.
" setglobal relativenumber
autocmd WinEnter * :setlocal relativenumber
autocmd WinLeave,FocusLost * :setlocal number
autocmd InsertEnter * :setlocal number
autocmd InsertLeave * :setlocal relativenumber
function! g:ToggleNuMode()
if(&relativenumber == 1)
set number
else
set relativenumber
endif
endfunc
map <C-l> :call g:ToggleNuMode()<CR>

Pressing "Home" in Vim on an Indented Line

I have a bad habit of using the 'home' key to go back to the beginning of a line. As I recently started using vim I noticed that when I press the home key on a lined that is indented, it returns me to the very beginning of the line. In Notepad++ (the editor I used to use) it would return me to the beginning of the code on that line, right after the indent.
Is there some way to replicate this behavior in vim? Usually, when I'm pressing home it's in the Insert mode for me to (usually) stick a variable there.
I have set smartindent in my vimrc, with set noautoindent as a "tips" page told me to make sure to disable autoindent (although it didn't seem to be enabled in the first place - perhaps that option is extraneous.)
There are two usual ways to go to the "beginning" of a line in Vim:
0 (zero) go to the first column of text
^ go to the first non-whitespace on the line
I find that using 0w is usually the most convenient way for me to go to the first nonblank character on a line, it's the same number of keys as ^ and is easier to reach. (Of course, if there are no leading spaces on the line, don't press w.)
You could remap Home to be the same as ^ (the docs say Home's default function is equivalent to the movement command 1|):
:map <Home> ^
:imap <Home> <Esc>^i
Which should make the insert mode mapping be equivalent to escaping out of insert mode, pressing ^ and then returning to insert mode. I don't know about the best method of mapping a motion command for use inside insert mode, so this may break something, but it seems to work.
As to your indentation settings, they shouldn't have an effect on movement controls, but I also think you probably would prefer to have them set differently. autoindent just keeps your current indentation for new lines (so if you place 4 spaces at the beginning of a line, after you press return your new line will also have 4 spaces placed in front of it). I don't know why you wouldn't want that, since it's pretty useful in pretty much any programming language, or even just freeform text. smartindent on the other hand implements a couple of hard-coded lightly C-ish indentation rules, like indenting after an opening {, and deindenting after a closing }, but doesn't automatically carry over indentation from previous lines. The docs recommend keeping autoindent on if you use smartindent.
However, smartindent is useless for languages that don't meet its hard-coded rules, or even actively harmful (like when it automatically removes indentation from any line starting with a '#', which it thinks is a preprocessor directive but is wrong for python programmers trying to write an indented comment).
So vim also includes a more advanced indentation mode, filetype indentation, which allows flexible indentation rules on a per-language/filetype basis and is the preferred indentation mode for most people (even for C-like languages). If you do use filetype indentation, it's best to turn off smartindent (otherwise it can interfere with the filetype indentation, like moving all comment lines to column 0 in python files).
Personally, I always have autoindent on, use filetype when available, and never use smartindent. My .vimrc includes:
set autoindent " doesn't interfere with filetype indents, and is useful for text
if has("autocmd")
" Enable file type detection and indentation
filetype plugin indent on
set nosmartindent
endif
I imagine there's something you could do to have smartindent turned on only when filetype indenting doesn't exist for a filetype, if you're editing that many different C-like languages with no filetype indentation available.
Here’s what I have in my .vimrc. This maps Home to move to the beginning of the
text if you are anywhere in the line, and column 0 if you are at the beginning
of the text.
function ExtendedHome()
let column = col('.')
normal! ^
if column == col('.')
normal! 0
endif
endfunction
noremap <silent> <Home> :call ExtendedHome()<CR>
inoremap <silent> <Home> <C-O>:call ExtendedHome()<CR>
Note: I am using a keyboard layout that maps Home to Alt Gr+A, that why I’m using this. If you have to leave the letter field of your keyboard to reach Home, you should probably go to normal mode instead.
You could also use _ in Normal mode to go to the first non-whitespace character of the current line. You can also use a count with this motion.
_ <underscore> [count] - 1 lines downward,
on the first non-blank character linewise.
Try pressing 0 (also see :help 0)
also, this might help:
:imap <C-Home> <esc>0a

Why can't I stop vim from wrapping my code?

I can't stop vim from wrapping my Python code. If I enter :set nowrap like a champ, but it still wraps.
I can hit J to unite the split lines of code, so it seems like a real carriage return is being inserted. I just don't understand why or how to stop it.
'textwidth' 'tw' number (default 0)
local to buffer
{not in Vi}
Maximum width of text that is being inserted. A longer line will be
broken after white space to get this width. A zero value disables
this. 'textwidth' is set to 0 when the 'paste' option is set. When
'textwidth' is zero, 'wrapmargin' may be used. See also
'formatoptions' and |ins-textwidth|.
When 'formatexpr' is set it will be used to break the line.
NOTE: This option is set to 0 when 'compatible' is set.
'wrapmargin' 'wm' number (default 0)
local to buffer
Number of characters from the right window border where wrapping
starts. When typing text beyond this limit, an <EOL> will be inserted
and inserting continues on the next line.
Options that add a margin, such as 'number' and 'foldcolumn', cause
the text width to be further reduced. This is Vi compatible.
When 'textwidth' is non-zero, this option is not used.
See also 'formatoptions' and |ins-textwidth|. {Vi: works differently
and less usefully}
If you refer to auto wrapping of long lines sending them to the next one, try
:set textwidth=0
:set wrapmargin=0
None of the other answers worked for me (IDK why).
:set wrap! Did the trick for me (using GVim for Windows).
set formatoptions-=t should do the trick. set formatoptions+=t will turn auto-wrapping back on.
For more information on what you can do with formatoptions, see the docs.
For preventing vim from wrapping long lines I use these two lines in my .vimrc:
set nowrap " do not automatically wrap on load
set formatoptions-=t " do not automatically wrap text when typing
To disable line wrap, you can enter
:set wrap! or append this command to your ~/.vimrc.
Maybe it's the textwidth that's set, which automatically breaks lines when it reaches a certain length
Try
:set tw=0
If that fails play with e.g.
:set wrap linebreak textwidth=0
and
:set virtualedit=insert
Vim may have to be in vi-compatible mode.
Open vimrc_example.vim (Yes, this is the file in Vim74) and set textwidth=0.
On macbook pro I outcommented in .vimrc the line
autocmd FileType text setlocal textwidth=78
so it became
" autocmd FileType text setlocal textwidth=78
.
(I installed a version of vim via homebrew.)
This helped for all .txt files.

Resources