Syntax Highlighting with Fine Granularity - vim

Is there a way to assign an individual character, as identified by a height and depth index, to a highlight group? Every match feature I have come across uses a regex pattern as input.
The reason I ask is because I am making a syntax coloring plugin that will make text an increasingly lighter shade of gray with increasing parenthesis depth. If vim has no such feature and another algorithm makes character-by-character highlighting unnecessary, please point me to it!

Vim has a whole set of special regular expression atoms that can specify buffer positions.
For lines, \%23l matches only in line 23. You can also use \%>23l for all lines starting from 23, and concatenate two of those with < and > to specify ranges.
For columns, there are the corresponding \%23c and \%23v. The former uses byte indices (what Vim somewhat confusingly calls "columns"), as returned by functions like col() and getpos(), the latter screen widths (from virtcol()).
By combining those atoms, you can select arbitrary blocks of text, and highlight them, e.g. with :call matchadd(...). See :help /\%l for details on the atoms.
For your plugin implementation, you may be able to get some ideas from the vim js context coloring plugin, which highlights JavaScript code according to its scope.

Related

How to make Vim syntax highlight characters exceeding a byte count within a paragraph?

I would like to develop a syntax highlighter that is able to highlight text which exceeds a certain byte count. I've written a regex that can match the too-long text if it is not hard-wrapped:
\(^.*\)\#127<!.\+
Note that the behavior of the negative lookbehind assertion (\#127<!) is to count bytes, which is useful for handling multi-byte characters correctly in contrast to braces (e.g., doing ^.\{127}\zs.\+ instead) which count characters.
What I have been looking for is a modification that will work even if the lines are hard-wrapped and delineated by empty lines (i.e., as paragraphs), but that seems beyond the powers of Vim's syntax match commands. Are text properties perhaps the right way to go instead? If so, how would you implement this with text properties?
I believe something similar to this can do the job:
/\(\_.\)\{127}

Setting a sign to highlight only text instead of whole line in Vim

When defining a :sign you can use the linehl argument to assign a highlight group for the whole line the sign is placed in.
This highlights the whole line until the end, but how I do to highlight only the text of that line?
Edit: The idea is to use Syntastic to show the errors and warnings, but I can't redefine the SyntasticStyleError sign to do what I want. It highlights all the line instead of only the text of that line.
It is not possible as far as I know. Look at the :h sign-define:
:sign define {name} {argument}...
Define a new sign or set attributes for an existing sign.
The {name} can either be a number (all digits) or a name
starting with a non-digit. Leading digits are ignored, thus
"0012", "012" and "12" are considered the same name.
About 120 different signs can be defined.
Accepted arguments:
icon={bitmap}
Define the file name where the bitmap can be found. Should be
a full path. The bitmap should fit in the place of two
characters. This is not checked. If the bitmap is too big it
will cause redraw problems. Only GTK 2 can scale the bitmap
to fit the space available.
toolkit supports ~
GTK 1 pixmap (.xpm)
GTK 2 many
Motif pixmap (.xpm)
Win32 .bmp, .ico, .cur
pixmap (.xpm) |+xpm_w32|
linehl={group}
Highlighting group used for the whole line the sign is placed
in. Most useful is defining a background color.
text={text} *E239*
Define the text that is displayed when there is no icon or the
GUI is not being used. Only printable characters are allowed
and they must occupy one or two display cells.
texthl={group}
Highlighting group used for the text item.
It does not offer you a straight-forward way to distinguish between the text background colour and the background colour of the line - in fact, you can only set the linehl parameter.
Maybe there is a hacky way to do what you want. I've stumbled upon this link you might find useful: https://sunaku.github.io/vim-256color-bce.html
Another interesting idea is explained on vim.wikia.com (link) in the Highlighting that stays after cursor moves section. It suggests using the following command:
:nnoremap <silent> <Leader>l ml:execute 'match Search /\%'.line('.').'l/'<CR>
This way you might mix it with the information you get from :sign place and replace signs with your custom highlighting method I posted above. It requires some scripting though.

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

Multiple matches for syntax highlighting in VIM

I'm writing a syntax file to match a log format (basically column based; think syslog for a similar example), and I'm trying to set up a type of inheritance for columns.
I have two main goals with this.
First, I want to say that column 3 is the "component" field (let's say it's marked by a header; it could also be at a fixed position) and set the background to, say, Grey. I then want to say that component "foo" gets a foreground color of Red, and component "bar" gets a foreground color of Green, but they should inherit the background color of the "component" column. In this case, the field should really have two syntax matches; this also makes it easy to conceal the entire column (a la Toggling the concealed attribute for a syntax highlight in VIM)
Second, there's a field for levels; I want to set the background of the entire line for a critical level message to Red, but the foreground should be continue to be set via the normal highlighting (component, source, etc; I left off most of the other requirements).
From what I can see in the vim documentation, this doesn't seem possible. Am I missing something? Alternatively, can anyone suggest a good workaround?
Thanks
You can't (yet). For each character, Vim only uses one particular highlight group, determined by the last, "most inner" non-transparent syntax group match.
To work around this, you need to define a combined highlight group and corresponding :syntax commands. Some syntaxes (e.g. $VIMRUNTIME/syntax/html.vim, and various Wiki formats) use that for combining bold, italic and underline, but it gets tedious and repetitive after that.
There's a patch proposed that would add a combine modifier for :syntax commands; it's in Bram's Todo list.

Context sensitive word wrap in vi/vim

How can I can specific word wrapping for specific tags. For example, in LaTex I want word wrapping for my paragraphs but not for my figure commands (they are always very long and run off the screen).
Or with Javascript, I want the right margin for code to be at, for example 50 columns, but for the comments to be at only 40 columns
This is not builtin
You could probably script something yourself using a devious combination of `formatexpr` and synID(). I suggest you look at the help of the latter first, because it contains inspirational samples:
for id in synstack(line("."), col("."))
echo synIDattr(id, "name")
endfor
taken from :he synstack
The formatexpr is usually set to something like
:set formatexpr=mylang#Format()
thus delegating to a filetype plugin. You could implement the function to use different margins for different syntax contexts.
Bear in mind
the default formatexpr (if absent, formatprg) are probably no good for a source file (in my experience it has the tendency to string together lines as if they were text paragraphs). But then again, you can implement it any which way you want
that syntax highlighting may become out of sync. I'm not sure what happens when the cursor is at, say, 70% of a large document and you issue ggVGgq. It might not update the syntax highlighting all the way (meaning that your formatexpr function would get the 'wrong' synID() values. You get around this by saying something like
:syntax sync fromstart
this again might impact the highlighting performance depending on the size/complexity of the source and highlighting scripts

Resources