AUCTeX Sync -- New Style Files
[packages] / xemacs-packages / auctex / style / enumitem.el
1 ;;; enumitem.el --- AUCTeX style for `enumitem.sty' (v3.5.2)
2
3 ;; Copyright (C) 2015, 2016 Free Software Foundation, Inc.
4
5 ;; Author: Arash Esbati <arash@gnu.org>
6 ;; Maintainer: auctex-devel@gnu.org
7 ;; Created: 2014-10-20
8 ;; Keywords: tex
9
10 ;; This file is part of AUCTeX.
11
12 ;; AUCTeX is free software; you can redistribute it and/or modify it
13 ;; under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 3, or (at your option)
15 ;; any later version.
16
17 ;; AUCTeX is distributed in the hope that it will be useful, but
18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 ;; General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with AUCTeX; see the file COPYING.  If not, write to the Free
24 ;; Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
25 ;; 02110-1301, USA.
26
27 ;;; Commentary:
28
29 ;; This file adds support for `enumitem.sty' (v3.5.2) from 2011/09/28.
30 ;; `enumitem.sty' is part of TeXLive.
31
32 ;; Tassilo Horn's `minted.el' was a major source of inspiration for
33 ;; this style, many thanks to him (also for patiently answering my
34 ;; many other questions, incl. the stupid ones.)
35
36 ;; If things do not work or when in doubt, press `C-c C-n'.  Comments
37 ;; for improvement are welcome.
38
39 ;;; Code:
40
41 ;; Needed for compiling `pushnew':
42 (eval-when-compile (require 'cl))
43
44 ;; Needed for auto-parsing.
45 (require 'tex)
46
47 (defvar LaTeX-enumitem-key-val-options
48   '(;; Vertical Spacing
49     ("topsep")
50     ("partopsep")
51     ("parsep")
52     ("itemsep")
53     ;; Horizontal Spacing
54     ("leftmargin"  ("*" "!"))
55     ("itemindent"  ("*" "!"))
56     ("labelsep"    ("*" "!"))
57     ("labelwidth"  ("*" "!"))
58     ("labelindent" ("*" "!"))
59     ("labelsep*")
60     ("labelindent*")
61     ("widest")
62     ("widest*")
63     ("rightmargin")
64     ;; Labels and cross reference format
65     ("label")
66     ("label*")
67     ("ref")
68     ("font")
69     ("format")
70     ("align" ("left" "right" "parleft"))
71     ;; Numbering, stopping, resuming
72     ("start")
73     ("resume")
74     ("resume*")
75     ;; Series
76     ("series")
77     ;; Penalties
78     ("beginpenalty")
79     ("midpenalty")
80     ("endpenalty")
81     ("before")
82     ("before*")
83     ("after")
84     ("after*")
85     ;; Description styles
86     ("style" ("standard" "multiline" "nextline" "sameline" "unboxed"))
87     ;; Compact lists
88     ("noitemsep")
89     ("nosep")
90     ;; Wide lists
91     ("wide")
92     ;; Inline lists
93     ("itemjoin")
94     ("itemjoin*")
95     ("afterlabel")
96     ("mode" ("boxed" "unboxed")))
97   "Key=value options for enumitem macros and environments.")
98
99 (defvar LaTeX-enumitem-key-val-options-local nil
100   "Buffer-local key=value options for enumitem macros and environments.")
101 (make-variable-buffer-local 'LaTeX-enumitem-key-val-options-local)
102
103 (defvar LaTeX-enumitem-newlist-list-local nil
104   "Local list of all environments definded with `\\newlist' plus
105 the ones initially available through `enumitem' package.")
106 (make-variable-buffer-local 'LaTeX-enumitem-newlist-list-local)
107
108 ;; Setup for \newlist:
109
110 (TeX-auto-add-type "enumitem-newlist" "LaTeX")
111
112 (defvar LaTeX-enumitem-newlist-regexp
113   '("\\\\newlist{\\([^}]+\\)}{\\([^}]+\\)}"
114     (1 2) LaTeX-auto-enumitem-newlist)
115   "Matches the arguments of `\\newlist' from `enumitem'
116 package.")
117
118 ;; Setup for \SetLabelAlign:
119
120 (TeX-auto-add-type "enumitem-SetLabelAlign" "LaTeX")
121
122 (defvar LaTeX-enumitem-SetLabelAlign-regexp
123   '("\\\\SetLabelAlign{\\([^}]+\\)}"
124     1 LaTeX-auto-enumitem-SetLabelAlign)
125   "Matches the argument of `\\SetLabelAlign' from `enumitem'
126 package.")
127
128 ;; Setup for \SetEnumitemKey:
129
130 (TeX-auto-add-type "enumitem-SetEnumitemKey" "LaTeX")
131
132 (defvar LaTeX-enumitem-SetEnumitemKey-regexp
133   '("\\\\SetEnumitemKey{\\([^}]+\\)}"
134     1 LaTeX-auto-enumitem-SetEnumitemKey)
135   "Matches the arguments of `\\SetEnumitemKey' from `enumitem'
136 package.")
137
138 ;; Setup for \SetEnumitemValue:
139
140 (TeX-auto-add-type "enumitem-SetEnumitemValue" "LaTeX")
141
142 ;; Upon Tassilo's recommendation, we include also `0' so that we can
143 ;; use the function `LaTeX-enumitem-SetEnumitemValue-list' while we
144 ;; make sure that `TeX-auto-list-information' doesn't remove multiple
145 ;; defined values to a specific key.  For this reason, we also ignore
146 ;; the 3. argument to the `\SetEnumitemValue' macro (i.e., a third
147 ;; {\\([^}]+\\)} in regex) so that we don't pollute the generated
148 ;; `docname.el' with unnecessary (La)TeX code.
149 (defvar LaTeX-enumitem-SetEnumitemValue-regexp
150   '("\\\\SetEnumitemValue{\\([^}]+\\)}{\\([^}]+\\)}"
151     (0 1 2) LaTeX-auto-enumitem-SetEnumitemValue)
152   "Matches the arguments of `\\SetEnumitemValue' from `enumitem'
153 package.")
154
155 ;; Plug them into the machinery.
156 (defun LaTeX-enumitem-auto-prepare ()
157   "Clear various `LaTeX-enumitem-*' before parsing."
158   (setq LaTeX-auto-enumitem-newlist          nil
159         LaTeX-auto-enumitem-SetLabelAlign    nil
160         LaTeX-auto-enumitem-SetEnumitemKey   nil
161         LaTeX-auto-enumitem-SetEnumitemValue nil))
162
163 (defun LaTeX-enumitem-auto-cleanup ()
164   "Move parsing results into right places for further usage."
165   ;; \newlist{<name>}{<type>}{<max-depth>}
166   ;; env=<name>, type=<type>, ignored=<max-depth>
167   (dolist (env-type (LaTeX-enumitem-newlist-list))
168     (let* ((env  (car env-type))
169            (type (cadr env-type)))
170       (LaTeX-add-environments (list env 'LaTeX-enumitem-env-with-opts))
171       ;; Tell AUCTeX about parsed description like environments.
172       (when (or (string-equal type "description")
173                 (string-equal type "description*"))
174         (add-to-list 'LaTeX-item-list `(,env . LaTeX-item-argument)))
175       ;; Add new env's to `ispell-tex-skip-alist': skip the optional argument
176       (TeX-ispell-skip-setcdr `((,env ispell-tex-arg-end 0)))))
177   ;; Now add the parsed env's to the local list.
178   (when (LaTeX-enumitem-newlist-list)
179     (setq LaTeX-enumitem-newlist-list-local
180           (append (mapcar 'list (mapcar 'car (LaTeX-enumitem-newlist-list)))
181                   LaTeX-enumitem-newlist-list-local))))
182
183 (add-hook 'TeX-auto-prepare-hook #'LaTeX-enumitem-auto-prepare t)
184 (add-hook 'TeX-auto-cleanup-hook #'LaTeX-enumitem-auto-cleanup t)
185 (add-hook 'TeX-update-style-hook #'TeX-auto-parse t)
186
187 (defun LaTeX-enumitem-env-with-opts (env)
188   "Update available key-val options, then insert ENV and optional
189 key-val and the first item."
190   (LaTeX-enumitem-update-key-val-options)
191   (LaTeX-insert-environment
192    env
193    (let ((opts (TeX-read-key-val t LaTeX-enumitem-key-val-options-local)))
194      (when (and opts (not (string-equal opts "")))
195        (format "[%s]" opts))))
196   (if (TeX-active-mark)
197       (progn
198         (LaTeX-find-matching-begin)
199         (end-of-line 1))
200     (end-of-line 0))
201   (delete-char 1)
202   (when (looking-at (concat "^[ \t]+$\\|"
203                             "^[ \t]*" TeX-comment-start-regexp "+[ \t]*$"))
204     (delete-region (point) (line-end-position)))
205   (delete-horizontal-space)
206   ;; Deactivate the mark here in order to prevent `TeX-parse-macro'
207   ;; from swapping point and mark and the \item ending up right after
208   ;; \begin{...}.
209   (TeX-deactivate-mark)
210   (LaTeX-insert-item)
211   ;; The inserted \item may have outdented the first line to the
212   ;; right.  Fill it, if appropriate.
213   (when (and (not (looking-at "$"))
214              (not (assoc env LaTeX-indent-environment-list))
215              (> (- (line-end-position) (line-beginning-position))
216                 (current-fill-column)))
217     (LaTeX-fill-paragraph nil)))
218
219 (defun LaTeX-arg-SetLabelAlign (optional)
220   "Ask for new type (value) for the \"align\" key and add it to
221 `LaTeX-enumitem-key-val-options-local'."
222   (LaTeX-enumitem-update-key-val-options)
223   (let ((val (TeX-read-string "Alignment: ")))
224     (TeX-argument-insert val optional)
225     (LaTeX-add-enumitem-SetLabelAligns val)))
226
227 (defun LaTeX-arg-SetEnumitemKey (optional)
228   "Ask for a new key to be defined and add it to
229 `LaTeX-enumitem-key-val-options-local'."
230   (LaTeX-enumitem-update-key-val-options)
231   (let ((key     (TeX-read-string "New Key: "))
232         (replace (TeX-read-key-val optional
233                                    LaTeX-enumitem-key-val-options-local "Replacement")))
234     (TeX-argument-insert key     optional)
235     (TeX-argument-insert replace optional)
236     (LaTeX-add-enumitem-SetEnumitemKeys key)))
237
238 ;; In `LaTeX-enumitem-SetEnumitemValue-regexp', we match (0 1 2).
239 ;; When adding a new `key=val', we need something unique for `0'-match
240 ;; until the next `C-c C-n'.  We mimic that regex-match bei concat'ing
241 ;; the elements and pass the result to
242 ;; `LaTeX-add-enumitem-SetEnumitemValues'.  It will vanish upon next
243 ;; invocation of `C-c C-n'.
244 (defun LaTeX-arg-SetEnumitemValue (optional)
245   "Ask for a new value added to an existing key incl. the final
246 replacement of the value."
247   (LaTeX-enumitem-update-key-val-options)
248   (let ((key (completing-read  "Key: " LaTeX-enumitem-key-val-options-local))
249         (val (TeX-read-string "String value: ")))
250     (TeX-argument-insert key optional)
251     (TeX-argument-insert val optional)
252     (LaTeX-add-enumitem-SetEnumitemValues
253      (list (concat "\\SetEnumitemValue{" key "}{" val "}")
254            key val))))
255
256 (defun LaTeX-enumitem-update-key-val-options ()
257   "Update the buffer-local key-val options before offering them
258 in `enumitem'-completions."
259   (dolist (key (LaTeX-enumitem-SetEnumitemKey-list))
260     (add-to-list 'LaTeX-enumitem-key-val-options-local key))
261   (dolist (keyvals (LaTeX-enumitem-SetEnumitemValue-list))
262     (let* ((key (nth 1 keyvals))
263            (val (nth 2 keyvals))
264            ;; (key-match (car (assoc key LaTeX-enumitem-key-val-options-local)))
265            (val-match (cdr (assoc key LaTeX-enumitem-key-val-options-local)))
266            (temp (copy-alist LaTeX-enumitem-key-val-options-local))
267            (opts (assq-delete-all (car (assoc key temp)) temp)))
268       (if val-match
269           (pushnew (list key (TeX-delete-duplicate-strings (apply #'append (list val) val-match)))
270                    opts :test #'equal)
271         (pushnew (list key (list val)) opts :test #'equal))
272       (setq LaTeX-enumitem-key-val-options-local (copy-alist opts))))
273   (dolist (newalign (LaTeX-enumitem-SetLabelAlign-list))
274     (let* ((key "align")
275            (val (car newalign))
276            (val-match (cdr (assoc key LaTeX-enumitem-key-val-options-local)))
277            (temp (copy-alist LaTeX-enumitem-key-val-options-local))
278            (opts (assq-delete-all (car (assoc key temp)) temp)))
279       (pushnew (list key (TeX-delete-duplicate-strings (apply #'append (list val) val-match)))
280                opts :test #'equal)
281       (setq LaTeX-enumitem-key-val-options-local (copy-alist opts)))))
282
283 (TeX-add-style-hook
284  "enumitem"
285  (lambda ()
286
287    ;; Add enumitem to the parser.
288    (TeX-auto-add-regexp LaTeX-enumitem-newlist-regexp)
289    (TeX-auto-add-regexp LaTeX-enumitem-SetEnumitemKey-regexp)
290    (TeX-auto-add-regexp LaTeX-enumitem-SetEnumitemValue-regexp)
291    (TeX-auto-add-regexp LaTeX-enumitem-SetLabelAlign-regexp)
292
293    ;; Activate the buffer-local version of key-vals.
294    (setq LaTeX-enumitem-key-val-options-local
295          (copy-alist LaTeX-enumitem-key-val-options))
296
297    ;; Set the standard env's to the local list.
298    (setq LaTeX-enumitem-newlist-list-local
299          '(("itemize") ("enumerate") ("description")))
300
301    ;; Add the starred versions to the local list.
302    (when (LaTeX-provided-package-options-member "enumitem" "inline")
303      (setq LaTeX-enumitem-newlist-list-local
304            (append '(("itemize*") ("enumerate*") ("description*"))
305                    LaTeX-enumitem-newlist-list-local)))
306
307    ;; Standard env's take key-val as optional argument.
308    (LaTeX-add-environments
309     '("itemize"      LaTeX-enumitem-env-with-opts)
310     '("enumerate"    LaTeX-enumitem-env-with-opts)
311     '("description"  LaTeX-enumitem-env-with-opts))
312
313    ;; Make inline env's available with package option "inline"
314    (when (LaTeX-provided-package-options-member "enumitem" "inline")
315      (LaTeX-add-environments
316       '("itemize*"     LaTeX-enumitem-env-with-opts)
317       '("enumerate*"   LaTeX-enumitem-env-with-opts)
318       '("description*" LaTeX-enumitem-env-with-opts))
319      (add-to-list 'LaTeX-item-list '("description*" . LaTeX-item-argument)))
320
321    ;; Cloning lists
322    (TeX-add-symbols
323     ;; The easy way would be:
324     ;; '("newlist"
325     ;;   "Name" (TeX-arg-eval
326     ;;           completing-read "Type: "
327     ;;                 '(("itemize")  ("enumerate")  ("description")
328     ;;                   ("itemize*") ("enumerate*") ("description*")))
329     ;;  "Max-depth")
330     ;; But we go the extra mile to improve the user experience and add
331     ;; the arguments directly to appropriate lists.
332     ;; \newlist{<name>}{<type>}{<max-depth>}
333     '("newlist"
334       (TeX-arg-eval
335        (lambda ()
336          (let ((name (TeX-read-string "Name: "))
337                (type (completing-read
338                       "Type: "
339                       '(("itemize")  ("enumerate")  ("description")
340                         ("itemize*") ("enumerate*") ("description*"))))
341                (depth (TeX-read-string "Max-depth: ")))
342            (setq LaTeX-enumitem-newlist-list-local
343                  (append `(,(list name)) LaTeX-enumitem-newlist-list-local))
344            (when (or (string-equal type "description")
345                      (string-equal type "description*"))
346              (add-to-list 'LaTeX-item-list `(,name . LaTeX-item-argument)))
347            (LaTeX-add-environments `(,name LaTeX-enumitem-env-with-opts))
348            (LaTeX-add-enumitem-newlists (list name type))
349            (TeX-ispell-skip-setcdr `((,name ispell-tex-arg-end 0)))
350            (TeX-argument-insert name optional)
351            (TeX-argument-insert type optional)
352            (format "%s" depth)))))
353
354     ;; \renewlist{<name>}{<type>}{<max-depth>}
355     '("renewlist"
356       (TeX-arg-eval completing-read "Name: "
357                     LaTeX-enumitem-newlist-list-local)
358       (TeX-arg-eval completing-read "Type: "
359                     '(("itemize")  ("enumerate")  ("description")
360                       ("itemize*") ("enumerate*") ("description*")))
361       "Max-depth")
362
363     ;; \setlist[<names,levels>]{<key-vals>}
364     '("setlist"
365       [TeX-arg-eval mapconcat #'identity
366                     (TeX-completing-read-multiple
367                      "Environment(s), level(s): "
368                      `(,@LaTeX-enumitem-newlist-list-local
369                        ("1") ("2") ("3") ("4"))) ","]
370       (TeX-arg-eval
371        (lambda ()
372          (LaTeX-enumitem-update-key-val-options)
373          (let ((opts (TeX-read-key-val nil LaTeX-enumitem-key-val-options-local)))
374            (format "%s" opts)))))
375
376     ;; \setlist*[<names,levels>]{<key-vals>}
377     '("setlist*"
378       [TeX-arg-eval mapconcat #'identity
379                     (TeX-completing-read-multiple
380                      "Environment, level: "
381                      `(,@LaTeX-enumitem-newlist-list-local
382                        ("1") ("2") ("3") ("4"))) ","]
383       (TeX-arg-eval
384        (lambda ()
385          (LaTeX-enumitem-update-key-val-options)
386          (let ((opts (TeX-read-key-val nil LaTeX-enumitem-key-val-options-local)))
387            (format "%s" opts))))) )
388
389    ;; General commands:
390    (TeX-add-symbols
391
392     ;; Ask for an Integer and insert it.
393     '("setlistdepth" "Integer")
394
395     ;; Just add the braces and let the user do the rest.
396     '("AddEnumerateCounter" 3)
397     '("AddEnumerateCounter*" 3)
398
399     ;; "\restartlist" only works for lists defined with "resume" key.
400     ;; We will not extract that information and leave that to users.
401     ;; For completion, extract enumerated environments from
402     ;; `LaTeX-enumitem-newlist-list' and add "enumerate" to them.
403     '("restartlist"
404       (TeX-arg-eval
405        (lambda ()
406          (let ((enums '("enumerate")))
407            (when (LaTeX-provided-package-options-member "enumitem" "inline")
408              (pushnew "enumerate*" enums :test #'equal))
409            (dolist (env-type (LaTeX-enumitem-newlist-list))
410              (let ((env   (car env-type))
411                    (type  (cadr env-type)))
412                (when (or (string-equal type "enumerate")
413                          (string-equal type "enumerate*"))
414                  (pushnew env enums :test #'equal))))
415            (completing-read "List name: " enums)))))
416
417     ;; "Align" is added as new value to "align" key in key-val list.
418     '("SetLabelAlign" LaTeX-arg-SetLabelAlign t)
419
420     ;; "Key" will be parsed and added to key-val list.
421     '("SetEnumitemKey" LaTeX-arg-SetEnumitemKey)
422
423     ;; "Key" and "Value" are added to our key-val list
424     '("SetEnumitemValue" LaTeX-arg-SetEnumitemValue "Replacement"))
425
426    ;; Setting enumerate short label
427    (when (LaTeX-provided-package-options-member "enumitem" "shortlabels")
428      (TeX-add-symbols
429       '("SetEnumerateShortLabel"
430         (TeX-arg-eval completing-read "Key: "
431                       '(("A") ("a") ("I") ("i") ("1")))
432         "Replacement")))
433
434    ;; Fontification
435    (when (and (featurep 'font-latex)
436               (eq TeX-install-font-lock 'font-latex-setup))
437      (font-latex-add-keywords '(("newlist"             "{{{")
438                                 ("renewlist"           "{{{")
439                                 ("setlist"             "*[{")
440                                 ("AddEnumerateCounter" "*{{{")
441                                 ("SetLabelAlign"       "{{")
442                                 ("SetEnumitemKey"      "{{" )
443                                 ("SetEnumitemValue"    "{{{"))
444                               'function)
445      (font-latex-add-keywords '(("restartlist"            "{" )
446                                 ("setlistdepth"           "{" )
447                                 ("SetEnumerateShortLabel" "{{"))
448                               'variable)))
449  LaTeX-dialect)
450
451 (defvar LaTeX-enumitem-package-options
452   '("inline" "ignoredisplayed" "shortlabels" "loadonly")
453   "Package options for the enumitem package.")
454
455 ;;; enumitem.el ends here