From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Simen =?UTF-8?Q?Heggest=C3=B8yl?= Newsgroups: gmane.emacs.bugs Subject: bug#27881: New major mode: Less mode Date: Fri, 11 Aug 2017 00:53:22 +0200 Message-ID: <1502405602.1756.4@smtp.gmail.com> References: <1501437183.13205.0@smtp.gmail.com> <1501782658.6810.1@smtp.gmail.com> <1501782658.6810.1@smtp.gmail.com> <"Simen =?UTF-8?Q?Heggest=C3=B8=3D=3FUTF-8=3FQ=3Fyl?="'s_message_of_"Thu, _03_Aug_2017_19:50:58_+0200"> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-ganHNVWVIOy0wIe+ow0v" X-Trace: blaine.gmane.org 1502405665 10609 195.159.176.226 (10 Aug 2017 22:54:25 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Thu, 10 Aug 2017 22:54:25 +0000 (UTC) Cc: steve@sanityinc.com, Tom Tromey , 27881@debbugs.gnu.org, dgutov@yandex.ru To: Stefan Monnier Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Fri Aug 11 00:54:16 2017 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dfwLE-0001zP-NJ for geb-bug-gnu-emacs@m.gmane.org; Fri, 11 Aug 2017 00:54:13 +0200 Original-Received: from localhost ([::1]:55640 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dfwLJ-000459-37 for geb-bug-gnu-emacs@m.gmane.org; Thu, 10 Aug 2017 18:54:17 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:36332) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dfwL9-000452-8B for bug-gnu-emacs@gnu.org; Thu, 10 Aug 2017 18:54:10 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dfwL4-0002ql-V5 for bug-gnu-emacs@gnu.org; Thu, 10 Aug 2017 18:54:07 -0400 Original-Received: from debbugs.gnu.org ([208.118.235.43]:46144) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dfwL4-0002qV-NF for bug-gnu-emacs@gnu.org; Thu, 10 Aug 2017 18:54:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1dfwL4-0006O0-72 for bug-gnu-emacs@gnu.org; Thu, 10 Aug 2017 18:54:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Simen =?UTF-8?Q?Heggest=C3=B8yl?= Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 10 Aug 2017 22:54:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 27881 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 27881-submit@debbugs.gnu.org id=B27881.150240561924505 (code B ref 27881); Thu, 10 Aug 2017 22:54:02 +0000 Original-Received: (at 27881) by debbugs.gnu.org; 10 Aug 2017 22:53:39 +0000 Original-Received: from localhost ([127.0.0.1]:54825 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dfwKc-0006N3-Iy for submit@debbugs.gnu.org; Thu, 10 Aug 2017 18:53:39 -0400 Original-Received: from mail-qt0-f194.google.com ([209.85.216.194]:34579) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dfwKY-0006Mo-JJ for 27881@debbugs.gnu.org; Thu, 10 Aug 2017 18:53:31 -0400 Original-Received: by mail-qt0-f194.google.com with SMTP id i19so2191109qte.1 for <27881@debbugs.gnu.org>; Thu, 10 Aug 2017 15:53:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:subject:to:cc:message-id:in-reply-to:references :mime-version; bh=Lug/YQOAmlW+T4FIiSCJ1BisJICnDM1cA3xjEZUV7CQ=; b=CwZwGkJWaagH/y8hdNzVlRUTnQ/cOy/TqE8yFPR2R71ICqx0U9U0vcBGIhv4bS8gjS sUGbz3uT1zsGMM6qH1PyZuaolx261mc0pMzIlRZnHalhhxydEtEmvMYqzQhqiCgVL2XQ aWFXXSK56ekMCApM1N7/78VIdpVdddAJZoZog2opQgONjd66kd3zkhyYPFUzk4CX7Htv bJNCKHACCjlIw4iCNW+1ZSmDONfa+5z0qFYgL4t0e0VVMTwgBhEocjHqg2gtaNE3Fk3o qmJG7hnEK0zeP/mW824IKt18EcRtoy6UnIRvNtBzVtygBpSymcnxyhG0CAXemMcnY9YV hhlw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:subject:to:cc:message-id:in-reply-to :references:mime-version; bh=Lug/YQOAmlW+T4FIiSCJ1BisJICnDM1cA3xjEZUV7CQ=; b=IIHNyyteVC11svqPAHXkdkR2g0Cx1uQ9eZGEqxCay7icqRLzl5Wm5Siom1o2pbsWRP fEBGUJN2fq/ykSyGq+B66zjN+vR/Excpn51Ce9s/E8RNLkiHFQo5yGIuRk+TFq1i2wk7 OFQyOrPd4YxtJk81ezeHhkDMWpkk4WXAGyBObmqYNCbujLDnt4WGBdDbY3lmWCk0J7+/ rZEZ2LRcyX+PRj4s6l68lXn1SQK2FGrIp3kaw47TqeyyBexxrHDVpCiKte92ppye9Hwu oMnF2iFbQdjlMA90Rb+Mo0q9NCuDGz0Pq3vkd3Z89UsWBG/ZJ0lbi9Q0o+86PU7CWFZe b7iQ== X-Gm-Message-State: AHYfb5h8VNR9R/tsxA0HuyGlWato8/rlVxWkiNw3ucnvICi8THLzZvbu o2YPF39MfzF23g== X-Received: by 10.237.36.195 with SMTP id u3mr19362182qtc.151.1502405604890; Thu, 10 Aug 2017 15:53:24 -0700 (PDT) Original-Received: from [192.168.2.165] (216-164-224-125.c3-0.tlg-cbr3.atw-tlg.pa.cable.rcn.com. [216.164.224.125]) by smtp.gmail.com with ESMTPSA id k36sm4801589qtc.41.2017.08.10.15.53.22 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 10 Aug 2017 15:53:23 -0700 (PDT) In-Reply-To: X-Mailer: geary/0.11.3 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:135631 Archived-At: --=-ganHNVWVIOy0wIe+ow0v Content-Type: text/plain; charset=utf-8; format=flowed On Thu, Aug 3, 2017 at 10:08 PM, Stefan Monnier wrote: > ;;;###autoload > (put ' 'safe-local-variable ') OK, thanks. How does it look now? -- Simen --=-ganHNVWVIOy0wIe+ow0v Content-Type: multipart/mixed; boundary="=-AlcmsjUGNvt/L11XRzLB" --=-AlcmsjUGNvt/L11XRzLB Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-New-major-mode-Less-CSS-mode.patch Content-Transfer-Encoding: quoted-printable >From 8d24b049ee1d051b975da6b1e8707f0db42a1ac7 Mon Sep 17 00:00:00 2001 From: Steve Purcell Date: Tue, 1 Aug 2017 20:15:45 +0200 Subject: [PATCH 1/2] New major mode: Less CSS mode * lisp/textmodes/less-css-mode.el: New file. --- lisp/textmodes/less-css-mode.el | 258 ++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 258 insertions(+) create mode 100644 lisp/textmodes/less-css-mode.el diff --git a/lisp/textmodes/less-css-mode.el b/lisp/textmodes/less-css-mode= .el new file mode 100644 index 0000000000..8a981d67b9 --- /dev/null +++ b/lisp/textmodes/less-css-mode.el @@ -0,0 +1,258 @@ +;;; less-css-mode.el --- Major mode for editing LESS CSS files (lesscss.or= g) +;; +;; Copyright (C) 2011-2014 Steve Purcell +;; +;; Author: Steve Purcell +;; URL: https://github.com/purcell/less-css-mode +;; Keywords: less css mode +;; Version: DEV +;; +;; 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 2 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. +;; +;;; Commentary: +;; +;; This mode provides syntax highlighting for LESS CSS files, plus +;; optional support for compilation of .less files to .css files at +;; the time they are saved: use `less-css-compile-at-save' to enable +;; this. +;; +;; Command line utility "lessc" is required if setting +;; `less-css-compile-at-save' to t. To install "lessc" using the +;; Node.js package manager, run "npm install less" +;; +;; Also make sure the "lessc" executable is in Emacs' PATH, example: +;; (setq exec-path (cons (expand-file-name "~/.gem/ruby/1.8/bin") exec-pat= h)) +;; or customize `less-css-lessc-command' to point to your "lessc" executab= le. +;; +;; We target lessc >=3D 1.4.0, and thus use the `--no-color' flag by +;; default. You may want to adjust `less-css-lessc-options' for +;; compatibility with older versions. +;; +;; `less-css-mode' is derived from `css-mode', and indentation of +;; nested blocks may not work correctly with versions of `css-mode' +;; other than that bundled with recent Emacs. +;; +;; You can specify per-file values for `less-css-compile-at-save', +;; `less-css-output-file-name' or `less-css-output-directory' using a +;; variables header at the top of your .less file, e.g.: +;; +;; // -*- less-css-compile-at-save: t; less-css-output-directory: "../css"= -*- +;; +;; Alternatively, you can use directory local variables to set the +;; default value of `less-css-output-directory' for your project. +;; +;; In the case of files which are included in other .less files, you +;; may want to trigger the compilation of a "master" .less file on +;; save: you can accomplish this with `less-css-input-file-name', +;; which is probably best set using directory local variables. +;; +;; If you don't need CSS output but would like to be warned of any +;; syntax errors in your .less source, consider using `flymake-less': +;; https://github.com/purcell/flymake-less +;; +;;; Credits +;; +;; The original code for this mode was, in large part, written using +;; Anton Johansson's scss-mode as a template -- thanks Anton! +;; https://github.com/antonj +;; +;;; Code: + +(require 'derived) +(require 'compile) + +;; There are at least three css-mode.el implementations, but we need +;; the right one in order to work as expected, not the versions by +;; Landstr=C3=B6m or Garshol + +(require 'css-mode) +(unless (or (boundp 'css-navigation-syntax-table) + (functionp 'css-smie-rules)) + (error "Wrong css-mode.el: please use the version by Stefan Monnier, bun= dled with Emacs >=3D 23")) + +(defgroup less-css nil + "Less-css mode" + :prefix "less-css-" + :group 'css) + +;;;###autoload +(defcustom less-css-lessc-command "lessc" + "Command used to compile LESS files. +Should be lessc or the complete path to your lessc executable, + e.g.: \"~/.gem/ruby/1.8/bin/lessc\"" + :type 'file + :group 'less-css + :safe 'stringp) + +;;;###autoload +(defcustom less-css-compile-at-save nil + "If non-nil, the LESS buffers will be compiled to CSS after each save." + :type 'boolean + :group 'less-css + :safe 'booleanp) + +;;;###autoload +(defcustom less-css-lessc-options '("--no-color") + "Command line options for less executable. + +Use \"-x\" to minify output." + :type '(repeat string) + :group 'less-css + :safe t) + +;;;###autoload +(defcustom less-css-output-directory nil + "Directory in which to save CSS, or nil to use the LESS file's directory= . + +This path is expanded relative to the directory of the LESS file +using `expand-file-name', so both relative and absolute paths +will work as expected." + :type 'directory + :group 'less-css + :safe 'stringp) + +;;;###autoload +(defcustom less-css-output-file-name nil + "File name in which to save CSS, or nil to use .css for .les= s. + +This can be also be set to a full path, or a relative path. If +the path is relative, it will be relative to the value of +`less-css-output-dir', if set, or the current directory by +default." + :type 'file + :group 'less-css + :safe 'stringp) +(make-variable-buffer-local 'less-css-output-file-name) + +;;;###autoload +(defcustom less-css-input-file-name nil + "File name which will be compiled to CSS. + +When the current buffer is saved `less-css-input-file-name' file +will be compiled to css instead of the current file. + +Set this in order to trigger compilation of a \"master\" .less +file which includes the current file. The best way to set this +variable in most cases is likely to be via directory local +variables. + +This can be also be set to a full path, or a relative path. If +the path is relative, it will be relative to the the current directory by +default." + :type 'file + :group 'less-css + :safe 'stringp) +(make-variable-buffer-local 'less-css-input-file-name) + +(defconst less-css-default-error-regex + "^\\(?:\e\\[31m\\)?\\([^\e\n]*\\|FileError:.*\n\\)\\(?:\e\\[39m\e\\[31m\= \)? in \\(?:\e\\[39m\\)?\\([^ \r\n\t\e]+\\)\\(?:\e\\[90m\\)?\\(?::\\| on li= ne \\)\\([0-9]+\\)\\(?::\\|, column \\)\\([0-9]+\\):?\\(?:\e\\[39m\\)?") + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;;;; +;; Compilation to CSS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;;;; + +(add-to-list 'compilation-error-regexp-alist-alist + (list 'less-css less-css-default-error-regex 2 3 4 nil 1)) +(add-to-list 'compilation-error-regexp-alist 'less-css) + + +(defun less-css-compile-maybe () + "Run `less-css-compile' if `less-css-compile-at-save' is non-nil." + (if less-css-compile-at-save + (less-css-compile))) + +(defun less-css--output-path () + "Calculate the path for the compiled CSS file created by `less-css-compi= le'." + (expand-file-name (or less-css-output-file-name + (concat (file-name-nondirectory (file-name-sans-ex= tension buffer-file-name)) ".css")) + (or less-css-output-directory default-directory))) + +(defun less-css--maybe-shell-quote-command (command) + "Selectively shell-quote COMMAND appropriately for `system-type'." + (funcall (if (eq system-type 'windows-nt) + 'identity + 'shell-quote-argument) command)) + +;;;###autoload +(defun less-css-compile () + "Compiles the current buffer to css using `less-css-lessc-command'." + (interactive) + (message "Compiling less to css") + (let ((compilation-buffer-name-function (lambda (mode-name) "*less-css-c= ompilation*"))) + (save-window-excursion + (with-current-buffer + (compile + (mapconcat 'identity + (append (list (less-css--maybe-shell-quote-command l= ess-css-lessc-command)) + (mapcar 'shell-quote-argument less-css-lessc= -options) + (list (shell-quote-argument + (or less-css-input-file-name buffer-f= ile-name)) + (shell-quote-argument (less-css--outpu= t-path)))) + " ")) + (add-hook 'compilation-finish-functions + (lambda (buf msg) + (unless (string-match-p "^finished" msg) + (display-buffer buf))) + nil + t))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;;;; +;; Minor mode +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;;;; + +;; TODO: interpolation ("@{val}"), escaped values (~"..."), JS eval (~`...= `), custom faces +(defconst less-css-font-lock-keywords + '(;; Variables + ("@[a-z_-][a-z-_0-9]*" . font-lock-constant-face) + ("&" . font-lock-preprocessor-face) + ;; Mixins + ("\\(?:[ \t{;]\\|^\\)\\(\\.[a-z_-][a-z-_0-9]*\\)[ \t]*;" . (1 font-loc= k-keyword-face))) + ) + +;;;###autoload +(define-derived-mode less-css-mode css-mode "LESS" + "Major mode for editing LESS files, http://lesscss.org/ +Special commands: +\\{less-css-mode-map}" + (font-lock-add-keywords nil less-css-font-lock-keywords) + ;; cpp-style comments + (modify-syntax-entry ?/ ". 124b" less-css-mode-syntax-table) + (modify-syntax-entry ?* ". 23" less-css-mode-syntax-table) + (modify-syntax-entry ?\n "> b" less-css-mode-syntax-table) + ;; Special chars that sometimes come at the beginning of words. + (modify-syntax-entry ?. "'" less-css-mode-syntax-table) + + (set (make-local-variable 'comment-start) "//") + (set (make-local-variable 'comment-end) "") + (set (make-local-variable 'indent-line-function) 'less-css-indent-line) + (when (functionp 'css-smie-rules) + (smie-setup css-smie-grammar #'css-smie-rules + :forward-token #'css-smie--forward-token + :backward-token #'css-smie--backward-token)) + + (add-hook 'after-save-hook 'less-css-compile-maybe nil t)) + +(define-key less-css-mode-map "\C-c\C-c" 'less-css-compile) + +(defun less-css-indent-line () + "Indent current line according to LESS CSS indentation rules." + (let ((css-navigation-syntax-table less-css-mode-syntax-table)) + (if (fboundp 'css-indent-line) + (css-indent-line) + (smie-indent-line)))) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.less\\'" . less-css-mode)) + + +(provide 'less-css-mode) +;;; less-css-mode.el ends here --=20 2.13.2 = --=-AlcmsjUGNvt/L11XRzLB Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-Fixes-and-tweaks-for-the-new-Less-CSS-mode.patch Content-Transfer-Encoding: quoted-printable >From cdf3582216b9f0a5a031dbad5784d87dbabb8a36 Mon Sep 17 00:00:00 2001 From: =3D?UTF-8?q?Simen=3D20Heggest=3DC3=3DB8yl?=3D Date: Tue, 1 Aug 2017 20:23:21 +0200 Subject: [PATCH 2/2] 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. --- etc/NEWS | 3 + lisp/textmodes/less-css-mode.el | 261 ++++++++++++++++++------------------= ---- 2 files changed, 119 insertions(+), 145 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 2b789be3c8..7c2172947e 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1100,6 +1100,9 @@ fontification, and commenting for embedded JavaScript= and CSS. =20 ** New minor mode 'pixel-scroll-mode' provides smooth pixel-level scrollin= g. =20 +** New major mode 'less-css-mode' (a minor variant of 'css-mode') for +editing Less files. + =0C * Incompatible Lisp Changes in Emacs 26.1 =20 diff --git a/lisp/textmodes/less-css-mode.el b/lisp/textmodes/less-css-mode= .el index 8a981d67b9..1d3f2c6b8d 100644 --- a/lisp/textmodes/less-css-mode.el +++ b/lisp/textmodes/less-css-mode.el @@ -1,36 +1,41 @@ -;;; less-css-mode.el --- Major mode for editing LESS CSS files (lesscss.or= g) -;; -;; Copyright (C) 2011-2014 Steve Purcell -;; +;;; less-css-mode.el --- Major mode for editing Less CSS files -*- lexica= l-binding: t; -*- + +;; Copyright (C) 2011-2017 Free Software Foundation, Inc. + ;; Author: Steve Purcell -;; URL: https://github.com/purcell/less-css-mode -;; Keywords: less css mode -;; Version: DEV -;; -;; 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 2 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. -;; +;; Maintainer: Simen Heggest=C3=B8yl +;; Keywords: hypermedia + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 GNU Emacs. If not, see . + ;;; Commentary: -;; -;; This mode provides syntax highlighting for LESS CSS files, plus -;; optional support for compilation of .less files to .css files at -;; the time they are saved: use `less-css-compile-at-save' to enable -;; this. + +;; This mode provides syntax highlighting for Less CSS files +;; (http://lesscss.org/), plus optional support for compilation of +;; .less files to .css files at the time they are saved: use +;; `less-css-compile-at-save' to enable this. ;; ;; Command line utility "lessc" is required if setting ;; `less-css-compile-at-save' to t. To install "lessc" using the -;; Node.js package manager, run "npm install less" +;; Node.js package manager, run "npm install less". ;; ;; Also make sure the "lessc" executable is in Emacs' PATH, example: -;; (setq exec-path (cons (expand-file-name "~/.gem/ruby/1.8/bin") exec-pat= h)) -;; or customize `less-css-lessc-command' to point to your "lessc" executab= le. +;; (push (expand-file-name "~/.gem/ruby/1.8/bin") exec-path) +;; or customize `less-css-lessc-command' to point to your "lessc" +;; executable. ;; ;; We target lessc >=3D 1.4.0, and thus use the `--no-color' flag by ;; default. You may want to adjust `less-css-lessc-options' for @@ -56,148 +61,122 @@ ;; ;; If you don't need CSS output but would like to be warned of any ;; syntax errors in your .less source, consider using `flymake-less': -;; https://github.com/purcell/flymake-less -;; +;; https://github.com/purcell/flymake-less. + ;;; Credits -;; + ;; The original code for this mode was, in large part, written using ;; Anton Johansson's scss-mode as a template -- thanks Anton! ;; https://github.com/antonj -;; + ;;; Code: =20 -(require 'derived) (require 'compile) - -;; There are at least three css-mode.el implementations, but we need -;; the right one in order to work as expected, not the versions by -;; Landstr=C3=B6m or Garshol - (require 'css-mode) -(unless (or (boundp 'css-navigation-syntax-table) - (functionp 'css-smie-rules)) - (error "Wrong css-mode.el: please use the version by Stefan Monnier, bun= dled with Emacs >=3D 23")) +(require 'derived) +(eval-when-compile (require 'subr-x)) =20 (defgroup less-css nil - "Less-css mode" + "Less CSS mode." :prefix "less-css-" :group 'css) =20 -;;;###autoload (defcustom less-css-lessc-command "lessc" - "Command used to compile LESS files. -Should be lessc or the complete path to your lessc executable, - e.g.: \"~/.gem/ruby/1.8/bin/lessc\"" - :type 'file - :group 'less-css - :safe 'stringp) + "Command used to compile Less files. +Should be \"lessc\" or the complete path to your lessc +executable, e.g.: \"~/.gem/ruby/1.8/bin/lessc\"." + :type 'file) =20 -;;;###autoload (defcustom less-css-compile-at-save nil - "If non-nil, the LESS buffers will be compiled to CSS after each save." - :type 'boolean - :group 'less-css - :safe 'booleanp) - + "If non-nil, Less buffers are compiled to CSS after each save." + :type 'boolean) ;;;###autoload -(defcustom less-css-lessc-options '("--no-color") - "Command line options for less executable. +(put 'less-css-compile-at-save 'safe-local-variable 'booleanp) =20 +(defcustom less-css-lessc-options '("--no-color") + "Command line options for Less executable. Use \"-x\" to minify output." - :type '(repeat string) - :group 'less-css - :safe t) - + :type '(repeat string)) ;;;###autoload -(defcustom less-css-output-directory nil - "Directory in which to save CSS, or nil to use the LESS file's directory= . +(put 'less-css-lessc-options 'safe-local-variable t) =20 -This path is expanded relative to the directory of the LESS file +(defcustom less-css-output-directory nil + "Directory in which to save CSS, or nil to use the Less file's directory= . +This path is expanded relative to the directory of the Less file using `expand-file-name', so both relative and absolute paths will work as expected." - :type 'directory - :group 'less-css - :safe 'stringp) - + :type 'directory) ;;;###autoload +(put 'less-css-output-directory 'safe-local-variable 'stringp) + (defcustom less-css-output-file-name nil "File name in which to save CSS, or nil to use .css for .les= s. - This can be also be set to a full path, or a relative path. If the path is relative, it will be relative to the value of `less-css-output-dir', if set, or the current directory by default." - :type 'file - :group 'less-css - :safe 'stringp) + :type 'file) (make-variable-buffer-local 'less-css-output-file-name) =20 -;;;###autoload (defcustom less-css-input-file-name nil "File name which will be compiled to CSS. - When the current buffer is saved `less-css-input-file-name' file -will be compiled to css instead of the current file. +will be compiled to CSS instead of the current file. =20 Set this in order to trigger compilation of a \"master\" .less file which includes the current file. The best way to set this variable in most cases is likely to be via directory local variables. =20 -This can be also be set to a full path, or a relative path. If -the path is relative, it will be relative to the the current directory by -default." - :type 'file - :group 'less-css - :safe 'stringp) +This can be also be set to a full path, or a relative path. If +the path is relative, it will be relative to the the current +directory by default." + :type 'file) +;;;###autoload +(put 'less-css-input-file-name 'safe-local-variable 'stringp) (make-variable-buffer-local 'less-css-input-file-name) =20 (defconst less-css-default-error-regex "^\\(?:\e\\[31m\\)?\\([^\e\n]*\\|FileError:.*\n\\)\\(?:\e\\[39m\e\\[31m\= \)? in \\(?:\e\\[39m\\)?\\([^ \r\n\t\e]+\\)\\(?:\e\\[90m\\)?\\(?::\\| on li= ne \\)\\([0-9]+\\)\\(?::\\|, column \\)\\([0-9]+\\):?\\(?:\e\\[39m\\)?") =20 - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;;;; -;; Compilation to CSS -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;;;; +;;; Compilation to CSS =20 (add-to-list 'compilation-error-regexp-alist-alist (list 'less-css less-css-default-error-regex 2 3 4 nil 1)) (add-to-list 'compilation-error-regexp-alist 'less-css) =20 - (defun less-css-compile-maybe () "Run `less-css-compile' if `less-css-compile-at-save' is non-nil." - (if less-css-compile-at-save - (less-css-compile))) + (when less-css-compile-at-save + (less-css-compile))) =20 (defun less-css--output-path () - "Calculate the path for the compiled CSS file created by `less-css-compi= le'." - (expand-file-name (or less-css-output-file-name - (concat (file-name-nondirectory (file-name-sans-ex= tension buffer-file-name)) ".css")) - (or less-css-output-directory default-directory))) + "Return the path to use for the compiled CSS file." + (expand-file-name + (or less-css-output-file-name + (concat + (file-name-nondirectory + (file-name-sans-extension buffer-file-name)) + ".css")) + (or less-css-output-directory default-directory))) =20 -(defun less-css--maybe-shell-quote-command (command) - "Selectively shell-quote COMMAND appropriately for `system-type'." - (funcall (if (eq system-type 'windows-nt) - 'identity - 'shell-quote-argument) command)) - -;;;###autoload (defun less-css-compile () - "Compiles the current buffer to css using `less-css-lessc-command'." + "Compile the current buffer to CSS using `less-css-lessc-command'." (interactive) - (message "Compiling less to css") - (let ((compilation-buffer-name-function (lambda (mode-name) "*less-css-c= ompilation*"))) + (message "Compiling Less to CSS") + (let ((compilation-buffer-name-function + (lambda (_) "*less-css-compilation*"))) (save-window-excursion (with-current-buffer (compile - (mapconcat 'identity - (append (list (less-css--maybe-shell-quote-command l= ess-css-lessc-command)) - (mapcar 'shell-quote-argument less-css-lessc= -options) - (list (shell-quote-argument - (or less-css-input-file-name buffer-f= ile-name)) - (shell-quote-argument (less-css--outpu= t-path)))) - " ")) + (string-join + (append + (list less-css-lessc-command) + (mapcar #'shell-quote-argument less-css-lessc-options) + (list (shell-quote-argument + (or less-css-input-file-name buffer-file-name)) + (shell-quote-argument (less-css--output-path)))) + " ")) (add-hook 'compilation-finish-functions (lambda (buf msg) (unless (string-match-p "^finished" msg) @@ -205,54 +184,46 @@ less-css-compile nil t))))) =20 -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;;;; -;; Minor mode -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;;;; +;;; Major mode =20 -;; TODO: interpolation ("@{val}"), escaped values (~"..."), JS eval (~`...= `), custom faces +;; TODO: +;; - interpolation ("@{val}") +;; - escaped values (~"...") +;; - JS eval (~`...`) +;; - custom faces. (defconst less-css-font-lock-keywords '(;; Variables - ("@[a-z_-][a-z-_0-9]*" . font-lock-constant-face) + ("@[a-z_-][a-z-_0-9]*" . font-lock-variable-name-face) ("&" . font-lock-preprocessor-face) ;; Mixins - ("\\(?:[ \t{;]\\|^\\)\\(\\.[a-z_-][a-z-_0-9]*\\)[ \t]*;" . (1 font-loc= k-keyword-face))) - ) - + ("\\(?:[ \t{;]\\|^\\)\\(\\.[a-z_-][a-z-_0-9]*\\)[ \t]*;" . + (1 font-lock-keyword-face)))) + +(defvar less-css-mode-syntax-table + (let ((st (make-syntax-table css-mode-syntax-table))) + ;; C++-style comments. + (modify-syntax-entry ?/ ". 124b" st) + (modify-syntax-entry ?* ". 23" st) + (modify-syntax-entry ?\n "> b" st) + ;; Special chars that sometimes come at the beginning of words. + (modify-syntax-entry ?. "'" st) + st)) + +(defvar less-css-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-c\C-c" 'less-css-compile) + map)) + +;;;###autoload (add-to-list 'auto-mode-alist '("\\.less\\'" . less-css-mod= e)) ;;;###autoload -(define-derived-mode less-css-mode css-mode "LESS" - "Major mode for editing LESS files, http://lesscss.org/ +(define-derived-mode less-css-mode css-mode "Less" + "Major mode for editing Less files (http://lesscss.org/). Special commands: \\{less-css-mode-map}" (font-lock-add-keywords nil less-css-font-lock-keywords) - ;; cpp-style comments - (modify-syntax-entry ?/ ". 124b" less-css-mode-syntax-table) - (modify-syntax-entry ?* ". 23" less-css-mode-syntax-table) - (modify-syntax-entry ?\n "> b" less-css-mode-syntax-table) - ;; Special chars that sometimes come at the beginning of words. - (modify-syntax-entry ?. "'" less-css-mode-syntax-table) - - (set (make-local-variable 'comment-start) "//") - (set (make-local-variable 'comment-end) "") - (set (make-local-variable 'indent-line-function) 'less-css-indent-line) - (when (functionp 'css-smie-rules) - (smie-setup css-smie-grammar #'css-smie-rules - :forward-token #'css-smie--forward-token - :backward-token #'css-smie--backward-token)) - + (setq-local comment-start "//") + (setq-local comment-end "") (add-hook 'after-save-hook 'less-css-compile-maybe nil t)) =20 -(define-key less-css-mode-map "\C-c\C-c" 'less-css-compile) - -(defun less-css-indent-line () - "Indent current line according to LESS CSS indentation rules." - (let ((css-navigation-syntax-table less-css-mode-syntax-table)) - (if (fboundp 'css-indent-line) - (css-indent-line) - (smie-indent-line)))) - -;;;###autoload -(add-to-list 'auto-mode-alist '("\\.less\\'" . less-css-mode)) - - (provide 'less-css-mode) ;;; less-css-mode.el ends here --=20 2.13.2 = --=-AlcmsjUGNvt/L11XRzLB-- --=-ganHNVWVIOy0wIe+ow0v--