Skip to content

Instantly share code, notes, and snippets.

@karthink
Last active September 23, 2024 05:35
Show Gist options
  • Save karthink/7d89df35ee9b7ac0c93d0177b862dadb to your computer and use it in GitHub Desktop.
Save karthink/7d89df35ee9b7ac0c93d0177b862dadb to your computer and use it in GitHub Desktop.
Configuration for super-fast Latex input using AucTeX, CDLatex and a bit of YaSnippet. See https://karthinks.com/software/latex-input-for-impatient-scholars
;; This elisp code uses use-package, a macro to simplify configuration. It will
;; install it if it's not available, so please edit the following code as
;; appropriate before running it.
;; Note that this file does not define any auto-expanding YaSnippets.
;; Install use-package
(package-install 'use-package)
;; AucTeX settings - almost no changes
(use-package latex
:ensure auctex
:hook ((LaTeX-mode . prettify-symbols-mode))
:bind (:map LaTeX-mode-map
("C-S-e" . latex-math-from-calc))
:config
;; Format math as a Latex string with Calc
(defun latex-math-from-calc ()
"Evaluate `calc' on the contents of line at point."
(interactive)
(cond ((region-active-p)
(let* ((beg (region-beginning))
(end (region-end))
(string (buffer-substring-no-properties beg end)))
(kill-region beg end)
(insert (calc-eval `(,string calc-language latex
calc-prefer-frac t
calc-angle-mode rad)))))
(t (let ((l (thing-at-point 'line)))
(end-of-line 1) (kill-line 0)
(insert (calc-eval `(,l
calc-language latex
calc-prefer-frac t
calc-angle-mode rad))))))))
(use-package preview
:after latex
:hook ((LaTeX-mode . preview-larger-previews))
:config
(defun preview-larger-previews ()
(setq preview-scale-function
(lambda () (* 1.25
(funcall (preview-scale-from-face)))))))
;; CDLatex settings
(use-package cdlatex
:ensure t
:hook (LaTeX-mode . turn-on-cdlatex)
:bind (:map cdlatex-mode-map
("<tab>" . cdlatex-tab)))
;; Yasnippet settings
(use-package yasnippet
:ensure t
:hook ((LaTeX-mode . yas-minor-mode)
(post-self-insert . my/yas-try-expanding-auto-snippets))
:config
(use-package warnings
:config
(cl-pushnew '(yasnippet backquote-change)
warning-suppress-types
:test 'equal))
(setq yas-triggers-in-field t)
;; Function that tries to autoexpand YaSnippets
;; The double quoting is NOT a typo!
(defun my/yas-try-expanding-auto-snippets ()
(when (and (boundp 'yas-minor-mode) yas-minor-mode)
(let ((yas-buffer-local-condition ''(require-snippet-condition . auto)))
(yas-expand)))))
;; CDLatex integration with YaSnippet: Allow cdlatex tab to work inside Yas
;; fields
(use-package cdlatex
:hook ((cdlatex-tab . yas-expand)
(cdlatex-tab . cdlatex-in-yas-field))
:config
(use-package yasnippet
:bind (:map yas-keymap
("<tab>" . yas-next-field-or-cdlatex)
("TAB" . yas-next-field-or-cdlatex))
:config
(defun cdlatex-in-yas-field ()
;; Check if we're at the end of the Yas field
(when-let* ((_ (overlayp yas--active-field-overlay))
(end (overlay-end yas--active-field-overlay)))
(if (>= (point) end)
;; Call yas-next-field if cdlatex can't expand here
(let ((s (thing-at-point 'sexp)))
(unless (and s (assoc (substring-no-properties s)
cdlatex-command-alist-comb))
(yas-next-field-or-maybe-expand)
t))
;; otherwise expand and jump to the correct location
(let (cdlatex-tab-hook minp)
(setq minp
(min (save-excursion (cdlatex-tab)
(point))
(overlay-end yas--active-field-overlay)))
(goto-char minp) t))))
(defun yas-next-field-or-cdlatex nil
(interactive)
"Jump to the next Yas field correctly with cdlatex active."
(if
(or (bound-and-true-p cdlatex-mode)
(bound-and-true-p org-cdlatex-mode))
(cdlatex-tab)
(yas-next-field-or-maybe-expand)))))
;; Array/tabular input with org-tables and cdlatex
(use-package org-table
:after cdlatex
:bind (:map orgtbl-mode-map
("<tab>" . lazytab-org-table-next-field-maybe)
("TAB" . lazytab-org-table-next-field-maybe))
:init
(add-hook 'cdlatex-tab-hook 'lazytab-cdlatex-or-orgtbl-next-field 90)
;; Tabular environments using cdlatex
(add-to-list 'cdlatex-command-alist '("smat" "Insert smallmatrix env"
"\\left( \\begin{smallmatrix} ? \\end{smallmatrix} \\right)"
lazytab-position-cursor-and-edit
nil nil t))
(add-to-list 'cdlatex-command-alist '("bmat" "Insert bmatrix env"
"\\begin{bmatrix} ? \\end{bmatrix}"
lazytab-position-cursor-and-edit
nil nil t))
(add-to-list 'cdlatex-command-alist '("pmat" "Insert pmatrix env"
"\\begin{pmatrix} ? \\end{pmatrix}"
lazytab-position-cursor-and-edit
nil nil t))
(add-to-list 'cdlatex-command-alist '("tbl" "Insert table"
"\\begin{table}\n\\centering ? \\caption{}\n\\end{table}\n"
lazytab-position-cursor-and-edit
nil t nil))
:config
;; Tab handling in org tables
(defun lazytab-position-cursor-and-edit ()
;; (if (search-backward "\?" (- (point) 100) t)
;; (delete-char 1))
(cdlatex-position-cursor)
(lazytab-orgtbl-edit))
(defun lazytab-orgtbl-edit ()
(advice-add 'orgtbl-ctrl-c-ctrl-c :after #'lazytab-orgtbl-replace)
(orgtbl-mode 1)
(open-line 1)
(insert "\n|"))
(defun lazytab-orgtbl-replace (_)
(interactive "P")
(unless (org-at-table-p) (user-error "Not at a table"))
(let* ((table (org-table-to-lisp))
params
(replacement-table
(if (texmathp)
(lazytab-orgtbl-to-amsmath table params)
(orgtbl-to-latex table params))))
(kill-region (org-table-begin) (org-table-end))
(open-line 1)
(push-mark)
(insert replacement-table)
(align-regexp (region-beginning) (region-end) "\\([:space:]*\\)& ")
(orgtbl-mode -1)
(advice-remove 'orgtbl-ctrl-c-ctrl-c #'lazytab-orgtbl-replace)))
(defun lazytab-orgtbl-to-amsmath (table params)
(orgtbl-to-generic
table
(org-combine-plists
'(:splice t
:lstart ""
:lend " \\\\"
:sep " & "
:hline nil
:llend "")
params)))
(defun lazytab-cdlatex-or-orgtbl-next-field ()
(when (and (bound-and-true-p orgtbl-mode)
(org-table-p)
(looking-at "[[:space:]]*\\(?:|\\|$\\)")
(let ((s (thing-at-point 'sexp)))
(not (and s (assoc s cdlatex-command-alist-comb)))))
(call-interactively #'org-table-next-field)
t))
(defun lazytab-org-table-next-field-maybe ()
(interactive)
(if (bound-and-true-p cdlatex-mode)
(cdlatex-tab)
(org-table-next-field))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment