5

I'm new to Emacs and Org-mode, this is a very basic question. Unfortunately the keywords are too common for me to find the answer.

I would like to create a custom pattern to colour my writing input.

Something like

_theorem: (it would detect _ and a non-whitespace character for the start, and would trace it until the end, or colon)

_theorem 2: (it would be great if this could also include whitespaces)

_theorem on topic 1: (such as this).

The script would thus automatically color all of the above writing that is now in bold. References that would help me do this would also be helpful. Many thanks for helping a beginner!

Update

I've added a follow-up question in the comments on adding multiple such rules that ran into problems. Here's the full code for it. While the first answer to the first question is working perfectly now, the other two new rules seem to be mistakenly formulated or in conflict somehow. On the instances where either of them is found, it breaks the regular coloring of org-mode and does no coloring itself.

(add-hook 'org-mode-hook
          (lambda ()
                (font-lock-add-keywords nil
                                    '((
                                    "\\(^\\|\\s-+\\)\\(_\\([a-zA-Z0-9]+\\s-?\\)\\{0,4\\}:\\)" 2
                                    font-lock-type-face t)))
                (font-lock-add-keywords nil
                                    '((
                                    "\\(\\w+\\(\\s-&\\s-\\w+\\)?,\\s-[0-9]\\{4\\})" 2
                                    font-lock-type-face t)))
                (font-lock-add-keywords nil
                                    '((
                                    "^\\w+:" 2
                                       font-lock-type-face t)))
))

2 Answers 2

10

You can use font-lock-add-keywords to add custom highlights.

In the below example, I am highlighting any string

  • that begins with _ preceded by a white-space character or beginning of the line
  • followed by a single alpha-numeric character
  • followed by anything else
  • ending with :

The highlight color chosen is font-lock-warning-face; you can choose any other face of your liking.

This highlighting will happen only in org-mode.

(add-hook 'org-mode-hook
          (lambda ()
            (font-lock-add-keywords nil
                                    '(("\\(^\\|\\s-+\\)\\(_[a-zA-Z0-9].*?:\\)" 2
                                       font-lock-warning-face t)))))

Update:

To match at most 4 words before the colon,

(add-hook 'org-mode-hook
          (lambda ()
            (font-lock-add-keywords nil
                                    '(("\\(^\\|\\s-+\\)\\(_\\w+\\(?:\\s-+\\w+\\)\\{0,3\\}\\s-*:\\)" 2
                                       font-lock-warning-face t)))))

Update 2:

Preview of the "max 4 words" regexp in re-builder:

enter image description here

Update 3:

Alright, I can't keep on updating this as your question changes. I would suggest that you spend adequate time understanding the elisp regular expression syntax and how the font-lock-add-keywords function works.

  • Elisp Regular Expression
  • font-lock-add-keywords - Do C-h f font-lock-add-keywords RET in emacs and then click on the font-lock.el hyperlink in the buffer that opens. That will take you to the function definition. Read the doc-string for that function.
  • In a similar fashion, you can learn more about any variable by doing C-h v VARIABLE-NAME RET and jumping through the hyperlinks.
  • Keep on experimenting with re-builder till you get a hang of the regexp syntax.

Below is the solution to your last modified request.

(add-hook 'org-mode-hook
          (lambda ()
            (font-lock-add-keywords
             nil
             '(
               ;; Highlight upto 4 words (including ,) between ( and )
               ("\\(([a-zA-Z0-9,]+\\(?:\\s-+[a-zA-Z0-9,]+\\)\\{0,3\\})\\)" 1 font-lock-type-face)
               ;; Highlight ^word:
               ("^\\([a-zA-Z0-9]+:\\)" 1 font-lock-type-face)
               ;; Highlight upto 4 words between _ and :
               ("\\(^\\|\\s-+\\)\\(_[a-zA-Z0-9]+\\(?:\\s-+[a-zA-Z0-9]+\\)\\{0,3\\}\\s-*:\\)" 2 font-lock-type-face)
               ))))

Alternative Solution, does the same thing as in Update 3

This approach updates font-lock-keywords-alist instead of polluting font-lock-keywords. There is no easy way to fix incorrect regexp added to font-lock-keywords other than restarting emacs.

But usually font-lock-keywords-alist is much smaller in size and can be tweaked manually or can be reset completely by doing

(setq font-lock-keywords-alist nil)

while you are testing out the regexp.

(font-lock-add-keywords
 'org-mode
 '(
   ;; Highlight upto 4 words (including ,) between ( and )
   ("\\(([a-zA-Z0-9,]+\\(?:\\s-+[a-zA-Z0-9,]+\\)\\{0,3\\})\\)" 1 font-lock-type-face)
   ;; Highlight ^word:
   ("^\\([a-zA-Z0-9]+:\\)" 1 font-lock-type-face)
   ;; Highlight upto 4 words between _ and :
   ("\\(^\\|\\s-+\\)\\(_[a-zA-Z0-9]+\\(?:\\s-+[a-zA-Z0-9]+\\)\\{0,3\\}\\s-*:\\)" 2 font-lock-type-face)
   )
 )
13
  • 1
    Brilliant! It does exactly the trick. Is there a good online regex checker for emacs? I tried to alter the expression to a new constraint so as to include maximum 4 words before the colon. However there seem to be some parts of the syntax that I couldn't figure out very quickly with the help of the manual. Thanks again for your help!
    – puslet88
    Feb 13, 2015 at 15:42
  • Check out emacs.stackexchange.com/q/869/115. Also search for terms like regexp and visual in this stackexchange for more examples. Feb 13, 2015 at 15:44
  • Perfect, exactly what I needed, thanks again!
    – puslet88
    Feb 13, 2015 at 15:47
  • You might want to replace the regexp between the double with this: \(^\|\s-+\)\(_\w+\(?:\s-+\w+\)\{0,3\}\s-*:\). Make sure to replace the single back-slashes with double back-slashes when doing so. [Regexp Backslash Reference] Feb 13, 2015 at 16:02
  • Thanks again! Strange, but I couldn't get the single backslashes to work with the built-in RE-builder, best similar case I could do was "\\(^\\|\\s-+\\)\\(_\\w+\\(?:\\s-+\\w+\\)\\{0,3\\}\\s-*:\\)" Not sure if this may have been due to inadequacies of the interface or me. But this feature is great! When I add more hooks of the same type "font-lock-add-keywords", should I create a new "add-hook" or should I add them under the same hook somehow. Any idea what happens if one of the partially includes the other. In case of conflict, perhaps either the first or last one is used? Many thanks again.
    – puslet88
    Feb 13, 2015 at 16:41
1

A while ago, I posted a similar question here: check How to highlight text permanently in org-mode

Not exactly what you are asking for, this gives you more, customize it as you like:

(setq org-emphasis-alist
      '(
        ("*" (:foreground "cyan" :weight bold))
        ("/" (:foreground "cyan" :slant italic))
        ("_" (:foreground "cyan" :underline t))
        ("=" (:foreground "cyan" :weight bold))
        ("~" (:foreground "cyan" :weight bold
                          :box (:line-width 3 :color "#545454" :style released-button)))
        ("+" (:foreground "cyan" :strike-through t))))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.