1

Wondering how would one go about applying a face to the agenda header. I tried it with the below code, but it does not apply the face. It does not generate errors, but it won't apply a face. I am quite new to spacemacs and org-mode.

To be precise, this is within a configuration for custom agenda. The relevant line looks like this:

(org-agenda-overriding-header (propertize "Purchases" 'face '(:foreground "yellow")))

I have spent a lot of time searching for an answer online and tried a lot of different things to no avail. As a last resort I am asking for help here.

Thanks a bunch!

0

The face property is overwritten by org after inserting the header. It's using the face org-agenda-structure. There are seven places in "org-agenda.el" that put this face property. Changing this behavior would probably get complicated.

There are two workarounds that work:

1. Change the Face

Not sure if org-agenda-structure only affects the header, but if it does you could change the face:

  • with (set-face-attribute 'org-agenda-structure nil :foreground "red")
  • or in the theme you are using.

2. Put the text property afterwards with an advice

Add an advice around the functions called by org-agenda, get the point before calling the original function, call the original function and then replace the header with the propertized one. With the advice the lexical bound value of org-agenda-overriding-header is available.

(defun my-org-agenda-override-header (orig-fun &rest args)
  "Change the face of the overriden header string if needed.
The propertized header text is taken from `org-agenda-overriding-header'.
The face is only changed if the overriding header is propertized with a face."
  (let ((pt (point))
        (header org-agenda-overriding-header))
    (apply orig-fun args)
    ;; Only replace if there is an overriding header and not an empty string.
    ;; And only if the header text has a face property.
    (when (and header (> (length header) 0)
               (get-text-property 0 'face header))
      (save-excursion
        (goto-char pt)
        ;; Search for the header text.
        (search-forward header)
        (unwind-protect
            (progn
              (read-only-mode -1)
              ;; Replace it with the propertized text.
              (replace-match header))
          (read-only-mode 1))))))

(defun my-org-agenda-override-header-add-advices ()
  "Add advices to make changing work in all agenda commands."
  (interactive)
  (dolist (fun '(org-agenda-list org-todo-list org-search-view org-tags-view))
    (advice-add fun :around #'my-org-agenda-override-header)))

Then run the function to add the advices:

(my-org-agenda-override-header-add-advices)

Test

(let ((org-agenda-custom-commands
      '(("b" "Test"
         ((agenda ""
                  ((org-agenda-span 1)
                   (org-agenda-overriding-header
                    (propertize "Red\ntext with new line" 'face '(:foreground "red")))))
          (todo "JUSTFOR"
                ((org-agenda-overriding-header "Not propertized, uses standard face")))
          (todo "SCREENSHOT"
                ((org-agenda-overriding-header
                  (propertize "Green background" 'face '(:background "green" :foreground "black"))))))))))
  (org-agenda nil "b"))

Result: (had to eval twice to make it not complain about missing key)

enter image description here

Note

It would be simpler to just add an :after advice to org-agenda--insert-overriding-header but was not able to because:

When you advise a macro, keep in mind that macros are expanded when a program is compiled, not when a compiled program is run. All subroutines used by the advice need to be available when the byte compiler expands the macro.

If anyone knows how to do this, please add a comment or a new answer.

  • Thank you so much Hubisan! – Nikdo Sep 5 at 6:19
  • Hubisan, this second answer, using advices, indeed works in an org-agenda-custom-commands. Huge thank you; this will be very helpful and introduced me to many new concepts! – Nikdo Sep 8 at 19:33
  • Hubisan, one more point. Using your test example, or any propertization I tried myself, it appears that some properties for the face just cannot be added. Namely, different font name, font weight and font italic does not seem to work no matter what. Is it possibly that the advice you have added to the function only acts on certain properties of the font? I have thought that perhaps this is due to the fact that some fonts cannot render weight bold or italic slant style...but I have tried few fonts to no avail. Am I missing something ridiculously simple? Thanks – Nikdo Sep 10 at 0:59
  • This works for instance (propertize "Arial big bold italic" 'face '(:family "Arial" :height 120 :weight bold :slant italic)) – Hubisan Sep 10 at 8:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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