align.el 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620
  1. ;;; align.el --- align text to a specific column, by regexp -*- lexical-binding:t -*-
  2. ;; Copyright (C) 1999-2017 Free Software Foundation, Inc.
  3. ;; Author: John Wiegley <johnw@gnu.org>
  4. ;; Maintainer: emacs-devel@gnu.org
  5. ;; Keywords: convenience languages lisp
  6. ;; This file is part of GNU Emacs.
  7. ;; GNU Emacs is free software: you can redistribute it and/or modify
  8. ;; it under the terms of the GNU General Public License as published by
  9. ;; the Free Software Foundation, either version 3 of the License, or
  10. ;; (at your option) any later version.
  11. ;; GNU Emacs is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;; GNU General Public License for more details.
  15. ;; You should have received a copy of the GNU General Public License
  16. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;; This mode allows you to align regions in a context-sensitive fashion.
  19. ;; The classic use is to align assignments:
  20. ;;
  21. ;; int a = 1;
  22. ;; short foo = 2;
  23. ;; double blah = 4;
  24. ;;
  25. ;; becomes
  26. ;;
  27. ;; int a = 1;
  28. ;; short foo = 2;
  29. ;; double blah = 4;
  30. ;;; Usage:
  31. ;; There are several variables which define how certain "categories"
  32. ;; of syntax are to be treated. These variables go by the name
  33. ;; `align-CATEGORY-modes'. For example, "c++" is such a category.
  34. ;; There are several rules which apply to c++, but since several other
  35. ;; languages have a syntax similar to c++ (e.g., c, java, etc), these
  36. ;; modes are treated as belonging to the same category.
  37. ;;
  38. ;; If you want to add a new mode under a certain category, just
  39. ;; customize that list, or add the new mode manually. For example, to
  40. ;; make jde-mode a c++ category mode, use this code in your .emacs
  41. ;; file:
  42. ;;
  43. ;; (setq align-c++-modes (cons 'jde-mode align-c++-modes))
  44. ;; In some programming modes, it's useful to have the aligner run only
  45. ;; after indentation is performed. To achieve this, customize or set
  46. ;; the variable `align-indent-before-aligning' to t.
  47. ;;; Module Authors:
  48. ;; In order to incorporate align's functionality into your own
  49. ;; modules, there are only a few steps you have to follow.
  50. ;; 1. Require or load in the align.el library.
  51. ;;
  52. ;; 2. Define your alignment and exclusion rules lists, either
  53. ;; customizable or not.
  54. ;;
  55. ;; 3. In your mode function, set the variables
  56. ;; `align-mode-rules-list' and `align-mode-exclude-rules-list'
  57. ;; to your own rules lists.
  58. ;; If there is any need to add your mode name to one of the
  59. ;; align-?-modes variables (for example, `align-dq-string-modes'), use
  60. ;; `add-to-list', or some similar function which checks first to see
  61. ;; if the value is already there. Since the user may customize that
  62. ;; mode list, and then write your mode name into their init file,
  63. ;; causing the symbol already to be present the next time they load
  64. ;; your package.
  65. ;; Example:
  66. ;;
  67. ;; (require 'align)
  68. ;;
  69. ;; (defcustom my-align-rules-list
  70. ;; '((my-rule
  71. ;; (regexp . "Sample")))
  72. ;; :type align-rules-list-type
  73. ;; :group 'my-package)
  74. ;;
  75. ;; (put 'my-align-rules-list 'risky-local-variable t)
  76. ;;
  77. ;; (add-to-list 'align-dq-string-modes 'my-package-mode)
  78. ;; (add-to-list 'align-open-comment-modes 'my-package-mode)
  79. ;;
  80. ;; (defun my-mode ()
  81. ;; ...
  82. ;; (setq align-mode-rules-list my-align-rules-list))
  83. ;;
  84. ;; Note that if you need to install your own exclusion rules, then you
  85. ;; will also need to reproduce any double-quoted string, or open
  86. ;; comment exclusion rules that are defined in the standard
  87. ;; `align-exclude-rules-list'. At the moment there is no convenient
  88. ;; way to mix both mode-local and global rules lists.
  89. ;;; History:
  90. ;; Version 1.0 was created in the earlier part of 1996, using a very
  91. ;; simple algorithm that understand only basic regular expressions.
  92. ;; Parts of the code were broken up and included in vhdl-mode.el
  93. ;; around this time. After several comments from users, and a need to
  94. ;; find a more robust, higher performing algorithm, 2.0 was born in late
  95. ;; 1998. Many different approaches were taken (mostly due to the
  96. ;; complexity of TeX tables), but finally a scheme was discovered
  97. ;; which worked fairly well for most common usage cases. Development
  98. ;; beyond version 2.8 is not planned, except for problems that users
  99. ;; might encounter.
  100. ;;; Code:
  101. (defgroup align nil
  102. "Align text to a specific column, by regexp."
  103. :version "21.1"
  104. :group 'fill)
  105. ;;; User Variables:
  106. (defcustom align-load-hook nil
  107. "Hook that gets run after the aligner has been loaded."
  108. :type 'hook
  109. :group 'align)
  110. (defcustom align-indent-before-aligning nil
  111. "If non-nil, indent the marked region before aligning it."
  112. :type 'boolean
  113. :group 'align)
  114. (defcustom align-default-spacing 1
  115. "An integer that represents the default amount of padding to use.
  116. If `align-to-tab-stop' is non-nil, this will represent the number of
  117. tab stops to use for alignment, rather than the number of spaces.
  118. Each alignment rule can optionally override both this variable and
  119. `align-to-tab-stop'. See `align-rules-list'."
  120. :type 'integer
  121. :group 'align)
  122. (defcustom align-to-tab-stop 'indent-tabs-mode
  123. "If non-nil, alignments will always fall on a tab boundary.
  124. It may also be a symbol, whose value will be taken."
  125. :type '(choice (const nil) symbol)
  126. :group 'align)
  127. (defcustom align-region-heuristic 500
  128. "If non-nil, used as a heuristic by `align-current'.
  129. Since each alignment rule can possibly have its own set of alignment
  130. sections (whenever `align-region-separate' is non-nil, and not a
  131. string), this heuristic is used to determine how far before and after
  132. point we should search in looking for a region separator. Larger
  133. values can mean slower performance in large files, although smaller
  134. values may cause unexpected behavior at times."
  135. :type 'integer
  136. :group 'align)
  137. (defcustom align-highlight-change-face 'highlight
  138. "The face to highlight with if changes are necessary."
  139. :type 'face
  140. :group 'align)
  141. (defcustom align-highlight-nochange-face 'secondary-selection
  142. "The face to highlight with if no changes are necessary."
  143. :type 'face
  144. :group 'align)
  145. (defcustom align-large-region 10000
  146. "If an integer, defines what constitutes a \"large\" region.
  147. If nil, then no messages will ever be printed to the minibuffer."
  148. :type 'integer
  149. :group 'align)
  150. (defcustom align-c++-modes '(c++-mode c-mode java-mode)
  151. "A list of modes whose syntax resembles C/C++."
  152. :type '(repeat symbol)
  153. :group 'align)
  154. (defcustom align-perl-modes '(perl-mode cperl-mode)
  155. "A list of modes where Perl syntax is to be seen."
  156. :type '(repeat symbol)
  157. :group 'align)
  158. (defcustom align-lisp-modes
  159. '(emacs-lisp-mode lisp-interaction-mode lisp-mode scheme-mode)
  160. "A list of modes whose syntax resembles Lisp."
  161. :type '(repeat symbol)
  162. :group 'align)
  163. (defcustom align-tex-modes
  164. '(tex-mode plain-tex-mode latex-mode slitex-mode)
  165. "A list of modes whose syntax resembles TeX (and family)."
  166. :type '(repeat symbol)
  167. :group 'align)
  168. (defcustom align-text-modes '(text-mode outline-mode)
  169. "A list of modes whose content is plain text."
  170. :type '(repeat symbol)
  171. :group 'align)
  172. (defcustom align-dq-string-modes
  173. (append align-lisp-modes align-c++-modes align-perl-modes
  174. '(python-mode))
  175. "A list of modes where double quoted strings should be excluded."
  176. :type '(repeat symbol)
  177. :group 'align)
  178. (defcustom align-sq-string-modes
  179. (append align-perl-modes '(python-mode))
  180. "A list of modes where single quoted strings should be excluded."
  181. :type '(repeat symbol)
  182. :group 'align)
  183. (defcustom align-open-comment-modes
  184. (append align-lisp-modes align-c++-modes align-perl-modes
  185. '(python-mode makefile-mode))
  186. "A list of modes with a single-line comment syntax.
  187. These are comments as in Lisp, which have a beginning, but end with
  188. the line (i.e., `comment-end' is an empty string)."
  189. :type '(repeat symbol)
  190. :group 'align)
  191. (defcustom align-region-separate "^\\s-*[{}]?\\s-*$"
  192. "Select the method by which alignment sections will be separated.
  193. If this is a symbol, that symbol's value will be used.
  194. For the sake of clarification, consider the following example, which
  195. will be referred to in the descriptions below.
  196. int alpha = 1; /* one */
  197. double beta = 2.0;
  198. long gamma; /* ten */
  199. unsigned int delta = 1; /* one */
  200. long double epsilon = 3.0;
  201. long long omega; /* ten */
  202. The possible settings for `align-region-separate' are:
  203. `entire' The entire region being aligned will be considered as a
  204. single alignment section. Assuming that comments were not
  205. being aligned to a particular column, the example would
  206. become:
  207. int alpha = 1; /* one */
  208. double beta = 2.0;
  209. long gamma; /* ten */
  210. unsigned int delta = 1; /* one */
  211. long double epsilon;
  212. long long chi = 10; /* ten */
  213. `group' Each contiguous set of lines where a specific alignment
  214. occurs is considered a section for that alignment rule.
  215. Note that each rule may have any entirely different set
  216. of section divisions than another.
  217. int alpha = 1; /* one */
  218. double beta = 2.0;
  219. long gamma; /* ten */
  220. unsigned int delta = 1; /* one */
  221. long double epsilon;
  222. long long chi = 10; /* ten */
  223. `largest' When contiguous rule sets overlap, the largest section
  224. described will be taken as the alignment section for each
  225. rule touched by that section.
  226. int alpha = 1; /* one */
  227. double beta = 2.0;
  228. long gamma; /* ten */
  229. unsigned int delta = 1; /* one */
  230. long double epsilon;
  231. long long chi = 10; /* ten */
  232. NOTE: This option is not supported yet, due to algorithmic
  233. issues which haven't been satisfactorily resolved. There
  234. are ways to do it, but they're both ugly and resource
  235. consumptive.
  236. regexp A regular expression string which defines the section
  237. divider. If the mode you're in has a consistent divider
  238. between sections, the behavior will be very similar to
  239. `largest', and faster. But if the mode does not use clear
  240. separators (for example, if you collapse your braces onto
  241. the preceding statement in C or Perl), `largest' is
  242. probably the better alternative.
  243. function A function that will be passed the beginning and ending
  244. locations of the region in which to look for the section
  245. separator. At the very beginning of the attempt to align,
  246. both of these parameters will be nil, in which case the
  247. function should return non-nil if it wants each rule to
  248. define its own section, or nil if it wants the largest
  249. section found to be used as the common section for all
  250. rules that occur there.
  251. list A list of markers within the buffer that represent where
  252. the section dividers lie. Be certain to use markers! For
  253. when the aligning begins, the ensuing contract/expanding of
  254. whitespace will throw off any non-marker positions.
  255. This method is intended for use in Lisp programs, and not
  256. by the user."
  257. :type '(choice
  258. (const :tag "Entire region is one section" entire)
  259. (const :tag "Align by contiguous groups" group)
  260. ; (const largest)
  261. (regexp :tag "Regexp defines section boundaries")
  262. (function :tag "Function defines section boundaries"))
  263. :group 'align)
  264. (put 'align-region-separate 'risky-local-variable t)
  265. (defvar align-rules-list-type
  266. '(repeat
  267. (cons
  268. :tag "Alignment rule"
  269. (symbol :tag "Title")
  270. (cons :tag "Required attributes"
  271. (cons :tag "Regexp"
  272. (const :tag "(Regular expression to match)" regexp)
  273. (choice :value "\\(\\s-+\\)" regexp function))
  274. (repeat
  275. :tag "Optional attributes"
  276. (choice
  277. (cons :tag "Repeat"
  278. (const :tag "(Repeat this rule throughout line)"
  279. repeat)
  280. (boolean :value t))
  281. (cons :tag "Paren group"
  282. (const :tag "(Parenthesis group to use)" group)
  283. (choice :value 2
  284. integer (repeat integer)))
  285. (cons :tag "Modes"
  286. (const :tag "(Modes where this rule applies)" modes)
  287. (sexp :value (text-mode)))
  288. (cons :tag "Case-fold"
  289. (const :tag "(Should case be ignored for this rule)"
  290. case-fold)
  291. (boolean :value t))
  292. (cons :tag "To Tab Stop"
  293. (const :tag "(Should rule align to tab stops)"
  294. tab-stop)
  295. (boolean :value nil))
  296. (cons :tag "Valid"
  297. (const :tag "(Return non-nil if rule is valid)"
  298. valid)
  299. (function :value t))
  300. (cons :tag "Run If"
  301. (const :tag "(Return non-nil if rule should run)"
  302. run-if)
  303. (function :value t))
  304. (cons :tag "Column"
  305. (const :tag "(Column to fix alignment at)" column)
  306. (choice :value comment-column
  307. integer symbol))
  308. (cons :tag "Spacing"
  309. (const :tag "(Amount of spacing to use)" spacing)
  310. (integer :value 1))
  311. (cons :tag "Justify"
  312. (const :tag "(Should text be right justified)"
  313. justify)
  314. (boolean :value t))
  315. ;; make sure this stays up-to-date with any changes
  316. ;; in `align-region-separate'
  317. (cons :tag "Separate"
  318. (const :tag "(Separation to use for this rule)"
  319. separate)
  320. (choice :value "^\\s-*$"
  321. (const entire)
  322. (const group)
  323. ; (const largest)
  324. regexp function)))))))
  325. "The `type' form for any `align-rules-list' variable.")
  326. (defcustom align-rules-list
  327. `((lisp-second-arg
  328. (regexp . "\\(^\\s-+[^( \t\n]\\|(\\(\\S-+\\)\\s-+\\)\\S-+\\(\\s-+\\)")
  329. (group . 3)
  330. (modes . align-lisp-modes)
  331. (run-if . ,(function (lambda () current-prefix-arg))))
  332. (lisp-alist-dot
  333. (regexp . "\\(\\s-*\\)\\.\\(\\s-*\\)")
  334. (group . (1 2))
  335. (modes . align-lisp-modes))
  336. (open-comment
  337. (regexp . ,(function
  338. (lambda (end reverse)
  339. (funcall (if reverse 're-search-backward
  340. 're-search-forward)
  341. (concat "[^ \t\n\\\\]"
  342. (regexp-quote comment-start)
  343. "\\(.+\\)$") end t))))
  344. (modes . align-open-comment-modes))
  345. (c-macro-definition
  346. (regexp . "^\\s-*#\\s-*define\\s-+\\S-+\\(\\s-+\\)")
  347. (modes . align-c++-modes))
  348. (c-variable-declaration
  349. (regexp . ,(concat "[*&0-9A-Za-z_]>?[&*]*\\(\\s-+[*&]*\\)"
  350. "[A-Za-z_][0-9A-Za-z:_]*\\s-*\\(\\()\\|"
  351. "=[^=\n].*\\|(.*)\\|\\(\\[.*\\]\\)*\\)?"
  352. "\\s-*[;,]\\|)\\s-*$\\)"))
  353. (group . 1)
  354. (modes . align-c++-modes)
  355. (justify . t)
  356. (valid
  357. . ,(function
  358. (lambda ()
  359. (not (or (save-excursion
  360. (goto-char (match-beginning 1))
  361. (backward-word 1)
  362. (looking-at
  363. "\\(goto\\|return\\|new\\|delete\\|throw\\)"))
  364. (if (and (boundp 'font-lock-mode) font-lock-mode)
  365. (eq (get-text-property (point) 'face)
  366. 'font-lock-comment-face)
  367. (eq (caar (c-guess-basic-syntax)) 'c))))))))
  368. (c-assignment
  369. (regexp . ,(concat "[^-=!^&*+<>/| \t\n]\\(\\s-*[-=!^&*+<>/|]*\\)"
  370. "=\\(\\s-*\\)\\([^= \t\n]\\|$\\)"))
  371. (group . (1 2))
  372. (modes . align-c++-modes)
  373. (justify . t)
  374. (tab-stop . nil))
  375. (perl-assignment
  376. (regexp . ,(concat "[^=!^&*-+<>/| \t\n]\\(\\s-*\\)=[~>]?"
  377. "\\(\\s-*\\)\\([^>= \t\n]\\|$\\)"))
  378. (group . (1 2))
  379. (modes . align-perl-modes)
  380. (tab-stop . nil))
  381. (python-assignment
  382. (regexp . ,(concat "[^=!<> \t\n]\\(\\s-*\\)="
  383. "\\(\\s-*\\)\\([^>= \t\n]\\|$\\)"))
  384. (group . (1 2))
  385. (modes . '(python-mode))
  386. (tab-stop . nil))
  387. (make-assignment
  388. (regexp . "^\\s-*\\w+\\(\\s-*\\):?=\\(\\s-*\\)\\([^\t\n \\\\]\\|$\\)")
  389. (group . (1 2))
  390. (modes . '(makefile-mode))
  391. (tab-stop . nil))
  392. (c-comma-delimiter
  393. (regexp . ",\\(\\s-*\\)[^/ \t\n]")
  394. (repeat . t)
  395. (modes . align-c++-modes)
  396. (run-if . ,(function (lambda () current-prefix-arg))))
  397. ; (valid
  398. ; . ,(function
  399. ; (lambda ()
  400. ; (memq (caar (c-guess-basic-syntax))
  401. ; '(brace-list-intro
  402. ; brace-list-entry
  403. ; brace-entry-open))))))
  404. ;; With a prefix argument, comma delimiter will be aligned. Since
  405. ;; perl-mode doesn't give us enough syntactic information (and we
  406. ;; don't do our own parsing yet), this rule is too destructive to
  407. ;; run normally.
  408. (basic-comma-delimiter
  409. (regexp . ",\\(\\s-*\\)[^# \t\n]")
  410. (repeat . t)
  411. (modes . (append align-perl-modes '(python-mode)))
  412. (run-if . ,(function (lambda () current-prefix-arg))))
  413. (c++-comment
  414. (regexp . "\\(\\s-*\\)\\(//.*\\|/\\*.*\\*/\\s-*\\)$")
  415. (modes . align-c++-modes)
  416. (column . comment-column)
  417. (valid . ,(function
  418. (lambda ()
  419. (save-excursion
  420. (goto-char (match-beginning 1))
  421. (not (bolp)))))))
  422. (c-chain-logic
  423. (regexp . "\\(\\s-*\\)\\(&&\\|||\\|\\<and\\>\\|\\<or\\>\\)")
  424. (modes . align-c++-modes)
  425. (valid . ,(function
  426. (lambda ()
  427. (save-excursion
  428. (goto-char (match-end 2))
  429. (looking-at "\\s-*\\(/[*/]\\|$\\)"))))))
  430. (perl-chain-logic
  431. (regexp . "\\(\\s-*\\)\\(&&\\|||\\|\\<and\\>\\|\\<or\\>\\)")
  432. (modes . align-perl-modes)
  433. (valid . ,(function
  434. (lambda ()
  435. (save-excursion
  436. (goto-char (match-end 2))
  437. (looking-at "\\s-*\\(#\\|$\\)"))))))
  438. (python-chain-logic
  439. (regexp . "\\(\\s-*\\)\\(\\<and\\>\\|\\<or\\>\\)")
  440. (modes . '(python-mode))
  441. (valid . ,(function
  442. (lambda ()
  443. (save-excursion
  444. (goto-char (match-end 2))
  445. (looking-at "\\s-*\\(#\\|$\\|\\\\\\)"))))))
  446. (c-macro-line-continuation
  447. (regexp . "\\(\\s-*\\)\\\\$")
  448. (modes . align-c++-modes)
  449. (column . c-backslash-column))
  450. ; (valid
  451. ; . ,(function
  452. ; (lambda ()
  453. ; (memq (caar (c-guess-basic-syntax))
  454. ; '(cpp-macro cpp-macro-cont))))))
  455. (basic-line-continuation
  456. (regexp . "\\(\\s-*\\)\\\\$")
  457. (modes . '(python-mode makefile-mode)))
  458. (tex-record-separator
  459. (regexp . ,(function
  460. (lambda (end reverse)
  461. (align-match-tex-pattern "&" end reverse))))
  462. (group . (1 2))
  463. (modes . align-tex-modes)
  464. (repeat . t))
  465. (tex-tabbing-separator
  466. (regexp . ,(function
  467. (lambda (end reverse)
  468. (align-match-tex-pattern "\\\\[=>]" end reverse))))
  469. (group . (1 2))
  470. (modes . align-tex-modes)
  471. (repeat . t)
  472. (run-if . ,(function
  473. (lambda ()
  474. (eq major-mode 'latex-mode)))))
  475. (tex-record-break
  476. (regexp . "\\(\\s-*\\)\\\\\\\\")
  477. (modes . align-tex-modes))
  478. ;; With a numeric prefix argument, or C-u, space delimited text
  479. ;; tables will be aligned.
  480. (text-column
  481. (regexp . "\\(^\\|\\S-\\)\\([ \t]+\\)\\(\\S-\\|$\\)")
  482. (group . 2)
  483. (modes . align-text-modes)
  484. (repeat . t)
  485. (run-if . ,(function
  486. (lambda ()
  487. (and current-prefix-arg
  488. (not (eq '- current-prefix-arg)))))))
  489. ;; With a negative prefix argument, lists of dollar figures will
  490. ;; be aligned.
  491. (text-dollar-figure
  492. (regexp . "\\$?\\(\\s-+[0-9]+\\)\\.")
  493. (modes . align-text-modes)
  494. (justify . t)
  495. (run-if . ,(function
  496. (lambda ()
  497. (eq '- current-prefix-arg)))))
  498. (css-declaration
  499. (regexp . "^\\s-*\\(?:\\w-?\\)+:\\(\\s-*\\).*;")
  500. (group . (1))
  501. (modes . '(css-mode html-mode))))
  502. "A list describing all of the available alignment rules.
  503. The format is:
  504. ((TITLE
  505. (ATTRIBUTE . VALUE) ...)
  506. ...)
  507. The following attributes are meaningful:
  508. `regexp' This required attribute must be either a string describing
  509. a regular expression, or a function (described below).
  510. For every line within the section that this regular
  511. expression matches, the given rule will be applied to that
  512. line. The exclusion rules denote which part(s) of the
  513. line should not be modified; the alignment rules cause the
  514. identified whitespace group to be contracted/expanded such
  515. that the \"alignment character\" (the character
  516. immediately following the identified parenthesis group),
  517. occurs in the same column for every line within the
  518. alignment section (see `align-region-separate' for a
  519. description of how the region is broken up into alignment
  520. sections).
  521. The `regexp' attribute describes how the text should be
  522. treated. Within this regexp, there must be at least one
  523. group of characters (typically whitespace) identified by
  524. the special opening and closing parens used in regexp
  525. expressions (`\\\\(' and `\\\\)') (see the Emacs manual on
  526. the syntax of regular expressions for more info).
  527. If `regexp' is a function, it will be called as a
  528. replacement for `re-search-forward'. This means that it
  529. should return nil if nothing is found to match the rule,
  530. or it should set the match data appropriately, move point
  531. to the end of the match, and return the value of point.
  532. `group' For exclusion rules, the group identifies the range of
  533. characters that should be ignored. For alignment rules,
  534. these are the characters that will be deleted/expanded for
  535. the purposes of alignment. The \"alignment character\" is
  536. always the first character immediately following this
  537. parenthesis group. This attribute may also be a list of
  538. integers, in which case multiple alignment characters will
  539. be aligned, with the list of integers identifying the
  540. whitespace groups which precede them. The default for
  541. this attribute is 1.
  542. `modes' The `modes' attribute, if set, should name a list of
  543. major modes -- or evaluate to such a value -- in which the
  544. rule is valid. If not set, the rule will apply to all
  545. modes.
  546. `case-fold' If `regexp' is an ordinary regular expression string
  547. containing alphabetic character, sometimes you may want
  548. the search to proceed case-insensitively (for languages
  549. that ignore case, such as Pascal for example). In that
  550. case, set `case-fold' to a non-nil value, and the regular
  551. expression search will ignore case. If `regexp' is set to
  552. a function, that function must handle the job of ignoring
  553. case by itself.
  554. `tab-stop' If the `tab-stop' attribute is set, and non-nil, the
  555. alignment character will always fall on a tab stop
  556. (whether it uses tabs to get there or not depends on the
  557. value of `indent-tabs-mode'). If the `tab-stop' attribute
  558. is set to nil, tab stops will never be used. Otherwise,
  559. the value of `align-to-tab-stop' determines whether or not
  560. to align to a tab stop. The `tab-stop' attribute may also
  561. be a list of t or nil values, corresponding to the number
  562. of parenthesis groups specified by the `group' attribute.
  563. `repeat' If the `repeat' attribute is present, and non-nil, the
  564. rule will be applied to the line continuously until no
  565. further matches are found.
  566. `valid' If the `valid' attribute is set, it will be used to
  567. determine whether the rule should be invoked. This form
  568. is evaluated after the regular expression match has been
  569. performed, so that it is possible to use the results of
  570. that match to determine whether the alignment should be
  571. performed. The buffer should not be modified during the
  572. evaluation of this form.
  573. `run-if' Like `valid', the `run-if' attribute tests whether the
  574. rule should be run at all -- even before any searches are
  575. done to determine if the rule applies to the alignment
  576. region. This can save time, since `run-if' will only be
  577. run once for each rule. If it returns nil, the rule will
  578. not be attempted.
  579. `column' For alignment rules, if the `column' attribute is set --
  580. which must be an integer, or a symbol whose value is an
  581. integer -- it will be used as the column in which to align
  582. the alignment character. If the text on a particular line
  583. happens to overrun that column, a single space character,
  584. or tab stop (see `align-to-tab-stop') will be added
  585. between the last text character and the alignment
  586. character.
  587. `spacing' Alignment rules may also override the amount of spacing
  588. that would normally be used by providing a `spacing'
  589. attribute. This must be an integer, or a list of integers
  590. corresponding to the number of parenthesis groups matched
  591. by the `group' attribute. If a list of value is used, and
  592. any of those values is nil, `align-default-spacing' will
  593. be used for that subgroup. See `align-default-spacing'
  594. for more details on spacing, tab stops, and how to
  595. indicate how much spacing should be used. If TAB-STOP is
  596. present, it will override the value of `align-to-tab-stop'
  597. for that rule.
  598. `justify' It is possible with `regexp' and `group' to identify a
  599. character group that contains more than just whitespace
  600. characters. By default, any non-whitespace characters in
  601. that group will also be deleted while aligning the
  602. alignment character. However, if the `justify' attribute
  603. is set to a non-nil value, only the initial whitespace
  604. characters within that group will be deleted. This has
  605. the effect of right-justifying the characters that remain,
  606. and can be used for outdenting or just plain old right-
  607. justification.
  608. `separate' Each rule can define its own section separator, which
  609. describes how to identify the separation of \"sections\"
  610. within the region to be aligned. Setting the `separate'
  611. attribute overrides the value of `align-region-separate'
  612. (see the documentation of that variable for possible
  613. values), and any separation argument passed to `align'."
  614. :type align-rules-list-type
  615. :group 'align)
  616. (put 'align-rules-list 'risky-local-variable t)
  617. (defvar align-exclude-rules-list-type
  618. '(repeat
  619. (cons
  620. :tag "Exclusion rule"
  621. (symbol :tag "Title")
  622. (cons :tag "Required attributes"
  623. (cons :tag "Regexp"
  624. (const :tag "(Regular expression to match)" regexp)
  625. (choice :value "\\(\\s-+\\)" regexp function))
  626. (repeat
  627. :tag "Optional attributes"
  628. (choice
  629. (cons :tag "Repeat"
  630. (const :tag "(Repeat this rule throughout line)"
  631. repeat)
  632. (boolean :value t))
  633. (cons :tag "Paren group"
  634. (const :tag "(Parenthesis group to use)" group)
  635. (choice :value 2
  636. integer (repeat integer)))
  637. (cons :tag "Modes"
  638. (const :tag "(Modes where this rule applies)" modes)
  639. (sexp :value (text-mode)))
  640. (cons :tag "Case-fold"
  641. (const :tag "(Should case be ignored for this rule)"
  642. case-fold)
  643. (boolean :value t)))))))
  644. "The `type' form for any `align-exclude-rules-list' variable.")
  645. (defcustom align-exclude-rules-list
  646. `((exc-dq-string
  647. (regexp . "\"\\([^\"\n]+\\)\"")
  648. (repeat . t)
  649. (modes . align-dq-string-modes))
  650. (exc-sq-string
  651. (regexp . "'\\([^'\n]+\\)'")
  652. (repeat . t)
  653. (modes . align-sq-string-modes))
  654. (exc-open-comment
  655. (regexp
  656. . ,(function
  657. (lambda (end reverse)
  658. (funcall (if reverse 're-search-backward
  659. 're-search-forward)
  660. (concat "[^ \t\n\\\\]"
  661. (regexp-quote comment-start)
  662. "\\(.+\\)$") end t))))
  663. (modes . align-open-comment-modes))
  664. (exc-c-comment
  665. (regexp . "/\\*\\(.+\\)\\*/")
  666. (repeat . t)
  667. (modes . align-c++-modes))
  668. (exc-c-func-params
  669. (regexp . "(\\([^)\n]+\\))")
  670. (repeat . t)
  671. (modes . align-c++-modes))
  672. (exc-c-macro
  673. (regexp . "^\\s-*#\\s-*\\(if\\w*\\|endif\\)\\(.*\\)$")
  674. (group . 2)
  675. (modes . align-c++-modes)))
  676. "A list describing text that should be excluded from alignment.
  677. See the documentation for `align-rules-list' for more info."
  678. :type align-exclude-rules-list-type
  679. :group 'align)
  680. (put 'align-exclude-rules-list 'risky-local-variable t)
  681. ;;; Internal Variables:
  682. (defvar align-mode-rules-list nil
  683. "Alignment rules specific to the current major mode.
  684. See the variable `align-rules-list' for more details.")
  685. (make-variable-buffer-local 'align-mode-rules-list)
  686. (defvar align-mode-exclude-rules-list nil
  687. "Alignment exclusion rules specific to the current major mode.
  688. See the variable `align-exclude-rules-list' for more details.")
  689. (make-variable-buffer-local 'align-mode-exclude-rules-list)
  690. (defvar align-highlight-overlays nil
  691. "The current overlays highlighting the text matched by a rule.")
  692. (defvar align-regexp-history nil
  693. "Input history for the full user-entered regex in `align-regexp'")
  694. ;; Sample extension rule set, for vhdl-mode. This should properly be
  695. ;; in vhdl-mode.el itself.
  696. (defcustom align-vhdl-rules-list
  697. `((vhdl-declaration
  698. (regexp . "\\(signal\\|variable\\|constant\\)\\(\\s-+\\)\\S-")
  699. (group . 2))
  700. (vhdl-case
  701. (regexp . "\\(others\\|[^ \t\n=<]\\)\\(\\s-*\\)=>\\(\\s-*\\)\\S-")
  702. (group . (2 3))
  703. (valid
  704. . ,(function
  705. (lambda ()
  706. (not (string= (downcase (match-string 1))
  707. "others"))))))
  708. (vhdl-colon
  709. (regexp . "[^ \t\n:]\\(\\s-*\\):\\(\\s-*\\)[^=\n]")
  710. (group . (1 2)))
  711. (direction
  712. (regexp . ":\\s-*\\(in\\|out\\|inout\\|buffer\\)\\(\\s-*\\)")
  713. (group . 2))
  714. (sig-assign
  715. (regexp . "[^ \t\n=<]\\(\\s-*\\)<=\\(\\s-*\\)\\S-")
  716. (group . (1 2)))
  717. (var-assign
  718. (regexp . "[^ \t\n:]\\(\\s-*\\):="))
  719. (use-entity
  720. (regexp . "\\(\\s-+\\)use\\s-+entity")))
  721. "Alignment rules for `vhdl-mode'. See `align-rules-list' for more info."
  722. :type align-rules-list-type
  723. :group 'align)
  724. (put 'align-vhdl-rules-list 'risky-local-variable t)
  725. (defun align-set-vhdl-rules ()
  726. "Setup the `align-mode-rules-list' variable for `vhdl-mode'."
  727. (setq align-mode-rules-list align-vhdl-rules-list))
  728. (add-hook 'vhdl-mode-hook 'align-set-vhdl-rules)
  729. (add-to-list 'align-dq-string-modes 'vhdl-mode)
  730. (add-to-list 'align-open-comment-modes 'vhdl-mode)
  731. ;;; User Functions:
  732. ;;;###autoload
  733. (defun align (beg end &optional separate rules exclude-rules)
  734. "Attempt to align a region based on a set of alignment rules.
  735. BEG and END mark the region. If BEG and END are specifically set to
  736. nil (this can only be done programmatically), the beginning and end of
  737. the current alignment section will be calculated based on the location
  738. of point, and the value of `align-region-separate' (or possibly each
  739. rule's `separate' attribute).
  740. If SEPARATE is non-nil, it overrides the value of
  741. `align-region-separate' for all rules, except those that have their
  742. `separate' attribute set.
  743. RULES and EXCLUDE-RULES, if either is non-nil, will replace the
  744. default rule lists defined in `align-rules-list' and
  745. `align-exclude-rules-list'. See `align-rules-list' for more details
  746. on the format of these lists."
  747. (interactive "r")
  748. (let ((separator
  749. (or separate
  750. (if (and (symbolp align-region-separate)
  751. (boundp align-region-separate))
  752. (symbol-value align-region-separate)
  753. align-region-separate)
  754. 'entire)))
  755. (if (not (or ;(eq separator 'largest)
  756. (and (functionp separator)
  757. (not (funcall separator nil nil)))))
  758. (align-region beg end separator
  759. (or rules align-mode-rules-list align-rules-list)
  760. (or exclude-rules align-mode-exclude-rules-list
  761. align-exclude-rules-list))
  762. (let ((sec-first end)
  763. (sec-last beg))
  764. (align-region beg end
  765. separator
  766. nil ; rules
  767. (or exclude-rules
  768. align-mode-exclude-rules-list
  769. align-exclude-rules-list)
  770. (lambda (b e mode)
  771. (when (consp mode)
  772. (setq sec-first (min sec-first b)
  773. sec-last (max sec-last e)))))
  774. (if (< sec-first sec-last)
  775. (align-region sec-first sec-last 'entire
  776. (or rules align-mode-rules-list align-rules-list)
  777. (or exclude-rules align-mode-exclude-rules-list
  778. align-exclude-rules-list)))))))
  779. ;;;###autoload
  780. (defun align-regexp (beg end regexp &optional group spacing repeat)
  781. "Align the current region using an ad-hoc rule read from the minibuffer.
  782. BEG and END mark the limits of the region. Interactively, this function
  783. prompts for the regular expression REGEXP to align with.
  784. For example, let's say you had a list of phone numbers, and wanted to
  785. align them so that the opening parentheses would line up:
  786. Fred (123) 456-7890
  787. Alice (123) 456-7890
  788. Mary-Anne (123) 456-7890
  789. Joe (123) 456-7890
  790. There is no predefined rule to handle this, but you could easily do it
  791. using a REGEXP like \"(\". Interactively, all you would have to do is
  792. to mark the region, call `align-regexp' and enter that regular expression.
  793. REGEXP must contain at least one parenthesized subexpression, typically
  794. whitespace of the form \"\\\\(\\\\s-*\\\\)\". In normal interactive use,
  795. this is automatically added to the start of your regular expression after
  796. you enter it. You only need to supply the characters to be lined up, and
  797. any preceding whitespace is replaced.
  798. If you specify a prefix argument (or use this function non-interactively),
  799. you must enter the full regular expression, including the subexpression.
  800. The function also then prompts for which subexpression parenthesis GROUP
  801. \(default 1) within REGEXP to modify, the amount of SPACING (default
  802. `align-default-spacing') to use, and whether or not to REPEAT the rule
  803. throughout the line.
  804. See `align-rules-list' for more information about these options.
  805. The non-interactive form of the previous example would look something like:
  806. (align-regexp (point-min) (point-max) \"\\\\(\\\\s-*\\\\)(\")
  807. This function is a nothing more than a small wrapper that helps you
  808. construct a rule to pass to `align-region', which does the real work."
  809. (interactive
  810. (append
  811. (list (region-beginning) (region-end))
  812. (if current-prefix-arg
  813. (list (read-string "Complex align using regexp: "
  814. "\\(\\s-*\\)" 'align-regexp-history)
  815. (string-to-number
  816. (read-string
  817. "Parenthesis group to modify (justify if negative): " "1"))
  818. (string-to-number
  819. (read-string "Amount of spacing (or column if negative): "
  820. (number-to-string align-default-spacing)))
  821. (y-or-n-p "Repeat throughout line? "))
  822. (list (concat "\\(\\s-*\\)"
  823. (read-string "Align regexp: "))
  824. 1 align-default-spacing nil))))
  825. (or group (setq group 1))
  826. (or spacing (setq spacing align-default-spacing))
  827. (let ((rule
  828. (list (list nil (cons 'regexp regexp)
  829. (cons 'group (abs group))
  830. (if (< group 0)
  831. (cons 'justify t)
  832. (cons 'bogus nil))
  833. (if (>= spacing 0)
  834. (cons 'spacing spacing)
  835. (cons 'column (abs spacing)))
  836. (cons 'repeat repeat)))))
  837. (align-region beg end 'entire rule nil nil)))
  838. ;;;###autoload
  839. (defun align-entire (beg end &optional rules exclude-rules)
  840. "Align the selected region as if it were one alignment section.
  841. BEG and END mark the extent of the region. If RULES or EXCLUDE-RULES
  842. is set to a list of rules (see `align-rules-list'), it can be used to
  843. override the default alignment rules that would have been used to
  844. align that section."
  845. (interactive "r")
  846. (align beg end 'entire rules exclude-rules))
  847. ;;;###autoload
  848. (defun align-current (&optional rules exclude-rules)
  849. "Call `align' on the current alignment section.
  850. This function assumes you want to align only the current section, and
  851. so saves you from having to specify the region. If RULES or
  852. EXCLUDE-RULES is set to a list of rules (see `align-rules-list'), it
  853. can be used to override the default alignment rules that would have
  854. been used to align that section."
  855. (interactive)
  856. (align nil nil nil rules exclude-rules))
  857. ;;;###autoload
  858. (defun align-highlight-rule (beg end title &optional rules exclude-rules)
  859. "Highlight the whitespace which a given rule would have modified.
  860. BEG and END mark the extent of the region. TITLE identifies the rule
  861. that should be highlighted. If RULES or EXCLUDE-RULES is set to a
  862. list of rules (see `align-rules-list'), it can be used to override the
  863. default alignment rules that would have been used to identify the text
  864. to be colored."
  865. (interactive
  866. (list (region-beginning) (region-end)
  867. (completing-read
  868. "Title of rule to highlight: "
  869. (mapcar
  870. (function
  871. (lambda (rule)
  872. (list (symbol-name (car rule)))))
  873. (append (or align-mode-rules-list align-rules-list)
  874. (or align-mode-exclude-rules-list
  875. align-exclude-rules-list))) nil t)))
  876. (let ((ex-rule (assq (intern title)
  877. (or align-mode-exclude-rules-list
  878. align-exclude-rules-list)))
  879. face)
  880. (align-unhighlight-rule)
  881. (align-region
  882. beg end 'entire
  883. (or rules (if ex-rule
  884. (or exclude-rules align-mode-exclude-rules-list
  885. align-exclude-rules-list)
  886. (or align-mode-rules-list align-rules-list)))
  887. (unless ex-rule (or exclude-rules align-mode-exclude-rules-list
  888. align-exclude-rules-list))
  889. (function
  890. (lambda (b e mode)
  891. (if (and mode (listp mode))
  892. (if (equal (symbol-name (car mode)) title)
  893. (setq face (cons align-highlight-change-face
  894. align-highlight-nochange-face))
  895. (setq face nil))
  896. (when face
  897. (let ((overlay (make-overlay b e)))
  898. (setq align-highlight-overlays
  899. (cons overlay align-highlight-overlays))
  900. (overlay-put overlay 'face
  901. (if mode
  902. (car face)
  903. (cdr face)))))))))))
  904. ;;;###autoload
  905. (defun align-unhighlight-rule ()
  906. "Remove any highlighting that was added by `align-highlight-rule'."
  907. (interactive)
  908. (while align-highlight-overlays
  909. (delete-overlay (car align-highlight-overlays))
  910. (setq align-highlight-overlays
  911. (cdr align-highlight-overlays))))
  912. ;;;###autoload
  913. (defun align-newline-and-indent ()
  914. "A replacement function for `newline-and-indent', aligning as it goes.
  915. The alignment is done by calling `align' on the region that was
  916. indented."
  917. (interactive)
  918. (let ((separate (or (if (and (symbolp align-region-separate)
  919. (boundp align-region-separate))
  920. (symbol-value align-region-separate)
  921. align-region-separate)
  922. 'entire))
  923. (end (point)))
  924. (call-interactively 'newline-and-indent)
  925. (save-excursion
  926. (forward-line -1)
  927. (while (not (or (bobp)
  928. (align-new-section-p (point) end separate)))
  929. (forward-line -1))
  930. (align (point) end))))
  931. ;;; Internal Functions:
  932. (defun align-match-tex-pattern (regexp end &optional reverse)
  933. "Match REGEXP in TeX mode, counting backslashes appropriately.
  934. END denotes the end of the region to be searched, while REVERSE, if
  935. non-nil, indicates that the search should proceed backward from the
  936. current position."
  937. (let (result)
  938. (while
  939. (and (setq result
  940. (funcall
  941. (if reverse 're-search-backward
  942. 're-search-forward)
  943. (concat "\\(\\s-*\\)" regexp
  944. "\\(\\s-*\\)") end t))
  945. (let ((pos (match-end 1))
  946. (count 0))
  947. (while (and (> pos (point-min))
  948. (eq (char-before pos) ?\\))
  949. (setq count (1+ count) pos (1- pos)))
  950. (eq (mod count 2) 1))
  951. (goto-char (match-beginning (if reverse 1 2)))))
  952. result))
  953. (defun align-new-section-p (beg end separator)
  954. "Is there a section divider between BEG and END?
  955. SEPARATOR specifies how to look for the section divider. See the
  956. documentation for `align-region-separate' for more details."
  957. (cond ((or (not separator)
  958. (eq separator 'entire))
  959. nil)
  960. ((eq separator 'group)
  961. (let ((amount 2))
  962. (save-excursion
  963. (goto-char end)
  964. (if (bolp)
  965. (setq amount 1)))
  966. (> (count-lines beg end) amount)))
  967. ((stringp separator)
  968. (save-excursion
  969. (goto-char beg)
  970. (re-search-forward separator end t)))
  971. ((functionp separator)
  972. (funcall separator beg end))
  973. ((listp separator)
  974. (let ((seps separator) yes)
  975. (while seps
  976. (if (and (>= (car seps) beg)
  977. (<= (car seps) end))
  978. (setq yes t seps nil)
  979. (setq seps (cdr seps))))
  980. yes))))
  981. (defun align-adjust-col-for-rule (column _rule spacing tab-stop)
  982. "Adjust COLUMN according to the given RULE.
  983. SPACING specifies how much spacing to use.
  984. TAB-STOP specifies whether SPACING refers to tab-stop boundaries."
  985. (unless spacing
  986. (setq spacing align-default-spacing))
  987. (if (<= spacing 0)
  988. column
  989. (if (not tab-stop)
  990. (+ column spacing)
  991. (dotimes (_ spacing)
  992. (setq column (indent-next-tab-stop column)))
  993. column)))
  994. (defsubst align-column (pos)
  995. "Given a position in the buffer, state what column it's in.
  996. POS is the position whose column will be taken. Note that this
  997. function will change the location of point."
  998. (goto-char pos)
  999. (current-column))
  1000. (defsubst align-regions (regions props rule func)
  1001. "Align the regions specified in REGIONS, a list of cons cells.
  1002. PROPS describes formatting features specific to the given regions.
  1003. RULE specifies exactly how to perform the alignments.
  1004. If FUNC is specified, it will be called with each region that would
  1005. have been aligned, rather than modifying the text."
  1006. (while regions
  1007. (save-excursion
  1008. (align-areas (car regions) (car props) rule func))
  1009. (setq regions (cdr regions)
  1010. props (cdr props))))
  1011. (defun align-areas (areas props rule func)
  1012. "Given a list of AREAS and formatting PROPS, align according to RULE.
  1013. AREAS should be a list of cons cells containing beginning and ending
  1014. markers. This function sweeps through all of the beginning markers,
  1015. finds out which one starts in the furthermost column, and then deletes
  1016. and inserts text such that all of the ending markers occur in the same
  1017. column.
  1018. If FUNC is non-nil, it will be called for each text region that would
  1019. have been aligned. No changes will be made to the buffer."
  1020. (let* ((column (cdr (assq 'column rule)))
  1021. (fixed (if (symbolp column)
  1022. (symbol-value column)
  1023. column))
  1024. (justify (cdr (assq 'justify rule)))
  1025. (col (or fixed 0))
  1026. (width 0)
  1027. ecol change)
  1028. ;; Determine the alignment column.
  1029. (let ((a areas))
  1030. (while a
  1031. (unless fixed
  1032. (setq col (max col (align-column (caar a)))))
  1033. (unless change
  1034. (goto-char (cdar a))
  1035. (if ecol
  1036. (if (/= ecol (current-column))
  1037. (setq change t))
  1038. (setq ecol (current-column))))
  1039. (when justify
  1040. (goto-char (caar a))
  1041. (if (and (re-search-forward "\\s-*" (cdar a) t)
  1042. (/= (point) (cdar a)))
  1043. (let ((bcol (current-column)))
  1044. (setcdr (car a) (cons (point-marker) (cdar a)))
  1045. (goto-char (cdr (cdar a)))
  1046. (setq width (max width (- (current-column) bcol))))))
  1047. (setq a (cdr a))))
  1048. (unless fixed
  1049. (setq col (+ (align-adjust-col-for-rule
  1050. col rule (car props) (cdr props)) width)))
  1051. ;; Make all ending positions to occur in the goal column. Since
  1052. ;; the whitespace to be modified was already deleted by
  1053. ;; `align-region', all we have to do here is indent.
  1054. (unless change
  1055. (setq change (and ecol (/= col ecol))))
  1056. (when (or func change)
  1057. (while areas
  1058. (let ((area (car areas))
  1059. (gocol col) cur)
  1060. (when area
  1061. (if func
  1062. (funcall func
  1063. (marker-position (car area))
  1064. (marker-position (cdr area))
  1065. change)
  1066. (if (not (and justify
  1067. (consp (cdr area))))
  1068. (goto-char (cdr area))
  1069. (goto-char (cddr area))
  1070. (let ((ecol (current-column)))
  1071. (goto-char (cadr area))
  1072. (setq gocol (- col (- ecol (current-column))))))
  1073. (setq cur (current-column))
  1074. (cond ((< gocol 0) t) ; don't do anything
  1075. ((= cur gocol) t) ; don't need to
  1076. ((< cur gocol) ; just add space
  1077. ;; FIXME: It is stated above that "...the
  1078. ;; whitespace to be modified was already
  1079. ;; deleted by `align-region', all we have
  1080. ;; to do here is indent." However, this
  1081. ;; doesn't seem to be true, so we first
  1082. ;; delete the whitespace to avoid tabs
  1083. ;; after spaces.
  1084. (delete-horizontal-space t)
  1085. (indent-to gocol))
  1086. (t
  1087. ;; This code works around an oddity in the
  1088. ;; FORCE argument of `move-to-column', which
  1089. ;; tends to screw up markers if there is any
  1090. ;; tabbing.
  1091. (let ((endcol (align-column
  1092. (if (and justify
  1093. (consp (cdr area)))
  1094. (cadr area)
  1095. (cdr area))))
  1096. (abuts (<= gocol
  1097. (align-column (car area)))))
  1098. (if abuts
  1099. (goto-char (car area))
  1100. (move-to-column gocol t))
  1101. (let ((here (point)))
  1102. (move-to-column endcol t)
  1103. (delete-region here (point))
  1104. (if abuts
  1105. (indent-to (align-adjust-col-for-rule
  1106. (current-column) rule
  1107. (car props) (cdr props)))))))))))
  1108. (setq areas (cdr areas))))))
  1109. (defmacro align--set-marker (marker-var pos &optional type)
  1110. "If MARKER-VAR is a marker, move it to position POS.
  1111. Otherwise, create a new marker at position POS, with type TYPE."
  1112. `(if (markerp ,marker-var)
  1113. (move-marker ,marker-var ,pos)
  1114. (setq ,marker-var (copy-marker ,pos ,type))))
  1115. (defun align-region (beg end separate rules exclude-rules
  1116. &optional func)
  1117. "Align a region based on a given set of alignment rules.
  1118. BEG and END specify the region to be aligned. Either may be nil, in
  1119. which case the range will stop at the nearest section division (see
  1120. `align-region-separate', and `align-region-heuristic' for more
  1121. information').
  1122. The region will be divided into separate alignment sections based on
  1123. the value of SEPARATE.
  1124. RULES and EXCLUDE-RULES are a pair of lists describing how to align
  1125. the region, and which text areas within it should be excluded from
  1126. alignment. See the `align-rules-list' for more information on the
  1127. required format of these two lists.
  1128. If FUNC is specified, no text will be modified. What `align-region'
  1129. will do with the rules is to search for the alignment areas, as it
  1130. regularly would, taking account for exclusions, and then call FUNC,
  1131. first with the beginning and ending of the region to be aligned
  1132. according to that rule (this can be different for each rule, if BEG
  1133. and END were nil), and then with the beginning and ending of each
  1134. text region that the rule would have applied to.
  1135. The signature of FUNC should thus be:
  1136. (defun my-align-function (beg end mode)
  1137. \"If MODE is a rule (a list), return t if BEG to END are to be searched.
  1138. Otherwise BEG to END will be a region of text that matches the rule's
  1139. definition, and MODE will be non-nil if any changes are necessary.\"
  1140. (unless (and mode (listp mode))
  1141. (message \"Would have aligned from %d to %d...\" beg end)))
  1142. This feature (of passing a FUNC) is used internally to locate the
  1143. position of exclusion areas, but could also be used for any other
  1144. purpose where you might want to know where the regions that the
  1145. aligner would have dealt with are."
  1146. (let ((end-mark (and end (copy-marker end t)))
  1147. (real-beg beg)
  1148. (report (and (not func) align-large-region beg end
  1149. (>= (- end beg) align-large-region)))
  1150. (rule-index 1)
  1151. (rule-count (length rules))
  1152. markers)
  1153. (if (and align-indent-before-aligning real-beg end-mark)
  1154. (indent-region real-beg end-mark nil))
  1155. (while rules
  1156. (let* ((rule (car rules))
  1157. (run-if (assq 'run-if rule))
  1158. (modes (assq 'modes rule)))
  1159. ;; unless the `run-if' form tells us not to, look for the
  1160. ;; rule..
  1161. (unless (or (and modes (not (memq major-mode
  1162. (eval (cdr modes)))))
  1163. (and run-if (not (funcall (cdr run-if)))))
  1164. (let* ((case-fold-search case-fold-search)
  1165. (case-fold (assq 'case-fold rule))
  1166. (regexp (cdr (assq 'regexp rule)))
  1167. (regfunc (and (functionp regexp) regexp))
  1168. (rulesep (assq 'separate rule))
  1169. (thissep (if rulesep (cdr rulesep) separate))
  1170. same (eol 0)
  1171. search-start
  1172. groups group-c
  1173. spacing spacing-c
  1174. tab-stop tab-stop-c
  1175. repeat repeat-c
  1176. valid valid-c
  1177. first
  1178. regions index
  1179. last-point
  1180. save-match-data
  1181. exclude-p
  1182. align-props)
  1183. (save-excursion
  1184. ;; if beg and end were not given, figure out what the
  1185. ;; current alignment region should be. Depending on the
  1186. ;; value of `align-region-separate' it's possible for
  1187. ;; each rule to have its own definition of what that
  1188. ;; current alignment section is.
  1189. (if real-beg
  1190. (goto-char beg)
  1191. (if (or (not thissep) (eq thissep 'entire))
  1192. (error "Cannot determine alignment region for `%s'"
  1193. (symbol-name (cdr (assq 'title rule)))))
  1194. (beginning-of-line)
  1195. (while (and (not (eobp))
  1196. (looking-at "^\\s-*$"))
  1197. (forward-line))
  1198. (let* ((here (point))
  1199. (start here))
  1200. (while (and here
  1201. (let ((terminus
  1202. (and align-region-heuristic
  1203. (- (point)
  1204. align-region-heuristic))))
  1205. (if regfunc
  1206. (funcall regfunc terminus t)
  1207. (re-search-backward regexp
  1208. terminus t))))
  1209. (if (align-new-section-p (point) here thissep)
  1210. (setq beg here
  1211. here nil)
  1212. (setq here (point))))
  1213. (if (not here)
  1214. (goto-char beg))
  1215. (beginning-of-line)
  1216. (setq beg (point))
  1217. (goto-char start)
  1218. (setq here (point))
  1219. (while (and here
  1220. (let ((terminus
  1221. (and align-region-heuristic
  1222. (+ (point)
  1223. align-region-heuristic))))
  1224. (if regfunc
  1225. (funcall regfunc terminus nil)
  1226. (re-search-forward regexp terminus t))))
  1227. (if (align-new-section-p here (point) thissep)
  1228. (setq end here
  1229. here nil)
  1230. (setq here (point))))
  1231. (if (not here)
  1232. (goto-char end))
  1233. (forward-line)
  1234. (setq end (point))
  1235. (align--set-marker end-mark end t)
  1236. (goto-char beg)))
  1237. ;; If we have a region to align, and `func' is set and
  1238. ;; reports back that the region is ok, then align it.
  1239. (when (or (not func)
  1240. (funcall func beg end rule))
  1241. (let (rule-beg exclude-areas)
  1242. ;; determine first of all where the exclusions
  1243. ;; lie in this region
  1244. (when exclude-rules
  1245. (align-region
  1246. beg end 'entire
  1247. exclude-rules nil
  1248. (lambda (b e mode)
  1249. (or (and mode (listp mode))
  1250. (setq exclude-areas
  1251. (cons (cons b e)
  1252. exclude-areas)))))
  1253. (setq exclude-areas
  1254. (nreverse
  1255. (sort exclude-areas #'car-less-than-car))))
  1256. ;; set `case-fold-search' according to the
  1257. ;; (optional) `case-fold' property
  1258. (and case-fold
  1259. (setq case-fold-search (cdr case-fold)))
  1260. ;; while we can find the rule in the alignment
  1261. ;; region..
  1262. (while (and (< (point) end-mark)
  1263. (setq search-start (point))
  1264. (if regfunc
  1265. (funcall regfunc end-mark nil)
  1266. (re-search-forward regexp
  1267. end-mark t)))
  1268. ;; give the user some indication of where we
  1269. ;; are, if it's a very large region being
  1270. ;; aligned
  1271. (if report
  1272. (let ((symbol (car rule)))
  1273. (if (and symbol (symbolp symbol))
  1274. (message
  1275. "Aligning `%s' (rule %d of %d) %d%%..."
  1276. (symbol-name symbol) rule-index rule-count
  1277. (floor (* (- (point) real-beg) 100.0)
  1278. (- end-mark real-beg)))
  1279. (message
  1280. "Aligning %d%%..."
  1281. (floor (* (- (point) real-beg) 100.0)
  1282. (- end-mark real-beg))))))
  1283. ;; if the search ended us on the beginning of
  1284. ;; the next line, move back to the end of the
  1285. ;; previous line.
  1286. (if (and (bolp) (> (point) search-start))
  1287. (forward-char -1))
  1288. ;; lookup the `group' attribute the first time
  1289. ;; that we need it
  1290. (unless group-c
  1291. (setq groups (or (cdr (assq 'group rule)) 1))
  1292. (unless (listp groups)
  1293. (setq groups (list groups)))
  1294. (setq first (car groups)))
  1295. (unless spacing-c
  1296. (setq spacing (cdr (assq 'spacing rule))
  1297. spacing-c t))
  1298. (unless tab-stop-c
  1299. (setq tab-stop
  1300. (let ((rule-ts (assq 'tab-stop rule)))
  1301. (cond (rule-ts
  1302. (cdr rule-ts))
  1303. ((symbolp align-to-tab-stop)
  1304. (symbol-value align-to-tab-stop))
  1305. (t
  1306. align-to-tab-stop)))
  1307. tab-stop-c t))
  1308. ;; test whether we have found a match on the same
  1309. ;; line as a previous match
  1310. (when (> (point) eol)
  1311. (setq same nil)
  1312. (align--set-marker eol (line-end-position)))
  1313. ;; lookup the `repeat' attribute the first time
  1314. (or repeat-c
  1315. (setq repeat (cdr (assq 'repeat rule))
  1316. repeat-c t))
  1317. ;; lookup the `valid' attribute the first time
  1318. (or valid-c
  1319. (setq valid (assq 'valid rule)
  1320. valid-c t))
  1321. ;; remember the beginning position of this rule
  1322. ;; match, and save the match-data, since either
  1323. ;; the `valid' form, or the code that searches for
  1324. ;; section separation, might alter it
  1325. (setq rule-beg (match-beginning first)
  1326. save-match-data (match-data))
  1327. (or rule-beg
  1328. (error "No match for subexpression %s" first))
  1329. ;; unless the `valid' attribute is set, and tells
  1330. ;; us that the rule is not valid at this point in
  1331. ;; the code..
  1332. (unless (and valid (not (funcall (cdr valid))))
  1333. ;; look to see if this match begins a new
  1334. ;; section. If so, we should align what we've
  1335. ;; collected so far, and then begin collecting
  1336. ;; anew for the next alignment section
  1337. (when (and last-point
  1338. (align-new-section-p last-point rule-beg
  1339. thissep))
  1340. (align-regions regions align-props rule func)
  1341. (setq regions nil)
  1342. (setq align-props nil))
  1343. (align--set-marker last-point rule-beg t)
  1344. ;; restore the match data
  1345. (set-match-data save-match-data)
  1346. ;; check whether the region to be aligned
  1347. ;; straddles an exclusion area
  1348. (let ((excls exclude-areas))
  1349. (setq exclude-p nil)
  1350. (while excls
  1351. (if (and (< (match-beginning (car groups))
  1352. (cdar excls))
  1353. (> (match-end (car (last groups)))
  1354. (caar excls)))
  1355. (setq exclude-p t
  1356. excls nil)
  1357. (setq excls (cdr excls)))))
  1358. ;; go through the parenthesis groups
  1359. ;; matching whitespace to be contracted or
  1360. ;; expanded (or possibly justified, if the
  1361. ;; `justify' attribute was set)
  1362. (unless exclude-p
  1363. (dolist (g groups)
  1364. ;; We must use markers, since
  1365. ;; `align-areas' may modify the buffer.
  1366. ;; Avoid polluting the markers.
  1367. (let* ((group-beg (copy-marker
  1368. (match-beginning g) t))
  1369. (group-end (copy-marker
  1370. (match-end g) t))
  1371. (region (cons group-beg group-end))
  1372. (props (cons (if (listp spacing)
  1373. (car spacing)
  1374. spacing)
  1375. (if (listp tab-stop)
  1376. (car tab-stop)
  1377. tab-stop))))
  1378. (push group-beg markers)
  1379. (push group-end markers)
  1380. (setq index (if same (1+ index) 0))
  1381. (cond
  1382. ((nth index regions)
  1383. (setcar (nthcdr index regions)
  1384. (cons region
  1385. (nth index regions))))
  1386. (regions
  1387. (nconc regions
  1388. (list (list region)))
  1389. (nconc align-props (list props)))
  1390. (t
  1391. (setq regions
  1392. (list (list region)))
  1393. (setq align-props (list props)))))
  1394. ;; If any further rule matches are found
  1395. ;; before `eol', they are on the same
  1396. ;; line as this one; this can only
  1397. ;; happen if the `repeat' attribute is
  1398. ;; non-nil.
  1399. (if (listp spacing)
  1400. (setq spacing (cdr spacing)))
  1401. (if (listp tab-stop)
  1402. (setq tab-stop (cdr tab-stop)))
  1403. (setq same t))
  1404. ;; if `repeat' has not been set, move to
  1405. ;; the next line; don't bother searching
  1406. ;; anymore on this one
  1407. (if (and (not repeat) (not (bolp)))
  1408. (forward-line))
  1409. ;; if the search did not change point,
  1410. ;; move forward to avoid an infinite loop
  1411. (if (= (point) search-start)
  1412. (forward-char)))))
  1413. ;; when they are no more matches for this rule,
  1414. ;; align whatever was left over
  1415. (if regions
  1416. (align-regions regions align-props rule func))))))))
  1417. (setq rules (cdr rules)
  1418. rule-index (1+ rule-index)))
  1419. ;; This function can use a lot of temporary markers, so instead of
  1420. ;; waiting for the next GC we delete them immediately (Bug#10047).
  1421. (when end-mark (set-marker end-mark nil))
  1422. (dolist (m markers)
  1423. (set-marker m nil))
  1424. (if report
  1425. (message "Aligning...done"))))
  1426. ;; Provide:
  1427. (provide 'align)
  1428. (run-hooks 'align-load-hook)
  1429. ;;; align.el ends here