align.el 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615
  1. ;;; align.el --- align text to a specific column, by regexp -*- lexical-binding:t -*-
  2. ;; Copyright (C) 1999-2015 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. ;; Sample extension rule set, for vhdl-mode. This should properly be
  693. ;; in vhdl-mode.el itself.
  694. (defcustom align-vhdl-rules-list
  695. `((vhdl-declaration
  696. (regexp . "\\(signal\\|variable\\|constant\\)\\(\\s-+\\)\\S-")
  697. (group . 2))
  698. (vhdl-case
  699. (regexp . "\\(others\\|[^ \t\n=<]\\)\\(\\s-*\\)=>\\(\\s-*\\)\\S-")
  700. (group . (2 3))
  701. (valid
  702. . ,(function
  703. (lambda ()
  704. (not (string= (downcase (match-string 1))
  705. "others"))))))
  706. (vhdl-colon
  707. (regexp . "[^ \t\n:]\\(\\s-*\\):\\(\\s-*\\)[^=\n]")
  708. (group . (1 2)))
  709. (direction
  710. (regexp . ":\\s-*\\(in\\|out\\|inout\\|buffer\\)\\(\\s-*\\)")
  711. (group . 2))
  712. (sig-assign
  713. (regexp . "[^ \t\n=<]\\(\\s-*\\)<=\\(\\s-*\\)\\S-")
  714. (group . (1 2)))
  715. (var-assign
  716. (regexp . "[^ \t\n:]\\(\\s-*\\):="))
  717. (use-entity
  718. (regexp . "\\(\\s-+\\)use\\s-+entity")))
  719. "Alignment rules for `vhdl-mode'. See `align-rules-list' for more info."
  720. :type align-rules-list-type
  721. :group 'align)
  722. (put 'align-vhdl-rules-list 'risky-local-variable t)
  723. (defun align-set-vhdl-rules ()
  724. "Setup the `align-mode-rules-list' variable for `vhdl-mode'."
  725. (setq align-mode-rules-list align-vhdl-rules-list))
  726. (add-hook 'vhdl-mode-hook 'align-set-vhdl-rules)
  727. (add-to-list 'align-dq-string-modes 'vhdl-mode)
  728. (add-to-list 'align-open-comment-modes 'vhdl-mode)
  729. ;;; User Functions:
  730. ;;;###autoload
  731. (defun align (beg end &optional separate rules exclude-rules)
  732. "Attempt to align a region based on a set of alignment rules.
  733. BEG and END mark the region. If BEG and END are specifically set to
  734. nil (this can only be done programmatically), the beginning and end of
  735. the current alignment section will be calculated based on the location
  736. of point, and the value of `align-region-separate' (or possibly each
  737. rule's `separate' attribute).
  738. If SEPARATE is non-nil, it overrides the value of
  739. `align-region-separate' for all rules, except those that have their
  740. `separate' attribute set.
  741. RULES and EXCLUDE-RULES, if either is non-nil, will replace the
  742. default rule lists defined in `align-rules-list' and
  743. `align-exclude-rules-list'. See `align-rules-list' for more details
  744. on the format of these lists."
  745. (interactive "r")
  746. (let ((separator
  747. (or separate
  748. (if (and (symbolp align-region-separate)
  749. (boundp align-region-separate))
  750. (symbol-value align-region-separate)
  751. align-region-separate)
  752. 'entire)))
  753. (if (not (or ;(eq separator 'largest)
  754. (and (functionp separator)
  755. (not (funcall separator nil nil)))))
  756. (align-region beg end separator
  757. (or rules align-mode-rules-list align-rules-list)
  758. (or exclude-rules align-mode-exclude-rules-list
  759. align-exclude-rules-list))
  760. (let ((sec-first end)
  761. (sec-last beg))
  762. (align-region beg end
  763. (or exclude-rules
  764. align-mode-exclude-rules-list
  765. align-exclude-rules-list) nil
  766. separator
  767. (function
  768. (lambda (b e mode)
  769. (when (and mode (listp mode))
  770. (setq sec-first (min sec-first b)
  771. sec-last (max sec-last e))))))
  772. (if (< sec-first sec-last)
  773. (align-region sec-first sec-last 'entire
  774. (or rules align-mode-rules-list align-rules-list)
  775. (or exclude-rules align-mode-exclude-rules-list
  776. align-exclude-rules-list)))))))
  777. ;;;###autoload
  778. (defun align-regexp (beg end regexp &optional group spacing repeat)
  779. "Align the current region using an ad-hoc rule read from the minibuffer.
  780. BEG and END mark the limits of the region. Interactively, this function
  781. prompts for the regular expression REGEXP to align with.
  782. For example, let's say you had a list of phone numbers, and wanted to
  783. align them so that the opening parentheses would line up:
  784. Fred (123) 456-7890
  785. Alice (123) 456-7890
  786. Mary-Anne (123) 456-7890
  787. Joe (123) 456-7890
  788. There is no predefined rule to handle this, but you could easily do it
  789. using a REGEXP like \"(\". Interactively, all you would have to do is
  790. to mark the region, call `align-regexp' and enter that regular expression.
  791. REGEXP must contain at least one parenthesized subexpression, typically
  792. whitespace of the form \"\\\\(\\\\s-*\\\\)\". In normal interactive use,
  793. this is automatically added to the start of your regular expression after
  794. you enter it. You only need to supply the characters to be lined up, and
  795. any preceding whitespace is replaced.
  796. If you specify a prefix argument (or use this function non-interactively),
  797. you must enter the full regular expression, including the subexpression.
  798. The function also then prompts for which subexpression parenthesis GROUP
  799. \(default 1) within REGEXP to modify, the amount of SPACING (default
  800. `align-default-spacing') to use, and whether or not to REPEAT the rule
  801. throughout the line.
  802. See `align-rules-list' for more information about these options.
  803. The non-interactive form of the previous example would look something like:
  804. (align-regexp (point-min) (point-max) \"\\\\(\\\\s-*\\\\)(\")
  805. This function is a nothing more than a small wrapper that helps you
  806. construct a rule to pass to `align-region', which does the real work."
  807. (interactive
  808. (append
  809. (list (region-beginning) (region-end))
  810. (if current-prefix-arg
  811. (list (read-string "Complex align using regexp: "
  812. "\\(\\s-*\\)")
  813. (string-to-number
  814. (read-string
  815. "Parenthesis group to modify (justify if negative): " "1"))
  816. (string-to-number
  817. (read-string "Amount of spacing (or column if negative): "
  818. (number-to-string align-default-spacing)))
  819. (y-or-n-p "Repeat throughout line? "))
  820. (list (concat "\\(\\s-*\\)"
  821. (read-string "Align regexp: "))
  822. 1 align-default-spacing nil))))
  823. (or group (setq group 1))
  824. (or spacing (setq spacing align-default-spacing))
  825. (let ((rule
  826. (list (list nil (cons 'regexp regexp)
  827. (cons 'group (abs group))
  828. (if (< group 0)
  829. (cons 'justify t)
  830. (cons 'bogus nil))
  831. (if (>= spacing 0)
  832. (cons 'spacing spacing)
  833. (cons 'column (abs spacing)))
  834. (cons 'repeat repeat)))))
  835. (align-region beg end 'entire rule nil nil)))
  836. ;;;###autoload
  837. (defun align-entire (beg end &optional rules exclude-rules)
  838. "Align the selected region as if it were one alignment section.
  839. BEG and END mark the extent of the region. If RULES or EXCLUDE-RULES
  840. is set to a list of rules (see `align-rules-list'), it can be used to
  841. override the default alignment rules that would have been used to
  842. align that section."
  843. (interactive "r")
  844. (align beg end 'entire rules exclude-rules))
  845. ;;;###autoload
  846. (defun align-current (&optional rules exclude-rules)
  847. "Call `align' on the current alignment section.
  848. This function assumes you want to align only the current section, and
  849. so saves you from having to specify the region. If RULES or
  850. EXCLUDE-RULES is set to a list of rules (see `align-rules-list'), it
  851. can be used to override the default alignment rules that would have
  852. been used to align that section."
  853. (interactive)
  854. (align nil nil nil rules exclude-rules))
  855. ;;;###autoload
  856. (defun align-highlight-rule (beg end title &optional rules exclude-rules)
  857. "Highlight the whitespace which a given rule would have modified.
  858. BEG and END mark the extent of the region. TITLE identifies the rule
  859. that should be highlighted. If RULES or EXCLUDE-RULES is set to a
  860. list of rules (see `align-rules-list'), it can be used to override the
  861. default alignment rules that would have been used to identify the text
  862. to be colored."
  863. (interactive
  864. (list (region-beginning) (region-end)
  865. (completing-read
  866. "Title of rule to highlight: "
  867. (mapcar
  868. (function
  869. (lambda (rule)
  870. (list (symbol-name (car rule)))))
  871. (append (or align-mode-rules-list align-rules-list)
  872. (or align-mode-exclude-rules-list
  873. align-exclude-rules-list))) nil t)))
  874. (let ((ex-rule (assq (intern title)
  875. (or align-mode-exclude-rules-list
  876. align-exclude-rules-list)))
  877. face)
  878. (align-unhighlight-rule)
  879. (align-region
  880. beg end 'entire
  881. (or rules (if ex-rule
  882. (or exclude-rules align-mode-exclude-rules-list
  883. align-exclude-rules-list)
  884. (or align-mode-rules-list align-rules-list)))
  885. (unless ex-rule (or exclude-rules align-mode-exclude-rules-list
  886. align-exclude-rules-list))
  887. (function
  888. (lambda (b e mode)
  889. (if (and mode (listp mode))
  890. (if (equal (symbol-name (car mode)) title)
  891. (setq face (cons align-highlight-change-face
  892. align-highlight-nochange-face))
  893. (setq face nil))
  894. (when face
  895. (let ((overlay (make-overlay b e)))
  896. (setq align-highlight-overlays
  897. (cons overlay align-highlight-overlays))
  898. (overlay-put overlay 'face
  899. (if mode
  900. (car face)
  901. (cdr face)))))))))))
  902. ;;;###autoload
  903. (defun align-unhighlight-rule ()
  904. "Remove any highlighting that was added by `align-highlight-rule'."
  905. (interactive)
  906. (while align-highlight-overlays
  907. (delete-overlay (car align-highlight-overlays))
  908. (setq align-highlight-overlays
  909. (cdr align-highlight-overlays))))
  910. ;;;###autoload
  911. (defun align-newline-and-indent ()
  912. "A replacement function for `newline-and-indent', aligning as it goes."
  913. (interactive)
  914. (let ((separate (or (if (and (symbolp align-region-separate)
  915. (boundp align-region-separate))
  916. (symbol-value align-region-separate)
  917. align-region-separate)
  918. 'entire))
  919. (end (point)))
  920. (call-interactively 'newline-and-indent)
  921. (save-excursion
  922. (forward-line -1)
  923. (while (not (or (bobp)
  924. (align-new-section-p (point) end separate)))
  925. (forward-line -1))
  926. (align (point) end))))
  927. ;;; Internal Functions:
  928. (defun align-match-tex-pattern (regexp end &optional reverse)
  929. "Match REGEXP in TeX mode, counting backslashes appropriately.
  930. END denotes the end of the region to be searched, while REVERSE, if
  931. non-nil, indicates that the search should proceed backward from the
  932. current position."
  933. (let (result)
  934. (while
  935. (and (setq result
  936. (funcall
  937. (if reverse 're-search-backward
  938. 're-search-forward)
  939. (concat "\\(\\s-*\\)" regexp
  940. "\\(\\s-*\\)") end t))
  941. (let ((pos (match-end 1))
  942. (count 0))
  943. (while (and (> pos (point-min))
  944. (eq (char-before pos) ?\\))
  945. (setq count (1+ count) pos (1- pos)))
  946. (eq (mod count 2) 1))
  947. (goto-char (match-beginning (if reverse 1 2)))))
  948. result))
  949. (defun align-new-section-p (beg end separator)
  950. "Is there a section divider between BEG and END?
  951. SEPARATOR specifies how to look for the section divider. See the
  952. documentation for `align-region-separate' for more details."
  953. (cond ((or (not separator)
  954. (eq separator 'entire))
  955. nil)
  956. ((eq separator 'group)
  957. (let ((amount 2))
  958. (save-excursion
  959. (goto-char end)
  960. (if (bolp)
  961. (setq amount 1)))
  962. (> (count-lines beg end) amount)))
  963. ((stringp separator)
  964. (save-excursion
  965. (goto-char beg)
  966. (re-search-forward separator end t)))
  967. ((functionp separator)
  968. (funcall separator beg end))
  969. ((listp separator)
  970. (let ((seps separator) yes)
  971. (while seps
  972. (if (and (>= (car seps) beg)
  973. (<= (car seps) end))
  974. (setq yes t seps nil)
  975. (setq seps (cdr seps))))
  976. yes))))
  977. (defun align-adjust-col-for-rule (column _rule spacing tab-stop)
  978. "Adjust COLUMN according to the given RULE.
  979. SPACING specifies how much spacing to use.
  980. TAB-STOP specifies whether SPACING refers to tab-stop boundaries."
  981. (unless spacing
  982. (setq spacing align-default-spacing))
  983. (if (<= spacing 0)
  984. column
  985. (if (not tab-stop)
  986. (+ column spacing)
  987. (dotimes (_ spacing)
  988. (setq column (indent-next-tab-stop column)))
  989. column)))
  990. (defsubst align-column (pos)
  991. "Given a position in the buffer, state what column it's in.
  992. POS is the position whose column will be taken. Note that this
  993. function will change the location of point."
  994. (goto-char pos)
  995. (current-column))
  996. (defsubst align-regions (regions props rule func)
  997. "Align the regions specified in REGIONS, a list of cons cells.
  998. PROPS describes formatting features specific to the given regions.
  999. RULE specifies exactly how to perform the alignments.
  1000. If FUNC is specified, it will be called with each region that would
  1001. have been aligned, rather than modifying the text."
  1002. (while regions
  1003. (save-excursion
  1004. (align-areas (car regions) (car props) rule func))
  1005. (setq regions (cdr regions)
  1006. props (cdr props))))
  1007. (defun align-areas (areas props rule func)
  1008. "Given a list of AREAS and formatting PROPS, align according to RULE.
  1009. AREAS should be a list of cons cells containing beginning and ending
  1010. markers. This function sweeps through all of the beginning markers,
  1011. finds out which one starts in the furthermost column, and then deletes
  1012. and inserts text such that all of the ending markers occur in the same
  1013. column.
  1014. If FUNC is non-nil, it will be called for each text region that would
  1015. have been aligned. No changes will be made to the buffer."
  1016. (let* ((column (cdr (assq 'column rule)))
  1017. (fixed (if (symbolp column)
  1018. (symbol-value column)
  1019. column))
  1020. (justify (cdr (assq 'justify rule)))
  1021. (col (or fixed 0))
  1022. (width 0)
  1023. ecol change)
  1024. ;; Determine the alignment column.
  1025. (let ((a areas))
  1026. (while a
  1027. (unless fixed
  1028. (setq col (max col (align-column (caar a)))))
  1029. (unless change
  1030. (goto-char (cdar a))
  1031. (if ecol
  1032. (if (/= ecol (current-column))
  1033. (setq change t))
  1034. (setq ecol (current-column))))
  1035. (when justify
  1036. (goto-char (caar a))
  1037. (if (and (re-search-forward "\\s-*" (cdar a) t)
  1038. (/= (point) (cdar a)))
  1039. (let ((bcol (current-column)))
  1040. (setcdr (car a) (cons (point-marker) (cdar a)))
  1041. (goto-char (cdr (cdar a)))
  1042. (setq width (max width (- (current-column) bcol))))))
  1043. (setq a (cdr a))))
  1044. (unless fixed
  1045. (setq col (+ (align-adjust-col-for-rule
  1046. col rule (car props) (cdr props)) width)))
  1047. ;; Make all ending positions to occur in the goal column. Since
  1048. ;; the whitespace to be modified was already deleted by
  1049. ;; `align-region', all we have to do here is indent.
  1050. (unless change
  1051. (setq change (and ecol (/= col ecol))))
  1052. (when (or func change)
  1053. (while areas
  1054. (let ((area (car areas))
  1055. (gocol col) cur)
  1056. (when area
  1057. (if func
  1058. (funcall func
  1059. (marker-position (car area))
  1060. (marker-position (cdr area))
  1061. change)
  1062. (if (not (and justify
  1063. (consp (cdr area))))
  1064. (goto-char (cdr area))
  1065. (goto-char (cddr area))
  1066. (let ((ecol (current-column)))
  1067. (goto-char (cadr area))
  1068. (setq gocol (- col (- ecol (current-column))))))
  1069. (setq cur (current-column))
  1070. (cond ((< gocol 0) t) ; don't do anything
  1071. ((= cur gocol) t) ; don't need to
  1072. ((< cur gocol) ; just add space
  1073. ;; FIXME: It is stated above that "...the
  1074. ;; whitespace to be modified was already
  1075. ;; deleted by `align-region', all we have
  1076. ;; to do here is indent." However, this
  1077. ;; doesn't seem to be true, so we first
  1078. ;; delete the whitespace to avoid tabs
  1079. ;; after spaces.
  1080. (delete-horizontal-space t)
  1081. (indent-to gocol))
  1082. (t
  1083. ;; This code works around an oddity in the
  1084. ;; FORCE argument of `move-to-column', which
  1085. ;; tends to screw up markers if there is any
  1086. ;; tabbing.
  1087. (let ((endcol (align-column
  1088. (if (and justify
  1089. (consp (cdr area)))
  1090. (cadr area)
  1091. (cdr area))))
  1092. (abuts (<= gocol
  1093. (align-column (car area)))))
  1094. (if abuts
  1095. (goto-char (car area))
  1096. (move-to-column gocol t))
  1097. (let ((here (point)))
  1098. (move-to-column endcol t)
  1099. (delete-region here (point))
  1100. (if abuts
  1101. (indent-to (align-adjust-col-for-rule
  1102. (current-column) rule
  1103. (car props) (cdr props)))))))))))
  1104. (setq areas (cdr areas))))))
  1105. (defmacro align--set-marker (marker-var pos &optional type)
  1106. "If MARKER-VAR is a marker, move it to position POS.
  1107. Otherwise, create a new marker at position POS, with type TYPE."
  1108. `(if (markerp ,marker-var)
  1109. (move-marker ,marker-var ,pos)
  1110. (setq ,marker-var (copy-marker ,pos ,type))))
  1111. (defun align-region (beg end separate rules exclude-rules
  1112. &optional func)
  1113. "Align a region based on a given set of alignment rules.
  1114. BEG and END specify the region to be aligned. Either may be nil, in
  1115. which case the range will stop at the nearest section division (see
  1116. `align-region-separate', and `align-region-heuristic' for more
  1117. information').
  1118. The region will be divided into separate alignment sections based on
  1119. the value of SEPARATE.
  1120. RULES and EXCLUDE-RULES are a pair of lists describing how to align
  1121. the region, and which text areas within it should be excluded from
  1122. alignment. See the `align-rules-list' for more information on the
  1123. required format of these two lists.
  1124. If FUNC is specified, no text will be modified. What `align-region'
  1125. will do with the rules is to search for the alignment areas, as it
  1126. regularly would, taking account for exclusions, and then call FUNC,
  1127. first with the beginning and ending of the region to be aligned
  1128. according to that rule (this can be different for each rule, if BEG
  1129. and END were nil), and then with the beginning and ending of each
  1130. text region that the rule would have applied to.
  1131. The signature of FUNC should thus be:
  1132. (defun my-align-function (beg end mode)
  1133. \"If MODE is a rule (a list), return t if BEG to END are to be searched.
  1134. Otherwise BEG to END will be a region of text that matches the rule's
  1135. definition, and MODE will be non-nil if any changes are necessary.\"
  1136. (unless (and mode (listp mode))
  1137. (message \"Would have aligned from %d to %d...\" beg end)))
  1138. This feature (of passing a FUNC) is used internally to locate the
  1139. position of exclusion areas, but could also be used for any other
  1140. purpose where you might want to know where the regions that the
  1141. aligner would have dealt with are."
  1142. (let ((end-mark (and end (copy-marker end t)))
  1143. (real-beg beg)
  1144. (report (and (not func) align-large-region beg end
  1145. (>= (- end beg) align-large-region)))
  1146. (rule-index 1)
  1147. (rule-count (length rules))
  1148. markers)
  1149. (if (and align-indent-before-aligning real-beg end-mark)
  1150. (indent-region real-beg end-mark nil))
  1151. (while rules
  1152. (let* ((rule (car rules))
  1153. (run-if (assq 'run-if rule))
  1154. (modes (assq 'modes rule)))
  1155. ;; unless the `run-if' form tells us not to, look for the
  1156. ;; rule..
  1157. (unless (or (and modes (not (memq major-mode
  1158. (eval (cdr modes)))))
  1159. (and run-if (not (funcall (cdr run-if)))))
  1160. (let* ((case-fold-search case-fold-search)
  1161. (case-fold (assq 'case-fold rule))
  1162. (regexp (cdr (assq 'regexp rule)))
  1163. (regfunc (and (functionp regexp) regexp))
  1164. (rulesep (assq 'separate rule))
  1165. (thissep (if rulesep (cdr rulesep) separate))
  1166. same (eol 0)
  1167. search-start
  1168. groups group-c
  1169. spacing spacing-c
  1170. tab-stop tab-stop-c
  1171. repeat repeat-c
  1172. valid valid-c
  1173. first
  1174. regions index
  1175. last-point
  1176. save-match-data
  1177. exclude-p
  1178. align-props)
  1179. (save-excursion
  1180. ;; if beg and end were not given, figure out what the
  1181. ;; current alignment region should be. Depending on the
  1182. ;; value of `align-region-separate' it's possible for
  1183. ;; each rule to have its own definition of what that
  1184. ;; current alignment section is.
  1185. (if real-beg
  1186. (goto-char beg)
  1187. (if (or (not thissep) (eq thissep 'entire))
  1188. (error "Cannot determine alignment region for ‘%s’"
  1189. (symbol-name (cdr (assq 'title rule)))))
  1190. (beginning-of-line)
  1191. (while (and (not (eobp))
  1192. (looking-at "^\\s-*$"))
  1193. (forward-line))
  1194. (let* ((here (point))
  1195. (start here))
  1196. (while (and here
  1197. (let ((terminus
  1198. (and align-region-heuristic
  1199. (- (point)
  1200. align-region-heuristic))))
  1201. (if regfunc
  1202. (funcall regfunc terminus t)
  1203. (re-search-backward regexp
  1204. terminus t))))
  1205. (if (align-new-section-p (point) here thissep)
  1206. (setq beg here
  1207. here nil)
  1208. (setq here (point))))
  1209. (if (not here)
  1210. (goto-char beg))
  1211. (beginning-of-line)
  1212. (setq beg (point))
  1213. (goto-char start)
  1214. (setq here (point))
  1215. (while (and here
  1216. (let ((terminus
  1217. (and align-region-heuristic
  1218. (+ (point)
  1219. align-region-heuristic))))
  1220. (if regfunc
  1221. (funcall regfunc terminus nil)
  1222. (re-search-forward regexp terminus t))))
  1223. (if (align-new-section-p here (point) thissep)
  1224. (setq end here
  1225. here nil)
  1226. (setq here (point))))
  1227. (if (not here)
  1228. (goto-char end))
  1229. (forward-line)
  1230. (setq end (point))
  1231. (align--set-marker end-mark end t)
  1232. (goto-char beg)))
  1233. ;; If we have a region to align, and `func' is set and
  1234. ;; reports back that the region is ok, then align it.
  1235. (when (or (not func)
  1236. (funcall func beg end rule))
  1237. (let (rule-beg exclude-areas)
  1238. ;; determine first of all where the exclusions
  1239. ;; lie in this region
  1240. (when exclude-rules
  1241. (align-region
  1242. beg end 'entire
  1243. exclude-rules nil
  1244. (lambda (b e mode)
  1245. (or (and mode (listp mode))
  1246. (setq exclude-areas
  1247. (cons (cons b e)
  1248. exclude-areas)))))
  1249. (setq exclude-areas
  1250. (nreverse
  1251. (sort exclude-areas #'car-less-than-car))))
  1252. ;; set `case-fold-search' according to the
  1253. ;; (optional) `case-fold' property
  1254. (and case-fold
  1255. (setq case-fold-search (cdr case-fold)))
  1256. ;; while we can find the rule in the alignment
  1257. ;; region..
  1258. (while (and (< (point) end-mark)
  1259. (setq search-start (point))
  1260. (if regfunc
  1261. (funcall regfunc end-mark nil)
  1262. (re-search-forward regexp
  1263. end-mark t)))
  1264. ;; give the user some indication of where we
  1265. ;; are, if it's a very large region being
  1266. ;; aligned
  1267. (if report
  1268. (let ((symbol (car rule)))
  1269. (if (and symbol (symbolp symbol))
  1270. (message
  1271. "Aligning `%s' (rule %d of %d) %d%%..."
  1272. (symbol-name symbol) rule-index rule-count
  1273. (floor (* (- (point) real-beg) 100.0)
  1274. (- end-mark real-beg)))
  1275. (message
  1276. "Aligning %d%%..."
  1277. (floor (* (- (point) real-beg) 100.0)
  1278. (- end-mark real-beg))))))
  1279. ;; if the search ended us on the beginning of
  1280. ;; the next line, move back to the end of the
  1281. ;; previous line.
  1282. (if (and (bolp) (> (point) search-start))
  1283. (forward-char -1))
  1284. ;; lookup the `group' attribute the first time
  1285. ;; that we need it
  1286. (unless group-c
  1287. (setq groups (or (cdr (assq 'group rule)) 1))
  1288. (unless (listp groups)
  1289. (setq groups (list groups)))
  1290. (setq first (car groups)))
  1291. (unless spacing-c
  1292. (setq spacing (cdr (assq 'spacing rule))
  1293. spacing-c t))
  1294. (unless tab-stop-c
  1295. (setq tab-stop
  1296. (let ((rule-ts (assq 'tab-stop rule)))
  1297. (cond (rule-ts
  1298. (cdr rule-ts))
  1299. ((symbolp align-to-tab-stop)
  1300. (symbol-value align-to-tab-stop))
  1301. (t
  1302. align-to-tab-stop)))
  1303. tab-stop-c t))
  1304. ;; test whether we have found a match on the same
  1305. ;; line as a previous match
  1306. (when (> (point) eol)
  1307. (setq same nil)
  1308. (align--set-marker eol (line-end-position)))
  1309. ;; lookup the `repeat' attribute the first time
  1310. (or repeat-c
  1311. (setq repeat (cdr (assq 'repeat rule))
  1312. repeat-c t))
  1313. ;; lookup the `valid' attribute the first time
  1314. (or valid-c
  1315. (setq valid (assq 'valid rule)
  1316. valid-c t))
  1317. ;; remember the beginning position of this rule
  1318. ;; match, and save the match-data, since either
  1319. ;; the `valid' form, or the code that searches for
  1320. ;; section separation, might alter it
  1321. (setq rule-beg (match-beginning first)
  1322. save-match-data (match-data))
  1323. (or rule-beg
  1324. (error "No match for subexpression %s" first))
  1325. ;; unless the `valid' attribute is set, and tells
  1326. ;; us that the rule is not valid at this point in
  1327. ;; the code..
  1328. (unless (and valid (not (funcall (cdr valid))))
  1329. ;; look to see if this match begins a new
  1330. ;; section. If so, we should align what we've
  1331. ;; collected so far, and then begin collecting
  1332. ;; anew for the next alignment section
  1333. (when (and last-point
  1334. (align-new-section-p last-point rule-beg
  1335. thissep))
  1336. (align-regions regions align-props rule func)
  1337. (setq regions nil)
  1338. (setq align-props nil))
  1339. (align--set-marker last-point rule-beg t)
  1340. ;; restore the match data
  1341. (set-match-data save-match-data)
  1342. ;; check whether the region to be aligned
  1343. ;; straddles an exclusion area
  1344. (let ((excls exclude-areas))
  1345. (setq exclude-p nil)
  1346. (while excls
  1347. (if (and (< (match-beginning (car groups))
  1348. (cdar excls))
  1349. (> (match-end (car (last groups)))
  1350. (caar excls)))
  1351. (setq exclude-p t
  1352. excls nil)
  1353. (setq excls (cdr excls)))))
  1354. ;; go through the parenthesis groups
  1355. ;; matching whitespace to be contracted or
  1356. ;; expanded (or possibly justified, if the
  1357. ;; `justify' attribute was set)
  1358. (unless exclude-p
  1359. (dolist (g groups)
  1360. ;; We must use markers, since
  1361. ;; `align-areas' may modify the buffer.
  1362. ;; Avoid polluting the markers.
  1363. (let* ((group-beg (copy-marker
  1364. (match-beginning g) t))
  1365. (group-end (copy-marker
  1366. (match-end g) t))
  1367. (region (cons group-beg group-end))
  1368. (props (cons (if (listp spacing)
  1369. (car spacing)
  1370. spacing)
  1371. (if (listp tab-stop)
  1372. (car tab-stop)
  1373. tab-stop))))
  1374. (push group-beg markers)
  1375. (push group-end markers)
  1376. (setq index (if same (1+ index) 0))
  1377. (cond
  1378. ((nth index regions)
  1379. (setcar (nthcdr index regions)
  1380. (cons region
  1381. (nth index regions))))
  1382. (regions
  1383. (nconc regions
  1384. (list (list region)))
  1385. (nconc align-props (list props)))
  1386. (t
  1387. (setq regions
  1388. (list (list region)))
  1389. (setq align-props (list props)))))
  1390. ;; If any further rule matches are found
  1391. ;; before `eol', they are on the same
  1392. ;; line as this one; this can only
  1393. ;; happen if the `repeat' attribute is
  1394. ;; non-nil.
  1395. (if (listp spacing)
  1396. (setq spacing (cdr spacing)))
  1397. (if (listp tab-stop)
  1398. (setq tab-stop (cdr tab-stop)))
  1399. (setq same t))
  1400. ;; if `repeat' has not been set, move to
  1401. ;; the next line; don't bother searching
  1402. ;; anymore on this one
  1403. (if (and (not repeat) (not (bolp)))
  1404. (forward-line))
  1405. ;; if the search did not change point,
  1406. ;; move forward to avoid an infinite loop
  1407. (if (= (point) search-start)
  1408. (forward-char)))))
  1409. ;; when they are no more matches for this rule,
  1410. ;; align whatever was left over
  1411. (if regions
  1412. (align-regions regions align-props rule func))))))))
  1413. (setq rules (cdr rules)
  1414. rule-index (1+ rule-index)))
  1415. ;; This function can use a lot of temporary markers, so instead of
  1416. ;; waiting for the next GC we delete them immediately (Bug#10047).
  1417. (when end-mark (set-marker end-mark nil))
  1418. (dolist (m markers)
  1419. (set-marker m nil))
  1420. (if report
  1421. (message "Aligning...done"))))
  1422. ;; Provide:
  1423. (provide 'align)
  1424. (run-hooks 'align-load-hook)
  1425. ;;; align.el ends here