From c296bcc6c42ebb0fbc5078a137bbf6b501b8a44f Mon Sep 17 00:00:00 2001 From: Hugo Heagren Date: Sat, 1 Apr 2023 22:27:25 +0100 Subject: [PATCH] Support right-align in mode-line * lisp/bindings.el (mode-line-right-align-edge): New custom variable, controls where `mode-line-format-right-align' should align to. (mode-line-format-right-align): New function. If the symbol `mode-line-format-right-align' appears in `mode-line-format', then return return a padding string which aligns everything after that symbol to the right. Padding width is altered with the display property and depends on the value of `mode-line-right-align-edge'. (mode-line-format-right-align): New variable. Convenience definition for including right alignment in `mode-line-format'. * doc/lispref/modes.texi (Mode Line Variables): Document new alignment functionality and user option. (Bug#62606) --- doc/lispref/modes.texi | 10 +++++++ etc/NEWS | 6 ++++ lisp/bindings.el | 64 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi index 8ca0afe1bca..b4f69e79155 100644 --- a/doc/lispref/modes.texi +++ b/doc/lispref/modes.texi @@ -2275,6 +2275,16 @@ current buffer is remote. @defvar mode-line-client This variable is used to identify @code{emacsclient} frames. +@end defvar + +@defvar mode-line-format-right-align +Anything following this symbol in @code{mode-line-format} will be +right-aligned. +@end defvar + +@defvar mode-line-right-align-edge +This variable controls exactly @code{mode-line-format-right-align} +aligns content to. @end defvar The following three variables are used in @code{mode-line-modes}: diff --git a/etc/NEWS b/etc/NEWS index e36e77fa97f..50fd1382866 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -92,6 +92,12 @@ plus, minus, check-mark, start, etc. The 'tool-bar-position' frame parameter can be set to 'bottom' on all window systems other than Nextstep. +** Modeline elements can now be right-aligned +Anything following the symbol 'mode-line-format-right-align' in +'mode-line-format' will be right-aligned. Exactly where it is +right-aligned to is controlled by the new user option +'mode-line-right-align-edge'. + * Editing Changes in Emacs 30.1 diff --git a/lisp/bindings.el b/lisp/bindings.el index c77b64c05da..f1a75b080be 100644 --- a/lisp/bindings.el +++ b/lisp/bindings.el @@ -304,6 +304,70 @@ Normally nil in most modes, since there is no process to display.") ;;;###autoload (put 'mode-line-process 'risky-local-variable t) +(defcustom mode-line-right-align-edge 'window + "Where function `mode-line-format-right-align' should align to. +Internally, that function uses `:align-to' in a display property, +so aligns to the left edge of the given area. See info node +`(elisp)Pixel Specification'. + +Must be set to a symbol. Acceptable values are: +- `window': align to extreme right of window, regardless of margins + or fringes +- `right-fringe': align to right-fringe +- `right-margin': align to right-margin" + :type '(choice (const right-margin) + (const right-fringe) + (const window)) + :group 'mode-line + :version "30.1") + +(defun mode--line-format-right-align () + "Right-align all following mode-line constructs. + +When the symbol `mode-line-format-right-align' appears in +`mode-line-format', return a string of one space, with a display +property to make it appear long enough to align anything after +that symbol to the right of the rendered mode line. Exactly how +far to the right is controlled by `mode-line-right-align-edge'. + +It is important that the symbol `mode-line-format-right-align' be +included in `mode-line-format' (and not another similar construct +such as `(:eval (mode-line-format-right-align)'). This is because +the symbol `mode-line-format-right-align' is processed by +`format-mode-line' as a variable." + (let* ((rest (cdr (memq 'mode-line-format-right-align + mode-line-format))) + (rest-str (format-mode-line `("" ,@rest))) + (rest-width (string-pixel-width rest-str))) + (propertize " " 'display + ;; The `right' spec doesn't work on TTY frames + ;; when windows are split horizontally (bug#59620) + (if (and (display-graphic-p) + (not (eq mode-line-right-align-edge 'window))) + `(space :align-to (- ,mode-line-right-align-edge + (,rest-width))) + `(space :align-to (,(- (window-pixel-width) + (window-scroll-bar-width) + (window-right-divider-width) + (* (or (cdr (window-margins)) 1) + (frame-char-width)) + ;; Manually account for value of + ;; `mode-line-right-align-edge' even + ;; when display is non-graphical + (pcase mode-line-right-align-edge + ('right-margin + (or (cdr (window-margins)) 0)) + ('right-fringe + ;; what here? + (or (cadr (window-fringes)) 0)) + (_ 0)) + rest-width))))))) + +(defvar mode-line-format-right-align '(:eval (mode--line-format-right-align)) + "Mode line construct to right align all following constructs.") +;;;###autoload +(put 'mode-line-format-right-align 'risky-local-variable t) + (defun bindings--define-key (map key item) "Define KEY in keymap MAP according to ITEM from a menu. This is like `define-key', but it takes the definition from the -- 2.39.2