Commit | Line | Data |
---|---|---|
9a130e19 AK |
1 | ;;; guix-prettify.el --- Prettify Guix store file names |
2 | ||
c10521e9 | 3 | ;; Copyright © 2014, 2015 Alex Kost <alezost@gmail.com> |
9a130e19 AK |
4 | |
5 | ;; This file is part of GNU Guix. | |
6 | ||
7 | ;; GNU Guix is free software; you can redistribute it and/or modify | |
8 | ;; it under the terms of the GNU General Public License as published by | |
9 | ;; the Free Software Foundation, either version 3 of the License, or | |
10 | ;; (at your option) any later version. | |
11 | ||
12 | ;; GNU Guix is distributed in the hope that it will be useful, | |
13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | ;; GNU General Public License for more details. | |
16 | ||
17 | ;; You should have received a copy of the GNU General Public License | |
18 | ;; along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | ||
20 | ;;; Commentary: | |
21 | ||
22 | ;; This package provides minor-mode for prettifying Guix store file | |
23 | ;; names — i.e., after enabling `guix-prettify-mode', | |
24 | ;; '/gnu/store/72f54nfp6g1hz873w8z3gfcah0h4nl9p-foo-0.1' names will be | |
25 | ;; replaced with '/gnu/store/…-foo-0.1' in the current buffer. There is | |
26 | ;; also `global-guix-prettify-mode' for global prettifying. | |
27 | ||
28 | ;; To install, add the following to your emacs init file: | |
29 | ;; | |
30 | ;; (add-to-list 'load-path "/path/to/dir-with-guix-prettify") | |
31 | ;; (autoload 'guix-prettify-mode "guix-prettify" nil t) | |
32 | ;; (autoload 'global-guix-prettify-mode "guix-prettify" nil t) | |
33 | ||
34 | ;; If you want to enable/disable composition after "M-x font-lock-mode", | |
35 | ;; use the following setting: | |
36 | ;; | |
37 | ;; (setq font-lock-extra-managed-props | |
38 | ;; (cons 'composition font-lock-extra-managed-props)) | |
39 | ||
40 | ;; Credits: | |
41 | ;; | |
42 | ;; Thanks to Ludovic Courtès for the idea of this package. | |
43 | ;; | |
44 | ;; Thanks to the authors of `prettify-symbols-mode' (part of Emacs 24.4) | |
45 | ;; and "pretty-symbols.el" <http://github.com/drothlis/pretty-symbols> | |
46 | ;; for the code. It helped to write this package. | |
47 | ||
48 | ;;; Code: | |
49 | ||
c10521e9 AK |
50 | (require 'guix-utils) |
51 | ||
9a130e19 AK |
52 | (defgroup guix-prettify nil |
53 | "Prettify Guix store file names." | |
54 | :prefix "guix-prettify-" | |
935d079b | 55 | :group 'guix |
9a130e19 AK |
56 | :group 'font-lock |
57 | :group 'convenience) | |
58 | ||
59 | (defcustom guix-prettify-char ?… | |
60 | "Character used for prettifying." | |
61 | :type 'character | |
62 | :group 'guix-prettify) | |
63 | ||
64 | (defcustom guix-prettify-decompose-force nil | |
65 | "If non-nil, remove any composition. | |
66 | ||
67 | By default, after disabling `guix-prettify-mode', | |
68 | compositions (prettifying names with `guix-prettify-char') are | |
69 | removed only from strings matching `guix-prettify-regexp', so | |
70 | that compositions created by other modes are left untouched. | |
71 | ||
72 | Set this variable to non-nil, if you want to remove any | |
73 | composition unconditionally (like `prettify-symbols-mode' does). | |
74 | Most likely it will do no harm and will make the process of | |
75 | disabling `guix-prettify-mode' a little faster." | |
76 | :type 'boolean | |
77 | :group 'guix-prettify) | |
78 | ||
79 | (defcustom guix-prettify-regexp | |
67ee7c95 AK |
80 | ;; The following file names / URLs should be abbreviated: |
81 | ||
82 | ;; /gnu/store/…-foo-0.1 | |
83 | ;; /nix/store/…-foo-0.1 | |
84 | ;; http://hydra.gnu.org/nar/…-foo-0.1 | |
85 | ;; http://hydra.gnu.org/log/…-foo-0.1 | |
86 | ||
87 | (rx "/" (or "store" "nar" "log") "/" | |
9a130e19 AK |
88 | ;; Hash-parts do not include "e", "o", "u" and "t". See base32Chars |
89 | ;; at <https://github.com/NixOS/nix/blob/master/src/libutil/hash.cc> | |
90 | (group (= 32 (any "0-9" "a-d" "f-n" "p-s" "v-z")))) | |
91 | "Regexp matching file names for prettifying. | |
92 | ||
93 | Disable `guix-prettify-mode' before modifying this variable and | |
94 | make sure to modify `guix-prettify-regexp-group' if needed. | |
95 | ||
96 | Example of a \"deeper\" prettifying: | |
97 | ||
98 | (setq guix-prettify-regexp \"store/[[:alnum:]]\\\\\\={32\\\\}\" | |
99 | guix-prettify-regexp-group 0) | |
100 | ||
101 | This will transform | |
102 | '/gnu/store/72f54nfp6g1hz873w8z3gfcah0h4nl9p-foo-0.1' into | |
103 | '/gnu/…-foo-0.1'" | |
104 | :type 'regexp | |
105 | :group 'guix-prettify) | |
106 | ||
107 | (defcustom guix-prettify-regexp-group 1 | |
108 | "Regexp group in `guix-prettify-regexp' for prettifying." | |
109 | :type 'integer | |
110 | :group 'guix-prettify) | |
111 | ||
112 | (defvar guix-prettify-special-modes | |
113 | '(guix-info-mode ibuffer-mode) | |
114 | "List of special modes that support font-locking. | |
115 | ||
116 | By default, \\[global-guix-prettify-mode] enables prettifying in | |
117 | all buffers except the ones where `font-lock-defaults' is | |
118 | nil (see Info node `(elisp) Font Lock Basics'), because it may | |
119 | break the existing highlighting. | |
120 | ||
121 | Modes from this list and all derived modes are exceptions | |
122 | \(`global-guix-prettify-mode' enables prettifying there).") | |
123 | ||
124 | (defvar guix-prettify-flush-function | |
125 | (cond ((fboundp 'font-lock-flush) #'font-lock-flush) | |
126 | ((fboundp 'jit-lock-refontify) #'jit-lock-refontify)) | |
127 | "Function used to refontify buffer. | |
128 | This function is called without arguments after | |
129 | enabling/disabling `guix-prettify-mode'. If nil, do nothing.") | |
130 | ||
131 | (defun guix-prettify-compose () | |
132 | "Compose matching region in the current buffer." | |
133 | (let ((beg (match-beginning guix-prettify-regexp-group)) | |
134 | (end (match-end guix-prettify-regexp-group))) | |
135 | (compose-region beg end guix-prettify-char 'decompose-region)) | |
136 | ;; Return nil because we're not adding any face property. | |
137 | nil) | |
138 | ||
139 | (defun guix-prettify-decompose-buffer () | |
140 | "Remove file names compositions from the current buffer." | |
141 | (with-silent-modifications | |
142 | (let ((inhibit-read-only t)) | |
143 | (if guix-prettify-decompose-force | |
144 | (remove-text-properties (point-min) | |
145 | (point-max) | |
146 | '(composition nil)) | |
c10521e9 AK |
147 | (guix-while-search guix-prettify-regexp |
148 | (remove-text-properties | |
149 | (match-beginning guix-prettify-regexp-group) | |
150 | (match-end guix-prettify-regexp-group) | |
151 | '(composition nil))))))) | |
9a130e19 AK |
152 | |
153 | ;;;###autoload | |
154 | (define-minor-mode guix-prettify-mode | |
155 | "Toggle Guix Prettify mode. | |
156 | ||
157 | With a prefix argument ARG, enable Guix Prettify mode if ARG is | |
158 | positive, and disable it otherwise. If called from Lisp, enable | |
159 | the mode if ARG is omitted or nil. | |
160 | ||
161 | When Guix Prettify mode is enabled, hash-parts of the Guix store | |
162 | file names (see `guix-prettify-regexp') are prettified, | |
163 | i.e. displayed as `guix-prettify-char' character. This mode can | |
164 | be enabled programmatically using hooks: | |
165 | ||
166 | (add-hook 'shell-mode-hook 'guix-prettify-mode) | |
167 | ||
168 | It is possible to enable the mode in any buffer, however not any | |
169 | buffer's highlighting may survive after adding new elements to | |
170 | `font-lock-keywords' (see `guix-prettify-special-modes' for | |
171 | details). | |
172 | ||
173 | Also you can use `global-guix-prettify-mode' to enable Guix | |
174 | Prettify mode for all modes that support font-locking." | |
175 | :init-value nil | |
176 | :lighter " …" | |
177 | (let ((keywords `((,guix-prettify-regexp | |
178 | (,guix-prettify-regexp-group | |
179 | (guix-prettify-compose)))))) | |
180 | (if guix-prettify-mode | |
181 | ;; Turn on. | |
182 | (font-lock-add-keywords nil keywords) | |
183 | ;; Turn off. | |
184 | (font-lock-remove-keywords nil keywords) | |
185 | (guix-prettify-decompose-buffer)) | |
186 | (and guix-prettify-flush-function | |
187 | (funcall guix-prettify-flush-function)))) | |
188 | ||
189 | (defun guix-prettify-supported-p () | |
190 | "Return non-nil, if the mode can be harmlessly enabled in current buffer." | |
191 | (or font-lock-defaults | |
192 | (apply #'derived-mode-p guix-prettify-special-modes))) | |
193 | ||
194 | (defun guix-prettify-turn-on () | |
195 | "Enable `guix-prettify-mode' in the current buffer if needed. | |
196 | See `guix-prettify-special-modes' for details." | |
197 | (and (not guix-prettify-mode) | |
198 | (guix-prettify-supported-p) | |
199 | (guix-prettify-mode))) | |
200 | ||
201 | ;;;###autoload | |
202 | (define-globalized-minor-mode global-guix-prettify-mode | |
203 | guix-prettify-mode guix-prettify-turn-on) | |
204 | ||
205 | ;;;###autoload | |
206 | (defalias 'guix-prettify-global-mode 'global-guix-prettify-mode) | |
207 | ||
208 | (provide 'guix-prettify) | |
209 | ||
210 | ;;; guix-prettify.el ends here |