seagle0128 / doom-modeline

A fancy and fast mode-line inspired by minimalism design.
https://seagle0128.github.io/doom-modeline/
GNU General Public License v3.0
1.29k stars 159 forks source link

[Feature Request] use builtin right align support for emacs >30 #646

Closed merrickluo closed 1 year ago

merrickluo commented 1 year ago

Is your feature request related to a problem? Please describe.

The right align calculation seems never worked well for me on Linux, see: image

Sometimes even the diagnostic symbol is gone :joy:

Describe the solution you'd like Quote the news file for emacs 30 (current master)

** 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'.

I've hacked it into doom-modeline, and it looks so much better: image

although it has some limitations

Describe alternatives you've considered

Additional context

here is my hacky code:

From 2b10d4a8567276318126ca148431d77c8f2a436d Mon Sep 17 00:00:00 2001
From: Merrick Luo <merrick@luois.me>
Date: Tue, 1 Aug 2023 20:03:48 +0800
Subject: [PATCH] feat: hacky right align for emacs 30

---
 doom-modeline-core.el | 27 +++++++--------------------
 1 file changed, 7 insertions(+), 20 deletions(-)

diff --git a/doom-modeline-core.el b/doom-modeline-core.el
index 8de1d5d..c22111f 100644
--- a/doom-modeline-core.el
+++ b/doom-modeline-core.el
@@ -1078,24 +1078,8 @@ Example:
         (rhs-forms (doom-modeline--prepare-segments rhs)))
     (defalias sym
       (lambda ()
-        (list lhs-forms
-              (propertize
-               " "
-               'face (doom-modeline-face)
-               'display `(space
-                          :align-to
-                          (- (+ right right-fringe right-margin scroll-bar)
-                             ,(let ((rhs-str (format-mode-line (cons "" rhs-forms))))
-                                (if (and (>= emacs-major-version 29)
-                                         (fboundp 'string-pixel-width))
-                                    (/ (string-pixel-width rhs-str)
-                                       (doom-modeline--font-width)
-                                       1.0)
-                                  (* (string-width rhs-str)
-                                     (if (display-graphic-p)
-                                         (/ (doom-modeline--font-width) (frame-char-width) 0.95)
-                                       1.0)))))))
-              rhs-forms))
+        `(,lhs-forms
+          ,rhs-forms))
       (concat "Modeline:\n"
               (format "  %s\n  %s"
                       (prin1-to-string lhs)
@@ -1107,7 +1091,10 @@ Example:
 Throws an error if it doesn't exist."
   (let ((fn (intern-soft (format "doom-modeline-format--%s" key))))
     (when (functionp fn)
-      `(:eval (,fn)))))
+      (let* ((modeline (funcall fn))
+            (lhs (car modeline))
+            (rhs (cdr modeline)))
+        `(,lhs mode-line-format-right-align ,rhs)))))

 (defun doom-modeline-set-modeline (key &optional default)
   "Set the modeline format. Does nothing if the modeline KEY doesn't exist.
@@ -1116,7 +1103,7 @@ If DEFAULT is non-nil, set the default mode-line for all buffers."
     (setf (if default
               (default-value 'mode-line-format)
             mode-line-format)
-          (list "%e" modeline))))
+          modeline)))

 ;;
-- 
2.41.0
merrickluo commented 1 year ago

btw the implementation looks quite similar to the current one doom-modeline use, so maybe we can backport it to emacs 29 too?

(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 (progn
                       (add-face-text-property
                        0 (length rest-str) 'mode-line t rest-str)
                       (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)))))))
seagle0128 commented 1 year ago

I back ported the codes from 30 and tested on 29. Not sure if it's working on other versions, since window-pixel-width is buggy on old versions.

qcfu-bu commented 1 year ago

This update has broken right alignment for the emacs that I am using (28.2). Everything is in the modeline is now left aligned.

seagle0128 commented 1 year ago

@qcfu-bu Please try the latest version.

subego commented 1 year ago

@seagle0128 Use the following code to only use the header-line-format. RHS will not be displayed.

(setq-default header-line-format (setup-custom-doom-modeline))
(setq-default mode-line-format nil)
SCR-20230807-swup

Determine if mode-line-format is nil in order for mode-line-format-right-align to be displayed correctly in both header-line-format and mode-line-format.

(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
                          (if (null mode-line-format)
                              header-line-format
                            mode-line-format))))
         (rest-str (format-mode-line `("" ,@rest)))
         (rest-width (progn
                       (add-face-text-property
                        0 (length rest-str) 'mode-line t rest-str)
                       (doom-modeline-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)))))))
SCR-20230807-tdmb SCR-20230807-tczf
seagle0128 commented 1 year ago

@subego I think it's related tosetup-custom-doom-modeline. It should be reimplemented by mode--line-format-right-align.