2011-03-11 15:04:22 -05:00
|
|
|
;;; smie.el --- Simple Minded Indentation Engine -*- lexical-binding: t -*-
|
2010-11-07 10:52:33 -05:00
|
|
|
|
2020-01-01 00:19:43 +00:00
|
|
|
;; Copyright (C) 2010-2020 Free Software Foundation, Inc.
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
|
|
|
|
;; Keywords: languages, lisp, internal, parsing, indentation
|
|
|
|
|
|
|
|
;; 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
|
2017-09-13 15:52:52 -07:00
|
|
|
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
|
|
;; While working on the SML indentation code, the idea grew that maybe
|
|
|
|
;; I could write something generic to do the same thing, and at the
|
|
|
|
;; end of working on the SML code, I had a pretty good idea of what it
|
|
|
|
;; could look like. That idea grew stronger after working on
|
|
|
|
;; LaTeX indentation.
|
|
|
|
;;
|
|
|
|
;; So at some point I decided to try it out, by writing a new
|
|
|
|
;; indentation code for Coq while trying to keep most of the code
|
|
|
|
;; "table driven", where only the tables are Coq-specific. The result
|
|
|
|
;; (which was used for Beluga-mode as well) turned out to be based on
|
|
|
|
;; something pretty close to an operator precedence parser.
|
|
|
|
|
|
|
|
;; So here is another rewrite, this time following the actual principles of
|
|
|
|
;; operator precedence grammars. Why OPG? Even though they're among the
|
|
|
|
;; weakest kinds of parsers, these parsers have some very desirable properties
|
|
|
|
;; for Emacs:
|
|
|
|
;; - most importantly for indentation, they work equally well in either
|
|
|
|
;; direction, so you can use them to parse backward from the indentation
|
|
|
|
;; point to learn the syntactic context;
|
|
|
|
;; - they work locally, so there's no need to keep a cache of
|
|
|
|
;; the parser's state;
|
|
|
|
;; - because of that locality, indentation also works just fine when earlier
|
|
|
|
;; parts of the buffer are syntactically incorrect since the indentation
|
|
|
|
;; looks at "as little as possible" of the buffer to make an indentation
|
|
|
|
;; decision.
|
|
|
|
;; - they typically have no error handling and can't even detect a parsing
|
|
|
|
;; error, so we don't have to worry about what to do in case of a syntax
|
|
|
|
;; error because the parser just automatically does something. Better yet,
|
|
|
|
;; we can afford to use a sloppy grammar.
|
|
|
|
|
2020-05-29 15:01:58 -04:00
|
|
|
;; The benefits of this approach were presented in the following article,
|
|
|
|
;; which includes a kind of tutorial to get started with SMIE:
|
|
|
|
;;
|
|
|
|
;; SMIE: Weakness is Power! Auto-indentation with incomplete information
|
|
|
|
;; Stefan Monnier, <Programming> Journal 2020, volumn 5, issue 1.
|
|
|
|
;; doi: 10.22152/programming-journal.org/2020/5/1
|
|
|
|
|
2010-11-07 10:52:33 -05:00
|
|
|
;; A good background to understand the development (especially the parts
|
|
|
|
;; building the 2D precedence tables and then computing the precedence levels
|
|
|
|
;; from it) can be found in pages 187-194 of "Parsing techniques" by Dick Grune
|
|
|
|
;; and Ceriel Jacobs (BookBody.pdf available at
|
2012-02-04 16:43:26 +08:00
|
|
|
;; http://dickgrune.com/Books/PTAPG_1st_Edition/).
|
2010-11-07 10:52:33 -05:00
|
|
|
;;
|
|
|
|
;; OTOH we had to kill many chickens, read many coffee grounds, and practice
|
|
|
|
;; untold numbers of black magic spells, to come up with the indentation code.
|
|
|
|
;; Since then, some of that code has been beaten into submission, but the
|
|
|
|
;; smie-indent-keyword is still pretty obscure.
|
|
|
|
|
2020-05-29 15:01:58 -04:00
|
|
|
|
2010-11-11 00:08:25 -05:00
|
|
|
;; Conflict resolution:
|
|
|
|
;;
|
|
|
|
;; - One source of conflicts is when you have:
|
|
|
|
;; (exp ("IF" exp "ELSE" exp "END") ("CASE" cases "END"))
|
|
|
|
;; (cases (cases "ELSE" insts) ...)
|
|
|
|
;; The IF-rule implies ELSE=END and the CASE-rule implies ELSE>END.
|
2011-11-18 11:30:43 -05:00
|
|
|
;; This can be resolved simply with:
|
|
|
|
;; (exp ("IF" expelseexp "END") ("CASE" cases "END"))
|
|
|
|
;; (expelseexp (exp) (exp "ELSE" exp))
|
|
|
|
;; (cases (cases "ELSE" insts) ...)
|
|
|
|
;; - Another source of conflict is when a terminator/separator is used to
|
|
|
|
;; terminate elements at different levels, as in:
|
|
|
|
;; (decls ("VAR" vars) (decls "," decls))
|
|
|
|
;; (vars (id) (vars "," vars))
|
|
|
|
;; often these can be resolved by making the lexer distinguish the two
|
|
|
|
;; kinds of commas, e.g. based on the following token.
|
2010-11-11 00:08:25 -05:00
|
|
|
|
2010-11-11 20:33:28 -05:00
|
|
|
;; TODO & BUGS:
|
|
|
|
;;
|
2011-11-18 11:30:43 -05:00
|
|
|
;; - We could try to resolve conflicts such as the IFexpELSEexpEND -vs-
|
|
|
|
;; CASE(casesELSEexp)END automatically by changing the way BNF rules such as
|
|
|
|
;; the IF-rule is handled. I.e. rather than IF=ELSE and ELSE=END, we could
|
|
|
|
;; turn them into IF<ELSE and ELSE>END and IF=END.
|
2010-11-11 20:33:28 -05:00
|
|
|
;; - Using the structural information SMIE gives us, it should be possible to
|
|
|
|
;; implement a `smie-align' command that would automatically figure out what
|
|
|
|
;; there is to align and how to do it (something like: align the token of
|
|
|
|
;; lowest precedence that appears the same number of times on all lines,
|
|
|
|
;; and then do the same on each side of that token).
|
|
|
|
;; - Maybe accept two juxtaposed non-terminals in the BNF under the condition
|
|
|
|
;; that the first always ends with a terminal, or that the second always
|
|
|
|
;; starts with a terminal.
|
2011-06-15 14:36:00 -04:00
|
|
|
;; - Permit EBNF-style notation.
|
|
|
|
;; - If the grammar has conflicts, the only way is to make the lexer return
|
|
|
|
;; different tokens for the different cases. This extra work performed by
|
|
|
|
;; the lexer can be costly and unnecessary: we perform this extra work every
|
|
|
|
;; time we find the conflicting token, regardless of whether or not the
|
|
|
|
;; difference between the various situations is relevant to the current
|
|
|
|
;; situation. E.g. we may try to determine whether a ";" is a ";-operator"
|
|
|
|
;; or a ";-separator" in a case where we're skipping over a "begin..end" pair
|
|
|
|
;; where the difference doesn't matter. For frequently occurring tokens and
|
|
|
|
;; rarely occurring conflicts, this can be a significant performance problem.
|
|
|
|
;; We could try and let the lexer return a "set of possible tokens
|
|
|
|
;; plus a refinement function" and then let parser call the refinement
|
|
|
|
;; function if needed.
|
|
|
|
;; - Make it possible to better specify the behavior in the face of
|
|
|
|
;; syntax errors. IOW provide some control over the choice of precedence
|
|
|
|
;; levels within the limits of the constraints. E.g. make it possible for
|
|
|
|
;; the grammar to specify that "begin..end" has lower precedence than
|
|
|
|
;; "Module..EndModule", so that if a "begin" is missing, scanning from the
|
|
|
|
;; "end" will stop at "Module" rather than going past it (and similarly,
|
|
|
|
;; scanning from "Module" should not stop at a spurious "end").
|
2010-11-07 10:52:33 -05:00
|
|
|
|
2010-11-11 20:33:28 -05:00
|
|
|
;;; Code:
|
2010-11-07 10:52:33 -05:00
|
|
|
|
2011-11-18 11:30:43 -05:00
|
|
|
;; FIXME:
|
|
|
|
;; - smie-indent-comment doesn't interact well with mis-indented lines (where
|
|
|
|
;; the indent rules don't do what the user wants). Not sure what to do.
|
|
|
|
|
2012-06-10 09:28:26 -04:00
|
|
|
(eval-when-compile (require 'cl-lib))
|
2010-11-07 10:52:33 -05:00
|
|
|
|
2017-03-23 11:32:59 -06:00
|
|
|
(require 'prog-mode)
|
|
|
|
|
2010-11-07 10:52:33 -05:00
|
|
|
(defgroup smie nil
|
|
|
|
"Simple Minded Indentation Engine."
|
|
|
|
:group 'languages)
|
|
|
|
|
|
|
|
(defvar comment-continue)
|
|
|
|
(declare-function comment-string-strip "newcomment" (str beforep afterp))
|
|
|
|
|
|
|
|
;;; Building precedence level tables from BNF specs.
|
|
|
|
|
|
|
|
;; We have 4 different representations of a "grammar":
|
|
|
|
;; - a BNF table, which is a list of BNF rules of the form
|
|
|
|
;; (NONTERM RHS1 ... RHSn) where each RHS is a list of terminals (tokens)
|
|
|
|
;; or nonterminals. Any element in these lists which does not appear as
|
|
|
|
;; the `car' of a BNF rule is taken to be a terminal.
|
|
|
|
;; - A list of precedences (key word "precs"), is a list, sorted
|
|
|
|
;; from lowest to highest precedence, of precedence classes that
|
|
|
|
;; have the form (ASSOCIATIVITY TERMINAL1 .. TERMINALn), where
|
|
|
|
;; ASSOCIATIVITY can be `assoc', `left', `right' or `nonassoc'.
|
|
|
|
;; - a 2 dimensional precedence table (key word "prec2"), is a 2D
|
|
|
|
;; table recording the precedence relation (can be `<', `=', `>', or
|
|
|
|
;; nil) between each pair of tokens.
|
2011-11-16 13:34:47 +01:00
|
|
|
;; - a precedence-level table (key word "grammar"), which is an alist
|
2010-11-07 10:52:33 -05:00
|
|
|
;; giving for each token its left and right precedence level (a
|
|
|
|
;; number or nil). This is used in `smie-grammar'.
|
|
|
|
;; The prec2 tables are only intermediate data structures: the source
|
|
|
|
;; code normally provides a mix of BNF and precs tables, and then
|
|
|
|
;; turns them into a levels table, which is what's used by the rest of
|
|
|
|
;; the SMIE code.
|
|
|
|
|
2011-11-18 11:30:43 -05:00
|
|
|
(defvar smie-warning-count 0)
|
|
|
|
|
2010-11-07 10:52:33 -05:00
|
|
|
(defun smie-set-prec2tab (table x y val &optional override)
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-assert (and x y))
|
2010-11-07 10:52:33 -05:00
|
|
|
(let* ((key (cons x y))
|
|
|
|
(old (gethash key table)))
|
|
|
|
(if (and old (not (eq old val)))
|
|
|
|
(if (and override (gethash key override))
|
|
|
|
;; FIXME: The override is meant to resolve ambiguities,
|
|
|
|
;; but it also hides real conflicts. It would be great to
|
|
|
|
;; be able to distinguish the two cases so that overrides
|
|
|
|
;; don't hide real conflicts.
|
|
|
|
(puthash key (gethash key override) table)
|
2011-11-18 11:30:43 -05:00
|
|
|
(display-warning 'smie (format "Conflict: %s %s/%s %s" x old val y))
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-incf smie-warning-count))
|
2010-11-07 10:52:33 -05:00
|
|
|
(puthash key val table))))
|
|
|
|
|
|
|
|
(defun smie-precs->prec2 (precs)
|
|
|
|
"Compute a 2D precedence table from a list of precedences.
|
|
|
|
PRECS should be a list, sorted by precedence (e.g. \"+\" will
|
|
|
|
come before \"*\"), of elements of the form \(left OP ...)
|
|
|
|
or (right OP ...) or (nonassoc OP ...) or (assoc OP ...). All operators in
|
|
|
|
one of those elements share the same precedence level and associativity."
|
2015-10-29 10:35:08 -04:00
|
|
|
(declare (pure t))
|
2010-11-07 10:52:33 -05:00
|
|
|
(let ((prec2-table (make-hash-table :test 'equal)))
|
|
|
|
(dolist (prec precs)
|
|
|
|
(dolist (op (cdr prec))
|
|
|
|
(let ((selfrule (cdr (assq (car prec)
|
|
|
|
'((left . >) (right . <) (assoc . =))))))
|
|
|
|
(when selfrule
|
|
|
|
(dolist (other-op (cdr prec))
|
|
|
|
(smie-set-prec2tab prec2-table op other-op selfrule))))
|
|
|
|
(let ((op1 '<) (op2 '>))
|
|
|
|
(dolist (other-prec precs)
|
|
|
|
(if (eq prec other-prec)
|
|
|
|
(setq op1 '> op2 '<)
|
|
|
|
(dolist (other-op (cdr other-prec))
|
|
|
|
(smie-set-prec2tab prec2-table op other-op op2)
|
|
|
|
(smie-set-prec2tab prec2-table other-op op op1)))))))
|
|
|
|
prec2-table))
|
|
|
|
|
|
|
|
(defun smie-merge-prec2s (&rest tables)
|
2015-10-29 10:35:08 -04:00
|
|
|
(declare (pure t))
|
2010-11-07 10:52:33 -05:00
|
|
|
(if (null (cdr tables))
|
|
|
|
(car tables)
|
|
|
|
(let ((prec2 (make-hash-table :test 'equal)))
|
|
|
|
(dolist (table tables)
|
|
|
|
(maphash (lambda (k v)
|
|
|
|
(if (consp k)
|
|
|
|
(smie-set-prec2tab prec2 (car k) (cdr k) v)
|
|
|
|
(if (and (gethash k prec2)
|
|
|
|
(not (equal (gethash k prec2) v)))
|
|
|
|
(error "Conflicting values for %s property" k)
|
|
|
|
(puthash k v prec2))))
|
|
|
|
table))
|
|
|
|
prec2)))
|
|
|
|
|
2011-11-18 11:30:43 -05:00
|
|
|
(defun smie-bnf->prec2 (bnf &rest resolvers)
|
|
|
|
"Convert the BNF grammar into a prec2 table.
|
|
|
|
BNF is a list of nonterminal definitions of the form:
|
2015-09-17 16:08:20 -07:00
|
|
|
(NONTERM RHS1 RHS2 ...)
|
2011-11-18 11:30:43 -05:00
|
|
|
where each RHS is a (non-empty) list of terminals (aka tokens) or non-terminals.
|
|
|
|
Not all grammars are accepted:
|
|
|
|
- an RHS cannot be an empty list (this is not needed, since SMIE allows all
|
|
|
|
non-terminals to match the empty string anyway).
|
|
|
|
- an RHS cannot have 2 consecutive non-terminals: between each non-terminal
|
|
|
|
needs to be a terminal (aka token). This is a fundamental limitation of
|
|
|
|
the parsing technology used (operator precedence grammar).
|
|
|
|
Additionally, conflicts can occur:
|
|
|
|
- The returned prec2 table holds constraints between pairs of
|
|
|
|
token, and for any given pair only one constraint can be
|
|
|
|
present, either: T1 < T2, T1 = T2, or T1 > T2.
|
|
|
|
- A token can either be an `opener' (something similar to an open-paren),
|
|
|
|
a `closer' (like a close-paren), or `neither' of the two (e.g. an infix
|
|
|
|
operator, or an inner token like \"else\").
|
|
|
|
Conflicts can be resolved via RESOLVERS, which is a list of elements that can
|
|
|
|
be either:
|
|
|
|
- a precs table (see `smie-precs->prec2') to resolve conflicting constraints,
|
|
|
|
- a constraint (T1 REL T2) where REL is one of = < or >."
|
2015-10-29 10:35:08 -04:00
|
|
|
(declare (pure t))
|
2010-11-11 00:08:25 -05:00
|
|
|
;; FIXME: Add repetition operator like (repeat <separator> <elems>).
|
|
|
|
;; Maybe also add (or <elem1> <elem2>...) for things like
|
|
|
|
;; (exp (exp (or "+" "*" "=" ..) exp)).
|
|
|
|
;; Basically, make it EBNF (except for the specification of a separator in
|
2011-03-11 15:04:22 -05:00
|
|
|
;; the repetition, maybe).
|
2019-06-26 10:24:59 -04:00
|
|
|
(let* ((nts (mapcar 'car bnf)) ;Non-terminals.
|
2011-11-18 11:30:43 -05:00
|
|
|
(first-ops-table ())
|
|
|
|
(last-ops-table ())
|
|
|
|
(first-nts-table ())
|
|
|
|
(last-nts-table ())
|
|
|
|
(smie-warning-count 0)
|
|
|
|
(prec2 (make-hash-table :test 'equal))
|
|
|
|
(override
|
|
|
|
(let ((precs ())
|
|
|
|
(over (make-hash-table :test 'equal)))
|
|
|
|
(dolist (resolver resolvers)
|
|
|
|
(cond
|
|
|
|
((and (= 3 (length resolver)) (memq (nth 1 resolver) '(= < >)))
|
|
|
|
(smie-set-prec2tab
|
|
|
|
over (nth 0 resolver) (nth 2 resolver) (nth 1 resolver)))
|
|
|
|
((memq (caar resolver) '(left right assoc nonassoc))
|
|
|
|
(push resolver precs))
|
|
|
|
(t (error "Unknown resolver %S" resolver))))
|
|
|
|
(apply #'smie-merge-prec2s over
|
2019-06-26 10:24:59 -04:00
|
|
|
(mapcar 'smie-precs->prec2 precs))))
|
2011-11-18 11:30:43 -05:00
|
|
|
again)
|
2010-11-07 10:52:33 -05:00
|
|
|
(dolist (rules bnf)
|
|
|
|
(let ((nt (car rules))
|
|
|
|
(last-ops ())
|
|
|
|
(first-ops ())
|
|
|
|
(last-nts ())
|
|
|
|
(first-nts ()))
|
|
|
|
(dolist (rhs (cdr rules))
|
|
|
|
(unless (consp rhs)
|
|
|
|
(signal 'wrong-type-argument `(consp ,rhs)))
|
|
|
|
(if (not (member (car rhs) nts))
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-pushnew (car rhs) first-ops)
|
|
|
|
(cl-pushnew (car rhs) first-nts)
|
2010-11-07 10:52:33 -05:00
|
|
|
(when (consp (cdr rhs))
|
|
|
|
;; If the first is not an OP we add the second (which
|
|
|
|
;; should be an OP if BNF is an "operator grammar").
|
|
|
|
;; Strictly speaking, this should only be done if the
|
|
|
|
;; first is a non-terminal which can expand to a phrase
|
|
|
|
;; without any OP in it, but checking doesn't seem worth
|
|
|
|
;; the trouble, and it lets the writer of the BNF
|
|
|
|
;; be a bit more sloppy by skipping uninteresting base
|
|
|
|
;; cases which are terminals but not OPs.
|
2011-06-23 12:55:59 -04:00
|
|
|
(when (member (cadr rhs) nts)
|
|
|
|
(error "Adjacent non-terminals: %s %s"
|
|
|
|
(car rhs) (cadr rhs)))
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-pushnew (cadr rhs) first-ops)))
|
2010-11-07 10:52:33 -05:00
|
|
|
(let ((shr (reverse rhs)))
|
|
|
|
(if (not (member (car shr) nts))
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-pushnew (car shr) last-ops)
|
|
|
|
(cl-pushnew (car shr) last-nts)
|
2010-11-07 10:52:33 -05:00
|
|
|
(when (consp (cdr shr))
|
2011-06-26 10:43:52 +02:00
|
|
|
(when (member (cadr shr) nts)
|
2011-06-23 12:55:59 -04:00
|
|
|
(error "Adjacent non-terminals: %s %s"
|
2011-06-26 10:43:52 +02:00
|
|
|
(cadr shr) (car shr)))
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-pushnew (cadr shr) last-ops)))))
|
2010-11-07 10:52:33 -05:00
|
|
|
(push (cons nt first-ops) first-ops-table)
|
|
|
|
(push (cons nt last-ops) last-ops-table)
|
|
|
|
(push (cons nt first-nts) first-nts-table)
|
|
|
|
(push (cons nt last-nts) last-nts-table)))
|
|
|
|
;; Compute all first-ops by propagating the initial ones we have
|
|
|
|
;; now, according to first-nts.
|
|
|
|
(setq again t)
|
|
|
|
(while (prog1 again (setq again nil))
|
|
|
|
(dolist (first-nts first-nts-table)
|
|
|
|
(let* ((nt (pop first-nts))
|
|
|
|
(first-ops (assoc nt first-ops-table)))
|
|
|
|
(dolist (first-nt first-nts)
|
|
|
|
(dolist (op (cdr (assoc first-nt first-ops-table)))
|
|
|
|
(unless (member op first-ops)
|
|
|
|
(setq again t)
|
Provide generalized variables in core Elisp.
* lisp/emacs-lisp/gv.el: New file.
* lisp/subr.el (push, pop): Extend to generalized variables.
* lisp/loadup.el (macroexp): Unload if preloaded and uncompiled.
* lisp/emacs-lisp/cl-lib.el (cl-pop, cl-push, cl--set-nthcdr): Remove.
* lisp/emacs-lisp/cl-macs.el: Require gv. Use gv-define-setter,
gv-define-simple-setter, and gv-define-expander.
Remove setf-methods defined in gv. Rename cl-setf -> setf.
(cl-setf, cl-do-pop, cl-get-setf-method): Remove.
(cl-letf, cl-letf*, cl-define-modify-macro, cl-defsetf)
(cl-define-setf-expander, cl-struct-setf-expander): Move to cl.el.
(cl-remf, cl-shiftf, cl-rotatef, cl-callf, cl-callf2): Rewrite with
gv-letplace.
(cl-defstruct): Don't define setf-method any more.
* lisp/emacs-lisp/cl.el (flet): Don't autoload.
(cl--letf, letf, cl--letf*, letf*, cl--gv-adapt)
(define-setf-expander, defsetf, define-modify-macro)
(cl-struct-setf-expander): Move from cl-lib.el.
* lisp/emacs-lisp/syntax.el:
* lisp/emacs-lisp/ewoc.el:
* lisp/emacs-lisp/smie.el:
* lisp/emacs-lisp/cconv.el:
* lisp/emacs-lisp/timer.el: Rename cl-setf -> setf, cl-push -> push.
(timer--time): Use gv-define-simple-setter.
* lisp/emacs-lisp/macroexp.el (macroexp-let2): Rename from macroexp-let²
to avoid coding-system problems in subr.el. Adjust all users.
(macroexp--maxsize, macroexp-small-p): New functions.
* lisp/emacs-lisp/bytecomp.el (byte-compile-file): Don't use cl-letf.
* lisp/scroll-bar.el (scroll-bar-mode):
* lisp/simple.el (auto-fill-mode, overwrite-mode, binary-overwrite-mode)
(normal-erase-is-backspace-mode): Don't use the `eq' place.
* lisp/winner.el (winner-configuration, winner-make-point-alist)
(winner-set-conf, winner-get-point, winner-set): Don't abuse letf.
* lisp/files.el (locate-file-completion-table): Avoid list*.
Fixes: debbugs:11657
2012-06-22 09:42:38 -04:00
|
|
|
(push op (cdr first-ops))))))))
|
2010-11-07 10:52:33 -05:00
|
|
|
;; Same thing for last-ops.
|
|
|
|
(setq again t)
|
|
|
|
(while (prog1 again (setq again nil))
|
|
|
|
(dolist (last-nts last-nts-table)
|
|
|
|
(let* ((nt (pop last-nts))
|
|
|
|
(last-ops (assoc nt last-ops-table)))
|
|
|
|
(dolist (last-nt last-nts)
|
|
|
|
(dolist (op (cdr (assoc last-nt last-ops-table)))
|
|
|
|
(unless (member op last-ops)
|
|
|
|
(setq again t)
|
Provide generalized variables in core Elisp.
* lisp/emacs-lisp/gv.el: New file.
* lisp/subr.el (push, pop): Extend to generalized variables.
* lisp/loadup.el (macroexp): Unload if preloaded and uncompiled.
* lisp/emacs-lisp/cl-lib.el (cl-pop, cl-push, cl--set-nthcdr): Remove.
* lisp/emacs-lisp/cl-macs.el: Require gv. Use gv-define-setter,
gv-define-simple-setter, and gv-define-expander.
Remove setf-methods defined in gv. Rename cl-setf -> setf.
(cl-setf, cl-do-pop, cl-get-setf-method): Remove.
(cl-letf, cl-letf*, cl-define-modify-macro, cl-defsetf)
(cl-define-setf-expander, cl-struct-setf-expander): Move to cl.el.
(cl-remf, cl-shiftf, cl-rotatef, cl-callf, cl-callf2): Rewrite with
gv-letplace.
(cl-defstruct): Don't define setf-method any more.
* lisp/emacs-lisp/cl.el (flet): Don't autoload.
(cl--letf, letf, cl--letf*, letf*, cl--gv-adapt)
(define-setf-expander, defsetf, define-modify-macro)
(cl-struct-setf-expander): Move from cl-lib.el.
* lisp/emacs-lisp/syntax.el:
* lisp/emacs-lisp/ewoc.el:
* lisp/emacs-lisp/smie.el:
* lisp/emacs-lisp/cconv.el:
* lisp/emacs-lisp/timer.el: Rename cl-setf -> setf, cl-push -> push.
(timer--time): Use gv-define-simple-setter.
* lisp/emacs-lisp/macroexp.el (macroexp-let2): Rename from macroexp-let²
to avoid coding-system problems in subr.el. Adjust all users.
(macroexp--maxsize, macroexp-small-p): New functions.
* lisp/emacs-lisp/bytecomp.el (byte-compile-file): Don't use cl-letf.
* lisp/scroll-bar.el (scroll-bar-mode):
* lisp/simple.el (auto-fill-mode, overwrite-mode, binary-overwrite-mode)
(normal-erase-is-backspace-mode): Don't use the `eq' place.
* lisp/winner.el (winner-configuration, winner-make-point-alist)
(winner-set-conf, winner-get-point, winner-set): Don't abuse letf.
* lisp/files.el (locate-file-completion-table): Avoid list*.
Fixes: debbugs:11657
2012-06-22 09:42:38 -04:00
|
|
|
(push op (cdr last-ops))))))))
|
2010-11-07 10:52:33 -05:00
|
|
|
;; Now generate the 2D precedence table.
|
|
|
|
(dolist (rules bnf)
|
|
|
|
(dolist (rhs (cdr rules))
|
|
|
|
(while (cdr rhs)
|
|
|
|
(cond
|
|
|
|
((member (car rhs) nts)
|
|
|
|
(dolist (last (cdr (assoc (car rhs) last-ops-table)))
|
|
|
|
(smie-set-prec2tab prec2 last (cadr rhs) '> override)))
|
|
|
|
((member (cadr rhs) nts)
|
|
|
|
(dolist (first (cdr (assoc (cadr rhs) first-ops-table)))
|
|
|
|
(smie-set-prec2tab prec2 (car rhs) first '< override))
|
|
|
|
(if (and (cddr rhs) (not (member (car (cddr rhs)) nts)))
|
|
|
|
(smie-set-prec2tab prec2 (car rhs) (car (cddr rhs))
|
|
|
|
'= override)))
|
|
|
|
(t (smie-set-prec2tab prec2 (car rhs) (cadr rhs) '= override)))
|
|
|
|
(setq rhs (cdr rhs)))))
|
|
|
|
;; Keep track of which tokens are openers/closer, so they can get a nil
|
|
|
|
;; precedence in smie-prec2->grammar.
|
2011-11-18 11:30:43 -05:00
|
|
|
(puthash :smie-open/close-alist (smie-bnf--classify bnf) prec2)
|
|
|
|
(puthash :smie-closer-alist (smie-bnf--closer-alist bnf) prec2)
|
|
|
|
(if (> smie-warning-count 0)
|
|
|
|
(display-warning
|
|
|
|
'smie (format "Total: %d warnings" smie-warning-count)))
|
2010-11-07 10:52:33 -05:00
|
|
|
prec2))
|
|
|
|
|
|
|
|
;; (defun smie-prec2-closer-alist (prec2 include-inners)
|
|
|
|
;; "Build a closer-alist from a PREC2 table.
|
|
|
|
;; The return value is in the same form as `smie-closer-alist'.
|
|
|
|
;; INCLUDE-INNERS if non-nil means that inner keywords will be included
|
|
|
|
;; in the table, e.g. the table will include things like (\"if\" . \"else\")."
|
|
|
|
;; (let* ((non-openers '())
|
|
|
|
;; (non-closers '())
|
|
|
|
;; ;; For each keyword, this gives the matching openers, if any.
|
|
|
|
;; (openers (make-hash-table :test 'equal))
|
|
|
|
;; (closers '())
|
|
|
|
;; (done nil))
|
|
|
|
;; ;; First, find the non-openers and non-closers.
|
|
|
|
;; (maphash (lambda (k v)
|
|
|
|
;; (unless (or (eq v '<) (member (cdr k) non-openers))
|
|
|
|
;; (push (cdr k) non-openers))
|
|
|
|
;; (unless (or (eq v '>) (member (car k) non-closers))
|
|
|
|
;; (push (car k) non-closers)))
|
|
|
|
;; prec2)
|
|
|
|
;; ;; Then find the openers and closers.
|
|
|
|
;; (maphash (lambda (k _)
|
|
|
|
;; (unless (member (car k) non-openers)
|
|
|
|
;; (puthash (car k) (list (car k)) openers))
|
|
|
|
;; (unless (or (member (cdr k) non-closers)
|
|
|
|
;; (member (cdr k) closers))
|
|
|
|
;; (push (cdr k) closers)))
|
|
|
|
;; prec2)
|
|
|
|
;; ;; Then collect the matching elements.
|
|
|
|
;; (while (not done)
|
|
|
|
;; (setq done t)
|
|
|
|
;; (maphash (lambda (k v)
|
|
|
|
;; (when (eq v '=)
|
|
|
|
;; (let ((aopeners (gethash (car k) openers))
|
|
|
|
;; (dopeners (gethash (cdr k) openers))
|
|
|
|
;; (new nil))
|
|
|
|
;; (dolist (o aopeners)
|
|
|
|
;; (unless (member o dopeners)
|
|
|
|
;; (setq new t)
|
|
|
|
;; (push o dopeners)))
|
|
|
|
;; (when new
|
|
|
|
;; (setq done nil)
|
|
|
|
;; (puthash (cdr k) dopeners openers)))))
|
|
|
|
;; prec2))
|
|
|
|
;; ;; Finally, dump the resulting table.
|
|
|
|
;; (let ((alist '()))
|
|
|
|
;; (maphash (lambda (k v)
|
|
|
|
;; (when (or include-inners (member k closers))
|
|
|
|
;; (dolist (opener v)
|
|
|
|
;; (unless (equal opener k)
|
|
|
|
;; (push (cons opener k) alist)))))
|
|
|
|
;; openers)
|
|
|
|
;; alist)))
|
|
|
|
|
2011-11-18 11:30:43 -05:00
|
|
|
(defun smie-bnf--closer-alist (bnf &optional no-inners)
|
2010-11-07 10:52:33 -05:00
|
|
|
;; We can also build this closer-alist table from a prec2 table,
|
|
|
|
;; but it takes more work, and the order is unpredictable, which
|
|
|
|
;; is a problem for smie-close-block.
|
|
|
|
;; More convenient would be to build it from a levels table since we
|
|
|
|
;; always have this table (contrary to the BNF), but it has all the
|
|
|
|
;; disadvantages of the prec2 case plus the disadvantage that the levels
|
|
|
|
;; table has lost some info which would result in extra invalid pairs.
|
|
|
|
"Build a closer-alist from a BNF table.
|
|
|
|
The return value is in the same form as `smie-closer-alist'.
|
|
|
|
NO-INNERS if non-nil means that inner keywords will be excluded
|
|
|
|
from the table, e.g. the table will not include things like (\"if\" . \"else\")."
|
|
|
|
(let ((nts (mapcar #'car bnf)) ;non terminals.
|
|
|
|
(alist '()))
|
|
|
|
(dolist (nt bnf)
|
|
|
|
(dolist (rhs (cdr nt))
|
|
|
|
(unless (or (< (length rhs) 2) (member (car rhs) nts))
|
|
|
|
(if no-inners
|
|
|
|
(let ((last (car (last rhs))))
|
|
|
|
(unless (member last nts)
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-pushnew (cons (car rhs) last) alist :test #'equal)))
|
2010-11-07 10:52:33 -05:00
|
|
|
;; Reverse so that the "real" closer gets there first,
|
|
|
|
;; which is important for smie-close-block.
|
|
|
|
(dolist (term (reverse (cdr rhs)))
|
|
|
|
(unless (member term nts)
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-pushnew (cons (car rhs) term) alist :test #'equal)))))))
|
2010-11-07 10:52:33 -05:00
|
|
|
(nreverse alist)))
|
|
|
|
|
2011-11-18 11:30:43 -05:00
|
|
|
(defun smie-bnf--set-class (table token class)
|
|
|
|
(let ((prev (gethash token table class)))
|
|
|
|
(puthash token
|
|
|
|
(cond
|
|
|
|
((eq prev class) class)
|
|
|
|
((eq prev t) t) ;Non-terminal.
|
|
|
|
(t (display-warning
|
|
|
|
'smie
|
|
|
|
(format "token %s is both %s and %s" token class prev))
|
|
|
|
'neither))
|
|
|
|
table)))
|
|
|
|
|
|
|
|
(defun smie-bnf--classify (bnf)
|
2010-11-07 10:52:33 -05:00
|
|
|
"Return a table classifying terminals.
|
2011-11-18 11:30:43 -05:00
|
|
|
Each terminal can either be an `opener', a `closer', or `neither'."
|
2010-11-07 10:52:33 -05:00
|
|
|
(let ((table (make-hash-table :test #'equal))
|
|
|
|
(alist '()))
|
|
|
|
(dolist (category bnf)
|
2011-11-18 11:30:43 -05:00
|
|
|
(puthash (car category) t table)) ;Mark non-terminals.
|
|
|
|
(dolist (category bnf)
|
2010-11-07 10:52:33 -05:00
|
|
|
(dolist (rhs (cdr category))
|
|
|
|
(if (null (cdr rhs))
|
2011-11-18 11:30:43 -05:00
|
|
|
(smie-bnf--set-class table (pop rhs) 'neither)
|
|
|
|
(smie-bnf--set-class table (pop rhs) 'opener)
|
|
|
|
(while (cdr rhs) ;Remove internals.
|
|
|
|
(smie-bnf--set-class table (pop rhs) 'neither))
|
|
|
|
(smie-bnf--set-class table (pop rhs) 'closer))))
|
2010-11-07 10:52:33 -05:00
|
|
|
(maphash (lambda (tok v)
|
|
|
|
(when (memq v '(closer opener))
|
|
|
|
(push (cons tok v) alist)))
|
|
|
|
table)
|
|
|
|
alist))
|
|
|
|
|
|
|
|
(defun smie-debug--prec2-cycle (csts)
|
|
|
|
"Return a cycle in CSTS, assuming there's one.
|
|
|
|
CSTS is a list of pairs representing arcs in a graph."
|
|
|
|
;; A PATH is of the form (START . REST) where REST is a reverse
|
|
|
|
;; list of nodes through which the path goes.
|
|
|
|
(let ((paths (mapcar (lambda (pair) (list (car pair) (cdr pair))) csts))
|
|
|
|
(cycle nil))
|
|
|
|
(while (null cycle)
|
|
|
|
(dolist (path (prog1 paths (setq paths nil)))
|
|
|
|
(dolist (cst csts)
|
|
|
|
(when (eq (car cst) (nth 1 path))
|
|
|
|
(if (eq (cdr cst) (car path))
|
|
|
|
(setq cycle path)
|
|
|
|
(push (cons (car path) (cons (cdr cst) (cdr path)))
|
|
|
|
paths))))))
|
|
|
|
(cons (car cycle) (nreverse (cdr cycle)))))
|
|
|
|
|
|
|
|
(defun smie-debug--describe-cycle (table cycle)
|
|
|
|
(let ((names
|
|
|
|
(mapcar (lambda (val)
|
|
|
|
(let ((res nil))
|
|
|
|
(dolist (elem table)
|
|
|
|
(if (eq (cdr elem) val)
|
|
|
|
(push (concat "." (car elem)) res))
|
|
|
|
(if (eq (cddr elem) val)
|
|
|
|
(push (concat (car elem) ".") res)))
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-assert res)
|
2010-11-07 10:52:33 -05:00
|
|
|
res))
|
|
|
|
cycle)))
|
|
|
|
(mapconcat
|
2019-06-26 10:24:59 -04:00
|
|
|
(lambda (elems) (mapconcat 'identity elems "="))
|
2010-11-07 10:52:33 -05:00
|
|
|
(append names (list (car names)))
|
|
|
|
" < ")))
|
|
|
|
|
2010-11-11 20:33:28 -05:00
|
|
|
;; (defun smie-check-grammar (grammar prec2 &optional dummy)
|
|
|
|
;; (maphash (lambda (k v)
|
|
|
|
;; (when (consp k)
|
|
|
|
;; (let ((left (nth 2 (assoc (car k) grammar)))
|
|
|
|
;; (right (nth 1 (assoc (cdr k) grammar))))
|
|
|
|
;; (when (and left right)
|
|
|
|
;; (cond
|
2012-06-10 09:28:26 -04:00
|
|
|
;; ((< left right) (cl-assert (eq v '<)))
|
|
|
|
;; ((> left right) (cl-assert (eq v '>)))
|
|
|
|
;; (t (cl-assert (eq v '=))))))))
|
2010-11-11 20:33:28 -05:00
|
|
|
;; prec2))
|
|
|
|
|
2010-11-07 10:52:33 -05:00
|
|
|
(defun smie-prec2->grammar (prec2)
|
|
|
|
"Take a 2D precedence table and turn it into an alist of precedence levels.
|
|
|
|
PREC2 is a table as returned by `smie-precs->prec2' or
|
|
|
|
`smie-bnf->prec2'."
|
2015-10-29 10:35:08 -04:00
|
|
|
(declare (pure t))
|
2010-11-07 10:52:33 -05:00
|
|
|
;; For each operator, we create two "variables" (corresponding to
|
|
|
|
;; the left and right precedence level), which are represented by
|
|
|
|
;; cons cells. Those are the very cons cells that appear in the
|
|
|
|
;; final `table'. The value of each "variable" is kept in the `car'.
|
|
|
|
(let ((table ())
|
|
|
|
(csts ())
|
2012-06-10 09:28:26 -04:00
|
|
|
(eqs ()))
|
2010-11-07 10:52:33 -05:00
|
|
|
;; From `prec2' we construct a list of constraints between
|
|
|
|
;; variables (aka "precedence levels"). These can be either
|
|
|
|
;; equality constraints (in `eqs') or `<' constraints (in `csts').
|
|
|
|
(maphash (lambda (k v)
|
|
|
|
(when (consp k)
|
2012-06-10 09:28:26 -04:00
|
|
|
(let ((tmp (assoc (car k) table))
|
|
|
|
x y)
|
|
|
|
(if tmp
|
|
|
|
(setq x (cddr tmp))
|
|
|
|
(setq x (cons nil nil))
|
|
|
|
(push (cons (car k) (cons nil x)) table))
|
|
|
|
(if (setq tmp (assoc (cdr k) table))
|
|
|
|
(setq y (cdr tmp))
|
|
|
|
(setq y (cons nil (cons nil nil)))
|
|
|
|
(push (cons (cdr k) y) table))
|
|
|
|
(pcase v
|
2018-11-05 01:22:15 +01:00
|
|
|
('= (push (cons x y) eqs))
|
|
|
|
('< (push (cons x y) csts))
|
|
|
|
('> (push (cons y x) csts))
|
2012-06-10 09:28:26 -04:00
|
|
|
(_ (error "SMIE error: prec2 has %S↦%S which ∉ {<,+,>}"
|
|
|
|
k v))))))
|
2010-11-07 10:52:33 -05:00
|
|
|
prec2)
|
|
|
|
;; First process the equality constraints.
|
|
|
|
(let ((eqs eqs))
|
|
|
|
(while eqs
|
|
|
|
(let ((from (caar eqs))
|
|
|
|
(to (cdar eqs)))
|
|
|
|
(setq eqs (cdr eqs))
|
|
|
|
(if (eq to from)
|
2010-11-26 16:33:21 -05:00
|
|
|
nil ;Nothing to do.
|
2010-11-07 10:52:33 -05:00
|
|
|
(dolist (other-eq eqs)
|
|
|
|
(if (eq from (cdr other-eq)) (setcdr other-eq to))
|
|
|
|
(when (eq from (car other-eq))
|
|
|
|
;; This can happen because of `assoc' settings in precs
|
|
|
|
;; or because of a rhs like ("op" foo "op").
|
|
|
|
(setcar other-eq to)))
|
|
|
|
(dolist (cst csts)
|
|
|
|
(if (eq from (cdr cst)) (setcdr cst to))
|
|
|
|
(if (eq from (car cst)) (setcar cst to)))))))
|
|
|
|
;; Then eliminate trivial constraints iteratively.
|
|
|
|
(let ((i 0))
|
|
|
|
(while csts
|
2019-06-26 10:24:59 -04:00
|
|
|
(let ((rhvs (mapcar 'cdr csts))
|
2010-11-07 10:52:33 -05:00
|
|
|
(progress nil))
|
|
|
|
(dolist (cst csts)
|
|
|
|
(unless (memq (car cst) rhvs)
|
|
|
|
(setq progress t)
|
|
|
|
;; We could give each var in a given iteration the same value,
|
|
|
|
;; but we can also give them arbitrarily different values.
|
|
|
|
;; Basically, these are vars between which there is no
|
|
|
|
;; constraint (neither equality nor inequality), so
|
|
|
|
;; anything will do.
|
|
|
|
;; We give them arbitrary values, which means that we
|
|
|
|
;; replace the "no constraint" case with either > or <
|
|
|
|
;; but not =. The reason we do that is so as to try and
|
|
|
|
;; distinguish associative operators (which will have
|
|
|
|
;; left = right).
|
|
|
|
(unless (caar cst)
|
|
|
|
(setcar (car cst) i)
|
2010-11-11 20:33:28 -05:00
|
|
|
;; (smie-check-grammar table prec2 'step1)
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-incf i))
|
2010-11-07 10:52:33 -05:00
|
|
|
(setq csts (delq cst csts))))
|
|
|
|
(unless progress
|
|
|
|
(error "Can't resolve the precedence cycle: %s"
|
|
|
|
(smie-debug--describe-cycle
|
|
|
|
table (smie-debug--prec2-cycle csts)))))
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-incf i 10))
|
2011-11-26 20:43:11 -08:00
|
|
|
;; Propagate equality constraints back to their sources.
|
2010-11-07 10:52:33 -05:00
|
|
|
(dolist (eq (nreverse eqs))
|
2010-11-11 20:33:28 -05:00
|
|
|
(when (null (cadr eq))
|
|
|
|
;; There's an equality constraint, but we still haven't given
|
|
|
|
;; it a value: that means it binds tighter than anything else,
|
|
|
|
;; and it can't be an opener/closer (those don't have equality
|
|
|
|
;; constraints).
|
|
|
|
;; So set it here rather than below since doing it below
|
|
|
|
;; makes it more difficult to obey the equality constraints.
|
|
|
|
(setcar (cdr eq) i)
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-incf i))
|
|
|
|
(cl-assert (or (null (caar eq)) (eq (caar eq) (cadr eq))))
|
2010-11-11 20:33:28 -05:00
|
|
|
(setcar (car eq) (cadr eq))
|
|
|
|
;; (smie-check-grammar table prec2 'step2)
|
|
|
|
)
|
2010-11-26 16:33:21 -05:00
|
|
|
;; Finally, fill in the remaining vars (which did not appear on the
|
|
|
|
;; left side of any < constraint).
|
|
|
|
(dolist (x table)
|
|
|
|
(unless (nth 1 x)
|
Provide generalized variables in core Elisp.
* lisp/emacs-lisp/gv.el: New file.
* lisp/subr.el (push, pop): Extend to generalized variables.
* lisp/loadup.el (macroexp): Unload if preloaded and uncompiled.
* lisp/emacs-lisp/cl-lib.el (cl-pop, cl-push, cl--set-nthcdr): Remove.
* lisp/emacs-lisp/cl-macs.el: Require gv. Use gv-define-setter,
gv-define-simple-setter, and gv-define-expander.
Remove setf-methods defined in gv. Rename cl-setf -> setf.
(cl-setf, cl-do-pop, cl-get-setf-method): Remove.
(cl-letf, cl-letf*, cl-define-modify-macro, cl-defsetf)
(cl-define-setf-expander, cl-struct-setf-expander): Move to cl.el.
(cl-remf, cl-shiftf, cl-rotatef, cl-callf, cl-callf2): Rewrite with
gv-letplace.
(cl-defstruct): Don't define setf-method any more.
* lisp/emacs-lisp/cl.el (flet): Don't autoload.
(cl--letf, letf, cl--letf*, letf*, cl--gv-adapt)
(define-setf-expander, defsetf, define-modify-macro)
(cl-struct-setf-expander): Move from cl-lib.el.
* lisp/emacs-lisp/syntax.el:
* lisp/emacs-lisp/ewoc.el:
* lisp/emacs-lisp/smie.el:
* lisp/emacs-lisp/cconv.el:
* lisp/emacs-lisp/timer.el: Rename cl-setf -> setf, cl-push -> push.
(timer--time): Use gv-define-simple-setter.
* lisp/emacs-lisp/macroexp.el (macroexp-let2): Rename from macroexp-let²
to avoid coding-system problems in subr.el. Adjust all users.
(macroexp--maxsize, macroexp-small-p): New functions.
* lisp/emacs-lisp/bytecomp.el (byte-compile-file): Don't use cl-letf.
* lisp/scroll-bar.el (scroll-bar-mode):
* lisp/simple.el (auto-fill-mode, overwrite-mode, binary-overwrite-mode)
(normal-erase-is-backspace-mode): Don't use the `eq' place.
* lisp/winner.el (winner-configuration, winner-make-point-alist)
(winner-set-conf, winner-get-point, winner-set): Don't abuse letf.
* lisp/files.el (locate-file-completion-table): Avoid list*.
Fixes: debbugs:11657
2012-06-22 09:42:38 -04:00
|
|
|
(setf (nth 1 x) i)
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-incf i)) ;See other (cl-incf i) above.
|
2010-11-26 16:33:21 -05:00
|
|
|
(unless (nth 2 x)
|
Provide generalized variables in core Elisp.
* lisp/emacs-lisp/gv.el: New file.
* lisp/subr.el (push, pop): Extend to generalized variables.
* lisp/loadup.el (macroexp): Unload if preloaded and uncompiled.
* lisp/emacs-lisp/cl-lib.el (cl-pop, cl-push, cl--set-nthcdr): Remove.
* lisp/emacs-lisp/cl-macs.el: Require gv. Use gv-define-setter,
gv-define-simple-setter, and gv-define-expander.
Remove setf-methods defined in gv. Rename cl-setf -> setf.
(cl-setf, cl-do-pop, cl-get-setf-method): Remove.
(cl-letf, cl-letf*, cl-define-modify-macro, cl-defsetf)
(cl-define-setf-expander, cl-struct-setf-expander): Move to cl.el.
(cl-remf, cl-shiftf, cl-rotatef, cl-callf, cl-callf2): Rewrite with
gv-letplace.
(cl-defstruct): Don't define setf-method any more.
* lisp/emacs-lisp/cl.el (flet): Don't autoload.
(cl--letf, letf, cl--letf*, letf*, cl--gv-adapt)
(define-setf-expander, defsetf, define-modify-macro)
(cl-struct-setf-expander): Move from cl-lib.el.
* lisp/emacs-lisp/syntax.el:
* lisp/emacs-lisp/ewoc.el:
* lisp/emacs-lisp/smie.el:
* lisp/emacs-lisp/cconv.el:
* lisp/emacs-lisp/timer.el: Rename cl-setf -> setf, cl-push -> push.
(timer--time): Use gv-define-simple-setter.
* lisp/emacs-lisp/macroexp.el (macroexp-let2): Rename from macroexp-let²
to avoid coding-system problems in subr.el. Adjust all users.
(macroexp--maxsize, macroexp-small-p): New functions.
* lisp/emacs-lisp/bytecomp.el (byte-compile-file): Don't use cl-letf.
* lisp/scroll-bar.el (scroll-bar-mode):
* lisp/simple.el (auto-fill-mode, overwrite-mode, binary-overwrite-mode)
(normal-erase-is-backspace-mode): Don't use the `eq' place.
* lisp/winner.el (winner-configuration, winner-make-point-alist)
(winner-set-conf, winner-get-point, winner-set): Don't abuse letf.
* lisp/files.el (locate-file-completion-table): Avoid list*.
Fixes: debbugs:11657
2012-06-22 09:42:38 -04:00
|
|
|
(setf (nth 2 x) i)
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-incf i)))) ;See other (cl-incf i) above.
|
2010-11-26 16:33:21 -05:00
|
|
|
;; Mark closers and openers.
|
|
|
|
(dolist (x (gethash :smie-open/close-alist prec2))
|
|
|
|
(let* ((token (car x))
|
2012-06-10 09:28:26 -04:00
|
|
|
(cons (pcase (cdr x)
|
2018-11-05 01:22:15 +01:00
|
|
|
('closer (cddr (assoc token table)))
|
|
|
|
('opener (cdr (assoc token table))))))
|
2015-02-18 20:31:17 -05:00
|
|
|
;; `cons' can be nil for openers/closers which only contain
|
|
|
|
;; "atomic" elements.
|
|
|
|
(when cons
|
|
|
|
(cl-assert (numberp (car cons)))
|
|
|
|
(setf (car cons) (list (car cons))))))
|
2010-11-07 10:52:33 -05:00
|
|
|
(let ((ca (gethash :smie-closer-alist prec2)))
|
|
|
|
(when ca (push (cons :smie-closer-alist ca) table)))
|
2010-11-11 20:33:28 -05:00
|
|
|
;; (smie-check-grammar table prec2 'step3)
|
2010-11-07 10:52:33 -05:00
|
|
|
table))
|
|
|
|
|
|
|
|
;;; Parsing using a precedence level table.
|
|
|
|
|
|
|
|
(defvar smie-grammar 'unset
|
|
|
|
"List of token parsing info.
|
|
|
|
This list is normally built by `smie-prec2->grammar'.
|
|
|
|
Each element is of the form (TOKEN LEFT-LEVEL RIGHT-LEVEL).
|
|
|
|
Parsing is done using an operator precedence parser.
|
2010-11-17 14:59:16 -05:00
|
|
|
LEFT-LEVEL and RIGHT-LEVEL can be either numbers or a list, where a list
|
2010-11-07 10:52:33 -05:00
|
|
|
means that this operator does not bind on the corresponding side,
|
2010-11-17 14:59:16 -05:00
|
|
|
e.g. a LEFT-LEVEL of nil means this is a token that behaves somewhat like
|
2010-11-07 10:52:33 -05:00
|
|
|
an open-paren, whereas a RIGHT-LEVEL of nil would correspond to something
|
|
|
|
like a close-paren.")
|
|
|
|
|
2014-07-20 21:58:43 -04:00
|
|
|
(defvar smie-forward-token-function #'smie-default-forward-token
|
2010-11-07 10:52:33 -05:00
|
|
|
"Function to scan forward for the next token.
|
|
|
|
Called with no argument should return a token and move to its end.
|
|
|
|
If no token is found, return nil or the empty string.
|
|
|
|
It can return nil when bumping into a parenthesis, which lets SMIE
|
|
|
|
use syntax-tables to handle them in efficient C code.")
|
|
|
|
|
2014-07-20 21:58:43 -04:00
|
|
|
(defvar smie-backward-token-function #'smie-default-backward-token
|
2010-11-07 10:52:33 -05:00
|
|
|
"Function to scan backward the previous token.
|
|
|
|
Same calling convention as `smie-forward-token-function' except
|
|
|
|
it should move backward to the beginning of the previous token.")
|
|
|
|
|
|
|
|
(defalias 'smie-op-left 'car)
|
|
|
|
(defalias 'smie-op-right 'cadr)
|
|
|
|
|
|
|
|
(defun smie-default-backward-token ()
|
|
|
|
(forward-comment (- (point)))
|
|
|
|
(buffer-substring-no-properties
|
|
|
|
(point)
|
|
|
|
(progn (if (zerop (skip-syntax-backward "."))
|
|
|
|
(skip-syntax-backward "w_'"))
|
|
|
|
(point))))
|
|
|
|
|
|
|
|
(defun smie-default-forward-token ()
|
|
|
|
(forward-comment (point-max))
|
|
|
|
(buffer-substring-no-properties
|
|
|
|
(point)
|
|
|
|
(progn (if (zerop (skip-syntax-forward "."))
|
|
|
|
(skip-syntax-forward "w_'"))
|
|
|
|
(point))))
|
|
|
|
|
|
|
|
(defun smie--associative-p (toklevels)
|
|
|
|
;; in "a + b + c" we want to stop at each +, but in
|
|
|
|
;; "if a then b elsif c then d else c" we don't want to stop at each keyword.
|
|
|
|
;; To distinguish the two cases, we made smie-prec2->grammar choose
|
|
|
|
;; different levels for each part of "if a then b else c", so that
|
|
|
|
;; by checking if the left-level is equal to the right level, we can
|
|
|
|
;; figure out that it's an associative operator.
|
|
|
|
;; This is not 100% foolproof, tho, since the "elsif" will have to have
|
|
|
|
;; equal left and right levels (since it's optional), so smie-next-sexp
|
|
|
|
;; has to be careful to distinguish those different cases.
|
|
|
|
(eq (smie-op-left toklevels) (smie-op-right toklevels)))
|
|
|
|
|
|
|
|
(defun smie-next-sexp (next-token next-sexp op-forw op-back halfsexp)
|
|
|
|
"Skip over one sexp.
|
|
|
|
NEXT-TOKEN is a function of no argument that moves forward by one
|
|
|
|
token (after skipping comments if needed) and returns it.
|
|
|
|
NEXT-SEXP is a lower-level function to skip one sexp.
|
|
|
|
OP-FORW is the accessor to the forward level of the level data.
|
|
|
|
OP-BACK is the accessor to the backward level of the level data.
|
|
|
|
HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the
|
|
|
|
first token we see is an operator, skip over its left-hand-side argument.
|
2010-11-26 16:33:21 -05:00
|
|
|
HALFSEXP can also be a token, in which case it means to parse as if
|
|
|
|
we had just successfully passed this token.
|
2010-11-07 10:52:33 -05:00
|
|
|
Possible return values:
|
|
|
|
(FORW-LEVEL POS TOKEN): we couldn't skip TOKEN because its back-level
|
|
|
|
is too high. FORW-LEVEL is the forw-level of TOKEN,
|
|
|
|
POS is its start position in the buffer.
|
|
|
|
(t POS TOKEN): same thing when we bump on the wrong side of a paren.
|
2012-05-15 09:25:03 -04:00
|
|
|
Instead of t, the `car' can also be some other non-nil non-number value.
|
2010-11-07 10:52:33 -05:00
|
|
|
(nil POS TOKEN): we skipped over a paren-like pair.
|
|
|
|
nil: we skipped over an identifier, matched parentheses, ..."
|
|
|
|
(catch 'return
|
2010-11-26 16:33:21 -05:00
|
|
|
(let ((levels
|
|
|
|
(if (stringp halfsexp)
|
2019-11-21 18:24:37 -05:00
|
|
|
(prog1 (list (or (cdr (assoc halfsexp smie-grammar))
|
|
|
|
(when (string-match "\\`\\s(\\|\\s)\\(\\)\\'"
|
|
|
|
halfsexp)
|
|
|
|
(if (match-end 1) '(0 nil) '(nil 0)))
|
|
|
|
(error "Unknown token: %S" halfsexp)))
|
2010-11-26 16:33:21 -05:00
|
|
|
(setq halfsexp nil)))))
|
2010-11-07 10:52:33 -05:00
|
|
|
(while
|
|
|
|
(let* ((pos (point))
|
|
|
|
(token (funcall next-token))
|
|
|
|
(toklevels (cdr (assoc token smie-grammar))))
|
|
|
|
(cond
|
|
|
|
((null toklevels)
|
|
|
|
(when (zerop (length token))
|
|
|
|
(condition-case err
|
2013-10-05 14:37:08 -04:00
|
|
|
(progn (funcall next-sexp 1) nil)
|
2012-06-23 11:38:23 -04:00
|
|
|
(scan-error
|
2014-06-13 11:31:17 -04:00
|
|
|
(let* ((epos1 (nth 2 err))
|
|
|
|
(epos (if (<= (point) epos1) (nth 3 err) epos1)))
|
2013-10-07 12:56:51 -04:00
|
|
|
(goto-char pos)
|
2012-06-23 11:38:23 -04:00
|
|
|
(throw 'return
|
2013-10-07 12:56:51 -04:00
|
|
|
(list t epos
|
2015-12-03 15:22:14 -05:00
|
|
|
(unless (= (point) epos)
|
|
|
|
(buffer-substring-no-properties
|
|
|
|
epos
|
|
|
|
(+ epos (if (< (point) epos) -1 1)))))))))
|
2010-11-07 10:52:33 -05:00
|
|
|
(if (eq pos (point))
|
|
|
|
;; We did not move, so let's abort the loop.
|
|
|
|
(throw 'return (list t (point))))))
|
2010-11-17 14:59:16 -05:00
|
|
|
((not (numberp (funcall op-back toklevels)))
|
2010-11-07 10:52:33 -05:00
|
|
|
;; A token like a paren-close.
|
2012-06-10 09:28:26 -04:00
|
|
|
(cl-assert (numberp ; Otherwise, why mention it in smie-grammar.
|
|
|
|
(funcall op-forw toklevels)))
|
2010-11-07 10:52:33 -05:00
|
|
|
(push toklevels levels))
|
|
|
|
(t
|
|
|
|
(while (and levels (< (funcall op-back toklevels)
|
|
|
|
(funcall op-forw (car levels))))
|
|
|
|
(setq levels (cdr levels)))
|
|
|
|
(cond
|
|
|
|
((null levels)
|
2010-11-17 14:59:16 -05:00
|
|
|
(if (and halfsexp (numberp (funcall op-forw toklevels)))
|
2010-11-07 10:52:33 -05:00
|
|
|
(push toklevels levels)
|
|
|
|
(throw 'return
|
2012-05-13 12:04:37 -04:00
|
|
|
(prog1 (list (or (funcall op-forw toklevels) t)
|
|
|
|
(point) token)
|
2010-11-07 10:52:33 -05:00
|
|
|
(goto-char pos)))))
|
|
|
|
(t
|
|
|
|
(let ((lastlevels levels))
|
|
|
|
(if (and levels (= (funcall op-back toklevels)
|
|
|
|
(funcall op-forw (car levels))))
|
|
|
|
(setq levels (cdr levels)))
|
|
|
|
;; We may have found a match for the previously pending
|
|
|
|
;; operator. Is this the end?
|
|
|
|
(cond
|
|
|
|
;; Keep looking as long as we haven't matched the
|
|
|
|
;; topmost operator.
|
|
|
|
(levels
|
2011-11-18 11:30:43 -05:00
|
|
|
(cond
|
|
|
|
((numberp (funcall op-forw toklevels))
|
|
|
|
(push toklevels levels))
|
|
|
|
;; FIXME: For some languages, we can express the grammar
|
|
|
|
;; OK, but next-sexp doesn't stop where we'd want it to.
|
|
|
|
;; E.g. in SML, we'd want to stop right in front of
|
|
|
|
;; "local" if we're scanning (both forward and backward)
|
|
|
|
;; from a "val/fun/..." at the same level.
|
|
|
|
;; Same for Pascal/Modula2's "procedure" w.r.t
|
|
|
|
;; "type/var/const".
|
|
|
|
;;
|
|
|
|
;; ((and (functionp (cadr (funcall op-forw toklevels)))
|
|
|
|
;; (funcall (cadr (funcall op-forw toklevels))
|
|
|
|
;; levels))
|
|
|
|
;; (setq levels nil))
|
|
|
|
))
|
2010-11-07 10:52:33 -05:00
|
|
|
;; We matched the topmost operator. If the new operator
|
|
|
|
;; is the last in the corresponding BNF rule, we're done.
|
2010-11-17 14:59:16 -05:00
|
|
|
((not (numberp (funcall op-forw toklevels)))
|
2010-11-07 10:52:33 -05:00
|
|
|
;; It is the last element, let's stop here.
|
|
|
|
(throw 'return (list nil (point) token)))
|
|
|
|
;; If the new operator is not the last in the BNF rule,
|
2010-11-11 00:08:25 -05:00
|
|
|
;; and is not associative, it's one of the inner operators
|
2010-11-07 10:52:33 -05:00
|
|
|
;; (like the "in" in "let .. in .. end"), so keep looking.
|
|
|
|
((not (smie--associative-p toklevels))
|
|
|
|
(push toklevels levels))
|
|
|
|
;; The new operator is associative. Two cases:
|
|
|
|
;; - it's really just an associative operator (like + or ;)
|
|
|
|
;; in which case we should have stopped right before.
|
|
|
|
((and lastlevels
|
|
|
|
(smie--associative-p (car lastlevels)))
|
|
|
|
(throw 'return
|
2012-05-13 12:04:37 -04:00
|
|
|
(prog1 (list (or (funcall op-forw toklevels) t)
|
|
|
|
(point) token)
|
2010-11-07 10:52:33 -05:00
|
|
|
(goto-char pos))))
|
|
|
|
;; - it's an associative operator within a larger construct
|
|
|
|
;; (e.g. an "elsif"), so we should just ignore it and keep
|
|
|
|
;; looking for the closing element.
|
|
|
|
(t (setq levels lastlevels))))))))
|
|
|
|
levels)
|
|
|
|
(setq halfsexp nil)))))
|
|
|
|
|
|
|
|
(defun smie-backward-sexp (&optional halfsexp)
|
|
|
|
"Skip over one sexp.
|
|
|
|
HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the
|
|
|
|
first token we see is an operator, skip over its left-hand-side argument.
|
2010-11-26 16:33:21 -05:00
|
|
|
HALFSEXP can also be a token, in which case we should skip the text
|
|
|
|
assuming it is the left-hand-side argument of that token.
|
2010-11-07 10:52:33 -05:00
|
|
|
Possible return values:
|
|
|
|
(LEFT-LEVEL POS TOKEN): we couldn't skip TOKEN because its right-level
|
|
|
|
is too high. LEFT-LEVEL is the left-level of TOKEN,
|
|
|
|
POS is its start position in the buffer.
|
|
|
|
(t POS TOKEN): same thing but for an open-paren or the beginning of buffer.
|
2012-05-15 09:25:03 -04:00
|
|
|
Instead of t, the `car' can also be some other non-nil non-number value.
|
2010-11-07 10:52:33 -05:00
|
|
|
(nil POS TOKEN): we skipped over a paren-like pair.
|
|
|
|
nil: we skipped over an identifier, matched parentheses, ..."
|
|
|
|
(smie-next-sexp
|
|
|
|
(indirect-function smie-backward-token-function)
|
2015-11-23 11:26:16 -05:00
|
|
|
(lambda (n)
|
|
|
|
(if (bobp)
|
2015-11-29 21:50:59 -08:00
|
|
|
;; Arguably backward-sexp should signal this error for us.
|
2015-11-23 11:26:16 -05:00
|
|
|
(signal 'scan-error
|
|
|
|
(list "Beginning of buffer" (point) (point)))
|
|
|
|
(backward-sexp n)))
|
2014-07-20 21:58:43 -04:00
|
|
|
(indirect-function #'smie-op-left)
|
|
|
|
(indirect-function #'smie-op-right)
|
2010-11-07 10:52:33 -05:00
|
|
|
halfsexp))
|
|
|
|
|
|
|
|
(defun smie-forward-sexp (&optional halfsexp)
|
|
|
|
"Skip over one sexp.
|
|
|
|
HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the
|
2010-11-26 16:33:21 -05:00
|
|
|
first token we see is an operator, skip over its right-hand-side argument.
|
|
|
|
HALFSEXP can also be a token, in which case we should skip the text
|
|
|
|
assuming it is the right-hand-side argument of that token.
|
2010-11-07 10:52:33 -05:00
|
|
|
Possible return values:
|
|
|
|
(RIGHT-LEVEL POS TOKEN): we couldn't skip TOKEN because its left-level
|
|
|
|
is too high. RIGHT-LEVEL is the right-level of TOKEN,
|
|
|
|
POS is its end position in the buffer.
|
2012-05-15 09:25:03 -04:00
|
|
|
(t POS TOKEN): same thing but for a close-paren or the end of buffer.
|
|
|
|
Instead of t, the `car' can also be some other non-nil non-number value.
|
2010-11-07 10:52:33 -05:00
|
|
|
(nil POS TOKEN): we skipped over a paren-like pair.
|
|
|
|
nil: we skipped over an identifier, matched parentheses, ..."
|
|
|
|
(smie-next-sexp
|
|
|
|
(indirect-function smie-forward-token-function)
|
2014-07-20 21:58:43 -04:00
|
|
|
(indirect-function #'forward-sexp)
|
|
|
|
(indirect-function #'smie-op-right)
|
|
|
|
(indirect-function #'smie-op-left)
|
2010-11-07 10:52:33 -05:00
|
|
|
halfsexp))
|
|
|
|
|
2011-11-13 22:27:12 -08:00
|
|
|
;;; Miscellaneous commands using the precedence parser.
|
2010-11-07 10:52:33 -05:00
|
|
|
|
2015-03-26 09:36:24 -04:00
|
|
|
(defun smie-backward-sexp-command (n)
|
2010-11-07 10:52:33 -05:00
|
|
|
"Move backward through N logical elements."
|
|
|
|
(interactive "^p")
|
|
|
|
(smie-forward-sexp-command (- n)))
|
|
|
|
|
2015-03-26 09:36:24 -04:00
|
|
|
(defun smie-forward-sexp-command (n)
|
2010-11-07 10:52:33 -05:00
|
|
|
"Move forward through N logical elements."
|
|
|
|
(interactive "^p")
|
|
|
|
(let ((forw (> n 0))
|
|
|
|
(forward-sexp-function nil))
|
|
|
|
(while (/= n 0)
|
|
|
|
(setq n (- n (if forw 1 -1)))
|
|
|
|
(let ((pos (point))
|
|
|
|
(res (if forw
|
|
|
|
(smie-forward-sexp 'halfsexp)
|
|
|
|
(smie-backward-sexp 'halfsexp))))
|
|
|
|
(if (and (car res) (= pos (point)) (not (if forw (eobp) (bobp))))
|
|
|
|
(signal 'scan-error
|
|
|
|
(list "Containing expression ends prematurely"
|
|
|
|
(cadr res) (cadr res)))
|
|
|
|
nil)))))
|
|
|
|
|
|
|
|
(defvar smie-closer-alist nil
|
|
|
|
"Alist giving the closer corresponding to an opener.")
|
|
|
|
|
|
|
|
(defun smie-close-block ()
|
|
|
|
"Close the closest surrounding block."
|
|
|
|
(interactive)
|
|
|
|
(let ((closer
|
|
|
|
(save-excursion
|
|
|
|
(backward-up-list 1)
|
|
|
|
(if (looking-at "\\s(")
|
|
|
|
(string (cdr (syntax-after (point))))
|
|
|
|
(let* ((open (funcall smie-forward-token-function))
|
|
|
|
(closer (cdr (assoc open smie-closer-alist)))
|
|
|
|
(levels (list (assoc open smie-grammar)))
|
|
|
|
(seen '())
|
|
|
|
(found '()))
|
|
|
|
(cond
|
|
|
|
;; Even if we improve the auto-computation of closers,
|
|
|
|
;; there are still cases where we need manual
|
|
|
|
;; intervention, e.g. for Octave's use of `until'
|
|
|
|
;; as a pseudo-closer of `do'.
|
|
|
|
(closer)
|
2010-11-17 14:59:16 -05:00
|
|
|
((or (equal levels '(nil)) (numberp (nth 1 (car levels))))
|
2010-11-07 10:52:33 -05:00
|
|
|
(error "Doesn't look like a block"))
|
|
|
|
(t
|
|
|
|
;; Now that smie-setup automatically sets smie-closer-alist
|
|
|
|
;; from the BNF, this is not really needed any more.
|
|
|
|
(while levels
|
|
|
|
(let ((level (pop levels)))
|
|
|
|
(dolist (other smie-grammar)
|
|
|
|
(when (and (eq (nth 2 level) (nth 1 other))
|
|
|
|
(not (memq other seen)))
|
|
|
|
(push other seen)
|
2010-11-17 14:59:16 -05:00
|
|
|
(if (numberp (nth 2 other))
|
2010-11-07 10:52:33 -05:00
|
|
|
(push other levels)
|
|
|
|
(push (car other) found))))))
|
|
|
|
(cond
|
|
|
|
((null found) (error "No known closer for opener %s" open))
|
2010-11-26 16:33:21 -05:00
|
|
|
;; What should we do if there are various closers?
|
2010-11-07 10:52:33 -05:00
|
|
|
(t (car found))))))))))
|
|
|
|
(unless (save-excursion (skip-chars-backward " \t") (bolp))
|
|
|
|
(newline))
|
|
|
|
(insert closer)
|
|
|
|
(if (save-excursion (skip-chars-forward " \t") (eolp))
|
|
|
|
(indent-according-to-mode)
|
|
|
|
(reindent-then-newline-and-indent))))
|
|
|
|
|
|
|
|
(defun smie-down-list (&optional arg)
|
|
|
|
"Move forward down one level paren-like blocks. Like `down-list'.
|
|
|
|
With argument ARG, do this that many times.
|
|
|
|
A negative argument means move backward but still go down a level.
|
|
|
|
This command assumes point is not in a string or comment."
|
|
|
|
(interactive "p")
|
|
|
|
(let ((start (point))
|
|
|
|
(inc (if (< arg 0) -1 1))
|
|
|
|
(offset (if (< arg 0) 1 0))
|
|
|
|
(next-token (if (< arg 0)
|
|
|
|
smie-backward-token-function
|
|
|
|
smie-forward-token-function)))
|
|
|
|
(while (/= arg 0)
|
|
|
|
(setq arg (- arg inc))
|
|
|
|
(while
|
|
|
|
(let* ((pos (point))
|
|
|
|
(token (funcall next-token))
|
|
|
|
(levels (assoc token smie-grammar)))
|
|
|
|
(cond
|
|
|
|
((zerop (length token))
|
|
|
|
(if (if (< inc 0) (looking-back "\\s(\\|\\s)" (1- (point)))
|
|
|
|
(looking-at "\\s(\\|\\s)"))
|
|
|
|
;; Go back to `start' in case of an error. This presumes
|
|
|
|
;; none of the token we've found until now include a ( or ).
|
|
|
|
(progn (goto-char start) (down-list inc) nil)
|
|
|
|
(forward-sexp inc)
|
|
|
|
(/= (point) pos)))
|
2010-11-17 14:59:16 -05:00
|
|
|
((and levels (not (numberp (nth (+ 1 offset) levels)))) nil)
|
|
|
|
((and levels (not (numberp (nth (- 2 offset) levels))))
|
2010-11-07 10:52:33 -05:00
|
|
|
(let ((end (point)))
|
|
|
|
(goto-char start)
|
|
|
|
(signal 'scan-error
|
|
|
|
(list "Containing expression ends prematurely"
|
|
|
|
pos end))))
|
|
|
|
(t)))))))
|
|
|
|
|
|
|
|
(defvar smie-blink-matching-triggers '(?\s ?\n)
|
|
|
|
"Chars which might trigger `blink-matching-open'.
|
|
|
|
These can include the final chars of end-tokens, or chars that are
|
|
|
|
typically inserted right after an end token.
|
|
|
|
I.e. a good choice can be:
|
|
|
|
(delete-dups
|
|
|
|
(mapcar (lambda (kw) (aref (cdr kw) (1- (length (cdr kw)))))
|
|
|
|
smie-closer-alist))")
|
|
|
|
|
|
|
|
(defcustom smie-blink-matching-inners t
|
|
|
|
"Whether SMIE should blink to matching opener for inner keywords.
|
|
|
|
If non-nil, it will blink not only for \"begin..end\" but also for \"if...else\"."
|
|
|
|
:type 'boolean
|
|
|
|
:group 'smie)
|
|
|
|
|
|
|
|
(defun smie-blink-matching-check (start end)
|
|
|
|
(save-excursion
|
|
|
|
(goto-char end)
|
|
|
|
(let ((ender (funcall smie-backward-token-function)))
|
|
|
|
(cond
|
|
|
|
((not (and ender (rassoc ender smie-closer-alist)))
|
2013-06-07 18:58:35 -04:00
|
|
|
;; This is not one of the begin..end we know how to check.
|
2010-11-07 10:52:33 -05:00
|
|
|
(blink-matching-check-mismatch start end))
|
|
|
|
((not start) t)
|
|
|
|
((eq t (car (rassoc ender smie-closer-alist))) nil)
|
|
|
|
(t
|
|
|
|
(goto-char start)
|
|
|
|
(let ((starter (funcall smie-forward-token-function)))
|
|
|
|
(not (member (cons starter ender) smie-closer-alist))))))))
|
|
|
|
|
|
|
|
(defun smie-blink-matching-open ()
|
|
|
|
"Blink the matching opener when applicable.
|
|
|
|
This uses SMIE's tables and is expected to be placed on `post-self-insert-hook'."
|
|
|
|
(let ((pos (point)) ;Position after the close token.
|
|
|
|
token)
|
|
|
|
(when (and blink-matching-paren
|
|
|
|
smie-closer-alist ; Optimization.
|
|
|
|
(or (eq (char-before) last-command-event) ;; Sanity check.
|
|
|
|
(save-excursion
|
|
|
|
(or (progn (skip-chars-backward " \t")
|
|
|
|
(setq pos (point))
|
|
|
|
(eq (char-before) last-command-event))
|
|
|
|
(progn (skip-chars-backward " \n\t")
|
|
|
|
(setq pos (point))
|
|
|
|
(eq (char-before) last-command-event)))))
|
|
|
|
(memq last-command-event smie-blink-matching-triggers)
|
|
|
|
(not (nth 8 (syntax-ppss))))
|
|
|
|
(save-excursion
|
|
|
|
(setq token (funcall smie-backward-token-function))
|
|
|
|
(when (and (eq (point) (1- pos))
|
|
|
|
(= 1 (length token))
|
|
|
|
(not (rassoc token smie-closer-alist)))
|
|
|
|
;; The trigger char is itself a token but is not one of the
|
|
|
|
;; closers (e.g. ?\; in Octave mode), so go back to the
|
|
|
|
;; previous token.
|
|
|
|
(setq pos (point))
|
|
|
|
(setq token (funcall smie-backward-token-function)))
|
|
|
|
(when (rassoc token smie-closer-alist)
|
|
|
|
;; We're after a close token. Let's still make sure we
|
|
|
|
;; didn't skip a comment to find that token.
|
|
|
|
(funcall smie-forward-token-function)
|
|
|
|
(when (and (save-excursion
|
|
|
|
;; Skip the trigger char, if applicable.
|
|
|
|
(if (eq (char-after) last-command-event)
|
|
|
|
(forward-char 1))
|
|
|
|
(if (eq ?\n last-command-event)
|
|
|
|
;; Skip any auto-indentation, if applicable.
|
|
|
|
(skip-chars-forward " \t"))
|
|
|
|
(>= (point) pos))
|
|
|
|
;; If token ends with a trigger char, don't blink for
|
|
|
|
;; anything else than this trigger char, lest we'd blink
|
|
|
|
;; both when inserting the trigger char and when
|
|
|
|
;; inserting a subsequent trigger char like SPC.
|
2011-02-10 14:40:17 -05:00
|
|
|
(or (eq (char-before) last-command-event)
|
2010-11-07 10:52:33 -05:00
|
|
|
(not (memq (char-before)
|
|
|
|
smie-blink-matching-triggers)))
|
2013-06-07 18:58:35 -04:00
|
|
|
;; FIXME: For octave's "switch ... case ... case" we flash
|
|
|
|
;; `switch' at the end of the first `case' and we burp
|
|
|
|
;; "mismatch" at the end of the second `case'.
|
2010-11-07 10:52:33 -05:00
|
|
|
(or smie-blink-matching-inners
|
2010-11-17 14:59:16 -05:00
|
|
|
(not (numberp (nth 2 (assoc token smie-grammar))))))
|
2010-11-07 10:52:33 -05:00
|
|
|
;; The major mode might set blink-matching-check-function
|
|
|
|
;; buffer-locally so that interactive calls to
|
|
|
|
;; blink-matching-open work right, but let's not presume
|
|
|
|
;; that's the case.
|
|
|
|
(let ((blink-matching-check-function #'smie-blink-matching-check))
|
|
|
|
(blink-matching-open))))))))
|
|
|
|
|
2013-06-05 15:40:02 +08:00
|
|
|
(defvar-local smie--matching-block-data-cache nil)
|
|
|
|
|
2013-06-07 18:58:35 -04:00
|
|
|
(defun smie--opener/closer-at-point ()
|
|
|
|
"Return (OPENER TOKEN START END) or nil.
|
|
|
|
OPENER is non-nil if TOKEN is an opener and nil if it's a closer."
|
|
|
|
(let* ((start (point))
|
|
|
|
;; Move to a previous position outside of a token.
|
|
|
|
(_ (funcall smie-backward-token-function))
|
|
|
|
;; Move to the end of the token before point.
|
|
|
|
(btok (funcall smie-forward-token-function))
|
|
|
|
(bend (point)))
|
|
|
|
(cond
|
|
|
|
;; Token before point is a closer?
|
|
|
|
((and (>= bend start) (rassoc btok smie-closer-alist))
|
|
|
|
(funcall smie-backward-token-function)
|
|
|
|
(when (< (point) start)
|
|
|
|
(prog1 (list nil btok (point) bend)
|
|
|
|
(goto-char bend))))
|
|
|
|
;; Token around point is an opener?
|
|
|
|
((and (> bend start) (assoc btok smie-closer-alist))
|
|
|
|
(funcall smie-backward-token-function)
|
|
|
|
(when (<= (point) start) (list t btok (point) bend)))
|
|
|
|
((<= bend start)
|
|
|
|
(let ((atok (funcall smie-forward-token-function))
|
|
|
|
(aend (point)))
|
|
|
|
(cond
|
|
|
|
((< aend start) nil) ;Hopefully shouldn't happen.
|
|
|
|
;; Token after point is a closer?
|
|
|
|
((assoc atok smie-closer-alist)
|
|
|
|
(funcall smie-backward-token-function)
|
|
|
|
(when (<= (point) start)
|
|
|
|
(list t atok (point) aend)))))))))
|
|
|
|
|
2013-06-05 15:40:02 +08:00
|
|
|
(defun smie--matching-block-data (orig &rest args)
|
|
|
|
"A function suitable for `show-paren-data-function' (which see)."
|
2013-06-07 18:58:35 -04:00
|
|
|
(if (or (null smie-closer-alist)
|
2013-10-11 03:45:03 +03:00
|
|
|
(equal (cons (point) (buffer-chars-modified-tick))
|
|
|
|
(car smie--matching-block-data-cache)))
|
2013-06-07 18:58:35 -04:00
|
|
|
(or (cdr smie--matching-block-data-cache)
|
|
|
|
(apply orig args))
|
2013-10-11 03:45:03 +03:00
|
|
|
(setq smie--matching-block-data-cache
|
|
|
|
(list (cons (point) (buffer-chars-modified-tick))))
|
2013-06-07 18:58:35 -04:00
|
|
|
(unless (nth 8 (syntax-ppss))
|
|
|
|
(condition-case nil
|
|
|
|
(let ((here (smie--opener/closer-at-point)))
|
|
|
|
(when (and here
|
|
|
|
(or smie-blink-matching-inners
|
|
|
|
(not (numberp
|
|
|
|
(nth (if (nth 0 here) 1 2)
|
|
|
|
(assoc (nth 1 here) smie-grammar))))))
|
|
|
|
(let ((there
|
|
|
|
(cond
|
|
|
|
((car here) ; Opener.
|
|
|
|
(let ((data (smie-forward-sexp 'halfsexp))
|
|
|
|
(tend (point)))
|
|
|
|
(unless (car data)
|
|
|
|
(funcall smie-backward-token-function)
|
|
|
|
(list (member (cons (nth 1 here) (nth 2 data))
|
|
|
|
smie-closer-alist)
|
|
|
|
(point) tend))))
|
|
|
|
(t ;Closer.
|
|
|
|
(let ((data (smie-backward-sexp 'halfsexp))
|
|
|
|
(htok (nth 1 here)))
|
|
|
|
(if (car data)
|
|
|
|
(let* ((hprec (nth 2 (assoc htok smie-grammar)))
|
|
|
|
(ttok (nth 2 data))
|
|
|
|
(tprec (nth 1 (assoc ttok smie-grammar))))
|
|
|
|
(when (and (numberp hprec) ;Here is an inner.
|
|
|
|
(eq hprec tprec))
|
|
|
|
(goto-char (nth 1 data))
|
|
|
|
(let ((tbeg (point)))
|
|
|
|
(funcall smie-forward-token-function)
|
|
|
|
(list t tbeg (point)))))
|
|
|
|
(let ((tbeg (point)))
|
|
|
|
(funcall smie-forward-token-function)
|
|
|
|
(list (member (cons (nth 2 data) htok)
|
|
|
|
smie-closer-alist)
|
|
|
|
tbeg (point)))))))))
|
|
|
|
;; Update the cache.
|
|
|
|
(setcdr smie--matching-block-data-cache
|
|
|
|
(list (nth 2 here) (nth 3 here)
|
|
|
|
(nth 1 there) (nth 2 there)
|
|
|
|
(not (nth 0 there)))))))
|
|
|
|
(scan-error nil))
|
2013-10-11 03:45:03 +03:00
|
|
|
(goto-char (caar smie--matching-block-data-cache)))
|
2013-06-07 18:58:35 -04:00
|
|
|
(apply #'smie--matching-block-data orig args)))
|
2013-05-17 06:58:58 +08:00
|
|
|
|
2010-11-07 10:52:33 -05:00
|
|
|
;;; The indentation engine.
|
|
|
|
|
|
|
|
(defcustom smie-indent-basic 4
|
|
|
|
"Basic amount of indentation."
|
|
|
|
:type 'integer
|
|
|
|
:group 'smie)
|
|
|
|
|
2014-07-20 21:58:43 -04:00
|
|
|
(defvar smie-rules-function #'ignore
|
2010-11-07 10:52:33 -05:00
|
|
|
"Function providing the indentation rules.
|
|
|
|
It takes two arguments METHOD and ARG where the meaning of ARG
|
|
|
|
and the expected return value depends on METHOD.
|
|
|
|
METHOD can be:
|
|
|
|
- :after, in which case ARG is a token and the function should return the
|
|
|
|
OFFSET to use for indentation after ARG.
|
|
|
|
- :before, in which case ARG is a token and the function should return the
|
|
|
|
OFFSET to use to indent ARG itself.
|
|
|
|
- :elem, in which case the function should return either:
|
|
|
|
- the offset to use to indent function arguments (ARG = `arg')
|
|
|
|
- the basic indentation step (ARG = `basic').
|
2015-09-22 11:11:50 -04:00
|
|
|
- the token to use (when ARG = `empty-line-token') when we don't know how
|
|
|
|
to indent an empty line.
|
2010-11-07 10:52:33 -05:00
|
|
|
- :list-intro, in which case ARG is a token and the function should return
|
|
|
|
non-nil if TOKEN is followed by a list of expressions (not separated by any
|
|
|
|
token) rather than an expression.
|
2013-12-17 03:31:55 +02:00
|
|
|
- :close-all, in which case ARG is a close-paren token at indentation and
|
|
|
|
the function should return non-nil if it should be aligned with the opener
|
|
|
|
of the last close-paren token on the same line, if there are multiple.
|
|
|
|
Otherwise, it will be aligned with its own opener.
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
When ARG is a token, the function is called with point just before that token.
|
|
|
|
A return value of nil always means to fallback on the default behavior, so the
|
|
|
|
function should return nil for arguments it does not expect.
|
|
|
|
|
|
|
|
OFFSET can be:
|
|
|
|
nil use the default indentation rule.
|
2011-11-18 11:30:43 -05:00
|
|
|
\(column . COLUMN) indent to column COLUMN.
|
2010-11-07 10:52:33 -05:00
|
|
|
NUMBER offset by NUMBER, relative to a base token
|
|
|
|
which is the current token for :after and
|
|
|
|
its parent for :before.
|
|
|
|
|
|
|
|
The functions whose name starts with \"smie-rule-\" are helper functions
|
|
|
|
designed specifically for use in this function.")
|
|
|
|
|
2014-06-19 21:05:40 -04:00
|
|
|
(defvar smie--hanging-eolp-function
|
|
|
|
;; FIXME: This is a quick hack for 24.4. Don't document it and replace with
|
|
|
|
;; a well-defined function with a cleaner interface instead!
|
|
|
|
(lambda ()
|
|
|
|
(skip-chars-forward " \t")
|
|
|
|
(or (eolp)
|
|
|
|
(and ;; (looking-at comment-start-skip) ;(bug#16041).
|
|
|
|
(forward-comment (point-max))))))
|
|
|
|
|
2010-11-07 10:52:33 -05:00
|
|
|
(defalias 'smie-rule-hanging-p 'smie-indent--hanging-p)
|
|
|
|
(defun smie-indent--hanging-p ()
|
|
|
|
"Return non-nil if the current token is \"hanging\".
|
|
|
|
A hanging keyword is one that's at the end of a line except it's not at
|
|
|
|
the beginning of a line."
|
|
|
|
(and (not (smie-indent--bolp))
|
|
|
|
(save-excursion
|
|
|
|
(<= (line-end-position)
|
|
|
|
(progn
|
2013-04-24 23:25:34 -04:00
|
|
|
(and (zerop (length (funcall smie-forward-token-function)))
|
|
|
|
(not (eobp))
|
|
|
|
;; Could be an open-paren.
|
|
|
|
(forward-char 1))
|
2014-06-19 21:05:40 -04:00
|
|
|
(funcall smie--hanging-eolp-function)
|
2010-11-07 10:52:33 -05:00
|
|
|
(point))))))
|
|
|
|
|
|
|
|
(defalias 'smie-rule-bolp 'smie-indent--bolp)
|
|
|
|
(defun smie-indent--bolp ()
|
|
|
|
"Return non-nil if the current token is the first on the line."
|
|
|
|
(save-excursion (skip-chars-backward " \t") (bolp)))
|
|
|
|
|
2012-05-15 09:25:03 -04:00
|
|
|
(defun smie-indent--bolp-1 ()
|
|
|
|
;; Like smie-indent--bolp but also returns non-nil if it's the first
|
|
|
|
;; non-comment token. Maybe we should simply always use this?
|
|
|
|
"Return non-nil if the current token is the first on the line.
|
|
|
|
Comments are treated as spaces."
|
|
|
|
(let ((bol (line-beginning-position)))
|
|
|
|
(save-excursion
|
|
|
|
(forward-comment (- (point)))
|
|
|
|
(<= (point) bol))))
|
|
|
|
|
2015-08-21 14:13:05 -04:00
|
|
|
(defun smie-indent--current-column ()
|
|
|
|
"Like `current-column', but if there's a comment before us, use that."
|
|
|
|
;; This is used, so that when we align elements, we don't get
|
|
|
|
;; toto = { /* foo, */ a,
|
|
|
|
;; b }
|
|
|
|
;; but
|
|
|
|
;; toto = { /* foo, */ a,
|
|
|
|
;; b }
|
|
|
|
(let ((pos (point))
|
|
|
|
(lbp (line-beginning-position)))
|
|
|
|
(save-excursion
|
|
|
|
(unless (and (forward-comment -1) (>= (point) lbp))
|
|
|
|
(goto-char pos))
|
|
|
|
(current-column))))
|
|
|
|
|
2010-11-07 10:52:33 -05:00
|
|
|
;; Dynamically scoped.
|
|
|
|
(defvar smie--parent) (defvar smie--after) (defvar smie--token)
|
|
|
|
|
|
|
|
(defun smie-indent--parent ()
|
|
|
|
(or smie--parent
|
|
|
|
(save-excursion
|
|
|
|
(let* ((pos (point))
|
|
|
|
(tok (funcall smie-forward-token-function)))
|
2010-11-17 14:59:16 -05:00
|
|
|
(unless (numberp (cadr (assoc tok smie-grammar)))
|
2010-11-07 10:52:33 -05:00
|
|
|
(goto-char pos))
|
|
|
|
(setq smie--parent
|
2011-02-10 14:40:17 -05:00
|
|
|
(or (smie-backward-sexp 'halfsexp)
|
|
|
|
(let (res)
|
|
|
|
(while (null (setq res (smie-backward-sexp))))
|
|
|
|
(list nil (point) (nth 2 res)))))))))
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
(defun smie-rule-parent-p (&rest parents)
|
|
|
|
"Return non-nil if the current token's parent is among PARENTS.
|
|
|
|
Only meaningful when called from within `smie-rules-function'."
|
|
|
|
(member (nth 2 (smie-indent--parent)) parents))
|
|
|
|
|
|
|
|
(defun smie-rule-next-p (&rest tokens)
|
|
|
|
"Return non-nil if the next token is among TOKENS.
|
|
|
|
Only meaningful when called from within `smie-rules-function'."
|
|
|
|
(let ((next
|
|
|
|
(save-excursion
|
|
|
|
(unless smie--after
|
|
|
|
(smie-indent-forward-token) (setq smie--after (point)))
|
|
|
|
(goto-char smie--after)
|
|
|
|
(smie-indent-forward-token))))
|
|
|
|
(member (car next) tokens)))
|
|
|
|
|
|
|
|
(defun smie-rule-prev-p (&rest tokens)
|
|
|
|
"Return non-nil if the previous token is among TOKENS."
|
|
|
|
(let ((prev (save-excursion
|
|
|
|
(smie-indent-backward-token))))
|
|
|
|
(member (car prev) tokens)))
|
|
|
|
|
|
|
|
(defun smie-rule-sibling-p ()
|
|
|
|
"Return non-nil if the parent is actually a sibling.
|
|
|
|
Only meaningful when called from within `smie-rules-function'."
|
|
|
|
(eq (car (smie-indent--parent))
|
|
|
|
(cadr (assoc smie--token smie-grammar))))
|
|
|
|
|
|
|
|
(defun smie-rule-parent (&optional offset)
|
|
|
|
"Align with parent.
|
|
|
|
If non-nil, OFFSET should be an integer giving an additional offset to apply.
|
|
|
|
Only meaningful when called from within `smie-rules-function'."
|
|
|
|
(save-excursion
|
|
|
|
(goto-char (cadr (smie-indent--parent)))
|
|
|
|
(cons 'column
|
|
|
|
(+ (or offset 0)
|
2013-11-03 17:56:03 -05:00
|
|
|
(smie-indent-virtual)))))
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
(defvar smie-rule-separator-outdent 2)
|
|
|
|
|
|
|
|
(defun smie-indent--separator-outdent ()
|
|
|
|
;; FIXME: Here we actually have several reasonable behaviors.
|
|
|
|
;; E.g. for a parent token of "FOO" and a separator ";" we may want to:
|
|
|
|
;; 1- left-align ; with FOO.
|
|
|
|
;; 2- right-align ; with FOO.
|
|
|
|
;; 3- align content after ; with content after FOO.
|
|
|
|
;; 4- align content plus add/remove spaces so as to align ; with FOO.
|
|
|
|
;; Currently, we try to align the contents (option 3) which actually behaves
|
|
|
|
;; just like option 2 (if the number of spaces after FOO and ; is equal).
|
|
|
|
(let ((afterpos (save-excursion
|
|
|
|
(let ((tok (funcall smie-forward-token-function)))
|
|
|
|
(unless tok
|
|
|
|
(with-demoted-errors
|
|
|
|
(error "smie-rule-separator: can't skip token %s"
|
|
|
|
smie--token))))
|
|
|
|
(skip-chars-forward " ")
|
|
|
|
(unless (eolp) (point)))))
|
|
|
|
(or (and afterpos
|
|
|
|
;; This should always be true, unless
|
|
|
|
;; smie-forward-token-function skipped a \n.
|
|
|
|
(< afterpos (line-end-position))
|
|
|
|
(- afterpos (point)))
|
|
|
|
smie-rule-separator-outdent)))
|
|
|
|
|
|
|
|
(defun smie-rule-separator (method)
|
|
|
|
"Indent current token as a \"separator\".
|
|
|
|
By \"separator\", we mean here a token whose sole purpose is to separate
|
|
|
|
various elements within some enclosing syntactic construct, and which does
|
|
|
|
not have any semantic significance in itself (i.e. it would typically no exist
|
|
|
|
as a node in an abstract syntax tree).
|
|
|
|
Such a token is expected to have an associative syntax and be closely tied
|
|
|
|
to its syntactic parent. Typical examples are \",\" in lists of arguments
|
|
|
|
\(enclosed inside parentheses), or \";\" in sequences of instructions (enclosed
|
|
|
|
in a {..} or begin..end block).
|
|
|
|
METHOD should be the method name that was passed to `smie-rules-function'.
|
|
|
|
Only meaningful when called from within `smie-rules-function'."
|
|
|
|
;; FIXME: The code below works OK for cases where the separators
|
|
|
|
;; are placed consistently always at beginning or always at the end,
|
|
|
|
;; but not if some are at the beginning and others are at the end.
|
|
|
|
;; I.e. it gets confused in cases such as:
|
|
|
|
;; ( a
|
|
|
|
;; , a,
|
|
|
|
;; b
|
|
|
|
;; , c,
|
|
|
|
;; d
|
|
|
|
;; )
|
|
|
|
;;
|
|
|
|
;; Assuming token is associative, the default rule for associative
|
|
|
|
;; tokens (which assumes an infix operator) works fine for many cases.
|
|
|
|
;; We mostly need to take care of the case where token is at beginning of
|
|
|
|
;; line, in which case we want to align it with its enclosing parent.
|
|
|
|
(cond
|
|
|
|
((and (eq method :before) (smie-rule-bolp) (not (smie-rule-sibling-p)))
|
2010-11-11 00:08:25 -05:00
|
|
|
(let ((parent-col (cdr (smie-rule-parent)))
|
2010-11-07 10:52:33 -05:00
|
|
|
(parent-pos-col ;FIXME: we knew this when computing smie--parent.
|
|
|
|
(save-excursion
|
|
|
|
(goto-char (cadr smie--parent))
|
|
|
|
(smie-indent-forward-token)
|
|
|
|
(forward-comment (point-max))
|
|
|
|
(current-column))))
|
|
|
|
(cons 'column
|
|
|
|
(max parent-col
|
|
|
|
(min parent-pos-col
|
|
|
|
(- parent-pos-col (smie-indent--separator-outdent)))))))
|
|
|
|
((and (eq method :after) (smie-indent--bolp))
|
|
|
|
(smie-indent--separator-outdent))))
|
|
|
|
|
|
|
|
(defun smie-indent--offset (elem)
|
|
|
|
(or (funcall smie-rules-function :elem elem)
|
|
|
|
(if (not (eq elem 'basic))
|
|
|
|
(funcall smie-rules-function :elem 'basic))
|
|
|
|
smie-indent-basic))
|
|
|
|
|
2020-05-29 15:01:58 -04:00
|
|
|
(defun smie-indent--rule ( method token
|
|
|
|
;; FIXME: Too many parameters.
|
|
|
|
&optional after parent base-pos)
|
2013-12-17 03:31:55 +02:00
|
|
|
"Compute indentation column according to `smie-rules-function'.
|
|
|
|
METHOD and TOKEN are passed to `smie-rules-function'.
|
2010-11-07 10:52:33 -05:00
|
|
|
AFTER is the position after TOKEN, if known.
|
|
|
|
PARENT is the parent info returned by `smie-backward-sexp', if known.
|
|
|
|
BASE-POS is the position relative to which offsets should be applied."
|
|
|
|
;; This is currently called in 3 cases:
|
|
|
|
;; - :before opener, where rest=nil but base-pos could as well be parent.
|
|
|
|
;; - :before other, where
|
|
|
|
;; ; after=nil
|
|
|
|
;; ; parent is set
|
|
|
|
;; ; base-pos=parent
|
|
|
|
;; - :after tok, where
|
|
|
|
;; ; after is set; parent=nil; base-pos=point;
|
|
|
|
(save-excursion
|
2013-12-17 03:31:55 +02:00
|
|
|
(let ((offset (smie-indent--rule-1 method token after parent)))
|
2010-11-07 10:52:33 -05:00
|
|
|
(cond
|
|
|
|
((not offset) nil)
|
|
|
|
((eq (car-safe offset) 'column) (cdr offset))
|
|
|
|
((integerp offset)
|
|
|
|
(+ offset
|
|
|
|
(if (null base-pos) 0
|
|
|
|
(goto-char base-pos)
|
2010-11-11 00:08:25 -05:00
|
|
|
;; Use smie-indent-virtual when indenting relative to an opener:
|
|
|
|
;; this will also by default use current-column unless
|
|
|
|
;; that opener is hanging, but will additionally consult
|
|
|
|
;; rules-function, so it gives it a chance to tweak indentation
|
|
|
|
;; (e.g. by forcing indentation relative to its own parent, as in
|
|
|
|
;; fn a => fn b => fn c =>).
|
|
|
|
;; When parent==nil it doesn't matter because the only case
|
|
|
|
;; where it's really used is when the base-pos is hanging anyway.
|
|
|
|
(if (or (and parent (null (car parent)))
|
|
|
|
(smie-indent--hanging-p))
|
2010-11-07 10:52:33 -05:00
|
|
|
(smie-indent-virtual) (current-column)))))
|
|
|
|
(t (error "Unknown indentation offset %s" offset))))))
|
|
|
|
|
2013-12-17 03:31:55 +02:00
|
|
|
(defun smie-indent--rule-1 (method token &optional after parent)
|
|
|
|
(let ((smie--parent parent)
|
|
|
|
(smie--token token)
|
|
|
|
(smie--after after))
|
|
|
|
(funcall smie-rules-function method token)))
|
|
|
|
|
2010-11-07 10:52:33 -05:00
|
|
|
(defun smie-indent-forward-token ()
|
|
|
|
"Skip token forward and return it, along with its levels."
|
|
|
|
(let ((tok (funcall smie-forward-token-function)))
|
|
|
|
(cond
|
|
|
|
((< 0 (length tok)) (assoc tok smie-grammar))
|
|
|
|
((looking-at "\\s(\\|\\s)\\(\\)")
|
|
|
|
(forward-char 1)
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
(cons (buffer-substring-no-properties (1- (point)) (point))
|
2013-05-23 13:44:38 -04:00
|
|
|
(if (match-end 1) '(0 nil) '(nil 0))))
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
((looking-at "\\s\"\\|\\s|")
|
2013-05-23 13:44:38 -04:00
|
|
|
(forward-sexp 1)
|
|
|
|
nil)
|
|
|
|
((eobp) nil)
|
|
|
|
(t (error "Bumped into unknown token")))))
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
(defun smie-indent-backward-token ()
|
|
|
|
"Skip token backward and return it, along with its levels."
|
|
|
|
(let ((tok (funcall smie-backward-token-function))
|
|
|
|
class)
|
|
|
|
(cond
|
|
|
|
((< 0 (length tok)) (assoc tok smie-grammar))
|
|
|
|
;; 4 == open paren syntax, 5 == close.
|
|
|
|
((memq (setq class (syntax-class (syntax-after (1- (point))))) '(4 5))
|
|
|
|
(forward-char -1)
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
(cons (buffer-substring-no-properties (point) (1+ (point)))
|
2013-05-23 13:44:38 -04:00
|
|
|
(if (eq class 4) '(nil 0) '(0 nil))))
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
((memq class '(7 15))
|
2013-05-23 13:44:38 -04:00
|
|
|
(backward-sexp 1)
|
|
|
|
nil)
|
|
|
|
((bobp) nil)
|
|
|
|
(t (error "Bumped into unknown token")))))
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
(defun smie-indent-virtual ()
|
|
|
|
;; We used to take an optional arg (with value :not-hanging) to specify that
|
|
|
|
;; we should only use (smie-indent-calculate) if we're looking at a hanging
|
|
|
|
;; keyword. This was a bad idea, because the virtual indent of a position
|
|
|
|
;; should not depend on the caller, since it leads to situations where two
|
|
|
|
;; dependent indentations get indented differently.
|
|
|
|
"Compute the virtual indentation to use for point.
|
|
|
|
This is used when we're not trying to indent point but just
|
|
|
|
need to compute the column at which point should be indented
|
|
|
|
in order to figure out the indentation of some other (further down) point."
|
|
|
|
;; Trust pre-existing indentation on other lines.
|
|
|
|
(if (smie-indent--bolp) (current-column) (smie-indent-calculate)))
|
|
|
|
|
|
|
|
(defun smie-indent-fixindent ()
|
|
|
|
;; Obey the `fixindent' special comment.
|
|
|
|
(and (smie-indent--bolp)
|
|
|
|
(save-excursion
|
|
|
|
(comment-normalize-vars)
|
2019-04-05 08:00:09 -04:00
|
|
|
(re-search-forward (concat "\\(?:" comment-start-skip "\\)"
|
2010-11-07 10:52:33 -05:00
|
|
|
"fixindent"
|
2019-04-05 08:00:09 -04:00
|
|
|
"\\(?:" comment-end-skip "\\)")
|
2010-11-07 10:52:33 -05:00
|
|
|
;; 1+ to account for the \n comment termination.
|
|
|
|
(1+ (line-end-position)) t))
|
|
|
|
(current-column)))
|
|
|
|
|
|
|
|
(defun smie-indent-bob ()
|
|
|
|
;; Start the file at column 0.
|
|
|
|
(save-excursion
|
|
|
|
(forward-comment (- (point)))
|
2017-03-23 11:32:59 -06:00
|
|
|
(if (bobp) (prog-first-column))))
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
(defun smie-indent-close ()
|
|
|
|
;; Align close paren with opening paren.
|
|
|
|
(save-excursion
|
|
|
|
;; (forward-comment (point-max))
|
|
|
|
(when (looking-at "\\s)")
|
2013-12-17 03:31:55 +02:00
|
|
|
(if (smie-indent--rule-1 :close-all
|
|
|
|
(buffer-substring-no-properties
|
|
|
|
(point) (1+ (point)))
|
|
|
|
(1+ (point)))
|
|
|
|
(while (not (zerop (skip-syntax-forward ")")))
|
|
|
|
(skip-chars-forward " \t"))
|
|
|
|
(forward-char 1))
|
2010-11-07 10:52:33 -05:00
|
|
|
(condition-case nil
|
|
|
|
(progn
|
|
|
|
(backward-sexp 1)
|
|
|
|
(smie-indent-virtual)) ;:not-hanging
|
|
|
|
(scan-error nil)))))
|
|
|
|
|
2010-11-26 16:33:21 -05:00
|
|
|
(defun smie-indent-keyword (&optional token)
|
|
|
|
"Indent point based on the token that follows it immediately.
|
|
|
|
If TOKEN is non-nil, assume that that is the token that follows point.
|
|
|
|
Returns either a column number or nil if it considers that indentation
|
|
|
|
should not be computed on the basis of the following token."
|
2010-11-07 10:52:33 -05:00
|
|
|
(save-excursion
|
|
|
|
(let* ((pos (point))
|
2010-11-26 16:33:21 -05:00
|
|
|
(toklevels
|
|
|
|
(if token
|
|
|
|
(assoc token smie-grammar)
|
|
|
|
(let* ((res (smie-indent-forward-token)))
|
|
|
|
;; Ignore tokens on subsequent lines.
|
|
|
|
(if (and (< pos (line-beginning-position))
|
|
|
|
;; Make sure `token' also *starts* on another line.
|
|
|
|
(save-excursion
|
2013-04-24 23:25:34 -04:00
|
|
|
(let ((endpos (point)))
|
|
|
|
(goto-char pos)
|
|
|
|
(forward-line 1)
|
2016-03-16 22:55:56 -04:00
|
|
|
;; As seen in bug#22960, pos may be inside
|
|
|
|
;; a string, and forward-token may then stumble.
|
|
|
|
(and (ignore-errors
|
|
|
|
(equal res (smie-indent-forward-token)))
|
2013-04-24 23:25:34 -04:00
|
|
|
(eq (point) endpos)))))
|
2010-11-26 16:33:21 -05:00
|
|
|
nil
|
|
|
|
(goto-char pos)
|
|
|
|
res)))))
|
|
|
|
(setq token (pop toklevels))
|
2010-11-17 14:59:16 -05:00
|
|
|
(cond
|
2010-11-26 16:33:21 -05:00
|
|
|
((null (cdr toklevels)) nil) ;Not a keyword.
|
2010-11-17 14:59:16 -05:00
|
|
|
((not (numberp (car toklevels)))
|
2010-11-26 16:33:21 -05:00
|
|
|
;; Different cases:
|
|
|
|
;; - smie-indent--bolp: "indent according to others".
|
|
|
|
;; - common hanging: "indent according to others".
|
|
|
|
;; - SML-let hanging: "indent like parent".
|
|
|
|
;; - if-after-else: "indent-like parent".
|
|
|
|
;; - middle-of-line: "trust current position".
|
|
|
|
(cond
|
|
|
|
((smie-indent--rule :before token))
|
2012-05-15 09:25:03 -04:00
|
|
|
((smie-indent--bolp-1) ;I.e. non-virtual indent.
|
2010-11-26 16:33:21 -05:00
|
|
|
;; For an open-paren-like thingy at BOL, always indent only
|
|
|
|
;; based on other rules (typically smie-indent-after-keyword).
|
2012-05-15 09:25:03 -04:00
|
|
|
;; FIXME: we do the same if after a comment, since we may be trying
|
|
|
|
;; to compute the indentation of this comment and we shouldn't indent
|
|
|
|
;; based on the indentation of subsequent code.
|
2010-11-26 16:33:21 -05:00
|
|
|
nil)
|
|
|
|
(t
|
|
|
|
;; By default use point unless we're hanging.
|
|
|
|
(unless (smie-indent--hanging-p) (current-column)))))
|
2010-11-17 14:59:16 -05:00
|
|
|
(t
|
2010-11-07 10:52:33 -05:00
|
|
|
;; FIXME: This still looks too much like black magic!!
|
2010-11-26 16:33:21 -05:00
|
|
|
(let* ((parent (smie-backward-sexp token)))
|
2010-11-07 10:52:33 -05:00
|
|
|
;; Different behaviors:
|
|
|
|
;; - align with parent.
|
|
|
|
;; - parent + offset.
|
|
|
|
;; - after parent's column + offset (actually, after or before
|
|
|
|
;; depending on where backward-sexp stopped).
|
|
|
|
;; ? let it drop to some other indentation function (almost never).
|
|
|
|
;; ? parent + offset + parent's own offset.
|
|
|
|
;; Different cases:
|
|
|
|
;; - bump into a same-level operator.
|
|
|
|
;; - bump into a specific known parent.
|
|
|
|
;; - find a matching open-paren thingy.
|
|
|
|
;; - bump into some random parent.
|
|
|
|
;; ? borderline case (almost never).
|
|
|
|
;; ? bump immediately into a parent.
|
|
|
|
(cond
|
|
|
|
((not (or (< (point) pos)
|
|
|
|
(and (cadr parent) (< (cadr parent) pos))))
|
|
|
|
;; If we didn't move at all, that means we didn't really skip
|
|
|
|
;; what we wanted. Should almost never happen, other than
|
|
|
|
;; maybe when an infix or close-paren is at the beginning
|
|
|
|
;; of a buffer.
|
|
|
|
nil)
|
|
|
|
((save-excursion
|
|
|
|
(goto-char pos)
|
|
|
|
(smie-indent--rule :before token nil parent (cadr parent))))
|
|
|
|
((eq (car parent) (car toklevels))
|
|
|
|
;; We bumped into a same-level operator; align with it.
|
|
|
|
(if (and (smie-indent--bolp) (/= (point) pos)
|
|
|
|
(save-excursion
|
|
|
|
(goto-char (goto-char (cadr parent)))
|
|
|
|
(not (smie-indent--bolp))))
|
|
|
|
;; If the parent is at EOL and its children are indented like
|
|
|
|
;; itself, then we can just obey the indentation chosen for the
|
|
|
|
;; child.
|
|
|
|
;; This is important for operators like ";" which
|
|
|
|
;; are usually at EOL (and have an offset of 0): otherwise we'd
|
|
|
|
;; always go back over all the statements, which is
|
|
|
|
;; a performance problem and would also mean that fixindents
|
|
|
|
;; in the middle of such a sequence would be ignored.
|
|
|
|
;;
|
|
|
|
;; This is a delicate point!
|
|
|
|
;; Even if the offset is not 0, we could follow the same logic
|
|
|
|
;; and subtract the offset from the child's indentation.
|
|
|
|
;; But that would more often be a bad idea: OT1H we generally
|
|
|
|
;; want to reuse the closest similar indentation point, so that
|
|
|
|
;; the user's choice (or the fixindents) are obeyed. But OTOH
|
|
|
|
;; we don't want this to affect "unrelated" parts of the code.
|
|
|
|
;; E.g. a fixindent in the body of a "begin..end" should not
|
|
|
|
;; affect the indentation of the "end".
|
|
|
|
(current-column)
|
|
|
|
(goto-char (cadr parent))
|
|
|
|
;; Don't use (smie-indent-virtual :not-hanging) here, because we
|
|
|
|
;; want to jump back over a sequence of same-level ops such as
|
|
|
|
;; a -> b -> c
|
|
|
|
;; -> d
|
|
|
|
;; So as to align with the earliest appropriate place.
|
|
|
|
(smie-indent-virtual)))
|
|
|
|
(t
|
|
|
|
(if (and (= (point) pos) (smie-indent--bolp))
|
|
|
|
;; Since we started at BOL, we're not computing a virtual
|
|
|
|
;; indentation, and we're still at the starting point, so
|
|
|
|
;; we can't use `current-column' which would cause
|
|
|
|
;; indentation to depend on itself and we can't use
|
|
|
|
;; smie-indent-virtual since that would be an inf-loop.
|
|
|
|
nil
|
|
|
|
;; In indent-keyword, if we're indenting `then' wrt `if', we
|
|
|
|
;; want to use indent-virtual rather than use just
|
|
|
|
;; current-column, so that we can apply the (:before . "if")
|
|
|
|
;; rule which does the "else if" dance in SML. But in other
|
|
|
|
;; cases, we do not want to use indent-virtual (e.g. indentation
|
|
|
|
;; of "*" w.r.t "+", or ";" wrt "("). We could just always use
|
|
|
|
;; indent-virtual and then have indent-rules say explicitly to
|
|
|
|
;; use `point' after things like "(" or "+" when they're not at
|
|
|
|
;; EOL, but you'd end up with lots of those rules.
|
|
|
|
;; So we use a heuristic here, which is that we only use virtual
|
|
|
|
;; if the parent is tightly linked to the child token (they're
|
|
|
|
;; part of the same BNF rule).
|
2015-08-21 14:13:05 -04:00
|
|
|
(if (car parent)
|
|
|
|
(smie-indent--current-column)
|
|
|
|
(smie-indent-virtual)))))))))))
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
(defun smie-indent-comment ()
|
|
|
|
"Compute indentation of a comment."
|
|
|
|
;; Don't do it for virtual indentations. We should normally never be "in
|
|
|
|
;; front of a comment" when doing virtual-indentation anyway. And if we are
|
|
|
|
;; (as can happen in octave-mode), moving forward can lead to inf-loops.
|
|
|
|
(and (smie-indent--bolp)
|
|
|
|
(let ((pos (point)))
|
|
|
|
(save-excursion
|
|
|
|
(beginning-of-line)
|
|
|
|
(and (re-search-forward comment-start-skip (line-end-position) t)
|
|
|
|
(eq pos (or (match-end 1) (match-beginning 0))))))
|
|
|
|
(save-excursion
|
|
|
|
(forward-comment (point-max))
|
|
|
|
(skip-chars-forward " \t\r\n")
|
2013-04-24 23:25:34 -04:00
|
|
|
(unless
|
|
|
|
;; Don't align with a closer, since the comment is "within" the
|
|
|
|
;; closed element. Don't align with EOB either.
|
|
|
|
(save-excursion
|
|
|
|
(let ((next (funcall smie-forward-token-function)))
|
|
|
|
(or (if (zerop (length next))
|
|
|
|
(or (eobp) (eq (car (syntax-after (point))) 5)))
|
|
|
|
(rassoc next smie-closer-alist))))
|
|
|
|
;; FIXME: We assume here that smie-indent-calculate will compute the
|
|
|
|
;; indentation of the next token based on text before the comment,
|
|
|
|
;; but this is not guaranteed, so maybe we should let
|
|
|
|
;; smie-indent-calculate return some info about which buffer
|
|
|
|
;; position was used as the "indentation base" and check that this
|
|
|
|
;; base is before `pos'.
|
|
|
|
(smie-indent-calculate)))))
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
(defun smie-indent-comment-continue ()
|
|
|
|
;; indentation of comment-continue lines.
|
|
|
|
(let ((continue (and comment-continue
|
|
|
|
(comment-string-strip comment-continue t t))))
|
|
|
|
(and (< 0 (length continue))
|
|
|
|
(looking-at (regexp-quote continue)) (nth 4 (syntax-ppss))
|
|
|
|
(let ((ppss (syntax-ppss)))
|
|
|
|
(save-excursion
|
|
|
|
(forward-line -1)
|
2019-04-19 23:50:58 -04:00
|
|
|
(let ((start (nth 8 ppss)))
|
|
|
|
(if (<= (point) start)
|
|
|
|
(progn
|
|
|
|
(goto-char start)
|
|
|
|
(if (not (and comment-start-skip
|
|
|
|
(looking-at comment-start-skip)))
|
|
|
|
(forward-char 1)
|
|
|
|
(goto-char (match-end 0))
|
|
|
|
(skip-chars-backward " \t")
|
|
|
|
;; Try to align the first char of the comment-continue
|
|
|
|
;; with the second char of the comment-start or the
|
|
|
|
;; first char if the comment-start is made of
|
|
|
|
;; a single char. E.g.
|
|
|
|
;;
|
|
|
|
;; /* foo
|
|
|
|
;; * bar */
|
|
|
|
;;
|
|
|
|
;; but
|
|
|
|
;;
|
|
|
|
;; { foo
|
|
|
|
;; | bar }
|
|
|
|
(goto-char (if (eq (point) (1+ start))
|
|
|
|
start (1+ start))))
|
|
|
|
(current-column))
|
|
|
|
(skip-chars-forward " \t")
|
|
|
|
(if (looking-at (regexp-quote continue))
|
|
|
|
(current-column)))))))))
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
(defun smie-indent-comment-close ()
|
|
|
|
(and (boundp 'comment-end-skip)
|
|
|
|
comment-end-skip
|
|
|
|
(not (looking-at " \t*$")) ;Not just a \n comment-closer.
|
|
|
|
(looking-at comment-end-skip)
|
2010-11-11 00:08:25 -05:00
|
|
|
(let ((end (match-string 0)))
|
|
|
|
(and (nth 4 (syntax-ppss))
|
|
|
|
(save-excursion
|
|
|
|
(goto-char (nth 8 (syntax-ppss)))
|
|
|
|
(and (looking-at comment-start-skip)
|
|
|
|
(let ((start (match-string 0)))
|
|
|
|
;; Align the common substring between starter
|
|
|
|
;; and ender, if possible.
|
|
|
|
(if (string-match "\\(.+\\).*\n\\(.*?\\)\\1"
|
|
|
|
(concat start "\n" end))
|
|
|
|
(+ (current-column) (match-beginning 0)
|
|
|
|
(- (match-beginning 2) (match-end 2)))
|
|
|
|
(current-column)))))))))
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
(defun smie-indent-comment-inside ()
|
|
|
|
(and (nth 4 (syntax-ppss))
|
|
|
|
'noindent))
|
|
|
|
|
2011-02-10 14:40:17 -05:00
|
|
|
(defun smie-indent-inside-string ()
|
|
|
|
(and (nth 3 (syntax-ppss))
|
|
|
|
'noindent))
|
|
|
|
|
2010-11-07 10:52:33 -05:00
|
|
|
(defun smie-indent-after-keyword ()
|
|
|
|
;; Indentation right after a special keyword.
|
|
|
|
(save-excursion
|
|
|
|
(let* ((pos (point))
|
|
|
|
(toklevel (smie-indent-backward-token))
|
|
|
|
(tok (car toklevel)))
|
|
|
|
(cond
|
|
|
|
((null toklevel) nil)
|
|
|
|
((smie-indent--rule :after tok pos nil (point)))
|
|
|
|
;; The default indentation after a keyword/operator is
|
|
|
|
;; 0 for infix, t for prefix, and use another rule
|
|
|
|
;; for postfix.
|
2010-11-17 14:59:16 -05:00
|
|
|
((not (numberp (nth 2 toklevel))) nil) ;A closer.
|
|
|
|
((or (not (numberp (nth 1 toklevel))) ;An opener.
|
|
|
|
(rassoc tok smie-closer-alist)) ;An inner.
|
2010-11-07 10:52:33 -05:00
|
|
|
(+ (smie-indent-virtual) (smie-indent--offset 'basic))) ;
|
2010-11-17 14:59:16 -05:00
|
|
|
(t (smie-indent-virtual)))))) ;An infix.
|
2010-11-07 10:52:33 -05:00
|
|
|
|
2015-09-22 11:11:50 -04:00
|
|
|
(defun smie-indent-empty-line ()
|
|
|
|
"Indentation rule when there's nothing yet on the line."
|
|
|
|
;; Without this rule, SMIE assumes that an empty line will be filled with an
|
|
|
|
;; argument (since it falls back to smie-indent-sexps), which tends
|
|
|
|
;; to indent far too deeply.
|
|
|
|
(when (eolp)
|
|
|
|
(let ((token (or (funcall smie-rules-function :elem 'empty-line-token)
|
|
|
|
;; FIXME: Should we default to ";"?
|
|
|
|
;; ";"
|
|
|
|
)))
|
|
|
|
(when (assoc token smie-grammar)
|
|
|
|
(smie-indent-keyword token)))))
|
|
|
|
|
2010-11-07 10:52:33 -05:00
|
|
|
(defun smie-indent-exps ()
|
|
|
|
;; Indentation of sequences of simple expressions without
|
|
|
|
;; intervening keywords or operators. E.g. "a b c" or "g (balbla) f".
|
|
|
|
;; Can be a list of expressions or a function call.
|
|
|
|
;; If it's a function call, the first element is special (it's the
|
|
|
|
;; function). We distinguish function calls from mere lists of
|
|
|
|
;; expressions based on whether the preceding token is listed in
|
|
|
|
;; the `list-intro' entry of smie-indent-rules.
|
|
|
|
;;
|
|
|
|
;; TODO: to indent Lisp code, we should add a way to specify
|
|
|
|
;; particular indentation for particular args depending on the
|
|
|
|
;; function (which would require always skipping back until the
|
|
|
|
;; function).
|
|
|
|
;; TODO: to indent C code, such as "if (...) {...}" we might need
|
|
|
|
;; to add similar indentation hooks for particular positions, but
|
|
|
|
;; based on the preceding token rather than based on the first exp.
|
|
|
|
(save-excursion
|
|
|
|
(let ((positions nil)
|
|
|
|
arg)
|
|
|
|
(while (and (null (car (smie-backward-sexp)))
|
|
|
|
(push (point) positions)
|
|
|
|
(not (smie-indent--bolp))))
|
|
|
|
(save-excursion
|
|
|
|
;; Figure out if the atom we just skipped is an argument rather
|
|
|
|
;; than a function.
|
|
|
|
(setq arg
|
|
|
|
(or (null (car (smie-backward-sexp)))
|
|
|
|
(funcall smie-rules-function :list-intro
|
|
|
|
(funcall smie-backward-token-function)))))
|
|
|
|
(cond
|
|
|
|
((null positions)
|
|
|
|
;; We're the first expression of the list. In that case, the
|
|
|
|
;; indentation should be (have been) determined by its context.
|
|
|
|
nil)
|
|
|
|
(arg
|
|
|
|
;; There's a previous element, and it's not special (it's not
|
|
|
|
;; the function), so let's just align with that one.
|
|
|
|
(goto-char (car positions))
|
2015-08-21 14:13:05 -04:00
|
|
|
(smie-indent--current-column))
|
2010-11-07 10:52:33 -05:00
|
|
|
((cdr positions)
|
|
|
|
;; We skipped some args plus the function and bumped into something.
|
|
|
|
;; Align with the first arg.
|
|
|
|
(goto-char (cadr positions))
|
2015-08-21 14:13:05 -04:00
|
|
|
(smie-indent--current-column))
|
2010-11-07 10:52:33 -05:00
|
|
|
(positions
|
|
|
|
;; We're the first arg.
|
|
|
|
(goto-char (car positions))
|
|
|
|
(+ (smie-indent--offset 'args)
|
|
|
|
;; We used to use (smie-indent-virtual), but that
|
|
|
|
;; doesn't seem right since it might then indent args less than
|
|
|
|
;; the function itself.
|
2015-08-21 14:13:05 -04:00
|
|
|
(smie-indent--current-column)))))))
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
(defvar smie-indent-functions
|
|
|
|
'(smie-indent-fixindent smie-indent-bob smie-indent-close
|
2011-02-10 14:40:17 -05:00
|
|
|
smie-indent-comment smie-indent-comment-continue smie-indent-comment-close
|
|
|
|
smie-indent-comment-inside smie-indent-inside-string
|
|
|
|
smie-indent-keyword smie-indent-after-keyword
|
2015-09-22 11:11:50 -04:00
|
|
|
smie-indent-empty-line smie-indent-exps)
|
2010-11-07 10:52:33 -05:00
|
|
|
"Functions to compute the indentation.
|
|
|
|
Each function is called with no argument, shouldn't move point, and should
|
|
|
|
return either nil if it has no opinion, or an integer representing the column
|
|
|
|
to which that point should be aligned, if we were to reindent it.")
|
|
|
|
|
|
|
|
(defun smie-indent-calculate ()
|
|
|
|
"Compute the indentation to use for point."
|
|
|
|
(run-hook-with-args-until-success 'smie-indent-functions))
|
|
|
|
|
|
|
|
(defun smie-indent-line ()
|
|
|
|
"Indent current line using the SMIE indentation engine."
|
|
|
|
(interactive)
|
|
|
|
(let* ((savep (point))
|
|
|
|
(indent (or (with-demoted-errors
|
|
|
|
(save-excursion
|
|
|
|
(forward-line 0)
|
|
|
|
(skip-chars-forward " \t")
|
|
|
|
(if (>= (point) savep) (setq savep nil))
|
|
|
|
(or (smie-indent-calculate) 0)))
|
|
|
|
0)))
|
|
|
|
(if (not (numberp indent))
|
|
|
|
;; If something funny is used (e.g. `noindent'), return it.
|
|
|
|
indent
|
|
|
|
(if (< indent 0) (setq indent 0)) ;Just in case.
|
|
|
|
(if savep
|
|
|
|
(save-excursion (indent-line-to indent))
|
|
|
|
(indent-line-to indent)))))
|
|
|
|
|
2013-05-24 15:37:55 -04:00
|
|
|
(defun smie-auto-fill (do-auto-fill)
|
lisp/*: Add declarations, remove unused bindings, mark unused args.
* lisp/avoid.el (mouse-avoidance-mode): Mark unused arg.
(mouse-avoidance-nudge-mouse): Remove unused binding.
* lisp/imenu.el (imenu-default-goto-function): Mark unused args.
(imenu-progress-message): Remove obsolete macro; all callers changed.
* lisp/mouse.el (mouse-menu-major-mode-map):
* lisp/emacs-lisp/authors.el (authors-scan-change-log)
(authors-add-to-author-list):
* lisp/emacs-lisp/avl-tree.el (avl-tree--enter-balance):
* lisp/emacs-lisp/smie.el (smie-auto-fill):
* lisp/mail/sendmail.el (mail-bury):
* lisp/mail/unrmail.el (unrmail):
* lisp/net/tls.el (open-tls-stream):
* lisp/textmodes/picture.el (picture-mouse-set-point):
Remove unused bindings.
* lisp/subr.el (keymap-canonicalize): Remove unused binding.
(read-passwd): Mark unused arg.
* lisp/tutorial.el (tutorial--display-changes): Remove unused binding.
(tutorial--save-tutorial-to): Remove unused variable.
* lisp/emacs-lisp/package.el (define-package, package-menu-mark-delete)
(package-menu-mark-install, package-menu-mark-unmark): Mark unused args.
(package-generate-autoloads, package-menu--generate)
(package-menu--find-upgrades): Remove unused bindings.
* lisp/emulation/cua-rect.el (cua-restrict-regexp-rectangle)
(cua-restrict-prefix-rectangle): Doc fixes. Remove unused bindings.
(cua--mouse-ignore, cua--delete-rectangle, cua--extract-rectangle)
(cua--indent-rectangle, cua-open-rectangle, cua-close-rectangle)
(cua-blank-rectangle, cua-string-rectangle, cua-replace-in-rectangle)
(cua-incr-rectangle, cua-sequence-rectangle, cua--convert-rectangle-as)
(cua--rectangle-aux-replace, cua--left-fill-rectangle)
(cua-scroll-rectangle-up, cua-scroll-rectangle-down)
(cua-delete-char-rectangle): Mark unused args.
(cua-align-rectangle): Remove unused binding.
* lisp/mail/rmail.el (compilation--message->loc)
(epa--find-coding-system-for-mime-charset): Declare.
* lisp/net/dbus.el (dbus-register-service): Declare.
(dbus-name-owner-changed-handler): Remove unused binding.
* lisp/nxml/nxml-mode.el (nxml-electric-slash, nxml-in-mixed-content-p)
(nxml-compute-indent-from-matching-start-tag): Remove unused variables.
(nxml-scan-backward-within): Mark unused arg.
(nxml-dynamic-markup-word): Remove unused binding.
2012-04-19 19:20:26 +02:00
|
|
|
(let ((fc (current-fill-column)))
|
2013-05-24 15:37:55 -04:00
|
|
|
(when (and fc (> (current-column) fc))
|
|
|
|
;; The loop below presumes BOL is outside of strings or comments. Also,
|
|
|
|
;; sometimes we prefer to fill the comment than the code around it.
|
|
|
|
(unless (or (nth 8 (save-excursion
|
|
|
|
(syntax-ppss (line-beginning-position))))
|
|
|
|
(nth 4 (save-excursion
|
|
|
|
(move-to-column fc)
|
|
|
|
(syntax-ppss))))
|
|
|
|
(while
|
|
|
|
(and (with-demoted-errors
|
|
|
|
(save-excursion
|
|
|
|
(let ((end (point))
|
|
|
|
(bsf nil) ;Best-so-far.
|
|
|
|
(gain 0))
|
|
|
|
(beginning-of-line)
|
|
|
|
(while (progn
|
2013-03-14 10:48:03 -04:00
|
|
|
(smie-indent-forward-token)
|
2013-05-24 15:37:55 -04:00
|
|
|
(and (<= (point) end)
|
|
|
|
(<= (current-column) fc)))
|
|
|
|
;; FIXME? `smie-indent-calculate' can (and often
|
|
|
|
;; does) return a result that actually depends on the
|
|
|
|
;; presence/absence of a newline, so the gain computed
|
|
|
|
;; here may not be accurate, but in practice it seems
|
|
|
|
;; to work well enough.
|
|
|
|
(skip-chars-forward " \t")
|
|
|
|
(let* ((newcol (smie-indent-calculate))
|
|
|
|
(newgain (- (current-column) newcol)))
|
|
|
|
(when (> newgain gain)
|
|
|
|
(setq gain newgain)
|
|
|
|
(setq bsf (point)))))
|
|
|
|
(when (> gain 0)
|
|
|
|
(goto-char bsf)
|
|
|
|
(newline-and-indent)
|
|
|
|
'done))))
|
|
|
|
(> (current-column) fc))))
|
|
|
|
(when (> (current-column) fc)
|
|
|
|
(funcall do-auto-fill)))))
|
2012-02-15 09:38:21 -05:00
|
|
|
|
|
|
|
|
2010-11-07 10:52:33 -05:00
|
|
|
(defun smie-setup (grammar rules-function &rest keywords)
|
|
|
|
"Setup SMIE navigation and indentation.
|
|
|
|
GRAMMAR is a grammar table generated by `smie-prec2->grammar'.
|
|
|
|
RULES-FUNCTION is a set of indentation rules for use on `smie-rules-function'.
|
|
|
|
KEYWORDS are additional arguments, which can use the following keywords:
|
|
|
|
- :forward-token FUN
|
|
|
|
- :backward-token FUN"
|
2013-05-24 15:37:55 -04:00
|
|
|
(setq-local smie-rules-function rules-function)
|
|
|
|
(setq-local smie-grammar grammar)
|
|
|
|
(setq-local indent-line-function #'smie-indent-line)
|
|
|
|
(add-function :around (local 'normal-auto-fill-function) #'smie-auto-fill)
|
|
|
|
(setq-local forward-sexp-function #'smie-forward-sexp-command)
|
2010-11-07 10:52:33 -05:00
|
|
|
(while keywords
|
|
|
|
(let ((k (pop keywords))
|
|
|
|
(v (pop keywords)))
|
2012-06-10 09:28:26 -04:00
|
|
|
(pcase k
|
2018-10-27 01:48:35 +02:00
|
|
|
(:forward-token
|
2010-11-07 10:52:33 -05:00
|
|
|
(set (make-local-variable 'smie-forward-token-function) v))
|
2018-10-27 01:48:35 +02:00
|
|
|
(:backward-token
|
2010-11-07 10:52:33 -05:00
|
|
|
(set (make-local-variable 'smie-backward-token-function) v))
|
2012-06-10 09:28:26 -04:00
|
|
|
(_ (message "smie-setup: ignoring unknown keyword %s" k)))))
|
2010-11-07 10:52:33 -05:00
|
|
|
(let ((ca (cdr (assq :smie-closer-alist grammar))))
|
|
|
|
(when ca
|
2013-05-24 15:37:55 -04:00
|
|
|
(setq-local smie-closer-alist ca)
|
2010-11-07 10:52:33 -05:00
|
|
|
;; Only needed for interactive calls to blink-matching-open.
|
2013-05-24 15:37:55 -04:00
|
|
|
(setq-local blink-matching-check-function #'smie-blink-matching-check)
|
2013-06-05 15:40:02 +08:00
|
|
|
(add-hook 'post-self-insert-hook
|
|
|
|
#'smie-blink-matching-open 'append 'local)
|
|
|
|
(add-function :around (local 'show-paren-data-function)
|
|
|
|
#'smie--matching-block-data)
|
2013-05-24 15:37:55 -04:00
|
|
|
;; Setup smie-blink-matching-triggers. Rather than wait for SPC to
|
|
|
|
;; blink, try to blink as soon as we type the last char of a block ender.
|
|
|
|
(let ((closers (sort (mapcar #'cdr smie-closer-alist) #'string-lessp))
|
|
|
|
(triggers ())
|
|
|
|
closer)
|
|
|
|
(while (setq closer (pop closers))
|
|
|
|
(unless
|
|
|
|
;; FIXME: this eliminates prefixes of other closers, but we
|
|
|
|
;; should probably eliminate prefixes of other keywords as well.
|
|
|
|
(and closers (string-prefix-p closer (car closers)))
|
|
|
|
(push (aref closer (1- (length closer))) triggers)))
|
|
|
|
(setq-local smie-blink-matching-triggers
|
|
|
|
(append smie-blink-matching-triggers
|
|
|
|
(delete-dups triggers)))))))
|
2010-11-07 10:52:33 -05:00
|
|
|
|
2014-06-13 11:31:17 -04:00
|
|
|
(declare-function edebug-instrument-function "edebug" (func))
|
|
|
|
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
(defun smie-edebug ()
|
|
|
|
"Instrument the `smie-rules-function' for Edebug."
|
|
|
|
(interactive)
|
|
|
|
(require 'edebug)
|
|
|
|
(if (symbolp smie-rules-function)
|
|
|
|
(edebug-instrument-function smie-rules-function)
|
|
|
|
(error "Sorry, don't know how to instrument a lambda expression")))
|
|
|
|
|
2013-11-03 17:56:03 -05:00
|
|
|
(defun smie--next-indent-change ()
|
|
|
|
"Go to the next line that needs to be reindented (and reindent it)."
|
|
|
|
(interactive)
|
|
|
|
(while
|
2013-11-04 15:45:36 -05:00
|
|
|
(let ((tick (buffer-chars-modified-tick)))
|
2013-11-03 17:56:03 -05:00
|
|
|
(indent-according-to-mode)
|
2013-11-04 15:45:36 -05:00
|
|
|
(eq tick (buffer-chars-modified-tick)))
|
2013-11-03 17:56:03 -05:00
|
|
|
(forward-line 1)))
|
|
|
|
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
;;; User configuration
|
|
|
|
|
|
|
|
;; This is designed to be a completely independent "module", so we can play
|
|
|
|
;; with various kinds of smie-config modules without having to change the core.
|
|
|
|
|
|
|
|
;; This smie-config module is fairly primitive and suffers from serious
|
|
|
|
;; restrictions:
|
|
|
|
;; - You can only change a returned offset, so you can't change the offset
|
|
|
|
;; passed to smie-rule-parent, nor can you change the object with which
|
|
|
|
;; to align (in general).
|
|
|
|
;; - The rewrite rule can only distinguish cases based on the kind+token arg
|
|
|
|
;; and smie-rules-function's return value, so you can't distinguish cases
|
|
|
|
;; where smie-rules-function returns the same value.
|
|
|
|
;; - Since config-rules depend on the return value of smie-rules-function, any
|
|
|
|
;; config change that modifies this return value (e.g. changing
|
|
|
|
;; foo-indent-basic) ends up invalidating config-rules.
|
|
|
|
;; This last one is a serious problem since it means that file-local
|
|
|
|
;; config-rules will only work if the user hasn't changed foo-indent-basic.
|
|
|
|
;; One possible way to change it is to modify smie-rules-functions so they can
|
|
|
|
;; return special symbols like +, ++, -, etc. Or make them use a new
|
|
|
|
;; smie-rule-basic function which can then be used to know when a returned
|
|
|
|
;; offset was computed based on foo-indent-basic.
|
|
|
|
|
|
|
|
(defvar-local smie-config--mode-local nil
|
|
|
|
"Indentation config rules installed for this major mode.
|
|
|
|
Typically manipulated from the major-mode's hook.")
|
|
|
|
(defvar-local smie-config--buffer-local nil
|
|
|
|
"Indentation config rules installed for this very buffer.
|
|
|
|
E.g. provided via a file-local call to `smie-config-local'.")
|
|
|
|
(defvar smie-config--trace nil
|
|
|
|
"Variable used to trace calls to `smie-rules-function'.")
|
|
|
|
|
|
|
|
(defun smie-config--advice (orig kind token)
|
|
|
|
(let* ((ret (funcall orig kind token))
|
|
|
|
(sig (list kind token ret))
|
|
|
|
(brule (rassoc sig smie-config--buffer-local))
|
|
|
|
(mrule (rassoc sig smie-config--mode-local)))
|
|
|
|
(when smie-config--trace
|
|
|
|
(setq smie-config--trace (or brule mrule)))
|
|
|
|
(cond
|
|
|
|
(brule (car brule))
|
|
|
|
(mrule (car mrule))
|
|
|
|
(t ret))))
|
|
|
|
|
|
|
|
(defun smie-config--mode-hook (rules)
|
|
|
|
(setq smie-config--mode-local
|
|
|
|
(append rules smie-config--mode-local))
|
|
|
|
(add-function :around (local 'smie-rules-function) #'smie-config--advice))
|
|
|
|
|
|
|
|
(defvar smie-config--modefuns nil)
|
|
|
|
|
|
|
|
(defun smie-config--setter (var value)
|
2017-08-30 19:31:48 -04:00
|
|
|
(set-default var value)
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
(let ((old-modefuns smie-config--modefuns))
|
|
|
|
(setq smie-config--modefuns nil)
|
|
|
|
(pcase-dolist (`(,mode . ,rules) value)
|
|
|
|
(let ((modefunname (intern (format "smie-config--modefun-%s" mode))))
|
|
|
|
(fset modefunname (lambda () (smie-config--mode-hook rules)))
|
|
|
|
(push modefunname smie-config--modefuns)
|
|
|
|
(add-hook (intern (format "%s-hook" mode)) modefunname)))
|
|
|
|
;; Neuter any left-over previously installed hook.
|
|
|
|
(dolist (modefun old-modefuns)
|
|
|
|
(unless (memq modefun smie-config--modefuns)
|
|
|
|
(fset modefun #'ignore)))))
|
|
|
|
|
|
|
|
(defcustom smie-config nil
|
|
|
|
;; FIXME: there should be a file-local equivalent.
|
|
|
|
"User configuration of SMIE indentation.
|
|
|
|
This is a list of elements (MODE . RULES), where RULES is a list
|
|
|
|
of elements describing when and how to change the indentation rules.
|
|
|
|
Each RULE element should be of the form (NEW KIND TOKEN NORMAL),
|
|
|
|
where KIND and TOKEN are the elements passed to `smie-rules-function',
|
|
|
|
NORMAL is the value returned by `smie-rules-function' and NEW is the
|
|
|
|
value with which to replace it."
|
2013-12-27 18:16:05 -08:00
|
|
|
:version "24.4"
|
|
|
|
;; FIXME improve value-type.
|
|
|
|
:type '(choice (const nil)
|
|
|
|
(alist :key-type symbol))
|
2017-08-30 19:31:48 -04:00
|
|
|
:initialize 'custom-initialize-set
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
:set #'smie-config--setter)
|
|
|
|
|
|
|
|
(defun smie-config-local (rules)
|
|
|
|
"Add RULES as local indentation rules to use in this buffer.
|
|
|
|
These replace any previous local rules, but supplement the rules
|
|
|
|
specified in `smie-config'."
|
|
|
|
(setq smie-config--buffer-local rules)
|
|
|
|
(add-function :around (local 'smie-rules-function) #'smie-config--advice))
|
|
|
|
|
|
|
|
;; Make it so we can set those in the file-local block.
|
|
|
|
;; FIXME: Better would be to be able to write "smie-config-local: (...)" rather
|
|
|
|
;; than "eval: (smie-config-local '(...))".
|
|
|
|
(put 'smie-config-local 'safe-local-eval-function t)
|
|
|
|
|
|
|
|
(defun smie-config--get-trace ()
|
|
|
|
(save-excursion
|
|
|
|
(forward-line 0)
|
|
|
|
(skip-chars-forward " \t")
|
|
|
|
(let* ((trace ())
|
|
|
|
(srf-fun (lambda (orig kind token)
|
|
|
|
(let* ((pos (point))
|
|
|
|
(smie-config--trace t)
|
|
|
|
(res (funcall orig kind token)))
|
|
|
|
(push (if (consp smie-config--trace)
|
|
|
|
(list pos kind token res smie-config--trace)
|
|
|
|
(list pos kind token res))
|
|
|
|
trace)
|
|
|
|
res))))
|
|
|
|
(unwind-protect
|
|
|
|
(progn
|
|
|
|
(add-function :around (local 'smie-rules-function) srf-fun)
|
|
|
|
(cons (smie-indent-calculate)
|
|
|
|
trace))
|
|
|
|
(remove-function (local 'smie-rules-function) srf-fun)))))
|
|
|
|
|
|
|
|
(defun smie-config-show-indent (&optional arg)
|
|
|
|
"Display the SMIE rules that are used to indent the current line.
|
|
|
|
If prefix ARG is given, then move briefly point to the buffer
|
|
|
|
position corresponding to each rule."
|
|
|
|
(interactive "P")
|
|
|
|
(let ((trace (cdr (smie-config--get-trace))))
|
|
|
|
(cond
|
|
|
|
((null trace) (message "No SMIE rules involved"))
|
|
|
|
((not arg)
|
|
|
|
(message "Rules used: %s"
|
|
|
|
(mapconcat (lambda (elem)
|
|
|
|
(pcase-let ((`(,_pos ,kind ,token ,res ,rewrite)
|
|
|
|
elem))
|
|
|
|
(format "%S %S -> %S%s" kind token res
|
|
|
|
(if (null rewrite) ""
|
|
|
|
(format "(via %S)" (nth 3 rewrite))))))
|
|
|
|
trace
|
|
|
|
", ")))
|
|
|
|
(t
|
|
|
|
(save-excursion
|
|
|
|
(pcase-dolist (`(,pos ,kind ,token ,res ,rewrite) trace)
|
|
|
|
(message "%S %S -> %S%s" kind token res
|
|
|
|
(if (null rewrite) ""
|
|
|
|
(format "(via %S)" (nth 3 rewrite))))
|
|
|
|
(goto-char pos)
|
|
|
|
(sit-for blink-matching-delay)))))))
|
|
|
|
|
|
|
|
(defun smie-config--guess-value (sig)
|
|
|
|
(add-function :around (local 'smie-rules-function) #'smie-config--advice)
|
|
|
|
(let* ((rule (cons 0 sig))
|
|
|
|
(smie-config--buffer-local (cons rule smie-config--buffer-local))
|
|
|
|
(goal (current-indentation))
|
|
|
|
(cur (smie-indent-calculate)))
|
|
|
|
(cond
|
|
|
|
((and (eq goal
|
|
|
|
(progn (setf (car rule) (- goal cur))
|
|
|
|
(smie-indent-calculate))))
|
|
|
|
(- goal cur)))))
|
|
|
|
|
|
|
|
(defun smie-config-set-indent ()
|
|
|
|
"Add a rule to adjust the indentation of current line."
|
|
|
|
(interactive)
|
|
|
|
(let* ((trace (cdr (smie-config--get-trace)))
|
|
|
|
(_ (unless trace (error "No SMIE rules involved")))
|
|
|
|
(sig (if (null (cdr trace))
|
|
|
|
(pcase-let* ((elem (car trace))
|
|
|
|
(`(,_pos ,kind ,token ,res ,rewrite) elem))
|
|
|
|
(list kind token (or (nth 3 rewrite) res)))
|
|
|
|
(let* ((choicestr
|
|
|
|
(completing-read
|
|
|
|
"Adjust rule: "
|
|
|
|
(mapcar (lambda (elem)
|
|
|
|
(format "%s %S"
|
|
|
|
(substring (symbol-name (cadr elem))
|
|
|
|
1)
|
|
|
|
(nth 2 elem)))
|
|
|
|
trace)
|
|
|
|
nil t nil nil
|
|
|
|
nil)) ;FIXME: Provide good default!
|
|
|
|
(choicelst (car (read-from-string
|
|
|
|
(concat "(:" choicestr ")")))))
|
|
|
|
(catch 'found
|
|
|
|
(pcase-dolist (`(,_pos ,kind ,token ,res ,rewrite) trace)
|
|
|
|
(when (and (eq kind (car choicelst))
|
|
|
|
(equal token (nth 1 choicelst)))
|
|
|
|
(throw 'found (list kind token
|
|
|
|
(or (nth 3 rewrite) res)))))))))
|
|
|
|
(default-new (smie-config--guess-value sig))
|
Use `format-prompt' when prompting with default values
* lisp/woman.el (woman-file-name):
* lisp/wid-edit.el (widget-file-prompt-value)
(widget-coding-system-prompt-value):
* lisp/w32-fns.el (w32-set-system-coding-system):
* lisp/vc/vc.el (vc-print-root-log):
* lisp/vc/vc-annotate.el (vc-annotate):
* lisp/vc/emerge.el (emerge-read-file-name):
* lisp/vc/ediff.el (ediff-directories)
(ediff-directory-revisions, ediff-directories3)
(ediff-merge-directories, )
(ediff-merge-directories-with-ancestor)
(ediff-merge-directory-revisions)
(ediff-merge-directory-revisions-with-ancestor)
(ediff-merge-revisions, ediff-merge-revisions-with-ancestor)
(ediff-revision):
* lisp/vc/ediff-util.el (ediff-toggle-regexp-match):
* lisp/vc/ediff-mult.el (ediff-filegroup-action):
* lisp/vc/add-log.el (prompt-for-change-log-name):
* lisp/textmodes/table.el (table-insert-row-column)
(table-span-cell, table-split-cell-horizontally)
(table-split-cell, table-justify, table-generate-source)
(table-insert-sequence, table-capture)
(table--read-from-minibuffer, table--query-justification):
* lisp/textmodes/sgml-mode.el (sgml-tag, sgml-tag-help):
* lisp/textmodes/reftex-ref.el (reftex-goto-label):
* lisp/textmodes/refer.el (refer-get-bib-files):
* lisp/textmodes/css-mode.el (css-lookup-symbol):
* lisp/term.el (serial-read-name, serial-read-speed):
* lisp/speedbar.el (speedbar-change-initial-expansion-list):
* lisp/simple.el (previous-matching-history-element)
(set-variable):
* lisp/ses.el (ses-read-cell, ses-set-column-width):
* lisp/replace.el (query-replace-read-from)
(occur-read-primary-args):
* lisp/rect.el (string-rectangle, string-insert-rectangle):
* lisp/progmodes/tcl.el (tcl-help-on-word):
* lisp/progmodes/sh-script.el (sh-set-shell):
* lisp/progmodes/python.el (python-eldoc-at-point):
* lisp/progmodes/octave.el (octave-completing-read)
(octave-update-function-file-comment, octave-insert-defun):
* lisp/progmodes/inf-lisp.el (lisp-symprompt):
* lisp/progmodes/cperl-mode.el (cperl-info-on-command)
(cperl-perldoc):
* lisp/progmodes/compile.el (compilation-find-file):
* lisp/net/rcirc.el (rcirc-prompt-for-encryption):
* lisp/net/eww.el (eww):
* lisp/net/browse-url.el (browse-url-with-browser-kind):
* lisp/man.el (man):
* lisp/mail/sendmail.el (sendmail-query-user-about-smtp):
* lisp/mail/mailalias.el (build-mail-aliases):
* lisp/mail/mailabbrev.el (merge-mail-abbrevs)
(rebuild-mail-abbrevs):
* lisp/locate.el (locate-prompt-for-search-string):
* lisp/isearch.el (isearch-occur):
* lisp/international/ogonek.el (ogonek-read-encoding)
(ogonek-read-prefix):
* lisp/international/mule.el (read-buffer-file-coding-system)
(set-terminal-coding-system, set-keyboard-coding-system)
(set-next-selection-coding-system, recode-region):
* lisp/international/mule-cmds.el ()
(universal-coding-system-argument, search-unencodable-char)
(select-safe-coding-system-interactively):
* lisp/info.el (Info-search, Info-search-backward, Info-menu):
* lisp/info-look.el (info-lookup-interactive-arguments):
* lisp/imenu.el (imenu--completion-buffer):
* lisp/ibuf-ext.el (mode, used-mode, ibuffer-mark-by-mode):
* lisp/hi-lock.el (hi-lock-unface-buffer)
(hi-lock-read-face-name):
* lisp/help.el (view-emacs-news, where-is):
* lisp/help-fns.el (describe-variable, describe-symbol)
(describe-keymap):
* lisp/gnus/mm-decode.el (mm-save-part):
* lisp/gnus/gnus-sum.el (gnus-summary-browse-url):
* lisp/gnus/gnus-group.el (gnus-group--read-bug-ids)
(gnus-group-set-current-level):
* lisp/frame.el (make-frame-on-monitor)
(close-display-connection, select-frame-by-name):
* lisp/format.el (format-encode-buffer, format-encode-region):
* lisp/files.el (recode-file-name):
* lisp/files-x.el (read-file-local-variable)
(read-file-local-variable-value, )
(read-file-local-variable-mode):
* lisp/ffap.el (ffap-menu-ask):
* lisp/faces.el (face-read-string):
* lisp/facemenu.el (facemenu-set-charset):
* lisp/erc/erc-dcc.el (erc-dcc-do-GET-command):
* lisp/emulation/edt-mapper.el (edt-mapper):
* lisp/emacs-lisp/trace.el (trace--read-args)
(trace-function-foreground, trace-function-background):
* lisp/emacs-lisp/smie.el (smie-config-set-indent):
* lisp/emacs-lisp/re-builder.el (reb-change-syntax):
* lisp/emacs-lisp/package.el (describe-package):
* lisp/emacs-lisp/find-func.el (read-library-name)
(find-function-read):
* lisp/emacs-lisp/ert.el (ert-read-test-name)
(ert-run-tests-interactively):
* lisp/emacs-lisp/disass.el (disassemble):
* lisp/emacs-lisp/debug.el (debug-on-entry)
(debug-on-variable-change):
* lisp/emacs-lisp/advice.el (ad-read-advised-function)
(ad-read-advice-class, ad-read-advice-name, ad-read-regexp):
* lisp/dired-x.el (dired--mark-suffix-interactive-spec):
* lisp/dired-aux.el (dired-diff):
* lisp/cus-edit.el (custom-variable-prompt, customize-mode)
(customize-changed-options):
* lisp/completion.el (interactive-completion-string-reader):
* lisp/calendar/timeclock.el (timeclock-ask-for-project):
* lisp/calc/calcalg3.el (calc-get-fit-variables):
* lisp/calc/calc-store.el (calc-edit-variable):
* lisp/calc/calc-bin.el (calc-word-size):
* lisp/bookmark.el (bookmark-set-internal):
* lisp/abbrev.el (read-abbrev-file): Use `format-prompt' for
prompting (bug#12443).
2020-09-06 16:56:44 +02:00
|
|
|
(newstr (read-string (format-prompt
|
|
|
|
"Adjust rule (%S %S -> %S) to" default-new
|
|
|
|
(nth 0 sig) (nth 1 sig) (nth 2 sig))
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
nil nil (format "%S" default-new)))
|
|
|
|
(new (car (read-from-string newstr))))
|
|
|
|
(let ((old (rassoc sig smie-config--buffer-local)))
|
|
|
|
(when old
|
|
|
|
(setq smie-config--buffer-local
|
|
|
|
(remove old smie-config--buffer-local))))
|
|
|
|
(push (cons new sig) smie-config--buffer-local)
|
|
|
|
(message "Added rule %S %S -> %S (via %S)"
|
|
|
|
(nth 0 sig) (nth 1 sig) new (nth 2 sig))
|
|
|
|
(add-function :around (local 'smie-rules-function) #'smie-config--advice)))
|
|
|
|
|
|
|
|
(defun smie-config--guess (beg end)
|
|
|
|
(let ((otraces (make-hash-table :test #'equal))
|
|
|
|
(smie-config--buffer-local nil)
|
|
|
|
(smie-config--mode-local nil)
|
|
|
|
(pr (make-progress-reporter "Analyzing the buffer" beg end)))
|
|
|
|
|
|
|
|
;; First, lets get the indentation traces and offsets for the region.
|
|
|
|
(save-excursion
|
|
|
|
(goto-char beg)
|
|
|
|
(forward-line 0)
|
|
|
|
(while (< (point) end)
|
|
|
|
(skip-chars-forward " \t")
|
|
|
|
(unless (eolp) ;Skip empty lines.
|
|
|
|
(progress-reporter-update pr (point))
|
|
|
|
(let* ((itrace (smie-config--get-trace))
|
|
|
|
(nindent (car itrace))
|
|
|
|
(trace (mapcar #'cdr (cdr itrace)))
|
|
|
|
(cur (current-indentation)))
|
|
|
|
(when (numberp nindent) ;Skip `noindent' and friends.
|
|
|
|
(cl-incf (gethash (cons (- cur nindent) trace) otraces 0)))))
|
|
|
|
(forward-line 1)))
|
|
|
|
(progress-reporter-done pr)
|
|
|
|
|
|
|
|
;; Second, compile the data. Our algorithm only knows how to adjust rules
|
|
|
|
;; where the smie-rules-function returns an integer. We call those
|
|
|
|
;; "adjustable sigs". We build a table mapping each adjustable sig
|
|
|
|
;; to its data, describing the total number of times we encountered it,
|
|
|
|
;; the offsets found, and the traces in which it was found.
|
|
|
|
(message "Guessing...")
|
|
|
|
(let ((sigs (make-hash-table :test #'equal)))
|
|
|
|
(maphash (lambda (otrace count)
|
|
|
|
(let ((offset (car otrace))
|
|
|
|
(trace (cdr otrace))
|
|
|
|
(double nil))
|
|
|
|
(let ((sigs trace))
|
|
|
|
(while sigs
|
|
|
|
(let ((sig (pop sigs)))
|
|
|
|
(if (and (integerp (nth 2 sig)) (member sig sigs))
|
|
|
|
(setq double t)))))
|
|
|
|
(if double
|
|
|
|
;; Disregard those traces where an adjustable sig
|
|
|
|
;; appears twice, because the rest of the code assumes
|
|
|
|
;; that adding a rule to add an offset N will change the
|
|
|
|
;; end result by N rather than 2*N or more.
|
|
|
|
nil
|
|
|
|
(dolist (sig trace)
|
|
|
|
(if (not (integerp (nth 2 sig)))
|
|
|
|
;; Disregard those sigs that return nil or a column,
|
|
|
|
;; because our algorithm doesn't know how to adjust
|
|
|
|
;; them anyway.
|
|
|
|
nil
|
|
|
|
(let ((sig-data (or (gethash sig sigs)
|
|
|
|
(let ((data (list 0 nil nil)))
|
|
|
|
(puthash sig data sigs)
|
|
|
|
data))))
|
|
|
|
(cl-incf (nth 0 sig-data) count)
|
|
|
|
(push (cons count otrace) (nth 2 sig-data))
|
|
|
|
(let ((sig-off-data
|
|
|
|
(or (assq offset (nth 1 sig-data))
|
|
|
|
(let ((off-data (cons offset 0)))
|
|
|
|
(push off-data (nth 1 sig-data))
|
|
|
|
off-data))))
|
|
|
|
(cl-incf (cdr sig-off-data) count))))))))
|
|
|
|
otraces)
|
|
|
|
|
|
|
|
;; Finally, guess the indentation rules.
|
2014-07-20 21:58:43 -04:00
|
|
|
(prog1
|
|
|
|
(smie-config--guess-1 sigs)
|
|
|
|
(message "Guessing...done")))))
|
|
|
|
|
|
|
|
(defun smie-config--guess-1 (sigs)
|
|
|
|
(let ((ssigs nil)
|
|
|
|
(rules nil))
|
|
|
|
;; Sort the sigs by frequency of occurrence.
|
|
|
|
(maphash (lambda (sig sig-data) (push (cons sig sig-data) ssigs)) sigs)
|
|
|
|
(setq ssigs (sort ssigs (lambda (sd1 sd2) (> (cadr sd1) (cadr sd2)))))
|
|
|
|
(while ssigs
|
|
|
|
(pcase-let ((`(,sig ,total ,off-alist ,cotraces) (pop ssigs)))
|
|
|
|
(cl-assert (= total (apply #'+ (mapcar #'cdr off-alist))))
|
|
|
|
(let* ((sorted-off-alist
|
|
|
|
(sort off-alist (lambda (x y) (> (cdr x) (cdr y)))))
|
|
|
|
(offset (caar sorted-off-alist)))
|
|
|
|
(if (zerop offset)
|
|
|
|
;; Nothing to do with this sig; indentation is
|
|
|
|
;; correct already.
|
|
|
|
nil
|
|
|
|
(push (cons (+ offset (nth 2 sig)) sig) rules)
|
|
|
|
;; Adjust the rest of the data.
|
|
|
|
(pcase-dolist ((and cotrace `(,count ,toffset . ,trace))
|
|
|
|
cotraces)
|
|
|
|
(setf (nth 1 cotrace) (- toffset offset))
|
|
|
|
(dolist (sig trace)
|
|
|
|
(let ((sig-data (cdr (assq sig ssigs))))
|
|
|
|
(when sig-data
|
|
|
|
(let* ((ooff-data (assq toffset (nth 1 sig-data)))
|
|
|
|
(noffset (- toffset offset))
|
|
|
|
(noff-data
|
|
|
|
(or (assq noffset (nth 1 sig-data))
|
|
|
|
(let ((off-data (cons noffset 0)))
|
|
|
|
(push off-data (nth 1 sig-data))
|
|
|
|
off-data))))
|
|
|
|
(cl-assert (>= (cdr ooff-data) count))
|
|
|
|
(cl-decf (cdr ooff-data) count)
|
|
|
|
(cl-incf (cdr noff-data) count))))))))))
|
|
|
|
rules))
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
|
|
|
|
(defun smie-config-guess ()
|
2014-03-04 00:35:11 -08:00
|
|
|
"Try and figure out this buffer's indentation settings.
|
|
|
|
To save the result for future sessions, use `smie-config-save'."
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
(interactive)
|
2014-03-04 00:35:11 -08:00
|
|
|
(if (eq smie-grammar 'unset)
|
|
|
|
(user-error "This buffer does not seem to be using SMIE"))
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
(let ((config (smie-config--guess (point-min) (point-max))))
|
|
|
|
(cond
|
|
|
|
((null config) (message "Nothing to change"))
|
|
|
|
((null smie-config--buffer-local)
|
2014-06-20 17:10:40 -04:00
|
|
|
(smie-config-local config)
|
|
|
|
(message "Local rules set"))
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
((y-or-n-p "Replace existing local config? ")
|
|
|
|
(message "Local rules replaced")
|
2014-06-20 17:10:40 -04:00
|
|
|
(smie-config-local config))
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
((y-or-n-p "Merge with existing local config? ")
|
|
|
|
(message "Local rules adjusted")
|
2014-06-20 17:10:40 -04:00
|
|
|
(smie-config-local (append config smie-config--buffer-local)))
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
(t
|
|
|
|
(message "Rules guessed: %S" config)))))
|
|
|
|
|
|
|
|
(defun smie-config-save ()
|
2014-03-04 00:35:11 -08:00
|
|
|
"Save local rules for use with this major mode.
|
|
|
|
One way to generate local rules is the command `smie-config-guess'."
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
(interactive)
|
|
|
|
(cond
|
|
|
|
((null smie-config--buffer-local)
|
|
|
|
(message "No local rules to save"))
|
|
|
|
(t
|
|
|
|
(let* ((existing (assq major-mode smie-config))
|
|
|
|
(config
|
|
|
|
(cond ((null existing)
|
Go back to grave quoting in source-code docstrings etc.
This reverts almost all my recent changes to use curved quotes
in docstrings and/or strings used for error diagnostics.
There are a few exceptions, e.g., Bahá’í proper names.
* admin/unidata/unidata-gen.el (unidata-gen-table):
* lisp/abbrev.el (expand-region-abbrevs):
* lisp/align.el (align-region):
* lisp/allout.el (allout-mode, allout-solicit-alternate-bullet)
(outlineify-sticky):
* lisp/apropos.el (apropos-library):
* lisp/bookmark.el (bookmark-default-annotation-text):
* lisp/button.el (button-category-symbol, button-put)
(make-text-button):
* lisp/calc/calc-aent.el (math-read-if, math-read-factor):
* lisp/calc/calc-embed.el (calc-do-embedded):
* lisp/calc/calc-ext.el (calc-user-function-list):
* lisp/calc/calc-graph.el (calc-graph-show-dumb):
* lisp/calc/calc-help.el (calc-describe-key)
(calc-describe-thing, calc-full-help):
* lisp/calc/calc-lang.el (calc-c-language)
(math-parse-fortran-vector-end, math-parse-tex-sum)
(math-parse-eqn-matrix, math-parse-eqn-prime)
(calc-yacas-language, calc-maxima-language, calc-giac-language)
(math-read-giac-subscr, math-read-math-subscr)
(math-read-big-rec, math-read-big-balance):
* lisp/calc/calc-misc.el (calc-help, report-calc-bug):
* lisp/calc/calc-mode.el (calc-auto-why, calc-save-modes)
(calc-auto-recompute):
* lisp/calc/calc-prog.el (calc-fix-token-name)
(calc-read-parse-table-part, calc-user-define-invocation)
(math-do-arg-check):
* lisp/calc/calc-store.el (calc-edit-variable):
* lisp/calc/calc-units.el (math-build-units-table-buffer):
* lisp/calc/calc-vec.el (math-read-brackets):
* lisp/calc/calc-yank.el (calc-edit-mode):
* lisp/calc/calc.el (calc, calc-do, calc-user-invocation):
* lisp/calendar/appt.el (appt-display-message):
* lisp/calendar/diary-lib.el (diary-check-diary-file)
(diary-mail-entries, diary-from-outlook):
* lisp/calendar/icalendar.el (icalendar-export-region)
(icalendar--convert-float-to-ical)
(icalendar--convert-date-to-ical)
(icalendar--convert-ical-to-diary)
(icalendar--convert-recurring-to-diary)
(icalendar--add-diary-entry):
* lisp/calendar/time-date.el (format-seconds):
* lisp/calendar/timeclock.el (timeclock-mode-line-display)
(timeclock-make-hours-explicit, timeclock-log-data):
* lisp/calendar/todo-mode.el (todo-prefix, todo-delete-category)
(todo-item-mark, todo-check-format)
(todo-insert-item--next-param, todo-edit-item--next-key)
(todo-mode):
* lisp/cedet/ede/pmake.el (ede-proj-makefile-insert-dist-rules):
* lisp/cedet/mode-local.el (describe-mode-local-overload)
(mode-local-print-binding, mode-local-describe-bindings-2):
* lisp/cedet/semantic/complete.el (semantic-displayor-show-request):
* lisp/cedet/srecode/srt-mode.el (srecode-macro-help):
* lisp/cus-start.el (standard):
* lisp/cus-theme.el (describe-theme-1):
* lisp/custom.el (custom-add-dependencies, custom-check-theme)
(custom--sort-vars-1, load-theme):
* lisp/descr-text.el (describe-text-properties-1, describe-char):
* lisp/dired-x.el (dired-do-run-mail):
* lisp/dired.el (dired-log):
* lisp/emacs-lisp/advice.el (ad-read-advised-function)
(ad-read-advice-class, ad-read-advice-name, ad-enable-advice)
(ad-disable-advice, ad-remove-advice, ad-set-argument)
(ad-set-arguments, ad--defalias-fset, ad-activate)
(ad-deactivate):
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-compile-unfold-lambda, byte-optimize-form-code-walker)
(byte-optimize-while, byte-optimize-apply):
* lisp/emacs-lisp/byte-run.el (defun, defsubst):
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode)
(byte-compile-log-file, byte-compile-format-warn)
(byte-compile-nogroup-warn, byte-compile-arglist-warn)
(byte-compile-cl-warn)
(byte-compile-warn-about-unresolved-functions)
(byte-compile-file, byte-compile--declare-var)
(byte-compile-file-form-defmumble, byte-compile-form)
(byte-compile-normal-call, byte-compile-check-variable)
(byte-compile-variable-ref, byte-compile-variable-set)
(byte-compile-subr-wrong-args, byte-compile-setq-default)
(byte-compile-negation-optimizer)
(byte-compile-condition-case--old)
(byte-compile-condition-case--new, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-lambda-form)
(byte-compile-make-variable-buffer-local, display-call-tree)
(batch-byte-compile):
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use):
* lisp/emacs-lisp/chart.el (chart-space-usage):
* lisp/emacs-lisp/check-declare.el (check-declare-scan)
(check-declare-warn, check-declare-file)
(check-declare-directory):
* lisp/emacs-lisp/checkdoc.el (checkdoc-this-string-valid-engine)
(checkdoc-message-text-engine):
* lisp/emacs-lisp/cl-extra.el (cl-parse-integer)
(cl--describe-class):
* lisp/emacs-lisp/cl-generic.el (cl-defgeneric)
(cl--generic-describe, cl-generic-generalizers):
* lisp/emacs-lisp/cl-macs.el (cl--parse-loop-clause, cl-tagbody)
(cl-symbol-macrolet):
* lisp/emacs-lisp/cl.el (cl-unload-function, flet):
* lisp/emacs-lisp/copyright.el (copyright)
(copyright-update-directory):
* lisp/emacs-lisp/edebug.el (edebug-read-list):
* lisp/emacs-lisp/eieio-base.el (eieio-persistent-read):
* lisp/emacs-lisp/eieio-core.el (eieio--slot-override)
(eieio-oref):
* lisp/emacs-lisp/eieio-opt.el (eieio-help-constructor):
* lisp/emacs-lisp/eieio-speedbar.el:
(eieio-speedbar-child-make-tag-lines)
(eieio-speedbar-child-description):
* lisp/emacs-lisp/eieio.el (defclass, change-class):
* lisp/emacs-lisp/elint.el (elint-file, elint-get-top-forms)
(elint-init-form, elint-check-defalias-form)
(elint-check-let-form):
* lisp/emacs-lisp/ert.el (ert-get-test, ert-results-mode-menu)
(ert-results-pop-to-backtrace-for-test-at-point)
(ert-results-pop-to-messages-for-test-at-point)
(ert-results-pop-to-should-forms-for-test-at-point)
(ert-describe-test):
* lisp/emacs-lisp/find-func.el (find-function-search-for-symbol)
(find-function-library):
* lisp/emacs-lisp/generator.el (iter-yield):
* lisp/emacs-lisp/gv.el (gv-define-simple-setter):
* lisp/emacs-lisp/lisp-mnt.el (lm-verify):
* lisp/emacs-lisp/macroexp.el (macroexp--obsolete-warning):
* lisp/emacs-lisp/map-ynp.el (map-y-or-n-p):
* lisp/emacs-lisp/nadvice.el (advice--make-docstring)
(advice--make, define-advice):
* lisp/emacs-lisp/package-x.el (package-upload-file):
* lisp/emacs-lisp/package.el (package-version-join)
(package-disabled-p, package-activate-1, package-activate)
(package--download-one-archive)
(package--download-and-read-archives)
(package-compute-transaction, package-install-from-archive)
(package-install, package-install-selected-packages)
(package-delete, package-autoremove, describe-package-1)
(package-install-button-action, package-delete-button-action)
(package-menu-hide-package, package-menu--list-to-prompt)
(package-menu--perform-transaction)
(package-menu--find-and-notify-upgrades):
* lisp/emacs-lisp/pcase.el (pcase-exhaustive, pcase--u1):
* lisp/emacs-lisp/re-builder.el (reb-enter-subexp-mode):
* lisp/emacs-lisp/ring.el (ring-previous, ring-next):
* lisp/emacs-lisp/rx.el (rx-check, rx-anything)
(rx-check-any-string, rx-check-any, rx-check-not, rx-=)
(rx-repeat, rx-check-backref, rx-syntax, rx-check-category)
(rx-form):
* lisp/emacs-lisp/smie.el (smie-config-save):
* lisp/emacs-lisp/subr-x.el (internal--check-binding):
* lisp/emacs-lisp/tabulated-list.el (tabulated-list-put-tag):
* lisp/emacs-lisp/testcover.el (testcover-1value):
* lisp/emacs-lisp/timer.el (timer-event-handler):
* lisp/emulation/viper-cmd.el (viper-toggle-parse-sexp-ignore-comments)
(viper-toggle-search-style, viper-kill-buffer)
(viper-brac-function):
* lisp/emulation/viper-macs.el (viper-record-kbd-macro):
* lisp/env.el (setenv):
* lisp/erc/erc-button.el (erc-nick-popup):
* lisp/erc/erc.el (erc-cmd-LOAD, erc-handle-login, english):
* lisp/eshell/em-dirs.el (eshell/cd):
* lisp/eshell/em-glob.el (eshell-glob-regexp)
(eshell-glob-entries):
* lisp/eshell/em-pred.el (eshell-parse-modifiers):
* lisp/eshell/esh-opt.el (eshell-show-usage):
* lisp/facemenu.el (facemenu-add-new-face)
(facemenu-add-new-color):
* lisp/faces.el (read-face-name, read-face-font, describe-face)
(x-resolve-font-name):
* lisp/files-x.el (modify-file-local-variable):
* lisp/files.el (locate-user-emacs-file, find-alternate-file)
(set-auto-mode, hack-one-local-variable--obsolete)
(dir-locals-set-directory-class, write-file, basic-save-buffer)
(delete-directory, copy-directory, recover-session)
(recover-session-finish, insert-directory)
(file-modes-char-to-who, file-modes-symbolic-to-number)
(move-file-to-trash):
* lisp/filesets.el (filesets-add-buffer, filesets-remove-buffer):
* lisp/find-cmd.el (find-generic, find-to-string):
* lisp/finder.el (finder-commentary):
* lisp/font-lock.el (font-lock-fontify-buffer):
* lisp/format.el (format-write-file, format-find-file)
(format-insert-file):
* lisp/frame.el (get-device-terminal, select-frame-by-name):
* lisp/fringe.el (fringe--check-style):
* lisp/gnus/nnmairix.el (nnmairix-widget-create-query):
* lisp/help-fns.el (help-fns--key-bindings)
(help-fns--compiler-macro, help-fns--parent-mode)
(help-fns--obsolete, help-fns--interactive-only)
(describe-function-1, describe-variable):
* lisp/help.el (describe-mode)
(describe-minor-mode-from-indicator):
* lisp/image.el (image-type):
* lisp/international/ccl.el (ccl-dump):
* lisp/international/fontset.el (x-must-resolve-font-name):
* lisp/international/mule-cmds.el (prefer-coding-system)
(select-safe-coding-system-interactively)
(select-safe-coding-system, activate-input-method)
(toggle-input-method, describe-current-input-method)
(describe-language-environment):
* lisp/international/mule-conf.el (code-offset):
* lisp/international/mule-diag.el (describe-character-set)
(list-input-methods-1):
* lisp/mail/feedmail.el (feedmail-run-the-queue):
* lisp/mouse.el (minor-mode-menu-from-indicator):
* lisp/mpc.el (mpc-playlist-rename):
* lisp/msb.el (msb--choose-menu):
* lisp/net/ange-ftp.el (ange-ftp-shell-command):
* lisp/net/imap.el (imap-interactive-login):
* lisp/net/mairix.el (mairix-widget-create-query):
* lisp/net/newst-backend.el (newsticker--sentinel-work):
* lisp/net/newst-treeview.el (newsticker--treeview-load):
* lisp/net/rlogin.el (rlogin):
* lisp/obsolete/iswitchb.el (iswitchb-possible-new-buffer):
* lisp/obsolete/otodo-mode.el (todo-more-important-p):
* lisp/obsolete/pgg-gpg.el (pgg-gpg-process-region):
* lisp/obsolete/pgg-pgp.el (pgg-pgp-process-region):
* lisp/obsolete/pgg-pgp5.el (pgg-pgp5-process-region):
* lisp/org/ob-core.el (org-babel-goto-named-src-block)
(org-babel-goto-named-result):
* lisp/org/ob-fortran.el (org-babel-fortran-ensure-main-wrap):
* lisp/org/ob-ref.el (org-babel-ref-resolve):
* lisp/org/org-agenda.el (org-agenda-prepare):
* lisp/org/org-clock.el (org-clock-notify-once-if-expired)
(org-clock-resolve):
* lisp/org/org-ctags.el (org-ctags-ask-rebuild-tags-file-then-find-tag):
* lisp/org/org-feed.el (org-feed-parse-atom-entry):
* lisp/org/org-habit.el (org-habit-parse-todo):
* lisp/org/org-mouse.el (org-mouse-popup-global-menu)
(org-mouse-context-menu):
* lisp/org/org-table.el (org-table-edit-formulas):
* lisp/org/ox.el (org-export-async-start):
* lisp/proced.el (proced-log):
* lisp/progmodes/ada-mode.el (ada-get-indent-case)
(ada-check-matching-start, ada-goto-matching-start):
* lisp/progmodes/ada-prj.el (ada-prj-display-page):
* lisp/progmodes/ada-xref.el (ada-find-executable):
* lisp/progmodes/ebrowse.el (ebrowse-tags-apropos):
* lisp/progmodes/etags.el (etags-tags-apropos-additional):
* lisp/progmodes/flymake.el (flymake-parse-err-lines)
(flymake-start-syntax-check-process):
* lisp/progmodes/python.el (python-shell-get-process-or-error)
(python-define-auxiliary-skeleton):
* lisp/progmodes/sql.el (sql-comint):
* lisp/progmodes/verilog-mode.el (verilog-load-file-at-point):
* lisp/progmodes/vhdl-mode.el (vhdl-widget-directory-validate):
* lisp/recentf.el (recentf-open-files):
* lisp/replace.el (query-replace-read-from)
(occur-after-change-function, occur-1):
* lisp/scroll-bar.el (scroll-bar-columns):
* lisp/server.el (server-get-auth-key):
* lisp/simple.el (execute-extended-command)
(undo-outer-limit-truncate, list-processes--refresh)
(compose-mail, set-variable, choose-completion-string)
(define-alternatives):
* lisp/startup.el (site-run-file, tty-handle-args, command-line)
(command-line-1):
* lisp/subr.el (noreturn, define-error, add-to-list)
(read-char-choice, version-to-list):
* lisp/term/common-win.el (x-handle-xrm-switch)
(x-handle-name-switch, x-handle-args):
* lisp/term/x-win.el (x-handle-parent-id, x-handle-smid):
* lisp/textmodes/reftex-ref.el (reftex-label):
* lisp/textmodes/reftex-toc.el (reftex-toc-rename-label):
* lisp/textmodes/two-column.el (2C-split):
* lisp/tutorial.el (tutorial--describe-nonstandard-key)
(tutorial--find-changed-keys):
* lisp/type-break.el (type-break-noninteractive-query):
* lisp/wdired.el (wdired-do-renames, wdired-do-symlink-changes)
(wdired-do-perm-changes):
* lisp/whitespace.el (whitespace-report-region):
Prefer grave quoting in source-code strings used to generate help
and diagnostics.
* lisp/faces.el (face-documentation):
No need to convert quotes, since the result is a docstring.
* lisp/info.el (Info-virtual-index-find-node)
(Info-virtual-index, info-apropos):
Simplify by generating only curved quotes, since info files are
typically that ways nowadays anyway.
* lisp/international/mule-diag.el (list-input-methods):
Don’t assume text quoting style is curved.
* lisp/org/org-bibtex.el (org-bibtex-fields):
Revert my recent changes, going back to the old quoting style.
2015-09-07 08:41:44 -07:00
|
|
|
(message "Local rules saved in `smie-config'")
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
smie-config--buffer-local)
|
|
|
|
((y-or-n-p "Replace the existing mode's config? ")
|
Go back to grave quoting in source-code docstrings etc.
This reverts almost all my recent changes to use curved quotes
in docstrings and/or strings used for error diagnostics.
There are a few exceptions, e.g., Bahá’í proper names.
* admin/unidata/unidata-gen.el (unidata-gen-table):
* lisp/abbrev.el (expand-region-abbrevs):
* lisp/align.el (align-region):
* lisp/allout.el (allout-mode, allout-solicit-alternate-bullet)
(outlineify-sticky):
* lisp/apropos.el (apropos-library):
* lisp/bookmark.el (bookmark-default-annotation-text):
* lisp/button.el (button-category-symbol, button-put)
(make-text-button):
* lisp/calc/calc-aent.el (math-read-if, math-read-factor):
* lisp/calc/calc-embed.el (calc-do-embedded):
* lisp/calc/calc-ext.el (calc-user-function-list):
* lisp/calc/calc-graph.el (calc-graph-show-dumb):
* lisp/calc/calc-help.el (calc-describe-key)
(calc-describe-thing, calc-full-help):
* lisp/calc/calc-lang.el (calc-c-language)
(math-parse-fortran-vector-end, math-parse-tex-sum)
(math-parse-eqn-matrix, math-parse-eqn-prime)
(calc-yacas-language, calc-maxima-language, calc-giac-language)
(math-read-giac-subscr, math-read-math-subscr)
(math-read-big-rec, math-read-big-balance):
* lisp/calc/calc-misc.el (calc-help, report-calc-bug):
* lisp/calc/calc-mode.el (calc-auto-why, calc-save-modes)
(calc-auto-recompute):
* lisp/calc/calc-prog.el (calc-fix-token-name)
(calc-read-parse-table-part, calc-user-define-invocation)
(math-do-arg-check):
* lisp/calc/calc-store.el (calc-edit-variable):
* lisp/calc/calc-units.el (math-build-units-table-buffer):
* lisp/calc/calc-vec.el (math-read-brackets):
* lisp/calc/calc-yank.el (calc-edit-mode):
* lisp/calc/calc.el (calc, calc-do, calc-user-invocation):
* lisp/calendar/appt.el (appt-display-message):
* lisp/calendar/diary-lib.el (diary-check-diary-file)
(diary-mail-entries, diary-from-outlook):
* lisp/calendar/icalendar.el (icalendar-export-region)
(icalendar--convert-float-to-ical)
(icalendar--convert-date-to-ical)
(icalendar--convert-ical-to-diary)
(icalendar--convert-recurring-to-diary)
(icalendar--add-diary-entry):
* lisp/calendar/time-date.el (format-seconds):
* lisp/calendar/timeclock.el (timeclock-mode-line-display)
(timeclock-make-hours-explicit, timeclock-log-data):
* lisp/calendar/todo-mode.el (todo-prefix, todo-delete-category)
(todo-item-mark, todo-check-format)
(todo-insert-item--next-param, todo-edit-item--next-key)
(todo-mode):
* lisp/cedet/ede/pmake.el (ede-proj-makefile-insert-dist-rules):
* lisp/cedet/mode-local.el (describe-mode-local-overload)
(mode-local-print-binding, mode-local-describe-bindings-2):
* lisp/cedet/semantic/complete.el (semantic-displayor-show-request):
* lisp/cedet/srecode/srt-mode.el (srecode-macro-help):
* lisp/cus-start.el (standard):
* lisp/cus-theme.el (describe-theme-1):
* lisp/custom.el (custom-add-dependencies, custom-check-theme)
(custom--sort-vars-1, load-theme):
* lisp/descr-text.el (describe-text-properties-1, describe-char):
* lisp/dired-x.el (dired-do-run-mail):
* lisp/dired.el (dired-log):
* lisp/emacs-lisp/advice.el (ad-read-advised-function)
(ad-read-advice-class, ad-read-advice-name, ad-enable-advice)
(ad-disable-advice, ad-remove-advice, ad-set-argument)
(ad-set-arguments, ad--defalias-fset, ad-activate)
(ad-deactivate):
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-compile-unfold-lambda, byte-optimize-form-code-walker)
(byte-optimize-while, byte-optimize-apply):
* lisp/emacs-lisp/byte-run.el (defun, defsubst):
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode)
(byte-compile-log-file, byte-compile-format-warn)
(byte-compile-nogroup-warn, byte-compile-arglist-warn)
(byte-compile-cl-warn)
(byte-compile-warn-about-unresolved-functions)
(byte-compile-file, byte-compile--declare-var)
(byte-compile-file-form-defmumble, byte-compile-form)
(byte-compile-normal-call, byte-compile-check-variable)
(byte-compile-variable-ref, byte-compile-variable-set)
(byte-compile-subr-wrong-args, byte-compile-setq-default)
(byte-compile-negation-optimizer)
(byte-compile-condition-case--old)
(byte-compile-condition-case--new, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-lambda-form)
(byte-compile-make-variable-buffer-local, display-call-tree)
(batch-byte-compile):
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use):
* lisp/emacs-lisp/chart.el (chart-space-usage):
* lisp/emacs-lisp/check-declare.el (check-declare-scan)
(check-declare-warn, check-declare-file)
(check-declare-directory):
* lisp/emacs-lisp/checkdoc.el (checkdoc-this-string-valid-engine)
(checkdoc-message-text-engine):
* lisp/emacs-lisp/cl-extra.el (cl-parse-integer)
(cl--describe-class):
* lisp/emacs-lisp/cl-generic.el (cl-defgeneric)
(cl--generic-describe, cl-generic-generalizers):
* lisp/emacs-lisp/cl-macs.el (cl--parse-loop-clause, cl-tagbody)
(cl-symbol-macrolet):
* lisp/emacs-lisp/cl.el (cl-unload-function, flet):
* lisp/emacs-lisp/copyright.el (copyright)
(copyright-update-directory):
* lisp/emacs-lisp/edebug.el (edebug-read-list):
* lisp/emacs-lisp/eieio-base.el (eieio-persistent-read):
* lisp/emacs-lisp/eieio-core.el (eieio--slot-override)
(eieio-oref):
* lisp/emacs-lisp/eieio-opt.el (eieio-help-constructor):
* lisp/emacs-lisp/eieio-speedbar.el:
(eieio-speedbar-child-make-tag-lines)
(eieio-speedbar-child-description):
* lisp/emacs-lisp/eieio.el (defclass, change-class):
* lisp/emacs-lisp/elint.el (elint-file, elint-get-top-forms)
(elint-init-form, elint-check-defalias-form)
(elint-check-let-form):
* lisp/emacs-lisp/ert.el (ert-get-test, ert-results-mode-menu)
(ert-results-pop-to-backtrace-for-test-at-point)
(ert-results-pop-to-messages-for-test-at-point)
(ert-results-pop-to-should-forms-for-test-at-point)
(ert-describe-test):
* lisp/emacs-lisp/find-func.el (find-function-search-for-symbol)
(find-function-library):
* lisp/emacs-lisp/generator.el (iter-yield):
* lisp/emacs-lisp/gv.el (gv-define-simple-setter):
* lisp/emacs-lisp/lisp-mnt.el (lm-verify):
* lisp/emacs-lisp/macroexp.el (macroexp--obsolete-warning):
* lisp/emacs-lisp/map-ynp.el (map-y-or-n-p):
* lisp/emacs-lisp/nadvice.el (advice--make-docstring)
(advice--make, define-advice):
* lisp/emacs-lisp/package-x.el (package-upload-file):
* lisp/emacs-lisp/package.el (package-version-join)
(package-disabled-p, package-activate-1, package-activate)
(package--download-one-archive)
(package--download-and-read-archives)
(package-compute-transaction, package-install-from-archive)
(package-install, package-install-selected-packages)
(package-delete, package-autoremove, describe-package-1)
(package-install-button-action, package-delete-button-action)
(package-menu-hide-package, package-menu--list-to-prompt)
(package-menu--perform-transaction)
(package-menu--find-and-notify-upgrades):
* lisp/emacs-lisp/pcase.el (pcase-exhaustive, pcase--u1):
* lisp/emacs-lisp/re-builder.el (reb-enter-subexp-mode):
* lisp/emacs-lisp/ring.el (ring-previous, ring-next):
* lisp/emacs-lisp/rx.el (rx-check, rx-anything)
(rx-check-any-string, rx-check-any, rx-check-not, rx-=)
(rx-repeat, rx-check-backref, rx-syntax, rx-check-category)
(rx-form):
* lisp/emacs-lisp/smie.el (smie-config-save):
* lisp/emacs-lisp/subr-x.el (internal--check-binding):
* lisp/emacs-lisp/tabulated-list.el (tabulated-list-put-tag):
* lisp/emacs-lisp/testcover.el (testcover-1value):
* lisp/emacs-lisp/timer.el (timer-event-handler):
* lisp/emulation/viper-cmd.el (viper-toggle-parse-sexp-ignore-comments)
(viper-toggle-search-style, viper-kill-buffer)
(viper-brac-function):
* lisp/emulation/viper-macs.el (viper-record-kbd-macro):
* lisp/env.el (setenv):
* lisp/erc/erc-button.el (erc-nick-popup):
* lisp/erc/erc.el (erc-cmd-LOAD, erc-handle-login, english):
* lisp/eshell/em-dirs.el (eshell/cd):
* lisp/eshell/em-glob.el (eshell-glob-regexp)
(eshell-glob-entries):
* lisp/eshell/em-pred.el (eshell-parse-modifiers):
* lisp/eshell/esh-opt.el (eshell-show-usage):
* lisp/facemenu.el (facemenu-add-new-face)
(facemenu-add-new-color):
* lisp/faces.el (read-face-name, read-face-font, describe-face)
(x-resolve-font-name):
* lisp/files-x.el (modify-file-local-variable):
* lisp/files.el (locate-user-emacs-file, find-alternate-file)
(set-auto-mode, hack-one-local-variable--obsolete)
(dir-locals-set-directory-class, write-file, basic-save-buffer)
(delete-directory, copy-directory, recover-session)
(recover-session-finish, insert-directory)
(file-modes-char-to-who, file-modes-symbolic-to-number)
(move-file-to-trash):
* lisp/filesets.el (filesets-add-buffer, filesets-remove-buffer):
* lisp/find-cmd.el (find-generic, find-to-string):
* lisp/finder.el (finder-commentary):
* lisp/font-lock.el (font-lock-fontify-buffer):
* lisp/format.el (format-write-file, format-find-file)
(format-insert-file):
* lisp/frame.el (get-device-terminal, select-frame-by-name):
* lisp/fringe.el (fringe--check-style):
* lisp/gnus/nnmairix.el (nnmairix-widget-create-query):
* lisp/help-fns.el (help-fns--key-bindings)
(help-fns--compiler-macro, help-fns--parent-mode)
(help-fns--obsolete, help-fns--interactive-only)
(describe-function-1, describe-variable):
* lisp/help.el (describe-mode)
(describe-minor-mode-from-indicator):
* lisp/image.el (image-type):
* lisp/international/ccl.el (ccl-dump):
* lisp/international/fontset.el (x-must-resolve-font-name):
* lisp/international/mule-cmds.el (prefer-coding-system)
(select-safe-coding-system-interactively)
(select-safe-coding-system, activate-input-method)
(toggle-input-method, describe-current-input-method)
(describe-language-environment):
* lisp/international/mule-conf.el (code-offset):
* lisp/international/mule-diag.el (describe-character-set)
(list-input-methods-1):
* lisp/mail/feedmail.el (feedmail-run-the-queue):
* lisp/mouse.el (minor-mode-menu-from-indicator):
* lisp/mpc.el (mpc-playlist-rename):
* lisp/msb.el (msb--choose-menu):
* lisp/net/ange-ftp.el (ange-ftp-shell-command):
* lisp/net/imap.el (imap-interactive-login):
* lisp/net/mairix.el (mairix-widget-create-query):
* lisp/net/newst-backend.el (newsticker--sentinel-work):
* lisp/net/newst-treeview.el (newsticker--treeview-load):
* lisp/net/rlogin.el (rlogin):
* lisp/obsolete/iswitchb.el (iswitchb-possible-new-buffer):
* lisp/obsolete/otodo-mode.el (todo-more-important-p):
* lisp/obsolete/pgg-gpg.el (pgg-gpg-process-region):
* lisp/obsolete/pgg-pgp.el (pgg-pgp-process-region):
* lisp/obsolete/pgg-pgp5.el (pgg-pgp5-process-region):
* lisp/org/ob-core.el (org-babel-goto-named-src-block)
(org-babel-goto-named-result):
* lisp/org/ob-fortran.el (org-babel-fortran-ensure-main-wrap):
* lisp/org/ob-ref.el (org-babel-ref-resolve):
* lisp/org/org-agenda.el (org-agenda-prepare):
* lisp/org/org-clock.el (org-clock-notify-once-if-expired)
(org-clock-resolve):
* lisp/org/org-ctags.el (org-ctags-ask-rebuild-tags-file-then-find-tag):
* lisp/org/org-feed.el (org-feed-parse-atom-entry):
* lisp/org/org-habit.el (org-habit-parse-todo):
* lisp/org/org-mouse.el (org-mouse-popup-global-menu)
(org-mouse-context-menu):
* lisp/org/org-table.el (org-table-edit-formulas):
* lisp/org/ox.el (org-export-async-start):
* lisp/proced.el (proced-log):
* lisp/progmodes/ada-mode.el (ada-get-indent-case)
(ada-check-matching-start, ada-goto-matching-start):
* lisp/progmodes/ada-prj.el (ada-prj-display-page):
* lisp/progmodes/ada-xref.el (ada-find-executable):
* lisp/progmodes/ebrowse.el (ebrowse-tags-apropos):
* lisp/progmodes/etags.el (etags-tags-apropos-additional):
* lisp/progmodes/flymake.el (flymake-parse-err-lines)
(flymake-start-syntax-check-process):
* lisp/progmodes/python.el (python-shell-get-process-or-error)
(python-define-auxiliary-skeleton):
* lisp/progmodes/sql.el (sql-comint):
* lisp/progmodes/verilog-mode.el (verilog-load-file-at-point):
* lisp/progmodes/vhdl-mode.el (vhdl-widget-directory-validate):
* lisp/recentf.el (recentf-open-files):
* lisp/replace.el (query-replace-read-from)
(occur-after-change-function, occur-1):
* lisp/scroll-bar.el (scroll-bar-columns):
* lisp/server.el (server-get-auth-key):
* lisp/simple.el (execute-extended-command)
(undo-outer-limit-truncate, list-processes--refresh)
(compose-mail, set-variable, choose-completion-string)
(define-alternatives):
* lisp/startup.el (site-run-file, tty-handle-args, command-line)
(command-line-1):
* lisp/subr.el (noreturn, define-error, add-to-list)
(read-char-choice, version-to-list):
* lisp/term/common-win.el (x-handle-xrm-switch)
(x-handle-name-switch, x-handle-args):
* lisp/term/x-win.el (x-handle-parent-id, x-handle-smid):
* lisp/textmodes/reftex-ref.el (reftex-label):
* lisp/textmodes/reftex-toc.el (reftex-toc-rename-label):
* lisp/textmodes/two-column.el (2C-split):
* lisp/tutorial.el (tutorial--describe-nonstandard-key)
(tutorial--find-changed-keys):
* lisp/type-break.el (type-break-noninteractive-query):
* lisp/wdired.el (wdired-do-renames, wdired-do-symlink-changes)
(wdired-do-perm-changes):
* lisp/whitespace.el (whitespace-report-region):
Prefer grave quoting in source-code strings used to generate help
and diagnostics.
* lisp/faces.el (face-documentation):
No need to convert quotes, since the result is a docstring.
* lisp/info.el (Info-virtual-index-find-node)
(Info-virtual-index, info-apropos):
Simplify by generating only curved quotes, since info files are
typically that ways nowadays anyway.
* lisp/international/mule-diag.el (list-input-methods):
Don’t assume text quoting style is curved.
* lisp/org/org-bibtex.el (org-bibtex-fields):
Revert my recent changes, going back to the old quoting style.
2015-09-07 08:41:44 -07:00
|
|
|
(message "Mode rules replaced in `smie-config'")
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
smie-config--buffer-local)
|
|
|
|
((y-or-n-p "Merge with existing mode's config? ")
|
Go back to grave quoting in source-code docstrings etc.
This reverts almost all my recent changes to use curved quotes
in docstrings and/or strings used for error diagnostics.
There are a few exceptions, e.g., Bahá’í proper names.
* admin/unidata/unidata-gen.el (unidata-gen-table):
* lisp/abbrev.el (expand-region-abbrevs):
* lisp/align.el (align-region):
* lisp/allout.el (allout-mode, allout-solicit-alternate-bullet)
(outlineify-sticky):
* lisp/apropos.el (apropos-library):
* lisp/bookmark.el (bookmark-default-annotation-text):
* lisp/button.el (button-category-symbol, button-put)
(make-text-button):
* lisp/calc/calc-aent.el (math-read-if, math-read-factor):
* lisp/calc/calc-embed.el (calc-do-embedded):
* lisp/calc/calc-ext.el (calc-user-function-list):
* lisp/calc/calc-graph.el (calc-graph-show-dumb):
* lisp/calc/calc-help.el (calc-describe-key)
(calc-describe-thing, calc-full-help):
* lisp/calc/calc-lang.el (calc-c-language)
(math-parse-fortran-vector-end, math-parse-tex-sum)
(math-parse-eqn-matrix, math-parse-eqn-prime)
(calc-yacas-language, calc-maxima-language, calc-giac-language)
(math-read-giac-subscr, math-read-math-subscr)
(math-read-big-rec, math-read-big-balance):
* lisp/calc/calc-misc.el (calc-help, report-calc-bug):
* lisp/calc/calc-mode.el (calc-auto-why, calc-save-modes)
(calc-auto-recompute):
* lisp/calc/calc-prog.el (calc-fix-token-name)
(calc-read-parse-table-part, calc-user-define-invocation)
(math-do-arg-check):
* lisp/calc/calc-store.el (calc-edit-variable):
* lisp/calc/calc-units.el (math-build-units-table-buffer):
* lisp/calc/calc-vec.el (math-read-brackets):
* lisp/calc/calc-yank.el (calc-edit-mode):
* lisp/calc/calc.el (calc, calc-do, calc-user-invocation):
* lisp/calendar/appt.el (appt-display-message):
* lisp/calendar/diary-lib.el (diary-check-diary-file)
(diary-mail-entries, diary-from-outlook):
* lisp/calendar/icalendar.el (icalendar-export-region)
(icalendar--convert-float-to-ical)
(icalendar--convert-date-to-ical)
(icalendar--convert-ical-to-diary)
(icalendar--convert-recurring-to-diary)
(icalendar--add-diary-entry):
* lisp/calendar/time-date.el (format-seconds):
* lisp/calendar/timeclock.el (timeclock-mode-line-display)
(timeclock-make-hours-explicit, timeclock-log-data):
* lisp/calendar/todo-mode.el (todo-prefix, todo-delete-category)
(todo-item-mark, todo-check-format)
(todo-insert-item--next-param, todo-edit-item--next-key)
(todo-mode):
* lisp/cedet/ede/pmake.el (ede-proj-makefile-insert-dist-rules):
* lisp/cedet/mode-local.el (describe-mode-local-overload)
(mode-local-print-binding, mode-local-describe-bindings-2):
* lisp/cedet/semantic/complete.el (semantic-displayor-show-request):
* lisp/cedet/srecode/srt-mode.el (srecode-macro-help):
* lisp/cus-start.el (standard):
* lisp/cus-theme.el (describe-theme-1):
* lisp/custom.el (custom-add-dependencies, custom-check-theme)
(custom--sort-vars-1, load-theme):
* lisp/descr-text.el (describe-text-properties-1, describe-char):
* lisp/dired-x.el (dired-do-run-mail):
* lisp/dired.el (dired-log):
* lisp/emacs-lisp/advice.el (ad-read-advised-function)
(ad-read-advice-class, ad-read-advice-name, ad-enable-advice)
(ad-disable-advice, ad-remove-advice, ad-set-argument)
(ad-set-arguments, ad--defalias-fset, ad-activate)
(ad-deactivate):
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-compile-unfold-lambda, byte-optimize-form-code-walker)
(byte-optimize-while, byte-optimize-apply):
* lisp/emacs-lisp/byte-run.el (defun, defsubst):
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode)
(byte-compile-log-file, byte-compile-format-warn)
(byte-compile-nogroup-warn, byte-compile-arglist-warn)
(byte-compile-cl-warn)
(byte-compile-warn-about-unresolved-functions)
(byte-compile-file, byte-compile--declare-var)
(byte-compile-file-form-defmumble, byte-compile-form)
(byte-compile-normal-call, byte-compile-check-variable)
(byte-compile-variable-ref, byte-compile-variable-set)
(byte-compile-subr-wrong-args, byte-compile-setq-default)
(byte-compile-negation-optimizer)
(byte-compile-condition-case--old)
(byte-compile-condition-case--new, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-lambda-form)
(byte-compile-make-variable-buffer-local, display-call-tree)
(batch-byte-compile):
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use):
* lisp/emacs-lisp/chart.el (chart-space-usage):
* lisp/emacs-lisp/check-declare.el (check-declare-scan)
(check-declare-warn, check-declare-file)
(check-declare-directory):
* lisp/emacs-lisp/checkdoc.el (checkdoc-this-string-valid-engine)
(checkdoc-message-text-engine):
* lisp/emacs-lisp/cl-extra.el (cl-parse-integer)
(cl--describe-class):
* lisp/emacs-lisp/cl-generic.el (cl-defgeneric)
(cl--generic-describe, cl-generic-generalizers):
* lisp/emacs-lisp/cl-macs.el (cl--parse-loop-clause, cl-tagbody)
(cl-symbol-macrolet):
* lisp/emacs-lisp/cl.el (cl-unload-function, flet):
* lisp/emacs-lisp/copyright.el (copyright)
(copyright-update-directory):
* lisp/emacs-lisp/edebug.el (edebug-read-list):
* lisp/emacs-lisp/eieio-base.el (eieio-persistent-read):
* lisp/emacs-lisp/eieio-core.el (eieio--slot-override)
(eieio-oref):
* lisp/emacs-lisp/eieio-opt.el (eieio-help-constructor):
* lisp/emacs-lisp/eieio-speedbar.el:
(eieio-speedbar-child-make-tag-lines)
(eieio-speedbar-child-description):
* lisp/emacs-lisp/eieio.el (defclass, change-class):
* lisp/emacs-lisp/elint.el (elint-file, elint-get-top-forms)
(elint-init-form, elint-check-defalias-form)
(elint-check-let-form):
* lisp/emacs-lisp/ert.el (ert-get-test, ert-results-mode-menu)
(ert-results-pop-to-backtrace-for-test-at-point)
(ert-results-pop-to-messages-for-test-at-point)
(ert-results-pop-to-should-forms-for-test-at-point)
(ert-describe-test):
* lisp/emacs-lisp/find-func.el (find-function-search-for-symbol)
(find-function-library):
* lisp/emacs-lisp/generator.el (iter-yield):
* lisp/emacs-lisp/gv.el (gv-define-simple-setter):
* lisp/emacs-lisp/lisp-mnt.el (lm-verify):
* lisp/emacs-lisp/macroexp.el (macroexp--obsolete-warning):
* lisp/emacs-lisp/map-ynp.el (map-y-or-n-p):
* lisp/emacs-lisp/nadvice.el (advice--make-docstring)
(advice--make, define-advice):
* lisp/emacs-lisp/package-x.el (package-upload-file):
* lisp/emacs-lisp/package.el (package-version-join)
(package-disabled-p, package-activate-1, package-activate)
(package--download-one-archive)
(package--download-and-read-archives)
(package-compute-transaction, package-install-from-archive)
(package-install, package-install-selected-packages)
(package-delete, package-autoremove, describe-package-1)
(package-install-button-action, package-delete-button-action)
(package-menu-hide-package, package-menu--list-to-prompt)
(package-menu--perform-transaction)
(package-menu--find-and-notify-upgrades):
* lisp/emacs-lisp/pcase.el (pcase-exhaustive, pcase--u1):
* lisp/emacs-lisp/re-builder.el (reb-enter-subexp-mode):
* lisp/emacs-lisp/ring.el (ring-previous, ring-next):
* lisp/emacs-lisp/rx.el (rx-check, rx-anything)
(rx-check-any-string, rx-check-any, rx-check-not, rx-=)
(rx-repeat, rx-check-backref, rx-syntax, rx-check-category)
(rx-form):
* lisp/emacs-lisp/smie.el (smie-config-save):
* lisp/emacs-lisp/subr-x.el (internal--check-binding):
* lisp/emacs-lisp/tabulated-list.el (tabulated-list-put-tag):
* lisp/emacs-lisp/testcover.el (testcover-1value):
* lisp/emacs-lisp/timer.el (timer-event-handler):
* lisp/emulation/viper-cmd.el (viper-toggle-parse-sexp-ignore-comments)
(viper-toggle-search-style, viper-kill-buffer)
(viper-brac-function):
* lisp/emulation/viper-macs.el (viper-record-kbd-macro):
* lisp/env.el (setenv):
* lisp/erc/erc-button.el (erc-nick-popup):
* lisp/erc/erc.el (erc-cmd-LOAD, erc-handle-login, english):
* lisp/eshell/em-dirs.el (eshell/cd):
* lisp/eshell/em-glob.el (eshell-glob-regexp)
(eshell-glob-entries):
* lisp/eshell/em-pred.el (eshell-parse-modifiers):
* lisp/eshell/esh-opt.el (eshell-show-usage):
* lisp/facemenu.el (facemenu-add-new-face)
(facemenu-add-new-color):
* lisp/faces.el (read-face-name, read-face-font, describe-face)
(x-resolve-font-name):
* lisp/files-x.el (modify-file-local-variable):
* lisp/files.el (locate-user-emacs-file, find-alternate-file)
(set-auto-mode, hack-one-local-variable--obsolete)
(dir-locals-set-directory-class, write-file, basic-save-buffer)
(delete-directory, copy-directory, recover-session)
(recover-session-finish, insert-directory)
(file-modes-char-to-who, file-modes-symbolic-to-number)
(move-file-to-trash):
* lisp/filesets.el (filesets-add-buffer, filesets-remove-buffer):
* lisp/find-cmd.el (find-generic, find-to-string):
* lisp/finder.el (finder-commentary):
* lisp/font-lock.el (font-lock-fontify-buffer):
* lisp/format.el (format-write-file, format-find-file)
(format-insert-file):
* lisp/frame.el (get-device-terminal, select-frame-by-name):
* lisp/fringe.el (fringe--check-style):
* lisp/gnus/nnmairix.el (nnmairix-widget-create-query):
* lisp/help-fns.el (help-fns--key-bindings)
(help-fns--compiler-macro, help-fns--parent-mode)
(help-fns--obsolete, help-fns--interactive-only)
(describe-function-1, describe-variable):
* lisp/help.el (describe-mode)
(describe-minor-mode-from-indicator):
* lisp/image.el (image-type):
* lisp/international/ccl.el (ccl-dump):
* lisp/international/fontset.el (x-must-resolve-font-name):
* lisp/international/mule-cmds.el (prefer-coding-system)
(select-safe-coding-system-interactively)
(select-safe-coding-system, activate-input-method)
(toggle-input-method, describe-current-input-method)
(describe-language-environment):
* lisp/international/mule-conf.el (code-offset):
* lisp/international/mule-diag.el (describe-character-set)
(list-input-methods-1):
* lisp/mail/feedmail.el (feedmail-run-the-queue):
* lisp/mouse.el (minor-mode-menu-from-indicator):
* lisp/mpc.el (mpc-playlist-rename):
* lisp/msb.el (msb--choose-menu):
* lisp/net/ange-ftp.el (ange-ftp-shell-command):
* lisp/net/imap.el (imap-interactive-login):
* lisp/net/mairix.el (mairix-widget-create-query):
* lisp/net/newst-backend.el (newsticker--sentinel-work):
* lisp/net/newst-treeview.el (newsticker--treeview-load):
* lisp/net/rlogin.el (rlogin):
* lisp/obsolete/iswitchb.el (iswitchb-possible-new-buffer):
* lisp/obsolete/otodo-mode.el (todo-more-important-p):
* lisp/obsolete/pgg-gpg.el (pgg-gpg-process-region):
* lisp/obsolete/pgg-pgp.el (pgg-pgp-process-region):
* lisp/obsolete/pgg-pgp5.el (pgg-pgp5-process-region):
* lisp/org/ob-core.el (org-babel-goto-named-src-block)
(org-babel-goto-named-result):
* lisp/org/ob-fortran.el (org-babel-fortran-ensure-main-wrap):
* lisp/org/ob-ref.el (org-babel-ref-resolve):
* lisp/org/org-agenda.el (org-agenda-prepare):
* lisp/org/org-clock.el (org-clock-notify-once-if-expired)
(org-clock-resolve):
* lisp/org/org-ctags.el (org-ctags-ask-rebuild-tags-file-then-find-tag):
* lisp/org/org-feed.el (org-feed-parse-atom-entry):
* lisp/org/org-habit.el (org-habit-parse-todo):
* lisp/org/org-mouse.el (org-mouse-popup-global-menu)
(org-mouse-context-menu):
* lisp/org/org-table.el (org-table-edit-formulas):
* lisp/org/ox.el (org-export-async-start):
* lisp/proced.el (proced-log):
* lisp/progmodes/ada-mode.el (ada-get-indent-case)
(ada-check-matching-start, ada-goto-matching-start):
* lisp/progmodes/ada-prj.el (ada-prj-display-page):
* lisp/progmodes/ada-xref.el (ada-find-executable):
* lisp/progmodes/ebrowse.el (ebrowse-tags-apropos):
* lisp/progmodes/etags.el (etags-tags-apropos-additional):
* lisp/progmodes/flymake.el (flymake-parse-err-lines)
(flymake-start-syntax-check-process):
* lisp/progmodes/python.el (python-shell-get-process-or-error)
(python-define-auxiliary-skeleton):
* lisp/progmodes/sql.el (sql-comint):
* lisp/progmodes/verilog-mode.el (verilog-load-file-at-point):
* lisp/progmodes/vhdl-mode.el (vhdl-widget-directory-validate):
* lisp/recentf.el (recentf-open-files):
* lisp/replace.el (query-replace-read-from)
(occur-after-change-function, occur-1):
* lisp/scroll-bar.el (scroll-bar-columns):
* lisp/server.el (server-get-auth-key):
* lisp/simple.el (execute-extended-command)
(undo-outer-limit-truncate, list-processes--refresh)
(compose-mail, set-variable, choose-completion-string)
(define-alternatives):
* lisp/startup.el (site-run-file, tty-handle-args, command-line)
(command-line-1):
* lisp/subr.el (noreturn, define-error, add-to-list)
(read-char-choice, version-to-list):
* lisp/term/common-win.el (x-handle-xrm-switch)
(x-handle-name-switch, x-handle-args):
* lisp/term/x-win.el (x-handle-parent-id, x-handle-smid):
* lisp/textmodes/reftex-ref.el (reftex-label):
* lisp/textmodes/reftex-toc.el (reftex-toc-rename-label):
* lisp/textmodes/two-column.el (2C-split):
* lisp/tutorial.el (tutorial--describe-nonstandard-key)
(tutorial--find-changed-keys):
* lisp/type-break.el (type-break-noninteractive-query):
* lisp/wdired.el (wdired-do-renames, wdired-do-symlink-changes)
(wdired-do-perm-changes):
* lisp/whitespace.el (whitespace-report-region):
Prefer grave quoting in source-code strings used to generate help
and diagnostics.
* lisp/faces.el (face-documentation):
No need to convert quotes, since the result is a docstring.
* lisp/info.el (Info-virtual-index-find-node)
(Info-virtual-index, info-apropos):
Simplify by generating only curved quotes, since info files are
typically that ways nowadays anyway.
* lisp/international/mule-diag.el (list-input-methods):
Don’t assume text quoting style is curved.
* lisp/org/org-bibtex.el (org-bibtex-fields):
Revert my recent changes, going back to the old quoting style.
2015-09-07 08:41:44 -07:00
|
|
|
(message "Mode rules adjusted in `smie-config'")
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
(append smie-config--buffer-local (cdr existing)))
|
|
|
|
(t (error "Abort")))))
|
|
|
|
(if existing
|
|
|
|
(setcdr existing config)
|
|
|
|
(push (cons major-mode config) smie-config))
|
|
|
|
(setq smie-config--mode-local config)
|
2014-03-04 00:35:11 -08:00
|
|
|
(kill-local-variable 'smie-config--buffer-local)
|
* lisp/emacs-lisp/smie.el: New smie-config system.
(smie-config): New defcustom.
(smie-edebug, smie-config-show-indent, smie-config-set-indent)
(smie-config-guess, smie-config-save): New commands.
(smie-config--mode-local, smie-config--buffer-local)
(smie-config--trace, smie-config--modefuns): New vars.
(smie-config--advice, smie-config--mode-hook)
(smie-config--setter, smie-config-local, smie-config--get-trace)
(smie-config--guess-value, smie-config--guess): New functions.
(smie-indent-forward-token, smie-indent-backward-token): Don't copy
text properties. Treat "string fence" syntax like string syntax.
* lisp/progmodes/sh-script.el (sh-use-smie): Change default.
(sh-smie-sh-rules, sh-smie-rc-rules): Obey legacy sh-indent-* vars.
(sh-var-value): Simplify by CSE.
(sh-show-indent, sh-set-indent, sh-learn-line-indent)
(sh-learn-buffer-indent): Redirect to their SMIE equivalent when SMIE
is used.
(sh-guess-basic-offset): Use cl-incf.
(sh-guess-basic-offset): Use push+nreverse to avoid O(n^2).
2013-10-24 17:16:20 -04:00
|
|
|
(customize-mark-as-set 'smie-config)))))
|
2010-11-07 10:52:33 -05:00
|
|
|
|
|
|
|
(provide 'smie)
|
|
|
|
;;; smie.el ends here
|