Jeremy Dormitzer
3141955f9c
Integrated language-detection to automatically detect and set major modes based on buffer/string content. Enhanced YAML editing with language detection for buffer initialization.
256 lines
8.1 KiB
EmacsLisp
256 lines
8.1 KiB
EmacsLisp
;; -*- lexical-binding: t; -*-
|
|
|
|
;; General text editing configuration
|
|
|
|
;; Better isearch
|
|
(use-package ctrlf
|
|
:config
|
|
(ctrlf-mode 1))
|
|
|
|
(use-package avy
|
|
:config
|
|
(with-eval-after-load 'embark
|
|
(defun avy-action-embark (point)
|
|
(unwind-protect
|
|
(save-excursion
|
|
(goto-char point)
|
|
(embark-act))
|
|
(select-window
|
|
(cdr (ring-ref avy-ring 0))))
|
|
t)
|
|
(setf (alist-get ?. avy-dispatch-alist)
|
|
#'avy-action-embark)
|
|
(add-to-list 'avy-dispatch-alist '(?\C-. . avy-action-embark)))
|
|
:bind
|
|
("M-f" . avy-goto-char-timer)
|
|
:custom
|
|
(avy-style 'pre))
|
|
|
|
|
|
;; "pair" management, where pairs are parentheses, braces, etc.
|
|
(use-package smartparens
|
|
:init
|
|
(leader-def-key "s" '(nil :which-key "smartparens"))
|
|
:config
|
|
(require 'smartparens-config)
|
|
(smartparens-global-mode)
|
|
(defun sp-wrap-double-quote ()
|
|
(interactive)
|
|
(sp-wrap-with-pair "\""))
|
|
(defun sp-wrap-single-quote ()
|
|
(interactive)
|
|
(sp-wrap-with-pair "'"))
|
|
(defun sp-wrap-angle-bracket ()
|
|
(interactive)
|
|
(sp-wrap-with-pair "<"))
|
|
(defun sp-wrap-backtick ()
|
|
(interactive)
|
|
(sp-wrap-with-pair "`"))
|
|
(defun sp-after-equals-p (_id action _context)
|
|
(when (memq action '(insert navigate))
|
|
(sp--looking-back-p "=>" 2)))
|
|
;; Enable ES6 arrow functions in web mode
|
|
(defun sp-after-equals-skip-p (ms mb _me)
|
|
(when (eq ms ">")
|
|
(save-excursion
|
|
(goto-char mb)
|
|
(sp--looking-back-p "=" 1))))
|
|
|
|
(defun sp-web-mode-is-code-context (id action context)
|
|
(and (eq action 'insert)
|
|
(not (or (get-text-property (point) 'part-side)
|
|
(get-text-property (point) 'block-side)))))
|
|
|
|
(sp-local-pair '(web-mode) "<" nil
|
|
:when '(sp-web-mode-is-code-context)
|
|
:unless '(:add sp-after-equals-p)
|
|
:skip-match 'sp-after-equals-skip-p)
|
|
:hook
|
|
(prog-mode . smartparens-strict-mode)
|
|
(eshell-mode . smartparens-strict-mode)
|
|
:general
|
|
;; Wrapping
|
|
(leader-map
|
|
"s(" #'sp-wrap-round
|
|
"s{" #'sp-wrap-curly
|
|
"s'" #'sp-wrap-single-quote
|
|
"s\"" #'sp-wrap-double-quote
|
|
"sW" #'sp-unwrap-sexp
|
|
"sl" #'sp-next-sexp
|
|
"sh" #'sp-backward-sexp
|
|
"sj" #'sp-down-sexp
|
|
"sk" #'sp-backward-up-sexp
|
|
"sL" #'sp-forward-symbol
|
|
"sH" #'sp-backward-symbol
|
|
"s^" #'sp-beginning-of-sexp
|
|
"s$" #'sp-end-of-sexp
|
|
"st" #'sp-transpose-sexp
|
|
"su" #'undo-tree-undo
|
|
"sy" #'sp-copy-sexp
|
|
"sd" #'sp-kill-sexp
|
|
"ss" #'sp-forward-slurp-sexp
|
|
"sS" #'sp-backward-slurp-sexp
|
|
"sb" #'sp-forward-barf-sexp
|
|
"sB" #'sp-backward-barf-sexp
|
|
"sv" #'sp-select-next-thing
|
|
"sV" #'sp-select-previous-thing)
|
|
(normal "g(" #'sp-wrap-round
|
|
"g[" #'sp-wrap-square
|
|
"g{" #'sp-wrap-curly
|
|
"g\"" #'sp-wrap-double-quote
|
|
"g'" #'sp-wrap-single-quote
|
|
"g<" #'sp-wrap-angle-bracket
|
|
"g`" #'sp-wrap-backtick))
|
|
|
|
(use-package evil-smartparens
|
|
:after (evil smartparens)
|
|
:hook (smartparens-enabled . evil-smartparens-mode))
|
|
|
|
;; Automagical indent
|
|
(use-package aggressive-indent
|
|
:hook ((lisp-mode . aggressive-indent-mode)
|
|
(emacs-lisp-mode . aggressive-indent-mode)
|
|
(clojure-mode . aggressive-indent-mode)))
|
|
|
|
;; Highlight indent level for whitespace-sensitive languages
|
|
(use-package highlight-indent-guides
|
|
:commands highlight-indent-guides-mode
|
|
:custom
|
|
(highlight-indent-guides-method 'character)
|
|
(highlight-indent-guides-auto-character-face-perc 7)
|
|
(highlight-indent-guides-responsive 'stack)
|
|
(highlight-indent-guides-auto-stack-character-face-perc 10))
|
|
|
|
;; Handy mode for prose writing and reading
|
|
(use-package olivetti
|
|
:general
|
|
("C-c o" #'olivetti-mode)
|
|
:custom
|
|
(olivetti-body-width 120))
|
|
|
|
;; Multiple cursors
|
|
(use-package evil-multiedit
|
|
:defer 2
|
|
:config
|
|
(evil-multiedit-default-keybinds))
|
|
|
|
;; Don't choke on files with long lines
|
|
(use-package so-long
|
|
:straight (:type built-in)
|
|
:demand t
|
|
:config
|
|
(global-so-long-mode))
|
|
|
|
;; Polite white-space trimming
|
|
(use-package ws-butler
|
|
:hook (prog-mode . ws-butler-mode))
|
|
|
|
;; Inc/dec numbers
|
|
(use-package evil-numbers
|
|
:straight (:host github :repo "juliapath/evil-numbers")
|
|
:general
|
|
(normal "g+" #'evil-numbers/inc-at-pt)
|
|
(normal "g-" #'evil-numbers/dec-at-pt)
|
|
(normal "g M-+" #'evil-numbers/inc-at-pt-incremental)
|
|
(normal "g M--" #'evil-numbers/dec-at-pt-incremental))
|
|
|
|
;; Manipulate string inflection, e.g. camelCase -> snake_case
|
|
(use-package evil-string-inflection
|
|
:general
|
|
(normal "gc" #'evil-operator-string-inflection))
|
|
|
|
(use-package origami
|
|
:hook ((prog-mode . origami-mode)
|
|
(text-mode . origami-mode))
|
|
:config
|
|
(defun origami-toggle-all-nodes-same-level (buffer point)
|
|
(interactive (list (current-buffer) (point)))
|
|
(when-let ((tree (origami-get-fold-tree buffer)))
|
|
(when-let ((path (origami-fold-find-path-containing tree point)))
|
|
(let ((parent (origami-fold-parent path)))
|
|
(dolist (fold (origami-fold-children parent))
|
|
(origami-toggle-node buffer (origami-fold-beg fold)))))))
|
|
(defun origami-setup ()
|
|
(evil-local-set-key 'normal (kbd "zM") #'origami-toggle-all-nodes-same-level))
|
|
(add-hook 'origami-mode-hook #'origami-setup))
|
|
|
|
;; Language detection of arbitrary strings/buffers
|
|
(use-package language-detection
|
|
:commands (language-detection-buffer
|
|
language-detection-string)
|
|
:init
|
|
(defun language-detection-detect-mode (string)
|
|
(let* ((map '((ada ada-mode)
|
|
(awk awk-mode)
|
|
(c c-mode)
|
|
(cpp c++-mode)
|
|
(clojure clojure-mode lisp-mode)
|
|
(csharp csharp-mode java-mode)
|
|
(css css-mode)
|
|
(dart dart-mode)
|
|
(delphi delphi-mode)
|
|
(emacslisp emacs-lisp-mode)
|
|
(erlang erlang-mode)
|
|
(fortran fortran-mode)
|
|
(fsharp fsharp-mode)
|
|
(go go-mode)
|
|
(groovy groovy-mode)
|
|
(haskell haskell-mode)
|
|
(html html-mode)
|
|
(java java-mode)
|
|
(javascript javascript-mode)
|
|
(json json-mode javascript-mode)
|
|
(latex latex-mode)
|
|
(lisp lisp-mode)
|
|
(lua lua-mode)
|
|
(matlab matlab-mode octave-mode)
|
|
(objc objc-mode c-mode)
|
|
(perl perl-mode)
|
|
(php php-mode)
|
|
(prolog prolog-mode)
|
|
(python python-mode)
|
|
(r r-mode)
|
|
(ruby ruby-mode)
|
|
(rust rust-mode)
|
|
(scala scala-mode)
|
|
(shell shell-script-mode)
|
|
(smalltalk smalltalk-mode)
|
|
(sql sql-mode)
|
|
(swift swift-mode)
|
|
(visualbasic visual-basic-mode)
|
|
(xml sgml-mode)))
|
|
(language (language-detection-string string))
|
|
(modes (cdr (assoc language map)))
|
|
(mode (cl-loop for mode in modes
|
|
when (fboundp mode)
|
|
return mode)))
|
|
(when (fboundp mode)
|
|
mode)))
|
|
(defun fontify-with-mode (mode text)
|
|
(with-temp-buffer
|
|
(insert text)
|
|
(delay-mode-hooks (funcall mode))
|
|
(font-lock-default-function mode)
|
|
(font-lock-default-fontify-region (point-min) (point-max) nil)
|
|
(buffer-string)))
|
|
(defun fontify-using-faces (text)
|
|
(let ((pos 0))
|
|
(while (setq next (next-single-property-change pos 'face text))
|
|
(put-text-property pos next 'font-lock-face (get-text-property pos 'face text) text)
|
|
(setq pos next))
|
|
(add-text-properties 0 (length text) '(fontified t) text)
|
|
text))
|
|
(defun language-detection-fontify-region (start end)
|
|
(interactive "r")
|
|
(let* ((text (buffer-substring-no-properties start end))
|
|
(mode (language-detection-detect-mode text))
|
|
(fontified (fontify-using-faces (fontify-with-mode mode text))))
|
|
(delete-region start end)
|
|
(insert fontified)))
|
|
(defun language-detection-fontify-buffer ()
|
|
(interactive)
|
|
(language-detection-fontify-region (point-min) (point-max))))
|
|
|
|
|
|
(provide 'init-editing)
|