I would like to run an external program on a regex highlight to determine the face of the match but could not figure out how to do it. For instance if the file contains dates in a certain format, I would like to run an external command with date +%u $date
to determine the day of the week and highlight each of them with different colors.
You should be able to do fine with shell expansion. For example:
:add-highlighter -override buffer/date-highlight regex %sh{date +%u date_value} 0:red
The override option is there so that you can invoke this command again to update which dates are highlighted. For multiple, different highlights you’d give them different name.
The date_value
placeholder can either be manually written or you could define a kakoune option where you set it’s value, then you could access it with shell variable $kak_opt_optionName
.
Sorry I did not explain clearly the problem I tried to solve. If a text file contains dates
in the following format:
2024-01-01
2024-01-02
I would like to match them with a regex and then run an external command on each of these matches.
date +%u -d 2024-01-01
date +%u -d 2024-01-02
to determine the day of the week from 1 (Monday) to 7 (Sunday) for each date. Then I would
like to use a different color for each day using a list defining 7 colors (red, green, yellow, …). This could be done with a shell script but I do not know how to interface the regex match in the highlighter with an external command in this way.
At a very high level, what you’ll need to do is:
- create seven “faces” (see
:set-face
and:doc faces
), one for each day of the week, to describe how a date representing that day should be displayed - create a
range-specs
option (see:declare-option
and:doc options types
), which will associate portions of the buffer with one of those faces - add a
ranges
highlighter (see:add-highlighter
and:doc highlighters specs-highlighters
) that tells Kakoune to interpret the payload of each item in therange-specs
option as a face to be applied to the text in the given range - use a
NormalIdle
hook (or similar) to invoke your code after each time the buffer is modified - in that hook:
- initialise the option to an empty value
- select all the dates with a regex (probably using
:execute-keys
to do a%s...
operation) - for each selection (see
:evaluate-commands -itersel
), add an item to the option (:set-option -add
) that uses the range of the current selection (%val{selection_desc}
) and runs thedate
command on the contents of the selection (%sh{ date +%u -d $kak_selection }
)
That’s kind of expensive, because it involves shelling out for every regex match. It might be possible to do something more efficient handling all of the dates at once, but it would also be more complex.
Excellent! Thank you very much.