Compare commits
No commits in common. "master" and "ab1503d2e851ce96aba74329c825ca99aa6f7e55" have entirely different histories.
master
...
ab1503d2e8
|
@ -1,388 +0,0 @@
|
|||
;;; edit-indirect.el --- Edit regions in separate buffers -*- lexical-binding: t -*-
|
||||
|
||||
;; Author: Fanael Linithien <fanael4@gmail.com>
|
||||
;; URL: https://github.com/Fanael/edit-indirect
|
||||
;; Version: 0.1.5
|
||||
;; Package-Requires: ((emacs "24.3"))
|
||||
|
||||
;; This file is NOT part of GNU Emacs.
|
||||
|
||||
;; SPDX-License-Identifier: BSD-2-clause
|
||||
;;
|
||||
;; Copyright (c) 2014-2017, Fanael Linithien
|
||||
;; All rights reserved.
|
||||
;;
|
||||
;; Redistribution and use in source and binary forms, with or without
|
||||
;; modification, are permitted provided that the following conditions are
|
||||
;; met:
|
||||
;;
|
||||
;; * Redistributions of source code must retain the above copyright
|
||||
;; notice, this list of conditions and the following disclaimer.
|
||||
;; * Redistributions in binary form must reproduce the above copyright
|
||||
;; notice, this list of conditions and the following disclaimer in the
|
||||
;; documentation and/or other materials provided with the distribution.
|
||||
;;
|
||||
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
;; IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
;; TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
;; PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
;; OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
;; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
;; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
;; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
;; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Edit regions in separate buffers, like `org-edit-src-code' but for arbitrary
|
||||
;; regions.
|
||||
;;
|
||||
;; See the docstring of `edit-indirect-region' for details.
|
||||
|
||||
;;; Code:
|
||||
(defgroup edit-indirect nil
|
||||
"Editing regions in separate buffers."
|
||||
:group 'editing)
|
||||
|
||||
(defcustom edit-indirect-guess-mode-function #'edit-indirect-default-guess-mode
|
||||
"The function used to guess the major mode of an edit-indirect buffer.
|
||||
It's called with the edit-indirect buffer as the current buffer.
|
||||
It's called with three arguments, the parent buffer, the beginning
|
||||
and the end of the parent buffer region being editing.
|
||||
|
||||
Note that the buffer-local value from the parent buffer is used."
|
||||
:type 'function
|
||||
:group 'edit-indirect)
|
||||
|
||||
(defcustom edit-indirect-after-creation-hook nil
|
||||
"Functions called after the edit-indirect buffer is created.
|
||||
The functions are called with the edit-indirect buffer as the
|
||||
current buffer.
|
||||
|
||||
Note that the buffer-local value from the parent buffer is used."
|
||||
:type 'hook
|
||||
:group 'edit-indirect)
|
||||
|
||||
(defcustom edit-indirect-before-commit-hook nil
|
||||
"Functions called before the edit-indirect buffer is committed.
|
||||
The functions are called with the edit-indirect buffer as the
|
||||
current buffer.
|
||||
|
||||
Note that the buffer-local value from the edit-indirect buffer is
|
||||
used."
|
||||
:type 'hook
|
||||
:group 'edit-indirect)
|
||||
|
||||
(defcustom edit-indirect-before-commit-functions nil
|
||||
"Functions called before an edit-indirect buffer is committed.
|
||||
The functions are called with the parent buffer as the current
|
||||
buffer.
|
||||
Each function is called with two arguments, the beginning and the
|
||||
end of the region to be changed."
|
||||
:type 'hook
|
||||
:group 'edit-indirect)
|
||||
|
||||
(defcustom edit-indirect-after-commit-functions nil
|
||||
"Functions called after an edit-indirect buffer has been committed.
|
||||
The functions are called with the parent buffer as the current
|
||||
buffer.
|
||||
Each function is called with two arguments, the beginning and the
|
||||
end of the changed region."
|
||||
:type 'hook
|
||||
:group 'edit-indirect)
|
||||
|
||||
(defgroup edit-indirect-faces nil
|
||||
"Faces used in `edit-indirect'."
|
||||
:group 'edit-indirect
|
||||
:group 'faces
|
||||
:prefix "edit-indirect")
|
||||
|
||||
(defface edit-indirect-edited-region
|
||||
'((t :inherit secondary-selection))
|
||||
"Face used to highlight an indirectly edited region."
|
||||
:group 'edit-indirect-faces)
|
||||
|
||||
;; Emacs <= 24.3 has no `define-error'.
|
||||
(let* ((user-error-conditions (get 'user-error 'error-conditions))
|
||||
(define-user-error (lambda (name message)
|
||||
(put name 'error-conditions
|
||||
(cons name user-error-conditions))
|
||||
(put name 'error-message message))))
|
||||
(funcall define-user-error 'edit-indirect-overlapping
|
||||
"Indirectly edited regions cannot overlap")
|
||||
(funcall define-user-error 'edit-indirect-read-only
|
||||
"Text is read-only, modify the edit-indirect buffer instead")
|
||||
(funcall define-user-error 'edit-indirect-not-indirect
|
||||
"This is not an edit-indirect buffer"))
|
||||
|
||||
(defvar edit-indirect--overlay)
|
||||
(defvar edit-indirect--should-quit-window nil)
|
||||
|
||||
;;;###autoload
|
||||
(defun edit-indirect-region (beg end &optional display-buffer)
|
||||
"Edit the region BEG..END in a separate buffer.
|
||||
The region is copied, without text properties, to a separate
|
||||
buffer, called edit-indirect buffer, and
|
||||
`edit-indirect-guess-mode-function' is called to set the major
|
||||
mode.
|
||||
When done, exit with `edit-indirect-commit', which will remove the
|
||||
original region and replace it with the edited version; or with
|
||||
`edit-indirect-abort', which will drop the modifications.
|
||||
|
||||
This differs from `clone-indirect-buffer' with narrowing in that
|
||||
the text properties are not shared, so the parent buffer major mode
|
||||
and the edit-indirect buffer major mode will not be able to tread
|
||||
on each other's toes by setting up potentially conflicting text
|
||||
properties, which happens surprisingly often when the font-lock
|
||||
mode is used.
|
||||
|
||||
Edit-indirect buffers use the `edit-indirect-mode-map' keymap.
|
||||
|
||||
If there's already an edit-indirect buffer for BEG..END, use that.
|
||||
If there's already an edit-indirect buffer active overlapping any
|
||||
portion of BEG..END, an `edit-indirect-overlapping' error is
|
||||
signaled.
|
||||
|
||||
When DISPLAY-BUFFER is non-nil or when called interactively,
|
||||
display the edit-indirect buffer in some window and select it.
|
||||
|
||||
In any case, return the edit-indirect buffer."
|
||||
(interactive
|
||||
(if (or (use-region-p) (not transient-mark-mode))
|
||||
(prog1 (list (region-beginning) (region-end) t)
|
||||
(deactivate-mark))
|
||||
(user-error "No region")))
|
||||
(let ((buffer (edit-indirect--get-edit-indirect-buffer beg end)))
|
||||
(when display-buffer
|
||||
(with-current-buffer buffer
|
||||
(setq-local edit-indirect--should-quit-window t))
|
||||
(select-window (display-buffer buffer)))
|
||||
buffer))
|
||||
|
||||
(defvar edit-indirect-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map (kbd "C-x C-s") #'edit-indirect-save)
|
||||
(define-key map (kbd "C-c '") #'edit-indirect-commit)
|
||||
(define-key map (kbd "C-c C-c") #'edit-indirect-commit)
|
||||
(define-key map (kbd "C-c C-k") #'edit-indirect-abort)
|
||||
map)
|
||||
"Keymap for edit-indirect buffers.
|
||||
|
||||
\\{edit-indirect-mode-map}")
|
||||
|
||||
(defun edit-indirect-commit ()
|
||||
"Commit the modifications done in an edit-indirect buffer.
|
||||
That is, replace the original region in the parent buffer with the
|
||||
contents of the edit-indirect buffer.
|
||||
The edit-indirect buffer is then killed.
|
||||
|
||||
Can be called only when the current buffer is an edit-indirect
|
||||
buffer."
|
||||
(interactive)
|
||||
(edit-indirect--barf-if-not-indirect)
|
||||
(edit-indirect--commit)
|
||||
(edit-indirect--clean-up))
|
||||
|
||||
(defun edit-indirect-save ()
|
||||
"Save the modifications done in an edit-indirect buffer.
|
||||
That is, replace the original region in the parent buffer with the
|
||||
contents of the edit-indirect buffer.
|
||||
|
||||
Can be called only when the current buffer is an edit-indirect
|
||||
buffer."
|
||||
(interactive)
|
||||
(edit-indirect--barf-if-not-indirect)
|
||||
(edit-indirect--commit))
|
||||
|
||||
(defun edit-indirect-abort ()
|
||||
"Abort indirect editing in the current buffer and kill the buffer.
|
||||
|
||||
Can be called only when the current buffer is an edit-indirect
|
||||
buffer."
|
||||
(interactive)
|
||||
(edit-indirect--barf-if-not-indirect)
|
||||
(edit-indirect--abort))
|
||||
|
||||
(defun edit-indirect-buffer-indirect-p (&optional buffer)
|
||||
"Non-nil iff the BUFFER is an edit-indirect buffer.
|
||||
BUFFER defaults to the current buffer."
|
||||
(save-current-buffer
|
||||
(when buffer
|
||||
(set-buffer buffer))
|
||||
;; (not (null)) so we don't leak the overlay to the outside world.
|
||||
(not (null edit-indirect--overlay))))
|
||||
|
||||
(defun edit-indirect-default-guess-mode (_parent-buffer _beg _end)
|
||||
"Guess the major mode for an edit-indirect buffer.
|
||||
It's done by calling `normal-mode'."
|
||||
(normal-mode))
|
||||
|
||||
(defvar edit-indirect--overlay nil
|
||||
"The overlay spanning the region of the parent buffer being edited.
|
||||
|
||||
It's also used as the variable determining if we're in an
|
||||
edit-indirect buffer at all.")
|
||||
(make-variable-buffer-local 'edit-indirect--overlay)
|
||||
(put 'edit-indirect--overlay 'permanent-local t)
|
||||
|
||||
;; Normally this would use `define-minor-mode', but that makes the mode function
|
||||
;; interactive, which we don't want, because it's just an implementation detail.
|
||||
(defun edit-indirect--mode (overlay)
|
||||
"Turn the `edit-indirect--mode' \"minor mode\" on.
|
||||
OVERLAY is the value to set `edit-indirect--overlay' to."
|
||||
(setq edit-indirect--overlay overlay)
|
||||
(add-hook 'kill-buffer-hook #'edit-indirect--abort-on-kill-buffer nil t))
|
||||
(with-no-warnings
|
||||
(add-minor-mode
|
||||
'edit-indirect--overlay " indirect" edit-indirect-mode-map nil #'ignore))
|
||||
|
||||
(defun edit-indirect--get-edit-indirect-buffer (beg end)
|
||||
"Return an edit-indirect buffer for the region BEG..END.
|
||||
If there's already an edit-indirect buffer active overlapping any
|
||||
portion of BEG..END, an `edit-indirect-overlapping' error is
|
||||
signaled."
|
||||
(let ((old-overlay (edit-indirect--search-for-edit-indirect beg end)))
|
||||
(cond
|
||||
((null old-overlay)
|
||||
(let ((overlay (edit-indirect--create-overlay beg end)))
|
||||
(edit-indirect--create-indirect-buffer beg end overlay)))
|
||||
((and (= beg (overlay-start old-overlay))
|
||||
(= end (overlay-end old-overlay)))
|
||||
(overlay-get old-overlay 'edit-indirect-buffer))
|
||||
(t
|
||||
(signal 'edit-indirect-overlapping '())))))
|
||||
|
||||
(defun edit-indirect--search-for-edit-indirect (beg end)
|
||||
"Return an existing edit-indirect overlay for some region inside BEG..END.
|
||||
If there's no indirectly edited region inside BEG..END, return
|
||||
nil."
|
||||
(catch 'done
|
||||
(dolist (overlay (overlays-in beg end))
|
||||
(when (overlay-get overlay 'edit-indirect-buffer)
|
||||
(throw 'done overlay)))
|
||||
nil))
|
||||
|
||||
(defmacro edit-indirect--buffer-local-value (buffer variable)
|
||||
"Get the BUFFER local value of VARIABLE.
|
||||
VARIABLE shall be a symbol."
|
||||
(unless (symbolp variable)
|
||||
(signal 'wrong-type-argument (list #'symbolp variable)))
|
||||
;; `with-current-buffer' is used instead of `buffer-local-value' because
|
||||
;; the latter doesn't give warnings about free variables when
|
||||
;; byte-compiled.
|
||||
`(with-current-buffer ,buffer ,variable))
|
||||
|
||||
(defun edit-indirect--create-indirect-buffer (beg end overlay)
|
||||
"Create an edit-indirect buffer and return it.
|
||||
|
||||
BEG..END is the parent buffer region to insert.
|
||||
OVERLAY is the overlay, see `edit-indirect--overlay'."
|
||||
(let ((buffer (generate-new-buffer (format "*edit-indirect %s*" (buffer-name))))
|
||||
(parent-buffer (current-buffer)))
|
||||
(overlay-put overlay 'edit-indirect-buffer buffer)
|
||||
(with-current-buffer buffer
|
||||
(insert-buffer-substring-no-properties parent-buffer beg end)
|
||||
(set-buffer-modified-p nil)
|
||||
(edit-indirect--mode overlay)
|
||||
;; Use the buffer-local values from the parent buffer. Don't retrieve the
|
||||
;; values before actual uses in case these variables are changed by some
|
||||
;; of the many possible hooks.
|
||||
(funcall (edit-indirect--buffer-local-value
|
||||
parent-buffer edit-indirect-guess-mode-function)
|
||||
parent-buffer beg end)
|
||||
(let ((edit-indirect-after-creation-hook
|
||||
(edit-indirect--buffer-local-value
|
||||
parent-buffer edit-indirect-after-creation-hook)))
|
||||
(run-hooks 'edit-indirect-after-creation-hook)))
|
||||
buffer))
|
||||
|
||||
(defun edit-indirect--create-overlay (beg end)
|
||||
"Create the edit-indirect overlay and return it.
|
||||
|
||||
BEG and END specify the region the overlay should encompass."
|
||||
(let ((overlay (make-overlay beg end)))
|
||||
(overlay-put overlay 'face 'edit-indirect-edited-region)
|
||||
(overlay-put overlay 'modification-hooks '(edit-indirect--barf-read-only))
|
||||
(overlay-put overlay 'insert-in-front-hooks '(edit-indirect--barf-read-only))
|
||||
overlay))
|
||||
|
||||
(defvar edit-indirect--inhibit-read-only nil
|
||||
"Non-nil means disregard read-only status of indirectly-edited region.")
|
||||
|
||||
(defun edit-indirect--barf-read-only (_ov _after _beg _end &optional _len)
|
||||
"Signal an error because the text is read-only.
|
||||
No error is signaled if `inhibit-read-only' or
|
||||
`edit-indirect--inhibit-read-only' is non-nil."
|
||||
(unless (or inhibit-read-only edit-indirect--inhibit-read-only)
|
||||
(signal 'edit-indirect-read-only '())))
|
||||
|
||||
(defun edit-indirect--commit ()
|
||||
"Commit the modifications done in an edit-indirect buffer."
|
||||
(run-hooks 'edit-indirect-before-commit-hook)
|
||||
(let ((beg (overlay-start edit-indirect--overlay))
|
||||
(end (overlay-end edit-indirect--overlay))
|
||||
(buffer (current-buffer))
|
||||
(edit-indirect--inhibit-read-only t))
|
||||
(with-current-buffer (overlay-buffer edit-indirect--overlay)
|
||||
(save-excursion
|
||||
(let ((beg-marker (copy-marker beg))
|
||||
(end-marker (copy-marker end)))
|
||||
(edit-indirect--run-hook-with-positions
|
||||
'edit-indirect-before-commit-functions beg-marker end-marker)
|
||||
(save-match-data
|
||||
(set-match-data (list beg-marker end-marker))
|
||||
(replace-match (with-current-buffer buffer
|
||||
(buffer-substring-no-properties 1 (1+ (buffer-size))))
|
||||
t t))
|
||||
(edit-indirect--run-hook-with-positions
|
||||
'edit-indirect-after-commit-functions beg-marker (point))
|
||||
(set-marker beg-marker nil)
|
||||
(set-marker end-marker nil))))))
|
||||
|
||||
(defun edit-indirect--run-hook-with-positions (hook beg end)
|
||||
"Run HOOK with the specified positions BEG and END.
|
||||
HOOK should be a symbol, a hook variable.
|
||||
The functions are passed integer positions.
|
||||
If a function changes the buffer contents, the next function will be
|
||||
called with updated positions."
|
||||
(let ((beg-marker (unless (markerp beg) (copy-marker beg)))
|
||||
(end-marker (unless (markerp end) (copy-marker end))))
|
||||
(run-hook-wrapped hook
|
||||
(lambda (f beg end)
|
||||
(funcall f (marker-position beg) (marker-position end))
|
||||
nil)
|
||||
(or beg-marker beg) (or end-marker end))
|
||||
(when beg-marker (set-marker beg-marker nil))
|
||||
(when end-marker (set-marker end-marker nil))))
|
||||
|
||||
(defun edit-indirect--abort ()
|
||||
"Abort indirect edit."
|
||||
(edit-indirect--clean-up))
|
||||
|
||||
(defun edit-indirect--clean-up ()
|
||||
"Clean up an edit-indirect buffer."
|
||||
(delete-overlay edit-indirect--overlay)
|
||||
;; Kill the overlay reference so that `edit-indirect--abort-on-kill-buffer'
|
||||
;; won't try to call us again.
|
||||
(setq edit-indirect--overlay nil)
|
||||
;; If we created a window, get rid of it. Kill the buffer we created.
|
||||
(if edit-indirect--should-quit-window
|
||||
(quit-window t)
|
||||
(kill-buffer)))
|
||||
|
||||
(defun edit-indirect--abort-on-kill-buffer ()
|
||||
"Abort indirect edit.
|
||||
Should be called only from `kill-buffer-hook'."
|
||||
(when edit-indirect--overlay
|
||||
(edit-indirect--abort)))
|
||||
|
||||
(defun edit-indirect--barf-if-not-indirect ()
|
||||
"Signal an error if the current buffer is not an edit-indirect buffer.
|
||||
The error signaled is `edit-indirect-not-indirect'."
|
||||
(unless edit-indirect--overlay
|
||||
(signal 'edit-indirect-not-indirect '())))
|
||||
|
||||
(provide 'edit-indirect)
|
||||
;;; edit-indirect.el ends here
|
|
@ -1 +1 @@
|
|||
Subproject commit 35f6826e435c3004dabf134d0f2ae2f31ea7b6a2
|
||||
Subproject commit 64be4a31390a62d248da5c0509aaa0de09b8e4f4
|
|
@ -1,242 +0,0 @@
|
|||
;;; ssass-mode.el --- Edit Sass without a Turing Machine
|
||||
|
||||
;; Copyright 2017 Adam Niederer
|
||||
|
||||
;; Author: Adam Niederer <adam.niederer@gmail.com>
|
||||
;; URL: http://github.com/AdamNiederer/ssass-mode
|
||||
;; Version: 0.2.0
|
||||
;; Keywords: languages sass
|
||||
;; Package-Requires: ((emacs "24.3"))
|
||||
|
||||
;; 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:
|
||||
;; This mode is a clone of sass-mode which works in mmm-mode and doesn't
|
||||
;; indent things as eagerly. Syntax highlighting is provided with
|
||||
;; `font-lock-mode'.
|
||||
;;
|
||||
;; Exported names start with "ssass-"; private names start with
|
||||
;; "ssass--".
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defgroup ssass nil
|
||||
"Major mode for Sass files"
|
||||
:prefix "ssass-"
|
||||
:group 'languages
|
||||
:link '(url-link :tag "Github" "https://github.com/AdamNiederer/ssass-mode")
|
||||
:link '(emacs-commentary-link :tag "Commentary" "ssass-mode"))
|
||||
|
||||
(defconst ssass-id-regex
|
||||
"#[a-z][A-Za-z0-9\-]+")
|
||||
|
||||
(defconst ssass-class-regex
|
||||
"\\.[a-z][A-Za-z0-9\-]+")
|
||||
|
||||
(defconst ssass-pseudoselector-regex
|
||||
"::?[A-Za-z0-9\-]+")
|
||||
|
||||
(defconst ssass-key-regex
|
||||
"^\s+[a-z\-]+:")
|
||||
|
||||
(defconst ssass-directive-noindent-regex
|
||||
"@\\(include\\|extend\\|import\\|warn\\|debug\\|error\\)"
|
||||
"Matches all directives which do not require indentation.")
|
||||
|
||||
(defconst ssass-variable-regex
|
||||
"\$[A-Za-z0-9\-]+")
|
||||
|
||||
(defconst ssass-variable-assignment-regex
|
||||
(concat ssass-variable-regex ":"))
|
||||
|
||||
(defconst ssass-builtin-regex
|
||||
"@[A-Za-z]+")
|
||||
|
||||
(defconst ssass-comment-regex
|
||||
"^\s+/[/*].*") ; TODO: Make better or use syntax table
|
||||
|
||||
(defconst ssass-function-regex
|
||||
"\\([A-Za-z\-]+?\\)\\((.*)\\)")
|
||||
|
||||
(defconst ssass-keywords
|
||||
'("and" "or" "not" "in" "from" "to" "through"))
|
||||
|
||||
(defconst ssass-control-directives
|
||||
'("@if" "@else" "@each" "@for"))
|
||||
|
||||
(defconst ssass-function-directives
|
||||
'("@function" "@return"))
|
||||
|
||||
(defconst ssass-mixin-directives
|
||||
'("@mixin" "@include"))
|
||||
|
||||
(defconst ssass-constants
|
||||
'("true" "false" "null"))
|
||||
|
||||
(defconst ssass-bang-regex
|
||||
"![a-z][A-Za-z0-9]+")
|
||||
|
||||
(defcustom ssass-tab-width 2
|
||||
"Tab width for ‘ssass-mode’."
|
||||
:group 'ssass
|
||||
:type 'integer)
|
||||
|
||||
(defcustom ssass-indent-blanks t
|
||||
"Whether to indent blank lines."
|
||||
:group 'ssass
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom ssass-compiler "sassc"
|
||||
"Sass compiler for `ssass-eval-region' and `ssass-eval-buffer'."
|
||||
:group 'ssass
|
||||
:type 'string)
|
||||
|
||||
(defcustom ssass-opt "--sass"
|
||||
"Options for `ssass-compiler'.
|
||||
|
||||
Use --sass for sassc, and --indented-syntax for node-sass."
|
||||
:group 'ssass
|
||||
:type 'string)
|
||||
|
||||
(defcustom ssass-color-keys nil
|
||||
"(TODO) Whether to color proprty names."
|
||||
:group 'ssass
|
||||
:type 'boolean)
|
||||
|
||||
(defconst ssass-font-lock-keywords
|
||||
`((,ssass-id-regex . (0 font-lock-keyword-face))
|
||||
(,ssass-class-regex . (0 font-lock-type-face))
|
||||
(,ssass-key-regex . (0 font-lock-variable-name-face))
|
||||
(,ssass-function-regex . (1 font-lock-function-name-face))
|
||||
(,ssass-builtin-regex . (0 font-lock-builtin-face))
|
||||
(,ssass-pseudoselector-regex . (0 font-lock-function-name-face))
|
||||
(,ssass-variable-regex . (0 font-lock-variable-name-face))
|
||||
(,ssass-bang-regex . (0 font-lock-warning-face))
|
||||
(,(regexp-opt ssass-keywords 'words) . font-lock-keyword-face)
|
||||
(,(regexp-opt ssass-control-directives 'words) . font-lock-keyword-face)
|
||||
(,(regexp-opt ssass-function-directives 'words) . font-lock-keyword-face)
|
||||
(,(regexp-opt ssass-constants 'words) . font-lock-constant-face))
|
||||
"List of Font Lock keywords.")
|
||||
|
||||
(defvar ssass-mode-map
|
||||
(let ((map (make-keymap)))
|
||||
(define-key map (kbd "<backtab>") 'ssass-dedent)
|
||||
(define-key map (kbd "C-c C-c") 'ssass-eval-buffer)
|
||||
(define-key map (kbd "C-c C-r") 'ssass-eval-region)
|
||||
map)
|
||||
"Keymap for ‘ssass-mode’.")
|
||||
|
||||
(defun ssass--selector-p (line)
|
||||
"Return whether LINE is a selector."
|
||||
(not (or (string-empty-p line)
|
||||
(string-match-p ssass-key-regex line)
|
||||
(string-match-p ssass-variable-assignment-regex line)
|
||||
(string-match-p ssass-directive-noindent-regex line)
|
||||
(string-match-p ssass-comment-regex line))))
|
||||
|
||||
(defun ssass--goto-last-anchor-line ()
|
||||
"Move point to the line of the last selector, or the beginning of the buffer."
|
||||
(forward-line -1)
|
||||
(while (not (or (equal (point-min) (point-at-bol))
|
||||
(ssass--selector-p (buffer-substring (point-at-bol) (point-at-eol)))))
|
||||
(forward-line -1)))
|
||||
|
||||
(defun ssass--last-anchor-line-indent-level ()
|
||||
"Return the number of spaces indenting the line of the last selector."
|
||||
(save-excursion
|
||||
(ssass--goto-last-anchor-line)
|
||||
(ssass--indent-level)))
|
||||
|
||||
(defun ssass--indent-level ()
|
||||
"Return the number of spaces indenting the current line."
|
||||
(- (save-excursion
|
||||
(back-to-indentation)
|
||||
(current-column))
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(current-column))))
|
||||
|
||||
(defun ssass--whitespace-p (line)
|
||||
"Return whether the line at offset from point LINE consists solely of whitespace."
|
||||
(save-excursion
|
||||
(forward-line line)
|
||||
(string-match-p "^[[:space:]]*$" (buffer-substring (point-at-bol) (point-at-eol)))))
|
||||
|
||||
(defun ssass--comma-before-p ()
|
||||
"Return whether the previous line has a comma at its end."
|
||||
(save-excursion
|
||||
(forward-line -1)
|
||||
(string-match-p ",\\s-*$" (buffer-substring (point-at-bol) (point-at-eol)))))
|
||||
|
||||
(defun ssass--no-anchor-line-p ()
|
||||
"Return whether there is no proper selector or keyword above this line."
|
||||
(save-excursion
|
||||
(ssass--goto-last-anchor-line)
|
||||
(not (ssass--selector-p (buffer-substring (point-at-bol) (point-at-eol))))))
|
||||
|
||||
(defun ssass-indent ()
|
||||
"Indent the current line."
|
||||
(interactive)
|
||||
(indent-line-to
|
||||
(cond
|
||||
((and (not ssass-indent-blanks) (ssass--whitespace-p 0)) 0)
|
||||
((ssass--whitespace-p -1) 0)
|
||||
((ssass--no-anchor-line-p) 0)
|
||||
((ssass--comma-before-p) (ssass--last-anchor-line-indent-level))
|
||||
(t (+ ssass-tab-width (ssass--last-anchor-line-indent-level))))))
|
||||
|
||||
(defun ssass-dedent ()
|
||||
"Remove one level of indentation from the current line."
|
||||
(interactive)
|
||||
(indent-line-to (max 0 (- (ssass--indent-level) ssass-tab-width))))
|
||||
|
||||
(defun ssass-eval-file (&optional filename)
|
||||
"Run the given file through sass, and display the output in another window.
|
||||
|
||||
If FILENAME is nil, it will open the current buffer's file"
|
||||
(interactive)
|
||||
(when (buffer-live-p (get-buffer "*sass*"))
|
||||
(kill-buffer "*sass*"))
|
||||
(start-process "sass" "*sass*" ssass-compiler ssass-opt (or filename (buffer-file-name)))
|
||||
(switch-to-buffer-other-window "*sass*")
|
||||
(special-mode))
|
||||
|
||||
(defun ssass-eval-region (beg end)
|
||||
"Run the region from BEG to END through sass, and display the output in another window."
|
||||
(interactive "r")
|
||||
(let ((tmp-file (make-temp-file "sass-eval" nil ".sass")))
|
||||
(write-region beg end tmp-file nil nil nil nil)
|
||||
(ssass-eval-file tmp-file)
|
||||
(delete-file tmp-file)) )
|
||||
|
||||
(defun ssass-eval-buffer ()
|
||||
"Run the current buffer through sass, and display the output in another window."
|
||||
(interactive)
|
||||
(ssass-eval-region (point-min) (point-max)))
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode ssass-mode prog-mode "Ssass"
|
||||
"Major mode for Sass"
|
||||
(setq-local electric-indent-mode nil)
|
||||
(setq-local comment-start "//")
|
||||
(setq-local comment-start-skip "\\(//+\\|/\\*+\\)\\s *")
|
||||
(set (make-local-variable 'tab-width) ssass-tab-width)
|
||||
(set (make-local-variable 'indent-line-function) 'ssass-indent)
|
||||
(font-lock-add-keywords nil ssass-font-lock-keywords)
|
||||
(modify-syntax-entry ?/ ". 124" ssass-mode-syntax-table)
|
||||
(modify-syntax-entry ?* ". 23b" ssass-mode-syntax-table)
|
||||
(modify-syntax-entry ?\n ">" ssass-mode-syntax-table))
|
||||
|
||||
(provide 'ssass-mode)
|
||||
;;; ssass-mode.el ends here
|
|
@ -1,131 +0,0 @@
|
|||
;;; vue-html-mode.el --- Major mode for editing Vue.js templates
|
||||
|
||||
;; Copyright 2016, 2017 Adam Niederer
|
||||
|
||||
;; Author: Adam Niederer <adam.niederer@gmail.com>
|
||||
;; URL: http://github.com/AdamNiederer/vue-html-mode
|
||||
;; Version: 0.2.0
|
||||
;; Keywords: languages vue template
|
||||
;; Package-Requires: ()
|
||||
|
||||
;; 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
|
||||
|
||||
;; The main features of this mode are syntax highlighting (enabled with
|
||||
;; `font-lock-mode' or `global-font-lock-mode'), and html-mode
|
||||
;; integration
|
||||
;;
|
||||
;; Exported names start with "vue-html-"; private names start with
|
||||
;; "vue-html--".
|
||||
;;
|
||||
;; TODO: Chained filters, possible code folding with overlays and colors
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defgroup vue-html nil
|
||||
"Major mode for vue template files"
|
||||
:prefix "vue-html-"
|
||||
:group 'languages
|
||||
:link '(url-link :tag "Github" "https://github.com/AdamNiederer/vue-html-mode")
|
||||
:link '(emacs-commentary-link :tag "Commentary" "vue-html-mode"))
|
||||
|
||||
(defconst vue-html-complex-interp-regex
|
||||
"\\({{\\)\\([^{].*?\\)?\\(|\\) *\\(.*?\\)(.*) *\\(}}\\)")
|
||||
|
||||
(defconst vue-html-filter-interp-regex
|
||||
"\\({{\\)\\([^{].*?\\)?\\(|\\) *\\([^\(\)]*?\\) *\\(}}\\)")
|
||||
|
||||
(defconst vue-html-simple-interp-regex
|
||||
"\\({{\\)\\(?:[^{].*?\\)?\\(}}\\)")
|
||||
|
||||
(defconst vue-html-shorthand-regex
|
||||
"\\s +\\([@:]\\)\\([A-z0-9-.]+\\)=.*?")
|
||||
|
||||
(defconst vue-html-directive-regex
|
||||
"\\b\\(v-[A-Za-z0-9-.]+\\)\\(:[A-z.]\\)?")
|
||||
|
||||
(defconst vue-html-keyword-regex
|
||||
"\\(v-\\(?:for\\|if\\|else-if\\|else\\|once\\)\\)[^-.A-Za-z0-9]")
|
||||
|
||||
(defcustom vue-html-tab-width 2
|
||||
"Tab width for vue-html-mode."
|
||||
:group 'vue-html
|
||||
:type 'integer)
|
||||
|
||||
(defcustom vue-html-extra-indent 0
|
||||
"The number of columns added to every line's indentation."
|
||||
:group 'vue-html
|
||||
:type 'integer)
|
||||
|
||||
(defcustom vue-html-color-interpolations nil
|
||||
"Whether to color the body of variable interpolations the same as delimiters.
|
||||
Does not affect the colors of filters and their arguments."
|
||||
:group 'vue-html
|
||||
:type 'boolean)
|
||||
|
||||
(defconst vue-html-color-interpolations-font-lock-keywords
|
||||
`((,vue-html-simple-interp-regex . (0 font-lock-variable-name-face t))
|
||||
(,vue-html-filter-interp-regex . (2 font-lock-variable-name-face t))
|
||||
(,vue-html-complex-interp-regex . (2 font-lock-variable-name-face t)))
|
||||
"List of Font Lock rules applied if `vue-html-color-interpolations' is non-nil.")
|
||||
|
||||
(defconst vue-html-font-lock-keywords
|
||||
`((,vue-html-simple-interp-regex . (1 font-lock-variable-name-face t))
|
||||
(,vue-html-simple-interp-regex . (2 font-lock-variable-name-face t))
|
||||
(,vue-html-filter-interp-regex . (1 font-lock-variable-name-face t))
|
||||
(,vue-html-filter-interp-regex . (3 font-lock-function-name-face t))
|
||||
(,vue-html-filter-interp-regex . (4 font-lock-function-name-face t))
|
||||
(,vue-html-filter-interp-regex . (5 font-lock-variable-name-face t))
|
||||
(,vue-html-complex-interp-regex . (1 font-lock-variable-name-face t))
|
||||
(,vue-html-complex-interp-regex . (3 font-lock-function-name-face t))
|
||||
(,vue-html-complex-interp-regex . (4 font-lock-function-name-face t))
|
||||
(,vue-html-complex-interp-regex . (5 font-lock-variable-name-face t))
|
||||
(,vue-html-directive-regex . (1 font-lock-builtin-face t))
|
||||
(,vue-html-shorthand-regex . (1 font-lock-builtin-face t))
|
||||
(,vue-html-shorthand-regex . (2 font-lock-variable-name-face t))
|
||||
(,vue-html-keyword-regex . (1 font-lock-keyword-face t)))
|
||||
"List of Font Lock keywords which are applied regardless of settings.")
|
||||
|
||||
(defvar vue-html-mode-map
|
||||
(let ((map (make-keymap)))
|
||||
map)
|
||||
"Keymap for vue-html-mode.")
|
||||
|
||||
(defun vue-html-last-line-p ()
|
||||
"Return whether point is on the last line in the buffer."
|
||||
(save-excursion (= (line-number-at-pos) (line-number-at-pos (point-max)))))
|
||||
|
||||
(defun vue-html-line-empty-p ()
|
||||
"Return whether point is on an empty line."
|
||||
(string-match-p "^\s*$" (buffer-substring (point-at-bol) (point-at-eol))))
|
||||
|
||||
(defun vue-html-indent ()
|
||||
"Indent the line according to `vue-html-tab-width' and `vue-html-extra-indent'."
|
||||
(cond
|
||||
((= 1 (line-number-at-pos)) (indent-line-to vue-html-extra-indent))
|
||||
((and (vue-html-last-line-p) (vue-html-line-empty-p)) (indent-line-to 0))
|
||||
(t (sgml-indent-line))))
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode vue-html-mode html-mode "vue-html"
|
||||
"Major mode for Vue.js templates."
|
||||
(setq tab-width vue-html-tab-width)
|
||||
(setq indent-line-function #'vue-html-indent)
|
||||
(font-lock-add-keywords nil vue-html-font-lock-keywords)
|
||||
(when vue-html-color-interpolations
|
||||
(font-lock-add-keywords nil vue-html-color-interpolations-font-lock-keywords)))
|
||||
|
||||
(provide 'vue-html-mode)
|
||||
;;; vue-html-mode.el ends here
|
Loading…
Reference in New Issue
Block a user