Subject: Re: bug#62606: [PATCH] function to align mode-line elements to right

From: [email-masked]
Date: Sun, 02 Jul 2023 13:43:21 +0100

> This will need suitable additions to NEWS

New patch attached with addition to NEWS (and a version tag for the
defcustom, which I forgot last time). I haven't marked the news item
with +++ or ---, wasn't sure whether I've done everything I need to yet.

> and the manual

I've added documentation to the 'Mode Line Variables' section of the
Elisp manual. This seemed to be where similar things were documented.
Updated my commit message to reflect this.

>> I'v already assinged copyright -- I've contributed to Emacs before.
> Yes, I see it now, sorry. (I didn't find it before because your name
> appears in the list of assignment with a typo. Should be fixed soon.)

Do I need to update my AUTHORs entry with this new change?

Hope that's all good.

Hugo

From ce5f8b86a56eb51f4c320a86de0c0444c9f052ce Mon Sep 17 00:00:00 2001
From: Hugo Heagren <[email-masked]>
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.
---
 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 @@ Mode Line Variables
 
 @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 3061a147b26..352c69f1cb1 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -87,6 +87,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 @@ mode-line-process
 ;;;###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.20.1