X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/70360d0cab4f5e9fa351cd131e45fa86401896c0..db4613576d3115aa320f0293d081ce98baa06acd:/lisp/align.el diff --git a/lisp/align.el b/lisp/align.el index 75046c147c..82a55b0fea 100644 --- a/lisp/align.el +++ b/lisp/align.el @@ -1,18 +1,17 @@ -;;; align.el --- align text to a specific column, by regexp +;;; align.el --- align text to a specific column, by regexp -*- lexical-binding:t -*- -;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, -;; 2005, 2006, 2007 Free Software Foundation, Inc. +;; Copyright (C) 1999-2015 Free Software Foundation, Inc. -;; Author: John Wiegley -;; Maintainer: FSF +;; Author: John Wiegley +;; Maintainer: emacs-devel@gnu.org ;; Keywords: convenience languages lisp ;; This file is part of GNU Emacs. -;; GNU Emacs is free software; you can redistribute it and/or modify +;; 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 2, or (at your option) -;; any later version. +;; 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 @@ -20,9 +19,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. +;; along with GNU Emacs. If not, see . ;;; Commentary: @@ -77,7 +74,7 @@ ;; align-?-modes variables (for example, `align-dq-string-modes'), use ;; `add-to-list', or some similar function which checks first to see ;; if the value is already there. Since the user may customize that -;; mode list, and then write your mode name into their .emacs file, +;; mode list, and then write your mode name into their init file, ;; causing the symbol already to be present the next time they load ;; your package. @@ -112,7 +109,7 @@ ;; simple algorithm that understand only basic regular expressions. ;; Parts of the code were broken up and included in vhdl-mode.el ;; around this time. After several comments from users, and a need to -;; find a more robust, performant algorithm, 2.0 was born in late +;; find a more robust, higher performing algorithm, 2.0 was born in late ;; 1998. Many different approaches were taken (mostly due to the ;; complexity of TeX tables), but finally a scheme was discovered ;; which worked fairly well for most common usage cases. Development @@ -129,108 +126,108 @@ ;;; User Variables: (defcustom align-load-hook nil - "*Hook that gets run after the aligner has been loaded." + "Hook that gets run after the aligner has been loaded." :type 'hook :group 'align) (defcustom align-indent-before-aligning nil - "*If non-nil, indent the marked region before aligning it." + "If non-nil, indent the marked region before aligning it." :type 'boolean :group 'align) (defcustom align-default-spacing 1 - "*An integer that represents the default amount of padding to use. + "An integer that represents the default amount of padding to use. If `align-to-tab-stop' is non-nil, this will represent the number of tab stops to use for alignment, rather than the number of spaces. -Each alignment rule can optionally override both this variable. See -`align-mode-alist'." +Each alignment rule can optionally override both this variable and +`align-to-tab-stop'. See `align-rules-list'." :type 'integer :group 'align) (defcustom align-to-tab-stop 'indent-tabs-mode - "*If non-nil, alignments will always fall on a tab boundary. + "If non-nil, alignments will always fall on a tab boundary. It may also be a symbol, whose value will be taken." :type '(choice (const nil) symbol) :group 'align) (defcustom align-region-heuristic 500 - "*If non-nil, used as a heuristic by `align-current'. + "If non-nil, used as a heuristic by `align-current'. Since each alignment rule can possibly have its own set of alignment sections (whenever `align-region-separate' is non-nil, and not a string), this heuristic is used to determine how far before and after point we should search in looking for a region separator. Larger -values can mean slower perform in large files, although smaller values -may cause unexpected behavior at times." +values can mean slower performance in large files, although smaller +values may cause unexpected behavior at times." :type 'integer :group 'align) (defcustom align-highlight-change-face 'highlight - "*The face to highlight with if changes are necessary." + "The face to highlight with if changes are necessary." :type 'face :group 'align) (defcustom align-highlight-nochange-face 'secondary-selection - "*The face to highlight with if no changes are necessary." + "The face to highlight with if no changes are necessary." :type 'face :group 'align) (defcustom align-large-region 10000 - "*If an integer, defines what constitutes a \"large\" region. -If nil,then no messages will ever be printed to the minibuffer." + "If an integer, defines what constitutes a \"large\" region. +If nil, then no messages will ever be printed to the minibuffer." :type 'integer :group 'align) (defcustom align-c++-modes '(c++-mode c-mode java-mode) - "*A list of modes whose syntax resembles C/C++." + "A list of modes whose syntax resembles C/C++." :type '(repeat symbol) :group 'align) (defcustom align-perl-modes '(perl-mode cperl-mode) - "*A list of modes where perl syntax is to be seen." + "A list of modes where Perl syntax is to be seen." :type '(repeat symbol) :group 'align) (defcustom align-lisp-modes '(emacs-lisp-mode lisp-interaction-mode lisp-mode scheme-mode) - "*A list of modes whose syntax resembles Lisp." + "A list of modes whose syntax resembles Lisp." :type '(repeat symbol) :group 'align) (defcustom align-tex-modes '(tex-mode plain-tex-mode latex-mode slitex-mode) - "*A list of modes whose syntax resembles TeX (and family)." + "A list of modes whose syntax resembles TeX (and family)." :type '(repeat symbol) :group 'align) (defcustom align-text-modes '(text-mode outline-mode) - "*A list of modes whose content is plain text." + "A list of modes whose content is plain text." :type '(repeat symbol) :group 'align) (defcustom align-dq-string-modes (append align-lisp-modes align-c++-modes align-perl-modes '(python-mode)) - "*A list of modes where double quoted strings should be excluded." + "A list of modes where double quoted strings should be excluded." :type '(repeat symbol) :group 'align) (defcustom align-sq-string-modes (append align-perl-modes '(python-mode)) - "*A list of modes where single quoted strings should be excluded." + "A list of modes where single quoted strings should be excluded." :type '(repeat symbol) :group 'align) (defcustom align-open-comment-modes (append align-lisp-modes align-c++-modes align-perl-modes '(python-mode makefile-mode)) - "*A list of modes with a single-line comment syntax. -These are comments as in Lisp, which have a beginning but, end with + "A list of modes with a single-line comment syntax. +These are comments as in Lisp, which have a beginning, but end with the line (i.e., `comment-end' is an empty string)." :type '(repeat symbol) :group 'align) (defcustom align-region-separate "^\\s-*[{}]?\\s-*$" - "*Select the method by which alignment sections will be separated. + "Select the method by which alignment sections will be separated. If this is a symbol, that symbol's value will be used. For the sake of clarification, consider the following example, which @@ -261,8 +258,8 @@ The possible settings for `align-region-separate' are: `group' Each contiguous set of lines where a specific alignment occurs is considered a section for that alignment rule. - Note that each rule will may have any entirely different - set of section divisions than another. + Note that each rule may have any entirely different set + of section divisions than another. int alpha = 1; /* one */ double beta = 2.0; @@ -294,7 +291,7 @@ The possible settings for `align-region-separate' are: between sections, the behavior will be very similar to `largest', and faster. But if the mode does not use clear separators (for example, if you collapse your braces onto - the preceding statement in C or perl), `largest' is + the preceding statement in C or Perl), `largest' is probably the better alternative. function A function that will be passed the beginning and ending @@ -303,8 +300,8 @@ The possible settings for `align-region-separate' are: both of these parameters will be nil, in which case the function should return non-nil if it wants each rule to define its own section, or nil if it wants the largest - section found to be used as the common section for all rules - that occur there. + section found to be used as the common section for all + rules that occur there. list A list of markers within the buffer that represent where the section dividers lie. Be certain to use markers! For @@ -583,7 +580,7 @@ The possible settings for `align-region-separate' are: (regexp . "^\\s-*\\w+:\\(\\s-*\\).*;") (group . (1)) (modes . '(css-mode html-mode)))) - "*A list describing all of the available alignment rules. + "A list describing all of the available alignment rules. The format is: ((TITLE @@ -625,8 +622,8 @@ The following attributes are meaningful: the purposes of alignment. The \"alignment character\" is always the first character immediately following this parenthesis group. This attribute may also be a list of - integer, in which case multiple alignment characters will - be aligned, with the list of integer identifying the + integers, in which case multiple alignment characters will + be aligned, with the list of integers identifying the whitespace groups which precede them. The default for this attribute is 1. @@ -638,7 +635,7 @@ The following attributes are meaningful: `case-fold' If `regexp' is an ordinary regular expression string containing alphabetic character, sometimes you may want the search to proceed case-insensitively (for languages - that ignore case, such as pascal for example). In that + that ignore case, such as Pascal for example). In that case, set `case-fold' to a non-nil value, and the regular expression search will ignore case. If `regexp' is set to a function, that function must handle the job of ignoring @@ -781,7 +778,7 @@ The following attributes are meaningful: (regexp . "^\\s-*#\\s-*\\(if\\w*\\|endif\\)\\(.*\\)$") (group . 2) (modes . align-c++-modes))) - "*A list describing text that should be excluded from alignment. + "A list describing text that should be excluded from alignment. See the documentation for `align-rules-list' for more info." :type align-exclude-rules-list-type :group 'align) @@ -839,7 +836,7 @@ See the variable `align-exclude-rules-list' for more details.") (use-entity (regexp . "\\(\\s-+\\)use\\s-+entity"))) - "*Alignment rules for `vhdl-mode'. See `align-rules-list' for more info." + "Alignment rules for `vhdl-mode'. See `align-rules-list' for more info." :type align-rules-list-type :group 'align) @@ -909,15 +906,8 @@ on the format of these lists." ;;;###autoload (defun align-regexp (beg end regexp &optional group spacing repeat) "Align the current region using an ad-hoc rule read from the minibuffer. -BEG and END mark the limits of the region. This function will prompt -for the REGEXP to align with. If no prefix arg was specified, you -only need to supply the characters to be lined up and any preceding -whitespace is replaced. If a prefix arg was specified, the full -regexp with parenthesized whitespace should be supplied; it will also -prompt for which parenthesis GROUP within REGEXP to modify, the amount -of SPACING to use, and whether or not to REPEAT the rule throughout -the line. See `align-rules-list' for more information about these -options. +BEG and END mark the limits of the region. Interactively, this function +prompts for the regular expression REGEXP to align with. For example, let's say you had a list of phone numbers, and wanted to align them so that the opening parentheses would line up: @@ -928,8 +918,29 @@ align them so that the opening parentheses would line up: Joe (123) 456-7890 There is no predefined rule to handle this, but you could easily do it -using a REGEXP like \"(\". All you would have to do is to mark the -region, call `align-regexp' and type in that regular expression." +using a REGEXP like \"(\". Interactively, all you would have to do is +to mark the region, call `align-regexp' and enter that regular expression. + +REGEXP must contain at least one parenthesized subexpression, typically +whitespace of the form \"\\\\(\\\\s-*\\\\)\". In normal interactive use, +this is automatically added to the start of your regular expression after +you enter it. You only need to supply the characters to be lined up, and +any preceding whitespace is replaced. + +If you specify a prefix argument (or use this function non-interactively), +you must enter the full regular expression, including the subexpression. +The function also then prompts for which subexpression parenthesis GROUP +\(default 1) within REGEXP to modify, the amount of SPACING (default +`align-default-spacing') to use, and whether or not to REPEAT the rule +throughout the line. + +See `align-rules-list' for more information about these options. + +The non-interactive form of the previous example would look something like: + (align-regexp (point-min) (point-max) \"\\\\(\\\\s-*\\\\)(\") + +This function is a nothing more than a small wrapper that helps you +construct a rule to pass to `align-region', which does the real work." (interactive (append (list (region-beginning) (region-end)) @@ -946,6 +957,8 @@ region, call `align-regexp' and type in that regular expression." (list (concat "\\(\\s-*\\)" (read-string "Align regexp: ")) 1 align-default-spacing nil)))) + (or group (setq group 1)) + (or spacing (setq spacing align-default-spacing)) (let ((rule (list (list nil (cons 'regexp regexp) (cons 'group (abs group)) @@ -1107,7 +1120,7 @@ documentation for `align-region-separate' for more details." (setq seps (cdr seps)))) yes)))) -(defun align-adjust-col-for-rule (column rule spacing tab-stop) +(defun align-adjust-col-for-rule (column _rule spacing tab-stop) "Adjust COLUMN according to the given RULE. SPACING specifies how much spacing to use. TAB-STOP specifies whether SPACING refers to tab-stop boundaries." @@ -1117,13 +1130,8 @@ TAB-STOP specifies whether SPACING refers to tab-stop boundaries." column (if (not tab-stop) (+ column spacing) - (let ((stops tab-stop-list)) - (while stops - (if (and (> (car stops) column) - (= (setq spacing (1- spacing)) 0)) - (setq column (car stops) - stops nil) - (setq stops (cdr stops))))) + (dotimes (_ spacing) + (setq column (indent-next-tab-stop column))) column))) (defsubst align-column (pos) @@ -1162,7 +1170,7 @@ have been aligned. No changes will be made to the buffer." (justify (cdr (assq 'justify rule))) (col (or fixed 0)) (width 0) - ecol change look) + ecol change) ;; Determine the alignment column. (let ((a areas)) @@ -1202,7 +1210,10 @@ have been aligned. No changes will be made to the buffer." (gocol col) cur) (when area (if func - (funcall func (car area) (cdr area) change) + (funcall func + (marker-position (car area)) + (marker-position (cdr area)) + change) (if (not (and justify (consp (cdr area)))) (goto-char (cdr area)) @@ -1247,6 +1258,13 @@ have been aligned. No changes will be made to the buffer." (car props) (cdr props))))))))))) (setq areas (cdr areas)))))) +(defmacro align--set-marker (marker-var pos &optional type) + "If MARKER-VAR is a marker, move it to position POS. +Otherwise, create a new marker at position POS, with type TYPE." + `(if (markerp ,marker-var) + (move-marker ,marker-var ,pos) + (setq ,marker-var (copy-marker ,pos ,type)))) + (defun align-region (beg end separate rules exclude-rules &optional func) "Align a region based on a given set of alignment rules. @@ -1286,11 +1304,11 @@ purpose where you might want to know where the regions that the aligner would have dealt with are." (let ((end-mark (and end (copy-marker end t))) (real-beg beg) - (real-end end) (report (and (not func) align-large-region beg end (>= (- end beg) align-large-region))) (rule-index 1) - (rule-count (length rules))) + (rule-count (length rules)) + markers) (if (and align-indent-before-aligning real-beg end-mark) (indent-region real-beg end-mark nil)) (while rules @@ -1302,21 +1320,22 @@ aligner would have dealt with are." (unless (or (and modes (not (memq major-mode (eval (cdr modes))))) (and run-if (not (funcall (cdr run-if))))) - (let* ((current-case-fold case-fold-search) + (let* ((case-fold-search case-fold-search) (case-fold (assq 'case-fold rule)) (regexp (cdr (assq 'regexp rule))) (regfunc (and (functionp regexp) regexp)) (rulesep (assq 'separate rule)) (thissep (if rulesep (cdr rulesep) separate)) same (eol 0) - group group-c + search-start + groups group-c spacing spacing-c tab-stop tab-stop-c repeat repeat-c valid valid-c - pos-list first + first regions index - last-point b e + last-point save-match-data exclude-p align-props) @@ -1371,223 +1390,217 @@ aligner would have dealt with are." (if (not here) (goto-char end)) (forward-line) - (setq end (point) - end-mark (copy-marker end t)) + (setq end (point)) + (align--set-marker end-mark end t) (goto-char beg))) ;; If we have a region to align, and `func' is set and ;; reports back that the region is ok, then align it. (when (or (not func) (funcall func beg end rule)) - (unwind-protect - (let (exclude-areas) - ;; determine first of all where the exclusions - ;; lie in this region - (when exclude-rules - ;; guard against a problem with recursion and - ;; dynamic binding vs. lexical binding, since - ;; the call to `align-region' below will - ;; re-enter this function, and rebind - ;; `exclude-areas' - (set (setq exclude-areas - (make-symbol "align-exclude-areas")) - nil) - (align-region - beg end 'entire - exclude-rules nil - `(lambda (b e mode) - (or (and mode (listp mode)) - (set (quote ,exclude-areas) - (cons (cons b e) - ,exclude-areas))))) - (setq exclude-areas - (sort (symbol-value exclude-areas) - (function - (lambda (l r) - (>= (car l) (car r))))))) - - ;; set `case-fold-search' according to the - ;; (optional) `case-fold' property - (and case-fold - (setq case-fold-search (cdr case-fold))) - - ;; while we can find the rule in the alignment - ;; region.. - (while (and (< (point) end-mark) - (if regfunc - (funcall regfunc end-mark nil) - (re-search-forward regexp - end-mark t))) - - ;; give the user some indication of where we - ;; are, if it's a very large region being - ;; aligned - (if report - (let ((symbol (car rule))) - (if (and symbol (symbolp symbol)) - (message - "Aligning `%s' (rule %d of %d) %d%%..." - (symbol-name symbol) rule-index rule-count - (/ (* (- (point) real-beg) 100) - (- end-mark real-beg))) - (message - "Aligning %d%%..." - (/ (* (- (point) real-beg) 100) - (- end-mark real-beg)))))) - - ;; if the search ended us on the beginning of - ;; the next line, move back to the end of the - ;; previous line. - (if (bolp) - (forward-char -1)) - - ;; lookup the `group' attribute the first time - ;; that we need it - (unless group-c - (setq group (or (cdr (assq 'group rule)) 1)) - (if (listp group) - (setq first (car group)) - (setq first group group (list group))) - (setq group-c t)) - - (unless spacing-c - (setq spacing (cdr (assq 'spacing rule)) - spacing-c t)) - - (unless tab-stop-c - (setq tab-stop - (let ((rule-ts (assq 'tab-stop rule))) - (if rule-ts - (cdr rule-ts) - (if (symbolp align-to-tab-stop) - (symbol-value align-to-tab-stop) - align-to-tab-stop))) - tab-stop-c t)) - - ;; test whether we have found a match on the same - ;; line as a previous match - (if (> (point) eol) - (setq same nil - eol (save-excursion - (end-of-line) - (point-marker)))) - - ;; lookup the `repeat' attribute the first time - (or repeat-c - (setq repeat (cdr (assq 'repeat rule)) - repeat-c t)) - - ;; lookup the `valid' attribute the first time - (or valid-c - (setq valid (assq 'valid rule) - valid-c t)) - - ;; remember the beginning position of this rule - ;; match, and save the match-data, since either - ;; the `valid' form, or the code that searches for - ;; section separation, might alter it - (setq b (match-beginning first) - save-match-data (match-data)) - - ;; unless the `valid' attribute is set, and tells - ;; us that the rule is not valid at this point in - ;; the code.. - (unless (and valid (not (funcall (cdr valid)))) - - ;; look to see if this match begins a new - ;; section. If so, we should align what we've - ;; collected so far, and then begin collecting - ;; anew for the next alignment section - (if (and last-point - (align-new-section-p last-point b - thissep)) - (progn - (align-regions regions align-props - rule func) - (setq last-point (copy-marker b t) - regions nil - align-props nil)) - (setq last-point (copy-marker b t))) - - ;; restore the match data - (set-match-data save-match-data) - - ;; check whether the region to be aligned - ;; straddles an exclusion area - (let ((excls exclude-areas)) - (setq exclude-p nil) - (while excls - (if (and (< (match-beginning (car group)) - (cdar excls)) - (> (match-end (car (last group))) - (caar excls))) - (setq exclude-p t - excls nil) - (setq excls (cdr excls))))) - - ;; go through the list of parenthesis groups - ;; matching whitespace text to be - ;; contracted/expanded (or possibly - ;; justified, if the `justify' attribute was - ;; set) - (unless exclude-p - (let ((g group)) - (while g - - ;; we have to use markers, since - ;; `align-areas' may modify the buffer - (setq b (copy-marker - (match-beginning (car g)) t) - e (copy-marker (match-end (car g)) t)) - - ;; record this text region for alignment - (setq index (if same (1+ index) 0)) - (let ((region (cons b e)) - (props (cons - (if (listp spacing) - (car spacing) - spacing) - (if (listp tab-stop) - (car tab-stop) - tab-stop)))) - (if (nth index regions) - (setcar (nthcdr index regions) - (cons region - (nth index regions))) - (if regions - (progn - (nconc regions - (list (list region))) - (nconc align-props (list props))) - (setq regions - (list (list region))) - (setq align-props (list props))))) - - ;; if any further rule matches are - ;; found before `eol', then they are - ;; on the same line as this one; this - ;; can only happen if the `repeat' - ;; attribute is non-nil - (if (listp spacing) - (setq spacing (cdr spacing))) - (if (listp tab-stop) - (setq tab-stop (cdr tab-stop))) - (setq same t g (cdr g)))) - - ;; if `repeat' has not been set, move to - ;; the next line; don't bother searching - ;; anymore on this one - (if (and (not repeat) (not (bolp))) - (forward-line))))) - - ;; when they are no more matches for this rule, - ;; align whatever was left over - (if regions - (align-regions regions align-props rule func))) - - (setq case-fold-search current-case-fold))))))) + (let (rule-beg exclude-areas) + ;; determine first of all where the exclusions + ;; lie in this region + (when exclude-rules + (align-region + beg end 'entire + exclude-rules nil + (lambda (b e mode) + (or (and mode (listp mode)) + (setq exclude-areas + (cons (cons b e) + exclude-areas))))) + (setq exclude-areas + (nreverse + (sort exclude-areas #'car-less-than-car)))) + + ;; set `case-fold-search' according to the + ;; (optional) `case-fold' property + (and case-fold + (setq case-fold-search (cdr case-fold))) + + ;; while we can find the rule in the alignment + ;; region.. + (while (and (< (point) end-mark) + (setq search-start (point)) + (if regfunc + (funcall regfunc end-mark nil) + (re-search-forward regexp + end-mark t))) + + ;; give the user some indication of where we + ;; are, if it's a very large region being + ;; aligned + (if report + (let ((symbol (car rule))) + (if (and symbol (symbolp symbol)) + (message + "Aligning `%s' (rule %d of %d) %d%%..." + (symbol-name symbol) rule-index rule-count + (/ (* (- (point) real-beg) 100) + (- end-mark real-beg))) + (message + "Aligning %d%%..." + (/ (* (- (point) real-beg) 100) + (- end-mark real-beg)))))) + + ;; if the search ended us on the beginning of + ;; the next line, move back to the end of the + ;; previous line. + (if (and (bolp) (> (point) search-start)) + (forward-char -1)) + + ;; lookup the `group' attribute the first time + ;; that we need it + (unless group-c + (setq groups (or (cdr (assq 'group rule)) 1)) + (unless (listp groups) + (setq groups (list groups))) + (setq first (car groups))) + + (unless spacing-c + (setq spacing (cdr (assq 'spacing rule)) + spacing-c t)) + + (unless tab-stop-c + (setq tab-stop + (let ((rule-ts (assq 'tab-stop rule))) + (cond (rule-ts + (cdr rule-ts)) + ((symbolp align-to-tab-stop) + (symbol-value align-to-tab-stop)) + (t + align-to-tab-stop))) + tab-stop-c t)) + + ;; test whether we have found a match on the same + ;; line as a previous match + (when (> (point) eol) + (setq same nil) + (align--set-marker eol (line-end-position))) + + ;; lookup the `repeat' attribute the first time + (or repeat-c + (setq repeat (cdr (assq 'repeat rule)) + repeat-c t)) + + ;; lookup the `valid' attribute the first time + (or valid-c + (setq valid (assq 'valid rule) + valid-c t)) + + ;; remember the beginning position of this rule + ;; match, and save the match-data, since either + ;; the `valid' form, or the code that searches for + ;; section separation, might alter it + (setq rule-beg (match-beginning first) + save-match-data (match-data)) + + (or rule-beg + (error "No match for subexpression %s" first)) + + ;; unless the `valid' attribute is set, and tells + ;; us that the rule is not valid at this point in + ;; the code.. + (unless (and valid (not (funcall (cdr valid)))) + + ;; look to see if this match begins a new + ;; section. If so, we should align what we've + ;; collected so far, and then begin collecting + ;; anew for the next alignment section + (when (and last-point + (align-new-section-p last-point rule-beg + thissep)) + (align-regions regions align-props rule func) + (setq regions nil) + (setq align-props nil)) + (align--set-marker last-point rule-beg t) + + ;; restore the match data + (set-match-data save-match-data) + + ;; check whether the region to be aligned + ;; straddles an exclusion area + (let ((excls exclude-areas)) + (setq exclude-p nil) + (while excls + (if (and (< (match-beginning (car groups)) + (cdar excls)) + (> (match-end (car (last groups))) + (caar excls))) + (setq exclude-p t + excls nil) + (setq excls (cdr excls))))) + + ;; go through the parenthesis groups + ;; matching whitespace to be contracted or + ;; expanded (or possibly justified, if the + ;; `justify' attribute was set) + (unless exclude-p + (dolist (g groups) + ;; We must use markers, since + ;; `align-areas' may modify the buffer. + ;; Avoid polluting the markers. + (let* ((group-beg (copy-marker + (match-beginning g) t)) + (group-end (copy-marker + (match-end g) t)) + (region (cons group-beg group-end)) + (props (cons (if (listp spacing) + (car spacing) + spacing) + (if (listp tab-stop) + (car tab-stop) + tab-stop)))) + (push group-beg markers) + (push group-end markers) + (setq index (if same (1+ index) 0)) + (cond + ((nth index regions) + (setcar (nthcdr index regions) + (cons region + (nth index regions)))) + (regions + (nconc regions + (list (list region))) + (nconc align-props (list props))) + (t + (setq regions + (list (list region))) + (setq align-props (list props))))) + ;; If any further rule matches are found + ;; before `eol', they are on the same + ;; line as this one; this can only + ;; happen if the `repeat' attribute is + ;; non-nil. + (if (listp spacing) + (setq spacing (cdr spacing))) + (if (listp tab-stop) + (setq tab-stop (cdr tab-stop))) + (setq same t)) + + ;; if `repeat' has not been set, move to + ;; the next line; don't bother searching + ;; anymore on this one + (if (and (not repeat) (not (bolp))) + (forward-line)) + + ;; if the search did not change point, + ;; move forward to avoid an infinite loop + (if (= (point) search-start) + (forward-char))))) + + ;; when they are no more matches for this rule, + ;; align whatever was left over + (if regions + (align-regions regions align-props rule func)))))))) (setq rules (cdr rules) rule-index (1+ rule-index))) + ;; This function can use a lot of temporary markers, so instead of + ;; waiting for the next GC we delete them immediately (Bug#10047). + (when end-mark (set-marker end-mark nil)) + (dolist (m markers) + (set-marker m nil)) (if report (message "Aligning...done")))) @@ -1598,5 +1611,4 @@ aligner would have dealt with are." (run-hooks 'align-load-hook) -;;; arch-tag: ef79cccf-1db8-4888-a8a1-d7ce2d1532f7 ;;; align.el ends here