12

this question actually arises because I like to use non-monospaced fonts, (Sabon, Minion, Garamond, etc.) This cause a problem when use org-indent-mode, since the text under the headlines are now not aligned with the headlines. Example: enter image description here

The font is Georgia. Now,if I change to consolas:

enter image description here

I think the problem is that in non-monospaced fonts, the "space" and the * does not take up the same space. Though I do not know how to solve this. I've searched the internet and couldn't find a tutorial to fine tune the indentation myself. I've tried to read org-indent.el but it's a long shot for me to understand. Help is greatly appreciated!

  • I also like to use proportionally-spaced serif fonts in Emacs and have experienced similar issues. I’ve been thinking that perhaps some tweaks to fontification could help, but I have not yet looked into it thoroughly. – Christian Gagné Jan 16 '15 at 4:15
  • 1
    Sounds like this has nothing to do with Org mode and you are just wondering how to get non-monospaced fonts to be aligned. The answer is that you need to do that using code - you cannot rely on space chars having the same width as other chars, etc. In short, in general you are out of luck. – Drew Jan 16 '15 at 5:44
  • @Drew you may be right "in general". But for this specific issue there is a solution, see my answer. The leading spaces used for indentation by org-indent are not really there, they are just line-prefix properties, so they can be replaced by any other character so long as it is invisible. – deprecated Jan 16 '15 at 6:24
  • @deprecated: I see. Thanks for the correction. BTW, perhaps Org itself could, be default, do what you suggest. Or just use SPC chars but with text (or overlay) property that imposes a face that (by default) has a monospaced font. Maybe an Org enhancement request is in order. ;-) – Drew Jan 16 '15 at 14:41
  • @Drew it's actually very easy to do that with font-lock, isn't it? – Clément Jul 27 '16 at 18:43
9

One solution is to modify org-indent-strings to use stars instead of spaces as the indentation character. This means that the width of the indentation will always be correct, even when using a proportional font. The trick then is to set the foreground color of the indentation to be the same as the background color, so that the stars become invisible.

We can achieve this with the following code, which advises the function org-indent-initialize:

(require 'cl)
(defun org-indent-use-stars-for-strings ()
  "Initialize the indentation strings with stars instead of spaces."
  (setq org-indent-strings (make-vector (1+ org-indent-max) nil))
  (aset org-indent-strings 0 nil)
  (loop for i from 1 to org-indent-max do
    (aset org-indent-strings i
          (org-add-props
          (concat (make-string (1- i) ?*) ; <- THIS IS THE ONLY CHANGE
              (char-to-string org-indent-boundary-char))
          nil 'face 'org-indent))))

(advice-add 'org-indent-initialize :after #'org-indent-use-stars-for-strings)
(set-face-foreground 'org-indent "white")

The result looks like this for me on Mac OS X using emacs -Q and (set-face-font 'default :family "Gill Sans"):

enter image description here

  • Hi @deprecated, thank you very much for providing the answer! This is a silly question but should I place your code in org-indent.el or my init.el? Neither seem to work for me. I am using Emacs 24.4 under windows, - do I need to compile anything or what? Thanks! – Alex Jan 17 '15 at 9:39
  • alright I did ask a stupid question. I need to compile org-indent.el. For future reference: the easiest way would be to change this line: (concat (make-string (1- i) ?\ ) to (concat (make-string (1- i) ?*) in the definition of org-indent-initialize i.e. (defun org-indent-initialize... then use M-x byte-compile-file to compile org-indent.el to org-indent.elc. Then restart emacs. – Alex Jan 17 '15 at 10:23
3

deprecated's answer is very good, but it didn't quite work for me. I'm currently on Emacs 24.4 and org 8.2.4, and advising org-indent-initialize didn't do anything. I had to redefine the function with the changed indent character, and that worked. Maybe when I upgrade to Emacs 24.5 and org 8.3 the advising will work.

But I also had to make a few other adjustments, because I use different size variable-width fonts for different heading levels, which means that a level-1 heading's * is not the same width as a level-2's, and so on.

So I also had to do this:

  1. Set the faces org-hide (used to indent headline lines) and org-indent (used to indent non-headline lines) to make sure they use the same font at the same size.
  2. Set the variable org-indent-boundary-character to * instead of the default (a space). This is the character that is inserted after the indentation characters but before the content. I'm not sure if changing this is a necessity, but it seems to help consistency. It might depend on the font you're using, sizes, etc.

Doing those things in addition to making the change to org-indent-initialize as deprecated provided seems to have done it. I end up with a buffer looking like this:

screenshot

You can see that, as the headline level goes down, the indentation doesn't line up perfectly with the heading text. I think that's because of using smaller fonts for lower-level headings, and I don't think there's an easy way to fix that. It might be possible to do something with text-properties like line-prefix and wrap-prefix, because those can be set to images and special characters, but that would probably be complicated and slow. If you use the same font size for all heading levels, this probably won't be an issue.

Anyway, this is probably good enough. :)

P.S. As requested, here are my org-level faces. These are copied from custom-set-faces, but if you don't use customize you can set them outside of it.

 '(org-level-1 ((t (:inherit variable-pitch :foreground "#cb4b16" :weight bold :height 1.3))))
 '(org-level-2 ((t (:inherit variable-pitch :foreground "#859900" :weight bold :height 1.2))))
 '(org-level-3 ((t (:inherit variable-pitch :foreground "#268bd2" :weight bold :height 1.15))))
 '(org-level-4 ((t (:inherit variable-pitch :foreground "#b58900" :weight bold :height 1.1))))
 '(org-level-5 ((t (:inherit variable-pitch :foreground "#2aa198" :weight bold))))
 '(org-level-6 ((t (:inherit variable-pitch :foreground "#6c71c4" :weight bold))))
 '(org-level-7 ((t (:inherit variable-pitch :foreground "#d33682" :weight bold))))
 '(org-level-8 ((t (:inherit variable-pitch :foreground "#dc322f" :weight bold))))
  • @bluejay I like how this looks. Do you have the complete config to get this posted somewhere? – erikstokes Sep 27 '15 at 0:01
  • Well, I'm using the solarized-dark theme, which is part of the solarized-theme package which you can install from ELPA. As for the org-level-* faces, I'll add them to the answer above. – blujay Sep 27 '15 at 6:59
  • This looks super cool. How do you replace the default * with those special symbols? – Alex Oct 7 '15 at 18:27
  • That's from the org-bullets package. Run package-list-packages and check out all the packages starting with org-. :) – blujay Oct 10 '15 at 2:51
2

Somehow I couldn't get the other answers to work for my setup, but the fastest and easiest fix that worked for me was:

`M-x customize-face org-hide`

Then, just change the Font Family attribute to your monospace font (in my case, Iosevka).

And that's literally all you have to do, since org-indent (face for outline indentation) automatically inherits from org-hide (face used to hide leading stars in headlines)

enter image description here

1

A much simpler solution: in org mode, press M-: and run the following

(font-lock-add-keywords 
 nil 
 '(("^[[:space:]*]+" 0 '(face (:family "Ubuntu Mono")) append))
 'append)

You may need M-x font-lock-fontify-buffer after that. This solution simply forces leading characters (spaces and stars) to use a monospace font.

Also, you'll want to replace "Ubuntu Mono" with a monospace font of your choosing,

  • This is no longer necessary considering the other solutions. :) – blujay Dec 29 '18 at 2:24

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.