116

As a programmer, I want to see a ruler at a specific column (usually 80), both so I see when I cross that column, but also to see how close I am getting to it so I can reformat my code early.

The options I have found so far are all not achieving this goal:

  • whitespace-mode, column-enforce-mode, and column-marker only highlight individual rows after the text in the row has already passed the fill-column. I'd like to see when I am getting close to the column, not just when I cross it.
  • fill-column-indicator would be a good solution, except it breaks auto-complete-mode, company-mode, avy, and more. These are issues that seem hard to fix, each requiring an individual workaround -- e.g., see the company-mode issue and the auto-complete-mode issue, the latter over two years old).

Are there any better alternatives?

Braham Snyder
  • 360
  • 3
  • 9
Jorgen Schäfer
  • 3,959
  • 2
  • 19
  • 19
  • 8
    This is not an answer to your question per se, but a practical solution is to set the width of your window/frame to 80 characters. – Eric Brown Sep 24 '14 at 09:48
  • 2
    Thanks for the suggestion. I think I would prefer having the optional width available when necessary, but it's certainly an option. :-) – Jorgen Schäfer Sep 24 '14 at 10:52
  • 5
    I would add to @EricBrown's suggestion, don't change the actual window width, but rather set the window's right margin so the editing space is 80 characters. (set-window-margins nil 0 (max (- (window-width) 80) 0)) So if you have a 120 character wide window, it'll shrink the space you have to actually display code to 80 characters. This way it won't mess up your window configuration and you can toggle it on an off if you'd like. If you have fringes, there will actually be a line drawn at 80 columns. – Jordon Biondo Sep 24 '14 at 19:06
  • 2
    Here's a gist of the idea: https://gist.github.com/jordonbiondo/aa6d68b680abdb1a5f70 and here it is in action: http://i.imgur.com/dUx4bNz.gif – Jordon Biondo Sep 24 '14 at 19:35
  • @jordon-biondo - this misses update hooks for window resize, see: https://bitbucket.org/snippets/ideasman42/zexMG5 – ideasman42 Feb 07 '19 at 10:37

9 Answers9

58

Note that as of Emacs 27, you should probably use the built-in display-fill-column-indicator-mode, as noted by the newer answer from Basil.

fill-column-indicator is the most mature solution, and if you find overlay-based code with which it conflicts, you can add code to suspend fci-mode while the conflicting code is active. For example, the following code makes it work with auto-complete:

  (defun sanityinc/fci-enabled-p () (symbol-value 'fci-mode))

(defvar sanityinc/fci-mode-suppressed nil) (make-variable-buffer-local 'sanityinc/fci-mode-suppressed)

(defadvice popup-create (before suppress-fci-mode activate) "Suspend fci-mode while popups are visible" (let ((fci-enabled (sanityinc/fci-enabled-p))) (when fci-enabled (setq sanityinc/fci-mode-suppressed fci-enabled) (turn-off-fci-mode))))

(defadvice popup-delete (after restore-fci-mode activate) "Restore fci-mode when all popups have closed" (when (and sanityinc/fci-mode-suppressed (null popup-instances)) (setq sanityinc/fci-mode-suppressed nil) (turn-on-fci-mode)))

sanityinc
  • 2,921
  • 14
  • 17
57

Are there any better alternatives?

Emacs 27 (officially released 2020-08-11) added support for a fill column indicator natively by way of the buffer-local minor mode display-fill-column-indicator-mode and its global counterpart global-display-fill-column-indicator-mode (see (info "(emacs) Minor Modes")).

For example, you can enable it in most programming language modes by adding something like the following to your user-init-file (see (info "(emacs) Hooks")):

(add-hook 'prog-mode-hook #'display-fill-column-indicator-mode)

Here it is in action:

enter image description here

Quoth (info "(emacs) Displaying Boundaries"):

14.15 Displaying Boundaries
===========================

Emacs can display an indication of the ‘fill-column’ position (see Fill Commands). The fill-column indicator is a useful functionality especially in ‘prog-mode’ and its descendants (see Major Modes) to indicate the position of a specific column that has some special meaning for formatting the source code of a program.

To activate the fill-column indication display, use the minor modes ‘M-x display-fill-column-indicator-mode’ and ‘M-x global-display-fill-column-indicator-mode’, which enable the indicator locally or globally, respectively.

Alternatively, you can set the two buffer-local variables ‘display-fill-column-indicator’ and ‘display-fill-column-indicator-character’ to activate the indicator and control the character used for the indication. Note that both variables must be non-‘nil’ for the indication to be displayed. (Turning on the minor mode sets both these variables.)

There are 2 buffer local variables and a face to customize this mode:

‘display-fill-column-indicator-column’ Specifies the column number where the indicator should be set. It can take positive numerical values for the column, or the special value ‘t’, which means that the value of the variable ‘fill-column’ will be used.

 Any other value disables the indicator.  The default value is ‘t’.

‘display-fill-column-indicator-character’ Specifies the character used for the indicator. This character can be any valid character including Unicode ones if the font supports them. The value ‘nil’ disables the indicator. When the mode is enabled through the functions ‘display-fill-column-indicator-mode’ or ‘global-display-fill-column-indicator-mode’, they will use the character specified by this variable, if it is non-‘nil’; otherwise Emacs will use the character ‘U+2502 VERTICAL LINE’, falling back to ‘|’ if ‘U+2502’ cannot be displayed.

‘fill-column-indicator’ Specifies the face used to display the indicator. It inherits its default values from the face ‘shadow’, but without background color. To change the indicator color, you need only set the foreground color of this face.

Basil
  • 12,383
  • 43
  • 69
  • Exactly what I was looking for. Thanks. Also, took as reason for upgrading to Emacs 27.1. – Vasantha Ganesh Sep 30 '20 at 08:00
  • 1
    It'd be nice to provide more specific instructions. Like, add (add-hook 'prog-mode-hook (lambda () (display-fill-column-indicator-mode))) to ~/.emacs to enable it for prog-mode buffers, or (global-display-fill-column-indicator-mode) to enable it globally. It least that's what I came up with after searching around. – x-yuri Jan 19 '21 at 18:59
  • 1
    @x-yuri Done. Note that the lambda isn't needed. I also linked to the sections of the Emacs manual that explain buffer-local and global minor modes, and prog-mode-hook. – Basil Jan 19 '21 at 19:21
  • Is it possible to have 70 column ruler only for the first line? git-commit message forces 70 column for the subject line for the first lines thats why I have urge to ask it. – alper Aug 02 '22 at 11:55
  • @alper No, there is only a single column value per buffer. But there are modes specific to git-commit that fontify the parts of the summary line that exceed 50 (by default) columns. – Basil Aug 02 '22 at 16:21
  • Is it possible to change color of the ruler? – alper Oct 01 '22 at 16:58
  • @alper See the fill-column-indicator face mentioned in the answer. – Basil Oct 01 '22 at 19:34
27

Here is one option which is more robust, it breaks almost nothing (occasionally company-mode being a noteworthy exception), but is not as convenient as fill-column-indicator.

Use header-line-format to mark the 80th column on the header.
Something like the following should suffice:

(setq-default header-line-format 
              (list " " (make-string 79 ?-) "|"))

You should change the number of spaces in that first string depending on the size of your left fringe. But other than that, this should work reasonably well. It's not as convenient as a ruler in the actual buffer, but it helps.

You can also set it to apply only on programming buffers.

(defun prog-mode-header-line ()
  "Setup the `header-line-format' on for buffers."
  (setq header-line-format 
        (list " " (make-string 79 ?-) "|")))

(add-hook 'prog-mode-hook #'prog-mode-header-line)

Result:
You should get something like the following (the first line is not actually in the buffer, but in the header).

-------------------------------------------------------------------------------|
;; This is what your buffer should look like all the way up to column number 80.
(setq some-dummy-variable we-are-all-friends)
Malabarba
  • 23,148
  • 6
  • 79
  • 164
  • 1
    Note that in Emacs 24.3 this will break Company Mode, too, at least in some edge cases. Emacs 24.3 fails to correctly the the header line into account when computing the height of a window. Consequently Company fails to draw proper popups in cases where the height is important, i.e. at the very bottom of the buffer. –  Sep 24 '14 at 10:18
  • 1
    This is a really interesting idea. Too bad I can't mark two answers as correct, the "patch fci" answer has some drawbacks and depending on circumstances, this can be a better choice. Thank you! – Jorgen Schäfer Sep 25 '14 at 20:07
  • 15
    There's also M-x ruler-mode. – sanityinc Nov 02 '14 at 14:32
  • This doesn't draw starting after number's (when line numbers displayed) – ideasman42 Oct 14 '16 at 10:11
22

After much suffering because of various bugs fill-column-indicator introduces, I eliminated it from my config for good.

What I currently use is built-in Emacs functionality to highlight lines that are too long. This even looks better, I wouldn't enable fill-column-indicator now even if it were bug-free.

For a start you may grab my setup:

(setq-default
 whitespace-line-column 80
 whitespace-style       '(face lines-tail))

Then enable it where you want. I use it only in programming context:

(add-hook 'prog-mode-hook #'whitespace-mode)
Mark Karpov
  • 4,943
  • 1
  • 26
  • 54
  • Have you tried your approach with another value for column? With emacs 28.2.1 I can set the value to what I want, but it does not have any effect. It probably should work for you with only the add-hook line which disables the whitespace-mode switching on the default behavior on marking lines longer than 80 columns. – Claudio Mar 17 '23 at 21:55
9

This EmacsWiki page is about Ruler Mode, a minor mode that shows a ruler for columns at the top of a window.

It also shows you the current column and the positions of comment-column, fill-column, goal-column, and the tab stops (as in tab-stop-list).

And this EmacsWiki page is about a ruler that pops up on demand, then disappears.


This other EmacsWiki page has lots of information about different ways to mark a particular column or otherwise let you know when you go past it.

The one I use is Mode Line Position.

But others include showing a vertical line at the column (Column Marker, Fill-Column Indicator) and using whitespace mode to highlight text that goes past the column.

(If you need the line to be far to the right of all text in all rows, you can always turn on picture-mode, but that is probably useful here only as a temporary workaround.)

See also Find Long Lines for ways to find long lines on demand.

Drew
  • 77,472
  • 10
  • 114
  • 243
7

Not exactually what you want, but ruler like @Malabarba♦ will waster space, here is better solution:

There is a built-in package in emacs-goodies-el(recommend to install it in terminal) called highlight-beyond-fill-column.el, add this to your .emacs or init.el:

(setq-default fill-column 80)
(add-hook 'prog-mode-hook 'highlight-beyond-fill-column)
(custom-set-faces '(highlight-beyond-fill-column-face
                    ((t (:foreground "red" )))))

The text beyond fill-column which is 80 in the snippet will be highlighted with the color of red. You can set the face as you like.

CodyChan
  • 2,649
  • 1
  • 21
  • 35
1

Since fill-column-indicator is quite heavy, this solution shows a character to the right of the current line.

So when you're typing you can see the line limit before you exceed it.

This defines the minor-mode hl-line-margin-mode:

;; Global, ensures one active margin for the active buffer.
(defvar hl-line-margin--overlay nil)

(defun hl-line-margin--overlay-clear ()
  "Clear the overlays."
  (when hl-line-margin--overlay
    (delete-overlay hl-line-margin--overlay)
    (setq hl-line-margin--overlay nil)))

(defun hl-line-margin--overlay ()
  "Create the line highlighting overlay."
  ;; Remove in the event of a changed buffer,
  ;; ensures we update for a modified fill-column.
  (when (and hl-line-margin--overlay
             (not (eq (current-buffer)
                      (overlay-buffer hl-line-margin--overlay))))
    (hl-line-margin--overlay-clear))
  (unless hl-line-margin--overlay
    (setq hl-line-margin--overlay (make-overlay 0 0))
    (let ((space `((space :align-to ,fill-column)
                   (space :width 0))))
      (overlay-put hl-line-margin--overlay 'after-string
                   (concat (propertize " " 'display space 'cursor t)
                           (propertize " " 'face '(:inverse-video t))))))
  (let ((eol (line-end-position)))
    (unless (eql eol (overlay-start hl-line-margin--overlay))
      (move-overlay hl-line-margin--overlay eol eol))))

(defun hl-line-margin-mode-enable ()
  "Turn on `hl-line-margin-mode' for the current buffer."
  (add-hook 'post-command-hook #'hl-line-margin--overlay nil t))

(defun hl-line-margin-mode-disable ()
  "Turn off `hl-line-margin-mode' for the current buffer."
  (hl-line-margin--overlay-clear)
  (remove-hook 'post-command-hook #'hl-line-margin--overlay t))

;;;###autoload
(define-minor-mode hl-line-margin-mode
  "Show a character at the fill column of the current line."
  :lighter ""
  (cond (hl-line-margin-mode
         (jit-lock-unregister #'hl-line-margin-mode-enable)
         (hl-line-margin-mode-enable))
        (t
         (jit-lock-unregister #'hl-line-margin-mode-disable)
         (hl-line-margin-mode-disable))))

If you use evil-mode and want to limit this to insert mode you can add the following hooks:

(add-hook 'evil-insert-state-entry-hook #'hl-line-margin-mode-enable)
(add-hook 'evil-insert-state-exit-hook #'hl-line-margin-mode-disable)
Basil
  • 12,383
  • 43
  • 69
ideasman42
  • 8,786
  • 1
  • 32
  • 114
1

In Spacemacs this functionality is easily toggled using SPC t f.

I'm not sure exactly how it is implemented but Spacemacs seems to use the fill-column-indicator package (defined in the .emacs.d/layers/+source-control/git/packages.el file).

Spacemacs also implements company and avy, I'm not sure if the fill-column-indicator breaks anything there.

Anyway for ease of configuration it is worth to take a look at Spacemacs

Stefan
  • 26,404
  • 3
  • 48
  • 85
dalanicolai
  • 7,795
  • 8
  • 24
1

Updated Answer

Since Emacs 27, use display-fill-column-indicator-mode.

In practice, one may utilize it by toggling the mode with a custom keybinding, like shown below:

;; Mnemonics: `b' Buffer, `i' Indicator (of fIll).
(global-set-key (kbd "C-c b i")
                  #'display-fill-column-indicator-mode)

Or enable the mode for particular major-mode, for instance:

(defun my-message-mode ()
  ;; Optional check for earlier Emacs versions.
  (when (fboundp 'display-fill-column-indicator-mode)
    (display-fill-column-indicator-mode 1)))

(add-hook 'message-mode-hook 'my-message-mode)

Or enable it globally (in all buffers) with:

(global-display-fill-column-indicator-mode 1)

Initial Answer

Probably one of the simplest ways that could be enough in many cases, is to use column-number-mode. With this mode enabled, the current column number is shown in the mode line.

This mode does not display a ruler, but provides information that is essentially needed in the first place. Arguably, this prevents a buffer from cluttering.

To enable the mode in your user-init-file, use

(column-number-mode)

Example screenshot with the column number shown in the mode line: Mode line with the column number

Y. E.
  • 767
  • 5
  • 9