A lightweight scrollbar for the Emacs mode line.
For graphical window systems:
and terminals too:
Emacs has so many great ways to navigate, I really only ever used scroll-bars as a visual indication of position and file size. But recently, to save space, I added (scroll-bar-mode -1)
to my init. Immediately I missed having that information at a glance. A percentage in the mode line (like 25%
) is not very glanceable, and also gives no information about the currently visible content relative to the total line length (i.e. from the length of the bar). I wanted something very fast and very lightweight, plus I'm not so into rainbow cats. Hence MLScroll.
mlscroll-width-chars
there. Get it from MELPA, and arrange to have:
(mlscroll-mode 1)
called at init time (or whenever you are feeling scrolly). Toggle on or off anytime.
Example for use-package
:
(use-package mlscroll
:ensure t
:config
(setq mlscroll-shortfun-min-width 11) ; truncate which-func
(mlscroll-mode 1))
Alternatively, if you start emacs using the command line --daemon
command (see below):
(use-package mlscroll
:ensure t
:hook (server-after-make-frame . mlscroll-mode))
Use M-x customize-group mlscroll
to change background colors, overall scroll bar width, minimum current "thumb" width, border size, and other settings.
By default, MLScroll disables the XX%
position mode line indication, and puts itself in the mode line variable mode-line-end-spaces
, prepending a spacer to right-align itself. Optionally, it can instead replace the XX%
indicator (or be placed anywhere in your mode line). See mlscroll-alter-percent-position
and mlscroll-right-align
.
The builtin which-function-mode
by default puts [full-function-name]
on the right side of the mode line. With long names and the default placement, this can push the MLScroll bar partially or fully off the mode line. Set mlscroll-shortfun-min-width
to a minimum width, and MLScroll will truncate the which-function
name to at least that many trailing characters (e.g. […function-name]
or similar), to make room for the scrollbar. The amount of truncation can be adjusted using mlscroll-shortfun-extra-width
.
Note that MLScroll is most visually compatible with "plain" mode line formats that don't use :box
bordering. It will warn you if you try to use a border with a :box
-full format enabled. It also doesn't inherit :underline
and :overline
mode line properties unless mlscroll-border
is set to 0 (these don't work with the combination of specified space and :box
).
See the suggestions for configuring moody for some config ideas.
For users of modus-themes
, (setq modus-themes-mode-line '(moody borderless))
is recommended, or, in more recent versions (>v4):
(setq modus-themes-common-palette-overrides
'((border-mode-line-active unspecified)
(border-mode-line-inactive unspecified)))
The MLScroll bar widths are based on the number of lines visible in the window (+ lines before and after it). The normal scroll bar is based on characters shown. Both tend to change as very long/wrapped lines come into view, but in the opposite sense: MLScroll sees fewer lines shown and shrinks the current thumb; the default scrollbar sees many characters come in view, and grows it. I find the lines approach to be more sensible, and it has the advantage that with truncate-lines
on, the thumb doesn't change size as you scroll. If you'd like to see the difference, evaluate (insert (make-string 5000 ?a) "\n")
in the *scratch*
buffer amidst other normal text, and scroll through before and after toggle-truncate-lines
. On the other hand, highly folded documents like org-mode docs will show a changing "thumb size" as you scroll through, as the current window could contain many (hidden) lines. I find that pretty convenient actually.
How does it work? MLScroll places itself by default in mode-line-end-spaces
, and uses a right-aligned space to align it at the end of the modeline. For drawing the bars themselves, it uses three "specified spaces".
MLScroll doesn't work with my fancy mode line mode! It should work automatically for simple mode lines that end in mode-line-end-spaces
. If you prefer, set mlscroll-right-align
to nil
and mlscroll-alter-percent-position
to 'replace
to put it in place of the XX%
percentage indicator. Otherwise, e.g. if you have a highly customized or pre-packaged mode line, you'll need to find somewhere to put MLScroll. A general recipe is to:
mlscroll-right-align
to nil
.(setq fancy-mode-line-variable-of-some-kind '(:eval (mlscroll-mode-line))
. MLScroll starts off very small when I start an emacs session using --daemon
. For graphical windows, MLScroll needs to know the width of font characters in the mode line (or at least the default font) to draw a pixel-perfect bar. Since --daemon
doesn't create a frame or know anything about the font widths, loading MLScroll directly under a --daemon
session misreports the font width as 1 pixel, leading to a very small scroller bar. The solution is either to abandon --daemon
in favor of (server-start)
in your init file, or arrange for MLScroll to be initialized later, after a frame is created, ala:
(use-package mlscroll
:hook (server-after-make-frame . mlscroll-mode))
How can I customize MLScroll? M-x customize-group mlscroll [Ret]
.
I want to use MLScroll with different themes throughout the day, what should I do? This should happen automatically since v0.2. Since the MLScroll "thumb" color defaults to the foreground color of the scroll-bar
face, you might configure that face for your theme, rather than mlscroll-in-color
directly.
I get a message about :box disabling my MLScroll border: MLScroll uses the :box
attribute to draw border (with the help of :inverse-video
). If your normal mode line face already has a :box
property, this will interfere and cause the left/right border to show up. If you want a border to make your MLScroll less tall, consider disabling the :box
property on faces 'mode-line
and 'mode-line-inactive
(M-x customized-group mode-line-faces [Ret]
). See issue. For users of modus-themes
, see above.
MLScroll takes up a decent (configurable) chunk of your mode line. To save space for it even when the window is somewhat narrow, I use:
(setq mlscroll-shortfun-min-width 11)
to trim down the which-function name as needed. (setq-default
mode-line-format ;less space, no MULE
(cl-nsubst-if " " (lambda (x) (and (stringp x) (string-blank-p x) (> (length x) 1)))
(remove 'mode-line-mule-info mode-line-format))))