Mode-line
This file holds my mode-line configuration. It is using powerline to emulate the sleek look of spacemacs, but with custom colors.
(use-package powerline :ensure t :if do.theme/enabled-theme :demand :config <<do.modeline/settings>> <<do.modeline/separators>> <<do.modeline/faces>> <<do.modeline/functions>> <<do.modeline/format>>)
Powerline general settings
(column-number-mode 1)
Separators
(cond ;; dark theme ((eq do.theme/enabled-theme 'dark) (setq powerline-default-separator-dir '(right . left)) (when (display-graphic-p) (setq powerline-default-separator 'contour) (setq powerline-height 27))) ;; light theme ((eq do.theme/enabled-theme 'light) (setq powerline-default-separator-dir '(right . left)) (when (display-graphic-p) (setq powerline-default-separator 'contour) (setq powerline-height 27))))
Powerline theme
My custom theme consists of three parts: First, I have a bunch of different
faces that switch between an "inactive mode" and "active mode", based on
whether a window is active or not. Second, I define a few functions that take
care of displaying some information about the buffer. Third, I use the
functions provided in powerline.el
to dynamically set the mode-line-format
variable. In doing so, I'm using a few cool unicode characters and some
characters from the powerline
fonts.
Faces
We first define some extra faces for the mode line.
(cond ((eq do.theme/enabled-theme 'dark) ;; first reset the faces that already exist (set-face-attribute 'mode-line nil :foreground (face-attribute 'default :foreground) :family "Fira Sans" :weight 'bold :background "#2d2d2d") (set-face-attribute 'mode-line-inactive nil :foreground (face-attribute 'font-lock-comment-face :foreground) :background "#2d2d2d" :family "Fira Sans" :weight 'bold :box `(:line-width -2 :color ,"#2d2d2d")) (set-face-attribute 'powerline-active1 nil :background "gray30") (set-face-attribute 'powerline-inactive1 nil :background (face-attribute 'default :background) :box `(:line-width -2 :color ,"#2d2d2d")) ;; these next faces are for the status indicator ;; read-only buffer (make-face 'mode-line-read-only-face) (make-face 'mode-line-read-only-inactive-face) (set-face-attribute 'mode-line-read-only-face nil :foreground (face-attribute 'default :foreground) :inherit 'mode-line) (set-face-attribute 'mode-line-read-only-inactive-face nil :foreground (face-attribute 'default :foreground) :inherit 'mode-line-inactive) ;; modified buffer (make-face 'mode-line-modified-face) (make-face 'mode-line-modified-inactive-face) (set-face-attribute 'mode-line-modified-face nil :foreground (face-attribute 'default :background) :background "indian red" ;"#e5786d" :inherit 'mode-line) (set-face-attribute 'mode-line-modified-inactive-face nil :foreground (face-attribute 'default :background) :background "indian red" ;"#e5786d" :inherit 'mode-line-inactive) ;; unmodified buffer (make-face 'mode-line-unmodified-face) (make-face 'mode-line-unmodified-inactive-face) (set-face-attribute 'mode-line-unmodified-face nil :foreground (face-attribute 'font-lock-comment-face :foreground) :inherit 'mode-line) (set-face-attribute 'mode-line-unmodified-inactive-face nil :foreground (face-attribute 'font-lock-comment-face :foreground) :inherit 'mode-line-inactive) ;; the remote indicator (make-face 'mode-line-remote-face) (make-face 'mode-line-remote-inactive-face) (set-face-attribute 'mode-line-remote-face nil :foreground (face-attribute 'font-lock-comment-face :foreground) :background (face-attribute 'default :background) :inherit 'mode-line) (set-face-attribute 'mode-line-remote-inactive-face nil :foreground (face-attribute 'font-lock-comment-face :foreground) :background (face-attribute 'default :background) :inherit 'mode-line-inactive) ;; the current file name (make-face 'mode-line-filename-face) (make-face 'mode-line-filename-inactive-face) (set-face-attribute 'mode-line-filename-face nil :foreground (face-attribute 'font-lock-type-face :foreground) :background (face-attribute 'default :background) :inherit 'mode-line) (set-face-attribute 'mode-line-filename-inactive-face nil :foreground (face-attribute 'font-lock-comment-face :foreground) :background (face-attribute 'default :background) :inherit 'mode-line-inactive) ;; the major mode name (make-face 'mode-line-major-mode-face) (make-face 'mode-line-major-mode-inactive-face) (set-face-attribute 'mode-line-major-mode-face nil :foreground (face-attribute 'default :foreground) :inherit 'powerline-active1) (set-face-attribute 'mode-line-major-mode-inactive-face nil :box `(:line-width -2 :color ,"#2d2d2d") :foreground (face-attribute 'font-lock-comment-face :foreground) :inherit 'powerline-inactive1) ;; the minor mode name (make-face 'mode-line-minor-mode-face) (make-face 'mode-line-minor-mode-inactive-face) (set-face-attribute 'mode-line-minor-mode-face nil :foreground (face-attribute 'font-lock-comment-face :foreground) :inherit 'powerline-active1) (set-face-attribute 'mode-line-minor-mode-inactive-face nil :box `(:line-width -2 :color ,"#2d2d2d") :foreground (face-attribute 'powerline-inactive1 :background) :inherit 'powerline-inactive1) ;; the position face (make-face 'mode-line-position-face) (make-face 'mode-line-position-inactive-face) (set-face-attribute 'mode-line-position-face nil :background (face-attribute 'default :background) :inherit 'mode-line) (set-face-attribute 'mode-line-position-inactive-face nil :foreground (face-attribute 'font-lock-comment-face :foreground) :background (face-attribute 'default :background) :inherit 'mode-line-inactive) ;; the 80col warning face (make-face 'mode-line-80col-face) (make-face 'mode-line-80col-inactive-face) (set-face-attribute 'mode-line-80col-face nil :background "indian red" ;"#e5786d" :foreground (face-attribute 'default :background) :inherit 'mode-line) (set-face-attribute 'mode-line-80col-inactive-face nil :foreground (face-attribute 'font-lock-comment-face :foreground) :background (face-attribute 'default :background) :inherit 'mode-line-inactive) ;; the buffer percentage face (make-face 'mode-line-percentage-face) (make-face 'mode-line-percentage-inactive-face) (set-face-attribute 'mode-line-percentage-face nil :foreground (face-attribute 'font-lock-comment-face :foreground) :inherit 'mode-line) (set-face-attribute 'mode-line-percentage-inactive-face nil :foreground (face-attribute 'font-lock-comment-face :foreground) :inherit 'mode-line-inactive) ;; the directory face (make-face 'mode-line-shell-dir-face) (make-face 'mode-line-shell-dir-inactive-face) (set-face-attribute 'mode-line-shell-dir-face nil :foreground (face-attribute 'font-lock-comment-face :foreground) :inherit 'powerline-active1) (set-face-attribute 'mode-line-shell-dir-inactive-face nil :foreground (face-attribute 'font-lock-comment-face :foreground) :inherit 'powerline-inactive1) ) ((eq do.theme/enabled-theme 'light) (plan9/with-color-variables ;; first reset the faces that already exist (set-face-attribute 'mode-line nil :foreground fg :family "Fira Sans" :weight 'bold :background blue) (set-face-attribute 'mode-line-inactive nil :foreground fg-light :background bg-dark :family "Fira Sans" :weight 'bold) (set-face-attribute 'powerline-active1 nil :background blue) (set-face-attribute 'powerline-inactive1 nil :background bg-dark) ;; these next faces are for the status indicator ;; read-only buffer (make-face 'mode-line-read-only-face) (make-face 'mode-line-read-only-inactive-face) (set-face-attribute 'mode-line-read-only-face nil :foreground bg :inherit 'mode-line) (set-face-attribute 'mode-line-read-only-inactive-face nil :foreground bg :inherit 'mode-line-inactive) ;; modified buffer (make-face 'mode-line-modified-face) (make-face 'mode-line-modified-inactive-face) (set-face-attribute 'mode-line-modified-face nil :foreground bg :background red :inherit 'mode-line) (set-face-attribute 'mode-line-modified-inactive-face nil :foreground fg-alt :background bg-dark :inherit 'mode-line-inactive) ;; unmodified buffer (make-face 'mode-line-unmodified-face) (make-face 'mode-line-unmodified-inactive-face) (set-face-attribute 'mode-line-unmodified-face nil :foreground bg :inherit 'mode-line) (set-face-attribute 'mode-line-unmodified-inactive-face nil :foreground fg-alt :inherit 'mode-line-inactive) ;; the remote indicator (make-face 'mode-line-remote-face) (make-face 'mode-line-remote-inactive-face) (set-face-attribute 'mode-line-remote-face nil :foreground green :background bg :inherit 'mode-line) (set-face-attribute 'mode-line-remote-inactive-face nil :foreground fg-alt :background bg :inherit 'mode-line-inactive) ;; the current file name (make-face 'mode-line-filename-face) (make-face 'mode-line-filename-inactive-face) (set-face-attribute 'mode-line-filename-face nil :foreground fg :background bg :inherit 'mode-line) (set-face-attribute 'mode-line-filename-inactive-face nil :foreground fg :background bg :inherit 'mode-line-inactive) ;; the major mode name (make-face 'mode-line-major-mode-face) (make-face 'mode-line-major-mode-inactive-face) (set-face-attribute 'mode-line-major-mode-face nil :foreground bg :inherit 'powerline-active1) (set-face-attribute 'mode-line-major-mode-inactive-face nil :foreground fg-alt :inherit 'powerline-inactive1) ;; the minor mode name (make-face 'mode-line-minor-mode-face) (make-face 'mode-line-minor-mode-inactive-face) (set-face-attribute 'mode-line-minor-mode-face nil :foreground fg-light :inherit 'powerline-active1) (set-face-attribute 'mode-line-minor-mode-inactive-face nil :foreground (face-attribute 'powerline-inactive1 :background) :inherit 'powerline-inactive1) ;; the position face (make-face 'mode-line-position-face) (make-face 'mode-line-position-inactive-face) (set-face-attribute 'mode-line-position-face nil :background bg :inherit 'mode-line) (set-face-attribute 'mode-line-position-inactive-face nil :foreground fg-alt :background bg :inherit 'mode-line-inactive) ;; the 80col warning face (make-face 'mode-line-80col-face) (make-face 'mode-line-80col-inactive-face) (set-face-attribute 'mode-line-80col-face nil :background red :foreground bg :inherit 'mode-line) (set-face-attribute 'mode-line-80col-inactive-face nil :foreground fg-alt :background bg-dark :inherit 'mode-line-inactive) ;; the buffer percentage face (make-face 'mode-line-percentage-face) (make-face 'mode-line-percentage-inactive-face) (set-face-attribute 'mode-line-percentage-face nil :foreground bg-dark :inherit 'mode-line) (set-face-attribute 'mode-line-percentage-inactive-face nil :foreground fg-alt :inherit 'mode-line-inactive) ;; the directory face (make-face 'mode-line-shell-dir-face) (make-face 'mode-line-shell-dir-inactive-face) (set-face-attribute 'mode-line-shell-dir-face nil :foreground bg-dark :inherit 'powerline-active1) (set-face-attribute 'mode-line-shell-dir-inactive-face nil :foreground fg-alt :inherit 'powerline-inactive1))))
Helper functions
Shorten Directory Name:
Now we want to define Amit's shorten-directory function. This will be used when
in an ansi-term
buffer.
Narrow indicator:
This detects the current state of narrowing. It is a slight modification of the
original function powerline-narrow
from powerline.el
.
Version Control:
This is a modification of the original powerline-vc
function. It correctly
displays the right glyphs using emacs' VC interface.
(defun do.modeline.functions/shorten-directory (dir max-length) "Show up to `max-length' characters of a directory name `dir'." (let ((path (reverse (split-string (abbreviate-file-name dir) "/"))) (output "")) (when (and path (equal "" (car path))) (setq path (cdr path))) (while (and path (< (length output) (- max-length 4))) (setq output (concat (car path) "/" output)) (setq path (cdr path))) (when path (setq output (concat ".../" output))) output)) (defpowerline do.modeline.functions/narrow (let (real-point-min real-point-max) (save-excursion (save-restriction (widen) (setq real-point-min (point-min) real-point-max (point-max)))) (when (or (/= real-point-min (point-min)) (/= real-point-max (point-max))) (propertize (concat (char-to-string #x2691) " Narrow") 'mouse-face 'mode-line-highlight 'help-echo "mouse-1: Remove narrowing from the current buffer" 'local-map (make-mode-line-mouse-map 'mouse-1 'mode-line-widen))))) (defpowerline do.modeline.functions/vc (when (and (buffer-file-name (current-buffer)) vc-mode) (if window-system (let ((backend (vc-backend (buffer-file-name (current-buffer))))) (when backend (format "%s %s: %s (%s)" (char-to-string #xe0a0) backend (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2)) (vc-state (buffer-file-name (current-buffer)) backend)))))))
mode-line-format
Now we can set the mode-line-format
variable to what we want.
(setq-default mode-line-format '("%e" (:eval (let* ((active (powerline-selected-window-active)) ;; toggle faces between active and inactive (mode-line (if active 'mode-line 'mode-line-inactive)) (face1 (if active 'powerline-active1 'powerline-inactive1)) (face2 (if active 'powerline-active2 'powerline-inactive2)) (read-only-face (if active 'mode-line-read-only-face 'mode-line-read-only-inactive-face)) (modified-face (if active 'mode-line-modified-face 'mode-line-modified-inactive-face)) (unmodified-face (if active 'mode-line-unmodified-face 'mode-line-unmodified-inactive-face)) (position-face (if active 'mode-line-position-face 'mode-line-position-inactive-face)) (80col-face (if active 'mode-line-80col-face 'mode-line-80col-inactive-face)) (major-mode-face (if active 'mode-line-major-mode-face 'mode-line-major-mode-inactive-face)) (minor-mode-face (if active 'mode-line-minor-mode-face 'mode-line-minor-mode-inactive-face)) (filename-face (if active 'mode-line-filename-face 'mode-line-filename-inactive-face)) (percentage-face (if active 'mode-line-percentage-face 'mode-line-percentage-inactive-face)) (remote-face (if active 'mode-line-remote-face 'mode-line-remote-inactive-face)) (shell-dir-face (if active 'mode-line-shell-dir-face 'mode-line-shell-dir-inactive-face)) ;; get the separators (separator-left (intern (format "powerline-%s-%s" (powerline-current-separator) (car powerline-default-separator-dir)))) (separator-right (intern (format "powerline-%s-%s" (powerline-current-separator) (cdr powerline-default-separator-dir)))) ;; the right side (rhs (list (do.modeline.functions/vc minor-mode-face 'r) (funcall separator-right face1 position-face) (powerline-raw " " position-face) (powerline-raw (char-to-string #xe0a1) position-face) (powerline-raw " " position-face) (powerline-raw "%4l" position-face 'r) ;; display a warning if we go above 80 columns (if (>= (current-column) 80) (funcall separator-right position-face 80col-face) (powerline-raw (char-to-string #x2502) position-face)) (if (>= (current-column) 80) (powerline-raw "%3c" 80col-face 'l) (powerline-raw "%3c" position-face 'l)) (if (>= (current-column) 80) (powerline-raw " " 80col-face) (powerline-raw " " position-face)) (if (>= (current-column) 80) (funcall separator-left 80col-face percentage-face) (funcall separator-left position-face percentage-face)) (powerline-raw " " percentage-face) (powerline-raw "%6p" percentage-face 'r))) ;; the left side (lhs (list ;; this is the modified status indicator (cond (buffer-read-only (powerline-raw " " read-only-face)) ((buffer-modified-p) ;; do not light up when in an interactive buffer. Set ;; ML-INTERACTIVE? in hooks for interactive buffers. (if (not (bound-and-true-p ml-interactive?)) (powerline-raw " " modified-face) (powerline-raw " " unmodified-face))) ((not (buffer-modified-p)) (powerline-raw " " unmodified-face))) (cond (buffer-read-only (powerline-raw (concat (char-to-string #xe0a2) " ") read-only-face 'l)) ((buffer-modified-p) (if (not (bound-and-true-p ml-interactive?)) (powerline-raw (concat (char-to-string #x2621) " ") modified-face 'l) (powerline-raw (concat (char-to-string #x259e) " ") unmodified-face 'l))) ((not (buffer-modified-p)) (powerline-raw (concat (char-to-string #x26c1) " ") unmodified-face 'l))) (cond (buffer-read-only (funcall separator-right read-only-face filename-face)) ((buffer-modified-p) (if (not (bound-and-true-p ml-interactive?)) (funcall separator-right modified-face filename-face) (funcall separator-right unmodified-face filename-face))) ((not (buffer-modified-p)) (funcall separator-right unmodified-face filename-face))) ;; remote indicator (when (file-remote-p default-directory) (powerline-raw (concat " " (char-to-string #x211b)) remote-face)) ;; filename and mode info (powerline-buffer-id filename-face 'l) (powerline-raw " " filename-face) (funcall separator-left filename-face major-mode-face) ;; do not need mode info when in ansi-term (unless (bound-and-true-p show-dir-in-mode-line?) (powerline-major-mode major-mode-face 'l)) (unless (bound-and-true-p show-dir-in-mode-line?) (powerline-process major-mode-face 'l)) ;; show a flag if in line mode in terminal (when (and (bound-and-true-p show-dir-in-mode-line?) (eq major-mode 'term-mode) (term-in-line-mode)) (powerline-raw (concat (char-to-string #x2691) " Line") major-mode-face)) (powerline-raw " " major-mode-face) ;; little trick to move the directory name to the mode line ;; when inside of emacs set SHOW-DIR-IN-MODE-LINE? to enable (if (bound-and-true-p show-dir-in-mode-line?) (when (not (file-remote-p default-directory)) (powerline-raw (do.modeline.functions/shorten-directory default-directory 45) shell-dir-face)) (powerline-minor-modes minor-mode-face 'l)) (unless (bound-and-true-p show-dir-in-mode-line?) (do.modeline.functions/narrow major-mode-face 'l))))) ;; concatenate it all together (concat (powerline-render lhs) (powerline-fill face1 (powerline-width rhs)) (powerline-render rhs))))))
Toggle Mode Line
Sometimes we don't want a mode-line. Use M-x hidden-mode-line
to activate.
(define-minor-mode hidden-mode-line-mode "Minor mode to hide the mode-line in the current buffer." :init-value nil :global t :variable hidden-mode-line-mode :group 'editing-basics (if hidden-mode-line-mode (setq hide-mode-line mode-line-format mode-line-format nil) (setq mode-line-format hide-mode-line hide-mode-line nil)) (force-mode-line-update) ;; Apparently force-mode-line-update is not always enough to ;; redisplay the mode-line (redraw-display) (when (and (called-interactively-p 'interactive) hidden-mode-line-mode) (run-with-idle-timer 0 nil 'message (concat "Hidden Mode Line Mode enabled. " "Use M-x hidden-mode-line-mode to make the mode-line appear."))))
If I ever feel like hiding the mode-line by default, I could do something like this: (this is currently not enabled)
(add-hook 'after-change-major-mode-hook 'hidden-mode-line-mode)