Curly bracket moving skips too many lines - vim

I mainly use curly brackets { } to move around in vim when I'm working on something. However, sometimes it will skip too many lines. I assume this is because there is no paragraph break, because if I go put new lines in, I can skip to those. This is mainly an issue when working on HTML that I didn't type or after pasting in some lines. It is very annoying when it skips too many lines for me to see what's between where I started and where I ended.
I hope I've described this well enough for some of you to know what I'm talking about.
Is there a remedy for this other than going through using j and adding line breaks? It's a huge hassle and blow to productivity when having to do this.
EDIT: I wanted to mention I only use the curly brackets to get close to pieces I need to work on. After I am close, I use other means.

That sounds like an issue where some lines contain only whitespace, and so don't get counted as paragraph breaks, even though they look like they should. Since it's only an issue in a few situations, I'd suggest just running a substitution to clean up those lines whenever you notice that it's a problem. For example:
%s/^\s*$//g
To translate what the regex means:
^ match the start of a line
\s* match any number of whitespace characters
$ match the end of the line
So it matches anything that contains only whitespace between the start and end of the line, and replaces it with nothing (note that replacing $ does not overwrite the newline character).

Related

How can I get the whitespace at the beginning of a line and use it in a search and replace?

Background
I want to convert an if statement from Fortran to C++. I like to have braces on a new line.
So I want to make
! this may be nested so indentation is unknown
if ( condition ) then
block
end if
to
if ( condition )
{
block
}
Changing end if to } is easy since the indentation is already how I want it. I just used :%s/end if/}/gc.
However, changing then is more challenging. I need to create a new line and set its the leading whitespace to the same as the previous line.
The closest I have to a solution is :%s/then/\=printf("\n%s{",indent(line('.')))/gc
However I want to use the value returned from indent(line('.') to set the number of indents.
Problem
Can I use a number I receive from a function to set the number of tabs at the beginning of line in a search and replace?
You want to substitute then with:
a newline,
followed by n spaces, as many as used for indenting the current line,
followed by an opening brace.
As is, your command does the following:
a newline,
followed by the number of spaces used for the indentation of the current line,
followed by an opening brace.
:help repeat() to the rescue:
:%s/then/\=printf("\n%s{",repeat(' ',indent(line('.'))))/gc
But there is still room for improvement…
you only want to substitute trailing thens so the g flag is useless:
:%s/then/\=printf("\n%s{",repeat(' ',indent(line('.'))))/c
the search pattern may match other thens so it should be restricted a little:
:%s/then\s*$/\=printf("\n%s{",repeat(' ',indent(line('.'))))/c
also, the pattern should include any whitespace before the then to avoid leaving annoying trailing whitespace behind:
:%s/\s*then\s*$/\=printf("\n%s{",repeat(' ',indent(line('.'))))/c
line('.') is unnecessary:
:%s/\s*then\s*$/\=printf("\n%s{",repeat(' ',indent('.')))/c
and we could use the new-ish "method" syntax to limit parenthesis nesting:
:%s/\s*then\s*$/\=repeat(' ',indent('.'))->printf("\n%s{")/c

Insert visual vim selection in the line below at the same position

I have a tedious task of converting chords from leadsheets into an inline format.
The format I have
G A
Never gonna give you up
F#m Bm
Never gonna let you down
G A F# Bm
Never gonna run around and desert you
And the format I need would b
Never gonna g[G]ive you [A]up
Never gonna l[F#m]et you do[Bm]wn
Never gonna r[G]un a[A]round and d[F#]esert [Bm]you
The problem with a script in Ruby or Python is, that the format isn't very consistent. So there could be newlines, weird characters, sometimes the chords are seperated with a dash... I haven't looked through all of the files, but I suspect more malformed stuff.
So I thought, if I have to go through of every leadsheet by hand, at least I can save some time using vim. This is the mapping I've come up with so far:
nmap <C-X> viWc[]<ESC>PviWx<down>p
Select the chord: viW
delete it and go into insert mode: c
add brackets
exit insert mode: <ESC>
paste the register to the left: P
select the chord again, including the brackets: viW
delete the selection: x
move cursor down, and paste it: p
But I few things I can't figure out is:
Sometimes the chords already have brackets, then I don't want to surround them with more brackets. Any idea how to only add brackets, if the chord isn't already surrounded with them?
It would be cool to do this with whole lines of chords. Sometimes there are multiple chords on the same line, and selecting them one by one is tedious. Any idea on how to operate the mapping above on a whole line?
well point 1 could be solved by adding the brackets around the chords on every second line:
:g/^/s/\[\=\zs[a-zA-Z#]\+\ze]\=/\[\0\]/g|+t+|-d
Credits: https://vi.stackexchange.com/questions/34785/search-and-replace-on-odd-even-numbered-lines-using-g
This however sucks, because it moves arround the chords, so we have to remove all brackets first and replace them with space
:%s/\[\([a-zA-Z#]\+\)\]/\1 /g
Then we can do the first line again, but remove some space too. Since there are no brackets left, it gets simpler (Note we use other brackets to get ride of some side effect the following code has):
:g/^/s/\([a-zA-Z#]\+\) \{0,3\}/\{\1\} /g|+t+|-d
Also we add a trailing whitespace at the end of the line so that the df} command will not move the cursor to a wrong place
Now that we have curly brackets everywhere, we can use reverse search with ?{ and then create a macro that jumps from results to result and moves it down, replaces the curly brackets with normal brackets and then calls itself (recursive macro):
gg0
qqq
?{<CR>
qq
df}jPr]F{r[n#qq
#q
And nearly all should be done.
The result:
Never gonna g[G]ive you [A]up
Never gonna l[F#m]et you dow[Bm]n
Never gonna r[G]un a[A]round and d[F#]esert [Bm]you
Note, we have to search backwards (? instead of /) so we can delete the chords directly.
If you have problems understanding what I did, feel free to ask.

Delete all newline characters not followed by ‘£’ on the next line in Vim

I have a very large file, and I want to remove all newline characters at the end of each line, so to merge all, except if the line starts with the character £.
So, if I have this:
data1
data2
£data3
data4
data5
I would like to end up with this:
data1data2
£data3data4data5
I was thinking of something like
:%s/\n(but not \n£)//g
Any ideas?
Just remove all new lines, then add them again where they should be. Or use a negative look ahead, but this is simpler, easier, and more comprehensible to anyone.
s/\n//g
s/£/\n£/g
Solution offered by #pb2q will remove all newlines and a next character if this character is not a “£” or a newline (because collection doesn’t match a newline by default), while in your question you asked to remove only the newline. This can be fixed by either using \ze, or a negative look-ahead:
%s/\n\ze\_[^£]
%s/\n£\#!
Note some things: first, you can omit a replacement string if you want to delete some text (unless you need to have a substitution flags which you don’t in this case). Second, \_ adds newline to a collection. It can be also written as [^£\n], but I guess it is not the best thing you can do: any guy coming from some PCRE-capable language thinks about [^£\n] as “match anything except ‘£’ and newline”, while in Vim it is really “match anything (including newline) except ‘£’”.
I would use the following :global command:
:g/^[^£]/-j!
It goes through all the lines that start with any character but £,
going from top to bottom, and joins each of those lines with the
preceding one via the :join command.

Vim replacing linefeeds

I resisted Vim, but have now given in. It works large files like a hot knife through butter.
Situation: I have a large text file, I want to put a pipe character at the beginning and ending of each line.
Problem: These Vims and other variations didn't work:
:%s/$/|\$|
:%s/\r/|\r|
:%s/$/|\r|
I suspect it's something simple to fix this, but searching Google and Stack didn't help.
You nearly had it:
:%s/^\|$/|/g
^\|$ means beginning or end of line. In a Vim regex, the | "or" pipe gets escaped. That is followed by /|/g -- replace with | globally.
Personally, I'd prefer the expressiveness of 'surround each line with pipe chars':
:%s/.*/|&|
This, in my brain, is more intuitive than 'replace a non-existing, imaginary character at the start or end of a line'.
It also depends on fewer magic chars (^,$, quoted \| which are all clumsy to type and error prone. (I mean, do you remember to quote the regex |? Do you know the difference between $ and \_$? Did you know some, if not all, of these depend on the 'magic configuration' of vim?)).
The above suffers from none of those.

Remove Various Whitespaces While Editing in Vim

So oftentimes, while editing with Vim, I'll get into a variety of situations where whitespace gives me hassle. For example, say I have a comment like this:
#This program was featured on the Today show, it is an algorithm for promoting world peace in third-world countries
#given the name of that country and the name of a celebrity to endorse its cause
If I want to, for example, trim the lines so they go to X characters, I end up putting a newline somewhere in the middle of the top line to get this (after hitting the newline and auto-indenting):
#This program was featured on the Today show, it is an algorithm for promoting
world peace in third-world countries
#given the name of that country and the name of a celebrity to endorse its cause
I then add a # to the beginning of the line, and that's all well and good, but then I want that line to line up, too. To do so, I have to delete the newline, all the whitespace for the indent on the next line, and then the commenting # mark. It doesn't take an awfully long amount of time to do that, but this and similar situations all add up over a day's worth of coding.
Now the example above is pretty specific, but my question isn't. What's a good way in Vim to delete all whitespace INCLUDING NEWLINES up until the next non-whitespace character? If Vim already has movements that do that, that would be awesome, but if not, does anyone have a favorite Vim function they use to do the above that could be mapped to a key? At the very least, am I missing some Vim usage idiom that prevents me from even having to worry about this case?
EDIT: Formatting to width, while useful and applicable to the case above, isn't the focus of this question. I'm concerned more with whitespace removal that doesn't stop at the end of a line, but instead carries on to the first non-whitespace character of the next line.
You really just want to reformat that comment to fit the current 'textwidth'. If the comment is a paragraph (i.e., separated by a line of whitespace above and below), then you can just use gqip (gq is the reformat command, ip is the "inner-paragraph" text object) to reformat it. If it's not a standalone paragraph, you can visually select those lines and then use gq.
This likely also relies on having 'formatoptions' set correctly to make sure the comment characters are handled properly, but in many cases the ftplugin has already done that.
This is a while later, but I found that there is a command that does what I need to in 90% of circumstances:
J -- join line below to the current one
This command seems to work:
:.s/\W*$\n\W*//g
it uses a replace to remove whitespace up to end of line and the new line at the end.
In this example:
testting aad $
asdjkasdjsdaksddjk$
(to see meta characters in vim use the command :set list)
if you place the cursor on the first line and use the first command it will delete everything from aad to $ (not including aad but including $ and a newline.)
Also, note for what you are doing it is far more efficient to use an external program to format comments for you. In particular, par is a great small C program that edits text and wraps it to desired lengths.
If you have par in your path, to do what you are trying to do is as easy as selecting the block of comment with Shift+v and running the command
:!par 40pgr
where 40 is the desired width in columns.
If you are feeling hackish, write your own program in C/perl/C++/python that edits comments however you like, then put it in path and use the external filter command :! to process blocks of text through it.

Resources