Multi-line Highlight in Vim - vim

I am currently writing a plugin in Vim that needs to highlight arbitrary lines in a file
at the same time.
My approach so far has been implementing match with the line number to highlight it, but the problem is that I would need to add | for every other line in a file and append that information and then call it every time the window gets redrawn.
There is another problem with match in my case, and that is that a line that may not have any whitespace would not look highlighted (match only highlights existing text/whitespace).
So even if I had match rewrite the window and highlighting all the lines I need, from a user's perspective this wouldn't be to useful if the highlighting doesn't show anything if there is no whitespace/text.
Can I get any suggestions in how to effectively show/display/highlight (I'm open to different implementations to solve my problem) arbitrary lines in a file at the same time regardless of amount of text or whitespace?
Edit: My main request is to be able to highlight lines by line number not by regex
matching. So any solution should need to be flexible enough to accept a Line number to match.
Edit: signs is the answer to my problem, and I found this tutorial the best way to grasp and implement what I needed: http://htmlpreview.github.io/?https://github.com/runpaint/vim-recipes/blob/master/text/07_navigation/12_bookmarking_lines_with_visible_markers.html

I would use region rather than match. Here is part of my manuscript syntax file that highlights speech:
:syntax region msSpeech start=/"/ end=/"\|\n\n/
:highlight msSpeech guifg=#000088
It starts with a double quote and ends with another double quote or the end of the paragraph. It will highlight multiple lines if need be.

Related

Highlight empty lines at beginning and end of file and more than one empty lines

In vim, I would like to highlight empty lines at beginning and end of file, and more than one consecutive line. Example:
--- start of file
.
an empty line just before this line (at the beginning of the file)
more than one empty line will follow
.
.
empty lines at the end of file will follow
.
.
--- end of file
In the example above, the lines with a dot should be highlighted.
I've tried to match the lines with the following expression, unfortunately without luck:
call matchadd('EmptyLines', '\n\s\*\n\s\*\n')
How can I match all of these lines and highlight them (preferably the whole line)?
The special regular expression atoms \%^ (:help start-of-file) and \%$ (:help end-of-file) will help here. With them, you can match empty lines at the boundaries of the buffer, like this:
call matchadd('EmptyLines', '\%^\n\+')
call matchadd('EmptyLines', '^\n\+\%$')
Unfortunately, there are some limitations:
You can only match what's there, which is not much in empty lines. Vim will just highlight a single cell width (that represents the newline character).
In the very last line, nothing is highlighted at all. If you want to see any indication of a single empty final line, you could drop the ^ from the pattern. Then, the empty trailing line would be indicated by highlighting before that line.
Implementation alternatives
Using :help signs, you can highlight the full width of empty lines, and have an additional indication in the sign column. The downside is that you can't simply define a pattern for signs. You have to explicitly place them on certain lines, and adapt this position whenever the buffer contents change. That would mean defining some :autocmds, and living with either poor performance or accepting short delays until the signs update. (They are meant to be used for things like marking build errors that don't change so often and only on demand.)
Instead of a visual indication, if your goal is to avoid having those empty lines, you could also hook into the BufWrite event and either print a warning or completely abort the :write if such lines are found. My DeleteTrailingWhitespace plugin does this (but for whitespace at the end of individual lines).

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.

How to compare long lines with vimdif?

I compare two version of Latex file, using vimdiff.
Lines in my file may contain as much as 30 sentences. The difference between the sentences are mostly small, like a typo, a word added or removed, word order reversed.
If a line differs between the two files, vimdiff marks the first word that differs plus the whole rest of the line in red in both files; this is too much, and additionally, makes it hard to spot differences, if present, in the marked text.
What can I do to spot these differences easier?
Is there a way to let vim diff compare files sentence by sentence instead of line by line?
Or is it possible to let vim diff mark only the words that differ within a line?
There's a new plugin, diffchar.vim - Highlight the difference, character by character, which apparently provides this (haven't tried it yet). In general, diffing is line-based, so any content that does not have great granularity on a line level is problematic.
A workaround would be to temporarily modify both buffers (without persisting) to introduce more line breaks, and then :diffupdate. Based on your follow-up question, you seem to be thinking along the same lines.

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