(Emacs/elisp|config)+new package that generates a mode-line

Using left, centre and right segments generates a mode line with
padded strings that actually achieves this.
This commit is contained in:
2024-06-30 01:15:07 +01:00
parent 9d327e4f70
commit 12b62f7cea
2 changed files with 135 additions and 81 deletions

View File

@@ -293,93 +293,58 @@ the borders for Emacs.
(fringe-mode 0)) (fringe-mode 0))
#+end_src #+end_src
** Mode line ** Mode line
The mode line is a little bar at the bottom of the buffer, just above The mode line is the little bar at the bottom of the buffer, just
the minibuffer (where you do completions). It can store quite above the minibuffer (where you do completions). It can store quite
literally anything, but generally stuff like the buffer name, file literally anything, but generally stuff like the buffer name, file
type, column and line info, etc is put there. type, column and line info, etc is put there.
The default mode-line is just... disgusting. It displays information The default mode-line is just... disgusting. It displays information
in an unintelligible format that you just have to learn and seems to in an unintelligible format and seems to smash together a bunch of
smash together a bunch of information without much care for ordering. information without much care for ordering. Most heartbreaking is
Most heartbreaking is that any mode can just insert new information that any mode can just insert new information onto the mode-line
onto the mode-line without any purview, which can be really annoying. without any purview, which can be really annoying. It's also very
It's also very overstimulating. overstimulating.
Here I define a "nicer" (imo) mode-line-format which contains just the I've got a custom Emacs lisp package
information I need to know what that buffer does. It also looks a bit ([[file:elisp/better-mode-line.el][here]]) which sets up the default
more aesthetically pleasing from being centred along the window. mode line as a set of 3 segments: left, centre and right. It pads out
the mode line to achieve this.
*** A better evil state tag
[[*Evil][Evil]], defined later, has a mode-line-tag for
mode-line-format. It's not awful but not exactly amazing either. So
I'm defining a little function which makes the tag for me
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defun +mode-line/evil-state () (use-package better-mode-line
"Returns either the empty string if no evil-state is defined or :load-path "elisp/"
the first character of the evil state capitalised" :demand t
(with-eval-after-load "evil" :init
(if (bound-and-true-p evil-state) (setq +better-mode-line/left-segment ;; LEFT SEGMENT
(upcase '("%l:%c" ;; Line and column count
(substring " "
(format "%s" "%p" ;; Percentage into buffer
evil-state) ("[" ;; Evil state
0 1)) (:eval
""))) (+better-mode-line/evil-state))
#+end_src "]"))
*** +mode-line/format +better-mode-line/centre-segment ;; CENTRE SEGMENT
Here I declare a new variable ~+mode-line/format~ which contains the '("%+" ;; Buffer state (changed or not)
usual contents for ~mode-line-format~. Looking at the "%b" ;; Buffer name
[[info:elisp#Mode Line Top][info page]] for the mode-line, it's ("(" ;; Major mode
essentially a list of either format strings (specially defined by (:eval (format "%s" major-mode))
mode-line), variables or special forms. The only special form I use ")")
here is ~:eval~ which evaluates the following expression every time " "
the mode-line is constructed. "%I" ;; Buffer size (in bytes)
#+begin_src emacs-lisp )
(defvar +mode-line/format +better-mode-line/right-segment ;; RIGHT SEGMENT
'("%l:%c " ;; Line and column '((:eval (if (project-current) ;; Name of current project (if any)
"%p" ;; %into file (project-name
("[" ;; evil state (project-current))))
(:eval (+mode-line/evil-state)) (vc-mode vc-mode) ;; Git branch (if any)
"] ") " "
"%+" ;; Buffer state (changed or not) (:eval ;; LSP information
"%b" ;; Buffer name (with-eval-after-load "eglot"
("(" ;; Major mode (if eglot--managed-mode
(:eval (format "%s" major-mode)) (eglot--mode-line-format))))
") ") mode-line-misc-info ;; Any other information
"%I " ;; Buffer size (in bytes) ))
(:eval (if (project-current) ;; Name of current project (if any) :config
(project-name (+better-mode-line/setup-mode-line))
(project-current))))
(vc-mode vc-mode) ;; Git branch (if any)
" "
(:eval ;; LSP information
(with-eval-after-load "eglot"
(if eglot--managed-mode
(eglot--mode-line-format))))
mode-line-misc-info ;; Any other information
)
"General format of mode line")
#+end_src
*** Left padding for the mode line
Here's the main logic for centring the entire mode-line. Essentially
just generate a string with enough spaces that the mode-line is in the
exact centre.
#+begin_src emacs-lisp
(defun +mode-line/left-padding ()
"Returns a string of spaces which will centre the mode-line if put
to the left of it."
(let* ((mode-line-size (length (format-mode-line +mode-line/format)))
(string-size (/ (- (window-width) mode-line-size) 2)))
;; ?\s means a whitespace character (why not #\Space Stallman?!)
(make-string string-size ?\s)))
#+end_src
*** mode-line-format
Put the left padded string and the rest of the format together to get
a nice little mode-line.
#+begin_src emacs-lisp
(setq-default mode-line-format
`((:eval (+mode-line/left-padding))
,@+mode-line/format))
#+end_src #+end_src
** Mouse ** Mouse
Who uses a mouse? 🤮 Who uses a mouse? 🤮

View File

@@ -0,0 +1,89 @@
;;; better-mode-line.el --- A better mode-line system designed by me -*- lexical-binding: t; -*-
;; Copyright (C) 2024 Aryadev Chavali
;; Author: Aryadev Chavali <aryadev@aryadevchavali.com>
;; Keywords:
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; There are 3 lists for the left, centre and right of the mode-line. They're
;; the same as mode-line-format in terms of general schema as they're fed
;; directly into that variable. Padding strings are automatically generated
;; based on these segments so be sure to set these.
;;; Code:
(defun +better-mode-line/evil-state ()
"Returns either the empty string if no evil-state is defined or
the first character of the evil state capitalised"
(with-eval-after-load "evil"
(if (bound-and-true-p evil-state)
(upcase
(substring
(format "%s"
evil-state)
0 1))
"")))
(defvar +better-mode-line/left-segment nil
"List of elements that are placed on the left of the mode-line")
(defvar +better-mode-line/centre-segment nil
"List of elements that should be on the centre of the mode-line")
(defvar +better-mode-line/right-segment nil
"List of elements that should be on the right of the mode-line")
(defconst +better-mode-line/--minimum-padding 4
"Minimum size of padding string.")
(defun +better-mode-line/--left->centre-padding ()
"Returns a string which pads the centre segment perfectly relative
to the left segment."
(let* ((left-segment-size (length (format-mode-line +better-mode-line/left-segment)))
(centre-segment-size (length (format-mode-line +better-mode-line/centre-segment)))
(padding-size (- (/ (window-width) 2) (/ centre-segment-size 2) left-segment-size)))
(make-string (if (< padding-size +better-mode-line/--minimum-padding)
+better-mode-line/--minimum-padding
padding-size)
?\s)))
(defun +better-mode-line/--centre->right-padding ()
"Returns a string which pads the right segment perfectly relative
to the centre segment"
(let* ((centre-segment-size (length (format-mode-line +better-mode-line/centre-segment)))
(right-segment-size (length (format-mode-line +better-mode-line/right-segment)))
(padding-size (- (/ (window-width) 2) (/ centre-segment-size 2) right-segment-size)))
(make-string (if (< padding-size +better-mode-line/--minimum-padding)
+better-mode-line/--minimum-padding
padding-size)
?\s)))
(defun +better-mode-line/setup-mode-line ()
"Call this to setup the mode-line when:
- first loading the package.
- segments are updated."
(setq-default mode-line-format
`(,@+better-mode-line/left-segment
(:eval (+better-mode-line/--left->centre-padding))
,@+better-mode-line/centre-segment
(:eval (+better-mode-line/--centre->right-padding))
,@+better-mode-line/right-segment)))
(provide 'better-mode-line)
;;; better-mode-line.el ends here