How do I change autoformat in vim? - vim

I use autoformat (textwidth = 72) to write my emails in vim.
The problem is that every time I write a list or short phrases, vim joins it to the line above.
p.e.
These are my options:
- option nr. 1
When I write "-", the "-" is immediately joined with the phrase above:
These are my options: -
Same when I use other kind of lists p.e. numbered lists or other symbols before the list.
Same thing when I write phrases shorter then 72 characters p.e.
This is my text.
This is my text on the 2nd line.
Autoformat changes it to:
This is my text. This is my text on the 2nd line.
How can I change this behavior?
I only want to format long lines when there are no Carriage Return <CR> in the first 72 characters.
If there is a <CR> it has to break there.

:help autoformat gives some useful hints:
You need to properly define paragraphs. The simplest is paragraphs that are
separated by a blank line. When there is no separating blank line, consider
using the 'w' flag and adding a space at the end of each line in the
paragraphs except the last one.
So, either :setlocal fo+=w, or turn off autoformat (maybe only temporarily, with a quick toggle mapping).

Related

Vim - count nonblank nonwhitespace lines

Using GVIM, I'd like to have something similar to the line count MSExcel offers - an on-the-fly line count that shows me how many lines I've selected so far that are non-blank (i.e. don't contain only whitespaces).
Up until now I've always used y for yank and then it shows on the bottom how many lines yanked, but:
this is not on-the-fly
this counts also blank/whitespace lines.
What's the best way to achieve this?
The downside of :substitute//n is that is clobbers the last search pattern and search history, and its output contains additional text and is difficult to capture. Alternatively, you can filter() the entire buffer, and count the matches:
:echo len(filter(getline(1, '$'), 'v:val =~# "\\S"'))
This can be easily turned into a custom mapping or command. If the performance is acceptable, you can even add this to your 'statusline':
:let &statusline .= ' %{len(filter(getline(1, "$"), ''v:val =~# "\\S"''))} lines'
Note: The statusline update won't work during a visual selection, because the marks '< and '> are only set after you've left the selection.
:%s/\S//n
3 matches on 3 lines
This combines a no-op :substitute (with the /n flag) that only counts the matching lines with the \S atom, which matches non-whitespace. As long as there is any such in a line, it is counted.
For the visual selection, just trigger it from there; it'll automatically use :'<,'> range instead of :%.
To get the number of blank lines you could use
:%s/^.\+//n
of course, instead of % you can use any other range command.
However, this approach will count only non-blank lines (without whitespace) not starting with a whitespace. Some hints on counting search results can be found here.
To allow for whitespace recognition you could use something like
:%s/^.*[^ ]\+//n

question about text formatting in Vim

I'm using Vim to write text that isn't code, just free form writing. To do this I like to have formatoptions include the w flag and sometimes the a flag.
The w flag is supposed to make it so an end-of-paragraph occurs when a line ends in a non-blank character, rather than at first blank line (which is Vim default). Here is snippet from the help docs:
w Trailing white space indicates a paragraph continues in the next line.
A line that ends in a non-white character ends a paragraph.
The a flag makes reformatting automatic, as you type. For example, in document with text below and w and a flags the lines reformat as I type only up to the 'last line in paragraph' and not below.
This it the first line of the paragraph. <cr>
The text in it reformats properly as I type <cr>
up to the last line of the paragraph, which is <cr>
right after this line, that is, just below here: <cr>
This is the last line of paragraph.<cr>
This is the first line of second paragraph. <cr>
Even though there is no blank line between <cr>
it and first paragraph, any reformatting of <cr>
the first paragraph ends at the last line <cr>
of first paragraph.<cr>
<cr>
This the the first line after second paragraph<cr>
Now to my question:
With a and w flags the reformatting works properly as I type in the first paragraph, i.e, second paragraph remains untouched. But sometimes I want to select the current paragraph using vap. It seems to me that with the w flag set this should select only the first paragraph. But in fact issuing vap in first paragraph selects the second paragraph also, all the way down to the blank line with <cr>, seemingly ignoring the w formatoptions flag.
Is this expected behavior? Am I missing something? Why does vap not select only the paragraph I'm in, which ends at first line with no trailing whitespace?
If you read the help at :h paragraph this does not mention the 'fo' setting. So it
looks like the fo setting does not really change, what defines a paragraph. This might be a bug or unclear documentation, so you might want to discuss this on the vim-dev mailinglist.
From :help text-objects or :h paragraph you can see that a paragraph for vim begins after each empty line, and also at each of a set of paragraph macros, specified by the pairs of characters in the 'paragraphs' option. Blank lines containing only whitespace are also paragraph boundaries.
The w flag in formatoptions only makes a difference when autoformatting a paragraph as you type: it will split lines and leave whitespace at the end of lines which do not end a paragraph. I suppose the help text is a bit confusing.

How to fill a line with character x up to column y using Vim

How can I fill the remainder of a line with the specified character up to a certain column using Vim? For example, imagine that the cursor is on column four and I want to fill the remainder of the current line with dashes up to column 80. How would I do that?
You can do 80Ax<Esc>d80| for a simpler solution.
Here's a function to implement what you ask, and slightly more.
It fills the line from its current end of line, rather than the cursor position
It forces a single space between what's currently on the line and the repeated chars
It allows you to specify any string to fill the rest of the line with
It uses vim's textwidth setting to decide how long the line should be
(rather than just assuming 80 chars)
The function is defined as follows:
" fill rest of line with characters
function! FillLine( str )
" set tw to the desired total length
let tw = &textwidth
if tw==0 | let tw = 80 | endif
" strip trailing spaces first
.s/[[:space:]]*$//
" calculate total number of 'str's to insert
let reps = (tw - col("$")) / len(a:str)
" insert them, if there's room, removing trailing spaces (though forcing
" there to be one)
if reps > 0
.s/$/\=(' '.repeat(a:str, reps))/
endif
endfunction
Insert that into your .vimrc, and make a mapping to it, e.g.
map <F12> :call FillLine( '-' )
Then you can press F12 to apply the hyphens to the current line
Note: this could probably be easily extended to act on a selection in VISUAL mode, but currently works for single lines only.*
If I understand the question correctly, this can be accomplished like this: in normal mode subtract the cursor's current column position from the desired ending column, then type the result followed by 'i' to enter insert mode, then the character you want to fill the space with. End by returning to normal mode. For example, with the cursor at column four in normal mode, if you wanted to fill the rest of the line up to column 80 with dashes, type 76i- then Esc or Ctrl-[ to return to normal mode. This should result in 76 dashes starting in column 4 and ending in column 79.
If you have the virtualedit option set to block or all, you can create a visual selection (even over empty space) up to the desired column:
v80| (if virtualedit=all) or
<c-v>80| (if virtualedit=block)
Then replace the selected area with dashes:
r-
It's probably helpful to start visual mode after the last character in the line by hitting l to avoid overwriting the last character in the line. If you are not using virtualedit=all, then you need to set virtualedit+=onemore so you can move one character beyond the end of line in normal mode.
One of the other answers here is: 80Ax<Esc>d80|. I initially started using it as a key mapping like this:
nnoremap <leader>- 80A-<Esc>d80<bar>
...but I didn't like how it leaves the cursor at the end of the line. Also, for narrow windows (e.g. just a little wider than 80 cells), it causes the entire window to scroll horizontally because the cursor briefly jumps to the end of the long line before it's trimmed back to 80. This is partially resolved by returning to the beginning of the line:
nnoremap <leader>- 80A-<Esc>d80<bar>0
...but then the screen will "flash" briefly while the cursor jumps offscreen and back (thus scrolling the window briefly to the right and back). To prevent this, we can temporarily use reverse insert mode (:h revins or :h ri) to keep the cursor onscreen while appending. Here's the full command as a key mapping:
nnoremap <leader>- :set ri<cr>80A-<esc>81<bar>d$0:set nori<cr>
This answer answers your question. Just replace len computation with your desired column number (+/- 1 may be, I never remember), and remove the enclosing double-quotes added by the substitution.
Using the textwidth value is also possible. It allows for different maximum line widths depending on filetype (check :h 'tw'). Here is what I now use, it appends a space after existing line content if present and will prompt for the string to use for the pattern:
function! FillLine() abort
if &textwidth
let l:str = input('FillLine>')
.s/\m\(\S\+\)$/\1 /e " Add space after content (if present).
" Calculate how many repetitions will fit.
let l:lastcol = col('$')-1 " See :h col().
if l:lastcol > 1
let l:numstr = float2nr(floor((&textwidth-l:lastcol)/len(l:str)))
else
let l:numstr = float2nr(floor(&textwidth/len(l:str)))
endif
if l:numstr > 0
.s/\m$/\=(repeat(l:str, l:numstr))/ " Append repeated pattern.
endif
else
echohl WarningMsg
echom "FillLine requires nonzero textwidth setting"
echohl None
endif
endfunction
You can map it for quick access of course. I like:
nnoremap <Leader>' :call FillLine()<Cr>
Note that the calculation assumes simple ASCII characters are being inserted. For more complicated strings, len(l:str) might not work. From :h strlen():
If you want to count the number of multi-byte characters use strchars().
Also see len(), strdisplaywidth() and strwidth().
You can insert first your dashes and then go to the first character and enter your text in replace mode: 80i-Esc0R
if you don't want to type the text, first delete the line with 0D, use 80i-Esc to insert the dashes and 0RCTRL+r " to paste the contents of the unamed register in replace mode.
I actually stumbled across this looking to align columns. Just in case anyone else does the same, this thread might be useful: How to insert spaces up to column X to line up things in columns?

How to reformat "gq"ed text in one line per paragraph format in Vim

I have some text files previously formatted in vim using "gggqG". Now I need to convert them to one line per paragraph format. I saw a way(using :g command) to do that before, but I have forgot it. Anyone knows?
There are two approaches I know of:
Set textwidth to something big and reformat:
:set tw=1000000
gggqG
Use substitute (this is more appropriate if you want to do it in a mapping):
:%s/.\zs\n\ze./ /
Explanation of the latter:
:%s " Search and replace across the whole file
/ " Delimiter
.\zs\n\ze. " Look for a character either side of a new-line (so ignore blank lines).
" The \zs and \ze make the replacement only replace the new-line character.
/ / " Delimiters and replace the new-line with a space.
If your text paragraphs are separated by a blank line, this seems to work:
:g!/^\s*$/normal vipJ
:g global (multi-repeat)
!/^\s*$/ match all lines except blank lines and those containing only whitespace.
normal enters 'normal' mode
vip visually select inner paragraph
J join lines
Maybe you should set textwidth to very large value (like 99999999) (0 does not work for some reason) and use gggqG?
// I cannot tell you a way to reformat your paragraph with :g without knowing exactly what the paragraph is. Maybe somebody else can.

Vim: How to reformat a set of lines into a single line (if the line is a single sentence)?

Not a dup of In Vim, what is the simplest way to join all lines in a file into a single line?, as I specifically mean to use the gq reformatting functionality.
I used to write latex in vim using 80 character textwidth. However, I've now switched to an infinite textwidth, so my lines go on forever.
Vim's reformatting (gqap for example), combines a few lines into a paragraph, wrapping them at 80 characters. I'd like it to instead combine them into a single line.
ie
Without a \clang{goto} statement in the HIR, we must instead use conditional
statements to check the iteration number.
should reformat into
Without a \clang{goto} statement in the HIR, we must instead use conditional statements to check the iteration number.
when it is highlighted and gq is pressed.
If you don't like "J" as depesz suggested then do
:set tw=9999
Then do 'gq'. Adjust tw to your needs.
Why don't you just "J" the lines after you select them?

Resources