aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimen Heggestøyl2017-08-01 20:23:21 +0200
committerSimen Heggestøyl2017-08-15 12:29:10 +0200
commit85a9f42b6ca7711c64cbd3e4e261fae308eab9d3 (patch)
tree4d1f41c2dd840771610a1fb6f7fd126b499de23f
parent3f887812e708123eca2f85cfbf5004e405aff914 (diff)
downloademacs-85a9f42b6ca7711c64cbd3e4e261fae308eab9d3.tar.gz
emacs-85a9f42b6ca7711c64cbd3e4e261fae308eab9d3.zip
Fixes and tweaks for the new Less CSS mode
* etc/NEWS: Add an entry for the new mode. * lisp/textmodes/less-css-mode.el (less-css): Tweak docstring. (less-css-lessc-command): Tweak docstring. Don't mark it as safe. Don't autoload. (less-css-compile-at-save, less-css-lessc-options) (less-css-output-directory): Tweak docstrings. Don't autoload. (less-css-output-file-name): Tweak docstring. Don't mark it as safe. (less-css-input-file-name): Tweak docstring. Don't autoload. (less-css-compile-maybe): Use `when' for one-armed `if'. (less-css--output-path): Tweak docstring. (less-css--maybe-shell-quote-command): Remove function. (less-css-compile): Don't autoload. Tweak docstring and message. Fix compiler warning. Use `string-join' instead of `mapconcat'. (less-css-font-lock-keywords): Use `font-lock-variable-name-face' for variables. (less-css-mode-syntax-table, less-css-mode-map): New variables. (less-css-mode): Change status line mode name from "LESS" to "Less". Tweak docstring. Move syntax table definitions to `less-css-mode-syntax-table'. (less-css-indent-line): Remove function.
-rw-r--r--etc/NEWS3
-rw-r--r--lisp/textmodes/less-css-mode.el264
2 files changed, 122 insertions, 145 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 3f38153048c..9e86af57757 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1106,6 +1106,9 @@ fontification, and commenting for embedded JavaScript and CSS.
1106 1106
1107** New minor mode 'pixel-scroll-mode' provides smooth pixel-level scrolling. 1107** New minor mode 'pixel-scroll-mode' provides smooth pixel-level scrolling.
1108 1108
1109** New major mode 'less-css-mode' (a minor variant of 'css-mode') for
1110editing Less files.
1111
1109 1112
1110* Incompatible Lisp Changes in Emacs 26.1 1113* Incompatible Lisp Changes in Emacs 26.1
1111 1114
diff --git a/lisp/textmodes/less-css-mode.el b/lisp/textmodes/less-css-mode.el
index 8a981d67b93..b38f2594291 100644
--- a/lisp/textmodes/less-css-mode.el
+++ b/lisp/textmodes/less-css-mode.el
@@ -1,36 +1,41 @@
1;;; less-css-mode.el --- Major mode for editing LESS CSS files (lesscss.org) 1;;; less-css-mode.el --- Major mode for editing Less CSS files -*- lexical-binding: t; -*-
2;; 2
3;; Copyright (C) 2011-2014 Steve Purcell 3;; Copyright (C) 2011-2017 Free Software Foundation, Inc.
4;; 4
5;; Author: Steve Purcell <steve@sanityinc.com> 5;; Author: Steve Purcell <steve@sanityinc.com>
6;; URL: https://github.com/purcell/less-css-mode 6;; Maintainer: Simen Heggestøyl <simenheg@gmail.com>
7;; Keywords: less css mode 7;; Keywords: hypermedia
8;; Version: DEV 8
9;; 9;; This file is part of GNU Emacs.
10;; This program is free software; you can redistribute it and/or 10
11;; modify it under the terms of the GNU General Public License as 11;; GNU Emacs is free software: you can redistribute it and/or modify
12;; published by the Free Software Foundation; either version 2 of 12;; it under the terms of the GNU General Public License as published by
13;; the License, or (at your option) any later version. 13;; the Free Software Foundation, either version 3 of the License, or
14;; 14;; (at your option) any later version.
15;; This program is distributed in the hope that it will be 15
16;; useful, but WITHOUT ANY WARRANTY; without even the implied 16;; GNU Emacs is distributed in the hope that it will be useful,
17;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; PURPOSE. See the GNU General Public License for more details. 18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; 19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
23
20;;; Commentary: 24;;; Commentary:
21;; 25
22;; This mode provides syntax highlighting for LESS CSS files, plus 26;; This mode provides syntax highlighting for Less CSS files
23;; optional support for compilation of .less files to .css files at 27;; (http://lesscss.org/), plus optional support for compilation of
24;; the time they are saved: use `less-css-compile-at-save' to enable 28;; .less files to .css files at the time they are saved: use
25;; this. 29;; `less-css-compile-at-save' to enable this.
26;; 30;;
27;; Command line utility "lessc" is required if setting 31;; Command line utility "lessc" is required if setting
28;; `less-css-compile-at-save' to t. To install "lessc" using the 32;; `less-css-compile-at-save' to t. To install "lessc" using the
29;; Node.js package manager, run "npm install less" 33;; Node.js package manager, run "npm install less".
30;; 34;;
31;; Also make sure the "lessc" executable is in Emacs' PATH, example: 35;; Also make sure the "lessc" executable is in Emacs' PATH, example:
32;; (setq exec-path (cons (expand-file-name "~/.gem/ruby/1.8/bin") exec-path)) 36;; (push (expand-file-name "~/.gem/ruby/1.8/bin") exec-path)
33;; or customize `less-css-lessc-command' to point to your "lessc" executable. 37;; or customize `less-css-lessc-command' to point to your "lessc"
38;; executable.
34;; 39;;
35;; We target lessc >= 1.4.0, and thus use the `--no-color' flag by 40;; We target lessc >= 1.4.0, and thus use the `--no-color' flag by
36;; default. You may want to adjust `less-css-lessc-options' for 41;; default. You may want to adjust `less-css-lessc-options' for
@@ -56,148 +61,122 @@
56;; 61;;
57;; If you don't need CSS output but would like to be warned of any 62;; If you don't need CSS output but would like to be warned of any
58;; syntax errors in your .less source, consider using `flymake-less': 63;; syntax errors in your .less source, consider using `flymake-less':
59;; https://github.com/purcell/flymake-less 64;; https://github.com/purcell/flymake-less.
60;; 65
61;;; Credits 66;;; Credits
62;; 67
63;; The original code for this mode was, in large part, written using 68;; The original code for this mode was, in large part, written using
64;; Anton Johansson's scss-mode as a template -- thanks Anton! 69;; Anton Johansson's scss-mode as a template -- thanks Anton!
65;; https://github.com/antonj 70;; https://github.com/antonj
66;; 71
67;;; Code: 72;;; Code:
68 73
69(require 'derived)
70(require 'compile) 74(require 'compile)
71
72;; There are at least three css-mode.el implementations, but we need
73;; the right one in order to work as expected, not the versions by
74;; Landström or Garshol
75
76(require 'css-mode) 75(require 'css-mode)
77(unless (or (boundp 'css-navigation-syntax-table) 76(require 'derived)
78 (functionp 'css-smie-rules)) 77(eval-when-compile (require 'subr-x))
79 (error "Wrong css-mode.el: please use the version by Stefan Monnier, bundled with Emacs >= 23"))
80 78
81(defgroup less-css nil 79(defgroup less-css nil
82 "Less-css mode" 80 "Less CSS mode."
83 :prefix "less-css-" 81 :prefix "less-css-"
84 :group 'css) 82 :group 'css)
85 83
86;;;###autoload
87(defcustom less-css-lessc-command "lessc" 84(defcustom less-css-lessc-command "lessc"
88 "Command used to compile LESS files. 85 "Command used to compile Less files.
89Should be lessc or the complete path to your lessc executable, 86Should be \"lessc\" or the complete path to your lessc
90 e.g.: \"~/.gem/ruby/1.8/bin/lessc\"" 87executable, e.g.: \"~/.gem/ruby/1.8/bin/lessc\"."
91 :type 'file 88 :type 'file)
92 :group 'less-css
93 :safe 'stringp)
94 89
95;;;###autoload
96(defcustom less-css-compile-at-save nil 90(defcustom less-css-compile-at-save nil
97 "If non-nil, the LESS buffers will be compiled to CSS after each save." 91 "If non-nil, Less buffers are compiled to CSS after each save."
98 :type 'boolean 92 :type 'boolean)
99 :group 'less-css
100 :safe 'booleanp)
101
102;;;###autoload 93;;;###autoload
103(defcustom less-css-lessc-options '("--no-color") 94(put 'less-css-compile-at-save 'safe-local-variable 'booleanp)
104 "Command line options for less executable.
105 95
96(defcustom less-css-lessc-options '("--no-color")
97 "Command line options for Less executable.
106Use \"-x\" to minify output." 98Use \"-x\" to minify output."
107 :type '(repeat string) 99 :type '(repeat string))
108 :group 'less-css
109 :safe t)
110
111;;;###autoload 100;;;###autoload
112(defcustom less-css-output-directory nil 101(put 'less-css-lessc-options 'safe-local-variable t)
113 "Directory in which to save CSS, or nil to use the LESS file's directory.
114 102
115This path is expanded relative to the directory of the LESS file 103(defcustom less-css-output-directory nil
104 "Directory in which to save CSS, or nil to use the Less file's directory.
105This path is expanded relative to the directory of the Less file
116using `expand-file-name', so both relative and absolute paths 106using `expand-file-name', so both relative and absolute paths
117will work as expected." 107will work as expected."
118 :type 'directory 108 :type 'directory)
119 :group 'less-css
120 :safe 'stringp)
121
122;;;###autoload 109;;;###autoload
110(put 'less-css-output-directory 'safe-local-variable 'stringp)
111
123(defcustom less-css-output-file-name nil 112(defcustom less-css-output-file-name nil
124 "File name in which to save CSS, or nil to use <name>.css for <name>.less. 113 "File name in which to save CSS, or nil to use <name>.css for <name>.less.
125
126This can be also be set to a full path, or a relative path. If 114This can be also be set to a full path, or a relative path. If
127the path is relative, it will be relative to the value of 115the path is relative, it will be relative to the value of
128`less-css-output-dir', if set, or the current directory by 116`less-css-output-dir', if set, or the current directory by
129default." 117default."
130 :type 'file 118 :type 'file)
131 :group 'less-css
132 :safe 'stringp)
133(make-variable-buffer-local 'less-css-output-file-name) 119(make-variable-buffer-local 'less-css-output-file-name)
134 120
135;;;###autoload
136(defcustom less-css-input-file-name nil 121(defcustom less-css-input-file-name nil
137 "File name which will be compiled to CSS. 122 "File name which will be compiled to CSS.
138
139When the current buffer is saved `less-css-input-file-name' file 123When the current buffer is saved `less-css-input-file-name' file
140will be compiled to css instead of the current file. 124will be compiled to CSS instead of the current file.
141 125
142Set this in order to trigger compilation of a \"master\" .less 126Set this in order to trigger compilation of a \"master\" .less
143file which includes the current file. The best way to set this 127file which includes the current file. The best way to set this
144variable in most cases is likely to be via directory local 128variable in most cases is likely to be via directory local
145variables. 129variables.
146 130
147This can be also be set to a full path, or a relative path. If 131This can be also be set to a full path, or a relative path. If
148the path is relative, it will be relative to the the current directory by 132the path is relative, it will be relative to the the current
149default." 133directory by default."
150 :type 'file 134 :type 'file)
151 :group 'less-css 135;;;###autoload
152 :safe 'stringp) 136(put 'less-css-input-file-name 'safe-local-variable 'stringp)
153(make-variable-buffer-local 'less-css-input-file-name) 137(make-variable-buffer-local 'less-css-input-file-name)
154 138
155(defconst less-css-default-error-regex 139(defconst less-css-default-error-regex
156 "^\\(?:\e\\[31m\\)?\\([^\e\n]*\\|FileError:.*\n\\)\\(?:\e\\[39m\e\\[31m\\)? in \\(?:\e\\[39m\\)?\\([^ \r\n\t\e]+\\)\\(?:\e\\[90m\\)?\\(?::\\| on line \\)\\([0-9]+\\)\\(?::\\|, column \\)\\([0-9]+\\):?\\(?:\e\\[39m\\)?") 140 "^\\(?:\e\\[31m\\)?\\([^\e\n]*\\|FileError:.*\n\\)\\(?:\e\\[39m\e\\[31m\\)? in \\(?:\e\\[39m\\)?\\([^ \r\n\t\e]+\\)\\(?:\e\\[90m\\)?\\(?::\\| on line \\)\\([0-9]+\\)\\(?::\\|, column \\)\\([0-9]+\\):?\\(?:\e\\[39m\\)?")
157 141
158 142;;; Compilation to CSS
159;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
160;; Compilation to CSS
161;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
162 143
163(add-to-list 'compilation-error-regexp-alist-alist 144(add-to-list 'compilation-error-regexp-alist-alist
164 (list 'less-css less-css-default-error-regex 2 3 4 nil 1)) 145 (list 'less-css less-css-default-error-regex 2 3 4 nil 1))
165(add-to-list 'compilation-error-regexp-alist 'less-css) 146(add-to-list 'compilation-error-regexp-alist 'less-css)
166 147
167
168(defun less-css-compile-maybe () 148(defun less-css-compile-maybe ()
169 "Run `less-css-compile' if `less-css-compile-at-save' is non-nil." 149 "Run `less-css-compile' if `less-css-compile-at-save' is non-nil."
170 (if less-css-compile-at-save 150 (when less-css-compile-at-save
171 (less-css-compile))) 151 (less-css-compile)))
172 152
173(defun less-css--output-path () 153(defun less-css--output-path ()
174 "Calculate the path for the compiled CSS file created by `less-css-compile'." 154 "Return the path to use for the compiled CSS file."
175 (expand-file-name (or less-css-output-file-name 155 (expand-file-name
176 (concat (file-name-nondirectory (file-name-sans-extension buffer-file-name)) ".css")) 156 (or less-css-output-file-name
177 (or less-css-output-directory default-directory))) 157 (concat
158 (file-name-nondirectory
159 (file-name-sans-extension buffer-file-name))
160 ".css"))
161 (or less-css-output-directory default-directory)))
178 162
179(defun less-css--maybe-shell-quote-command (command)
180 "Selectively shell-quote COMMAND appropriately for `system-type'."
181 (funcall (if (eq system-type 'windows-nt)
182 'identity
183 'shell-quote-argument) command))
184
185;;;###autoload
186(defun less-css-compile () 163(defun less-css-compile ()
187 "Compiles the current buffer to css using `less-css-lessc-command'." 164 "Compile the current buffer to CSS using `less-css-lessc-command'."
188 (interactive) 165 (interactive)
189 (message "Compiling less to css") 166 (message "Compiling Less to CSS")
190 (let ((compilation-buffer-name-function (lambda (mode-name) "*less-css-compilation*"))) 167 (let ((compilation-buffer-name-function
168 (lambda (_) "*less-css-compilation*")))
191 (save-window-excursion 169 (save-window-excursion
192 (with-current-buffer 170 (with-current-buffer
193 (compile 171 (compile
194 (mapconcat 'identity 172 (string-join
195 (append (list (less-css--maybe-shell-quote-command less-css-lessc-command)) 173 (append
196 (mapcar 'shell-quote-argument less-css-lessc-options) 174 (list less-css-lessc-command)
197 (list (shell-quote-argument 175 (mapcar #'shell-quote-argument less-css-lessc-options)
198 (or less-css-input-file-name buffer-file-name)) 176 (list (shell-quote-argument
199 (shell-quote-argument (less-css--output-path)))) 177 (or less-css-input-file-name buffer-file-name))
200 " ")) 178 (shell-quote-argument (less-css--output-path))))
179 " "))
201 (add-hook 'compilation-finish-functions 180 (add-hook 'compilation-finish-functions
202 (lambda (buf msg) 181 (lambda (buf msg)
203 (unless (string-match-p "^finished" msg) 182 (unless (string-match-p "^finished" msg)
@@ -205,54 +184,49 @@ default."
205 nil 184 nil
206 t))))) 185 t)))))
207 186
208;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 187;;; Major mode
209;; Minor mode
210;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
211 188
212;; TODO: interpolation ("@{val}"), escaped values (~"..."), JS eval (~`...`), custom faces 189;; TODO:
190;; - interpolation ("@{val}")
191;; - escaped values (~"...")
192;; - JS eval (~`...`)
193;; - custom faces.
213(defconst less-css-font-lock-keywords 194(defconst less-css-font-lock-keywords
214 '(;; Variables 195 '(;; Variables
215 ("@[a-z_-][a-z-_0-9]*" . font-lock-constant-face) 196 ("@[a-z_-][a-z-_0-9]*" . font-lock-variable-name-face)
216 ("&" . font-lock-preprocessor-face) 197 ("&" . font-lock-preprocessor-face)
217 ;; Mixins 198 ;; Mixins
218 ("\\(?:[ \t{;]\\|^\\)\\(\\.[a-z_-][a-z-_0-9]*\\)[ \t]*;" . (1 font-lock-keyword-face))) 199 ("\\(?:[ \t{;]\\|^\\)\\(\\.[a-z_-][a-z-_0-9]*\\)[ \t]*;" .
219 ) 200 (1 font-lock-keyword-face))))
220 201
202(defvar less-css-mode-syntax-table
203 (let ((st (make-syntax-table css-mode-syntax-table)))
204 ;; C++-style comments.
205 (modify-syntax-entry ?/ ". 124b" st)
206 (modify-syntax-entry ?* ". 23" st)
207 (modify-syntax-entry ?\n "> b" st)
208 ;; Special chars that sometimes come at the beginning of words.
209 (modify-syntax-entry ?. "'" st)
210 st))
211
212(defvar less-css-mode-map
213 (let ((map (make-sparse-keymap)))
214 (define-key map "\C-c\C-c" 'less-css-compile)
215 map))
216
217;;;###autoload (add-to-list 'auto-mode-alist '("\\.less\\'" . less-css-mode))
221;;;###autoload 218;;;###autoload
222(define-derived-mode less-css-mode css-mode "LESS" 219(define-derived-mode less-css-mode css-mode "Less"
223 "Major mode for editing LESS files, http://lesscss.org/ 220 "Major mode for editing Less files (http://lesscss.org/).
224Special commands: 221Special commands:
225\\{less-css-mode-map}" 222\\{less-css-mode-map}"
226 (font-lock-add-keywords nil less-css-font-lock-keywords) 223 (font-lock-add-keywords nil less-css-font-lock-keywords)
227 ;; cpp-style comments 224 (setq-local comment-start "//")
228 (modify-syntax-entry ?/ ". 124b" less-css-mode-syntax-table) 225 (setq-local comment-end "")
229 (modify-syntax-entry ?* ". 23" less-css-mode-syntax-table) 226 (setq-local comment-continue " *")
230 (modify-syntax-entry ?\n "> b" less-css-mode-syntax-table) 227 (setq-local comment-start-skip "/[*/]+[ \t]*")
231 ;; Special chars that sometimes come at the beginning of words. 228 (setq-local comment-end-skip "[ \t]*\\(?:\n\\|\\*+/\\)")
232 (modify-syntax-entry ?. "'" less-css-mode-syntax-table)
233
234 (set (make-local-variable 'comment-start) "//")
235 (set (make-local-variable 'comment-end) "")
236 (set (make-local-variable 'indent-line-function) 'less-css-indent-line)
237 (when (functionp 'css-smie-rules)
238 (smie-setup css-smie-grammar #'css-smie-rules
239 :forward-token #'css-smie--forward-token
240 :backward-token #'css-smie--backward-token))
241
242 (add-hook 'after-save-hook 'less-css-compile-maybe nil t)) 229 (add-hook 'after-save-hook 'less-css-compile-maybe nil t))
243 230
244(define-key less-css-mode-map "\C-c\C-c" 'less-css-compile)
245
246(defun less-css-indent-line ()
247 "Indent current line according to LESS CSS indentation rules."
248 (let ((css-navigation-syntax-table less-css-mode-syntax-table))
249 (if (fboundp 'css-indent-line)
250 (css-indent-line)
251 (smie-indent-line))))
252
253;;;###autoload
254(add-to-list 'auto-mode-alist '("\\.less\\'" . less-css-mode))
255
256
257(provide 'less-css-mode) 231(provide 'less-css-mode)
258;;; less-css-mode.el ends here 232;;; less-css-mode.el ends here