I would like to change the way headings render while still using the * to type headings (so this question is distinct from Change the asterisk (heading identifier) to some other symbol in Org mode)

I want this

* One
** Two
*** Three

to render as

# One
## Two
### Three

The closest I can get is by using org-bullets and changing the org-bullets-bullet-list symbols, but that conceals the initial symbols with spaces:

# One
 # Two
  # Three

Preferably, I would not need to use use the org-bullets package and just use a regex to replace the font face of the headings symbols. I found this snippet for changing - and * in plain lists to a .

  (font-lock-add-keywords 'org-mode
    '(("^ +\\([-*]\\) "
    (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))

When I try to modify it for headings it does not change the appearance of the headings and does not throw any error (maybe there is some later applied highlighting in org-mode that overwrites the regex substitution? or because I am just using a single # to replace possibly more than one *?).

  (font-lock-add-keywords 'org-mode
    '(("^*+ "
    (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "#"))))))

I am using Emacs through the Spacemacs distribution.


compose-region does not solve your problem. Use the text property display instead and put the string you like atop the header leader. You can let you guide by org-bullets-mode for that.

If you want to try that approach copy the following lines into your init file and re-start emacs.

Activate org-bullet-mode for replacing * with # in header leaders.

(defcustom org-bullet ?\#
  "Replacement for * as header prefixes."
  :type 'characterp
  :group 'org)

(define-minor-mode org-bullet-mode
    "Bullet for org-mode"
  nil nil nil
  (let* ((keyword
           `(("^\\*+ "
              (0 (let* ((level (- (match-end 0) (match-beginning 0) 1)))
           (when (> level 1)
             (put-text-property (match-beginning 0) (- (match-end 0) 2) 'display (make-string (1- level) org-bullet)))
           (put-text-property (- (match-end 0) 2) (- (match-end 0) 1) 'display (string org-bullet))
    (if org-bullet-mode
          (font-lock-add-keywords nil keyword)
        (goto-char (point-min))
        (font-lock-remove-keywords nil keyword)

You can activate org-bullet-mode automatically when starting org-mode with the following entry in your init file:

(add-hook 'org-mode-hook #'org-bullet-mode)
| improve this answer | |
  • Great, thanks! The reason I mentioned that i prefer not to use org-bullets is because I prefer to display all heading symbols when I narrow to subtree and deindent (so it doesn't look like the heading is indented from the left margin). I can use org-hide-leadings-stars for this, but didn't find a way to do use it with org-bullets, do you know of one? – joelostblom Feb 15 '18 at 14:59
  • @JoelOstblom org-bullet-mode from my answer displays all heading symbols, i.e., ** is replaced by ## and so on. That is what make-string does. – Tobias Feb 15 '18 at 15:03
  • For me, all * are replaced with # (for all heading levels), but only the last heading symbol is displayed, the rest are hidden unless the cursor is over them. This is the default behavior for org-bullets on my spacemacs installation, so there is some other setting I need to tweak I think to get the same behavior as when disabling org-hide-leading-stars when not using org-bullets. – joelostblom Feb 15 '18 at 15:17
  • @JoelOstblom Once again. Have you really tried the code of my answer? That is not the code of org-bullets! The code above is everything you need you don't need org-bullets. You can paste the above code into your init file and are done. Add also (add-hook 'org-mode-hook #'org-bullet-mode) if you want to use org-bullet-mode the code whenever your buffer is in org-mode. Maybe, the name difference between org-bullets-mode and org-bullet-mode is far too small to be easily recognized. Sorry about that. – Tobias Feb 15 '18 at 15:20
  • Agh! Sorry, I tried your code but didn't restart emacs (I missed your edit). And yes, I misread org-bullet-mode as org-bullets-mode so I thought that was the reason it was not working. I tried it again now and it works as I want except for when I use org-hide-leading-stars, which now hides all # of the headings instead of hiding all but the last # (the exception being first level headings, where the lone # is displayed). Do you see this as well? Thanks again and sorry for the confusion. – joelostblom Feb 15 '18 at 16:29

Not the most elegant approach, but this appears to work

  (font-lock-add-keywords 'org-mode
    (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "#"))))))

  (font-lock-add-keywords 'org-mode
    (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "#"))))))

  (font-lock-add-keywords 'org-mode
    (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "#"))))))

  (font-lock-add-keywords 'org-mode
    (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "#"))))))

The above snippet would change * at headings level 1-4 into # and can be extended to as many levels as needed.

| improve this answer | |

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.