Get line number of start/end of current paragraph - vim

for the need of a script I'm currently writing, I'm trying to get in the fastest way possible the line number of the start/end of the current paragraph.
At first I was using line("'{") and line("'}"), but this actually is not working in this use case:
1. this is a
2. paragraph
3.
4.
5. this is another paragraph
6. that is below the first one
Indeed, when cursor is on line 4, line("'{") returns 1, and line("'}") returns 6, when I'd want it to be something like either 1/2 or 5/6
I am reluctant to make the cursor move in order to get the wanted results, as those operations will be executed every time the user changes paragraph and moving cursor around is a bit slow.
If anyone knows a way to consistently get the lines numbers of the current paragraph start and end, I'd be glad to hear it!
Hope my question was clear enough!

The definition of paragraphs is mostly based on empty lines, though :help paragraph also mentions some (rather obscure and inherited from vi) nroff macros that can define paragraphs.
If you don't care about the obscure parts, and just base your definition on empty lines, you can use a :while loop together with empty(getline(lnum)) to check for empty lines and thereby detect paragraphs yourself. This explicit iteration completely avoids cursor moves, but could be slow if there are very large paragraphs (spanning hundreds of lines).
Your current approach only breaks down if the cursor currently is between paragraphs. You could explicitly check for that (again ignoring the obscure parts), and only then perform a jump, e.g. via normal! {.
The easiest (and only one that's fully correct also for the obscure parts) implementation always jumps around. Inside a :function, screen updates only happen on demand (via :redraw). You need to save and restore the current view, so that the user doesn't notice:
let l:save_view = winsaveview()
" Code that jumps around here.
call winrestview(l:save_view)
If you prefix your motions with :noautocmd (or temporarily set :help 'eventignore'), you can avoid that plugin actions (which can be far more costly than Vim's internal cursor moves) are triggered (on the CursorMoved event).
Summary
There are several options; which one is right for you, depends on your typical data and use cases.

Related

Emacs / vim quick copy paste

I'm trying to make a transition to emacs (using evil mode/vim keybindings) and I'm having a hard time feeling more efficient/productive than if I just used the mouse. Here is an example of a situation where I find myself really slow:
for i in range(self.allData.shape[0]):
self.correctSequence = self.displayNumbers(i, self.allData)
self.userSequence = self.numberEntry()
self.allData.set_value(i, 'userSequence', ''.join(self.userSequence))
if len(self.correctSequence) != len(self.userSequence):
self.allData.set_value(i, 'correct', 0)
else:
if list(reversed(self.correctSequence)) == self.userSequence:
self.allData.set_value(i, 'correct', 1)
else:
self.allData.set_value(i, 'correct', 0)
It would be very common for me to have to change the first 4 instances of self.allData to something else (self.testData, for example), leaving the last 2 untouched.
Normally this wouldnt be too bad with a mouse. For example, I could replace the first allData with testData, copy it, use the mouse to the next 3 occurences and just hit CTRL-V for each one. Or better yet, just use multiple cursors in sublime/atom and replace all 4 in one go
I use spacesmacs in emacs with vim keybindings. So, in emacs I find myself having to do something like the following:
SPC-SPC a (avy jump to words beginning with a)
cw testData
Repeat those 2 steps once for each word I want to replace
This seems really inefficient and I'm wondering: am I just using an inefficient method? Is there a faster way to do what I want?
It seems that even if I managed to complete those steps really fast (4 times), theres still A LOT more typing one would have to do, and I fail to see how this would be faster than just reaching for the mouse. Yes, one could make the argument that I'm losing time by constantly reaching for the mouse, but in my mind I'm saving typing time by reaching for the mouse because I can just hit CTRL-V a few times to achieve what I want. Where exactly are the vim speed gains in a situation like this?
If you just want to replace, you can use query-replace, and replace the word one by one.
You can use replace-string too, but remember to limit replacement to part of the buffer, activate the region around that part.
Anyway, these commands could prevent you from finding the word by your eyes, moving cursor by mouse and moving your hand back to keybaord. And they could avoid probable overlook too. At least I don't want to leave my hands from the keyboard when typing. :)
I'm not sure how "vim-like" Spacemacs is, but you could do it like this in Vim:
/all<CR>
cgntest<Esc>
.
.
.
or:
/all<CR>
cetestData<Esc>
n.
n.
n.
or:
:,$s/allD/testD/gc<CR>
Maybe one of these methods works in Spacemacs too?
In addition to the usual (and generally the best) answer, query-replace (see #songyuanyao's answer), you can use the secondary selection to advantage to selectively paste the same thing at various places. Unlike the region, the secondary selection is unrelated to the cursor position (aka point), so it is always available regardless of where the cursor is.
And unlike query-replacing, you can paste it on demand, instead of having to answer for each matching occurrence. If you use delete-selection mode then just select some text to replace and paste the secondary selection to replace it.
You can set and paste the secondary selection using the mouse - see Secondary Selection on the Emacs Wiki, and see the Emacs manual, node Secondary Selection.
If you use library second-sel.el then you can use the secondary selection from the keyboard as well, and get a lot more use out of it.

Toward Vim moves from conventional moves (<left> <right> <up> <down> <backspace>)

I am not trying to play golf with my editor. I am just trying to improve my editing skills with vim.
Let's consider this piece of assembly that I would like to convert to C. In order to do it methodically, I want to make small changes iteratively line after line.
dm(__abcd_bar_id + axis) = f4;
f1 = dm(_abcd_foo_id + axis);
f5 = f4 - f1;
The job with this example is:
Simplify the first line with abcd_bar_id[axis] = f4
Simplify the second line with f1 = abcd_foo_id[axis]
Replace f1 in the third line with the second line
Remove the second line
These steps are not negotiable. I know I can easily get rid of all my dm(__variable + index) with a regex like the one below but this is off topic.
:%s/dm\s*(\s*_\+\(\w\+\)\s\++\s\+\(\w\+\)\s*)/\1[\2]/g
So, to achieve these changes I traditionally do this:
▶▶▶▶DelDelDelDelDel▶▶▶▶▶▶▶▶▶▶▶▶[DelDelDel▶▶▶▶Right]
▼DeleteDelDel[▶▶▶▶]Del
Home▶▶▶▶RightDelDelDelDel
Shift+End Shift+◀ Ctrl+c
▼End◀◀BackspaceBackspace Ctrl+v
And the result should be this:
abcd_bar_id[axis] = f4;
f5 = f4 - abcd_foo_id[axis];
What saves me is I am quite fast hitting the same key multiple times. However I am sure I can be more productive if I use vi features
vfahd
wh3lxi[wr]
j:%s/dm(_//Enter
f+hv2lxi[Escwr]
$hvF2ay
jf1hhplxxx
Well, this seems to me much more complicated for my brain because a pre-processing bain-time is needed before each keystrokes.
For instance if I want to move to f1 I need to parse with my eyes if there is no other 1 on the way to f1.
I really feel I need years of training to be 'fluent' with vim.
So the questions are:
How a vim guru will treat this example?
Does a vim guru exist?
I definitely don't consider myself vim guru, although I use it on the daily basis. Answering your second question first, probably there's somebody who can be treated as a guru, there are simply so many options and possibilities in vim, that everybody can have their own way of doing things. Moreover, because you can tailor vim to your needs, it's easy to simplify regular tasks, and those configurations may differ a lot. Also people who are considered gurus by me (like, for instance, Derek Wyatt) claim that have still much to learn about vim, so it can definitely take years to become one.
But don't be discouraged, it takes only some practise to start thinking vim-way, and your editing tasks will become much easier :)
Back to your example. First of all, I'd edit the first line with slightly less keystrokes:
dta
f)r]
bdTd
i[
The difference isn't huge in terms of number of keystrokes, but it illustrates different approach. It allows, in my opinion, much less pre-processing, which is the problem you highlighted. I divided those keystrokes into sections to show you my thought process:
delete till a
find ) and replace it with ]
back one word and delete Till (backwards) d
insert [
I don't have to think much, when I apply those changes. You might think that this is counter-intuitive, that I jumped to ) character first, but it was much easier for me to spot closing bracket than count words or
hit h or l multiple times. Of course you might know the keystrokes but when you edit something you don't always remember all of them. This comes with practise and forcing yourself to use some of them (like t/T)
to put them firmly under your fingers. Also, print a cheat-sheet trying to make use of every key, until you'll learn it by heart. It won't take long ;)
As William already suggested in the comment, I'd also think about macro here. It's a powerful and easy-to-use tool, which can really automate your changes.
I already know how to edit first line. In your example, I know that in the second step I'll be doing the same thing, but in slightly different location, so instead of editing first line, I instantly record a macro, but I have to make it universal
for easier application. So I think about putting my cursor in proper location first, before making any changes. My macro would look like this:
qq
0fd dta f)r] bdTd i[
q
Notice, that I added 3 keystrokes at the beginning (not counting qq, which starts recording macro to q register). That might look redundant in the first line, but it ensures proper location of the cursor before making any changes.
That way I can easily apply this macro in the second line with #q
Now, you have to replace this f1 in the third line. You're still in the second line with your cursor, so you just yank with:
0fay$
and then paste it to the third line:
j$bPlD
Using macros mith look like a redundant thing when you edit just 3 lines, but when you get used to making changes in a vim way, you'll really feel you're taking advantage of it's power.
When it comes to remembering recorded macros it's not that hard, you have to have the proper attitude. First of all, you record your macros to registers, so typing :registers will show you also your macros. Secondly, you can edit them,
by pasting specific register, altering it and then saving to the same register. And then you can play it with #[register_letter]. And finally, don't get attached to specific macros. Save one or two, use them to make multiple changes at
once and forget about them. And then record another one under the same letter. For example, if you realize that you have to make some repetitive change across the file, use qq, because it's fast and intuitive. After making changes you rarely
need to play the same macro over again, because whole buffer is already in the right state. But if you know, that you'll need it, record next macro under another letter. If you'll get comfortable making changes intuitively vim way, so that
they can easily be repeted, you'll find that's much easier to record another macro than trying to remember under which letter you recorded previous one.
I hope that this answer will convince you, that you don't need years of training to get fluent, but of course it won't happen overnight ;)

Is there a way to show line numbers at end of the line in Vim

I am using
set relativenumber
set number
which let's me move easily around. However, it is often hard to know the exact the line number of the object where I would like to jump to because I first need to look to the left. I feel it would be easier if I could see the line numbers also on the right hand side right because my eyes have less space to follow (maybe?). I think the ideal setting would be to show the relative/absolute line number where the $ appears when whitespace characters are shown and to the left/right of the buffer. I.e.
1 Random text.$1 1
159 This is the line where the cursor is.$159 159
1 Some random text.$1 1
2 More random text. Another sentence. Maybe a third one? And so on.$2 2
3 Another line which might be quite long and my eyes focus somewhere here.$3 3
4 More random text containing more text and more words and stuff.$4 4
(In this example, I would like to do 3k but I may type 2k or 4k because I did not follow the correct line to the left.)
Is it possible to achieve this somehow?
Any suggestion on how to change my workflow are welcome, too.
Note: Using cursorline does not help as I do not seek the number of the current line.
No, there is no built-in support to your requirement. also I don't think this is easy to be done by plugin.
Maybe you could consider to change your habit/workflow. E.g. enable the cursorline option, to highlight your "current" line, it may let you easier to identify which line are you on right now.
To move cursor, if you don't want to count lines, you may want to try the EasyMotion plugin. It is very handy plugin. However it won't replace the hjkl ... motions.
No, that's not possible, unless you modify Vim's source code in a non-trivial way, or work around with kludges like a vertically split small scratch buffer at the side that is updated via autocmds.
Do you have :set cursorline? That helps (me) a lot to follow the current line, even with large window widths. Reducing those might help, too, though you have to deal with wrapping / scrolling of long lines then.

Is there a less fantastically kludgy way to do one-off highlights in Vim?

i. The Problem
My goal is something like the following:
I have a line of text like
Who left the dead mouse in the fridge?
and I want to highlight the first the in green, just this one occurrence. That is, I don't want to syn match ThisMagicWord "\<the\>" or anything that will overzealously highlight other thes.
There is one other requirement, which is that if the user edits the other text on the line, say to
Who on earth left the delicious dead mouse in the fridge?
the highlighting will track with the word the, so long as the user doesn't edit that one particular word.
ii. The Kludge
Now, I have a solution to this. In fact, I am proud of my solution, because it was tricky to think up. But it is not, by any stretch of the imagination, a good solution.
It turns out that the Unicode character Combining Grapheme Joiner is effectively a no-op in Vim. It produces no glyph, and takes up no width. It is the only such character that I have discovered. So what I do is, I surreptitiously edit the line in question to be
Who left the<CGJ> dead mouse in the fridge?
and then define a rule
syn match ThisMagicWord "the<CGJ>"
I will additionally trigger on BufWritePre and BufWritePost to strip the CGJs out of the file on disk.
iii. The Questions
Is there a no-op character in Vim (or a way to produce one) other than CGJ? Ideally a non-combining character, since the<CGJ> will not match a search for /the, due to the way Vim regexes handle combining characters.
Is there a better way to get at the behavior that I want?
You're right that there's currently no good way to mark static matches and keep them up-to-date when edits are done nearby. My approach would have been worse than your kludge: Include the line / column information in the match (via the \%l and \%v special atoms), and attempting to update those with a combination of marks (works for line changes) and intra-line custom diffing.
Though your use of special Unicode characters is clever, it's (as you admit) a hack. I've asked you for uses in the comments, and am still not completely satisfied / convinced. If you can come up with good, real use cases and current pain points, please direct them to the vim_dev mailing list (best with a functional draft patch attached). The functionality to keep track of such text is basically there (in the Vim internals), it's just not yet tracked and exposed to users / Vimscript. Though Vim development has been (often frustratingly) slow, with a compelling argument on your side, new functionality can and does happen.
How about using marks?
Move the cursor to the word you want, set a lowercase letter mark (e.g. mz), then add highlighting for the word like \%'zthe

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