;; icomplete
;; (use-package icomplete
;;   :disable
;;   :ensure nil
;;   :demand t
;;   :bind (:map icomplete-minibuffer-map
;;          ("C-S-s" . kill-line)
;;          ("C-j" . icomplete-forward-completions)
;;          ("C-k" . icomplete-backward-completions)
;;          ("DEL" . icomplete-fido-backward-updir)
;;          ("M-DEL". delete-backward-char)
;;          ("M-RET" . icomplete-force-complete-and-exit)
;;          ("TAB" . icomplete-force-complete)
;;          ("<escape>" . abort-recursive-edit)
;;          ("C-;" . embark-dwim)
;;          ("C-." . embark-act)
;;          ("<left>" . backward-char)
;;          ("<right>" . forward-char))
;;   :hook (icomplete-minibuffer-setup . my/icomplete-setup-hook-func)
;;   :init
;;   (defun my/icomplete-setup-hook-func ()
;;     (setq truncate-lines t))
;;   (setq completion-ignore-case t
;;         read-file-name-completion-ignore-case t
;;         read-buffer-completion-ignore-case t
;;         enable-recursive-minibuffers t
;;         minibuffer-prompt-properties '(read-only t
;;                                        cursor-intangible t
;;                                        face minibuffer-prompt)
;;         ;;completions-detailed t
;;         icomplete-compute-delay 0
;;         icomplete-scroll t)
;;   (defun my/crm-indicator (args)
;;     (cons (format "[CRM%s] %s"
;;                   (replace-regexp-in-string
;;                    "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
;;                    crm-separator)
;;                   (car args))
;;           (cdr args)))
;;   (advice-add #'completing-read-multiple :filter-args #'my/crm-indicator)
;;   (defun my/marginalia-trim-right (list)
;;     (cl-loop for (cand prefix suffix) in list collect
;;              (list cand prefix (string-trim-right suffix))))
;;   (advice-add #'marginalia--align :filter-return #'my/marginalia-trim-right)
;;   :config
;;   (set-face-attribute 'icomplete-selected-match nil :inherit 'region)
;;   (fido-mode 1)
;;   (fido-vertical-mode 1))

;; lsp-mode
;; (use-package consult-lsp)
;; (use-package lsp-mode
;;   :hook (((c-ts-mode c++-ts-mode java-ts-mode rust-ts-mode python-ts-mode
;;            latex-mode markdown-mode blueprint-ts-mode) . lsp-mode)
;;          (lsp-mode . my/-setup-lsp-mode-buffer))
;;   :init
;;   (setq lsp-completion-provider :none
;;         lsp-headerline-breadcrumb-enable nil
;;         lsp-inlay-hint-enable nil
;;         lsp-signature-doc-lines 1)
;;   (defun my/-setup-lsp-mode-buffer ()
;;     "Called by `lsp-mode-hook' to setup lsp-mode buffers."
;;     (evil-define-key '(normal visual motion) 'local
;;       "gR" #'lsp-rename
;;       "gA" #'lsp-execute-code-action
;;       "gs" #'consult-lsp-symbols)
;;     (setq-local evil-lookup-func #'lsp-describe-thing-at-point)))

;; vterm
;; (use-package vterm
;;   :hook (vterm-mode . with-editor-export-editor)
;;   :init
;;   (defvar my/project-vterm-hash-table (make-hash-table :test 'equal)
;;     "Hash table that maps project root dirs to vterm buffers.")
;;   (defun my/project-vterm (prompt)
;;     "Switch to or create a vterm buffer in the current projects root."
;;     (interactive (list t))
;;     (if-let ((proj (project-current prompt))
;;              (default-directory (project-root proj)))
;;         (if-let ((vterm-buff (gethash default-directory
;;                                       my/project-vterm-hash-table))
;;                  ((buffer-live-p vterm-buff)))
;;             (switch-to-buffer vterm-buff)
;;           (puthash default-directory
;;                    (vterm (concat "*vterm for project " default-directory "*"))
;;                    my/project-vterm-hash-table))))
;;   (defun my/project-vterm-or-default ()
;;     "Open a vterm for the current project, otherwise, open a normal vterm."
;;     (interactive)
;;     (unless (my/project-vterm nil)
;;       (if-let ((vterm-buff (gethash nil my/project-vterm-hash-table))
;;                ((buffer-live-p vterm-buff)))
;;           (switch-to-buffer vterm-buff)
;;         (puthash nil (vterm vterm-buffer-name) my/project-vterm-hash-table)))))

;; ai stuff (also mostly fun)
;; (use-package ellama
;;   :defer nil
;;   :custom
;;   (ellama-sessions-directory (no-littering-expand-var-file-name
;;                               "ellama-sessions"))
;;   (ellama-major-mode 'markdown-mode) ;; fix text inserting at top of buffer
;;   (ellama-session-file-extension "md")
;;   (ellama-nick-prefix "##")
;;   (ellama-keymap-prefix "C-c m")
;;   :hook (ellama-session-mode . my/-ellama-startup-hook)
;;   :init
;;   (defun my/-ellama-startup-hook ()
;;     "Hook to do stuff in llama buffers."
;;     (auto-fill-mode -1)))

;; company (in buffer auto-complete)
;; (use-package company
;;   :defer nil
;;   :bind (("M-TAB" . company-complete)
;;          ("M-<tab>" . company-complete)
;;          ("C-c f" . company-files)
;;          ([remap dabbrev-expand] . company-dabbrev)
;;          :map prog-mode-map
;;          ([remap company-dabbrev] . company-dabbrev-code))
;;   :hook ((company-search-mode . my/-company-search-mode-add-lighter)
;;          (sh-mode . my/-company-setup-shell-mode))
;;   :config
;;   (defun my/-company-setup-shell-mode ()
;;     (setq-local company-backends '(company-files company-keywords
;;                                                  company-dabbrev-code)))
;;   (defun my/-company-search-mode-add-lighter ()
;;     (if company-search-mode
;;         (cl-pushnew company-search-lighter global-mode-string :test 'equal)
;;       (setq global-mode-string
;;             (cl-delete company-search-lighter global-mode-string :test 'equal))))
;;   (defun my/-company-set-completion-styles (oldfun &rest args)
;;     (let ((completion-styles '(basic emacs21 flex)))
;;       (apply oldfun args)))
;;   (advice-add 'company-capf :around 'my/-company-set-completion-styles)
;;   (setopt company-format-margin-function #'company-text-icons-margin
;;           company-require-match nil
;;           company-tooltip-align-annotations t)
;;   (setq company-transformers '(company-sort-by-occurrence))
;;   (global-company-mode 1))
;; (use-package company-quickhelp
;;   :bind (:map company-active-map
;;          ("M-h" . company-quickhelp-manual-begin))
;;   :after company
;;   :config
;;   (company-quickhelp-mode 1)
;;   (setopt company-quickhelp-delay nil))

;; (La)TeX
;; (use-package tex-mode
;;   :hook ((latex-mode . eglot-ensure)
;;          (tex-mode . my/-setup-tex-mode-compile-command))
;;   :init
;;   (defun my/-setup-tex-mode-compile-command ()
;;     "Setup `compile-command' for `tex-mode'."
;;     (let ((quoted-name (shell-quote-argument buffer-file-name)))
;;       (setq-local compile-command
;;                   (concat "latexmk -pdf "
;;                           "-auxdir=" quoted-name "-build"
;;                           " " quoted-name))))
;;   :config
;;   (add-to-list 'auto-mode-alist '("/\\.latexmkrc\\'" . perl-mode)))

;; flyspell
;; (use-package flyspell
;;   :hook
;;   (((text-mode message-mode tex-mode) . flyspell-mode)
;;    (prog-mode . flyspell-prog-mode))
;;   :config
;;   (setq ispell-program-name "hunspell"
;;         flyspell-issue-message-flag nil
;;         flyspell-issue-welcome-flag nil)
;;   (define-key flyspell-mode-map (kbd "C-;") nil t)
;;   (define-key flyspell-mode-map (kbd "C-,") nil t))

;; (use-package aggressive-indent
;;   :hook (prog-mode . aggressive-indent-mode)
;;   :config
;;   (add-to-list 'aggressive-indent-protected-commands
;;                #'evil-undo))

;; ;; easier identification of local variables
;; (use-package color-identifiers-mode
;;   :hook (prog-mode . color-identifiers-mode-maybe)
;;   :init
;;   (setq color-identifiers:num-colors 10
;;         color-identifiers:recoloring-delay 0.5)
;;   :config
;;   ;; make sure that remapped treesitter modes are handled
;;   (defun my/color-identifiers-mode-remap-ts-modes ()
;;     (dolist (entry color-identifiers:modes-alist)
;;       (cl-destructuring-bind (mode &rest props) entry
;;         (when-let ((remapped-mode (alist-get mode major-mode-remap-alist))
;;                    ((string-match-p "-ts-" (symbol-name remapped-mode)))
;;                    ((not (assq remapped-mode color-identifiers:modes-alist))))
;;           ;; no need to test with `add-to-list'
;;           (push (cons remapped-mode props) color-identifiers:modes-alist)))))
;;   (my/color-identifiers-mode-remap-ts-modes)
;;   (setf (alist-get 'lisp-interaction-mode color-identifiers:modes-alist)
;;         (alist-get 'emacs-lisp-mode color-identifiers:modes-alist))
;;   (defun my/-color-identifiers-elisp-handle-let-like (sexp output)
;;     (cl-destructuring-bind (_name &optional vars &rest body) sexp
;;       (dolist (entry vars body)
;;         (cond
;;          ((and entry (symbolp entry)) (puthash entry t output))
;;          ((and (car entry) (symbolp (car entry)))
;;           (puthash (car entry) t output))))))
;;   (defun my/-color-identifiers-parse-lambda-list (list output)
;;     (dolist (entry list)
;;       (cond
;;        ((and entry (symbolp entry)
;;              (not (string-prefix-p ":" (symbol-name entry)))
;;              (not (string-prefix-p "&" (symbol-name entry))))
;;         (puthash entry t output))
;;        ((and (car-safe entry) (symbolp (car entry)))
;;         (puthash (car entry) t output)))))
;;   (defun my/-color-identifiers-elisp-handle-destructing-bind-like
;;       (sexp output)
;;     (cl-destructuring-bind (_name &optional vars &rest expr-and-body) sexp
;;       (my/-color-identifiers-parse-lambda-list vars output)
;;       expr-and-body))
;;   (defun my/-color-identifiers-elisp-handle-defun-like
;;       (sexp output)
;;     (cl-destructuring-bind (_name _func &optional vars &rest body) sexp
;;       (my/-color-identifiers-parse-lambda-list vars output)
;;       body))
;;   (defun my/-color-identifiers-elisp-handle-dolist-like
;;       (sexp output)
;;     (cl-destructuring-bind (_name &optional spec &rest body) sexp
;;       (cl-destructuring-bind (&optional var &rest forms) spec
;;         (when (symbolp var)
;;           (puthash var t output))
;;         (append body forms))))
;;   (defun my/-color-identifiers-elisp-handle-loop (sexp output)
;;     (let (body-forms)
;;       (cl-maplist
;;        (lambda (kwds)
;;          (cl-case (car kwds)
;;           (for ;; this could be a dotted list
;;            (let ((tail (ensure-list (cadr kwds))))
;;              (while tail
;;                (when (and (consp tail) (symbolp (car tail)))
;;                  (puthash (car tail) t output))
;;                (when (and (consp tail) (symbolp (cdr tail)))
;;                  (puthash (cdr tail) t output))
;;                (setq tail (cdr-safe tail)))))
;;           (using
;;            (when (and (listp (cdr kwds))
;;                       (symbolp (cl-second (cdr kwds))))
;;              (puthash (cl-second (cdr kwds)) t output)))
;;           ((with into)
;;            (when (symbolp (cadr kwds))
;;              (puthash (cadr kwds) t output)))
;;           (t
;;            (unless (atom (car kwds))
;;              (push (car kwds) body-forms)))))
;;        (cdr sexp))
;;       body-forms))
;;   (defun my/-color-identifiers-elisp-handle-do-like (sexp output)
;;     (let ((eval-forms))
;;       (cl-destructuring-bind (name &optional vars test-forms &rest body) sexp
;;         (dolist (entry vars (append eval-forms test-forms body))
;;           (cl-destructuring-bind (&optional var init step &rest _)
;;               entry
;;             (when (symbolp var)
;;               (puthash var t output)
;;               (cl-callf nconc eval-forms (list init step))))))))
;;   (defvar my/-color-identifiers-eslip-handlers
;;     (let ((table (make-hash-table)))
;;       (puthash 'quote #'ignore table)
;;       (puthash 'function #'ignore table)
;;       (puthash 'let #'my/-color-identifiers-elisp-handle-let-like table)
;;       (puthash 'let* #'my/-color-identifiers-elisp-handle-let-like table)
;;       (puthash 'cl-destructuring-bind
;;                #'my/-color-identifiers-elisp-handle-destructing-bind-like table)
;;       (puthash 'with-slots
;;                #'my/-color-identifiers-elisp-handle-destructing-bind-like table)
;;       (puthash 'lambda
;;                #'my/-color-identifiers-elisp-handle-destructing-bind-like table)
;;       (puthash 'cl-function
;;                #'my/-color-identifiers-elisp-handle-destructing-bind-like table)
;;       (puthash 'defun
;;                #'my/-color-identifiers-elisp-handle-defun-like table)
;;       (puthash 'cl-defun
;;                #'my/-color-identifiers-elisp-handle-defun-like table)
;;       (puthash 'defmacro
;;                #'my/-color-identifiers-elisp-handle-defun-like table)
;;       (puthash 'cl-defmacro
;;                #'my/-color-identifiers-elisp-handle-defun-like table)
;;       (puthash 'cl-defmacro
;;                #'my/-color-identifiers-elisp-handle-defun-like table)
;;       (puthash 'cl-loop
;;                #'my/-color-identifiers-elisp-handle-loop table)
;;       (puthash 'dolist
;;                #'my/-color-identifiers-elisp-handle-dolist-like table)
;;       (puthash 'dotimes
;;                #'my/-color-identifiers-elisp-handle-dolist-like table)
;;       (puthash 'cl-dolist
;;                #'my/-color-identifiers-elisp-handle-dolist-like table)
;;       (puthash 'cl-dotimes
;;                #'my/-color-identifiers-elisp-handle-dolist-like table)
;;       (puthash 'cl-do
;;                #'my/-color-identifiers-elisp-handle-do-like table)
;;       table)
;;     "A list of functions that find declarations in variables.
;; This is used in `my/-color-identifiers-elisp-declarations-in-sexp'.  It is a
;; hash table of function (or macro) names and a function that handles them.  The
;; functions should be of two arguments.  The first is the sexp to parse.  The
;; second is a hash table with the keys being the symbols of local variables.  The
;; function should return a list of the forms that it contains that should be
;; recursively searched.")
;;   (defun my/-color-identifiers-lisp-declarations-in-sexp (sexp output table)
;;     "Get all of the variable declarations in SEXP and place them in OUTPUT.
;; OUTPUT is a hash table. TABLE is a table like
;; `my/-color-identifiers-elisp-declarations-in-sexp'."
;;     (let ((stack (list sexp)))
;;       (while (and stack (not (input-pending-p)))
;;         (let ((entry (pop stack)))
;;           (when (proper-list-p entry)
;;             (if-let ((handler (gethash (car entry) table)))
;;                 (cl-callf nconc stack
;;                   (copy-sequence (funcall handler entry output)))
;;               (cl-callf nconc stack
;;                 (copy-sequence (cdr entry)))))))))
;;   (defun my/-color-identifiers-lisp-declarations-in-buffer (&optional buffer)
;;     (let ((result (make-hash-table)))
;;       (save-excursion
;;         (goto-char (point-min))
;;         (condition-case nil
;;             (while t
;;               (condition-case nil
;;                   (let ((sexp (read (or buffer (current-buffer)))))
;;                     (my/-color-identifiers-lisp-declarations-in-sexp
;;                      sexp result my/-color-identifiers-eslip-handlers))
;;                 (invalid-read-syntax nil)))
;;           (end-of-file nil))
;;         (let ((names))
;;           (maphash (lambda (k _v)
;;                      (unless (or (eq k t) (not k) (boundp k))
;;                        (push (symbol-name k) names)))
;;                    result)
;;           names))))
;;   (color-identifiers:set-declaration-scan-fn
;;    'emacs-lisp-mode
;;    'my/-color-identifiers-lisp-declarations-in-buffer)
;;   (color-identifiers:set-declaration-scan-fn
;;    'lisp-interaction-mode
;;    'my/-color-identifiers-lisp-declarations-in-buffer))