reddit / emacs

Modifying text foreground/background colour while font-lock is active

zenophine · 2022-05-17 15:12
I've tried a few combination of lisp commands but I cannot seem to get things working as I would expect: ;; Not expecting these commands to work since font-lock is active (set-text-properties 1 10 '(face (:background "#770202"))) (put-text-property 1 10 'face (list :background "#770202")) ;; These commands do nothing (set-text-properties 1 10 '(font-lock-face (:background"#770202"))) (put-text-property 1 10 'font-lock-face (list :background "#770202")) The only way I could get things to work is by doing this: (setq inhibit-modification-hooks t) (put-text-property 1 10 'face (list :background "#770202")) But from my understanding, this solution will hinder font-lock mode...
ndamee · 2022-05-17 18:32
Use overlays: https://www.gnu.org/software/emacs/manual/html_node/elisp/Overlays.html
zenophine · 2022-05-18 12:29
Seems a little odd to have to use an overlay to simply change the face property of some text though no? Even in the overlay manual page that you linked they recommend using text properties for large scale: >However, due to a different implementation, overlays generally don’t scale well (many operations take a time that is proportional to the number of overlays in the buffer). If you need to affect the visual appearance of many portions in the buffer, we recommend using text properties. This seems like an odd emacs (or font-lock) limitation
ndamee · 2022-05-18 16:28
I just recommended an alternative way for your issue. If you don't use a large number of overlays then it may work for you. I'm not an expert of properties, but AFAIK if you want to put text properties to a region where font-lock also puts properties then font lock will overwrite those, unless you add your own font lock rules to the buffer.
arthurno1 · 2022-05-19 10:37
It is not font lock limitation, it is just that [font-lock uses its own set of text properties](http://gnu.ist.utl.pt/software/emacs/manual/html_node/Font-Lock.html). It just ignores ordinary text properties, so you will have to customize those faces used by font-lock, see the manual. Overlays, as ndamee suggests, might be a fast (and dirty) way to achieve what you want, though probably less efficient computationally.
zenophine · 2022-05-19 12:42
Well, to me this seems like it could be 3 possibilities: 1. I am misunderstanding something about font-lock 2. This is a font-lock limitation 3. This is a font-lock bug `Font-lock` overrides the ability to set the face text property, and the documented way to change the face while `font-lock-mode` is active does not seem work. Looking at the [emacs manual](https://www.gnu.org/software/emacs/manual/html_node/elisp/Special-Properties.html#index-font_002dlock_002dface-_0028text-property_0029), I should be able to achieve the functionality that I desire, simply by setting the `font-lock-face` text property, but this snippet of code seems to have no affect: (set-text-properties 1 10 '(font-lock-face (:background"#770202")))
arthurno1 · 2022-05-19 19:33
I understand the frustration, but I am afraid it would be the case 1. ... which is not strange. Lots of people, me included, are struggling with font-lock, at least if I judge from the volume of questions on font-lock in Emacs on SX. Back to your example, I am not sure why you would like to use range with font-lock? It is more common to define your own face and a keyword and add that to font-lock and let it manage the syntax. However, your example works for me with slight change: I use put-text-property instead of set-text-property, check the docs for the difference. If you try this in *scratch* buffer, with font-lock on, it should work (it works for me): test something (defface my-face `((t (:background "#770202"))) "some color") (put-text-property 1 10 'font-lock-face 'my-face) I can see the background turn into some dark red color. However, since we are changing the color of the background, there are other things in play here. For example, if I move the cursor on the first line with "test something", where the range 1 to 10 is, the current line highlight, which is implemented with an overlay, takes precedence. Overlays take precedence over text properties in Emacs, and the font-lock background is not visible until I move the cursor away from that line. Check if that happens to you when you test. To check that it actually really works, try this in your scratch buffer: (defface another-face `((t (:foreground "#990202"))) "some color") (put-text-property 1 10 'font-lock-face 'another-face) Now the foreground will be more dark-ish red, and it will be visible when the current line is highlighted. I am not sure how font-lock works in details, I don't tinker much with it but there is a precedence in which order things are specified, as well as between syntax-table and font-lock. Check if something else takes precedence over your text properties. You will have to do more research on the subject to sort it out. I am not an expert, maybe someone else can help you more, but definitely check font-lock docs. As a tip, [font-lock-studio](https://github.com/Lindydancer/font-lock-studio) is useful when looking at font-lock properties. Again, instead of font-locking region, if you can get around with simply adding a bunch of keywords and possibly your own faces, you can easily do something like this (try in your scratch buffer, with the same text as before "test something"): (add-hook 'emacs-lisp-mode-hook (lambda () (font-lock-add-keywords 'emacs-lisp-mode '(("something" . 'font-lock-keyword-face))))) If you turn on emacs-lisp-mode in scratch buffer, you will see "something" rendered with the color used for elisp keywords. You can define your own face instead of using pre-defined font-lock-*-face, and font-lock-add-keywords really takes a regex, so you can define more complex syntax rules than simply stating your keyword(s) as I did in the example. Definitely read the docs and do more research on the web. Another tip is to do what ndamee suggests, use overlays. Don't know if it helps you, but hopefully at least it gives you some direction to look at.
zenophine · 2022-05-20 12:20
Thanks for the detailed response. Using keywords doesn't really fit what I am trying to do, since I am just trying to arbitrarily colour the emacs buffer (not based on the content in those regions). Using your code snippet and `what-cursor-position` seems to have revealed one of the mysteries to me: ``` There are text properties here: face font-lock-comment-delimiter-face font-lock-face my-face fontified t ``` Seems like my scratch buffer was using the comment face for the first few lines. Once I removed the semicolons your snippet worked as expected. I guess, it's as you say, I have to figure out precedence ordering, to make font-lock-face the displayed face regardless of what face is associated with that text.
arthurno1 · 2022-05-20 12:24
Ok, great you figured it out. Another thought: if you are coloring the content of your buffer regardless of syntax, then why don't you turn off font-lock?
zenophine · 2022-05-20 18:54
Yes, that would have been the simple solution! Unfortunately, I am just interested in changing the background colours while leaving font-lock to do it's normal syntax highlighting.
arthurno1 · 2022-05-20 19:17
This seems to me like a typical [XY problem](https://xyproblem.info/). What are you trying to do? [Striped background](https://github.com/sabof/stripe-buffer) (via overlays), or maybe [buffer local theme](https://github.com/vic/color-theme-buffer-local) (via face remapping)? Anyway, if nothing of those, still take a look at those projects, it might give you a clue how to achieve what you are looking for. Good luck :). Background colors are most probably controlled by your theme, so you should probably look there first and customize the theme, but that would affect every Emacs buffer, which is good or bad depending on what you are looking for.
zenophine · 2022-05-20 20:44
Well, I am trying to do write an elisp function that would temporarily flash a myriad of colours on a buffer. This is moreso an exercise out of general interest, than one for practical purposes.
arthurno1 · 2022-05-20 21:00
Alright, sounds like a good exercise, since it wasn't as trivial as it might sound.