eyeliner
Eyeliner is nougat providing high-level support for spaceline, the package behind Spacemacs’ mode-line. Eyeliner also depends on all-the-icons for providing multiple icon-fonts.
inactive unmodified buffer (dimmed)
user guide
The following sections will explain how Eyeliner works and how to best use it.
how spaceline works
The core concept behind Spaceline are the Segments that make up your mode-line. It depends on Powerline, which colors each of these segments differently so they are visually distinct. Typically, it also features unicode delimeters between the segments such as arrows, waves, bevels or zigzags.
Spaceline separates the mode-line in half into left and right sides. Segments are either configured to appear aligned on the left or the right, with empty space in between.
integrating with spaceline
In order to get your mode-line integrated with Spaceline, use the following snippet after Spaceline has been loaded:
(setq-default mode-line-format
'("%e" (:eval (spaceline-ml-main))))specifying what segments you want
Once Spaceline has been loaded you can call (spaceline-install 'main left right)
to customize your mode-line. Here is an example showing how to replicate the default
segments:
(spaceline-install 'main
'((eyeliner/buffer-modified)
(eyeliner/branch-icon :skip-alternate t :tight-right t)
(eyeliner/branch-name)
(eyeliner/project-name :skip-alternate t)
(eyeliner/mode-icon :skip-alternate t :tight-left t :tight-right t)
(eyeliner/buffer-name))
'(("%l:%c")))how spaceline segements are defined
Spaceline provides a macro (spaceline-define-segment NAME BODY) which defines a new
Segment. Segments must return some, potentially propertized, text. If Segments return
nil, they don’t appear in the mode-line. Additionally, the binding active will be t
or nil depending if the Segement is being called for the active buffer or not. This
can be used to change colors or hide the Segment.
Here is a simple example showing the buffer-name when the buffer is active. We can
choose a different face depending on buffer-state (modified, read-only, etc):
(spaceline-define-segment my/buffer-name-segment
(when active
(let* ((buffer-name (buffer-name))
(buffer-state (format-mode-line "%*"))
(style (cond
((string= buffer-state "-") 'mode-line)
((string= buffer-state "*") 'mode-line-emphasis)
((string= buffer-state "%") 'mode-line-highlight))))
(propertize buffer-name 'face style))))Later, we’ll see how Eyeliner can help you write nice Segments.
how all-the-icons works
all-the-icons.el is a package which provides a high-level API over a number of icon-font packages. It is useful for displaying information icongraphically which is terser and more aesthetically pleasing. It can even provide icons for many major-modes which is nice.
installing the fonts
After all-the-icons has been loaded, you can run (all-the-icons-install-fonts) to
install all of the associated fonts. You don’t need to put this into your
configuration as it only needs to be run one time.
looking up an icon
Calling (all-the-icons--function-name ICON-NAME) will return the icon as text
propertized with a simple face with the appropriate font family. However, you wont
need to do this as Eyeliner provides a better interface.
how eyeliner works
Eyeliner is going to help you do the following:
- define styles which are auto-magically be “dimmed” in inactive buffers
- define icons which are easy to use with styles
- defer your segement definitions so you can put them anywhere in your config
defining styles
Styles are functions you can call with some text to have it appropriately propertized based on whether the Style is being displayed in an active buffer or not. When Styles are displayed in inactive buffers they are shown as darkened desaturated versions.
(eyeliner/style greeting "blue")This will create a function (greeting-style TEXT) which will return the
propertized text:
(let ((active t))
(insert (greeting-style "Hello World")))defining icons
Icons are functions similar to Styles but they don’t take any text as a parameter and instead always return the propertized font icon.
(eyeliner/icon octoface "octoface" "red")This creates an Icon function (octoface-icon):
(let ((active t))
(insert (octoface-icon)))The dimmed versions of Styles and Icons are returned when active is nil:
(let ((active nil))
(insert (octoface-icon)))controlling dimming
Style and Icon dimming is controlled by the settings eyeliner/default-darkness and
eyeliner/default-desaturation. They are each a number between 0 and 100 representing
what percent the given color quality should be reduced to.
To set the darkness and desaturation for a specific Style or Icon pass the desired
values to eyeliner/style or eyeliner/icon:
;; set darkness and desaturation to 30 and 60
(eyeliner/icon octoface "octoface" "red" 30 60)customizing other face attributes
You can pass a plist of Face Attributes to either eyeliner/style or eyeliner/icon as
the sixth parameter:
;; dimming values will use the defaults
(eyeliner/style warning "red" nil nil
'(:slant italic))customizing display properties
You can pass Display Properties as well using the seventh parameter:
;; raise the icon slightly to vertically center it
(eyeliner/icon circle "circle-o" "yellow" nil nil nil
'((raise -0.2)))deferring segement definitions
Using spaceline-define-segment to define Segments before Spaceline is loaded will
resort in an error. If you need the flexibility, Eyeliner provides a simple macro for
deferring your Segment definitions:
(eyeliner/defer-segment
(spaceline-define-segment my/cool-segement
(when active
... )))customizing built-in segment colors
Eyeliner comes with a number of default Segments to get you started. They all utilize some default colors which you can customize:
eyeliner/warm-colorfor when something might need attending toeyeliner/cool-colorfor when something is A-OKeyeliner/plain-colora neutral color for other situations
To customize these, simply assign a color to them with setq BEFORE (!) you load this
file.
the built in segments
buffer-modified
Buffer modified: circle-o icon in eyeliner/cool-color
Buffer unmodified: dot-circle-o icon in eyeliner/warm-color
buffer-name
Buffer modified: the buffer name in eyeliner/plain-color
Buffer unmodified: the buffer name in eyeliner/warm-color
branch-icon
No staged or unstaged changes: git-branch icon in eyeliner/cool-color
Staged or unstaged changes: diff-added icon in eyeliner/warm-color
branch-name
No staged or unstaged changes: the branch name in eyeliner/cool-color
Staged or unstaged changes: the branch name in eyeliner/warm-color
project-name
(projectile-project-name) in eyeliner/plain-color
mode-icon
Major-mode relevant icon in eyeliner/plain-color
all the icons
Need to run (all-the-icons-install-fonts) on first run, then restart.
(use-package all-the-icons)settings
(setq-default eyeliner/warm-color "indian red")
(setq-default eyeliner/cool-color "deep sky blue")
(setq-default eyeliner/plain-color (face-foreground 'default))
(setq-default eyeliner/default-darkness 35)
(setq-default eyeliner/default-desaturation 65)boilerplate
(use-package dash)
(defmacro with (name as value &rest body)
(declare (indent defun))
`(let ((,name ,value)) ,@body))
(defun transform (expr)
(if (ignore-errors (fboundp expr)) `(it (apply (quote ,expr) (list it)))
`(it ,expr)))
(defmacro pipeline (value &rest exprs)
(declare (indent defun))
(let* ((transforms (mapcar 'transform exprs))
(assignments (append `((it ,value)) transforms)))
`(let* ,assignments it)))
(setq eyeliner/segments '())
(defmacro eyeliner/defer-segment (&rest body)
`(setq eyeliner/segments (append eyeliner/segments '(,@body))))
(defun eyeliner/define-segments ()
(mapc 'eval eyeliner/segments))
(defun eyeliner/symbol (name suffix)
"Return a symbol with the given name and suffix"
(intern (format "eyeliner/%s-%s" name suffix)))
;; (eyeliner/symbol "foo" "bar")
(defun eyeliner/adjust-color (color &optional darkness desaturation)
"Return COLOR modified by DARKNESS and DESATURATION"
(pipeline color
(color-darken-name it (or darkness eyeliner/default-darkness))
(color-desaturate-name it (or desaturation eyeliner/default-desaturation))))
;; (eyeliner/adjust-color (badger-color "blue"))
faces
(defun eyeliner/make-face (symbol props)
"Create a face with the given SYMBOL and PROPS"
(face-spec-set symbol (list (cons t props))) symbol)
(defun eyeliner/make-active-face (name color &optional props)
"Create a face with the given COLOR and PROPS and return the
symbol based on NAME"
(with symbol as (eyeliner/symbol name "active")
(with props as (append props `(:foreground ,color))
(eyeliner/make-face symbol props))))
;; (eyeliner/make-active-face "foo" (badger-color "blue"))
(defun eyeliner/make-inactive-face (name color &optional darkness desaturation props)
"Create a face with the given COLOR modified by DARKNESS and
DESATURATION and any other PROPS. Returns the symbol based on
NAME."
(with color as (eyeliner/adjust-color color darkness desaturation)
(with symbol as (eyeliner/symbol name "inactive")
(with props as `(:foreground ,color)
(eyeliner/make-face symbol props)))))
;; (eyeliner/make-inactive-face "foo" (badger-color "blue"))
(defun eyeliner/make-face-pair (name color &optional darkness desaturation props)
"Return the a cons containing symbols, based on NAME, for newly
created faces. One face's COLOR will be modified by DARKNESS
and DESATURATION."
(let ((active-face (eyeliner/make-active-face name color props))
(inactive-face (eyeliner/make-inactive-face name color darkness desaturation props)))
(cons active-face inactive-face)))
;; (eyeliner/make-face-pair "foo" (badger-color "blue"))
(defun eyeliner/make-icon-face-pair (icon-name color &optional darkness desaturation props)
"Create a face suitable for a spaceline icon"
(let* ((props (append props `(:family ,family))))
(apply 'eyeliner/make-face-pair icon-name color darkness desaturation props)))
;; (eyeliner/make-icon-face-pair "git-branch" (badger-color "blue"))icons
(defun eyeliner/get-icon-factory (set-name)
"Return an icon factory for the given iconset"
(--when-let (all-the-icons--function-name set-name)
(when (fboundp it) it)))
;; (eyeliner/get-icon-factory 'octicon)
;; (apply (eyeliner/get-icon-factory 'octicon) '("git-branch"))
(defun eyeliner/get-icon-family (set-name)
"Return the family-name for a given iconset"
(--when-let (all-the-icons--family-name set-name)
(apply it '())))
;; (eyeliner/get-icon-family 'octicon)
(defun eyeliner/find-icon (icon-name)
"Return a cons containing an icon and its family-name"
(cl-loop for set-name in '(octicon faicon wicon fileicon material alltheicon)
for factory = (eyeliner/get-icon-factory set-name)
for icon = (ignore-errors (apply factory `(,icon-name)))
for family = (eyeliner/get-icon-family set-name)
if icon
return (cons icon family)))
;; (eyeliner/find-icon "lock")
(defmacro eyeliner/with-icon (icon-name &rest body)
"Execute body while binding icon and family"
(declare (indent defun))
`(--when-let (eyeliner/find-icon ,icon-name)
(cl-destructuring-bind (icon . family) it ,@body)))
;; (propertize (eyeliner/with-icon "git-branch" icon) 'face 'eyeliner/foo-active)api
style
(defmacro eyeliner/style (name color &optional darkness desaturation props)
"Define a function which will return propertized text with the
proper color based on the value of ACTIVE which is bound by
spaceline."
(declare (indent defun))
(cl-destructuring-bind (active-face . inactive-face)
(let ((color (eval color)))
(eyeliner/make-face-pair name color darkness desaturation props))
(with symbol as (eyeliner/symbol name "style")
`(defun ,symbol (text)
(propertize text
'font-lock-face (if active (quote ,active-face)
(quote ,inactive-face))
'face (if active (quote ,active-face)
(quote ,inactive-face)))))))
;; (eyeliner/style foo (badger-color "blue"))icon
(defmacro eyeliner/icon (name icon-name color &optional darkness desaturation props display)
"Define a function which will return propertized text with the
proper color based on the value of ACTIVE which is bound by
spaceline."
(declare (indent defun))
(eyeliner/with-icon icon-name
(cl-destructuring-bind (active-face . inactive-face)
(let ((color (eval color))
(face-name (format "%s-icon" name)))
(eyeliner/make-face-pair face-name color darkness desaturation props))
(with symbol as (eyeliner/symbol name "icon")
`(defun ,symbol ()
(propertize ,icon
'display (or ,display '((height 1.0) (raise 0.0)))
'font-lock-face (if active (quote ,active-face)
(quote ,inactive-face))
'face (if active (quote ,active-face)
(quote ,inactive-face))))))))
;; (eyeliner/icon branch-new "git-branch" (badger-color "yellow"))segments
buffer-modified
;; buffer modification icon
(eyeliner/icon unmodified "circle-o" eyeliner/cool-color)
(eyeliner/icon modified "dot-circle-o" eyeliner/warm-color)
(eyeliner/icon locked "diff-added" eyeliner/warm-color)
(eyeliner/defer-segment
(spaceline-define-segment eyeliner/buffer-modified
"An `all-the-icons' segment depiciting the current buffers state"
(let ((buffer-state (format-mode-line "%*")))
(cond
((string= buffer-state "-") (eyeliner/unmodified-icon))
((string= buffer-state "*") (eyeliner/modified-icon))
((string= buffer-state "%") (eyeliner/locked-icon))))))
buffer-name
;; buffer name
(eyeliner/style buffer-name eyeliner/plain-color)
(eyeliner/style buffer-name-modified eyeliner/warm-color)
(eyeliner/defer-segment
(spaceline-define-segment eyeliner/buffer-name
(let* ((buffer-state (format-mode-line "%*"))
(style (cond
((string= buffer-state "-") 'eyeliner/buffer-name-style)
((string= buffer-state "*") 'eyeliner/buffer-name-modified-style)
((string= buffer-state "%") 'eyeliner/buffer-name-modified-style))))
(apply style `(,(buffer-name))))))branch-icon
(eyeliner/icon branch "git-branch" eyeliner/cool-color)
(eyeliner/icon branch-diff "note_add" eyeliner/warm-color nil nil nil
'((raise -0.2)))
(eyeliner/defer-segment
(spaceline-define-segment eyeliner/branch-icon
(when vc-mode
(if (magit-anything-modified-p) (eyeliner/branch-diff-icon)
(eyeliner/branch-icon)))))branch-name
(eyeliner/style branch-clean eyeliner/cool-color)
(eyeliner/style branch-dirty eyeliner/warm-color)
(eyeliner/defer-segment
(spaceline-define-segment eyeliner/branch-name
(when vc-mode
(let ((branch (mapconcat 'concat (cdr (split-string vc-mode "[:-]")) "-")))
(if (magit-anything-modified-p) (eyeliner/branch-dirty-style branch)
(eyeliner/branch-clean-style branch))))))project-name
(eyeliner/style project-name eyeliner/plain-color)
(eyeliner/defer-segment
(spaceline-define-segment eyeliner/project-name
(when (projectile-project-p)
(eyeliner/project-name-style (projectile-project-name)))))mode-icon
(eyeliner/defer-segment
(spaceline-define-segment eyeliner/mode-icon
(let ((icon (all-the-icons-icon-for-mode major-mode)))
(when icon
(propertize icon
'help-echo (format "Major-mode: `%s'" major-mode)
'display '(raise 0)
'face `(
:foreground eyeliner/plain-color
:height 0.9
:family ,(all-the-icons-icon-family-for-mode major-mode)
:inherit))))))setup
(use-package spaceline
:after (magit)
:config
(setq-default mode-line-format
'("%e" (:eval (spaceline-ml-main))))
(spaceline-helm-mode 1)
(custom-set-faces
`(powerline-active2
((t (:background ,(badger-color "bg")))))
`(powerline-inactive2
((t (:background ,(badger-color "bg"))))))
(eyeliner/define-segments)
(spaceline-install 'main
'((eyeliner/buffer-modified)
(eyeliner/branch-icon :skip-alternate t :tight-right t)
(eyeliner/branch-name)
(eyeliner/project-name :skip-alternate t)
(eyeliner/mode-icon :skip-alternate t :tight-left t :tight-right t)
(eyeliner/buffer-name))
'(("%l:%c"))))







