1 ;;; enumitem.el --- AUCTeX style for `enumitem.sty' (v3.5.2)
3 ;; Copyright (C) 2015, 2016 Free Software Foundation, Inc.
5 ;; Author: Arash Esbati <arash@gnu.org>
6 ;; Maintainer: auctex-devel@gnu.org
10 ;; This file is part of AUCTeX.
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)
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.
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
29 ;; This file adds support for `enumitem.sty' (v3.5.2) from 2011/09/28.
30 ;; `enumitem.sty' is part of TeXLive.
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.)
36 ;; If things do not work or when in doubt, press `C-c C-n'. Comments
37 ;; for improvement are welcome.
41 ;; Needed for compiling `pushnew':
42 (eval-when-compile (require 'cl))
44 ;; Needed for auto-parsing.
47 (defvar LaTeX-enumitem-key-val-options
54 ("leftmargin" ("*" "!"))
55 ("itemindent" ("*" "!"))
56 ("labelsep" ("*" "!"))
57 ("labelwidth" ("*" "!"))
58 ("labelindent" ("*" "!"))
64 ;; Labels and cross reference format
70 ("align" ("left" "right" "parleft"))
71 ;; Numbering, stopping, resuming
86 ("style" ("standard" "multiline" "nextline" "sameline" "unboxed"))
96 ("mode" ("boxed" "unboxed")))
97 "Key=value options for enumitem macros and environments.")
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)
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)
108 ;; Setup for \newlist:
110 (TeX-auto-add-type "enumitem-newlist" "LaTeX")
112 (defvar LaTeX-enumitem-newlist-regexp
113 '("\\\\newlist{\\([^}]+\\)}{\\([^}]+\\)}"
114 (1 2) LaTeX-auto-enumitem-newlist)
115 "Matches the arguments of `\\newlist' from `enumitem'
118 ;; Setup for \SetLabelAlign:
120 (TeX-auto-add-type "enumitem-SetLabelAlign" "LaTeX")
122 (defvar LaTeX-enumitem-SetLabelAlign-regexp
123 '("\\\\SetLabelAlign{\\([^}]+\\)}"
124 1 LaTeX-auto-enumitem-SetLabelAlign)
125 "Matches the argument of `\\SetLabelAlign' from `enumitem'
128 ;; Setup for \SetEnumitemKey:
130 (TeX-auto-add-type "enumitem-SetEnumitemKey" "LaTeX")
132 (defvar LaTeX-enumitem-SetEnumitemKey-regexp
133 '("\\\\SetEnumitemKey{\\([^}]+\\)}"
134 1 LaTeX-auto-enumitem-SetEnumitemKey)
135 "Matches the arguments of `\\SetEnumitemKey' from `enumitem'
138 ;; Setup for \SetEnumitemValue:
140 (TeX-auto-add-type "enumitem-SetEnumitemValue" "LaTeX")
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'
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))
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))))
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)
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
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)
198 (LaTeX-find-matching-begin)
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
209 (TeX-deactivate-mark)
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)))
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)))
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)))
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 "}")
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)))
269 (pushnew (list key (TeX-delete-duplicate-strings (apply #'append (list val) val-match)))
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))
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)))
281 (setq LaTeX-enumitem-key-val-options-local (copy-alist opts)))))
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)
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))
297 ;; Set the standard env's to the local list.
298 (setq LaTeX-enumitem-newlist-list-local
299 '(("itemize") ("enumerate") ("description")))
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)))
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))
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)))
323 ;; The easy way would be:
325 ;; "Name" (TeX-arg-eval
326 ;; completing-read "Type: "
327 ;; '(("itemize") ("enumerate") ("description")
328 ;; ("itemize*") ("enumerate*") ("description*")))
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>}
336 (let ((name (TeX-read-string "Name: "))
337 (type (completing-read
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)))))
354 ;; \renewlist{<name>}{<type>}{<max-depth>}
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*")))
363 ;; \setlist[<names,levels>]{<key-vals>}
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"))) ","]
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)))))
376 ;; \setlist*[<names,levels>]{<key-vals>}
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"))) ","]
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))))) )
392 ;; Ask for an Integer and insert it.
393 '("setlistdepth" "Integer")
395 ;; Just add the braces and let the user do the rest.
396 '("AddEnumerateCounter" 3)
397 '("AddEnumerateCounter*" 3)
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.
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)))))
417 ;; "Align" is added as new value to "align" key in key-val list.
418 '("SetLabelAlign" LaTeX-arg-SetLabelAlign t)
420 ;; "Key" will be parsed and added to key-val list.
421 '("SetEnumitemKey" LaTeX-arg-SetEnumitemKey)
423 ;; "Key" and "Value" are added to our key-val list
424 '("SetEnumitemValue" LaTeX-arg-SetEnumitemValue "Replacement"))
426 ;; Setting enumerate short label
427 (when (LaTeX-provided-package-options-member "enumitem" "shortlabels")
429 '("SetEnumerateShortLabel"
430 (TeX-arg-eval completing-read "Key: "
431 '(("A") ("a") ("I") ("i") ("1")))
435 (when (and (featurep 'font-latex)
436 (eq TeX-install-font-lock 'font-latex-setup))
437 (font-latex-add-keywords '(("newlist" "{{{")
440 ("AddEnumerateCounter" "*{{{")
441 ("SetLabelAlign" "{{")
442 ("SetEnumitemKey" "{{" )
443 ("SetEnumitemValue" "{{{"))
445 (font-latex-add-keywords '(("restartlist" "{" )
446 ("setlistdepth" "{" )
447 ("SetEnumerateShortLabel" "{{"))
451 (defvar LaTeX-enumitem-package-options
452 '("inline" "ignoredisplayed" "shortlabels" "loadonly")
453 "Package options for the enumitem package.")
455 ;;; enumitem.el ends here