mode-icons/mode-icons.el

747 lines
28 KiB
EmacsLisp
Raw Permalink Normal View History

;;; mode-icons.el --- Show icons for modes -*- lexical-binding: t; -*-
2012-11-10 23:12:36 +01:00
2016-02-21 13:43:50 +01:00
;; Copyright (C) 2013, 2016 Tom Willemse
;; 2016 Matthew L. Fidler
2012-11-10 23:12:36 +01:00
2013-06-02 14:45:06 +02:00
;; Author: Tom Willemse <tom@ryuslash.org>
2012-11-10 23:12:36 +01:00
;; Keywords: multimedia
2016-02-21 15:03:26 +01:00
;; Version: 0.3.0
2013-06-02 14:45:06 +02:00
;; URL: http://ryuslash.org/projects/mode-icons.html
;; Package-Requires: ((emacs "24") (cl-lib "0.5"))
2012-11-10 23:12:36 +01:00
;; 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 <http://www.gnu.org/licenses/>.
;;; Commentary:
2016-01-21 22:07:28 +01:00
;; This package provides a globalized minor mode that replaces the
;; major mode name in your mode-line and places like Ibuffer with an
;; icon. Currently the following programming modes are supported,
;; among others:
2012-11-10 23:12:36 +01:00
;;
2016-01-21 22:07:28 +01:00
;; - CSS
;; - Coffee
;; - Emacs-Lisp
;; - HTML
;; - Haml
;; - JavaScript
;; - Lisp
;; - nXML
;; - PHP
;; - Python
;; - Ruby
;; - Sass/Scss
;; - Scheme
;; - Shell-script
;; - Slim
;; - Snippet
;; - Web
;; - Yaml
;;
;; To enable this minor mode add the following line to your init file:
;;
;; (mode-icons-mode)
;;
;; As of version 0.3.0 this project includes some icons which use icon
;; fonts instead of images. These fonts are:
;;
;; - Font Awesome, found at URL `http://fontawesome.io/'.
;; - GitHub Octicons, found at URL `https://octicons.github.com/'.
;; - Font Mfizz, found at URL `http://fizzed.com/oss/font-mfizz'.
;;
;; You should have these installed if you want to use these icons,
;; otherwise you may get strange glyphs in your mode-line instead of
;; an icon.
2012-11-10 23:12:36 +01:00
;;; Code:
(require 'cl-lib)
(defgroup mode-icons nil
"Provide icons for major modes."
:group 'editing-basics
:group 'convenience)
2012-11-10 23:12:36 +01:00
(defconst mode-icons--directory
(if load-file-name
(file-name-directory load-file-name)
default-directory)
2012-11-10 23:17:42 +01:00
"Where mode-icons was loaded from.")
(defun mode-icons-get-icon-file (icon)
"Get the location of ICON.
ICON should be a file name with extension. The result is the
absolute path to ICON."
(concat mode-icons--directory "/icons/" icon))
2012-11-10 23:12:36 +01:00
2016-02-19 19:45:02 +01:00
(defmacro mode-icons-save-buffer-state (&rest body)
"Eval BODY,
then restore the buffer state under the assumption that no significant
modification has been made in BODY. A change is considered
significant if it affects the buffer text in any way that isn't
completely restored again. Changes in text properties like `face' or
`syntax-table' are considered insignificant. This macro allows text
properties to be changed, even in a read-only buffer.
This macro should be placed around all calculations which set
\"insignificant\" text properties in a buffer, even when the buffer is
known to be writeable. That way, these text properties remain set
even if the user undoes the command which set them.
This macro should ALWAYS be placed around \"temporary\" internal buffer
changes \(like adding a newline to calculate a text-property then
deleting it again\), so that the user never sees them on his
2016-02-21 13:44:04 +01:00
`buffer-undo-list'.
2016-02-19 19:45:02 +01:00
However, any user-visible changes to the buffer \(like auto-newlines\)
must not be within a `ergoemacs-save-buffer-state', since the user then
wouldn't be able to undo them.
The return value is the value of the last form in BODY.
This was stole/modified from `c-save-buffer-state'"
`(let* ((modified (buffer-modified-p)) (buffer-undo-list t)
(inhibit-read-only t) (inhibit-point-motion-hooks t)
before-change-functions after-change-functions
deactivate-mark
buffer-file-name buffer-file-truename ; Prevent primitives checking
; for file modification
)
(unwind-protect
(progn ,@body)
(and (not modified)
(buffer-modified-p)
(set-buffer-modified-p nil)))))
(defmacro mode-icons-define-font (font)
"Define FONT for `mode-icons'."
`(progn
(defvar ,(intern (format "mode-icons-font-spec-%s" font))
(font-spec :name ,(format "%s" font)))
(defvar ,(intern (format "mode-icons-font-%s" font))
(find-font ,(intern (format "mode-icons-font-spec-%s" font))))))
(mode-icons-define-font "github-octicons")
2016-02-10 06:20:16 +01:00
(mode-icons-define-font "font-mfizz")
2016-02-10 07:01:23 +01:00
(mode-icons-define-font "FontAwesome")
(defcustom mode-icons
`(("CSS" "css" xpm)
2015-12-24 06:39:38 +01:00
("Coffee" "coffee" xpm)
2016-01-06 06:44:36 +01:00
("Compilation" "compile" xpm)
2015-12-24 06:39:38 +01:00
("Emacs-Lisp" "emacs" xpm)
("Lisp Interaction" "emacs" xpm)
("HTML" "html" xpm)
2015-12-24 06:39:38 +01:00
("Haml" "haml" xpm)
("Image[imagemagick]" "svg" xpm)
2016-01-18 08:22:24 +01:00
("Inf-Ruby" "infruby" xpm)
2015-12-24 06:39:38 +01:00
("JavaScript" "js" xpm)
("Lisp" "cl" xpm)
2016-01-14 09:21:22 +01:00
("nXML" "xml" xpm)
2015-12-23 07:12:18 +01:00
("Org" "org" xpm)
2015-12-24 06:39:38 +01:00
("PHP" "php" xpm)
2016-01-21 21:49:57 +01:00
("PHP/l" "php" xpm)
2016-01-18 08:22:24 +01:00
("Projectile Rails Server" "rails" xpm)
2015-12-24 06:39:38 +01:00
("Python" "python" xpm)
2015-12-23 10:56:44 +01:00
("Ruby" "ruby" xpm)
2016-02-12 07:20:37 +01:00
("ESS\\[S\\]" "R" xpm)
("ESS\\[SAS\\]" "sas" xpm)
("ESS\\[BUGS\\]" #xf188 FontAwesome)
2016-01-20 22:21:05 +01:00
("iESS" "R" xpm)
2015-12-23 11:20:22 +01:00
("SCSS" "sass" xpm)
2015-12-24 06:39:38 +01:00
("Sass" "sass" xpm)
("Scheme" "scheme" xpm)
("Shell-script" "bash" xpm)
("Slim" "slim" xpm)
2016-01-21 21:49:57 +01:00
("Snippet" "yas" xpm)
2016-01-14 10:33:19 +01:00
("Term" "term" xpm)
2016-01-14 09:21:22 +01:00
("Web" "html" xpm)
("XML" "xml" xpm)
2015-12-23 10:56:44 +01:00
("YAML" "yaml" xpm)
2015-12-24 06:39:38 +01:00
("YASnippet" "yas" xpm)
2016-01-22 05:50:31 +01:00
(" yas" "yas" xpm)
(" hs" "hs" xpm)
2016-02-12 05:37:00 +01:00
("Markdown" #xf0c9 github-octicons)
("Scala" #xf15b font-mfizz)
("Magit" #xf1d2 FontAwesome)
(" Pulls" #xf092 FontAwesome)
("Zip-Archive" #xf1c6 FontAwesome)
("ARev" #xf021 FontAwesome)
("Calc\\(ulator\\)?" #xf1ec FontAwesome)
("Debug.*" #xf188 FontAwesome)
2016-02-12 07:20:37 +01:00
("Debug.*" #xf188 FontAwesome)
2016-02-12 05:37:00 +01:00
("Calendar" #xf073 FontAwesome)
("Help" #xf059 FontAwesome)
("WoMan" #xf05a FontAwesome)
("C/l" #xf107 font-mfizz)
("Custom" #xf013 FontAwesome)
2016-02-11 16:28:17 +01:00
("\\`Go\\'" "go" xpm)
2016-02-05 15:53:23 +01:00
(" Rbow" "rainbow" xpm)
2016-02-11 20:46:46 +01:00
(" Golden" "golden" xpm) ;; Icon created by Arthur Shlain from Noun Project
2016-02-12 05:00:56 +01:00
("BibTeX" "bibtex" xpm)
2016-02-12 05:37:00 +01:00
("C[+][+]/l" #xf10c font-mfizz)
2016-02-12 06:03:36 +01:00
("C[#]/l" #xf10d font-mfizz)
("Elixir" #xf115 font-mfizz)
("Erlang" #xf116 font-mfizz)
("Haskell" #xf126 font-mfizz)
("Clojure" #xf10a font-mfizz)
("Java/l" #xf12b font-mfizz)
("C?Perl" #xf148 font-mfizz)
2016-02-12 06:30:38 +01:00
("Octave" "octave" xpm)
2016-02-12 06:45:14 +01:00
("AHK" "autohotkey" xpm)
2016-02-18 15:39:26 +01:00
("Info" #xf05a FontAwesome)
2016-02-19 19:04:58 +01:00
("Narrow" #xf066 FontAwesome)
(read-only #xf023 FontAwesome)
(writable #xf09c FontAwesome)
2016-02-19 19:45:02 +01:00
(save #xf0c7 FontAwesome)
2016-02-20 07:09:35 +01:00
(saved "" nil)
2016-02-19 23:00:18 +01:00
(apple #xf179 FontAwesome)
(win #xf17a FontAwesome)
;; FIXME: use lsb_release to determine Linux variant and choose appropriate icon
(unix #xf166 font-mfizz) ;; Use ubuntu, since I think it is the most common.
2016-02-20 07:30:19 +01:00
(undecided #xf128 FontAwesome)
2016-02-20 07:09:35 +01:00
("Text\\'" #xf0f6 FontAwesome)
2016-01-25 15:45:40 +01:00
;; Diminished modes
2016-02-12 06:30:38 +01:00
("\\(?:ElDoc\\|Anzu\\|SP\\|Guide\\|PgLn\\|Undo-Tree\\|Ergo.*\\|,\\|Isearch\\|Ind\\|Fly\\)" nil nil)
2016-02-11 20:25:23 +01:00
)
2016-01-22 05:50:31 +01:00
"Icons for major and minor modes.
Each specificatioun is a list with the first element being the
name of the major mode. The second the name of the icon file,
without the extension. And the third being the type of icon."
:type '(repeat
2016-02-19 19:04:58 +01:00
(list (choice
(string :tag "Regular Expression")
(const :tag "Read Only Indicator" read-only)
2016-02-19 23:00:18 +01:00
(const :tag "Writable Indicator" writable)
(const :tag "Saved" saved)
(const :tag "Save" save)
(const :tag "Apple" apple)
(const :tag "Windows" win)
(const :tag "Unix" unix))
(choice
(string :tag "Icon Name")
2016-02-12 05:37:00 +01:00
(integer :tag "Font Glyph Code")
(const :tag "Suppress" nil))
(choice
(const :tag "text" nil)
(const :tag "Octicons" github-octicons)
2016-02-10 06:20:16 +01:00
(const :tag "Fizzed" font-mfizz)
2016-02-10 07:35:46 +01:00
(const :tag "Font Awesome" FontAwesome)
(const :tag "png" png)
(const :tag "gif" gif)
(const :tag "jpeg" jpeg)
2016-02-21 14:24:16 +01:00
(const :tag "jpg" jpg)
(const :tag "xbm" xbm)
(const :tag "xpm" xpm))))
:group 'mode-icons)
2016-02-21 13:44:04 +01:00
2016-01-22 05:50:31 +01:00
(defun mode-icons-get-icon-display (icon type)
"Get the value for the display property of ICON having TYPE.
ICON should be a string naming the file of the icon, without its
extension. Type should be a symbol designating the file type for
the icon."
(let ((icon-path (mode-icons-get-icon-file
(concat icon "." (symbol-name type)))))
`(image :type ,(or (and (eq type 'jpg) 'jpeg) type) :file ,icon-path :ascent center)))
2016-01-22 22:54:31 +01:00
(defcustom mode-icons-minor-mode-base-text-properties
'('help-echo nil
2016-01-22 22:54:31 +01:00
'mouse-face 'mode-line-highlight
'local-map mode-line-minor-mode-keymap)
"List of text propeties to apply to every minor mode."
:type '(repeat sexp)
:group 'mode-icons)
(defcustom mode-icons-major-mode-base-text-properties
'('help-echo "Major mode\nmouse-1: Display major mode menu\nmouse-2: Show help for major mode\nmouse-3: Toggle minor modes"
'mouse-face 'mode-line-highlight
'local-map mode-line-major-mode-keymap)
"List of text propeties to apply to every major mode."
:type '(repeat sexp)
:group 'mode-icons)
2016-02-19 06:13:20 +01:00
(defcustom mode-icons-narrow-text-properties
'('local-map
'(keymap
(mode-line keymap
(mouse-2 . mode-line-widen)))
'mouse-face 'mode-line-highlight 'help-echo "mouse-2: Remove narrowing from buffer")
"List of text propeties to apply to narrowing buffer indicator."
:type '(repeat sexp)
:group 'mode-icons)
2016-02-19 19:04:58 +01:00
(defcustom mode-icons-read-only-text-properties
'('mouse-face 'mode-line-highlight 'local-map
'(keymap
(mode-line keymap
(mouse-1 . mode-line-toggle-read-only)))
'help-echo 'mode-line-read-only-help-echo)
"List of text propeties to apply to read-only buffer indicator."
:type '(repeat sexp)
:group 'mode-icons)
2016-02-19 19:45:02 +01:00
(defcustom mode-icons-modified-text-properties
'('mouse-face 'mode-line-highlight
2016-02-21 14:24:16 +01:00
'local-map
'(keymap
(mode-line keymap
(mouse-1 . mode-icons-save-buffer)
(mouse-3 . mode-line-toggle-modified)))
'help-echo 'mode-icons-modified-help-echo)
2016-02-19 19:45:02 +01:00
"List of text propeties to apply to read-only buffer indicator."
:type '(repeat sexp)
:group 'mode-icons)
(defun mode-icons-save-buffer (event)
"Save buffer from mode line.
Use EVENT to determine location."
(interactive "e")
(with-selected-window (posn-window (event-start event))
(call-interactively (key-binding (where-is-internal 'save-buffer global-map t)))
2016-02-19 19:45:02 +01:00
(force-mode-line-update)))
(defun mode-icons-modified-help-echo (window _object _point)
"Return help text specifying WINDOW's buffer modification status."
(format "Buffer is %smodified\nmouse-1: Save Buffer\nmouse-3: Toggle modification state"
2016-02-21 14:24:16 +01:00
(if (buffer-modified-p (window-buffer window)) "" "not ")))
2016-02-19 19:45:02 +01:00
(defcustom mode-icons-read-only-text-properties
'('mouse-face 'mode-line-highlight 'local-map
'(keymap
(mode-line keymap
(mouse-1 . mode-line-toggle-read-only)))
'help-echo 'mode-line-read-only-help-echo)
"List of text propeties to apply to read-only buffer indicator."
:type '(repeat sexp)
:group 'mode-icons)
2016-01-22 22:54:31 +01:00
(defvar mode-icons-powerline-p nil)
(defun mode-icons-need-update-p ()
"Determine if the mode-icons need an update."
2016-01-22 22:54:31 +01:00
(not (or (and (boundp 'rich-minority-mode) rich-minority-mode)
(member 'sml/pos-id-separator mode-line-format)
(string-match-p "powerline" (prin1-to-string mode-line-format)))))
(defvar mode-icons-font-register-alist nil
"Alist of characters supported.")
(defun mode-icons-supported-font-p (char font &optional dont-register)
"Determine if the CHAR is supported in FONT.
When DONT-REGISTER is non-nil, don't register the font.
Otherwise, register the font for use in the mode-line and
everywhere else."
(when (and (or (integerp char)
(and (stringp char) (= 1 (length char))))
(boundp (intern (format "mode-icons-font-spec-%s" font)))
(symbol-value (intern (format "mode-icons-font-spec-%s" font))))
(let* ((char (or (and (integerp char) char)
(and (stringp char) (= 1 (length char))
(aref (vconcat char) 0))))
(found-char-p (assoc char mode-icons-font-register-alist))
(char-font-p (and found-char-p (eq (cdr found-char-p) font))))
(cond
(char-font-p t)
(found-char-p t)
(t ;; not yet registered.
(set-fontset-font t (cons char char) (symbol-value (intern (format "mode-icons-font-spec-%s" font))))
(push (cons char font) mode-icons-font-register-alist)
t)))))
2016-02-09 17:09:40 +01:00
(defun mode-icons-supported-p (icon-spec)
"Determine if ICON-SPEC is suppored on your system."
(or
2016-02-09 17:11:24 +01:00
(and (or (eq (nth 2 icon-spec) nil) (eq (nth 1 icon-spec) nil)) t)
(mode-icons-supported-font-p (nth 1 icon-spec) (nth 2 icon-spec) t)
(and (eq (nth 2 icon-spec) 'jpg) (image-type-available-p 'jpeg))
(and (image-type-available-p (nth 2 icon-spec)))))
(defun mode-icons-propertize-mode (mode icon-spec)
"Propertize MODE with ICON-SPEC.
MODE should be a string, the name of the mode to propertize.
ICON-SPEC should be a specification from `mode-icons'."
2016-02-19 19:45:02 +01:00
(mode-icons-save-buffer-state ;; Otherwise may cause issues with trasient mark mode
(let (tmp)
(cond
((and (stringp mode) (get-text-property 0 'mode-icons-p mode))
mode)
((not (nth 1 icon-spec))
"")
((and (stringp (nth 1 icon-spec)) (not (nth 2 icon-spec)))
(propertize (nth 1 icon-spec) 'display (nth 1 icon-spec)
2016-02-21 14:24:16 +01:00
'mode-icons-p t))
2016-02-19 19:45:02 +01:00
((mode-icons-supported-font-p (nth 1 icon-spec) (nth 2 icon-spec))
;; (propertize mode 'display (nth 1 icon-spec) 'mode-icons-p t)
;; Use `compose-region' because it allows clicable text.
(with-temp-buffer
2016-02-21 14:24:16 +01:00
(if (stringp mode)
(insert mode)
(insert (or (and (integerp (nth 1 icon-spec))
(make-string 1 (nth 1 icon-spec)))
(nth 1 icon-spec))))
(compose-region (point-min) (point-max) (or (and (integerp (nth 1 icon-spec))
(make-string 1 (nth 1 icon-spec)))
(nth 1 icon-spec)))
(put-text-property (point-min) (point-max) 'mode-icons-p t)
(buffer-string)))
2016-02-19 19:45:02 +01:00
(t (propertize (format "%s" mode) 'display (mode-icons-get-icon-display (nth 1 icon-spec) (nth 2 icon-spec)) 'mode-icons-p t))))))
2016-01-22 16:44:27 +01:00
(defun mode-icons-get-icon-spec (mode)
2016-02-09 15:05:13 +01:00
"Get icon spec for MODE based on regular expression."
2016-01-22 16:44:27 +01:00
(catch 'found-mode
(dolist (item mode-icons)
(when (and (mode-icons-supported-p item)
2016-02-19 19:04:58 +01:00
(or
(and
(stringp (car item))
(stringp mode)
(string-match-p (car item) mode))
(and
(symbolp (car item))
(symbolp mode)
(eq mode (car item)))))
(throw 'found-mode item)))
2016-01-22 16:44:27 +01:00
nil))
2016-02-20 07:14:52 +01:00
(defcustom mode-icons-show-mode-name nil
"Show Icon and `mode-name'."
:type 'boolean
:group 'mode-icons)
2016-01-22 05:50:31 +01:00
(defun mode-icons-get-mode-icon (mode)
"Get the icon for MODE, if there is one."
(let* ((mode-name (format-mode-line mode))
2016-01-22 16:44:27 +01:00
(icon-spec (mode-icons-get-icon-spec mode-name)))
(if icon-spec
2016-02-20 07:14:52 +01:00
(if mode-icons-show-mode-name
(concat (mode-icons-propertize-mode mode-name icon-spec) " " mode-name)
(mode-icons-propertize-mode mode-name icon-spec))
mode-name)))
2012-11-10 23:12:36 +01:00
2016-01-22 17:47:32 +01:00
(defvar mode-icons-cached-mode-name nil
"Cached mode name to restore when disabling mode-icons.")
2016-01-22 05:50:31 +01:00
(defun mode-icons-set-mode-icon (mode)
"Set the icon for MODE."
2016-01-22 17:47:32 +01:00
(unless mode-icons-cached-mode-name
(set (make-local-variable 'mode-icons-cached-mode-name)
mode-name)
2016-01-22 17:47:32 +01:00
(setq mode-name (mode-icons-get-mode-icon mode))))
(defun mode-icons-major-mode-icons-undo ()
"Undo the `mode-name' icons."
2016-01-22 17:47:32 +01:00
(dolist (b (buffer-list))
(with-current-buffer b
(when mode-icons-cached-mode-name
(setq mode-name mode-icons-cached-mode-name
mode-icons-cached-mode-name nil)))))
2016-01-22 17:47:32 +01:00
(defun mode-icons-major-mode-icons ()
"Apply mode name icons on all buffers."
2016-01-22 17:47:32 +01:00
(dolist (b (buffer-list))
(with-current-buffer b
(mode-icons-set-current-mode-icon))))
2012-11-10 23:12:36 +01:00
2016-01-22 05:50:31 +01:00
(defun mode-icons-set-current-mode-icon ()
"Set the icon for the current major mode."
2016-01-22 05:50:31 +01:00
(mode-icons-set-mode-icon mode-name))
2012-11-10 23:12:36 +01:00
2016-01-22 07:23:45 +01:00
(defvar mode-icons-set-minor-mode-icon-alist nil)
(defun mode-icons-set-minor-mode-icon-undo ()
"Undo minor modes."
2016-01-22 07:23:45 +01:00
(let (minor)
(dolist (mode mode-icons-set-minor-mode-icon-alist)
(setq minor (assq (car mode) minor-mode-alist))
(when minor
(setcdr minor (cdr mode)))))
2016-01-22 22:54:31 +01:00
(setq mode-icons-set-minor-mode-icon-alist nil)
(force-mode-line-update))
2016-01-22 07:23:45 +01:00
(defcustom mode-icons-separate-images-with-spaces t
"Separate minor-mode icons with spaces."
:type 'boolean
:group 'mode-icons)
2016-01-22 07:23:45 +01:00
(defun mode-icons-set-minor-mode-icon ()
"Set the icon for the minor modes."
(let (icon-spec mode-name minor)
(dolist (mode minor-mode-alist)
(unless (assq (car mode) mode-icons-set-minor-mode-icon-alist)
(setq mode-name (format-mode-line mode)
icon-spec (mode-icons-get-icon-spec mode-name))
(when icon-spec
(setq minor (assq (car mode) minor-mode-alist))
(when minor
(or (assq (car mode) mode-icons-set-minor-mode-icon-alist)
(push (copy-sequence minor) mode-icons-set-minor-mode-icon-alist))
(setq mode-name (replace-regexp-in-string "^ " "" mode-name)
mode-name (mode-icons-propertize-mode mode-name icon-spec))
(if (string= "" mode-name)
(setcdr minor (list ""))
(setcdr minor (list (concat (or (and mode-icons-separate-images-with-spaces " ") "")
mode-name)))))))))
2016-01-22 19:05:08 +01:00
(force-mode-line-update))
2016-01-22 07:23:45 +01:00
(defun mode-icons--generate-major-mode-item ()
"Give rich strings needed for `major-mode' viewing."
(eval `(propertize ,mode-name ,@mode-icons-major-mode-base-text-properties)))
2016-01-22 22:54:31 +01:00
(defun mode-icons--generate-minor-mode-list ()
"Extracts all rich strings necessary for the minor mode list."
(delete " " (delete "" (mapcar (lambda(mode)
(concat " " (eval `(propertize ,mode ,@mode-icons-minor-mode-base-text-properties))))
(split-string (format-mode-line minor-mode-alist))))))
2016-01-22 22:54:31 +01:00
2016-02-19 06:13:20 +01:00
(defun mode-icons--generate-narrow ()
"Extracts all rich strings necessary for narrow indicator."
(let (icon-spec)
(delete " " (delete "" (mapcar (lambda(mode)
(concat " " (eval `(propertize
,(if (setq icon-spec (mode-icons-get-icon-spec mode))
(mode-icons-propertize-mode mode icon-spec)
mode)
,@mode-icons-narrow-text-properties))))
(split-string (format-mode-line "%n")))))))
2016-02-19 19:04:58 +01:00
2016-02-20 07:09:35 +01:00
(defcustom mode-icons-read-only-space t
"Add Space after read-only icon."
:type 'boolean
:group 'mode-icons)
2016-02-19 19:04:58 +01:00
(defun mode-icons--read-only-status ()
"Get Read Only Status icon."
(eval `(propertize
,(let ((ro (format-mode-line "%1*"))
icon-spec)
2016-02-20 07:09:35 +01:00
(setq ro (cond
((string= "%" ro)
(if (setq icon-spec (mode-icons-get-icon-spec 'read-only))
(mode-icons-propertize-mode 'read-only icon-spec)
ro))
(t
(if (setq icon-spec (mode-icons-get-icon-spec 'writable))
(mode-icons-propertize-mode 'writable icon-spec)
ro))))
(when (and mode-icons-read-only-space
(not (string= ro "")))
(setq ro (concat ro " ")))
ro)
2016-02-19 19:04:58 +01:00
,@mode-icons-read-only-text-properties)))
2016-02-20 07:09:35 +01:00
(defcustom mode-icons-modified-status-space t
"Add Space to modified status."
:type 'boolean
:group 'mode-icons)
2016-02-19 19:45:02 +01:00
(defun mode-icons--modified-status ()
"Get modified status icon."
(eval `(propertize
,(let ((mod (format-mode-line "%1+"))
icon-spec)
2016-02-20 07:09:35 +01:00
(setq mod (cond
((string= "*" mod)
(if (setq icon-spec (mode-icons-get-icon-spec 'save))
(mode-icons-propertize-mode 'save icon-spec)
mod))
(t
(if (setq icon-spec (mode-icons-get-icon-spec 'saved))
(mode-icons-propertize-mode 'saved icon-spec)
mod))))
(when (and mode-icons-modified-status-space
(not (string= mod "")))
(setq mod (concat mod " "))))
2016-02-19 19:45:02 +01:00
,@mode-icons-modified-text-properties)))
2016-01-22 22:54:31 +01:00
;; Based on rich-minority by Artur Malabarba
(defvar mode-icons--backup-construct nil)
(defvar mode-icons--mode-line-construct
'(:eval (mode-icons--generate-minor-mode-list))
"Construct used to replace `minor-mode-alist'.")
(defvar mode-icons--major-backup-construct nil)
(defvar mode-icons--major-construct
'(:eval (mode-icons--generate-major-mode-item))
"Construct used to replace `mode-name'.")
2016-02-19 06:13:20 +01:00
(defvar mode-icons--narrow-backup-construct nil)
(defvar mode-icons--narrow-construct
'(:eval (mode-icons--generate-narrow))
"Construct used to replace %n in `mode-line-modes'.")
2016-02-19 19:04:58 +01:00
(defvar mode-icons--read-only-backup-construct nil)
(defvar mode-icons--read-only-construct
'(:eval (mode-icons--read-only-status))
"Construct used to replace %1* in `mode-line-modified'.")
2016-02-19 19:45:02 +01:00
(defvar mode-icons--modified-backup-construct nil)
(defvar mode-icons--modified-construct
'(:eval (mode-icons--modified-status))
"Construct used to replace %1+ in `mode-line-modified'.")
2016-02-19 23:00:18 +01:00
(defvar mode-icons--backup-eol-construct nil)
(defvar mode-icons--eol-construct
'(:eval (mode-icons--mode-line-eol-desc))
"End of Line Construct.")
2016-02-20 07:09:35 +01:00
(defcustom mode-icons-eol-space t
"Add a space to the end of line specification."
:type 'boolean
:group 'mode-icons)
(defcustom mode-icons-eol-text nil
"Describe end of line type
\(Unix) -> LF
\(DOS) -> CRLF
\(Mac) -> CR"
:type 'boolean
:group 'mode-icons)
2016-02-19 23:00:18 +01:00
(defun mode-icons--mode-line-eol-desc (&optional string)
"Modify `mode-line-eol-desc' to have icons.
STRING is the string to modify, or if absent, the value from `mode-line-eol-desc'."
(let* ((str (or string (mode-line-eol-desc)))
(props (text-properties-at 0 str))
2016-02-20 07:30:19 +01:00
(lt2 "")
2016-02-19 23:00:18 +01:00
icon-spec)
(setq str (cond
((string= "(Unix)" str)
2016-02-20 07:09:35 +01:00
(setq lt2 " LF")
2016-02-19 23:00:18 +01:00
(if (setq icon-spec (mode-icons-get-icon-spec 'unix))
(mode-icons-propertize-mode 'unix icon-spec)
str))
((or (string= str "(DOS)")
(string= str "\\"))
2016-02-20 07:09:35 +01:00
(setq lt2 " CRLF")
2016-02-19 23:00:18 +01:00
(if (setq icon-spec (mode-icons-get-icon-spec 'win))
(mode-icons-propertize-mode 'win icon-spec)
str))
((string= str "(Mac)")
2016-02-20 07:09:35 +01:00
(setq lt2 " CR")
2016-02-19 23:00:18 +01:00
(if (setq icon-spec (mode-icons-get-icon-spec 'apple))
(mode-icons-propertize-mode 'apple icon-spec)
str))
2016-02-21 14:24:16 +01:00
((string= str ":")
(setq lt2 " Undecided")
(if (setq icon-spec (mode-icons-get-icon-spec 'undecided))
2016-02-20 07:30:19 +01:00
(mode-icons-propertize-mode 'undecided icon-spec)
str))
2016-02-19 23:00:18 +01:00
(t str)))
2016-02-20 07:09:35 +01:00
(when mode-icons-eol-text
(setq str (concat str lt2)))
(when (and mode-icons-eol-space
(not (string= "" str)))
(setq str (concat str " ")))
2016-02-19 23:00:18 +01:00
(add-text-properties 0 (length str) props str)
str))
2016-02-19 19:45:02 +01:00
2016-01-22 22:54:31 +01:00
(defun mode-icons-fix (&optional enable)
"Fix mode-icons."
(if enable
(let ((place (or (member 'minor-mode-alist mode-line-modes)
(cl-member-if
(lambda (x) (and (listp x)
(equal (car x) :propertize)
(equal (cadr x) '("" minor-mode-alist))))
mode-line-modes)))
(place-major (cl-member-if
(lambda(x)
(and (listp x)
(equal (car x) :propertize)
(equal (cadr x) '("" mode-name))))
2016-02-19 06:13:20 +01:00
mode-line-modes))
(place-narrow (cl-member-if
(lambda(x)
(and (stringp x) (string= "%n" x)))
2016-02-19 19:04:58 +01:00
mode-line-modes))
(place-ro (cl-member-if
(lambda(x)
(and (stringp x) (string-match-p "%[0-9]*[*]" x)))
2016-02-19 19:45:02 +01:00
mode-line-modified))
(place-mod (cl-member-if
2016-02-19 23:00:18 +01:00
(lambda(x)
(and (stringp x) (string-match-p "%[0-9]*[+]" x)))
mode-line-modified))
(place-eol (cl-member-if
(lambda(x)
(and (listp x)
(equal (car x) :eval)
(eq (caadr x) 'mode-line-eol-desc)))
mode-line-mule-info)))
2016-01-22 22:54:31 +01:00
(when place
(setq mode-icons--backup-construct (car place))
(setcar place mode-icons--mode-line-construct))
(when place-major
(setq mode-icons--major-backup-construct (car place-major))
2016-02-19 06:13:20 +01:00
(setcar place-major mode-icons--major-construct))
(when place-narrow
(setq mode-icons--narrow-backup-construct (car place-narrow))
2016-02-19 19:04:58 +01:00
(setcar place-narrow mode-icons--narrow-construct))
(when place-ro
(setq mode-icons--read-only-backup-construct (car place-ro))
2016-02-19 19:45:02 +01:00
(setcar place-ro mode-icons--read-only-construct))
(when place-mod
(setq mode-icons--modified-backup-construct (car place-mod))
2016-02-19 23:00:18 +01:00
(setcar place-mod mode-icons--modified-construct))
(when place-eol
(setq mode-icons--backup-eol-construct (car place-eol))
(setcar place-eol mode-icons--eol-construct)))
(let ((place (member mode-icons--mode-line-construct mode-line-modes))
2016-02-19 23:00:18 +01:00
(place-major (member mode-icons--major-construct mode-line-modes))
(place-narrow (member mode-icons--narrow-construct mode-line-modes))
(place-ro (member mode-icons--read-only-construct mode-line-modified))
(place-mod (member mode-icons--modified-construct mode-line-modified))
(place-eol (member mode-icons--eol-construct mode-line-mule-info)))
2016-01-22 22:54:31 +01:00
(when place
(setcar place mode-icons--backup-construct))
(when place-major
2016-02-19 06:13:20 +01:00
(setcar place-major mode-icons--major-backup-construct))
(when place-narrow
2016-02-19 19:04:58 +01:00
(setcar place-narrow mode-icons--narrow-backup-construct))
(when place-ro
2016-02-19 19:45:02 +01:00
(setcar place-ro mode-icons--read-only-backup-construct))
2016-02-21 13:44:04 +01:00
(when place-mod
2016-02-19 23:00:18 +01:00
(setcar place-mod mode-icons--modified-backup-construct))
(when place-eol
(setcar place-eol mode-icons--backup-eol-construct)))))
2016-01-22 22:54:31 +01:00
;;;###autoload
(define-minor-mode mode-icons-mode
"Replace the name of the current major mode with an icon."
:global t
(if mode-icons-mode
(progn
2016-01-22 05:50:31 +01:00
(add-hook 'after-change-major-mode-hook 'mode-icons-set-current-mode-icon)
(add-hook 'after-change-major-mode-hook 'mode-icons-set-minor-mode-icon)
2016-01-22 22:54:31 +01:00
(mode-icons-fix t)
(mode-icons-set-minor-mode-icon)
(mode-icons-major-mode-icons))
2016-01-22 07:23:45 +01:00
(remove-hook 'after-change-major-mode-hook 'mode-icons-set-minor-mode-icon)
(remove-hook 'after-change-major-mode-hook 'mode-icons-set-current-mode-icon)
2016-01-22 17:47:32 +01:00
(mode-icons-set-minor-mode-icon-undo)
2016-01-22 22:54:31 +01:00
(mode-icons-major-mode-icons-undo)
(mode-icons-fix)))
2012-11-10 23:12:36 +01:00
(provide 'mode-icons)
;;; mode-icons.el ends here
;; Local Variables:
;; indent-tabs-mode: nil
;; End: