10

Given the following modeline configuration:

(setq-default mode-line-format
   (list
    ;; Current buffer name
    "%b "
    ;; Major mode
    "[%m] "
    ;; Modified status
    "[%*] "
    ;; Cursor position
    "Line: %l/%i Column: %c"))

I would like for the last item to appear right-aligned.

ideasman42
  • 8,375
  • 1
  • 28
  • 105
mkaito
  • 741
  • 6
  • 16
  • 1
    Here is a link to a related thread: http://stackoverflow.com/q/16775855/2112489 – lawlist Dec 18 '14 at 16:53
  • 1
    Since you asked for a specific `mode-line-format` this isn't a proper answer, but [`smart-mode-line`](https://github.com/Bruce-Connor/smart-mode-line/) right-aligns the `mode-line-misc-info` by default, and it can right-align the list of minor-modes by setting `sml/mode-width` to `'right`. – Malabarba Dec 18 '14 at 21:51

5 Answers5

13

Like the answer in the comments, you can do this yourself by writing code to return a nicely spaced string.

Here is a simple way that supports only left and right aligned text applied to your specifications.

;; write a function to do the spacing
(defun simple-mode-line-render (left right)
  "Return a string of `window-width' length containing LEFT, and RIGHT
 aligned respectively."
  (let* ((available-width (- (window-width) (length left) 2)))
    (format (format " %%s %%%ds " available-width) left right)))


;; use the function in conjunction with :eval and format-mode-line in your mode-line-format
(setq mode-line-format
      '((:eval (simple-mode-line-render
                ;; left
                (format-mode-line "%b [%m] [%*]")
                ;; right
                (format-mode-line "Line: %l/%i Column: %c")))))

it ends up looking like this: enter image description here

Also note, I used your mode-line-format args as you specified, but I believe your are using %i incorrectly, which prints the byte size of the buffer, not the number of lines. You can use something like (line-number-at-pos (point-max)) to get the number of lines in your buffer.

Jordon Biondo
  • 12,332
  • 2
  • 41
  • 62
  • One addition - you need to use `window-total-width` to calculate also linum and fringes additional paddings. – sandric Jul 16 '16 at 22:59
  • This answer has a bug where there returned mode-line will be evaluated again as a mode-line. Meaning `%` characters will attempt to be formatted twice. Accounted for this in my answer, https://emacs.stackexchange.com/a/37270/2418 -- also use `window-total-width` (thanks!) – ideasman42 Nov 05 '18 at 21:06
  • Resolved the bug in this answer: https://emacs.stackexchange.com/a/37270/2418 – ideasman42 Jun 13 '19 at 10:29
4

To expand on @jordon-biondo's answer and resolve a bug showing %.

This example shows how mode mode line variables can be used with alignment - which took me a while to figure out.

(defun simple-mode-line-render (left right)
  "Return a string of `window-width' length.
Containing LEFT, and RIGHT aligned respectively."
  (let ((available-width
         (- (window-total-width)
            (+ (length (format-mode-line left))
               (length (format-mode-line right))))))
    (append left
            (list (format (format "%%%ds" available-width) ""))
            right)))

(setq-default
 mode-line-format
 '((:eval
    (simple-mode-line-render
     ;; Left.
     (quote ("%e "
             mode-line-buffer-identification
             " %l : %c"
             evil-mode-line-tag
             "[%*]"))
     ;; Right.
     (quote ("%p "
             mode-line-frame-identification
             mode-line-modes
             mode-line-misc-info)))))))

Example output:

init.el 1 : 0 <N> [-] Top -F1 (Emacs-Lisp WK ivy drag AC GitGutter)

ideasman42
  • 8,375
  • 1
  • 28
  • 105
2

Building off of @ideasman42's answer, you can determine the required number of characters to pad the right items by using format-mode-line. For example, you can put the items you want to align to the right in the mode-line-end-spaces variable:

    (setq mode-line-end-spaces
          '(""
            display-time-string
            battery-mode-line-string))

Then create the function to determine the correct padding from this variable:

    (defun my-mode-line/padding ()
      (let ((r-length (length (format-mode-line mode-line-end-spaces))))
        (propertize " "
          'display `(space :align-to (- right ,r-length)))))

The format-mode-line function determines the expected output of mode-line-end-spaces on the mode line. Then the length of that string is subtracted from the right edge of the window.

Then use both in the last lines of your mode line format

    (setq-default mode-line-format
      '("%e "
        "%b "
        "[%m] "
        (:eval (my-mode-line/padding))
        mode-line-end-spaces))
Drew
  • 75,699
  • 9
  • 109
  • 225
1

While it's possible to do 'correct' left/right alignment adding an alternative method because fully evaluating the left and right just for alignment is a bit heavy, when there is a simpler alternative.

If you know you only need a fixed amount of space on the right, you can fill in all but N characters, this works as long as the right size is a fixed length.

String formatting %12s and similar can be used to ensure the string doesn't resize.

(defun mode-line-fill (reserve)
  "Return empty space using FACE and leaving RESERVE space on the right."
  (when
    (and window-system (eq 'right (get-scroll-bar-mode)))
    (setq reserve (- reserve 3)))
  (propertize " "
    'display
    `((space :align-to (- (+ right right-fringe right-margin) ,reserve)))))

(setq-default
  mode-line-format
  (list
    ;; left align
    "%e %b [%*]"
    ;; right align
    (mode-line-fill 18)
    "%6l, %4c, %8p")))

Eg:

CMakeLists.txt [-] 1590, 0, 94%

Note that this only works well if you want to display a few items on the right hand side, as with this example - line/column/percentage. Showing all minor modes for eg wouldn't work well.

ideasman42
  • 8,375
  • 1
  • 28
  • 105
0

This isn't supported out-of-the-box but the smart-mode-line package does support this. You could either use that package, or if it does more than what you want, extract just the bits that implement the feature you are asking for.

tarsius
  • 25,298
  • 4
  • 69
  • 109
  • Since the op did not follow up, I have turned @Malabarba's comment into an answer. This way the question isn't "unanswered" and this package might very well be what other users having the same question would want to use. – tarsius Jan 18 '15 at 11:14
  • That's what I ended up doing, extracting the relevant functionality from `smart-mode-line` and adding it to my dotemacs. It requires me figuring out how much space I want to the right, but it's better than nothing. Unless someone posts a way to get rid of the manual char counting, I won't accept an answer, though. – mkaito Jan 18 '15 at 15:56