I'm trying to apply highlighting to all regular expression matches only on the cursor's line. This code is close but I have to redraw the screen with every time the cursor moves, and it makes the cursor a part of the regex which is not ideal.
~/.vim/syntax/abc.vim:
syn match abcline "abc\%#"
hi def link abcline Todo
Your approach with the special \%# is correct. Unfortunately, its :help explicitly warns about the necessary redraw (which isn't done automatically for performance reasons).
\%# Matches with the cursor position.
WARNING: When the cursor is moved after the pattern was used, the
result becomes invalid. Vim doesn't automatically update the matches.
This is especially relevant for syntax highlighting and 'hlsearch'.
In other words: When the cursor moves the display isn't updated for
this change. An update is done for lines which are changed (the whole
line is updated) or when using the |CTRL-L| command (the whole screen
is updated).
So, you need an :autocmd CursorMoved,CursorMovedI to trigger a redraw. Alternatively, you could embed the current line number into the regular expression (\%23l), and update the syntax definition as the cursor moves around (again via :autocmd). I'm no fan of such frequent redraws; perhaps your use case would also allow to just trigger the highlighting on demand (via a mapping), or only updates when the uses pauses (CursorHold[I] events).
Doing syntax highlighting only for the current line is unusual; also reconsider whether a global highlighting would work (if you tone down the used highlight group; especially Todo is very visually distracting).
Related
I often need to translate a document in MS Word and I do it paragraph by paragraph, the translation text follows each individual paragraph of the original text. What I need is a keyboard shortcut to move the insertion point to the blank space after the following paragraph I need to translate, i.e to move the cursor from the end of the red colored text in the picture to the blank space after the following paragraph ending with "..and call it a day"
Ctrl+Down Arrow shortcut in Word places the insertion point at the beginning of every following paragraph, while I need it placed at the beginning of the blank line above it so I can immediately start typing.
I am looking for a Word shortcut key, regex expression or an autohotkey script that could perform this task, it would come handy to me in doing translation in MS Word.
Thank you for the help!
On MCL's suggestion I've created a simple Autohotkey script to solve the problem, combining Word keyboard shortcuts into one. I also added a code from another script which sets dark red color of the text which is being typed into the original document to make the contrast with the default text color of the original. This is a convenient option for translators which also allows saving only the translated text by using Find function in Word, and removes the need for any further editing of the translated document. Here's the script:
#IfWinActive ahk_class OpusApp
^2::
Send ^{Down}
Send ^{Down}
Send ^{Left}
Send {Enter}
{
oWord := ComObjActive("Word.Application") ; MS Word object
wdColorDarkRed = 128
oWord.Selection.Font.Color := wdColorDarkRed
}
return
I pose the question because I think both the question and possible answers might help Emacs users who write Lisp code that defines font-lock-keywords. I'm providing one answer that I think helps. I'm also interested in other answers.
That variable's value is a list of expressions, each of which can specify one or more patterns to match or functions to perform matching, and one or more faces for highlighting the matching text. The possibilities for font-lock-keywords values are numerous and complicated. (The doc describing this is the Elisp manual, node Search-based Fontification.)
In most cases the list has more than one element, which means more than one regexp pattern. These can interact in different ways. Some can prevent others from taking effect, or they can alter the effect of others. My library Dired+, for instance, defines font-lock-keywords in Dired mode with 31 entries (regexps), many of which interact.
How to keep all of that straight? How do you debug such a list when you are defining it or modifying it? You might comment out all but one of the list items, to see its effect when alone. And then repeat for another. And then perhaps add a few together, and maybe in different orders. There are various possibilities, I suppose, but just what do you do?
(OK, I know that most Elisp coders do not write super complex font-lock-keywords definitions. But even for simple definitions this can become complicated. And perhaps if this process were easier then users would not unnecessarily limit themselves to only one or two entries.)
You could use my newly released Font Lock Studio. The following is from the readme-file:
font-lock-studio - interactive debugger for Font Lock keywords
Font Lock Studio is an interactive debugger for Font Lock
keywords (Emacs syntax highlighting rules).
Introduction
Font Lock Studio lets you single-step Font Lock keywords --
matchers, highlights, and anchored rules, so that you can see what
happens when a buffer is fontified. You can set breakpoints on or
inside rules and run until one has been hit. When inside a rule,
matches are visualized using a palette of background colors. The
explainer can describe a rule in plain-text english. Tight
integration with Edebug allows you to step into Lisp expressions
that are part of the Font Lock keywords.
When using the debugger, an interface buffer is displayed, it
contains all the keywords and is used for navigation and
visalization of match data.
When Font Lock Studio is started, comments and strings are
pre-colored, as they are part of the earlier syntactic phase
(which isn't supported by Font Lock Studio).
Start the debugger by typing "M-x font-lock-studio RET". Press ?
or see the menu for available commands.
Example
For a buffer using html-mode, the interface buffer looks the
following. Other major modes typically have more and more complex
rules. The arrow on the left indicates the current active location.
A corresponding arrow in the source buffer is placed at the current
search location.
========================
=== Font Lock Studio ===
========================
--------------------------------------------------
=> "<\\([!?][_:[:alpha:]][-_.:[:alnum:]]*\\)"
(1 font-lock-keyword-face)
--------------------------------------------------
"</?\\([_[:alpha:]][-_.[:alnum:]]*\\)\\(?::\\([_:[:alpha:]]
[-_.:[:alnum:]]*\\)\\)?"
(1
(if
(match-end 2)
sgml-namespace-face font-lock-function-name-face))
(2 font-lock-function-name-face nil t)
--------------------------------------------------
"\\(?:^\\|[ \t]\\)\\([_[:alpha:]][-_.[:alnum:]]*\\)\\(?::
\\([_:[:alpha:]][-_.:[:alnum:]]*\\)\\)?=[\"']"
(1
(if
(match-end 2)
sgml-namespace-face font-lock-variable-name-face))
(2 font-lock-variable-name-face nil t)
--------------------------------------------------
"[&%][_:[:alpha:]][-_.:[:alnum:]]*;?"
(0 font-lock-variable-name-face)
--------------------------------------------------
"<\\(b\\(?:ig\\|link\\)\\|cite\\|em\\|h[1-6]\\|rev\\|s\\(?:
mall\\|trong\\)\\|t\\(?:itle\\|t\\)\\|var\\|[bisu]\\)
\\([ \t][^>]*\\)?>\\([^<]+\\)</\\1>"
(3
(cdr
(assoc-string
(match-string 1)
sgml-tag-face-alist t))
prepend)
==================================================
Public state:
Debug on error : YES
Debug on quit : YES
Explain rules : YES
Show compiled code : NO
Press space to single step through all the keywords. "n" will go
the the next keyword, "b" will set a breakpoint, "g" will run to
the end (or to the next breakpoint) and "q" will quit.
Features
Stepping
You can single step into, over, and out of Font Lock
keywords. Anchored rules are fully supported. In addition, you
can run to the end or to the next breakpoint.
Breakpoints
You can set breakpoints on part of the keyword, like the matcher
(e.g. the regexp), a highlight rule, or inside an anchored highlight
rule.
If you want to step or run without stopping on breakpoints, prefix
the command with C-u.
Note that in an anchored rule, you can set a breakpoints either on
the entire rule or on an individual part. In the former case, only
the outer parentheses are highlighted.
Match Data Visualization
After the matcher of a keyword or anchored highlight has been
executed, the match data (whatever the search found) is visualized
using background colors in the source buffer, in the regexp, and
over the corresponding highlight rule or rules. If part of a regexp
or a highlight didn't match, it is not colored, this can for
example happen when the postfix regexp operator ? is used.
Note that an inner match group gets precedence over an outer group.
This can lead to situations where a highlight rule gets a color
that doesn't appear in the regexp or in the source buffer. For
example, the matcher "\(abc\)" will be colored with the color for
match 1, while the higlight rule `(0 a-face)' gets the color for
match 0.
Normalized keywords
The keywords presented in the interface have been normalized. For
example, instead of
("xyz" . font-lock-type-face)
the keyword
("xyz" (0 font-lock-type-face))
is shown. See font-lock-studio-normalize-keywords for details.
Explainer
The explainer echoes a human-readble description of the current
part of the Font Lock keywords. This help you to understand that
all those nil:s and t:s in the rules actually mean.
When using the auto explainer, Font Lock Studio echoes the
explanation after each command.
Edebug -- the Emacs Lisp debugger
Tight integration with Edebug allows you to single-step expressions
embedded in the keywords in the interface buffer, and it allows you
to instrument called functions for debugging in their source file.
Follow mode awareness
The search location in the source buffer is visualized by an
overlay arrow and by updating the point. If the source buffer is
visible in multiple side-by-side windows and Follow mode is
enabled, the search location will be shown in a suitable windows to
minimize scrolling.
To help with this problem, I coded up an Icicles multi-command, icicle-font-lock-keywords. It lets you do things like the following:
Cycle among the separate font-lock-keywords entries (patterns), applying them individually to see the effect of each alone.
Pick individual entries and apply them separately, to see the same thing.
Pick a set of entries and apply it, in the same order the entries appear in font-lock-keywords. You can do this for any number of sets.
Accumulate the effect of multiple sets of entries, in the order you choose them.
Revert, to see the effect of all entries together, i.e., all of font-lock-keywords.
And you can do all of that, in any order, in a single invocation of the command.
M-o is the prefix key for Facemenu and font-locking, so I put this command on key M-o I, when in Icicle mode.
I'm using a CRichEditCtrl to edit a computer language, and on every change to it I'm calling SetSelectionCharFormat on the current line of text (as reported by LineFromChar(-1)) to highlight the syntax. (EG: comments in green, section headings in a bigger font, compilation errors in red, etc.) Note this language doesn't have multi-line features such as a C comment where typing /* on one line makes following lines part of a comment too; for any given character change I only need to change the color of the current line.
It all looks like its working fine.
However there are some weird issues. One is, when multiple lines of text is selected from somewhere else, and pasted. My OnUpdate() is called but is naively assuming that the only line that potentially needs re-formatting is the one returned by LineFromChar(). That suffices when the user is typing character by character, but it means that after receiving a multi-line paste, the program only reformats the last line of the pasted text. How can it know where the start of the insert was?
OnUpdate is called inside the Paste operation.
It should be possible to subclass the RTF control and to intercept the WM_PASTE message. If WM_PASTE is not used internally it might be possible to use EM_PASTESPECIAL. If even tis message isn't sent, you have to interecept the Ctrl+V that causes the paste Operation.
Than you can determine the starting position of the paste operation.
Spy++ might be helpful to determine the message flow in the RTF control.
Say I hava a LaTeX document open in Vim, and I want to highlight every occurence of
{\color{red} ... }
(where the dots are supposed to symbolize some contents), that is, I want to have {\color{red}, } and everything between these highlighted. This I have done with
:syn region WarningMsg start=+{\\color{red}+ end=+}+
but I have the problem that, if I write something like {\color{red} some{thing} important}, then it is only {\color{red} some{thing} which gets highlighted, because Vim of course mathces the first occurrence of }. How can I make this Highlighting rule so that it skips matching curly brackets? Even multiple levels of such.
For clarity it is better to give each syntax region a bespoke name, and then link it to a standard colour group. I have renamed your original region redTeX.
You need to define a second region, innerBrace, defining the braces you want to ignore, and mark this region as transparent. Then redTeX should be marked to contain the transparent region, which it will then ignore.
syn region innerBrace start=+{+ end=+}+ transparent contains=redTeX
syn region redTeX start=+{\\color{red}+ end=+}+ contains=innerBrace
hi link redTeX WarningMsg
Note that in this case there is the added subtlety that redTeX itself matches as an innerBrace. I fixed this by marking innerBrace as containing redTeX.
Hope that makes sense!
There's a completion type that isn't listed in the vim help files (notably: insert.txt), but which I instinctively feel the need for rather often. Let's say I have the words "Awesome" and "SuperCrazyAwesome" in my file. I find an instance of Awesome that should really be SuperCrazyAwesome, so I hop to the beginning of the word, enter insert mode, and then must type "SuperCrazy".
I feel I should be able to type "S", creating "SCrazy", and then simply hit a completion hotkey or two to have it find what's to the left of the cursor ("S"), what's to the right ("Crazy"), regex this against all words in the file ("/S\w*Crazy/"), and provide me with a completion popup menu of choices, or just do the replace if there's only one match.
I'd like to use the actual completion system for this. There exists a "user defined" completion which uses a function, and has a good example in the helps for replacing from a given list. However, I can't seem to track down many particulars that I'd need to make this happen, including:
How do I get a list of all words in the file from a vim function?
Can I list words from all buffers (with filenames), as vim's complete does?
How do I, in insert mode, get the text in the word before/after the cursor?
Can completion replace the entire word, and not just up to the cursor?
I've been at this for a couple of hours now. I keep hitting dead ends, like this one, which introduced me to \%# for matching with the cursor position, which doesn't seem to work for me. For instance, a search for \w*\%# returns only the first character of the word I'm on, regardless of where I'm in it. The \%# doesn't seem to anchor.
Although its not exactly following your desired method in the past I've written https://github.com/mjbrownie/swapit which might perform your task if you are looking for related keywords. It would fall down in this scenario if you have hundreds of matches.
It's mainly useful for 2-10 possible sequenced matches.
You would define a list
:SwapList awesomes Awesome MoreAwesome SuperCrazyAwesome FullyCompletelyAwesome UnbelievablyAwesome
and move through the matches with the incrementor decrementor keys (c+a) (c+x)
There are also a few other cycling type plugins like swap words that I know of on vim.org and github.
The advantage here is you don't have to group words together with regex.
I wrote something like that years ago when working with 3rd party libraries with rather long CamelCasePrefixes in every function different for each component. But it was in Before Git Hub era and I considered it a lost jewel, but search engine says I am not a complete ass and posted it to Vim wiki.
Here it is: http://vim.wikia.com/wiki/Custom_keyword_completion
Just do not ask me what 'MKw' means. No idea.
This will need some adaptation to your needs, as it is looking up only the word up to the cursor, but the idea is there. It works for current buffer only. Iterating through all buffers would be sluggish as it is not creating any index. For those purposes I would go with external grep.