Skip to content

kn66/halo.el

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

halo.el

halo is a curiosity-driven hobby package and experimental Emacs minor mode for quiet editing interfaces. It keeps the current line and nearby lines at normal contrast, then gradually reduces the contrast of visible lines farther away from point.

The goal is to reduce eye movement by keeping the cursor near the vertical center, and to make the center easier to attend to by keeping it at higher contrast than the surrounding lines.

This may help improve focus, but that is only an informal expectation.

Demo

gif/nano.gif

gif/nano-dark.gif

Requirements

  • Emacs 29.1 or later

Installation

Place this directory somewhere in load-path, then load it:

(add-to-list 'load-path "~/.emacs.d/lisp/halo.el")
(require 'halo)

Enable it in a buffer with:

(halo-mode 1)

Or run:

M-x halo-mode

Enable it globally with:

(halo-global-mode 1)

Or run:

M-x halo-global-mode

use-package

Minimal global setup:

(use-package halo
  :load-path "~/.emacs.d/lisp/halo.el"
  :config
  (halo-global-mode 1))

With explicit settings:

(use-package halo
  :load-path "~/.emacs.d/lisp/halo.el"
  :config
  (halo-global-mode 1)
  :custom
  (halo-radius 12)
  (halo-min-alpha 0.360)
  (halo-steps 6)
  (halo-falloff 'smoothstep)
  (halo-idle-delay 0.06)
  (halo-live-update t)
  (halo-center-cursor t)
  (halo-center-fraction 0.5)
  (halo-virtual-top-margin t)
  (halo-global-excluded-modes '(minibuffer-mode))
  (halo-global-exclude-predicate nil))

Options

  • halo-radius: lines above and below point that stay at normal contrast.
  • halo-min-alpha: minimum foreground alpha for far-away lines.
  • halo-steps: number of contrast levels.
  • halo-falloff: contrast curve outside the focus radius. The default smoothstep keeps the edge of the focus area gentler than linear dimming.
  • halo-idle-delay: idle delay before overlays are refreshed.
  • halo-live-update: when non-nil, update overlays immediately after cursor movement.
  • halo-center-cursor: when non-nil, call recenter after cursor movement so point stays near the vertical center of the selected window.
  • halo-center-fraction: vertical resting position for point when centering is enabled. 0.5 is the middle of the window; slightly smaller values leave more preview context below point.
  • halo-virtual-top-margin: when non-nil, add display-only space before the first buffer line so centering also works at the beginning of the buffer.
  • halo-global-excluded-modes: major modes where halo-global-mode should not enable halo-mode. Derived modes are also excluded.
  • halo-global-exclude-predicate: optional predicate called before halo-global-mode enables halo-mode in a buffer.

Refresh the selected window manually with:

M-x halo-refresh

Refresh all live windows showing buffers where halo-mode is enabled with:

M-x halo-refresh-all

For an even wider high-contrast area:

(setq halo-radius 16)
(setq halo-min-alpha 0.55)

Design

This package intentionally starts as a stable MVP.

  • It is a buffer-local minor mode.
  • halo-global-mode enables the buffer-local mode in ordinary buffers and skips minibuffers by default.
  • It can update immediately after commands, so contrast follows fast cursor movement. Idle refresh remains available when halo-live-update is nil.
  • It only processes the selected window’s visible range.
  • Contrast distance is measured in displayed lines, so folded or invisible sections do not make nearby visible lines look artificially far away.
  • The default contrast curve is smoothstep rather than linear, so lines just outside the focus radius do not drop abruptly.
  • For folded buffers such as Magit, the visible display lines are scanned once per refresh and then reused for distance calculation.
  • It caches dimming face specs and applies them to visible text ranges, keeping syntax foreground hues softened instead of flattening a dimmed line to one color.
  • It removes old contrast overlays before every refresh.
  • It also removes orphan overlays tagged by this package, so stale dimming does not survive reloads or mode re-enabling.
  • The current line and the configured radius around point are left untouched.
  • Optional cursor centering uses Emacs’ built-in recenter.
  • The beginning of the buffer can receive a display-only virtual top margin, so the first line can still sit near the vertical center without inserting text.

The dimming face blends each visible text range’s foreground color toward the default background. This keeps syntax colors recognizable while reducing contrast away from point.

Known Limitations

  • Overlay faces from other packages may not always be reflected in the softened foreground color.
  • If the same buffer is shown in multiple windows, each halo overlay is scoped to the window it was created for.
  • Very unusual themes or terminal color setups may produce less smooth dimming.
  • The package does not try to dim non-selected windows yet.

Org and Markdown

For prose-heavy buffers, a slightly larger focus radius is often more readable:

(add-hook
 'org-mode-hook
 (lambda ()
   (setq-local halo-radius 5)
   (setq-local halo-min-alpha 0.45)
   (setq-local halo-center-cursor t)
   (halo-mode 1)))

(add-hook
 'markdown-mode-hook
 (lambda ()
   (setq-local halo-radius 4)
   (setq-local halo-min-alpha 0.42)
   (setq-local halo-center-cursor t)
   (halo-mode 1)))

Future Ideas

  • A companion mode that dims buffers in non-selected windows.
  • Theme-aware color blending that handles more unusual face combinations.
  • A child-frame mask backend for GUI-only experiments that dim by covering distant screen regions instead of changing text foregrounds.
  • Separate profiles for programming, Org, Markdown, and prose editing.

License

GPLv3

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors