diff --git a/.config/guix/manifests/emacs.scm b/.config/guix/manifests/emacs.scm index 008518d..5a29131 100644 --- a/.config/guix/manifests/emacs.scm +++ b/.config/guix/manifests/emacs.scm @@ -6,8 +6,8 @@ "imagemagick" "yt-dlp" "mpv" + "graphviz" + "emacs-emacsql-sqlite3" "python-isort" "python-yapf" - "plantuml" - "graphviz" - "emacs-emacsql-sqlite3")) + "plantuml")) diff --git a/.emacs.d/init.el b/.emacs.d/init.el index 0bab5f7..ae1966d 100644 --- a/.emacs.d/init.el +++ b/.emacs.d/init.el @@ -1,12 +1,4 @@ -(add-hook 'emacs-startup-hook - (lambda () - (message "*** Emacs loaded in %s with %d garbage collections." - (format "%.2f seconds" - (float-time - (time-subtract after-init-time before-init-time))) - gcs-done))) - -;; (setq use-package-verbose t) +(setq use-package-verbose t) (defvar bootstrap-version) (let ((bootstrap-file @@ -41,6 +33,16 @@ (setenv "IS_EMACS" "true") +(add-hook 'emacs-startup-hook + (lambda () + (message "*** Emacs loaded in %s with %d garbage collections." + (format "%.2f seconds" + (float-time + (time-subtract after-init-time before-init-time))) + gcs-done))) + +;; (setq use-package-verbose t) + (setq gc-cons-threshold 80000000) (setq read-process-output-max (* 1024 1024)) @@ -419,15 +421,6 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer." ("kill" (evil-quit)) (- (i3-msg command)))) -(use-package visual-fill-column - :straight t - :config - (add-hook 'visual-fill-column-mode-hook - (lambda () (setq visual-fill-column-center-text t)))) - -(use-package smartparens - :straight t) - (use-package aggressive-indent :commands (aggressive-indent-mode) :straight t) @@ -441,12 +434,6 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer." (unless (cl-some #'derived-mode-p my/trailing-whitespace-modes) (delete-trailing-whitespace)))) -(use-package expand-region - :straight t - :commands (er/expand-region) - :init - (general-nmap "+" 'er/expand-region)) - (setq tab-always-indent nil) (setq-default default-tab-width 4) @@ -482,135 +469,34 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer." (setq undo-strong-limit 100663296) (setq undo-outer-limit 1006632960)) -(use-package helpful - :straight t - :commands (helpful-callable - helpful-variable - helpful-key - helpful-macro - helpful-function - helpful-command)) - -(my-leader-def - :infix "h" - "" '(:which-key "help") - "RET" 'view-order-manuals - "." 'display-local-help - "?" 'help-for-help - "C" 'describe-coding-system - "F" 'Info-goto-emacs-command-node - "I" 'describe-input-method - "K" 'Info-goto-emacs-key-command-node - "L" 'describe-language-environment - "P" 'describe-package - "S" 'info-lookup-symbol - "a" 'helm-apropos - "b" 'describe-bindings - "c" 'describe-key-briefly - "d" 'apropos-documentation - "e" 'view-echo-area-messages - "f" 'helpful-function - "g" 'describe-gnu-project - "h" 'view-hello-file - "i" 'info - "k" 'helpful-key - "l" 'view-lossage - "m" 'describe-mode - "n" 'view-emacs-news - "o" 'describe-symbol - "p" 'finder-by-keyword - "q" 'help-quit - "r" 'info-emacs-manual - "s" 'describe-syntax - "t" 'help-with-tutorial - "v" 'helpful-variable - "w" 'where-is - "" 'help-for-help) - -(use-package ivy - :straight t - :config - (setq ivy-use-virtual-buffers t) - (ivy-mode)) - -(use-package counsel - :straight t - :after ivy - :config - (counsel-mode)) - -(use-package swiper - :defer t +(use-package yasnippet-snippets :straight t) -(use-package ivy-rich +(use-package yasnippet :straight t - :after ivy :config - (ivy-rich-mode 1) - (setcdr (assq t ivy-format-functions-alist) #'ivy-format-function-line)) + (setq yas-snippet-dirs + `(,(concat (expand-file-name user-emacs-directory) "snippets") + yasnippet-snippets-dir)) + (setq yas-triggers-in-field t) + (yas-global-mode 1)) -(use-package ivy-prescient +(general-imap "M-TAB" 'company-yasnippet) + +(use-package smartparens + :straight t) + +(use-package expand-region + :straight t + :commands (er/expand-region) + :init + (general-nmap "+" 'er/expand-region)) + +(use-package visual-fill-column :straight t - :after counsel :config - (ivy-prescient-mode +1) - (setq ivy-prescient-retain-classic-highlighting t) - (prescient-persist-mode 1) - (setq ivy-prescient-sort-commands - '(:not swiper - swiper-isearch - ivy-switch-buffer - ;; ivy-resume - ;; ivy--restore-session - lsp-ivy-workspace-symbol - dap-switch-stack-frame - my/dap-switch-stack-frame - dap-switch-session - dap-switch-thread - counsel-grep - ;; counsel-find-file - counsel-git-grep - counsel-rg - counsel-ag - counsel-ack - counsel-fzf - counsel-pt - counsel-imenu - counsel-yank-pop - counsel-recentf - counsel-buffer-or-recentf - proced-filter-interactive - proced-sort-interactive)) - ;; Do not use prescient in find-file - (ivy--alist-set 'ivy-sort-functions-alist #'read-file-name-internal #'ivy-sort-file-function-default)) - -(my-leader-def - :infix "f" - "" '(:which-key "various completions")' - ;; "b" 'counsel-switch-buffer - "b" 'persp-ivy-switch-buffer - "e" 'conda-env-activate - "f" 'project-find-file - "c" 'counsel-yank-pop - "a" 'counsel-rg - "A" 'counsel-ag) - -(general-define-key - :states '(insert normal) - "C-y" 'counsel-yank-pop) - -(my-leader-def "SPC" 'ivy-resume) -(my-leader-def "s" 'swiper-isearch - "S" 'swiper-all) - -(general-define-key - :keymaps '(ivy-minibuffer-map swiper-map) - "M-j" 'ivy-next-line - "M-k" 'ivy-previous-line - "" 'ivy-call - "M-RET" 'ivy-immediate-done - [escape] 'minibuffer-keyboard-quit) + (add-hook 'visual-fill-column-mode-hook + (lambda () (setq visual-fill-column-center-text t)))) (use-package treemacs :straight t @@ -698,23 +584,6 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer." (general-nmap "C-p" 'counsel-projectile-find-file) -(use-package company - :straight t - :config - (global-company-mode) - (setq company-idle-delay (if my/lowpower 0.5 0.125)) - (setq company-dabbrev-downcase nil) - (setq company-show-numbers t)) - -(general-imap "C-SPC" 'company-complete) - -(use-package company-box - :straight t - :disabled - :if (and (display-graphic-p) (not my/lowpower)) - :after (company) - :hook (company-mode . company-box-mode)) - (use-package magit :straight t :commands (magit-status magit-file-dispatch) @@ -754,19 +623,152 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer." (add-to-list 'editorconfig-indentation-alist '(emmet-mode emmet-indentation))) -(use-package yasnippet-snippets - :straight t) - -(use-package yasnippet +(use-package ivy :straight t :config - (setq yas-snippet-dirs - `(,(concat (expand-file-name user-emacs-directory) "snippets") - yasnippet-snippets-dir)) - (setq yas-triggers-in-field t) - (yas-global-mode 1)) + (setq ivy-use-virtual-buffers t) + (ivy-mode)) -(general-imap "M-TAB" 'company-yasnippet) +(use-package counsel + :straight t + :after ivy + :config + (counsel-mode)) + +(use-package swiper + :defer t + :straight t) + +(use-package ivy-rich + :straight t + :after ivy + :config + (ivy-rich-mode 1) + (setcdr (assq t ivy-format-functions-alist) #'ivy-format-function-line)) + +(use-package ivy-prescient + :straight t + :after counsel + :config + (ivy-prescient-mode +1) + (setq ivy-prescient-retain-classic-highlighting t) + (prescient-persist-mode 1) + (setq ivy-prescient-sort-commands + '(:not swiper + swiper-isearch + ivy-switch-buffer + ;; ivy-resume + ;; ivy--restore-session + lsp-ivy-workspace-symbol + dap-switch-stack-frame + my/dap-switch-stack-frame + dap-switch-session + dap-switch-thread + counsel-grep + ;; counsel-find-file + counsel-git-grep + counsel-rg + counsel-ag + counsel-ack + counsel-fzf + counsel-pt + counsel-imenu + counsel-yank-pop + counsel-recentf + counsel-buffer-or-recentf + proced-filter-interactive + proced-sort-interactive)) + ;; Do not use prescient in find-file + (ivy--alist-set 'ivy-sort-functions-alist #'read-file-name-internal #'ivy-sort-file-function-default)) + +(my-leader-def + :infix "f" + "" '(:which-key "various completions")' + ;; "b" 'counsel-switch-buffer + "b" 'persp-ivy-switch-buffer + "e" 'conda-env-activate + "f" 'project-find-file + "c" 'counsel-yank-pop + "a" 'counsel-rg + "A" 'counsel-ag) + +(general-define-key + :states '(insert normal) + "C-y" 'counsel-yank-pop) + +(my-leader-def "SPC" 'ivy-resume) +(my-leader-def "s" 'swiper-isearch + "S" 'swiper-all) + +(general-define-key + :keymaps '(ivy-minibuffer-map swiper-map) + "M-j" 'ivy-next-line + "M-k" 'ivy-previous-line + "" 'ivy-call + "M-RET" 'ivy-immediate-done + [escape] 'minibuffer-keyboard-quit) + +(use-package company + :straight t + :config + (global-company-mode) + (setq company-idle-delay (if my/lowpower 0.5 0.125)) + (setq company-dabbrev-downcase nil) + (setq company-show-numbers t)) + +(general-imap "C-SPC" 'company-complete) + +(use-package company-box + :straight t + :disabled + :if (and (display-graphic-p) (not my/lowpower)) + :after (company) + :hook (company-mode . company-box-mode)) + +(use-package helpful + :straight t + :commands (helpful-callable + helpful-variable + helpful-key + helpful-macro + helpful-function + helpful-command)) + +(my-leader-def + :infix "h" + "" '(:which-key "help") + "RET" 'view-order-manuals + "." 'display-local-help + "?" 'help-for-help + "C" 'describe-coding-system + "F" 'Info-goto-emacs-command-node + "I" 'describe-input-method + "K" 'Info-goto-emacs-key-command-node + "L" 'describe-language-environment + "P" 'describe-package + "S" 'info-lookup-symbol + "a" 'helm-apropos + "b" 'describe-bindings + "c" 'describe-key-briefly + "d" 'apropos-documentation + "e" 'view-echo-area-messages + "f" 'helpful-function + "g" 'describe-gnu-project + "h" 'view-hello-file + "i" 'info + "k" 'helpful-key + "l" 'view-lossage + "m" 'describe-mode + "n" 'view-emacs-news + "o" 'describe-symbol + "p" 'finder-by-keyword + "q" 'help-quit + "r" 'info-emacs-manual + "s" 'describe-syntax + "t" 'help-with-tutorial + "v" 'helpful-variable + "w" 'where-is + "" 'help-for-help) (use-package wakatime-mode :straight (:host github :repo "SqrtMinusOne/wakatime-mode") @@ -804,17 +806,26 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer." (setq make-pointer-invisible t) +(show-paren-mode 1) + +(global-hl-line-mode 1) + (global-display-line-numbers-mode 1) (line-number-mode nil) (setq display-line-numbers-type 'visual) (column-number-mode) -(show-paren-mode 1) - (setq word-wrap 1) (global-visual-line-mode 1) -(global-hl-line-mode 1) +(setq-default frame-title-format + '("" + "emacs" + (:eval + (let ((project-name (projectile-project-name))) + (if (not (string= "-" project-name)) + (format ":%s@%s" project-name (system-name)) + (format "@%s" (system-name))))))) (use-package auto-dim-other-buffers :straight t @@ -882,14 +893,82 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer." (set-frame-font "JetBrainsMono Nerd Font 10" nil t) -(setq-default frame-title-format - '("" - "emacs" - (:eval - (let ((project-name (projectile-project-name))) - (if (not (string= "-" project-name)) - (format ":%s@%s" project-name (system-name)) - (format "@%s" (system-name))))))) +(use-package ligature + :straight (:host github :repo "mickeynp/ligature.el") + :if (display-graphic-p) + :config + (ligature-set-ligatures + '( + typescript-mode + js2-mode + vue-mode + svelte-mode + scss-mode + php-mode + python-mode + js-mode + markdown-mode + clojure-mode + go-mode + sh-mode + haskell-mode + web-mode) + '("--" "---" "==" "===" "!=" "!==" "=!=" "=:=" "=/=" "<=" + ">=" "&&" "&&&" "&=" "++" "+++" "***" ";;" "!!" "??" + "?:" "?." "?=" "<:" ":<" ":>" ">:" "<>" "<<<" ">>>" + "<<" ">>" "||" "-|" "_|_" "|-" "||-" "|=" "||=" "##" + "###" "####" "#{" "#[" "]#" "#(" "#?" "#_" "#_(" "#:" + "#!" "#=" "^=" "<$>" "<$" "$>" "<+>" "<+" "+>" "<*>" + "<*" "*>" "" "/>" "" "->" "->>" + "<<-" "<-" "<=<" "=<<" "<<=" "<==" "<=>" "<==>" "==>" "=>" + "=>>" ">=>" ">>=" ">>-" ">-" ">--" "-<" "-<<" ">->" "<-<" + "<-|" "<=|" "|=>" "|->" "<->" "<~~" "<~" "<~>" "~~" "~~>" + "~>" "~-" "-~" "~@" "[||]" "|]" "[|" "|}" "{|" "[<" + ">]" "|>" "<|" "||>" "<||" "|||>" "<|||" "<|>" "..." ".." + ".=" ".-" "..<" ".?" "::" ":::" ":=" "::=" ":?" ":?>" + "//" "///" "/*" "*/" "/=" "//=" "/==" "@_" "__")) + (global-ligature-mode t)) + +(use-package all-the-icons + :if (display-graphic-p) + :straight t) + +(use-package highlight-indent-guides + :straight t + :if (not (or my/lowpower my/remote-server)) + :hook ( + (prog-mode . highlight-indent-guides-mode) + (vue-mode . highlight-indent-guides-mode) + (LaTeX-mode . highlight-indent-guides-mode)) + :config + (setq highlight-indent-guides-method 'bitmap) + (setq highlight-indent-guides-bitmap-function 'highlight-indent-guides--bitmap-line)) + +(use-package rainbow-delimiters + :straight t + :if (not my/lowpower) + :hook ((prog-mode . rainbow-delimiters-mode))) + +(use-package rainbow-mode + :commands (rainbow-mode) + :straight t) + +(use-package hl-todo + :hook (prog-mode . hl-todo-mode) + :straight t) + +(use-package doom-modeline + :straight t + ;; :if (not (display-graphic-p)) + :init + (setq doom-modeline-env-enable-python nil) + (setq doom-modeline-env-enable-go nil) + (setq doom-modeline-buffer-encoding 'nondefault) + (setq doom-modeline-hud t) + :config + (doom-modeline-mode 1) + (setq doom-modeline-minor-modes nil) + (setq doom-modeline-buffer-state-icon nil)) (use-package perspective :straight t @@ -932,499 +1011,1227 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer." "m" #'my/persp-move-window-and-switch "f" #'my/persp-copy-window-and-switch)) -(setq my/project-title-separators "[-_ ]") - -(setq my/project-names-override-alist - '((".password-store" . "pass"))) - -(defun my/shorten-project-name-elem (elem crop) - (if (string-match "^\\[.*\\]$" elem) - (concat "[" - (my/shorten-project-name-elem (substring elem 1 (- (length elem) 1)) crop) - "]") - (let* ((prefix (car (s-match my/project-title-separators elem))) - (rest - (substring - (if prefix - (substring elem (length prefix)) - elem) - 0 (if crop 1 nil)))) - (concat prefix rest)))) - -(defun my/shorten-project-name (project-name) - (or - (cdr (assoc project-name my/project-names-override-alist)) - (let ((elems (s-slice-at my/project-title-separators project-name))) - (concat - (apply - #'concat - (cl-mapcar (lambda (elem) (my/shorten-project-name-elem elem t)) (butlast elems))) - (my/shorten-project-name-elem (car (last elems)) nil))))) - -(defun my/tab-bar-name-function () - (let ((project-name (projectile-project-name))) - (if (string= "-" project-name) - (tab-bar-tab-name-current-with-count) - (concat "[" (my/shorten-project-name project-name) "] " - (replace-regexp-in-string "<.*>" "" (tab-bar-tab-name-current-with-count)))))) - -(setq tab-bar-tab-name-function #'my/tab-bar-name-function) - -(use-package doom-modeline +(use-package lsp-mode :straight t - ;; :if (not (display-graphic-p)) - :init - (setq doom-modeline-env-enable-python nil) - (setq doom-modeline-env-enable-go nil) - (setq doom-modeline-buffer-encoding 'nondefault) - (setq doom-modeline-hud t) - :config - (doom-modeline-mode 1) - (setq doom-modeline-minor-modes nil) - (setq doom-modeline-buffer-state-icon nil)) - -(use-package spaceline - :straight t - :disabled - :config - (defun my/format-perspective-list () - (format "[%s]" - (let ((curr (persp-current-name))) - (mapconcat - (lambda (name) - (if (string-equal name curr) - (propertize - name - 'face - 'persp-selected-face) - name)) - (persp-names) - "|")))) - - (defvar my/spaceline-persp-list "") - - (defun my/persp-update-advice (&rest _) - (setq my/spaceline-persp-list (my/format-perspective-list))) - - (advice-add #'persp-update-modestring :after #'my/persp-update-advice) - (add-hook 'buffer-list-update-hook #'my/persp-update-advice) - (add-hook 'find-file-hook #'my/persp-update-advice) - - (spaceline-define-segment perspective - "Perspective.el" - my/spaceline-persp-list) - (defvar my/exwm-mode-line-info-no-props "") - - (spaceline-define-segment exwm - my/exwm-mode-line-info-no-props) - (spaceline-define-segment debug-on-error - (when debug-on-error - (propertize - "" - 'face 'warning - 'local-map (let ((map (make-sparse-keymap))) - (define-key map - [mode-line mouse-1] - #'toggle-debug-on-error) - map)))) - - (spaceline-define-segment debug-on-quit - (when debug-on-quit - (propertize - "" - 'face 'error - 'local-map (let ((map (make-sparse-keymap))) - (define-key map - [mode-line mouse-1] - #'toggle-debug-on-quit) - map)))) - (require 'spaceline-config) - - (spaceline-compile - "my" - '((evil-state :priority 100 :face (spaceline-highlight-face-evil-state)) - (buffer-modified :priority 50) - (version-control :priority 25 :when active) - (buffer-id :priority 90)) - '(;; (global) - (exwm :when active) - (perspective :when active) - (flycheck-error :when active) - (flycheck-warning :when active) - (debug-on-error :when active) - (debug-on-quit :when active) - (major-mode :when active :priority 90) - (selection-info :priority 95) - (line-column :when active :priority 99) - (hud :when active :priority 99))) - - (spaceline-ml-my) - - (setq-default mode-line-format '("%e" (:eval (spaceline-ml-my)))) - (setq mode-line-format '("%e" (:eval (spaceline-ml-my))))) - -(use-package ligature - :straight (:host github :repo "mickeynp/ligature.el") - :if (display-graphic-p) - :config - (ligature-set-ligatures - '( - typescript-mode - js2-mode - vue-mode - svelte-mode - scss-mode - php-mode - python-mode - js-mode - markdown-mode - clojure-mode - go-mode - sh-mode - haskell-mode - web-mode) - '("--" "---" "==" "===" "!=" "!==" "=!=" "=:=" "=/=" "<=" - ">=" "&&" "&&&" "&=" "++" "+++" "***" ";;" "!!" "??" - "?:" "?." "?=" "<:" ":<" ":>" ">:" "<>" "<<<" ">>>" - "<<" ">>" "||" "-|" "_|_" "|-" "||-" "|=" "||=" "##" - "###" "####" "#{" "#[" "]#" "#(" "#?" "#_" "#_(" "#:" - "#!" "#=" "^=" "<$>" "<$" "$>" "<+>" "<+" "+>" "<*>" - "<*" "*>" "" "/>" "" "->" "->>" - "<<-" "<-" "<=<" "=<<" "<<=" "<==" "<=>" "<==>" "==>" "=>" - "=>>" ">=>" ">>=" ">>-" ">-" ">--" "-<" "-<<" ">->" "<-<" - "<-|" "<=|" "|=>" "|->" "<->" "<~~" "<~" "<~>" "~~" "~~>" - "~>" "~-" "-~" "~@" "[||]" "|]" "[|" "|}" "{|" "[<" - ">]" "|>" "<|" "||>" "<||" "|||>" "<|||" "<|>" "..." ".." - ".=" ".-" "..<" ".?" "::" ":::" ":=" "::=" ":?" ":?>" - "//" "///" "/*" "*/" "/=" "//=" "/==" "@_" "__")) - (global-ligature-mode t)) - -(use-package all-the-icons - :if (display-graphic-p) - :straight t) - -(use-package hl-todo - :hook (prog-mode . hl-todo-mode) - :straight t) - -(use-package highlight-indent-guides - :straight t - :if (not (or my/lowpower my/remote-server)) + :if (not (or my/slow-ssh my/is-termux my/remote-server)) :hook ( - (prog-mode . highlight-indent-guides-mode) - (vue-mode . highlight-indent-guides-mode) - (LaTeX-mode . highlight-indent-guides-mode)) + (typescript-mode . lsp) + (js-mode . lsp) + (vue-mode . lsp) + (go-mode . lsp) + (svelte-mode . lsp) + ;; (python-mode . lsp) + (json-mode . lsp) + (haskell-mode . lsp) + (haskell-literate-mode . lsp) + (java-mode . lsp) + ;; (csharp-mode . lsp) + ) + :commands lsp + :init + (setq lsp-keymap-prefix nil) :config - (setq highlight-indent-guides-method 'bitmap) - (setq highlight-indent-guides-bitmap-function 'highlight-indent-guides--bitmap-line)) + (setq lsp-idle-delay 1) + (setq lsp-eslint-server-command '("node" "/home/pavel/.emacs.d/.cache/lsp/eslint/unzipped/extension/server/out/eslintServer.js" "--stdio")) + (setq lsp-eslint-run "onSave") + (setq lsp-signature-render-documentation nil) + ;; (lsp-headerline-breadcrumb-mode nil) + (setq lsp-headerline-breadcrumb-enable nil) + (add-to-list 'lsp-language-id-configuration '(svelte-mode . "svelte"))) -(use-package rainbow-delimiters +(use-package lsp-ui :straight t - :if (not my/lowpower) - :hook ((prog-mode . rainbow-delimiters-mode)) - ;; :commands (rainbow-delimiters-mode) - ;; :init - ;; (add-hook 'prog-mode-hook - ;; (lambda () - ;; (unless (org-in-src-block-p) - ;; (rainbow-delimiters-mode)))) - ) - -(use-package rainbow-mode - :commands (rainbow-mode) - :straight t) - -(use-package dired - :ensure nil - :custom ((dired-listing-switches "-alh --group-directories-first")) - :commands (dired) + :commands lsp-ui-mode :config - (setq dired-dwim-target t) - (setq wdired-allow-to-change-permissions t) - (setq wdired-create-parent-directories t) - (setq dired-recursive-copies 'always) - (setq dired-recursive-deletes 'always) - (setq dired-kill-when-opening-new-dired-buffer t) - (add-hook 'dired-mode-hook - (lambda () - (setq truncate-lines t) - (visual-line-mode nil))) - (general-define-key - :states '(normal) - :keymaps 'dired-mode-map - "h" 'dired-up-directory - "l" 'dired-find-file - "=" 'dired-narrow - "-" 'dired-create-empty-file - "~" 'vterm - "" 'dired-up-directory - "" 'dired-find-file - "M-" 'dired-open-xdg)) + (setq lsp-ui-doc-delay 2) + (setq lsp-ui-sideline-show-hover nil)) -(defun my/dired-home () - "Open dired at $HOME" - (interactive) - (dired (expand-file-name "~"))) +;; (use-package helm-lsp +;; :straight t +;; :commands helm-lsp-workspace-symbol) + +;; (use-package origami +;; :straight t +;; :hook (prog-mode . origami-mode)) + +;; (use-package lsp-origami +;; :straight t +;; :config +;; (add-hook 'lsp-after-open-hook #'lsp-origami-try-enable)) + +(use-package lsp-treemacs + :after (lsp) + :straight t + :commands lsp-treemacs-errors-list) (my-leader-def - "ad" #'dired - "aD" #'my/dired-home) + :infix "l" + "" '(:which-key "lsp") + "d" 'lsp-ui-peek-find-definitions + "r" 'lsp-rename + "u" 'lsp-ui-peek-find-references + "s" 'lsp-ui-find-workspace-symbol + "l" 'lsp-execute-code-action + "e" 'list-flycheck-errors) -(use-package diredfl +(use-package flycheck :straight t - :after dired :config - (diredfl-global-mode 1)) + (global-flycheck-mode) + (setq flycheck-check-syntax-automatically '(save idle-buffer-switch mode-enabled)) + ;; (add-hook 'evil-insert-state-exit-hook + ;; (lambda () + ;; (if flycheck-checker + ;; (flycheck-buffer)) + ;; )) + (advice-add 'flycheck-eslint-config-exists-p :override (lambda() t)) + (add-to-list 'display-buffer-alist + `(,(rx bos "*Flycheck errors*" eos) + (display-buffer-reuse-window + display-buffer-in-side-window) + (side . bottom) + (reusable-frames . visible) + (window-height . 0.33)))) -(use-package dired-single - :after dired - :disabled +(defun my/tree-sitter-if-not-mmm () + (when (not (and (boundp 'mmm-temp-buffer-name) + (string-equal mmm-temp-buffer-name (buffer-name)))) + (tree-sitter-mode) + (tree-sitter-hl-mode))) + +(use-package tree-sitter + :straight t + :if (not my/remote-server) + :hook ((typescript-mode . my/tree-sitter-if-not-mmm) + (js-mode . my/tree-sitter-if-not-mmm) + (python-mode . tree-sitter-mode) + (python-mode . tree-sitter-hl-mode) + (csharp-mode . tree-sitter-mode))) + +(use-package tree-sitter-langs + :straight t + :after tree-sitter) + +(use-package dap-mode + :straight t + :commands (dap-debug) + :init + (setq lsp-enable-dap-auto-configure nil) + :config + + (setq dap-ui-variable-length 100) + (setq dap-auto-show-output nil) + (require 'dap-node) + (dap-node-setup) + + (require 'dap-chrome) + (dap-chrome-setup) + + (require 'dap-python) + + (dap-mode 1) + (dap-ui-mode 1) + (dap-tooltip-mode 1) + (tooltip-mode 1)) + +(with-eval-after-load 'dap-mode + (defmacro my/define-dap-ui-window-toggler (name) + `(defun ,(intern (concat "my/dap-ui-toggle-" name)) () + ,(concat "Toggle DAP " name "buffer") + (interactive) + (if-let (window (get-buffer-window ,(intern (concat "dap-ui--" name "-buffer")))) + (quit-window nil window) + (,(intern (concat "dap-ui-" name)))))) + + (my/define-dap-ui-window-toggler "locals") + (my/define-dap-ui-window-toggler "expressions") + (my/define-dap-ui-window-toggler "sessions") + (my/define-dap-ui-window-toggler "breakpoints") + (my/define-dap-ui-window-toggler "repl")) + +(defhydra my/dap-hydra (:color pink :hint nil :foreign-keys run) + " +^Stepping^ ^UI^ ^Switch^ ^Breakpoints^ ^Debug^ ^Expressions +^^^^^^^^------------------------------------------------------------------------------------------------------------------------------------------ +_n_: Next _uc_: Controls _ss_: Session _bb_: Toggle _dd_: Debug _ee_: Eval +_i_: Step in _ue_: Expressions _st_: Thread _bd_: Delete _dr_: Debug recent _er_: Eval region +_o_: Step out _ul_: Locals _sf_: Stack frame _ba_: Add _dl_: Debug last _es_: Eval thing at point +_c_: Continue _ur_: REPL _su_: Up stack frame _bc_: Set condition _de_: Edit debug template _ea_: Add expression +_r_: Restart frame _uo_: Output _sd_: Down stack frame _bh_: Set hit count _Q_: Disconnect _ed_: Remove expression + _us_: Sessions _sF_: Stack frame filtered _bl_: Set log message _eu_: Refresh expressions + _ub_: Breakpoints " + + ("n" dap-next) + ("i" dap-step-in) + ("o" dap-step-out) + ("c" dap-continue) + ("r" dap-restart-frame) + ("uc" dap-ui-controls-mode) + ("ue" my/dap-ui-toggle-expressions) + ("ul" my/dap-ui-toggle-locals) + ("ur" my/dap-ui-toggle-repl) + ("uo" dap-ui-go-to-output-buffer) + ("us" my/dap-ui-toggle-sessions) + ("ub" my/dap-ui-toggle-breakpoints) + ("ss" dap-switch-session) + ("st" dap-switch-thread) + ("sf" dap-switch-stack-frame) + ("sF" my/dap-switch-stack-frame) + ("su" dap-up-stack-frame) + ("sd" dap-down-stack-frame) + ("bb" dap-breakpoint-toggle) + ("ba" dap-breakpoint-add) + ("bd" dap-breakpoint-delete) + ("bc" dap-breakpoint-condition) + ("bh" dap-breakpoint-hit-condition) + ("bl" dap-breakpoint-log-message) + ("dd" dap-debug) + ("dr" dap-debug-recent) + ("dl" dap-debug-last) + ("de" dap-debug-edit-template) + ("ee" dap-eval) + ("ea" dap-ui-expressions-add) + ("er" dap-eval-region) + ("es" dap-eval-thing-at-point) + ("ed" dap-ui-expressions-remove) + ("eu" dap-ui-expressions-refresh) + ("q" nil "quit" :color blue) + ("Q" dap-disconnect :color red)) + +(my-leader-def "d" #'my/dap-hydra/body) + +(defvar my/dap-mode-buffer-fixed nil) + +(with-eval-after-load 'dap-mode + (defmacro my/define-dap-tree-buffer-fixer (buffer-var buffer-name) + `(defun ,(intern (concat "my/fix-dap-ui-" buffer-name "-buffer")) (&rest _) + (with-current-buffer ,buffer-var + (unless my/dap-mode-buffer-fixed + (toggle-truncate-lines 1) + (doom-modeline-set-modeline 'info) + (setq-local my/dap-mode-buffer-fixed t))))) + + (my/define-dap-tree-buffer-fixer dap-ui--locals-buffer "locals") + (my/define-dap-tree-buffer-fixer dap-ui--expressions-buffer "expressions") + (my/define-dap-tree-buffer-fixer dap-ui--sessions-buffer "sessions") + (my/define-dap-tree-buffer-fixer dap-ui--breakpoints-buffer "breakpoints") + + (advice-add 'dap-ui-locals :after #'my/fix-dap-ui-locals-buffer) + (advice-add 'dap-ui-expressions :after #'my/fix-dap-ui-expressions-buffer) + (advice-add 'dap-ui-sessions :after #'my/fix-dap-ui-sessions-buffer) + (advice-add 'dap-ui-breakpoints :after #'my/fix-dap-ui-breakpoints-buffer)) + +(defun my/clear-bad-window-parameters () + "Clear window parameters that interrupt my workflow." + (interactive) + (let ((window (get-buffer-window (current-buffer)))) + (set-window-parameter window 'no-delete-other-windows nil))) + +(defun my/dap-yank-value-at-point (node) + (interactive (list (treemacs-node-at-point))) + (kill-new (message (plist-get (button-get node :item) :value)))) + +(defun my/dap-display-value (node) + (interactive (list (treemacs-node-at-point))) + (let ((value (plist-get (button-get node :item) :value))) + (when value + (let ((buffer (generate-new-buffer "dap-value"))) + (with-current-buffer buffer + (insert value)) + (select-window (display-buffer buffer)))))) + +(with-eval-after-load 'dap-mode + (setq my/dap-stack-frame-filters + `(("node_modules,node:internal" . ,(rx (or "node_modules" "node:internal"))) + ("node_modules" . ,(rx (or "node_modules"))) + ("node:internal" . ,(rx (or "node:internal"))))) + + (setq my/dap-stack-frame-current-filter (cdar my/dap-stack-frame-filters)) + + (defun my/dap-stack-frame-filter-set () + (interactive) + (setq my/dap-stack-frame-current-filter + (cdr + (assoc + (completing-read "Filter: " my/dap-stack-frame-filters) + my/dap-stack-frame-filters)))) + + (defun my/dap-stack-frame-filter (frame) + (when-let (path (dap--get-path-for-frame frame)) + (not (string-match my/dap-stack-frame-current-filter path))))) + +(defun my/dap-switch-stack-frame () + "Switch stackframe by selecting another stackframe stackframes from current thread." + (interactive) + (when (not (dap--cur-session)) + (error "There is no active session")) + + (-if-let (thread-id (dap--debug-session-thread-id (dap--cur-session))) + (-if-let (stack-frames + (gethash + thread-id + (dap--debug-session-thread-stack-frames (dap--cur-session)))) + (let* ((index 0) + (stack-framces-filtered + (-filter + #'my/dap-stack-frame-filter + stack-frames)) + (new-stack-frame + (dap--completing-read + "Select active frame: " + stack-framces-filtered + (-lambda ((frame &as &hash "name")) + (if-let (frame-path (dap--get-path-for-frame frame)) + (format "%s: %s (in %s)" + (cl-incf index) name frame-path) + (format "%s: %s" (cl-incf index) name))) + nil + t))) + (dap--go-to-stack-frame (dap--cur-session) new-stack-frame)) + (->> (dap--cur-session) + dap--debug-session-name + (format "Current session %s is not stopped") + error)) + (error "No thread is currently active %s" (dap--debug-session-name (dap--cur-session))))) + +(with-eval-after-load 'dap-mode + (dap-register-debug-template + "Node::Nest.js" + (list :type "node" + :request "attach" + :name "Node::Attach" + :port 9229 + :outFiles ["${workspaceFolder}/dist/**/*.js"] + :sourceMaps t + :program "${workspaceFolder}/src/app.ts")) + (dap-register-debug-template + "Node::Babel" + (list :type "node" + :request "attach" + :name "Node::Attach" + :port 9229 + :program "${workspaceFolder}/dist/bin/www.js"))) + +(use-package reformatter :straight t) -(use-package all-the-icons-dired +(defun my/set-smartparens-indent (mode) + (sp-local-pair mode "{" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET"))) + (sp-local-pair mode "[" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET"))) + (sp-local-pair mode "(" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET")))) + +(defun my/set-flycheck-eslint() + "Override flycheck checker with eslint." + (setq-local lsp-diagnostic-package :none) + (setq-local flycheck-checker 'javascript-eslint)) + +(use-package emmet-mode :straight t - :if (not (or my/lowpower my/slow-ssh (not (display-graphic-p)))) - :hook (dired-mode . (lambda () - (unless (string-match-p "/gnu/store" default-directory) - (all-the-icons-dired-mode)))) + :hook ((vue-html-mode . emmet-mode) + (svelte-mode . emmet-mode) + (web-mode . emmet-mode) + (html-mode . emmet-mode) + (css-mode . emmet-mode) + (scss-mode . emmet-mode)) :config - (advice-add 'dired-add-entry :around #'all-the-icons-dired--refresh-advice) - (advice-add 'dired-remove-entry :around #'all-the-icons-dired--refresh-advice) - (advice-add 'dired-kill-subdir :around #'all-the-icons-dired--refresh-advice)) + ;; (setq emmet-indent-after-insert nil) + (setq my/emmet-mmm-submodes '(vue-html-mode css-mode)) + (defun my/emmet-or-tab (&optional arg) + (interactive) + (if (and + (boundp 'mmm-current-submode) + mmm-current-submode + (not (member mmm-current-submode my/emmet-mmm-submodes))) + (indent-for-tab-command arg) + (or (emmet-expand-line arg) + (emmet-go-to-edit-point 1) + (indent-for-tab-command arg)))) + (general-imap :keymaps 'emmet-mode-keymap + "TAB" 'my/emmet-or-tab + "" 'emmet-prev-edit-point)) -(use-package dired-open +(use-package prettier + :commands (prettier-prettify) :straight t - :commands (dired-open-xdg)) + :init + (my-leader-def + :keymaps '(js-mode-map web-mode-map typescript-mode-map vue-mode-map svelte-mode-map) + "rr" #'prettier-prettify)) -(use-package dired-narrow +(use-package typescript-mode :straight t - :commands (dired-narrow) + :mode "\\.ts\\'" :config - (general-define-key - :keymaps 'dired-narrow-map - [escape] 'keyboard-quit)) + (add-hook 'typescript-mode-hook #'smartparens-mode) + (add-hook 'typescript-mode-hook #'rainbow-delimiters-mode) + (add-hook 'typescript-mode-hook #'hs-minor-mode) + (my/set-smartparens-indent 'typescript-mode)) -(use-package dired-git-info +(add-hook 'js-mode-hook #'smartparens-mode) +(add-hook 'js-mode-hook #'hs-minor-mode) +(my/set-smartparens-indent 'js-mode) + +(use-package jest-test-mode :straight t - :after dired - :if (not my/slow-ssh) + :hook ((typescript-mode . jest-test-mode) + (js-mode . jest-test-mode)) :config - (general-define-key - :keymap 'dired-mode-map - :states '(normal emacs) - ")" 'dired-git-info-mode)) + (my-leader-def + :keymaps 'jest-test-mode-map + :infix "t" + "t" 'jest-test-run-at-point + "r" 'jest-test-run + "a" 'jest-test-run-all-tests)) -(defun my/dired-open-this-subdir () +(defun my/jest-test-run-at-point-copy () + "Run the top level describe block of the current buffer's point." (interactive) - (dired (dired-current-directory))) + (let ((filename (jest-test-find-file)) + (example (jest-test-example-at-point))) + (if (and filename example) + (jest-test-from-project-directory filename + (let ((jest-test-options (seq-concatenate 'list jest-test-options (list "-t" example)))) + (kill-new (jest-test-command filename)))) + (message jest-test-not-found-message)))) -(defun my/dired-kill-all-subdirs () - (interactive) - (let ((dir dired-directory)) - (kill-buffer (current-buffer)) - (dired dir))) - -(with-eval-after-load 'dired - (general-define-key - :states '(normal) - :keymaps 'dired-mode-map - "s" nil - "ss" 'dired-maybe-insert-subdir - "sl" 'dired-maybe-insert-subdir - "sq" 'dired-kill-subdir - "sk" 'dired-prev-subdir - "sj" 'dired-next-subdir - "sS" 'my/dired-open-this-subdir - "sQ" 'my/dired-kill-all-subdirs - (kbd "TAB") 'dired-hide-subdir)) - -(setq tramp-verbose 1) - -(setq remote-file-name-inhibit-cache nil) -(setq vc-ignore-dir-regexp - (format "\\(%s\\)\\|\\(%s\\)" - vc-ignore-dir-regexp - tramp-file-name-regexp)) - -(when (or my/remote-server my/slow-ssh) - (setq explicit-shell-file-name "/bin/bash")) - -(with-eval-after-load 'tramp - (setq tramp-remote-path - (append tramp-remote-path - '(tramp-own-remote-path)))) - -(defun my/dired-bookmark-open () - (interactive) - (let ((bookmarks - (mapcar - (lambda (el) (cons (format "%-30s %s" (car el) (cdr el)) (cdr el))) - my/dired-bookmarks))) - (dired - (cdr - (assoc - (completing-read "Dired: " bookmarks nil nil "^") - bookmarks))))) - -(use-package vterm - ;; :straight t - :commands (vterm vterm-other-window) +(use-package web-mode + :straight t + :commands (web-mode) + :init + (add-to-list 'auto-mode-alist '("\\.svelte\\'" . web-mode)) + (add-to-list 'auto-mode-alist '("\\.vue\\'" . web-mode)) :config - (setq vterm-kill-buffer-on-exit t) + (add-hook 'web-mode-hook 'smartparens-mode) + (add-hook 'web-mode-hook 'hs-minor-mode) + (my/set-smartparens-indent 'web-mode)) - (add-hook 'vterm-mode-hook +(setq my/web-mode-lsp-extensions + `(,(rx ".svelte" eos) + ,(rx ".vue" eos))) + +(defun my/web-mode-lsp () + (when (seq-some + (lambda (regex) (string-match-p regex (buffer-name))) + my/web-mode-lsp-extensions) + (lsp-deferred))) + +(add-hook 'web-mode-hook #'my/web-mode-lsp) + +(defun my/web-mode-vue-setup () + (when (string-match-p (rx ".vue" eos) (buffer-name)) + (setq-local web-mode-script-padding 0))) + +(add-hook 'web-mode-hook 'my/web-mode-vue-setup) + +(use-package vue-mode + :straight t + :disabled + :mode "\\.vue\\'" + :config + (add-hook 'vue-mode-hook #'hs-minor-mode) + (add-hook 'vue-mode-hook #'smartparens-mode) + (my/set-smartparens-indent 'vue-mode) + (add-hook 'vue-mode-hook (lambda () (set-face-background 'mmm-default-submode-face nil))) + (defun mmm-syntax-propertize-function (start stop) + (let ((saved-mode mmm-current-submode) + (saved-ovl mmm-current-overlay)) + (mmm-save-changed-local-variables + mmm-current-submode mmm-current-overlay) + (unwind-protect + (mapc (lambda (elt) + (let* ((mode (car elt)) + (func (get mode 'mmm-syntax-propertize-function)) + (beg (cadr elt)) (end (nth 2 elt)) + (ovl (nth 3 elt)) + syntax-ppss-cache + syntax-ppss-last) + (goto-char beg) + (mmm-set-current-pair mode ovl) + (mmm-set-local-variables mode mmm-current-overlay) + (save-restriction + (if mmm-current-overlay + (narrow-to-region (overlay-start mmm-current-overlay) + (overlay-end mmm-current-overlay)) + (narrow-to-region beg end)) + (cond + (func + (funcall func beg end)) + (font-lock-syntactic-keywords + (let ((syntax-propertize-function nil)) + (font-lock-fontify-syntactic-keywords-region beg end)))) + (run-hook-with-args 'mmm-after-syntax-propertize-functions + mmm-current-overlay mode beg end)))) + (mmm-regions-in start stop)) + (mmm-set-current-pair saved-mode saved-ovl) + (mmm-set-local-variables (or saved-mode mmm-primary-mode) saved-ovl))))) + +(with-eval-after-load 'editorconfig + (add-to-list 'editorconfig-indentation-alist + '(vue-mode css-indent-offset + js-indent-level + sgml-basic-offset + ssass-tab-width + typescript-indent-level + emmet-indentation + vue-html-extra-indent))) + +(use-package svelte-mode + :straight t + :mode "\\.svelte\\'" + :disabled + :config + (add-hook 'svelte-mode-hook 'my/set-flycheck-eslint) + (add-hook 'svelte-mode-hook #'smartparens-mode) + (my/set-smartparens-indent 'svelte-mode) + ;; I have my own Emmet + (setq lsp-svelte-plugin-css-completions-emmet nil) + (setq lsp-svelte-plugin-html-completions-emmet nil)) + +(add-hook 'scss-mode-hook #'smartparens-mode) +(add-hook 'scss-mode-hook #'hs-minor-mode) +(my/set-smartparens-indent 'scss-mode) + +(use-package php-mode + :straight t + :mode "\\.php\\'") + +(use-package tex + :straight auctex + :defer t + :config + (setq-default TeX-auto-save t) + (setq-default TeX-parse-self t) + (TeX-PDF-mode) + ;; Use XeLaTeX & stuff + (setq-default TeX-engine 'xetex) + (setq-default TeX-command-extra-options "-shell-escape") + (setq-default TeX-source-correlate-method 'synctex) + (TeX-source-correlate-mode) + (setq-default TeX-source-correlate-start-server t) + (setq-default LaTeX-math-menu-unicode t) + + (setq-default font-latex-fontify-sectioning 1.3) + + ;; Scale preview for my DPI + (setq-default preview-scale-function 1.4) + (when (boundp 'tex--prettify-symbols-alist) + (assoc-delete-all "--" tex--prettify-symbols-alist) + (assoc-delete-all "---" tex--prettify-symbols-alist)) + + (add-hook 'LaTeX-mode-hook (lambda () - (setq-local global-display-line-numbers-mode nil) - (display-line-numbers-mode 0))) + (TeX-fold-mode 1) + (outline-minor-mode))) + (add-to-list 'TeX-view-program-selection + '(output-pdf "Zathura")) - (advice-add 'evil-collection-vterm-insert - :before (lambda (&rest args) - (ignore-errors - (apply #'vterm-reset-cursor-point args)))) + ;; Do not run lsp within templated TeX files + (add-hook 'LaTeX-mode-hook + (lambda () + (unless (string-match "\.hogan\.tex$" (buffer-name)) + (lsp)) + (setq-local lsp-diagnostic-package :none) + (setq-local flycheck-checker 'tex-chktex))) - (general-define-key - :keymaps 'vterm-mode-map - "M-q" 'vterm-send-escape + (add-hook 'LaTeX-mode-hook #'rainbow-delimiters-mode) + (add-hook 'LaTeX-mode-hook #'smartparens-mode) + (add-hook 'LaTeX-mode-hook #'prettify-symbols-mode) - "C-h" 'evil-window-left - "C-l" 'evil-window-right - "C-k" 'evil-window-up - "C-j" 'evil-window-down + (my/set-smartparens-indent 'LaTeX-mode) + (require 'smartparens-latex) - "C-" 'evil-window-right - "C-" 'evil-window-left - "C-" 'evil-window-up - "C-" 'evil-window-down + (general-nmap + :keymaps '(LaTeX-mode-map latex-mode-map) + "RET" 'TeX-command-run-all + "C-c t" 'orgtbl-mode) - "M-" 'vterm-send-left - "M-" 'vterm-send-right - "M-" 'vterm-send-up - "M-" 'vterm-send-down) + (setq my/greek-alphabet + '(("a" . "\\alpha") + ("b" . "\\beta" ) + ("g" . "\\gamma") + ("d" . "\\delta") + ("e" . "\\epsilon") + ("z" . "\\zeta") + ("h" . "\\eta") + ("o" . "\\theta") + ("i" . "\\iota") + ("k" . "\\kappa") + ("l" . "\\lambda") + ("m" . "\\mu") + ("n" . "\\nu") + ("x" . "\\xi") + ("p" . "\\pi") + ("r" . "\\rho") + ("s" . "\\sigma") + ("t" . "\\tau") + ("u" . "\\upsilon") + ("f" . "\\phi") + ("c" . "\\chi") + ("v" . "\\psi") + ("g" . "\\omega"))) + + (setq my/latex-greek-prefix "'") + + ;; The same for capitalized letters + (dolist (elem my/greek-alphabet) + (let ((key (car elem)) + (value (cdr elem))) + (when (string-equal key (downcase key)) + (add-to-list 'my/greek-alphabet + (cons + (capitalize (car elem)) + (concat + (substring value 0 1) + (capitalize (substring value 1 2)) + (substring value 2))))))) + + (yas-define-snippets + 'latex-mode + (mapcar + (lambda (elem) + (list (concat my/latex-greek-prefix (car elem)) (cdr elem) (concat "Greek letter " (car elem)))) + my/greek-alphabet)) + (setq my/english-alphabet + '("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z")) + + (dolist (elem my/english-alphabet) + (when (string-equal elem (downcase elem)) + (add-to-list 'my/english-alphabet (upcase elem)))) + + (setq my/latex-mathbb-prefix "`") + + (yas-define-snippets + 'latex-mode + (mapcar + (lambda (elem) + (list (concat my/latex-mathbb-prefix elem) (concat "\\mathbb{" elem "}") (concat "Mathbb letter " elem))) + my/english-alphabet)) + (setq my/latex-math-symbols + '(("x" . "\\times") + ("." . "\\cdot") + ("v" . "\\forall") + ("s" . "\\sum_{$1}^{$2}$0") + ("p" . "\\prod_{$1}^{$2}$0") + ("d" . "\\partial") + ("e" . "\\exists") + ("i" . "\\int_{$1}^{$2}$0") + ("c" . "\\cap") + ("u" . "\\cup") + ("0" . "\\emptyset") + ("^" . "\\widehat{$1}$0") + ("_" . "\\overline{$1}$0") + ("~" . "\\sim") + ("|" . "\\mid") + ("_|" . "\\perp"))) + + (setq my/latex-math-prefix ";") + + (yas-define-snippets + 'latex-mode + (mapcar + (lambda (elem) + (let ((key (car elem)) + (value (cdr elem))) + (list (concat my/latex-math-prefix key) value (concat "Math symbol " value)))) + my/latex-math-symbols)) + (setq my/latex-section-snippets + '(("ch" . "\\chapter{$1}") + ("sec" . "\\section{$1}") + ("ssec" . "\\subsection{$1}") + ("sssec" . "\\subsubsection{$1}") + ("par" . "\\paragraph{$1}}"))) + + (setq my/latex-section-snippets + (mapcar + (lambda (elem) + `(,(car elem) + ,(cdr elem) + ,(progn + (string-match "[a-z]+" (cdr elem)) + (match-string 0 (cdr elem))))) + my/latex-section-snippets)) + + (dolist (elem my/latex-section-snippets) + (let* ((key (nth 0 elem)) + (value (nth 1 elem)) + (desc (nth 2 elem)) + (star-index (string-match "\{\$1\}" value))) + (add-to-list 'my/latex-section-snippets + `(,(concat key "*") + ,(concat + (substring value 0 star-index) + "*" + (substring value star-index)) + ,(concat desc " with *"))) + (add-to-list 'my/latex-section-snippets + `(,(concat key "l") + ,(concat value "%\n\\label{sec:$2}") + ,(concat desc " with label"))))) + + (dolist (elem my/latex-section-snippets) + (setf (nth 1 elem) (concat (nth 1 elem) "\n$0"))) + + (yas-define-snippets + 'latex-mode + my/latex-section-snippets)) - (general-define-key - :keymaps 'vterm-mode-map - :states '(normal insert) - "" 'vterm-beginning-of-line - "" 'vterm-end-of-line) - - (general-define-key - :keymaps 'vterm-mode-map - :states '(insert) - "C-r" 'vterm-send-C-r - "C-k" 'vterm-send-C-k - "C-j" 'vterm-send-C-j - "M-l" 'vterm-send-right - "M-h" 'vterm-send-left - "M-k" 'vterm-send-up - "M-j" 'vterm-send-down)) - -(add-to-list 'display-buffer-alist - `(,"vterm-subterminal.*" - (display-buffer-reuse-window - display-buffer-in-side-window) - (side . bottom) - (reusable-frames . visible) - (window-height . 0.33))) - -(defun my/toggle-vterm-subteminal () - "Toogle subteminal." - (interactive) - (let - ((vterm-window - (seq-find - (lambda (window) - (string-match - "vterm-subterminal.*" - (buffer-name (window-buffer window)))) - (window-list)))) - (if vterm-window - (if (eq (get-buffer-window (current-buffer)) vterm-window) - (kill-buffer (current-buffer)) - (select-window vterm-window)) - (vterm-other-window "vterm-subterminal")))) - -(unless my/slow-ssh - (general-nmap "`" 'my/toggle-vterm-subteminal) - (general-nmap "~" 'vterm)) - -(defun my/vterm-get-pwd () - (if vterm--process - (file-truename (format "/proc/%d/cwd" (process-id vterm--process))) - default-directory)) - -(defun my/vterm-dired-other-window () - "Open dired in vterm pwd in other window" - (interactive) - (dired-other-window (my/vterm-get-pwd))) - -(defun my/vterm-dired-replace () - "Replace vterm with dired" - (interactive) - (let ((pwd (my/vterm-get-pwd))) - (kill-process vterm--process) - (dired pwd))) - -(with-eval-after-load 'vterm - (general-define-key - :keymaps 'vterm-mode-map - :states '(normal) - "gd" #'my/vterm-dired-other-window - "gD" #'my/vterm-dired-replace)) - -(use-package with-editor +(use-package ivy-bibtex + :commands (ivy-bibtex) :straight t - :after (vterm) + :init + (my-leader-def "fB" 'ivy-bibtex)) + +(add-hook 'bibtex-mode 'smartparens-mode) + +(defun my/list-sty () + (reverse + (sort + (seq-filter + (lambda (file) (if (string-match ".*\.sty$" file) 1 nil)) + (directory-files + (seq-some + (lambda (dir) + (if (and + (f-directory-p dir) + (seq-some + (lambda (file) (string-match ".*\.sty$" file)) + (directory-files dir)) + ) dir nil)) + (list "./styles" "../styles/" "." "..")) :full)) + (lambda (f1 f2) + (let ((f1b (file-name-base f1)) + (f1b (file-name-base f2))) + (cond + ((string-match-p ".*BibTex" f1) t) + ((and (string-match-p ".*Locale" f1) (not (string-match-p ".*BibTex" f2))) t) + ((string-match-p ".*Preamble" f2) t) + (t (string-lessp f1 f2)))))))) + +(defun my/import-sty () + (interactive) + (insert + (apply #'concat + (cl-mapcar + (lambda (file) (concat "\\usepackage{" (file-name-sans-extension (file-relative-name file default-directory)) "}\n")) + (my/list-sty))))) + +(defun my/import-sty-org () + (interactive) + (insert + (apply #'concat + (cl-mapcar + (lambda (file) (concat "#+LATEX_HEADER: \\usepackage{" (file-name-sans-extension (file-relative-name file default-directory)) "}\n")) + (my/list-sty))))) + +(setq my/greek-alphabet + '(("a" . "\\alpha") + ("b" . "\\beta" ) + ("g" . "\\gamma") + ("d" . "\\delta") + ("e" . "\\epsilon") + ("z" . "\\zeta") + ("h" . "\\eta") + ("o" . "\\theta") + ("i" . "\\iota") + ("k" . "\\kappa") + ("l" . "\\lambda") + ("m" . "\\mu") + ("n" . "\\nu") + ("x" . "\\xi") + ("p" . "\\pi") + ("r" . "\\rho") + ("s" . "\\sigma") + ("t" . "\\tau") + ("u" . "\\upsilon") + ("f" . "\\phi") + ("c" . "\\chi") + ("v" . "\\psi") + ("g" . "\\omega"))) + +(setq my/latex-greek-prefix "'") + +;; The same for capitalized letters +(dolist (elem my/greek-alphabet) + (let ((key (car elem)) + (value (cdr elem))) + (when (string-equal key (downcase key)) + (add-to-list 'my/greek-alphabet + (cons + (capitalize (car elem)) + (concat + (substring value 0 1) + (capitalize (substring value 1 2)) + (substring value 2))))))) + +(yas-define-snippets + 'latex-mode + (mapcar + (lambda (elem) + (list (concat my/latex-greek-prefix (car elem)) (cdr elem) (concat "Greek letter " (car elem)))) + my/greek-alphabet)) + +(setq my/english-alphabet + '("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z")) + +(dolist (elem my/english-alphabet) + (when (string-equal elem (downcase elem)) + (add-to-list 'my/english-alphabet (upcase elem)))) + +(setq my/latex-mathbb-prefix "`") + +(yas-define-snippets + 'latex-mode + (mapcar + (lambda (elem) + (list (concat my/latex-mathbb-prefix elem) (concat "\\mathbb{" elem "}") (concat "Mathbb letter " elem))) + my/english-alphabet)) + +(setq my/latex-math-symbols + '(("x" . "\\times") + ("." . "\\cdot") + ("v" . "\\forall") + ("s" . "\\sum_{$1}^{$2}$0") + ("p" . "\\prod_{$1}^{$2}$0") + ("d" . "\\partial") + ("e" . "\\exists") + ("i" . "\\int_{$1}^{$2}$0") + ("c" . "\\cap") + ("u" . "\\cup") + ("0" . "\\emptyset") + ("^" . "\\widehat{$1}$0") + ("_" . "\\overline{$1}$0") + ("~" . "\\sim") + ("|" . "\\mid") + ("_|" . "\\perp"))) + +(setq my/latex-math-prefix ";") + +(yas-define-snippets + 'latex-mode + (mapcar + (lambda (elem) + (let ((key (car elem)) + (value (cdr elem))) + (list (concat my/latex-math-prefix key) value (concat "Math symbol " value)))) + my/latex-math-symbols)) + +(setq my/latex-section-snippets + '(("ch" . "\\chapter{$1}") + ("sec" . "\\section{$1}") + ("ssec" . "\\subsection{$1}") + ("sssec" . "\\subsubsection{$1}") + ("par" . "\\paragraph{$1}}"))) + +(setq my/latex-section-snippets + (mapcar + (lambda (elem) + `(,(car elem) + ,(cdr elem) + ,(progn + (string-match "[a-z]+" (cdr elem)) + (match-string 0 (cdr elem))))) + my/latex-section-snippets)) + +(dolist (elem my/latex-section-snippets) + (let* ((key (nth 0 elem)) + (value (nth 1 elem)) + (desc (nth 2 elem)) + (star-index (string-match "\{\$1\}" value))) + (add-to-list 'my/latex-section-snippets + `(,(concat key "*") + ,(concat + (substring value 0 star-index) + "*" + (substring value star-index)) + ,(concat desc " with *"))) + (add-to-list 'my/latex-section-snippets + `(,(concat key "l") + ,(concat value "%\n\\label{sec:$2}") + ,(concat desc " with label"))))) + +(dolist (elem my/latex-section-snippets) + (setf (nth 1 elem) (concat (nth 1 elem) "\n$0"))) + +(yas-define-snippets + 'latex-mode + my/latex-section-snippets) + +(use-package markdown-mode + :straight t + :mode "\\.md\\'" :config - (add-hook 'vterm-mode-hook 'with-editor-export-editor)) - -(defun my/configure-eshell () - (add-hook 'eshell-pre-command-hook 'eshell-save-some-history) - (add-to-list 'eshell-output-filter-functions 'eshell-truncate-buffer) - (setq eshell-history-size 10000) - (setq eshell-hist-ingnoredups t) - (setq eshell-buffer-maximum-lines 10000) - - (evil-define-key '(normal insert visual) eshell-mode-map (kbd "") 'eshell-bol) - (evil-define-key '(normal insert visual) eshell-mode-map (kbd "C-r") 'counsel-esh-history) + (setq markdown-command + (concat + "pandoc" + " --from=markdown --to=html" + " --standalone --mathjax --highlight-style=pygments" + " --css=pandoc.css" + " --quiet" + )) + (setq markdown-live-preview-delete-export 'delete-on-export) + (setq markdown-asymmetric-header t) + (setq markdown-open-command "/home/pavel/bin/scripts/chromium-sep") + (add-hook 'markdown-mode-hook #'smartparens-mode) (general-define-key - :states '(normal) - :keymaps 'eshell-mode-map - (kbd "C-h") 'evil-window-left - (kbd "C-l") 'evil-window-right - (kbd "C-k") 'evil-window-up - (kbd "C-j") 'evil-window-down)) + :keymaps 'markdown-mode-map + "M-" 'markdown-promote + "M-" 'markdown-demote)) -(use-package eshell - :ensure nil - :after evil-collection - :commands (eshell) +;; (use-package livedown +;; :straight (:host github :repo "shime/emacs-livedown") +;; :commands livedown-preview +;; :config +;; (setq livedown-browser "qutebrowser")) + +(use-package plantuml-mode + :straight t + :mode "(\\.\\(plantuml?\\|uml\\|puml\\)\\'" :config - (add-hook 'eshell-first-time-mode-hook 'my/configure-eshell 90) - (when my/slow-ssh - (add-hook 'eshell-mode-hook - (lambda () - (setq-local company-idle-delay 1000)))) - (setq eshell-banner-message "")) + (setq plantuml-executable-path "/home/pavel/.guix-extra-profiles/emacs/emacs/bin/plantuml") + (setq plantuml-default-exec-mode 'executable) + (setq plantuml-indent-level 2) + (setq my/plantuml-indent-regexp-return "^\s*return\s+.+$") + (add-to-list + 'plantuml-indent-regexp-end + my/plantuml-indent-regexp-return) + (add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode)) + (add-to-list 'auto-mode-alist '("\\.uml\\'" . plantuml-mode)) + (add-hook 'plantuml-mode-hook #'smartparens-mode)) -(use-package aweshell - :straight (:repo "manateelazycat/aweshell" :host github) - :after eshell +(general-nmap + :keymaps 'plantuml-mode-map + "RET" 'plantuml-preview) + +(use-package langtool + :straight t + :commands (langtool-check) :config - (setq eshell-highlight-prompt nil) - (setq eshell-prompt-function 'epe-theme-pipeline)) + (setq langtool-language-tool-server-jar "/home/pavel/bin/LanguageTool-5.4/languagetool-server.jar") + (setq langtool-mother-tongue "ru") + (setq langtool-default-language "en-US")) -(use-package eshell-info-banner +(my-leader-def + :infix "L" + "" '(:which-key "languagetool") + "c" 'langtool-check + "s" 'langtool-server-stop + "d" 'langtool-check-done + "n" 'langtool-goto-next-error + "p" 'langtool-goto-previous-error + "l" 'langtool-correct-buffer) + +(use-package lispy + :commands (lispy-mode) + :straight t) + +(use-package lispyville + :hook (lispy-mode . lispyville-mode) + :straight t) + +(sp-with-modes sp-lisp-modes + (sp-local-pair "'" nil :actions nil)) + +(use-package flycheck-package + :straight t + :after flycheck + :config + (flycheck-package-setup)) + +(add-hook 'emacs-lisp-mode-hook #'aggressive-indent-mode) +;; (add-hook 'emacs-lisp-mode-hook #'smartparens-strict-mode) +(add-hook 'emacs-lisp-mode-hook #'lispy-mode) + +(use-package slime + :straight t + :commands (slime) + :config + (setq inferior-lisp-program "sbcl") + (add-hook 'slime-repl-mode 'smartparens-mode)) + +(add-hook 'lisp-mode-hook #'aggressive-indent-mode) +;; (add-hook 'emacs-lisp-mode-hook #'smartparens-strict-mode) +(add-hook 'lisp-mode-hook #'lispy-mode) + +(use-package clojure-mode + :straight t + :mode "\\.clj[sc]?\\'" + :config + ;; (add-hook 'clojure-mode-hook #'smartparens-strict-mode) + (add-hook 'clojure-mode-hook #'lispy-mode) + (add-hook 'clojure-mode-hook #'aggressive-indent-mode)) + +(use-package cider + :mode "\\.clj[sc]?\\'" + :straight t) + +(use-package hy-mode + :straight t + :mode "\\.hy\\'" + :config + (add-hook 'hy-mode-hook #'lispy-mode) + (add-hook 'hy-mode-hook #'aggressive-indent-mode)) + +(use-package geiser + :straight t + :if (not my/lowpower) + :commands (geiser run-geiser) + :config + (setq geiser-default-implementation 'guile)) + +(use-package geiser-guile + :straight t + :after geiser) + +(add-hook 'scheme-mode-hook #'aggressive-indent-mode) +(add-hook 'scheme-mode-hook #'lispy-mode) + +(use-package clips-mode + :straight t + :mode "\\.cl\\'" + :config + (add-hook 'clips-mode 'lispy-mode)) + +(setq my/pipenv-python-alist '()) + +(defun my/get-pipenv-python () + (let ((default-directory (projectile-project-root))) + (if (file-exists-p "Pipfile") + (let ((asc (assoc default-directory my/pipenv-python-alist))) + (if asc + (cdr asc) + (let ((python-executable + (string-trim (shell-command-to-string "PIPENV_IGNORE_VIRTUALENVS=1 pipenv run which python 2>/dev/null")))) + (if (string-match-p ".*not found.*" python-executable) + (message "Pipfile found, but not pipenv executable!") + (message (format "Found pipenv python: %s" python-executable)) + (add-to-list 'my/pipenv-python-alist (cons default-directory python-executable)) + python-executable)))) + "python"))) + +(use-package lsp-pyright + :straight t :defer t :if (not my/slow-ssh) - :straight (eshell-info-banner :type git - :host github - :repo "phundrak/eshell-info-banner.el") - :hook (eshell-banner-load . eshell-info-banner-update-banner)) + :hook (python-mode . (lambda () + (require 'lsp-pyright) + (setq-local lsp-pyright-python-executable-cmd (my/get-pipenv-python)) + (lsp)))) -(when my/slow-ssh - (general-nmap "`" 'aweshell-dedicated-toggle) - (general-nmap "~" 'eshell)) +(add-hook 'python-mode-hook #'smartparens-mode) +(add-hook 'python-mode-hook #'hs-minor-mode) + +(use-package pipenv + :straight t + :hook (python-mode . pipenv-mode) + :if (not my/slow-ssh) + :init + (setq + pipenv-projectile-after-switch-function + #'pipenv-projectile-after-switch-extended)) + +(use-package yapfify + :straight (:repo "JorisE/yapfify" :host github) + :commands (yapfify-region + yapfify-buffer + yapfify-region-or-buffer + yapf-mode)) + +(use-package py-isort + :straight t + :commands (py-isort-buffer py-isort-region)) + +(my-leader-def + :keymaps 'python-mode-map + "rr" (lambda () + (interactive) + (unless (and (fboundp #'org-src-edit-buffer-p) (org-src-edit-buffer-p)) + (py-isort-buffer)) + (yapfify-buffer))) + +(use-package sphinx-doc + :straight t + :hook (python-mode . sphinx-doc-mode) + :config + (my-leader-def + :keymaps 'sphinx-doc-mode-map + "rd" 'sphinx-doc)) + +(defun my/set-pipenv-pytest () + (setq-local + python-pytest-executable + (concat (my/get-pipenv-python) " -m pytest"))) + +(use-package python-pytest + :straight t + :commands (python-pytest-dispatch) + :init + (my-leader-def + :keymaps 'python-mode-map + :infix "t" + "t" 'python-pytest-dispatch) + :config + (cl-defun python-pytest--run-as-comint (&key command) + "Run a pytest comint session for COMMAND." + (let* ((buffer (python-pytest--get-buffer)) + (process (get-buffer-process buffer))) + (with-current-buffer buffer + (when (comint-check-proc buffer) + (unless (or compilation-always-kill + (yes-or-no-p "Kill running pytest process?")) + (user-error "Aborting; pytest still running"))) + (when process + (delete-process process)) + (let ((inhibit-read-only t)) + (erase-buffer)) + (unless (eq major-mode 'python-pytest-mode) + (python-pytest-mode)) + (compilation-forget-errors) + (display-buffer buffer) + (setq command (format "export COLUMNS=%s; %s" + (- (window-width (get-buffer-window buffer)) 5) + command)) + (insert (format "cwd: %s\ncmd: %s\n\n" default-directory command)) + (setq python-pytest--current-command command) + (when python-pytest-pdb-track + (add-hook + 'comint-output-filter-functions + 'python-pdbtrack-comint-output-filter-function + nil t)) + (run-hooks 'python-pytest-setup-hook) + (make-comint-in-buffer "pytest" buffer "bash" nil "-c" command) + (run-hooks 'python-pytest-started-hook) + (setq process (get-buffer-process buffer)) + (set-process-sentinel process #'python-pytest--process-sentinel)))) + (add-hook 'python-mode-hook #'my/set-pipenv-pytest) + (when (derived-mode-p 'python-mode) + (my/set-pipenv-pytest))) + +(use-package code-cells + :straight t + :commands (code-cells-mode)) + +(setq my/tensorboard-buffer "TensorBoard-out") + +(defun my/tensorboard () + (interactive) + (start-process + "tensorboard" + my/tensorboard-buffer + "tensorboard" + "serve" + "--logdir" + (car (find-file-read-args "Directory: " t))) + (display-buffer my/tensorboard-buffer)) + +(use-package lsp-java + :straight t + :after (lsp) + :config + (setq lsp-java-jdt-download-url "https://download.eclipse.org/jdtls/milestones/0.57.0/jdt-language-server-0.57.0-202006172108.tar.gz")) + +(add-hook 'java-mode-hook #'smartparens-mode) +;; (add-hook 'java-mode-hook #'hs-minor-mode) +(my/set-smartparens-indent 'java-mode) + +(use-package go-mode + :straight t + :mode "\\.go\\'" + :config + (my/set-smartparens-indent 'go-mode) + (add-hook 'go-mode-hook #'smartparens-mode) + (add-hook 'go-mode-hook #'hs-minor-mode)) + +(use-package csharp-mode + :straight t + :mode "\\.cs\\'" + :config + (setq lsp-csharp-server-path (executable-find "omnisharp-wrapper")) + (add-hook 'csharp-mode-hook #'csharp-tree-sitter-mode) + (add-hook 'csharp-tree-sitter-mode-hook #'smartparens-mode) + (add-hook 'csharp-mode-hook #'hs-minor-mode) + (my/set-smartparens-indent 'csharp-tree-sitter-mode)) + +(use-package csproj-mode + :straight t + :mode "\\.csproj\\'" + :config + (add-hook 'csproj-mode #'smartparens-mode)) + +(use-package fish-mode + :straight t + :mode "\\.fish\\'" + :config + (add-hook 'fish-mode-hook #'smartparens-mode)) + +(add-hook 'sh-mode-hook #'smartparens-mode) + +(use-package haskell-mode + :straight t + :mode "\\.hs\\'") + +(use-package lsp-haskell + :straight t + :after (lsp haskell-mode)) + +(use-package lua-mode + :straight t + :mode "\\.lua\\'" + :hook (lua-mode . smartparens-mode)) + +(my/set-smartparens-indent 'lua-mode) + +(use-package json-mode + :straight t + :mode "\\.json\\'" + :config + (add-hook 'json-mode #'smartparens-mode) + (add-hook 'json-mode #'hs-minor-mode) + (my/set-smartparens-indent 'json-mode)) + +(setq my/sqlformatter-dialect-choice + '("db2" "mariadb" "mysql" "n1ql" "plsql" "postgresql" "redshift" "spark" "sql" "tsql")) + +(setq my/sqlformatter-dialect "postgresql") + +(defun my/sqlformatter-set-dialect () + "Set dialect for sql-formatter" + (interactive) + (setq my/sqlformatter-dialect + (completing-read "Dialect: " my/sqlformatter-dialect-choice))) + +(reformatter-define sqlformat + :program (executable-find "sql-formatter") + :args `("-l" ,my/sqlformatter-dialect, "-u")) + +(my-leader-def + :keymaps '(sql-mode-map) + "rr" #'sqlformat-buffer) + +(use-package yaml-mode + :straight t + :mode "\\.yml\\'" + :config + (add-hook 'yaml-mode-hook 'smartparens-mode) + (add-hook 'yaml-mode-hook 'highlight-indent-guides-mode) + (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))) + +(use-package dotenv-mode + :straight t + :mode "\\.env\\..*\\'") + +(use-package csv-mode + :straight t + :mode "\\.csv\\'") + +(use-package dockerfile-mode + :mode "Dockerfile\\'" + :straight t + :config + (add-hook 'dockerfile-mode 'smartparens-mode)) + +(use-package crontab-mode + :straight t) (use-package org :straight t @@ -2406,1224 +3213,297 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer." (when (member (buffer-file-name) my/org-config-files) (setq-local org-confirm-babel-evaluate nil)))) -(use-package lsp-mode - :straight t - :if (not (or my/slow-ssh my/is-termux my/remote-server)) - :hook ( - (typescript-mode . lsp) - (js-mode . lsp) - (vue-mode . lsp) - (go-mode . lsp) - (svelte-mode . lsp) - ;; (python-mode . lsp) - (json-mode . lsp) - (haskell-mode . lsp) - (haskell-literate-mode . lsp) - (java-mode . lsp) - ;; (csharp-mode . lsp) - ) - :commands lsp - :init - (setq lsp-keymap-prefix nil) +(use-package dired + :ensure nil + :custom ((dired-listing-switches "-alh --group-directories-first")) + :commands (dired) :config - (setq lsp-idle-delay 1) - (setq lsp-eslint-server-command '("node" "/home/pavel/.emacs.d/.cache/lsp/eslint/unzipped/extension/server/out/eslintServer.js" "--stdio")) - (setq lsp-eslint-run "onSave") - (setq lsp-signature-render-documentation nil) - ;; (lsp-headerline-breadcrumb-mode nil) - (setq lsp-headerline-breadcrumb-enable nil) - (add-to-list 'lsp-language-id-configuration '(svelte-mode . "svelte"))) - -(use-package lsp-ui - :straight t - :commands lsp-ui-mode - :config - (setq lsp-ui-doc-delay 2) - (setq lsp-ui-sideline-show-hover nil)) - -;; (use-package helm-lsp -;; :straight t -;; :commands helm-lsp-workspace-symbol) - -;; (use-package origami -;; :straight t -;; :hook (prog-mode . origami-mode)) - -;; (use-package lsp-origami -;; :straight t -;; :config -;; (add-hook 'lsp-after-open-hook #'lsp-origami-try-enable)) - -(use-package lsp-treemacs - :after (lsp) - :straight t - :commands lsp-treemacs-errors-list) - -(my-leader-def - :infix "l" - "" '(:which-key "lsp") - "d" 'lsp-ui-peek-find-definitions - "r" 'lsp-rename - "u" 'lsp-ui-peek-find-references - "s" 'lsp-ui-find-workspace-symbol - "l" 'lsp-execute-code-action - "e" 'list-flycheck-errors) - -(use-package flycheck - :straight t - :config - (global-flycheck-mode) - (setq flycheck-check-syntax-automatically '(save idle-buffer-switch mode-enabled)) - ;; (add-hook 'evil-insert-state-exit-hook - ;; (lambda () - ;; (if flycheck-checker - ;; (flycheck-buffer)) - ;; )) - (advice-add 'flycheck-eslint-config-exists-p :override (lambda() t)) - (add-to-list 'display-buffer-alist - `(,(rx bos "*Flycheck errors*" eos) - (display-buffer-reuse-window - display-buffer-in-side-window) - (side . bottom) - (reusable-frames . visible) - (window-height . 0.33)))) - -(defun my/tree-sitter-if-not-mmm () - (when (not (and (boundp 'mmm-temp-buffer-name) - (string-equal mmm-temp-buffer-name (buffer-name)))) - (tree-sitter-mode) - (tree-sitter-hl-mode))) - -(use-package tree-sitter - :straight t - :if (not my/remote-server) - :hook ((typescript-mode . my/tree-sitter-if-not-mmm) - (js-mode . my/tree-sitter-if-not-mmm) - (python-mode . tree-sitter-mode) - (python-mode . tree-sitter-hl-mode) - (csharp-mode . tree-sitter-mode))) - -(use-package tree-sitter-langs - :straight t - :after tree-sitter) - -(use-package dap-mode - :straight t - :commands (dap-debug) - :init - (setq lsp-enable-dap-auto-configure nil) - :config - - (setq dap-ui-variable-length 100) - (setq dap-auto-show-output nil) - (require 'dap-node) - (dap-node-setup) - - (require 'dap-chrome) - (dap-chrome-setup) - - (require 'dap-python) - - (dap-mode 1) - (dap-ui-mode 1) - (dap-tooltip-mode 1) - (tooltip-mode 1)) - -(with-eval-after-load 'dap-mode - (defmacro my/define-dap-ui-window-toggler (name) - `(defun ,(intern (concat "my/dap-ui-toggle-" name)) () - ,(concat "Toggle DAP " name "buffer") - (interactive) - (if-let (window (get-buffer-window ,(intern (concat "dap-ui--" name "-buffer")))) - (quit-window nil window) - (,(intern (concat "dap-ui-" name)))))) - - (my/define-dap-ui-window-toggler "locals") - (my/define-dap-ui-window-toggler "expressions") - (my/define-dap-ui-window-toggler "sessions") - (my/define-dap-ui-window-toggler "breakpoints") - (my/define-dap-ui-window-toggler "repl")) - -(defhydra my/dap-hydra (:color pink :hint nil :foreign-keys run) - " -^Stepping^ ^UI^ ^Switch^ ^Breakpoints^ ^Debug^ ^Expressions -^^^^^^^^------------------------------------------------------------------------------------------------------------------------------------------ -_n_: Next _uc_: Controls _ss_: Session _bb_: Toggle _dd_: Debug _ee_: Eval -_i_: Step in _ue_: Expressions _st_: Thread _bd_: Delete _dr_: Debug recent _er_: Eval region -_o_: Step out _ul_: Locals _sf_: Stack frame _ba_: Add _dl_: Debug last _es_: Eval thing at point -_c_: Continue _ur_: REPL _su_: Up stack frame _bc_: Set condition _de_: Edit debug template _ea_: Add expression -_r_: Restart frame _uo_: Output _sd_: Down stack frame _bh_: Set hit count _Q_: Disconnect _ed_: Remove expression - _us_: Sessions _sF_: Stack frame filtered _bl_: Set log message _eu_: Refresh expressions - _ub_: Breakpoints " - - ("n" dap-next) - ("i" dap-step-in) - ("o" dap-step-out) - ("c" dap-continue) - ("r" dap-restart-frame) - ("uc" dap-ui-controls-mode) - ("ue" my/dap-ui-toggle-expressions) - ("ul" my/dap-ui-toggle-locals) - ("ur" my/dap-ui-toggle-repl) - ("uo" dap-ui-go-to-output-buffer) - ("us" my/dap-ui-toggle-sessions) - ("ub" my/dap-ui-toggle-breakpoints) - ("ss" dap-switch-session) - ("st" dap-switch-thread) - ("sf" dap-switch-stack-frame) - ("sF" my/dap-switch-stack-frame) - ("su" dap-up-stack-frame) - ("sd" dap-down-stack-frame) - ("bb" dap-breakpoint-toggle) - ("ba" dap-breakpoint-add) - ("bd" dap-breakpoint-delete) - ("bc" dap-breakpoint-condition) - ("bh" dap-breakpoint-hit-condition) - ("bl" dap-breakpoint-log-message) - ("dd" dap-debug) - ("dr" dap-debug-recent) - ("dl" dap-debug-last) - ("de" dap-debug-edit-template) - ("ee" dap-eval) - ("ea" dap-ui-expressions-add) - ("er" dap-eval-region) - ("es" dap-eval-thing-at-point) - ("ed" dap-ui-expressions-remove) - ("eu" dap-ui-expressions-refresh) - ("q" nil "quit" :color blue) - ("Q" dap-disconnect :color red)) - -(my-leader-def "d" #'my/dap-hydra/body) - -(defvar my/dap-mode-buffer-fixed nil) - -(with-eval-after-load 'dap-mode - (defmacro my/define-dap-tree-buffer-fixer (buffer-var buffer-name) - `(defun ,(intern (concat "my/fix-dap-ui-" buffer-name "-buffer")) (&rest _) - (with-current-buffer ,buffer-var - (unless my/dap-mode-buffer-fixed - (toggle-truncate-lines 1) - (doom-modeline-set-modeline 'info) - (setq-local my/dap-mode-buffer-fixed t))))) - - (my/define-dap-tree-buffer-fixer dap-ui--locals-buffer "locals") - (my/define-dap-tree-buffer-fixer dap-ui--expressions-buffer "expressions") - (my/define-dap-tree-buffer-fixer dap-ui--sessions-buffer "sessions") - (my/define-dap-tree-buffer-fixer dap-ui--breakpoints-buffer "breakpoints") - - (advice-add 'dap-ui-locals :after #'my/fix-dap-ui-locals-buffer) - (advice-add 'dap-ui-expressions :after #'my/fix-dap-ui-expressions-buffer) - (advice-add 'dap-ui-sessions :after #'my/fix-dap-ui-sessions-buffer) - (advice-add 'dap-ui-breakpoints :after #'my/fix-dap-ui-breakpoints-buffer)) - -(defun my/clear-bad-window-parameters () - "Clear window parameters that interrupt my workflow." - (interactive) - (let ((window (get-buffer-window (current-buffer)))) - (set-window-parameter window 'no-delete-other-windows nil))) - -(defun my/dap-yank-value-at-point (node) - (interactive (list (treemacs-node-at-point))) - (kill-new (message (plist-get (button-get node :item) :value)))) - -(defun my/dap-display-value (node) - (interactive (list (treemacs-node-at-point))) - (let ((value (plist-get (button-get node :item) :value))) - (when value - (let ((buffer (generate-new-buffer "dap-value"))) - (with-current-buffer buffer - (insert value)) - (select-window (display-buffer buffer)))))) - -(with-eval-after-load 'dap-mode - (setq my/dap-stack-frame-filters - `(("node_modules,node:internal" . ,(rx (or "node_modules" "node:internal"))) - ("node_modules" . ,(rx (or "node_modules"))) - ("node:internal" . ,(rx (or "node:internal"))))) - - (setq my/dap-stack-frame-current-filter (cdar my/dap-stack-frame-filters)) - - (defun my/dap-stack-frame-filter-set () - (interactive) - (setq my/dap-stack-frame-current-filter - (cdr - (assoc - (completing-read "Filter: " my/dap-stack-frame-filters) - my/dap-stack-frame-filters)))) - - (defun my/dap-stack-frame-filter (frame) - (when-let (path (dap--get-path-for-frame frame)) - (not (string-match my/dap-stack-frame-current-filter path))))) - -(defun my/dap-switch-stack-frame () - "Switch stackframe by selecting another stackframe stackframes from current thread." - (interactive) - (when (not (dap--cur-session)) - (error "There is no active session")) - - (-if-let (thread-id (dap--debug-session-thread-id (dap--cur-session))) - (-if-let (stack-frames - (gethash - thread-id - (dap--debug-session-thread-stack-frames (dap--cur-session)))) - (let* ((index 0) - (stack-framces-filtered - (-filter - #'my/dap-stack-frame-filter - stack-frames)) - (new-stack-frame - (dap--completing-read - "Select active frame: " - stack-framces-filtered - (-lambda ((frame &as &hash "name")) - (if-let (frame-path (dap--get-path-for-frame frame)) - (format "%s: %s (in %s)" - (cl-incf index) name frame-path) - (format "%s: %s" (cl-incf index) name))) - nil - t))) - (dap--go-to-stack-frame (dap--cur-session) new-stack-frame)) - (->> (dap--cur-session) - dap--debug-session-name - (format "Current session %s is not stopped") - error)) - (error "No thread is currently active %s" (dap--debug-session-name (dap--cur-session))))) - -(with-eval-after-load 'dap-mode - (dap-register-debug-template - "Node::Nest.js" - (list :type "node" - :request "attach" - :name "Node::Attach" - :port 9229 - :outFiles ["${workspaceFolder}/dist/**/*.js"] - :sourceMaps t - :program "${workspaceFolder}/src/app.ts")) - (dap-register-debug-template - "Node::Babel" - (list :type "node" - :request "attach" - :name "Node::Attach" - :port 9229 - :program "${workspaceFolder}/dist/bin/www.js"))) - -(use-package reformatter - :straight t) - -(defun my/set-smartparens-indent (mode) - (sp-local-pair mode "{" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET"))) - (sp-local-pair mode "[" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET"))) - (sp-local-pair mode "(" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET")))) - -(defun my/set-flycheck-eslint() - "Override flycheck checker with eslint." - (setq-local lsp-diagnostic-package :none) - (setq-local flycheck-checker 'javascript-eslint)) - -(use-package emmet-mode - :straight t - :hook ((vue-html-mode . emmet-mode) - (svelte-mode . emmet-mode) - (web-mode . emmet-mode) - (html-mode . emmet-mode) - (css-mode . emmet-mode) - (scss-mode . emmet-mode)) - :config - ;; (setq emmet-indent-after-insert nil) - (setq my/emmet-mmm-submodes '(vue-html-mode css-mode)) - (defun my/emmet-or-tab (&optional arg) - (interactive) - (if (and - (boundp 'mmm-current-submode) - mmm-current-submode - (not (member mmm-current-submode my/emmet-mmm-submodes))) - (indent-for-tab-command arg) - (or (emmet-expand-line arg) - (emmet-go-to-edit-point 1) - (indent-for-tab-command arg)))) - (general-imap :keymaps 'emmet-mode-keymap - "TAB" 'my/emmet-or-tab - "" 'emmet-prev-edit-point)) - -(use-package prettier - :commands (prettier-prettify) - :straight t - :init - (my-leader-def - :keymaps '(js-mode-map web-mode-map typescript-mode-map vue-mode-map svelte-mode-map) - "rr" #'prettier-prettify)) - -(use-package typescript-mode - :straight t - :mode "\\.ts\\'" - :config - (add-hook 'typescript-mode-hook #'smartparens-mode) - (add-hook 'typescript-mode-hook #'rainbow-delimiters-mode) - (add-hook 'typescript-mode-hook #'hs-minor-mode) - (my/set-smartparens-indent 'typescript-mode)) - -(add-hook 'js-mode-hook #'smartparens-mode) -(add-hook 'js-mode-hook #'hs-minor-mode) -(my/set-smartparens-indent 'js-mode) - -(use-package jest-test-mode - :straight t - :hook ((typescript-mode . jest-test-mode) - (js-mode . jest-test-mode)) - :config - (my-leader-def - :keymaps 'jest-test-mode-map - :infix "t" - "t" 'jest-test-run-at-point - "r" 'jest-test-run - "a" 'jest-test-run-all-tests)) - -(defun my/jest-test-run-at-point-copy () - "Run the top level describe block of the current buffer's point." - (interactive) - (let ((filename (jest-test-find-file)) - (example (jest-test-example-at-point))) - (if (and filename example) - (jest-test-from-project-directory filename - (let ((jest-test-options (seq-concatenate 'list jest-test-options (list "-t" example)))) - (kill-new (jest-test-command filename)))) - (message jest-test-not-found-message)))) - -(use-package web-mode - :straight t - :init - (add-to-list 'auto-mode-alist '("\\.svelte\\'" . web-mode)) - (add-to-list 'auto-mode-alist '("\\.vue\\'" . web-mode)) - :config - (add-hook 'web-mode-hook 'smartparens-mode) - (add-hook 'web-mode-hook 'hs-minor-mode) - (my/set-smartparens-indent 'web-mode)) - -(setq my/web-mode-lsp-extensions - `(,(rx ".svelte" eos) - ,(rx ".vue" eos))) - -(defun my/web-mode-lsp () - (when (seq-some - (lambda (regex) (string-match-p regex (buffer-name))) - my/web-mode-lsp-extensions) - (lsp-deferred))) - -(add-hook 'web-mode-hook #'my/web-mode-lsp) - -(defun my/web-mode-vue-setup () - (when (string-match-p (rx ".vue" eos) (buffer-name)) - (setq-local web-mode-script-padding 0))) - -(add-hook 'web-mode-hook 'my/web-mode-vue-setup) - -(use-package vue-mode - :straight t - :disabled - :mode "\\.vue\\'" - :config - (add-hook 'vue-mode-hook #'hs-minor-mode) - (add-hook 'vue-mode-hook #'smartparens-mode) - (my/set-smartparens-indent 'vue-mode) - (add-hook 'vue-mode-hook (lambda () (set-face-background 'mmm-default-submode-face nil))) - (defun mmm-syntax-propertize-function (start stop) - (let ((saved-mode mmm-current-submode) - (saved-ovl mmm-current-overlay)) - (mmm-save-changed-local-variables - mmm-current-submode mmm-current-overlay) - (unwind-protect - (mapc (lambda (elt) - (let* ((mode (car elt)) - (func (get mode 'mmm-syntax-propertize-function)) - (beg (cadr elt)) (end (nth 2 elt)) - (ovl (nth 3 elt)) - syntax-ppss-cache - syntax-ppss-last) - (goto-char beg) - (mmm-set-current-pair mode ovl) - (mmm-set-local-variables mode mmm-current-overlay) - (save-restriction - (if mmm-current-overlay - (narrow-to-region (overlay-start mmm-current-overlay) - (overlay-end mmm-current-overlay)) - (narrow-to-region beg end)) - (cond - (func - (funcall func beg end)) - (font-lock-syntactic-keywords - (let ((syntax-propertize-function nil)) - (font-lock-fontify-syntactic-keywords-region beg end)))) - (run-hook-with-args 'mmm-after-syntax-propertize-functions - mmm-current-overlay mode beg end)))) - (mmm-regions-in start stop)) - (mmm-set-current-pair saved-mode saved-ovl) - (mmm-set-local-variables (or saved-mode mmm-primary-mode) saved-ovl))))) - -(with-eval-after-load 'editorconfig - (add-to-list 'editorconfig-indentation-alist - '(vue-mode css-indent-offset - js-indent-level - sgml-basic-offset - ssass-tab-width - typescript-indent-level - emmet-indentation - vue-html-extra-indent))) - -(use-package svelte-mode - :straight t - :mode "\\.svelte\\'" - :disabled - :config - (add-hook 'svelte-mode-hook 'my/set-flycheck-eslint) - (add-hook 'svelte-mode-hook #'smartparens-mode) - (my/set-smartparens-indent 'svelte-mode) - ;; I have my own Emmet - (setq lsp-svelte-plugin-css-completions-emmet nil) - (setq lsp-svelte-plugin-html-completions-emmet nil)) - -(add-hook 'scss-mode-hook #'smartparens-mode) -(add-hook 'scss-mode-hook #'hs-minor-mode) -(my/set-smartparens-indent 'scss-mode) - -(use-package php-mode - :straight t - :mode "\\.php\\'") - -(use-package tex - :straight auctex - :defer t - :config - (setq-default TeX-auto-save t) - (setq-default TeX-parse-self t) - (TeX-PDF-mode) - ;; Use XeLaTeX & stuff - (setq-default TeX-engine 'xetex) - (setq-default TeX-command-extra-options "-shell-escape") - (setq-default TeX-source-correlate-method 'synctex) - (TeX-source-correlate-mode) - (setq-default TeX-source-correlate-start-server t) - (setq-default LaTeX-math-menu-unicode t) - - (setq-default font-latex-fontify-sectioning 1.3) - - ;; Scale preview for my DPI - (setq-default preview-scale-function 1.4) - (when (boundp 'tex--prettify-symbols-alist) - (assoc-delete-all "--" tex--prettify-symbols-alist) - (assoc-delete-all "---" tex--prettify-symbols-alist)) - - (add-hook 'LaTeX-mode-hook + (setq dired-dwim-target t) + (setq wdired-allow-to-change-permissions t) + (setq wdired-create-parent-directories t) + (setq dired-recursive-copies 'always) + (setq dired-recursive-deletes 'always) + (setq dired-kill-when-opening-new-dired-buffer t) + (add-hook 'dired-mode-hook (lambda () - (TeX-fold-mode 1) - (outline-minor-mode))) - - (add-to-list 'TeX-view-program-selection - '(output-pdf "Zathura")) - - ;; Do not run lsp within templated TeX files - (add-hook 'LaTeX-mode-hook - (lambda () - (unless (string-match "\.hogan\.tex$" (buffer-name)) - (lsp)) - (setq-local lsp-diagnostic-package :none) - (setq-local flycheck-checker 'tex-chktex))) - - (add-hook 'LaTeX-mode-hook #'rainbow-delimiters-mode) - (add-hook 'LaTeX-mode-hook #'smartparens-mode) - (add-hook 'LaTeX-mode-hook #'prettify-symbols-mode) - - (my/set-smartparens-indent 'LaTeX-mode) - (require 'smartparens-latex) - - (general-nmap - :keymaps '(LaTeX-mode-map latex-mode-map) - "RET" 'TeX-command-run-all - "C-c t" 'orgtbl-mode) - - (setq my/greek-alphabet - '(("a" . "\\alpha") - ("b" . "\\beta" ) - ("g" . "\\gamma") - ("d" . "\\delta") - ("e" . "\\epsilon") - ("z" . "\\zeta") - ("h" . "\\eta") - ("o" . "\\theta") - ("i" . "\\iota") - ("k" . "\\kappa") - ("l" . "\\lambda") - ("m" . "\\mu") - ("n" . "\\nu") - ("x" . "\\xi") - ("p" . "\\pi") - ("r" . "\\rho") - ("s" . "\\sigma") - ("t" . "\\tau") - ("u" . "\\upsilon") - ("f" . "\\phi") - ("c" . "\\chi") - ("v" . "\\psi") - ("g" . "\\omega"))) - - (setq my/latex-greek-prefix "'") - - ;; The same for capitalized letters - (dolist (elem my/greek-alphabet) - (let ((key (car elem)) - (value (cdr elem))) - (when (string-equal key (downcase key)) - (add-to-list 'my/greek-alphabet - (cons - (capitalize (car elem)) - (concat - (substring value 0 1) - (capitalize (substring value 1 2)) - (substring value 2))))))) - - (yas-define-snippets - 'latex-mode - (mapcar - (lambda (elem) - (list (concat my/latex-greek-prefix (car elem)) (cdr elem) (concat "Greek letter " (car elem)))) - my/greek-alphabet)) - (setq my/english-alphabet - '("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z")) - - (dolist (elem my/english-alphabet) - (when (string-equal elem (downcase elem)) - (add-to-list 'my/english-alphabet (upcase elem)))) - - (setq my/latex-mathbb-prefix "`") - - (yas-define-snippets - 'latex-mode - (mapcar - (lambda (elem) - (list (concat my/latex-mathbb-prefix elem) (concat "\\mathbb{" elem "}") (concat "Mathbb letter " elem))) - my/english-alphabet)) - (setq my/latex-math-symbols - '(("x" . "\\times") - ("." . "\\cdot") - ("v" . "\\forall") - ("s" . "\\sum_{$1}^{$2}$0") - ("p" . "\\prod_{$1}^{$2}$0") - ("d" . "\\partial") - ("e" . "\\exists") - ("i" . "\\int_{$1}^{$2}$0") - ("c" . "\\cap") - ("u" . "\\cup") - ("0" . "\\emptyset") - ("^" . "\\widehat{$1}$0") - ("_" . "\\overline{$1}$0") - ("~" . "\\sim") - ("|" . "\\mid") - ("_|" . "\\perp"))) - - (setq my/latex-math-prefix ";") - - (yas-define-snippets - 'latex-mode - (mapcar - (lambda (elem) - (let ((key (car elem)) - (value (cdr elem))) - (list (concat my/latex-math-prefix key) value (concat "Math symbol " value)))) - my/latex-math-symbols)) - (setq my/latex-section-snippets - '(("ch" . "\\chapter{$1}") - ("sec" . "\\section{$1}") - ("ssec" . "\\subsection{$1}") - ("sssec" . "\\subsubsection{$1}") - ("par" . "\\paragraph{$1}}"))) - - (setq my/latex-section-snippets - (mapcar - (lambda (elem) - `(,(car elem) - ,(cdr elem) - ,(progn - (string-match "[a-z]+" (cdr elem)) - (match-string 0 (cdr elem))))) - my/latex-section-snippets)) - - (dolist (elem my/latex-section-snippets) - (let* ((key (nth 0 elem)) - (value (nth 1 elem)) - (desc (nth 2 elem)) - (star-index (string-match "\{\$1\}" value))) - (add-to-list 'my/latex-section-snippets - `(,(concat key "*") - ,(concat - (substring value 0 star-index) - "*" - (substring value star-index)) - ,(concat desc " with *"))) - (add-to-list 'my/latex-section-snippets - `(,(concat key "l") - ,(concat value "%\n\\label{sec:$2}") - ,(concat desc " with label"))))) - - (dolist (elem my/latex-section-snippets) - (setf (nth 1 elem) (concat (nth 1 elem) "\n$0"))) - - (yas-define-snippets - 'latex-mode - my/latex-section-snippets)) - -(use-package ivy-bibtex - :commands (ivy-bibtex) - :straight t - :init - (my-leader-def "fB" 'ivy-bibtex)) - -(add-hook 'bibtex-mode 'smartparens-mode) - -(defun my/list-sty () - (reverse - (sort - (seq-filter - (lambda (file) (if (string-match ".*\.sty$" file) 1 nil)) - (directory-files - (seq-some - (lambda (dir) - (if (and - (f-directory-p dir) - (seq-some - (lambda (file) (string-match ".*\.sty$" file)) - (directory-files dir)) - ) dir nil)) - (list "./styles" "../styles/" "." "..")) :full)) - (lambda (f1 f2) - (let ((f1b (file-name-base f1)) - (f1b (file-name-base f2))) - (cond - ((string-match-p ".*BibTex" f1) t) - ((and (string-match-p ".*Locale" f1) (not (string-match-p ".*BibTex" f2))) t) - ((string-match-p ".*Preamble" f2) t) - (t (string-lessp f1 f2)))))))) - -(defun my/import-sty () - (interactive) - (insert - (apply #'concat - (cl-mapcar - (lambda (file) (concat "\\usepackage{" (file-name-sans-extension (file-relative-name file default-directory)) "}\n")) - (my/list-sty))))) - -(defun my/import-sty-org () - (interactive) - (insert - (apply #'concat - (cl-mapcar - (lambda (file) (concat "#+LATEX_HEADER: \\usepackage{" (file-name-sans-extension (file-relative-name file default-directory)) "}\n")) - (my/list-sty))))) - -(setq my/greek-alphabet - '(("a" . "\\alpha") - ("b" . "\\beta" ) - ("g" . "\\gamma") - ("d" . "\\delta") - ("e" . "\\epsilon") - ("z" . "\\zeta") - ("h" . "\\eta") - ("o" . "\\theta") - ("i" . "\\iota") - ("k" . "\\kappa") - ("l" . "\\lambda") - ("m" . "\\mu") - ("n" . "\\nu") - ("x" . "\\xi") - ("p" . "\\pi") - ("r" . "\\rho") - ("s" . "\\sigma") - ("t" . "\\tau") - ("u" . "\\upsilon") - ("f" . "\\phi") - ("c" . "\\chi") - ("v" . "\\psi") - ("g" . "\\omega"))) - -(setq my/latex-greek-prefix "'") - -;; The same for capitalized letters -(dolist (elem my/greek-alphabet) - (let ((key (car elem)) - (value (cdr elem))) - (when (string-equal key (downcase key)) - (add-to-list 'my/greek-alphabet - (cons - (capitalize (car elem)) - (concat - (substring value 0 1) - (capitalize (substring value 1 2)) - (substring value 2))))))) - -(yas-define-snippets - 'latex-mode - (mapcar - (lambda (elem) - (list (concat my/latex-greek-prefix (car elem)) (cdr elem) (concat "Greek letter " (car elem)))) - my/greek-alphabet)) - -(setq my/english-alphabet - '("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z")) - -(dolist (elem my/english-alphabet) - (when (string-equal elem (downcase elem)) - (add-to-list 'my/english-alphabet (upcase elem)))) - -(setq my/latex-mathbb-prefix "`") - -(yas-define-snippets - 'latex-mode - (mapcar - (lambda (elem) - (list (concat my/latex-mathbb-prefix elem) (concat "\\mathbb{" elem "}") (concat "Mathbb letter " elem))) - my/english-alphabet)) - -(setq my/latex-math-symbols - '(("x" . "\\times") - ("." . "\\cdot") - ("v" . "\\forall") - ("s" . "\\sum_{$1}^{$2}$0") - ("p" . "\\prod_{$1}^{$2}$0") - ("d" . "\\partial") - ("e" . "\\exists") - ("i" . "\\int_{$1}^{$2}$0") - ("c" . "\\cap") - ("u" . "\\cup") - ("0" . "\\emptyset") - ("^" . "\\widehat{$1}$0") - ("_" . "\\overline{$1}$0") - ("~" . "\\sim") - ("|" . "\\mid") - ("_|" . "\\perp"))) - -(setq my/latex-math-prefix ";") - -(yas-define-snippets - 'latex-mode - (mapcar - (lambda (elem) - (let ((key (car elem)) - (value (cdr elem))) - (list (concat my/latex-math-prefix key) value (concat "Math symbol " value)))) - my/latex-math-symbols)) - -(setq my/latex-section-snippets - '(("ch" . "\\chapter{$1}") - ("sec" . "\\section{$1}") - ("ssec" . "\\subsection{$1}") - ("sssec" . "\\subsubsection{$1}") - ("par" . "\\paragraph{$1}}"))) - -(setq my/latex-section-snippets - (mapcar - (lambda (elem) - `(,(car elem) - ,(cdr elem) - ,(progn - (string-match "[a-z]+" (cdr elem)) - (match-string 0 (cdr elem))))) - my/latex-section-snippets)) - -(dolist (elem my/latex-section-snippets) - (let* ((key (nth 0 elem)) - (value (nth 1 elem)) - (desc (nth 2 elem)) - (star-index (string-match "\{\$1\}" value))) - (add-to-list 'my/latex-section-snippets - `(,(concat key "*") - ,(concat - (substring value 0 star-index) - "*" - (substring value star-index)) - ,(concat desc " with *"))) - (add-to-list 'my/latex-section-snippets - `(,(concat key "l") - ,(concat value "%\n\\label{sec:$2}") - ,(concat desc " with label"))))) - -(dolist (elem my/latex-section-snippets) - (setf (nth 1 elem) (concat (nth 1 elem) "\n$0"))) - -(yas-define-snippets - 'latex-mode - my/latex-section-snippets) - -(use-package markdown-mode - :straight t - :mode "\\.md\\'" - :config - (setq markdown-command - (concat - "pandoc" - " --from=markdown --to=html" - " --standalone --mathjax --highlight-style=pygments" - " --css=pandoc.css" - " --quiet" - )) - (setq markdown-live-preview-delete-export 'delete-on-export) - (setq markdown-asymmetric-header t) - (setq markdown-open-command "/home/pavel/bin/scripts/chromium-sep") - (add-hook 'markdown-mode-hook #'smartparens-mode) + (setq truncate-lines t) + (visual-line-mode nil))) (general-define-key - :keymaps 'markdown-mode-map - "M-" 'markdown-promote - "M-" 'markdown-demote)) + :states '(normal) + :keymaps 'dired-mode-map + "h" 'dired-up-directory + "l" 'dired-find-file + "=" 'dired-narrow + "-" 'dired-create-empty-file + "~" 'vterm + "" 'dired-up-directory + "" 'dired-find-file + "M-" 'dired-open-xdg)) -;; (use-package livedown -;; :straight (:host github :repo "shime/emacs-livedown") -;; :commands livedown-preview -;; :config -;; (setq livedown-browser "qutebrowser")) - -(use-package plantuml-mode - :straight t - :mode "(\\.\\(plantuml?\\|uml\\|puml\\)\\'" - :config - (setq plantuml-executable-path "/home/pavel/.guix-extra-profiles/emacs/emacs/bin/plantuml") - (setq plantuml-default-exec-mode 'executable) - (setq plantuml-indent-level 2) - (setq my/plantuml-indent-regexp-return "^\s*return\s+.+$") - (add-to-list - 'plantuml-indent-regexp-end - my/plantuml-indent-regexp-return) - (add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode)) - (add-to-list 'auto-mode-alist '("\\.uml\\'" . plantuml-mode)) - (add-hook 'plantuml-mode-hook #'smartparens-mode)) - -(general-nmap - :keymaps 'plantuml-mode-map - "RET" 'plantuml-preview) - -(use-package langtool - :straight t - :commands (langtool-check) - :config - (setq langtool-language-tool-server-jar "/home/pavel/bin/LanguageTool-5.4/languagetool-server.jar") - (setq langtool-mother-tongue "ru") - (setq langtool-default-language "en-US")) +(defun my/dired-home () + "Open dired at $HOME" + (interactive) + (dired (expand-file-name "~"))) (my-leader-def - :infix "L" - "" '(:which-key "languagetool") - "c" 'langtool-check - "s" 'langtool-server-stop - "d" 'langtool-check-done - "n" 'langtool-goto-next-error - "p" 'langtool-goto-previous-error - "l" 'langtool-correct-buffer) + "ad" #'dired + "aD" #'my/dired-home) -(use-package lispy - :commands (lispy-mode) +(use-package diredfl + :straight t + :after dired + :config + (diredfl-global-mode 1)) + +(use-package dired-single + :after dired + :disabled :straight t) -(use-package lispyville - :hook (lispy-mode . lispyville-mode) - :straight t) - -(sp-with-modes sp-lisp-modes - (sp-local-pair "'" nil :actions nil)) - -(use-package flycheck-package +(use-package all-the-icons-dired :straight t - :after flycheck + :if (not (or my/lowpower my/slow-ssh (not (display-graphic-p)))) + :hook (dired-mode . (lambda () + (unless (string-match-p "/gnu/store" default-directory) + (all-the-icons-dired-mode)))) :config - (flycheck-package-setup)) + (advice-add 'dired-add-entry :around #'all-the-icons-dired--refresh-advice) + (advice-add 'dired-remove-entry :around #'all-the-icons-dired--refresh-advice) + (advice-add 'dired-kill-subdir :around #'all-the-icons-dired--refresh-advice)) -(add-hook 'emacs-lisp-mode-hook #'aggressive-indent-mode) -;; (add-hook 'emacs-lisp-mode-hook #'smartparens-strict-mode) -(add-hook 'emacs-lisp-mode-hook #'lispy-mode) - -(use-package slime +(use-package dired-open :straight t + :commands (dired-open-xdg)) + +(use-package dired-narrow + :straight t + :commands (dired-narrow) :config - (setq inferior-lisp-program "sbcl") - (add-hook 'slime-repl-mode 'smartparens-mode)) + (general-define-key + :keymaps 'dired-narrow-map + [escape] 'keyboard-quit)) -(add-hook 'lisp-mode-hook #'aggressive-indent-mode) -;; (add-hook 'emacs-lisp-mode-hook #'smartparens-strict-mode) -(add-hook 'lisp-mode-hook #'lispy-mode) - -(use-package clojure-mode +(use-package dired-git-info :straight t - :mode "\\.clj[sc]?\\'" + :after dired + :if (not my/slow-ssh) :config - ;; (add-hook 'clojure-mode-hook #'smartparens-strict-mode) - (add-hook 'clojure-mode-hook #'lispy-mode) - (add-hook 'clojure-mode-hook #'aggressive-indent-mode)) + (general-define-key + :keymap 'dired-mode-map + :states '(normal emacs) + ")" 'dired-git-info-mode)) -(use-package cider - :mode "\\.clj[sc]?\\'" - :straight t) +(defun my/dired-open-this-subdir () + (interactive) + (dired (dired-current-directory))) -(use-package hy-mode - :straight t - :mode "\\.hy\\'" +(defun my/dired-kill-all-subdirs () + (interactive) + (let ((dir dired-directory)) + (kill-buffer (current-buffer)) + (dired dir))) + +(with-eval-after-load 'dired + (general-define-key + :states '(normal) + :keymaps 'dired-mode-map + "s" nil + "ss" 'dired-maybe-insert-subdir + "sl" 'dired-maybe-insert-subdir + "sq" 'dired-kill-subdir + "sk" 'dired-prev-subdir + "sj" 'dired-next-subdir + "sS" 'my/dired-open-this-subdir + "sQ" 'my/dired-kill-all-subdirs + (kbd "TAB") 'dired-hide-subdir)) + +(setq tramp-verbose 1) + +(setq remote-file-name-inhibit-cache nil) +(setq vc-ignore-dir-regexp + (format "\\(%s\\)\\|\\(%s\\)" + vc-ignore-dir-regexp + tramp-file-name-regexp)) + +(when (or my/remote-server my/slow-ssh) + (setq explicit-shell-file-name "/bin/bash")) + +(with-eval-after-load 'tramp + (setq tramp-remote-path + (append tramp-remote-path + '(tramp-own-remote-path)))) + +(defun my/dired-bookmark-open () + (interactive) + (let ((bookmarks + (mapcar + (lambda (el) (cons (format "%-30s %s" (car el) (cdr el)) (cdr el))) + my/dired-bookmarks))) + (dired + (cdr + (assoc + (completing-read "Dired: " bookmarks nil nil "^") + bookmarks))))) + +(use-package vterm + ;; :straight t + :commands (vterm vterm-other-window) :config - (add-hook 'hy-mode-hook #'lispy-mode) - (add-hook 'hy-mode-hook #'aggressive-indent-mode)) + (setq vterm-kill-buffer-on-exit t) -(use-package geiser + (add-hook 'vterm-mode-hook + (lambda () + (setq-local global-display-line-numbers-mode nil) + (display-line-numbers-mode 0))) + + + (advice-add 'evil-collection-vterm-insert + :before (lambda (&rest args) + (ignore-errors + (apply #'vterm-reset-cursor-point args)))) + + (general-define-key + :keymaps 'vterm-mode-map + "M-q" 'vterm-send-escape + + "C-h" 'evil-window-left + "C-l" 'evil-window-right + "C-k" 'evil-window-up + "C-j" 'evil-window-down + + "C-" 'evil-window-right + "C-" 'evil-window-left + "C-" 'evil-window-up + "C-" 'evil-window-down + + "M-" 'vterm-send-left + "M-" 'vterm-send-right + "M-" 'vterm-send-up + "M-" 'vterm-send-down) + + (general-define-key + :keymaps 'vterm-mode-map + :states '(normal insert) + "" 'vterm-beginning-of-line + "" 'vterm-end-of-line) + + (general-define-key + :keymaps 'vterm-mode-map + :states '(insert) + "C-r" 'vterm-send-C-r + "C-k" 'vterm-send-C-k + "C-j" 'vterm-send-C-j + "M-l" 'vterm-send-right + "M-h" 'vterm-send-left + "M-k" 'vterm-send-up + "M-j" 'vterm-send-down)) + +(add-to-list 'display-buffer-alist + `(,"vterm-subterminal.*" + (display-buffer-reuse-window + display-buffer-in-side-window) + (side . bottom) + (reusable-frames . visible) + (window-height . 0.33))) + +(defun my/toggle-vterm-subteminal () + "Toogle subteminal." + (interactive) + (let + ((vterm-window + (seq-find + (lambda (window) + (string-match + "vterm-subterminal.*" + (buffer-name (window-buffer window)))) + (window-list)))) + (if vterm-window + (if (eq (get-buffer-window (current-buffer)) vterm-window) + (kill-buffer (current-buffer)) + (select-window vterm-window)) + (vterm-other-window "vterm-subterminal")))) + +(unless my/slow-ssh + (general-nmap "`" 'my/toggle-vterm-subteminal) + (general-nmap "~" 'vterm)) + +(defun my/vterm-get-pwd () + (if vterm--process + (file-truename (format "/proc/%d/cwd" (process-id vterm--process))) + default-directory)) + +(defun my/vterm-dired-other-window () + "Open dired in vterm pwd in other window" + (interactive) + (dired-other-window (my/vterm-get-pwd))) + +(defun my/vterm-dired-replace () + "Replace vterm with dired" + (interactive) + (let ((pwd (my/vterm-get-pwd))) + (kill-process vterm--process) + (dired pwd))) + +(with-eval-after-load 'vterm + (general-define-key + :keymaps 'vterm-mode-map + :states '(normal) + "gd" #'my/vterm-dired-other-window + "gD" #'my/vterm-dired-replace)) + +(use-package with-editor :straight t - :if (not my/lowpower) + :after (vterm) :config - (setq geiser-default-implementation 'guile)) + (add-hook 'vterm-mode-hook 'with-editor-export-editor)) -(use-package geiser-guile - :straight t - :after geiser) +(defun my/configure-eshell () + (add-hook 'eshell-pre-command-hook 'eshell-save-some-history) + (add-to-list 'eshell-output-filter-functions 'eshell-truncate-buffer) + (setq eshell-history-size 10000) + (setq eshell-hist-ingnoredups t) + (setq eshell-buffer-maximum-lines 10000) -(add-hook 'scheme-mode-hook #'aggressive-indent-mode) -(add-hook 'scheme-mode-hook #'lispy-mode) + (evil-define-key '(normal insert visual) eshell-mode-map (kbd "") 'eshell-bol) + (evil-define-key '(normal insert visual) eshell-mode-map (kbd "C-r") 'counsel-esh-history) + (general-define-key + :states '(normal) + :keymaps 'eshell-mode-map + (kbd "C-h") 'evil-window-left + (kbd "C-l") 'evil-window-right + (kbd "C-k") 'evil-window-up + (kbd "C-j") 'evil-window-down)) -(use-package clips-mode - :straight t - :mode "\\.cl\\'" +(use-package eshell + :ensure nil + :after evil-collection + :commands (eshell) :config - (add-hook 'clips-mode 'lispy-mode)) + (add-hook 'eshell-first-time-mode-hook 'my/configure-eshell 90) + (when my/slow-ssh + (add-hook 'eshell-mode-hook + (lambda () + (setq-local company-idle-delay 1000)))) + (setq eshell-banner-message "")) -(setq my/pipenv-python-alist '()) +(use-package aweshell + :straight (:repo "manateelazycat/aweshell" :host github) + :after eshell + :config + (setq eshell-highlight-prompt nil) + (setq eshell-prompt-function 'epe-theme-pipeline)) -(defun my/get-pipenv-python () - (let ((default-directory (projectile-project-root))) - (if (file-exists-p "Pipfile") - (let ((asc (assoc default-directory my/pipenv-python-alist))) - (if asc - (cdr asc) - (let ((python-executable - (string-trim (shell-command-to-string "PIPENV_IGNORE_VIRTUALENVS=1 pipenv run which python 2>/dev/null")))) - (if (string-match-p ".*not found.*" python-executable) - (message "Pipfile found, but not pipenv executable!") - (message (format "Found pipenv python: %s" python-executable)) - (add-to-list 'my/pipenv-python-alist (cons default-directory python-executable)) - python-executable)))) - "python"))) - -(use-package lsp-pyright - :straight t +(use-package eshell-info-banner :defer t :if (not my/slow-ssh) - :hook (python-mode . (lambda () - (require 'lsp-pyright) - (setq-local lsp-pyright-python-executable-cmd (my/get-pipenv-python)) - (lsp)))) + :straight (eshell-info-banner :type git + :host github + :repo "phundrak/eshell-info-banner.el") + :hook (eshell-banner-load . eshell-info-banner-update-banner)) -(add-hook 'python-mode-hook #'smartparens-mode) -(add-hook 'python-mode-hook #'hs-minor-mode) - -(use-package pipenv - :straight t - :hook (python-mode . pipenv-mode) - :if (not my/slow-ssh) - :init - (setq - pipenv-projectile-after-switch-function - #'pipenv-projectile-after-switch-extended)) - -(use-package yapfify - :straight (:repo "JorisE/yapfify" :host github) - :commands (yapfify-region - yapfify-buffer - yapfify-region-or-buffer - yapf-mode)) - -(use-package py-isort - :straight t - :commands (py-isort-buffer py-isort-region)) - -(my-leader-def - :keymaps 'python-mode-map - "rr" (lambda () - (interactive) - (unless (and (fboundp #'org-src-edit-buffer-p) (org-src-edit-buffer-p)) - (py-isort-buffer)) - (yapfify-buffer))) - -(use-package sphinx-doc - :straight t - :hook (python-mode . sphinx-doc-mode) - :config - (my-leader-def - :keymaps 'sphinx-doc-mode-map - "rd" 'sphinx-doc)) - -(defun my/set-pipenv-pytest () - (setq-local - python-pytest-executable - (concat (my/get-pipenv-python) " -m pytest"))) - -(use-package python-pytest - :straight t - :commands (python-pytest-dispatch) - :init - (my-leader-def - :keymaps 'python-mode-map - :infix "t" - "t" 'python-pytest-dispatch) - :config - (cl-defun python-pytest--run-as-comint (&key command) - "Run a pytest comint session for COMMAND." - (let* ((buffer (python-pytest--get-buffer)) - (process (get-buffer-process buffer))) - (with-current-buffer buffer - (when (comint-check-proc buffer) - (unless (or compilation-always-kill - (yes-or-no-p "Kill running pytest process?")) - (user-error "Aborting; pytest still running"))) - (when process - (delete-process process)) - (let ((inhibit-read-only t)) - (erase-buffer)) - (unless (eq major-mode 'python-pytest-mode) - (python-pytest-mode)) - (compilation-forget-errors) - (display-buffer buffer) - (setq command (format "export COLUMNS=%s; %s" - (- (window-width (get-buffer-window buffer)) 5) - command)) - (insert (format "cwd: %s\ncmd: %s\n\n" default-directory command)) - (setq python-pytest--current-command command) - (when python-pytest-pdb-track - (add-hook - 'comint-output-filter-functions - 'python-pdbtrack-comint-output-filter-function - nil t)) - (run-hooks 'python-pytest-setup-hook) - (make-comint-in-buffer "pytest" buffer "bash" nil "-c" command) - (run-hooks 'python-pytest-started-hook) - (setq process (get-buffer-process buffer)) - (set-process-sentinel process #'python-pytest--process-sentinel)))) - (add-hook 'python-mode-hook #'my/set-pipenv-pytest) - (when (derived-mode-p 'python-mode) - (my/set-pipenv-pytest))) - -(use-package code-cells - :straight t - :commands (code-cells-mode)) - -(setq my/tensorboard-buffer "TensorBoard-out") - -(defun my/tensorboard () - (interactive) - (start-process - "tensorboard" - my/tensorboard-buffer - "tensorboard" - "serve" - "--logdir" - (car (find-file-read-args "Directory: " t))) - (display-buffer my/tensorboard-buffer)) - -(use-package lsp-java - :straight t - :after (lsp) - :config - (setq lsp-java-jdt-download-url "https://download.eclipse.org/jdtls/milestones/0.57.0/jdt-language-server-0.57.0-202006172108.tar.gz")) - -(add-hook 'java-mode-hook #'smartparens-mode) -;; (add-hook 'java-mode-hook #'hs-minor-mode) -(my/set-smartparens-indent 'java-mode) - -(use-package go-mode - :straight t - :mode "\\.go\\'" - :config - (my/set-smartparens-indent 'go-mode) - (add-hook 'go-mode-hook #'smartparens-mode) - (add-hook 'go-mode-hook #'hs-minor-mode)) - -(use-package csharp-mode - :straight t - :mode "\\.cs\\'" - :config - (setq lsp-csharp-server-path (executable-find "omnisharp-wrapper")) - (add-hook 'csharp-mode-hook #'csharp-tree-sitter-mode) - (add-hook 'csharp-tree-sitter-mode-hook #'smartparens-mode) - (add-hook 'csharp-mode-hook #'hs-minor-mode) - (my/set-smartparens-indent 'csharp-tree-sitter-mode)) - -(use-package csproj-mode - :straight t - :mode "\\.csproj\\'" - :config - (add-hook 'csproj-mode #'smartparens-mode)) - -(use-package fish-mode - :straight t - :mode "\\.fish\\'" - :config - (add-hook 'fish-mode-hook #'smartparens-mode)) - -(add-hook 'sh-mode-hook #'smartparens-mode) - -(use-package haskell-mode - :straight t - :mode "\\.hs\\'") - -(use-package lsp-haskell - :straight t - :after (lsp haskell-mode)) - -(use-package lua-mode - :straight t - :mode "\\.lua\\'" - :hook (lua-mode . smartparens-mode)) - -(my/set-smartparens-indent 'lua-mode) - -(use-package json-mode - :straight t - :mode "\\.json\\'" - :config - (add-hook 'json-mode #'smartparens-mode) - (add-hook 'json-mode #'hs-minor-mode) - (my/set-smartparens-indent 'json-mode)) - -(setq my/sqlformatter-dialect-choice - '("db2" "mariadb" "mysql" "n1ql" "plsql" "postgresql" "redshift" "spark" "sql" "tsql")) - -(setq my/sqlformatter-dialect "postgresql") - -(defun my/sqlformatter-set-dialect () - "Set dialect for sql-formatter" - (interactive) - (setq my/sqlformatter-dialect - (completing-read "Dialect: " my/sqlformatter-dialect-choice))) - -(reformatter-define sqlformat - :program (executable-find "sql-formatter") - :args `("-l" ,my/sqlformatter-dialect, "-u")) - -(my-leader-def - :keymaps '(sql-mode-map) - "rr" #'sqlformat-buffer) - -(use-package yaml-mode - :straight t - :mode "\\.yml\\'" - :config - (add-hook 'yaml-mode-hook 'smartparens-mode) - (add-hook 'yaml-mode-hook 'highlight-indent-guides-mode) - (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))) - -(use-package dotenv-mode - :straight t - :mode "\\.env\\..*\\'") - -(use-package csv-mode - :straight t - :mode "\\.csv\\'") - -(use-package dockerfile-mode - :mode "Dockerfile\\'" - :straight t - :config - (add-hook 'dockerfile-mode 'smartparens-mode)) - -(use-package crontab-mode - :straight t) +(when my/slow-ssh + (general-nmap "`" 'aweshell-dedicated-toggle) + (general-nmap "~" 'eshell)) (defun my/edit-configuration () "Open the init file." @@ -4243,6 +4123,7 @@ _r_: Restart frame _uo_: Output _sd_: Down stack frame _bh_: Set (use-package pomm ;; :straight (:host github :repo "SqrtMinusOne/pomm.el" :files (:defaults "resources")) :straight (:local-repo "~/Code/Emacs/pomm" :files (:defaults "resources")) + :commands (pomm) :init (my-leader-def "ap" #'pomm) :config diff --git a/Emacs.org b/Emacs.org index 96b6974..2ecbaa4 100644 --- a/Emacs.org +++ b/Emacs.org @@ -9,6 +9,8 @@ One day we won't hate one another, no young boy will march to war and I will clean up my Emacs config. But that day isn't today. #+end_quote +My configuration of [[https://www.gnu.org/software/emacs/][GNU Emacs]], an awesome +text editor+ program that can do almost anything. + #+TOC: headlines 6 * Contents :noexport: @@ -16,153 +18,94 @@ One day we won't hate one another, no young boy will march to war and I will cle :TOC: :include all :depth 4 :END: :CONTENTS: -- [[#primary-setup][Primary setup]] - - [[#measure-startup-speed][Measure startup speed]] - - [[#straightel][straight.el]] - - [[#use-package][use-package]] - - [[#config-variants--environment][Config variants & environment]] +- [[#some-remarks][Some remarks]] +- [[#bootstrap][Bootstrap]] + - [[#packages][Packages]] + - [[#straightel][straight.el]] + - [[#use-package][use-package]] + - [[#variables--environment][Variables & environment]] - [[#performance][Performance]] + - [[#measure-startup-speed][Measure startup speed]] - [[#garbage-collection][Garbage collection]] - [[#run-garbage-collection-when-emacs-is-unfocused][Run garbage collection when Emacs is unfocused]] - [[#native-compilation][Native compilation]] - [[#anaconda][Anaconda]] - - [[#custom-file-location][Custom file location]] - - [[#private-config][Private config]] - - [[#no-littering][No littering]] + - [[#config-files][Config files]] + - [[#custom-file-location][Custom file location]] + - [[#private-config][Private config]] + - [[#no-littering][No littering]] - [[#prevent-emacs-from-closing][Prevent Emacs from closing]] -- [[#global-editing-configuration][Global editing configuration]] - - [[#general-keybindings-stuff][General keybindings stuff]] +- [[#general-settings][General settings]] + - [[#keybindings][Keybindings]] - [[#generalel][general.el]] - [[#which-key][which-key]] - [[#dump-keybindings][dump keybindings]] - - [[#evil-mode][Evil mode]] - - [[#evil][evil]] - - [[#addons][Addons]] - - [[#evil-collection][evil-collection]] - - [[#more-keybindings][More keybindings]] - - [[#escape-key][Escape key]] - - [[#home--end][Home & end]] - - [[#my-leader][My leader]] - - [[#universal-argument][Universal argument]] - - [[#profiler][Profiler]] - - [[#buffer-switching][Buffer switching]] - - [[#buffer-management][Buffer management]] - - [[#xref][xref]] - - [[#folding][Folding]] - - [[#zoom][Zoom]] + - [[#evil][Evil]] + - [[#evil-mode][Evil-mode]] + - [[#addons][Addons]] + - [[#evil-collection][evil-collection]] + - [[#my-keybindings][My keybindings]] + - [[#escape-key][Escape key]] + - [[#home--end][Home & end]] + - [[#my-leader][My leader]] + - [[#universal-argument][Universal argument]] + - [[#profiler][Profiler]] + - [[#buffer-switching][Buffer switching]] + - [[#buffer-management][Buffer management]] + - [[#xref][xref]] + - [[#folding][Folding]] + - [[#zoom-ui][Zoom UI]] - [[#i3-integration][i3 integration]] - - [[#editing-helpers][Editing helpers]] - - [[#visual-fill-column-mode][Visual fill column mode]] - - [[#smartparens][smartparens]] - - [[#aggressive-indent][Aggressive Indent]] - - [[#delete-trailing-whitespace][Delete trailing whitespace]] - - [[#expand-region][Expand region]] - - [[#various-settings][Various settings]] - - [[#tabs][Tabs]] - - [[#scrolling-config][Scrolling config]] - - [[#clipboard][Clipboard]] - - [[#backups][Backups]] - - [[#undo-tree][Undo Tree]] - - [[#help][Help]] - - [[#ivy-counsel-swiper][Ivy, counsel, swiper]] + - [[#editing-text][Editing text]] + - [[#indentation--whitespace][Indentation & whitespace]] + - [[#aggressive-indent][Aggressive Indent]] + - [[#delete-trailing-whitespace][Delete trailing whitespace]] + - [[#tabs][Tabs]] + - [[#settings][Settings]] + - [[#scrolling][Scrolling]] + - [[#clipboard][Clipboard]] + - [[#backups][Backups]] + - [[#undo-tree][Undo Tree]] + - [[#snippets][Snippets]] + - [[#other-small-packages][Other small packages]] + - [[#managing-parentheses-smartparens][Managing parentheses (smartparens)]] + - [[#expand-region][Expand region]] + - [[#visual-fill-column-mode][Visual fill column mode]] + - [[#working-with-projects][Working with projects]] + - [[#treemacs][Treemacs]] + - [[#helper-functions][Helper functions]] + - [[#custom-icons][Custom icons]] + - [[#projectile][Projectile]] + - [[#git--magit][Git & Magit]] + - [[#editorconfig][Editorconfig]] + - [[#completion][Completion]] + - [[#ivy-counsel-swiper][Ivy, counsel, swiper]] - [[#ivy-rich][ivy-rich]] - [[#prescient][prescient]] - - [[#keybindings][Keybindings]] - - [[#treemacs][Treemacs]] - - [[#helper-functions][Helper functions]] - - [[#custom-icons][Custom icons]] - - [[#projectile][Projectile]] - - [[#company][Company]] - - [[#git--magit][Git & Magit]] - - [[#editorconfig][Editorconfig]] - - [[#snippets][Snippets]] + - [[#keybindings][keybindings]] + - [[#company][company]] + - [[#help][Help]] - [[#time-trackers][Time trackers]] - [[#wakatime][WakaTime]] - [[#activitywatch][ActivityWatch]] -- [[#ui][UI]] - - [[#general-ui--gui-settings][General UI & GUI Settings]] - - [[#theme--global-stuff][Theme & global stuff]] +- [[#ui-settings][UI settings]] + - [[#general-settings][General settings]] + - [[#miscellaneous][Miscellaneous]] + - [[#line-numbers][Line numbers]] + - [[#word-wrapping][Word wrapping]] + - [[#custom-frame-format][Custom frame format]] + - [[#themes-and-colors][Themes and colors]] + - [[#dim-inactive-buffers][Dim inactive buffers]] + - [[#doom-themes][Doom themes]] - [[#custom-theme][Custom theme]] - - [[#font][Font]] - - [[#custom-frame-title][Custom frame title]] - - [[#perspectiveel][perspective.el]] - - [[#some-functions][Some functions]] - - [[#off-tab-bar][(OFF) Tab bar]] - - [[#setup][Setup]] - - [[#my-title][My title]] - - [[#modeline][Modeline]] - - [[#font-stuff][Font stuff]] + - [[#fonts][Fonts]] + - [[#frame-font][Frame font]] - [[#ligatures][Ligatures]] - [[#icons][Icons]] - - [[#highlight-todo][Highlight todo]] - - [[#text-highlight-improvements][Text highlight improvements]] -- [[#dired][Dired]] - - [[#basic-config--keybindings][Basic config & keybindings]] - - [[#addons][Addons]] - - [[#subdirectories][Subdirectories]] - - [[#tramp][TRAMP]] - - [[#bookmarks][Bookmarks]] -- [[#shells][Shells]] - - [[#vterm][vterm]] - - [[#configuration][Configuration]] - - [[#subterminal][Subterminal]] - - [[#dired-integration][Dired integration]] - - [[#with-editor-integration][With-editor integration]] - - [[#eshell][Eshell]] -- [[#org-mode][Org Mode]] - - [[#installation--basic-settings][Installation & basic settings]] - - [[#encryption][Encryption]] - - [[#org-contrib][org-contrib]] - - [[#integration-with-evil][Integration with evil]] - - [[#literate-programing][Literate programing]] - - [[#python--jupyter][Python & Jupyter]] - - [[#hy][Hy]] - - [[#view-html-in-browser][View HTML in browser]] - - [[#plantuml][PlantUML]] - - [[#setup][Setup]] - - [[#managing-jupyter-kernels][Managing Jupyter kernels]] - - [[#do-not-wrap-the-output-in-emacs-jupyter][Do not wrap the output in emacs-jupyter]] - - [[#wrap-source-code-output][Wrap source code output]] - - [[#managing-a-literate-programming-project][Managing a literate programming project]] - - [[#productivity--knowledge-management][Productivity & Knowledge management]] - - [[#capture-templates--various-settings][Capture templates & various settings]] - - [[#trello-sync][Trello sync]] - - [[#org-ql][org-ql]] - - [[#custom-agendas][Custom agendas]] - - [[#review-workflow][Review workflow]] - - [[#data-from-git--org-roam][Data from git & org-roam]] - - [[#data-from-org-journal][Data from org-journal]] - - [[#data-from-org-agenda-via-org-ql][Data from org-agenda via org-ql]] - - [[#capture-template][Capture template]] - - [[#org-journal][Org Journal]] - - [[#org-roam][Org Roam]] - - [[#org-roam-ui][org-roam-ui]] - - [[#org-roam-protocol][org-roam-protocol]] - - [[#org-ref][org-ref]] - - [[#org-roam-bibtex][org-roam-bibtex]] - - [[#managing-tables][Managing tables]] - - [[#ui][UI]] - - [[#off-instant-equations-preview][(OFF) Instant equations preview]] - - [[#latex-fragments][LaTeX fragments]] - - [[#better-headers][Better headers]] - - [[#org-agenda-icons][Org Agenda Icons]] - - [[#export][Export]] - - [[#general-settings][General settings]] - - [[#hugo][Hugo]] - - [[#jupyter-notebook][Jupyter Notebook]] - - [[#html-export][Html export]] - - [[#latex][LaTeX]] - - [[#keybindings--stuff][Keybindings & stuff]] - - [[#copy-a-link][Copy a link]] - - [[#open-a-file-from-org-directory][Open a file from org-directory]] - - [[#presentations][Presentations]] - - [[#tools][Tools]] - - [[#toc][TOC]] - - [[#screenshots][Screenshots]] - - [[#system-configuration][System configuration]] - - [[#tables-for-guix-dependencies][Tables for Guix Dependencies]] - - [[#noweb-evaluations][Noweb evaluations]] - - [[#yadm-hook][yadm hook]] + - [[#text-highlight][Text highlight]] + - [[#doom-modeline][Doom Modeline]] + - [[#perspectiveel][perspective.el]] + - [[#some-functions][Some functions]] - [[#programming][Programming]] - [[#general-setup][General setup]] - [[#lsp][LSP]] @@ -243,10 +186,76 @@ One day we won't hate one another, no young boy will march to war and I will cle - [[#yaml][YAML]] - [[#env][.env]] - [[#csv][CSV]] - - [[#off-pdf][(OFF) PDF]] - [[#docker][Docker]] - [[#crontab][crontab]] -- [[#apps--misc][Apps & Misc]] +- [[#org-mode][Org Mode]] + - [[#installation--basic-settings][Installation & basic settings]] + - [[#encryption][Encryption]] + - [[#org-contrib][org-contrib]] + - [[#integration-with-evil][Integration with evil]] + - [[#literate-programing][Literate programing]] + - [[#python--jupyter][Python & Jupyter]] + - [[#hy][Hy]] + - [[#view-html-in-browser][View HTML in browser]] + - [[#plantuml][PlantUML]] + - [[#setup][Setup]] + - [[#managing-jupyter-kernels][Managing Jupyter kernels]] + - [[#do-not-wrap-the-output-in-emacs-jupyter][Do not wrap the output in emacs-jupyter]] + - [[#wrap-source-code-output][Wrap source code output]] + - [[#managing-a-literate-programming-project][Managing a literate programming project]] + - [[#productivity--knowledge-management][Productivity & Knowledge management]] + - [[#capture-templates--various-settings][Capture templates & various settings]] + - [[#trello-sync][Trello sync]] + - [[#org-ql][org-ql]] + - [[#custom-agendas][Custom agendas]] + - [[#review-workflow][Review workflow]] + - [[#data-from-git--org-roam][Data from git & org-roam]] + - [[#data-from-org-journal][Data from org-journal]] + - [[#data-from-org-agenda-via-org-ql][Data from org-agenda via org-ql]] + - [[#capture-template][Capture template]] + - [[#org-journal][Org Journal]] + - [[#org-roam][Org Roam]] + - [[#org-roam-ui][org-roam-ui]] + - [[#org-roam-protocol][org-roam-protocol]] + - [[#org-ref][org-ref]] + - [[#org-roam-bibtex][org-roam-bibtex]] + - [[#managing-tables][Managing tables]] + - [[#ui][UI]] + - [[#off-instant-equations-preview][(OFF) Instant equations preview]] + - [[#latex-fragments][LaTeX fragments]] + - [[#better-headers][Better headers]] + - [[#org-agenda-icons][Org Agenda Icons]] + - [[#export][Export]] + - [[#general-settings][General settings]] + - [[#hugo][Hugo]] + - [[#jupyter-notebook][Jupyter Notebook]] + - [[#html-export][Html export]] + - [[#latex][LaTeX]] + - [[#keybindings--stuff][Keybindings & stuff]] + - [[#copy-a-link][Copy a link]] + - [[#open-a-file-from-org-directory][Open a file from org-directory]] + - [[#presentations][Presentations]] + - [[#tools][Tools]] + - [[#toc][TOC]] + - [[#screenshots][Screenshots]] + - [[#system-configuration][System configuration]] + - [[#tables-for-guix-dependencies][Tables for Guix Dependencies]] + - [[#noweb-evaluations][Noweb evaluations]] + - [[#yadm-hook][yadm hook]] +- [[#applications][Applications]] + - [[#dired][Dired]] + - [[#basic-config--keybindings][Basic config & keybindings]] + - [[#addons][Addons]] + - [[#subdirectories][Subdirectories]] + - [[#tramp][TRAMP]] + - [[#bookmarks][Bookmarks]] + - [[#shells][Shells]] + - [[#vterm][vterm]] + - [[#configuration][Configuration]] + - [[#subterminal][Subterminal]] + - [[#dired-integration][Dired integration]] + - [[#with-editor-integration][With-editor integration]] + - [[#eshell][Eshell]] - [[#managing-dotfiles][Managing dotfiles]] - [[#open-emacs-config][Open Emacs config]] - [[#open-magit-for-yadm][Open Magit for yadm]] @@ -290,25 +299,18 @@ One day we won't hate one another, no young boy will march to war and I will cle - [[#zone][Zone]] - [[#guix-settings][Guix settings]] :END: -* Primary setup -** Measure startup speed -A small function to print out the loading time and number of GCs during the loading. Can be useful as a point of data for optimizing Emacs startup time. -#+begin_src emacs-lisp -(add-hook 'emacs-startup-hook - (lambda () - (message "*** Emacs loaded in %s with %d garbage collections." - (format "%.2f seconds" - (float-time - (time-subtract after-init-time before-init-time))) - gcs-done))) -#+end_src +* Some remarks +I decided not to keep configs for features that I do not use anymore, because this config is already huge. But here are last commits which had these feature presented. -Set the following to =t= to print debug information during the startup. This will include the order in which the packages are loaded and the loading time of individual packages. -#+begin_src emacs-lisp -;; (setq use-package-verbose t) -#+end_src +| Feature | Last commit | +|------------+------------------------------------------| +| tab-bar.el | 19ff54db9fe21fd5bdf404a8d2612176baa8a6f5 | +| spaceline | 19ff54db9fe21fd5bdf404a8d2612176baa8a6f5 | +* Bootstrap +Setting up the environment, performance tuning and a few basic settings. -** straight.el +** Packages +*** straight.el Straight.el is my Emacs package manager of choice. Its advantages & disadvantages over other options are listed pretty thoroughly in the README file in the repo. The following is a straight.el bootstrap script. @@ -330,7 +332,7 @@ References: (eval-print-last-sexp))) (load bootstrap-file nil 'nomessage)) #+end_src -** use-package +*** use-package A macro to simplify package specification & configuration. Integrates with straight.el. Set ~use-package-verbose~ to ~t~ to print out individual package loading time. @@ -342,7 +344,7 @@ References: (straight-use-package 'use-package) (eval-when-compile (require 'use-package)) #+end_src -** Config variants & environment +** Variables & environment This section is about optionating the Emacs config. The following variable is true when my machine is not powerful enough for some resource-heavy packages. @@ -387,6 +389,23 @@ To launch Emacs with this config, run emacs -q -l ~/.emacs.d/init-minimal.el #+end_src ** Performance +*** Measure startup speed +A small function to print out the loading time and number of GCs during the loading. Can be useful as a point of data for optimizing Emacs startup time. +#+begin_src emacs-lisp +(add-hook 'emacs-startup-hook + (lambda () + (message "*** Emacs loaded in %s with %d garbage collections." + (format "%.2f seconds" + (float-time + (time-subtract after-init-time before-init-time))) + gcs-done))) +#+end_src + +Set the following to =t= to print debug information during the startup. This will include the order in which the packages are loaded and the loading time of individual packages. +#+begin_src emacs-lisp +;; (setq use-package-verbose t) +#+end_src + *** Garbage collection Just setting ~gc-cons-treshold~ to a larger value. @@ -441,14 +460,15 @@ References: (unless (getenv "CONDA_DEFAULT_ENV") (conda-env-activate "general"))) #+end_src -** Custom file location +** Config files +*** Custom file location By default, custom writes stuff to =init.el=, which is somewhat annoying. The following makes it write to a separate file =custom.el= #+begin_src emacs-lisp (setq custom-file (concat user-emacs-directory "custom.el")) (load custom-file 'noerror) #+end_src -** Private config +*** Private config I have some variables which I don't commit to the repo, e.g. my current location. They are stored in =private.el= #+begin_src emacs-lisp @@ -456,7 +476,7 @@ I have some variables which I don't commit to the repo, e.g. my current location (load-file private-file)) #+end_src -** No littering +*** No littering By default Mmacs and its packages create a lot files in =.emacs.d= and in other places. [[https://github.com/emacscollective/no-littering][no-littering]] is a collective effort to redirect all of that to two folders in =user-emacs-directory=. #+begin_src emacs-lisp @@ -469,8 +489,8 @@ This adds a confirmation to avoid accidental Emacs closing. #+begin_src emacs-lisp (setq confirm-kill-emacs 'y-or-n-p) #+end_src -* Global editing configuration -** General keybindings stuff +* General settings +** Keybindings *** general.el general.el provides a convenient interface to manage Emacs keybindings. @@ -527,7 +547,7 @@ A function to dump keybindings starting with a prefix to a buffer in tree-like f (my/dump-bindings-recursive prefix))) (switch-to-buffer-other-window "bindings")) #+end_src -** Evil mode +*** Evil An entire ecosystem of packages that emulates the main features of Vim. Probably the best vim emulator out there. The only problem is that the package name makes it hard to google anything by just typing "evil". @@ -536,7 +556,7 @@ References: - [[https://github.com/emacs-evil/evil][evil repo]] - [[https://www.youtube.com/watch?v=JWD1Fpdd4Pc][(YouTube) Evil Mode: Or, How I Learned to Stop Worrying and Love Emacs]] -*** evil +**** Evil-mode Basic evil configuration. #+begin_src emacs-lisp :noweb-ref minimal @@ -554,7 +574,7 @@ Basic evil configuration. ;; (setq evil-respect-visual-line-mode t) (evil-set-undo-system 'undo-tree)) #+end_src -*** Addons +**** Addons [[https://github.com/emacs-evil/evil-surround][evil-surround]] emulates one of my favorite vim plugins, surround.vim. Adds a lot of parentheses management options. #+begin_src emacs-lisp @@ -615,7 +635,7 @@ Basic evil configuration. :config (global-evil-matchit-mode 1)) #+end_src -*** evil-collection +**** evil-collection [[https://github.com/emacs-evil/evil-collection][evil-collection]] is a package that provides evil bindings for a lot of different packages. One can see the complete list in the [[https://github.com/emacs-evil/evil-collection/tree/master/modes][modes]] folder. #+begin_src emacs-lisp :noweb-ref minimal @@ -661,10 +681,11 @@ Basic evil configuration. prodigy slime))) #+end_src -** More keybindings -The main keybindings setup is positioned after evil mode to take the latter into account. +*** My keybindings +Various keybindings settings that I can't put anywhere else. + +**** Escape key -*** Escape key Use the escape key instead of =C-g= whenever possible. I must have copied it from somewhere, but as I googled to find out the source, I discovered quite a number of variations of the following code over time. I wonder if Richard Dawkins was inspired by something like this a few decades ago. @@ -692,13 +713,13 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer." minibuffer-local-isearch-map) [escape] 'minibuffer-keyboard-quit) #+end_src -*** Home & end +**** Home & end #+begin_src emacs-lisp (general-def :states '(normal insert visual) "" 'beginning-of-line "" 'end-of-line) #+end_src -*** My leader +**** My leader Using the =SPC= key as a leader key, like in Doom Emacs or Spacemacs. #+begin_src emacs-lisp @@ -723,7 +744,7 @@ Using the =SPC= key as a leader key, like in Doom Emacs or Spacemacs. (my-leader-def "a" '(:which-key "apps")) #+end_src -*** Universal argument +**** Universal argument Change the universal argument to =M-u=. I use =C-u= to scroll up, as I'm used to from vim. #+begin_src emacs-lisp @@ -735,7 +756,7 @@ Change the universal argument to =M-u=. I use =C-u= to scroll up, as I'm used to :states '(normal motion emacs insert visual) "M-u" 'universal-argument) #+end_src -*** Profiler +**** CHECK Profiler The built-in profiler is a magnificent tool to troubleshoot performance issues. #+begin_src emacs-lisp @@ -746,7 +767,7 @@ The built-in profiler is a magnificent tool to troubleshoot performance issues. "e" 'profiler-stop "p" 'profiler-report) #+end_src -*** Buffer switching +**** Buffer switching Some keybindings I used in vim to switch buffers and can't let go of. But I think I started to use these less since I made an attempt in [[*i3 integration][i3 integration]]. #+begin_src emacs-lisp @@ -781,7 +802,7 @@ It doesn't play too well with perspective.el, that is it has a single history li "u" 'winner-undo "U" 'winner-redo) #+end_src -*** Buffer management +**** Buffer management #+begin_src emacs-lisp (my-leader-def :infix "b" @@ -797,7 +818,7 @@ It doesn't play too well with perspective.el, that is it has a single history li "r" 'revert-buffer "u" 'ibuffer) #+end_src -*** xref +**** xref Some keybindings for xref and go to definition. #+begin_src emacs-lisp @@ -809,7 +830,7 @@ Some keybindings for xref and go to definition. (my-leader-def "fx" 'xref-find-apropos) #+end_src -*** Folding +**** Folding There are multiple ways to fold text in Emacs. The most versatile is the built-in =hs-minor-mode=, which seems to work out of the box for Lisps, C-like languages and Python. =outline-minor-mode= works for org-mode, LaTeX and the like. There is a 3rd-party solution [[https://github.com/elp-revive/origami.el][origami.el]], but I don't use it at the moment. @@ -821,7 +842,7 @@ Evil does a pretty good job of abstracting the first two with a set of vim-like "ze" 'hs-hide-level "TAB" 'evil-toggle-fold) #+end_src -*** Zoom +**** CHECK Zoom UI #+begin_src emacs-lisp (defun my/zoom-in () "Increase font size by 10 points" @@ -842,6 +863,8 @@ Evil does a pretty good job of abstracting the first two with a set of vim-like (global-set-key (kbd "C-=") 'my/zoom-out) #+end_src ** i3 integration +UPD <2021-11-27 Sat>. I have finally switched to EXWM as my window manager, but as long as I keep i3 as a backup solution, this section persists. Check out the [[https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/][post]] for a somewhat better presentation. + One advantage of EXWM for an Emacs user is that EXWM gives one set of keybindings to manage both Emacs windows and X windows. In every other WM, like my preferred [[https://i3wm.org][i3wm]], two orthogonal keymaps seem to be necessary. But, as both programs are quite customizable, I want to see whether I can replicate at least some part of the EXWM goodness in i3. But why not just use EXWM? One key reason is that to my taste (and perhaps on my hardware) EXWM didn't feel snappy enough. Also, I really like i3's tree-based layout structure; I feel like it fits my workflow much better than anything else I tried, including the master/stack paradigm of [[https://xmonad.org/][XMonad]]​, for instance. @@ -983,26 +1006,10 @@ Finally, the entrypoint for the Emacs integration. In addition to the commands d ("kill" (evil-quit)) (- (i3-msg command)))) #+end_src -** Editing helpers -*** Visual fill column mode -#+begin_src emacs-lisp -(use-package visual-fill-column - :straight t - :config - (add-hook 'visual-fill-column-mode-hook - (lambda () (setq visual-fill-column-center-text t)))) -#+end_src -*** smartparens -A minor mode to deal with pairs. Its functionality overlaps with evil-surround, but smartparens provides the most comfortable way to do stuff like automatically insert pairs. - -References: -- [[https://github.com/Fuco1/smartparens][smartparens repo]] - -#+begin_src emacs-lisp -(use-package smartparens - :straight t) -#+end_src -*** Aggressive Indent +** Editing text +Various packages, tricks ans settings that help with the central task of Emacs - editing text. +*** Indentation & whitespace +**** Aggressive Indent A package to keep the code intended. Doesn't work too well with many ecosystems because the LSP-based indentation is rather slow, but nice for Lisps. @@ -1015,7 +1022,7 @@ References: :commands (aggressive-indent-mode) :straight t) #+end_src -*** Delete trailing whitespace +**** Delete trailing whitespace Delete trailing whitespace on save, unless in particular modes where trailing whitespace is important, like Markdown. #+begin_src emacs-lisp @@ -1028,16 +1035,7 @@ Delete trailing whitespace on save, unless in particular modes where trailing wh (unless (cl-some #'derived-mode-p my/trailing-whitespace-modes) (delete-trailing-whitespace)))) #+end_src -*** Expand region -#+begin_src emacs-lisp -(use-package expand-region - :straight t - :commands (er/expand-region) - :init - (general-nmap "+" 'er/expand-region)) -#+end_src -** Various settings -*** Tabs +**** Tabs Some default settings to manage tabs. #+begin_src emacs-lisp (setq tab-always-indent nil) @@ -1049,7 +1047,8 @@ Some default settings to manage tabs. (setq-default tab-width 4) (setq-default evil-shift-round nil) #+end_src -*** Scrolling config +*** Settings +**** Scrolling #+begin_src emacs-lisp (setq scroll-conservatively scroll-margin) (setq scroll-step 1) @@ -1058,18 +1057,18 @@ Some default settings to manage tabs. (setq mouse-wheel-progressive-speed nil) (setq mouse-wheel-inhibit-click-time nil) #+end_src -*** Clipboard +**** Clipboard #+begin_src emacs-lisp (setq select-enable-clipboard t) (setq mouse-yank-at-point t) #+end_src -*** Backups +**** Backups #+begin_src emacs-lisp (setq backup-inhibited t) (setq auto-save-default nil) #+end_src -** Undo Tree -Replaces Emacs build-in sequential undo system with a tree-based one. Probably one of the greatest features of Emacs as a text editor. +*** Undo Tree +Replaces Emacs build-in sequential undo system with a tree-based one. Probably one of the greatest options of Emacs as a text editor. References: - [[https://www.emacswiki.org/emacs/UndoTree][UndoTree on EmacsWiki]] @@ -1089,6 +1088,358 @@ References: (setq undo-outer-limit 1006632960)) #+end_src +*** Snippets +A snippet system for Emacs and a collection of pre-built snippets. + +~yasnippet-snippets~ has to be loaded before ~yasnippet~ for user snippets to override the pre-built ones. + +References: +- [[http://joaotavora.github.io/yasnippet/][yasnippet documentation]] + +#+begin_src emacs-lisp +(use-package yasnippet-snippets + :straight t) + +(use-package yasnippet + :straight t + :config + (setq yas-snippet-dirs + `(,(concat (expand-file-name user-emacs-directory) "snippets") + yasnippet-snippets-dir)) + (setq yas-triggers-in-field t) + (yas-global-mode 1)) + +(general-imap "M-TAB" 'company-yasnippet) +#+end_src +*** Other small packages +**** Managing parentheses (smartparens) +A minor mode to deal with pairs. Its functionality overlaps with evil-surround, but smartparens provides the most comfortable way to do stuff like automatically insert pairs. + +References: +- [[https://github.com/Fuco1/smartparens][smartparens repo]] + +#+begin_src emacs-lisp +(use-package smartparens + :straight t) +#+end_src +**** Expand region +A package to select an ever-increasing (or ever-decreasing) region of text. + +#+begin_src emacs-lisp +(use-package expand-region + :straight t + :commands (er/expand-region) + :init + (general-nmap "+" 'er/expand-region)) +#+end_src +**** Visual fill column mode +#+begin_src emacs-lisp +(use-package visual-fill-column + :straight t + :config + (add-hook 'visual-fill-column-mode-hook + (lambda () (setq visual-fill-column-center-text t)))) +#+end_src +** Working with projects +*** Treemacs +| Type | Note | +|------+--------------------------------------------------------| +| TODO | Enable modeline only for particular treemacs instances | + +[[https://github.com/Alexander-Miller/treemacs][Treemacs]] calls itself a tree layout file explorer, but looks more like a project and workspace management system. + +Integrates with evil, magit, projectile and perspective. The latter is particularly great - each perspective can have its own treemacs workspace! + +#+begin_src emacs-lisp +(use-package treemacs + :straight t + :commands (treemacs treemacs-switch-workspace treemacs-edit-workspace) + :config + (setq treemacs-follow-mode nil) + (setq treemacs-follow-after-init nil) + (setq treemacs-space-between-root-nodes nil) + (treemacs-git-mode 'extended) + (add-to-list 'treemacs-pre-file-insert-predicates #'treemacs-is-file-git-ignored?) + (general-define-key + :keymaps 'treemacs-mode-map + [mouse-1] #'treemacs-single-click-expand-action + "M-l" #'treemacs-root-down + "M-h" #'treemacs-root-up)) + +(use-package treemacs-evil + :after (treemacs evil) + :straight t) + +(use-package treemacs-magit + :after (treemacs magit) + :straight t) + +(use-package treemacs-perspective + :after (treemacs perspective) + :straight t + :config + (treemacs-set-scope-type 'Perspectives)) + +(general-define-key + :keymaps '(normal override global) + "C-n" 'treemacs) + +(general-define-key + :keymaps '(treemacs-mode-map) [mouse-1] #'treemacs-single-click-expand-action) + +(my-leader-def + :infix "t" + "" '(:which-key "treemacs") + "w" 'treemacs-switch-workspace + "e" 'treemacs-edit-workspaces) +#+end_src +**** Helper functions +Function to open dired and vterm at given nodes. + +#+begin_src emacs-lisp +(defun my/treemacs-open-dired () + "Open dired at given treemacs node" + (interactive) + (let (path (treemacs--prop-at-point :path)) + (dired path))) + +(defun my/treemacs-open-vterm () + "Open vterm at given treemacs node" + (interactive) + (let ((default-directory (file-name-directory (treemacs--prop-at-point :path)))) + (vterm))) + +(with-eval-after-load 'treemacs + (general-define-key + :keymaps 'treemacs-mode-map + :states '(treemacs) + "gd" 'my/treemacs-open-dired + "gt" 'my/treemacs-open-vterm + "`" 'my/treemacs-open-vterm)) +#+end_src +**** Custom icons +#+begin_src emacs-lisp +;; (treemacs-define-custom-icon (concat " " (all-the-icons-fileicon "typescript")) "spec.ts") +;; (setq treemacs-file-extension-regex (rx "." (or "spec.ts" (+ (not "."))) eos)) +#+end_src +*** Projectile +[[https://github.com/bbatsov/projectile][Projectile]] gives a bunch of useful functions for managing projects, like finding files within a project, fuzzy-find, replace, etc. + +~defadvice~ is meant to speed projectile up with TRAMP a bit. +#+begin_src emacs-lisp +(use-package projectile + :straight t + :config + (projectile-mode +1) + (setq projectile-project-search-path '("~/Code" "~/Documents")) + (defadvice projectile-project-root (around ignore-remote first activate) + (unless (file-remote-p default-directory) ad-do-it))) + +(use-package counsel-projectile + :after (counsel projectile) + :straight t) + +(use-package treemacs-projectile + :after (treemacs projectile) + :straight t) + +(my-leader-def + "p" '(:keymap projectile-command-map :which-key "projectile")) + +(general-nmap "C-p" 'counsel-projectile-find-file) +#+end_src +*** Git & Magit +[[https://magit.vc/][Magic]] is a git interface for Emacs. The closest non-Emacs alternative (sans actual clones) I know is [[https://github.com/jesseduffield/lazygit][lazygit]], which I used before Emacs. + +[[https://github.com/emacsorphanage/git-gutter][git-gutter]] is a package which shows git changes for each line (added/changed/deleted lines). + +[[https://github.com/emacsmirror/git-timemachine][git-timemachine]] allows to visit previous versions of a file. + +#+begin_src emacs-lisp +(use-package magit + :straight t + :commands (magit-status magit-file-dispatch) + :config + (setq magit-blame-styles + '((margin + (margin-format . ("%a %A %s")) + (margin-width . 42) + (margin-face . magit-blame-margin) + (margin-body-face . (magit-blame-dimmed))) + (headings + (heading-format . "%-20a %C %s\n")) + (highlight + (highlight-face . magit-blame-highlight)) + (lines + (show-lines . t) + (show-message . t))))) + +(use-package git-gutter + :straight t + :if (not my/slow-ssh) + :config + (global-git-gutter-mode +1)) + +(use-package git-timemachine + :straight t + :commands (git-timemachine)) + +(my-leader-def + "m" 'magit + "M" 'magit-file-dispatch) +#+end_src + +*** Editorconfig +Editorconfig support for Emacs. + +References: +- [[https://editorconfig.org/][Editorconfig reference]] + +#+begin_src emacs-lisp +(use-package editorconfig + :straight t + :config + (unless my/slow-ssh (editorconfig-mode 1)) + (add-to-list 'editorconfig-indentation-alist + '(emmet-mode emmet-indentation))) +#+end_src + +** Completion +*** Ivy, counsel, swiper +Minibuffer completion tools for Emacs. + +References: +- [[https://oremacs.com/swiper/][repo]] +- [[https://oremacs.com/swiper/][User Manual]] + +#+begin_src emacs-lisp +(use-package ivy + :straight t + :config + (setq ivy-use-virtual-buffers t) + (ivy-mode)) + +(use-package counsel + :straight t + :after ivy + :config + (counsel-mode)) + +(use-package swiper + :defer t + :straight t) +#+end_src +*** ivy-rich +[[https://github.com/Yevgnen/ivy-rich][ivy-rich]] provides a more informative interface for ivy. +#+begin_src emacs-lisp +(use-package ivy-rich + :straight t + :after ivy + :config + (ivy-rich-mode 1) + (setcdr (assq t ivy-format-functions-alist) #'ivy-format-function-line)) +#+end_src + +*** prescient +A package that enhances sorting & filtering of candidates. =ivy-prescient= adds integration with Ivy. + +References: +- [[https://github.com/raxod502/prescient.el][prescient.el repo]] +#+begin_src emacs-lisp :noweb yes +(use-package ivy-prescient + :straight t + :after counsel + :config + (ivy-prescient-mode +1) + (setq ivy-prescient-retain-classic-highlighting t) + (prescient-persist-mode 1) + (setq ivy-prescient-sort-commands + '(:not swiper + swiper-isearch + ivy-switch-buffer + ;; ivy-resume + ;; ivy--restore-session + lsp-ivy-workspace-symbol + dap-switch-stack-frame + my/dap-switch-stack-frame + dap-switch-session + dap-switch-thread + counsel-grep + ;; counsel-find-file + counsel-git-grep + counsel-rg + counsel-ag + counsel-ack + counsel-fzf + counsel-pt + counsel-imenu + counsel-yank-pop + counsel-recentf + counsel-buffer-or-recentf + proced-filter-interactive + proced-sort-interactive)) + ;; Do not use prescient in find-file + (ivy--alist-set 'ivy-sort-functions-alist #'read-file-name-internal #'ivy-sort-file-function-default)) +#+end_src +*** keybindings +Setting up quick access to various completions. + +#+begin_src emacs-lisp +(my-leader-def + :infix "f" + "" '(:which-key "various completions")' + ;; "b" 'counsel-switch-buffer + "b" 'persp-ivy-switch-buffer + "e" 'conda-env-activate + "f" 'project-find-file + "c" 'counsel-yank-pop + "a" 'counsel-rg + "A" 'counsel-ag) + +(general-define-key + :states '(insert normal) + "C-y" 'counsel-yank-pop) + +(my-leader-def "SPC" 'ivy-resume) +(my-leader-def "s" 'swiper-isearch + "S" 'swiper-all) + +(general-define-key + :keymaps '(ivy-minibuffer-map swiper-map) + "M-j" 'ivy-next-line + "M-k" 'ivy-previous-line + "" 'ivy-call + "M-RET" 'ivy-immediate-done + [escape] 'minibuffer-keyboard-quit) +#+end_src +*** company +A completion framework for Emacs. + +References: +- [[http://company-mode.github.io/][company homepage]] +- [[https://github.com/sebastiencs/company-box][company-box homepage]] + +#+begin_src emacs-lisp +(use-package company + :straight t + :config + (global-company-mode) + (setq company-idle-delay (if my/lowpower 0.5 0.125)) + (setq company-dabbrev-downcase nil) + (setq company-show-numbers t)) + +(general-imap "C-SPC" 'company-complete) +#+end_src + +A company frontend with nice icons. Disabled since the base company got icons support and since company-box has some issues with spaceline. +#+begin_src emacs-lisp +(use-package company-box + :straight t + :disabled + :if (and (display-graphic-p) (not my/lowpower)) + :after (company) + :hook (company-mode . company-box-mode)) +#+end_src ** Help [[https://github.com/Wilfred/helpful][helpful]] package improves the =*help*= buffer. #+begin_src emacs-lisp @@ -1142,327 +1493,6 @@ As I use =C-h= to switch buffers, I moved the help to =SPC-h= with the code belo "" 'help-for-help) #+end_src -** Ivy, counsel, swiper -Minibuffer completion tools for Emacs. - -References: -- [[https://oremacs.com/swiper/][repo]] -- [[https://oremacs.com/swiper/][User Manual]] - -#+begin_src emacs-lisp -(use-package ivy - :straight t - :config - (setq ivy-use-virtual-buffers t) - (ivy-mode)) - -(use-package counsel - :straight t - :after ivy - :config - (counsel-mode)) - -(use-package swiper - :defer t - :straight t) -#+end_src - -*** ivy-rich -[[https://github.com/Yevgnen/ivy-rich][ivy-rich]] provides a more informative interface for ivy. -#+begin_src emacs-lisp -(use-package ivy-rich - :straight t - :after ivy - :config - (ivy-rich-mode 1) - (setcdr (assq t ivy-format-functions-alist) #'ivy-format-function-line)) -#+end_src - -*** prescient -A package that enhances sorting & filtering of candidates. =ivy-prescient= adds integration with Ivy. - -References: -- [[https://github.com/raxod502/prescient.el][prescient.el repo]] -#+begin_src emacs-lisp :noweb yes -(use-package ivy-prescient - :straight t - :after counsel - :config - (ivy-prescient-mode +1) - (setq ivy-prescient-retain-classic-highlighting t) - (prescient-persist-mode 1) - (setq ivy-prescient-sort-commands - '(:not swiper - swiper-isearch - ivy-switch-buffer - ;; ivy-resume - ;; ivy--restore-session - lsp-ivy-workspace-symbol - dap-switch-stack-frame - my/dap-switch-stack-frame - dap-switch-session - dap-switch-thread - counsel-grep - ;; counsel-find-file - counsel-git-grep - counsel-rg - counsel-ag - counsel-ack - counsel-fzf - counsel-pt - counsel-imenu - counsel-yank-pop - counsel-recentf - counsel-buffer-or-recentf - proced-filter-interactive - proced-sort-interactive)) - ;; Do not use prescient in find-file - (ivy--alist-set 'ivy-sort-functions-alist #'read-file-name-internal #'ivy-sort-file-function-default)) -#+end_src -*** Keybindings -#+begin_src emacs-lisp -(my-leader-def - :infix "f" - "" '(:which-key "various completions")' - ;; "b" 'counsel-switch-buffer - "b" 'persp-ivy-switch-buffer - "e" 'conda-env-activate - "f" 'project-find-file - "c" 'counsel-yank-pop - "a" 'counsel-rg - "A" 'counsel-ag) - -(general-define-key - :states '(insert normal) - "C-y" 'counsel-yank-pop) - -(my-leader-def "SPC" 'ivy-resume) -(my-leader-def "s" 'swiper-isearch - "S" 'swiper-all) - -(general-define-key - :keymaps '(ivy-minibuffer-map swiper-map) - "M-j" 'ivy-next-line - "M-k" 'ivy-previous-line - "" 'ivy-call - "M-RET" 'ivy-immediate-done - [escape] 'minibuffer-keyboard-quit) -#+end_src -** Treemacs -| Type | Note | -|------+--------------------------------------------------------| -| TODO | Enable modeline only for particular treemacs instances | - -[[https://github.com/Alexander-Miller/treemacs][Treemacs]] calls itself a tree layout file explorer, but looks more like a project and workspace management system. - -Integrates with evil, magit, projectile and perspective. The latter is particularly great - each perspective can have its own treemacs workspace! - -#+begin_src emacs-lisp -(use-package treemacs - :straight t - :commands (treemacs treemacs-switch-workspace treemacs-edit-workspace) - :config - (setq treemacs-follow-mode nil) - (setq treemacs-follow-after-init nil) - (setq treemacs-space-between-root-nodes nil) - (treemacs-git-mode 'extended) - (add-to-list 'treemacs-pre-file-insert-predicates #'treemacs-is-file-git-ignored?) - (general-define-key - :keymaps 'treemacs-mode-map - [mouse-1] #'treemacs-single-click-expand-action - "M-l" #'treemacs-root-down - "M-h" #'treemacs-root-up)) - -(use-package treemacs-evil - :after (treemacs evil) - :straight t) - -(use-package treemacs-magit - :after (treemacs magit) - :straight t) - -(use-package treemacs-perspective - :after (treemacs perspective) - :straight t - :config - (treemacs-set-scope-type 'Perspectives)) - -(general-define-key - :keymaps '(normal override global) - "C-n" 'treemacs) - -(general-define-key - :keymaps '(treemacs-mode-map) [mouse-1] #'treemacs-single-click-expand-action) - -(my-leader-def - :infix "t" - "" '(:which-key "treemacs") - "w" 'treemacs-switch-workspace - "e" 'treemacs-edit-workspaces) -#+end_src -*** Helper functions -Function to open dired and vterm at given nodes. - -#+begin_src emacs-lisp -(defun my/treemacs-open-dired () - "Open dired at given treemacs node" - (interactive) - (let (path (treemacs--prop-at-point :path)) - (dired path))) - -(defun my/treemacs-open-vterm () - "Open vterm at given treemacs node" - (interactive) - (let ((default-directory (file-name-directory (treemacs--prop-at-point :path)))) - (vterm))) - -(with-eval-after-load 'treemacs - (general-define-key - :keymaps 'treemacs-mode-map - :states '(treemacs) - "gd" 'my/treemacs-open-dired - "gt" 'my/treemacs-open-vterm - "`" 'my/treemacs-open-vterm)) -#+end_src -*** Custom icons -#+begin_src emacs-lisp -;; (treemacs-define-custom-icon (concat " " (all-the-icons-fileicon "typescript")) "spec.ts") -;; (setq treemacs-file-extension-regex (rx "." (or "spec.ts" (+ (not "."))) eos)) -#+end_src -** Projectile -[[https://github.com/bbatsov/projectile][Projectile]] gives a bunch of useful functions for managing projects, like finding files within a project, fuzzy-find, replace, etc. - -~defadvice~ is meant to speed projectile up with TRAMP a bit. -#+begin_src emacs-lisp -(use-package projectile - :straight t - :config - (projectile-mode +1) - (setq projectile-project-search-path '("~/Code" "~/Documents")) - (defadvice projectile-project-root (around ignore-remote first activate) - (unless (file-remote-p default-directory) ad-do-it))) - -(use-package counsel-projectile - :after (counsel projectile) - :straight t) - -(use-package treemacs-projectile - :after (treemacs projectile) - :straight t) - -(my-leader-def - "p" '(:keymap projectile-command-map :which-key "projectile")) - -(general-nmap "C-p" 'counsel-projectile-find-file) -#+end_src -** Company -A completion framework for Emacs. - -References: -- [[http://company-mode.github.io/][company homepage]] -- [[https://github.com/sebastiencs/company-box][company-box homepage]] - -#+begin_src emacs-lisp -(use-package company - :straight t - :config - (global-company-mode) - (setq company-idle-delay (if my/lowpower 0.5 0.125)) - (setq company-dabbrev-downcase nil) - (setq company-show-numbers t)) - -(general-imap "C-SPC" 'company-complete) -#+end_src - -A company frontend with nice icons. Disabled since the base company got icons support and since company-box has some issues with spaceline. -#+begin_src emacs-lisp -(use-package company-box - :straight t - :disabled - :if (and (display-graphic-p) (not my/lowpower)) - :after (company) - :hook (company-mode . company-box-mode)) -#+end_src - -** Git & Magit -[[https://magit.vc/][Magic]] is a git interface for Emacs. The closest non-Emacs alternative (sans actual clones) I know is [[https://github.com/jesseduffield/lazygit][lazygit]], which I used before Emacs. - -[[https://github.com/emacsorphanage/git-gutter][git-gutter]] is a package which shows git changes for each line (added/changed/deleted lines). - -[[https://github.com/emacsmirror/git-timemachine][git-timemachine]] allows to visit previous versions of a file. - -#+begin_src emacs-lisp -(use-package magit - :straight t - :commands (magit-status magit-file-dispatch) - :config - (setq magit-blame-styles - '((margin - (margin-format . ("%a %A %s")) - (margin-width . 42) - (margin-face . magit-blame-margin) - (margin-body-face . (magit-blame-dimmed))) - (headings - (heading-format . "%-20a %C %s\n")) - (highlight - (highlight-face . magit-blame-highlight)) - (lines - (show-lines . t) - (show-message . t))))) - -(use-package git-gutter - :straight t - :if (not my/slow-ssh) - :config - (global-git-gutter-mode +1)) - -(use-package git-timemachine - :straight t - :commands (git-timemachine)) - -(my-leader-def - "m" 'magit - "M" 'magit-file-dispatch) -#+end_src - -** Editorconfig -Editorconfig support for Emacs. - -References: -- [[https://editorconfig.org/][Editorconfig reference]] - -#+begin_src emacs-lisp -(use-package editorconfig - :straight t - :config - (unless my/slow-ssh (editorconfig-mode 1)) - (add-to-list 'editorconfig-indentation-alist - '(emmet-mode emmet-indentation))) -#+end_src - -** Snippets -A snippet system for Emacs and a collection of pre-built snippets. - -~yasnippet-snippets~ has to be loaded before ~yasnippet~ for user snippets to override the pre-built ones. - -References: -- [[http://joaotavora.github.io/yasnippet/][yasnippet documentation]] - -#+begin_src emacs-lisp -(use-package yasnippet-snippets - :straight t) - -(use-package yasnippet - :straight t - :config - (setq yas-snippet-dirs - `(,(concat (expand-file-name user-emacs-directory) "snippets") - yasnippet-snippets-dir)) - (setq yas-triggers-in-field t) - (yas-global-mode 1)) - -(general-imap "M-TAB" 'company-yasnippet) -#+end_src ** Time trackers A bunch of time trackers I use. @@ -1498,8 +1528,9 @@ Before I figure out how to package this for Guix: :config (global-activity-watch-mode)) #+end_src -* UI -** General UI & GUI Settings +* UI settings +** General settings +*** Miscellaneous Disable GUI elements #+begin_src emacs-lisp (unless my/is-termux @@ -1539,6 +1570,16 @@ Hide mouse cursor while typing (setq make-pointer-invisible t) #+end_src +Show pairs +#+begin_src emacs-lisp +(show-paren-mode 1) +#+end_src + +Highlight the current line +#+begin_src emacs-lisp +(global-hl-line-mode 1) +#+end_src +*** Line numbers Line numbers. There seems to be a catch with the relative number setting: - =visual= doesn't take folding into account but also doesn't take wrapped lines into account (makes multiple numbers for a single wrapped line) - =relative= makes a single number for a wrapped line, but counts folded lines. @@ -1550,12 +1591,7 @@ Line numbers. There seems to be a catch with the relative number setting: (setq display-line-numbers-type 'visual) (column-number-mode) #+end_src - -Show pairs -#+begin_src emacs-lisp -(show-paren-mode 1) -#+end_src - +*** Word wrapping Word wrapping. These settings aren't too obvious compared to =:set wrap= from vim: - =word-wrap= means just "don't split one word between two lines". So, if there isn't enough place to put a word at the end of the line, it will be put on a new one. Run =M-x toggle-word-wrap= to toggle that. - =visual-line-mode= seems to be a superset of =word-wrap=. It also enables some editing commands to work on visual lines instead of logical ones, hence the naming. @@ -1565,12 +1601,20 @@ Word wrapping. These settings aren't too obvious compared to =:set wrap= from vi (setq word-wrap 1) (global-visual-line-mode 1) #+end_src - -Highlight current line +*** Custom frame format +Title format, which looks something like =emacs:project@hostname=. #+begin_src emacs-lisp -(global-hl-line-mode 1) +(setq-default frame-title-format + '("" + "emacs" + (:eval + (let ((project-name (projectile-project-name))) + (if (not (string= "-" project-name)) + (format ":%s@%s" project-name (system-name)) + (format "@%s" (system-name))))))) #+end_src -** Theme & global stuff +** Themes and colors +*** Dim inactive buffers Dim inactive buffers. #+begin_src emacs-lisp (use-package auto-dim-other-buffers @@ -1579,7 +1623,7 @@ Dim inactive buffers. :config (auto-dim-other-buffers-mode t)) #+end_src - +*** Doom themes My colorscheme of choice. #+begin_src emacs-lisp (use-package doom-themes @@ -1648,7 +1692,8 @@ Also, a hook allows me to change doom-theme more or less at will, although I do (my/update-my-theme))) #+end_src -*** Font +** Fonts +*** Frame font To install a font, download the font and unpack it into the =.local/share/fonts= directory. Create one if it doesn't exist. As I use nerd fonts elsewhere, I use one in Emacs as well. @@ -1661,18 +1706,108 @@ References: #+end_src To make the icons work (e.g. in the Doom Modeline), run =M-x all-the-icons-install-fonts=. The package definition is somewhere later in the config. -** Custom frame title -Title format, which looks something like =emacs:project@hostname=. +*** Ligatures +Ligature setup for the JetBrainsMono font. +#+begin_src emacs-lisp +(use-package ligature + :straight (:host github :repo "mickeynp/ligature.el") + :if (display-graphic-p) + :config + (ligature-set-ligatures + '( + typescript-mode + js2-mode + vue-mode + svelte-mode + scss-mode + php-mode + python-mode + js-mode + markdown-mode + clojure-mode + go-mode + sh-mode + haskell-mode + web-mode) + '("--" "---" "==" "===" "!=" "!==" "=!=" "=:=" "=/=" "<=" + ">=" "&&" "&&&" "&=" "++" "+++" "***" ";;" "!!" "??" + "?:" "?." "?=" "<:" ":<" ":>" ">:" "<>" "<<<" ">>>" + "<<" ">>" "||" "-|" "_|_" "|-" "||-" "|=" "||=" "##" + "###" "####" "#{" "#[" "]#" "#(" "#?" "#_" "#_(" "#:" + "#!" "#=" "^=" "<$>" "<$" "$>" "<+>" "<+" "+>" "<*>" + "<*" "*>" "" "/>" "" "->" "->>" + "<<-" "<-" "<=<" "=<<" "<<=" "<==" "<=>" "<==>" "==>" "=>" + "=>>" ">=>" ">>=" ">>-" ">-" ">--" "-<" "-<<" ">->" "<-<" + "<-|" "<=|" "|=>" "|->" "<->" "<~~" "<~" "<~>" "~~" "~~>" + "~>" "~-" "-~" "~@" "[||]" "|]" "[|" "|}" "{|" "[<" + ">]" "|>" "<|" "||>" "<||" "|||>" "<|||" "<|>" "..." ".." + ".=" ".-" "..<" ".?" "::" ":::" ":=" "::=" ":?" ":?>" + "//" "///" "/*" "*/" "/=" "//=" "/==" "@_" "__")) + (global-ligature-mode t)) +#+end_src +*** Icons +#+begin_src emacs-lisp +(use-package all-the-icons + :if (display-graphic-p) + :straight t) +#+end_src +** Text highlight +Highlight indent guides. +#+begin_src emacs-lisp +(use-package highlight-indent-guides + :straight t + :if (not (or my/lowpower my/remote-server)) + :hook ( + (prog-mode . highlight-indent-guides-mode) + (vue-mode . highlight-indent-guides-mode) + (LaTeX-mode . highlight-indent-guides-mode)) + :config + (setq highlight-indent-guides-method 'bitmap) + (setq highlight-indent-guides-bitmap-function 'highlight-indent-guides--bitmap-line)) +#+end_src + +Rainbow parentheses. +#+begin_src emacs-lisp +(use-package rainbow-delimiters + :straight t + :if (not my/lowpower) + :hook ((prog-mode . rainbow-delimiters-mode))) +#+end_src + +Highlight colors +#+begin_src emacs-lisp +(use-package rainbow-mode + :commands (rainbow-mode) + :straight t) +#+end_src + +Highlight TODOs and stuff +#+begin_src emacs-lisp +(use-package hl-todo + :hook (prog-mode . hl-todo-mode) + :straight t) +#+end_src +** Doom Modeline +A modeline from Doom Emacs. + +A big advantage of this package is that it just works out of the box and does not require much customization. For now I opted out of it in favour of spaceline because I want to have a more powerline-ish look. + +References: +- [[https://github.com/seagle0128/doom-modeline][Doom Modeline]] #+begin_src emacs-lisp -(setq-default frame-title-format - '("" - "emacs" - (:eval - (let ((project-name (projectile-project-name))) - (if (not (string= "-" project-name)) - (format ":%s@%s" project-name (system-name)) - (format "@%s" (system-name))))))) +(use-package doom-modeline + :straight t + ;; :if (not (display-graphic-p)) + :init + (setq doom-modeline-env-enable-python nil) + (setq doom-modeline-env-enable-go nil) + (setq doom-modeline-buffer-encoding 'nondefault) + (setq doom-modeline-hud t) + :config + (doom-modeline-mode 1) + (setq doom-modeline-minor-modes nil) + (setq doom-modeline-buffer-state-icon nil)) #+end_src ** perspective.el [[https://github.com/nex3/perspective-el][perspective.el]] is a package which provides gives Emacs capacities to group buffers into "perspectives", which are like workspaces in tiling WMs. @@ -1732,686 +1867,1490 @@ Add keybindings to the default map. "m" #'my/persp-move-window-and-switch "f" #'my/persp-copy-window-and-switch)) #+end_src -** OFF (OFF) Tab bar -+I rely rather heavily on tab-bar in my workflow. I have a suspicion I'm not using it the intended way, but that works for me.+ - -For now switched to perspective.el, so the following block is not tangled. -*** Setup -#+begin_src emacs-lisp :tangle no -(general-define-key - :keymaps 'override - :states '(normal emacs) - "gt" 'tab-bar-switch-to-next-tab - "gT" 'tab-bar-switch-to-prev-tab - "gn" 'tab-bar-new-tab) - -(setq tab-bar-show 1) -(setq tab-bar-tab-hints t) -(setq tab-bar-tab-name-function 'tab-bar-tab-name-current-with-count) - -;; Tabs -(general-nmap "gn" 'tab-new) -(general-nmap "gN" 'tab-close) -#+end_src -*** My title -Prepend tab name with the shortened projectile project title - -#+begin_src emacs-lisp -(setq my/project-title-separators "[-_ ]") - -(setq my/project-names-override-alist - '((".password-store" . "pass"))) - -(defun my/shorten-project-name-elem (elem crop) - (if (string-match "^\\[.*\\]$" elem) - (concat "[" - (my/shorten-project-name-elem (substring elem 1 (- (length elem) 1)) crop) - "]") - (let* ((prefix (car (s-match my/project-title-separators elem))) - (rest - (substring - (if prefix - (substring elem (length prefix)) - elem) - 0 (if crop 1 nil)))) - (concat prefix rest)))) - -(defun my/shorten-project-name (project-name) - (or - (cdr (assoc project-name my/project-names-override-alist)) - (let ((elems (s-slice-at my/project-title-separators project-name))) - (concat - (apply - #'concat - (cl-mapcar (lambda (elem) (my/shorten-project-name-elem elem t)) (butlast elems))) - (my/shorten-project-name-elem (car (last elems)) nil))))) - -(defun my/tab-bar-name-function () - (let ((project-name (projectile-project-name))) - (if (string= "-" project-name) - (tab-bar-tab-name-current-with-count) - (concat "[" (my/shorten-project-name project-name) "] " - (replace-regexp-in-string "<.*>" "" (tab-bar-tab-name-current-with-count)))))) - -(setq tab-bar-tab-name-function #'my/tab-bar-name-function) -#+end_src -** Doom Modeline -A modeline from Doom Emacs. - -A big advantage of this package is that it just works out of the box and does not require much customization. For now I opted out of it in favour of spaceline because I want to have a more powerline-ish look. +* Programming +** General setup +*** LSP +LSP-mode provides an IDE-like experience for Emacs - real-time diagnostic, code actions, intelligent autocompletion, etc. References: -- [[https://github.com/seagle0128/doom-modeline][Doom Modeline]] - +- [[https://emacs-lsp.github.io/lsp-mode/][lsp-mode homepage]] +**** Setup #+begin_src emacs-lisp -(use-package doom-modeline +(use-package lsp-mode :straight t - ;; :if (not (display-graphic-p)) - :init - (setq doom-modeline-env-enable-python nil) - (setq doom-modeline-env-enable-go nil) - (setq doom-modeline-buffer-encoding 'nondefault) - (setq doom-modeline-hud t) - :config - (doom-modeline-mode 1) - (setq doom-modeline-minor-modes nil) - (setq doom-modeline-buffer-state-icon nil)) -#+end_src -** OFF (OFF) Spaceline -A modeline from Spacemacs. It provides a different look than Doom modeline, but also needs to be tuned more. - -#+begin_src emacs-lisp :noweb yes -(use-package spaceline - :straight t - :disabled - :config - <>) -#+end_src -*** Perspectives -Definining a bunch of custom powerline segments. First, a list of perspectives. - -#+begin_src emacs-lisp :noweb-ref spaceline-conf :tangle no -(defun my/format-perspective-list () - (format "[%s]" - (let ((curr (persp-current-name))) - (mapconcat - (lambda (name) - (if (string-equal name curr) - (propertize - name - 'face - 'persp-selected-face) - name)) - (persp-names) - "|")))) - -(defvar my/spaceline-persp-list "") - -(defun my/persp-update-advice (&rest _) - (setq my/spaceline-persp-list (my/format-perspective-list))) - -(advice-add #'persp-update-modestring :after #'my/persp-update-advice) -(add-hook 'buffer-list-update-hook #'my/persp-update-advice) -(add-hook 'find-file-hook #'my/persp-update-advice) - -(spaceline-define-segment perspective - "Perspective.el" - my/spaceline-persp-list) -#+end_src -*** EXWM workspace -Current EXWM workspace. The variable is being set in the EXWM config, the segment just displays it. - -#+begin_src emacs-lisp :noweb-ref spaceline-conf :tangle no -(defvar my/exwm-mode-line-info-no-props "") - -(spaceline-define-segment exwm - my/exwm-mode-line-info-no-props) -#+end_src -*** Debug -Indicators for =debug-on-error= and =debug-on-quit=. - -#+begin_src emacs-lisp :noweb-ref spaceline-conf :tangle no -(spaceline-define-segment debug-on-error - (when debug-on-error - (propertize - "" - 'face 'warning - 'local-map (let ((map (make-sparse-keymap))) - (define-key map - [mode-line mouse-1] - #'toggle-debug-on-error) - map)))) - -(spaceline-define-segment debug-on-quit - (when debug-on-quit - (propertize - "" - 'face 'error - 'local-map (let ((map (make-sparse-keymap))) - (define-key map - [mode-line mouse-1] - #'toggle-debug-on-quit) - map)))) -#+end_src -*** My theme -And a custom spaceline config with segments I like. - -#+begin_src emacs-lisp :noweb-ref spaceline-conf :tangle no -(require 'spaceline-config) - -(spaceline-compile - "my" - '((evil-state :priority 100 :face (spaceline-highlight-face-evil-state)) - (buffer-modified :priority 50) - (version-control :priority 25 :when active) - (buffer-id :priority 90)) - '(;; (global) - (exwm :when active) - (perspective :when active) - (flycheck-error :when active) - (flycheck-warning :when active) - (debug-on-error :when active) - (debug-on-quit :when active) - (major-mode :when active :priority 90) - (selection-info :priority 95) - (line-column :when active :priority 99) - (hud :when active :priority 99))) - -(spaceline-ml-my) - -(setq-default mode-line-format '("%e" (:eval (spaceline-ml-my)))) -(setq mode-line-format '("%e" (:eval (spaceline-ml-my)))) -#+end_src -** Font stuff -*** Ligatures -Ligature setup for the JetBrainsMono font. -#+begin_src emacs-lisp -(use-package ligature - :straight (:host github :repo "mickeynp/ligature.el") - :if (display-graphic-p) - :config - (ligature-set-ligatures - '( - typescript-mode - js2-mode - vue-mode - svelte-mode - scss-mode - php-mode - python-mode - js-mode - markdown-mode - clojure-mode - go-mode - sh-mode - haskell-mode - web-mode) - '("--" "---" "==" "===" "!=" "!==" "=!=" "=:=" "=/=" "<=" - ">=" "&&" "&&&" "&=" "++" "+++" "***" ";;" "!!" "??" - "?:" "?." "?=" "<:" ":<" ":>" ">:" "<>" "<<<" ">>>" - "<<" ">>" "||" "-|" "_|_" "|-" "||-" "|=" "||=" "##" - "###" "####" "#{" "#[" "]#" "#(" "#?" "#_" "#_(" "#:" - "#!" "#=" "^=" "<$>" "<$" "$>" "<+>" "<+" "+>" "<*>" - "<*" "*>" "" "/>" "" "->" "->>" - "<<-" "<-" "<=<" "=<<" "<<=" "<==" "<=>" "<==>" "==>" "=>" - "=>>" ">=>" ">>=" ">>-" ">-" ">--" "-<" "-<<" ">->" "<-<" - "<-|" "<=|" "|=>" "|->" "<->" "<~~" "<~" "<~>" "~~" "~~>" - "~>" "~-" "-~" "~@" "[||]" "|]" "[|" "|}" "{|" "[<" - ">]" "|>" "<|" "||>" "<||" "|||>" "<|||" "<|>" "..." ".." - ".=" ".-" "..<" ".?" "::" ":::" ":=" "::=" ":?" ":?>" - "//" "///" "/*" "*/" "/=" "//=" "/==" "@_" "__")) - (global-ligature-mode t)) -#+end_src -*** Icons -#+begin_src emacs-lisp -(use-package all-the-icons - :if (display-graphic-p) - :straight t) -#+end_src -*** Highlight todo -#+begin_src emacs-lisp -(use-package hl-todo - :hook (prog-mode . hl-todo-mode) - :straight t) -#+end_src -** Text highlight improvements -Highlight indent guides. -#+begin_src emacs-lisp -(use-package highlight-indent-guides - :straight t - :if (not (or my/lowpower my/remote-server)) + :if (not (or my/slow-ssh my/is-termux my/remote-server)) :hook ( - (prog-mode . highlight-indent-guides-mode) - (vue-mode . highlight-indent-guides-mode) - (LaTeX-mode . highlight-indent-guides-mode)) + (typescript-mode . lsp) + (js-mode . lsp) + (vue-mode . lsp) + (go-mode . lsp) + (svelte-mode . lsp) + ;; (python-mode . lsp) + (json-mode . lsp) + (haskell-mode . lsp) + (haskell-literate-mode . lsp) + (java-mode . lsp) + ;; (csharp-mode . lsp) + ) + :commands lsp + :init + (setq lsp-keymap-prefix nil) :config - (setq highlight-indent-guides-method 'bitmap) - (setq highlight-indent-guides-bitmap-function 'highlight-indent-guides--bitmap-line)) + (setq lsp-idle-delay 1) + (setq lsp-eslint-server-command '("node" "/home/pavel/.emacs.d/.cache/lsp/eslint/unzipped/extension/server/out/eslintServer.js" "--stdio")) + (setq lsp-eslint-run "onSave") + (setq lsp-signature-render-documentation nil) + ;; (lsp-headerline-breadcrumb-mode nil) + (setq lsp-headerline-breadcrumb-enable nil) + (add-to-list 'lsp-language-id-configuration '(svelte-mode . "svelte"))) + +(use-package lsp-ui + :straight t + :commands lsp-ui-mode + :config + (setq lsp-ui-doc-delay 2) + (setq lsp-ui-sideline-show-hover nil)) +#+end_src +**** Integrations +The only integration left now is treemacs. + +Origami should've leveraged LSP folding, but it was too unstable at the moment I tried it. +#+begin_src emacs-lisp +;; (use-package helm-lsp +;; :straight t +;; :commands helm-lsp-workspace-symbol) + +;; (use-package origami +;; :straight t +;; :hook (prog-mode . origami-mode)) + +;; (use-package lsp-origami +;; :straight t +;; :config +;; (add-hook 'lsp-after-open-hook #'lsp-origami-try-enable)) + +(use-package lsp-treemacs + :after (lsp) + :straight t + :commands lsp-treemacs-errors-list) +#+end_src +**** Keybindings +#+begin_src emacs-lisp +(my-leader-def + :infix "l" + "" '(:which-key "lsp") + "d" 'lsp-ui-peek-find-definitions + "r" 'lsp-rename + "u" 'lsp-ui-peek-find-references + "s" 'lsp-ui-find-workspace-symbol + "l" 'lsp-execute-code-action + "e" 'list-flycheck-errors) +#+end_src +*** Flycheck +A syntax checking extension for Emacs. Integrates with LSP-mode, but can also use various standalone checkers. + +References: +- [[https://www.flycheck.org/en/latest/][Flycheck homepage]] + +#+begin_src emacs-lisp +(use-package flycheck + :straight t + :config + (global-flycheck-mode) + (setq flycheck-check-syntax-automatically '(save idle-buffer-switch mode-enabled)) + ;; (add-hook 'evil-insert-state-exit-hook + ;; (lambda () + ;; (if flycheck-checker + ;; (flycheck-buffer)) + ;; )) + (advice-add 'flycheck-eslint-config-exists-p :override (lambda() t)) + (add-to-list 'display-buffer-alist + `(,(rx bos "*Flycheck errors*" eos) + (display-buffer-reuse-window + display-buffer-in-side-window) + (side . bottom) + (reusable-frames . visible) + (window-height . 0.33)))) +#+end_src +*** Tree Sitter +An incremental code parsing system, constructing a syntax tree at runtime. + +Right now it doesn't do much except provide a better syntax highlighting than regexes, but this integration is a rather recent development. There are already some major modes built on top of this thing. + +Also, it seems to break if ran from mmm-mode, so there is a small workaround. + +References: +- [[https://tree-sitter.github.io/tree-sitter/][Tree-sitter library]] +- [[https://ubolonton.github.io/emacs-tree-sitter/][Emacs Tree-sitter]] + +#+begin_src emacs-lisp +(defun my/tree-sitter-if-not-mmm () + (when (not (and (boundp 'mmm-temp-buffer-name) + (string-equal mmm-temp-buffer-name (buffer-name)))) + (tree-sitter-mode) + (tree-sitter-hl-mode))) + +(use-package tree-sitter + :straight t + :if (not my/remote-server) + :hook ((typescript-mode . my/tree-sitter-if-not-mmm) + (js-mode . my/tree-sitter-if-not-mmm) + (python-mode . tree-sitter-mode) + (python-mode . tree-sitter-hl-mode) + (csharp-mode . tree-sitter-mode))) + +(use-package tree-sitter-langs + :straight t + :after tree-sitter) +#+end_src +*** DAP +An Emacs client for Debugger Adapter Protocol. + +As of time of this writing, I mostly debug TypeScript, so the main competitor is Chrome Inspector for node.js. + +References: +- [[https://emacs-lsp.github.io/dap-mode/][dap-mode homepage]] +#+begin_src emacs-lisp +(use-package dap-mode + :straight t + :commands (dap-debug) + :init + (setq lsp-enable-dap-auto-configure nil) + :config + + (setq dap-ui-variable-length 100) + (setq dap-auto-show-output nil) + (require 'dap-node) + (dap-node-setup) + + (require 'dap-chrome) + (dap-chrome-setup) + + (require 'dap-python) + + (dap-mode 1) + (dap-ui-mode 1) + (dap-tooltip-mode 1) + (tooltip-mode 1)) #+end_src -Rainbow parentheses. +**** Controls +I don't like some keybindings in the built-in hydra, and there seems to be no easy way to modify the existing hydra, so I create my own. I tried to use transient, but the transient buffer seems to conflict with special buffers of DAP, and hydra does not. + +Also, I want the hydra to toggle UI windows instead of just opening them, so here is macro that defines such functions: #+begin_src emacs-lisp -(use-package rainbow-delimiters +(with-eval-after-load 'dap-mode + (defmacro my/define-dap-ui-window-toggler (name) + `(defun ,(intern (concat "my/dap-ui-toggle-" name)) () + ,(concat "Toggle DAP " name "buffer") + (interactive) + (if-let (window (get-buffer-window ,(intern (concat "dap-ui--" name "-buffer")))) + (quit-window nil window) + (,(intern (concat "dap-ui-" name)))))) + + (my/define-dap-ui-window-toggler "locals") + (my/define-dap-ui-window-toggler "expressions") + (my/define-dap-ui-window-toggler "sessions") + (my/define-dap-ui-window-toggler "breakpoints") + (my/define-dap-ui-window-toggler "repl")) +#+end_src + +And here is the hydra: +#+begin_src emacs-lisp +(defhydra my/dap-hydra (:color pink :hint nil :foreign-keys run) + " +^Stepping^ ^UI^ ^Switch^ ^Breakpoints^ ^Debug^ ^Expressions +^^^^^^^^------------------------------------------------------------------------------------------------------------------------------------------ +_n_: Next _uc_: Controls _ss_: Session _bb_: Toggle _dd_: Debug _ee_: Eval +_i_: Step in _ue_: Expressions _st_: Thread _bd_: Delete _dr_: Debug recent _er_: Eval region +_o_: Step out _ul_: Locals _sf_: Stack frame _ba_: Add _dl_: Debug last _es_: Eval thing at point +_c_: Continue _ur_: REPL _su_: Up stack frame _bc_: Set condition _de_: Edit debug template _ea_: Add expression +_r_: Restart frame _uo_: Output _sd_: Down stack frame _bh_: Set hit count _Q_: Disconnect _ed_: Remove expression + _us_: Sessions _sF_: Stack frame filtered _bl_: Set log message _eu_: Refresh expressions + _ub_: Breakpoints " + + ("n" dap-next) + ("i" dap-step-in) + ("o" dap-step-out) + ("c" dap-continue) + ("r" dap-restart-frame) + ("uc" dap-ui-controls-mode) + ("ue" my/dap-ui-toggle-expressions) + ("ul" my/dap-ui-toggle-locals) + ("ur" my/dap-ui-toggle-repl) + ("uo" dap-ui-go-to-output-buffer) + ("us" my/dap-ui-toggle-sessions) + ("ub" my/dap-ui-toggle-breakpoints) + ("ss" dap-switch-session) + ("st" dap-switch-thread) + ("sf" dap-switch-stack-frame) + ("sF" my/dap-switch-stack-frame) + ("su" dap-up-stack-frame) + ("sd" dap-down-stack-frame) + ("bb" dap-breakpoint-toggle) + ("ba" dap-breakpoint-add) + ("bd" dap-breakpoint-delete) + ("bc" dap-breakpoint-condition) + ("bh" dap-breakpoint-hit-condition) + ("bl" dap-breakpoint-log-message) + ("dd" dap-debug) + ("dr" dap-debug-recent) + ("dl" dap-debug-last) + ("de" dap-debug-edit-template) + ("ee" dap-eval) + ("ea" dap-ui-expressions-add) + ("er" dap-eval-region) + ("es" dap-eval-thing-at-point) + ("ed" dap-ui-expressions-remove) + ("eu" dap-ui-expressions-refresh) + ("q" nil "quit" :color blue) + ("Q" dap-disconnect :color red)) + +(my-leader-def "d" #'my/dap-hydra/body) +#+end_src +**** UI Fixes +There are some problems with DAP UI in my setup. + +First, DAP uses Treemacs buffers quite extensively, and they hide the doom modeline for some reason, so I can't tell which buffer is active and can't see borders between buffers. + +Second, lines are truncated in some strange way, but calling =toggle-truncate-lines= seems to fix that. + +So I define a macro that creates a function that I can further use in an advice. + +#+begin_src emacs-lisp +(defvar my/dap-mode-buffer-fixed nil) + +(with-eval-after-load 'dap-mode + (defmacro my/define-dap-tree-buffer-fixer (buffer-var buffer-name) + `(defun ,(intern (concat "my/fix-dap-ui-" buffer-name "-buffer")) (&rest _) + (with-current-buffer ,buffer-var + (unless my/dap-mode-buffer-fixed + (toggle-truncate-lines 1) + (doom-modeline-set-modeline 'info) + (setq-local my/dap-mode-buffer-fixed t))))) + + (my/define-dap-tree-buffer-fixer dap-ui--locals-buffer "locals") + (my/define-dap-tree-buffer-fixer dap-ui--expressions-buffer "expressions") + (my/define-dap-tree-buffer-fixer dap-ui--sessions-buffer "sessions") + (my/define-dap-tree-buffer-fixer dap-ui--breakpoints-buffer "breakpoints") + + (advice-add 'dap-ui-locals :after #'my/fix-dap-ui-locals-buffer) + (advice-add 'dap-ui-expressions :after #'my/fix-dap-ui-expressions-buffer) + (advice-add 'dap-ui-sessions :after #'my/fix-dap-ui-sessions-buffer) + (advice-add 'dap-ui-breakpoints :after #'my/fix-dap-ui-breakpoints-buffer)) +#+end_src +**** Helper functions +Some helper functions that make debugging with DAP easier. + +DAP seems to mess with window parameters from time to time. This function clears "bad" window parameters. +#+begin_src emacs-lisp +(defun my/clear-bad-window-parameters () + "Clear window parameters that interrupt my workflow." + (interactive) + (let ((window (get-buffer-window (current-buffer)))) + (set-window-parameter window 'no-delete-other-windows nil))) +#+end_src + +A function to kill a value from a treemacs node. +#+begin_src emacs-lisp +(defun my/dap-yank-value-at-point (node) + (interactive (list (treemacs-node-at-point))) + (kill-new (message (plist-get (button-get node :item) :value)))) +#+end_src + +A function to open a value from a treemacs node in a new buffer. +#+begin_src emacs-lisp +(defun my/dap-display-value (node) + (interactive (list (treemacs-node-at-point))) + (let ((value (plist-get (button-get node :item) :value))) + (when value + (let ((buffer (generate-new-buffer "dap-value"))) + (with-current-buffer buffer + (insert value)) + (select-window (display-buffer buffer)))))) +#+end_src +**** Improved stack frame switching +One significant improvement over Chrome Inspector for my particular stack is an ability to filter the stack frame list, for instance to see only frames that relate to my current project. + +So, here are functions that customize the filters: +#+begin_src emacs-lisp +(with-eval-after-load 'dap-mode + (setq my/dap-stack-frame-filters + `(("node_modules,node:internal" . ,(rx (or "node_modules" "node:internal"))) + ("node_modules" . ,(rx (or "node_modules"))) + ("node:internal" . ,(rx (or "node:internal"))))) + + (setq my/dap-stack-frame-current-filter (cdar my/dap-stack-frame-filters)) + + (defun my/dap-stack-frame-filter-set () + (interactive) + (setq my/dap-stack-frame-current-filter + (cdr + (assoc + (completing-read "Filter: " my/dap-stack-frame-filters) + my/dap-stack-frame-filters)))) + + (defun my/dap-stack-frame-filter (frame) + (when-let (path (dap--get-path-for-frame frame)) + (not (string-match my/dap-stack-frame-current-filter path))))) +#+end_src + +And here is a version of =dap-switch-stack-frame= that uses the said filter. +#+begin_src emacs-lisp +(defun my/dap-switch-stack-frame () + "Switch stackframe by selecting another stackframe stackframes from current thread." + (interactive) + (when (not (dap--cur-session)) + (error "There is no active session")) + + (-if-let (thread-id (dap--debug-session-thread-id (dap--cur-session))) + (-if-let (stack-frames + (gethash + thread-id + (dap--debug-session-thread-stack-frames (dap--cur-session)))) + (let* ((index 0) + (stack-framces-filtered + (-filter + #'my/dap-stack-frame-filter + stack-frames)) + (new-stack-frame + (dap--completing-read + "Select active frame: " + stack-framces-filtered + (-lambda ((frame &as &hash "name")) + (if-let (frame-path (dap--get-path-for-frame frame)) + (format "%s: %s (in %s)" + (cl-incf index) name frame-path) + (format "%s: %s" (cl-incf index) name))) + nil + t))) + (dap--go-to-stack-frame (dap--cur-session) new-stack-frame)) + (->> (dap--cur-session) + dap--debug-session-name + (format "Current session %s is not stopped") + error)) + (error "No thread is currently active %s" (dap--debug-session-name (dap--cur-session))))) +#+end_src +**** Debug templates +Some debug templates I frequently use. + +#+begin_src emacs-lisp +(with-eval-after-load 'dap-mode + (dap-register-debug-template + "Node::Nest.js" + (list :type "node" + :request "attach" + :name "Node::Attach" + :port 9229 + :outFiles ["${workspaceFolder}/dist/**/*.js"] + :sourceMaps t + :program "${workspaceFolder}/src/app.ts")) + (dap-register-debug-template + "Node::Babel" + (list :type "node" + :request "attach" + :name "Node::Attach" + :port 9229 + :program "${workspaceFolder}/dist/bin/www.js"))) + +#+end_src +*** OFF (OFF) TabNine +A ML-based autocompletion system. + +More often than not gives really good results, but is slow as hell & consumes a lot of RAM. Also, LSP-provided completions were more useful in my experience. + +References: +- [[https://www.tabnine.com/][TabNine Homepage]] +#+begin_src emacs-lisp :tangle no +(use-package company-tabnine :straight t :if (not my/lowpower) - :hook ((prog-mode . rainbow-delimiters-mode)) - ;; :commands (rainbow-delimiters-mode) - ;; :init - ;; (add-hook 'prog-mode-hook - ;; (lambda () - ;; (unless (org-in-src-block-p) - ;; (rainbow-delimiters-mode)))) - ) -#+end_src - -Highlight colors -#+begin_src emacs-lisp -(use-package rainbow-mode - :commands (rainbow-mode) - :straight t) -#+end_src -* Dired -Dired is a built-in file manager. I use it as my primary file manager, hence the top level of config. - -** Basic config & keybindings -My config mostly follows ranger's and vifm's keybindings which I'm used to. - -#+begin_src emacs-lisp -(use-package dired - :ensure nil - :custom ((dired-listing-switches "-alh --group-directories-first")) - :commands (dired) + :after company :config - (setq dired-dwim-target t) - (setq wdired-allow-to-change-permissions t) - (setq wdired-create-parent-directories t) - (setq dired-recursive-copies 'always) - (setq dired-recursive-deletes 'always) - (setq dired-kill-when-opening-new-dired-buffer t) - (add-hook 'dired-mode-hook - (lambda () - (setq truncate-lines t) - (visual-line-mode nil))) - (general-define-key - :states '(normal) - :keymaps 'dired-mode-map - "h" 'dired-up-directory - "l" 'dired-find-file - "=" 'dired-narrow - "-" 'dired-create-empty-file - "~" 'vterm - "" 'dired-up-directory - "" 'dired-find-file - "M-" 'dired-open-xdg)) - -(defun my/dired-home () - "Open dired at $HOME" - (interactive) - (dired (expand-file-name "~"))) - -(my-leader-def - "ad" #'dired - "aD" #'my/dired-home) + (add-to-list 'company-backends #'company-tabnine)) #+end_src -** Addons -I used to use [[https://www.emacswiki.org/emacs/DiredPlus][dired+]], which provides a lot of extensions for dired functionality, but it also creates some new problems, so I opt out of it. Fortunately, the one feature I want from this package - adding more colors to dired buffers - is available as a separate package. - -#+begin_src emacs-lisp -(use-package diredfl - :straight t - :after dired - :config - (diredfl-global-mode 1)) -#+end_src - -+Reuse the current dired buffer instead of spamming new ones.+ Looks like not neccesary with Emacs 28.1 -#+begin_src emacs-lisp -(use-package dired-single - :after dired - :disabled - :straight t) - #+end_src - -Display icons for files. - -| Note | Type | -|-----------+----------------------------------------------------------| -| *ACHTUNG* | This plugin is slow as hell with TRAMP or in =gnu/store= | - -#+begin_src emacs-lisp -(use-package all-the-icons-dired - :straight t - :if (not (or my/lowpower my/slow-ssh (not (display-graphic-p)))) - :hook (dired-mode . (lambda () - (unless (string-match-p "/gnu/store" default-directory) - (all-the-icons-dired-mode)))) - :config - (advice-add 'dired-add-entry :around #'all-the-icons-dired--refresh-advice) - (advice-add 'dired-remove-entry :around #'all-the-icons-dired--refresh-advice) - (advice-add 'dired-kill-subdir :around #'all-the-icons-dired--refresh-advice)) -#+end_src - -Provides stuff like =dired-open-xdg= -#+begin_src emacs-lisp -(use-package dired-open - :straight t - :commands (dired-open-xdg)) -#+end_src - -vifm-like filter -#+begin_src emacs-lisp -(use-package dired-narrow - :straight t - :commands (dired-narrow) - :config - (general-define-key - :keymaps 'dired-narrow-map - [escape] 'keyboard-quit)) -#+end_src - -Display git info, such as the last commit for file and stuff. It's pretty useful but also slows down Dired a bit, hence I don't turn it out by default. -#+begin_src emacs-lisp -(use-package dired-git-info - :straight t - :after dired - :if (not my/slow-ssh) - :config - (general-define-key - :keymap 'dired-mode-map - :states '(normal emacs) - ")" 'dired-git-info-mode)) -#+end_src -** Subdirectories -Subdirectories are one of the interesting features of Dired. It allows displaying multiple folders on the same window. - -I add my own keybindings and some extra functionality. - -#+begin_src emacs-lisp -(defun my/dired-open-this-subdir () - (interactive) - (dired (dired-current-directory))) - -(defun my/dired-kill-all-subdirs () - (interactive) - (let ((dir dired-directory)) - (kill-buffer (current-buffer)) - (dired dir))) - -(with-eval-after-load 'dired - (general-define-key - :states '(normal) - :keymaps 'dired-mode-map - "s" nil - "ss" 'dired-maybe-insert-subdir - "sl" 'dired-maybe-insert-subdir - "sq" 'dired-kill-subdir - "sk" 'dired-prev-subdir - "sj" 'dired-next-subdir - "sS" 'my/dired-open-this-subdir - "sQ" 'my/dired-kill-all-subdirs - (kbd "TAB") 'dired-hide-subdir)) -#+end_src -** TRAMP -TRAMP is a package that provides remote editing capacities. It is particularly useful for remote server management. - -One of the reasons why TRAMP may be slow is that some plugins do too many requests to the filesystem. To debug these issues, set the following variable to 6: -#+begin_src emacs-lisp -(setq tramp-verbose 1) -#+end_src - -To check if a file is remote, you can use ~file-remote-p~. E.g. ~(file-remote-p default-directory)~ for a current buffer. The problem with this approach is that it's rather awkward to add these checks in every hook, especially for global modes, so for now, I just set an environment variable for Emacs which disables these modes. - -So far I have found the following problematic plugins: -| Plugin | Note | Solution | -|---------------------+------------------------------------------+-------------------------------| -| editorconfig | looks for .editorconfig in the file tree | do not enable globally | -| all-the-icons-dired | runs test on every file in the directory | disable | -| projectile | looks for .git, .svn, etc | advice ~projectile-file-name~ | -| lsp | does a whole lot of stuff | disable | -| git-gutter | runs git | disable | -| vterm | no proper TRAMP integration | use eshell or shell | - -At any rate, it's usable, although not perfect. - -Some other optimization settings: -#+begin_src emacs-lisp -(setq remote-file-name-inhibit-cache nil) -(setq vc-ignore-dir-regexp - (format "\\(%s\\)\\|\\(%s\\)" - vc-ignore-dir-regexp - tramp-file-name-regexp)) -#+end_src - -Set the default shell to =bin/bash= for TRAMP or on a remote server. -#+begin_src emacs-lisp -(when (or my/remote-server my/slow-ssh) - (setq explicit-shell-file-name "/bin/bash")) -#+end_src - -Also, here is a hack to make TRAMP find =ls= on Guix: -#+begin_src emacs-lisp -(with-eval-after-load 'tramp - (setq tramp-remote-path - (append tramp-remote-path - '(tramp-own-remote-path)))) -#+end_src -** Bookmarks -A simple bookmark list for Dired, mainly to use with TRAMP. I may look into a proper bookmarking system later. - -Bookmarks are listed in the [[file:.emacs.d/private.el][private.el]] file, which has an expression like this: -#+begin_example emacs-lisp :tangle no -(setq my/dired-bookmarks - '(("sudo" . "/sudo::/"))) -#+end_example - -The file itself is encrypted with yadm. -#+begin_src emacs-lisp -(defun my/dired-bookmark-open () - (interactive) - (let ((bookmarks - (mapcar - (lambda (el) (cons (format "%-30s %s" (car el) (cdr el)) (cdr el))) - my/dired-bookmarks))) - (dired - (cdr - (assoc - (completing-read "Dired: " bookmarks nil nil "^") - bookmarks))))) -#+end_src -* Shells -** vterm -My terminal emulator of choice. +*** OFF (OFF) Code Compass +A set of code analyzing tools. References: -- [[https://github.com/akermu/emacs-libvterm][emacs-libvterm repo]] -*** Configuration -I use the package from the Guix repository to avoid building libvterm. +- [[https://github.com/ag91/code-compass][code-compass repo]] -#+begin_src emacs-lisp -(use-package vterm - ;; :straight t - :commands (vterm vterm-other-window) - :config - (setq vterm-kill-buffer-on-exit t) - - (add-hook 'vterm-mode-hook - (lambda () - (setq-local global-display-line-numbers-mode nil) - (display-line-numbers-mode 0))) - - - (advice-add 'evil-collection-vterm-insert - :before (lambda (&rest args) - (ignore-errors - (apply #'vterm-reset-cursor-point args)))) - - (general-define-key - :keymaps 'vterm-mode-map - "M-q" 'vterm-send-escape - - "C-h" 'evil-window-left - "C-l" 'evil-window-right - "C-k" 'evil-window-up - "C-j" 'evil-window-down - - "C-" 'evil-window-right - "C-" 'evil-window-left - "C-" 'evil-window-up - "C-" 'evil-window-down - - "M-" 'vterm-send-left - "M-" 'vterm-send-right - "M-" 'vterm-send-up - "M-" 'vterm-send-down) - - (general-define-key - :keymaps 'vterm-mode-map - :states '(normal insert) - "" 'vterm-beginning-of-line - "" 'vterm-end-of-line) - - (general-define-key - :keymaps 'vterm-mode-map - :states '(insert) - "C-r" 'vterm-send-C-r - "C-k" 'vterm-send-C-k - "C-j" 'vterm-send-C-j - "M-l" 'vterm-send-right - "M-h" 'vterm-send-left - "M-k" 'vterm-send-up - "M-j" 'vterm-send-down)) +**** Dependencies +#+begin_src emacs-lisp :tangle no +(use-package async + :straight t) +(use-package dash + :straight t) +(use-package f + :straight t) +(use-package s + :straight t) +(use-package simple-httpd + :straight t) #+end_src -*** Subterminal -Open a terminal in the lower third of the frame with the =`= key. - -#+begin_src emacs-lisp -(add-to-list 'display-buffer-alist - `(,"vterm-subterminal.*" - (display-buffer-reuse-window - display-buffer-in-side-window) - (side . bottom) - (reusable-frames . visible) - (window-height . 0.33))) - -(defun my/toggle-vterm-subteminal () - "Toogle subteminal." - (interactive) - (let - ((vterm-window - (seq-find - (lambda (window) - (string-match - "vterm-subterminal.*" - (buffer-name (window-buffer window)))) - (window-list)))) - (if vterm-window - (if (eq (get-buffer-window (current-buffer)) vterm-window) - (kill-buffer (current-buffer)) - (select-window vterm-window)) - (vterm-other-window "vterm-subterminal")))) - -(unless my/slow-ssh - (general-nmap "`" 'my/toggle-vterm-subteminal) - (general-nmap "~" 'vterm)) +**** Plugin +#+begin_src emacs-lisp :tangle no +(use-package code-compass + :straight ( + :repo "ag91/code-compass" + :files ("code-compass.el") + :branch "main" + )) #+end_src -*** Dired integration -A function to get pwd for vterm. Couldn't find a built-in function for some reason, but this seems to be working fine: +*** Reformatter +A general-purpose package to run formattters on files. While the most popular formatters are already packaged for Emacs, those that aren't can be invoked with this package. #+begin_src emacs-lisp -(defun my/vterm-get-pwd () - (if vterm--process - (file-truename (format "/proc/%d/cwd" (process-id vterm--process))) - default-directory)) +(use-package reformatter + :straight t) +#+end_src +*** General additional config +Make smartparens behave the way I like for C-like languages. +#+begin_src emacs-lisp +(defun my/set-smartparens-indent (mode) + (sp-local-pair mode "{" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET"))) + (sp-local-pair mode "[" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET"))) + (sp-local-pair mode "(" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET")))) #+end_src -Now we can open dired for vterm pwd: +Override flycheck checker with eslint. #+begin_src emacs-lisp -(defun my/vterm-dired-other-window () - "Open dired in vterm pwd in other window" - (interactive) - (dired-other-window (my/vterm-get-pwd))) - -(defun my/vterm-dired-replace () - "Replace vterm with dired" - (interactive) - (let ((pwd (my/vterm-get-pwd))) - (kill-process vterm--process) - (dired pwd))) +(defun my/set-flycheck-eslint() + "Override flycheck checker with eslint." + (setq-local lsp-diagnostic-package :none) + (setq-local flycheck-checker 'javascript-eslint)) #+end_src +** Web development +Configs for various web development technologies I'm using. +*** Emmet +[[https://emmet.io/][Emmet]] is a toolkit which greatly speeds up typing HTML & CSS. -The second function is particularly handy because that way I can alternate between vterm and dired. +| Type | Note | +|------+---------------------------------------------------| +| TODO | make expand div[disabled] as
| -Keybindings: -#+begin_src emacs-lisp -(with-eval-after-load 'vterm - (general-define-key - :keymaps 'vterm-mode-map - :states '(normal) - "gd" #'my/vterm-dired-other-window - "gD" #'my/vterm-dired-replace)) -#+end_src -*** With-editor integration -A package used by Magit to use the current Emacs instance as the =$EDITOR=. - -That is, with the help of [[file:Console.org::Functions][this function]], I can just write =e =, edit the file, and then return to the same vterm buffer. No more running vim inside Emacs. +My bit of config here: +- makes Emmet activate only in certain mmm-mode submodes. +- makes =TAB= the only key I have to use #+begin_src emacs-lisp -(use-package with-editor +(use-package emmet-mode :straight t - :after (vterm) + :hook ((vue-html-mode . emmet-mode) + (svelte-mode . emmet-mode) + (web-mode . emmet-mode) + (html-mode . emmet-mode) + (css-mode . emmet-mode) + (scss-mode . emmet-mode)) :config - (add-hook 'vterm-mode-hook 'with-editor-export-editor)) + ;; (setq emmet-indent-after-insert nil) + (setq my/emmet-mmm-submodes '(vue-html-mode css-mode)) + (defun my/emmet-or-tab (&optional arg) + (interactive) + (if (and + (boundp 'mmm-current-submode) + mmm-current-submode + (not (member mmm-current-submode my/emmet-mmm-submodes))) + (indent-for-tab-command arg) + (or (emmet-expand-line arg) + (emmet-go-to-edit-point 1) + (indent-for-tab-command arg)))) + (general-imap :keymaps 'emmet-mode-keymap + "TAB" 'my/emmet-or-tab + "" 'emmet-prev-edit-point)) #+end_src -** Eshell -A shell written in Emacs lisp. I don't use it as of now, but keep the config just in case. +*** Prettier #+begin_src emacs-lisp -(defun my/configure-eshell () - (add-hook 'eshell-pre-command-hook 'eshell-save-some-history) - (add-to-list 'eshell-output-filter-functions 'eshell-truncate-buffer) - (setq eshell-history-size 10000) - (setq eshell-hist-ingnoredups t) - (setq eshell-buffer-maximum-lines 10000) +(use-package prettier + :commands (prettier-prettify) + :straight t + :init + (my-leader-def + :keymaps '(js-mode-map web-mode-map typescript-mode-map vue-mode-map svelte-mode-map) + "rr" #'prettier-prettify)) +#+end_src +*** TypeScript +#+begin_src emacs-lisp +(use-package typescript-mode + :straight t + :mode "\\.ts\\'" + :config + (add-hook 'typescript-mode-hook #'smartparens-mode) + (add-hook 'typescript-mode-hook #'rainbow-delimiters-mode) + (add-hook 'typescript-mode-hook #'hs-minor-mode) + (my/set-smartparens-indent 'typescript-mode)) +#+end_src +*** JavaScript +#+begin_src emacs-lisp +(add-hook 'js-mode-hook #'smartparens-mode) +(add-hook 'js-mode-hook #'hs-minor-mode) +(my/set-smartparens-indent 'js-mode) +#+end_src +*** Jest +#+begin_src emacs-lisp +(use-package jest-test-mode + :straight t + :hook ((typescript-mode . jest-test-mode) + (js-mode . jest-test-mode)) + :config + (my-leader-def + :keymaps 'jest-test-mode-map + :infix "t" + "t" 'jest-test-run-at-point + "r" 'jest-test-run + "a" 'jest-test-run-all-tests)) +#+end_src - (evil-define-key '(normal insert visual) eshell-mode-map (kbd "") 'eshell-bol) - (evil-define-key '(normal insert visual) eshell-mode-map (kbd "C-r") 'counsel-esh-history) +#+begin_src emacs-lisp +(defun my/jest-test-run-at-point-copy () + "Run the top level describe block of the current buffer's point." + (interactive) + (let ((filename (jest-test-find-file)) + (example (jest-test-example-at-point))) + (if (and filename example) + (jest-test-from-project-directory filename + (let ((jest-test-options (seq-concatenate 'list jest-test-options (list "-t" example)))) + (kill-new (jest-test-command filename)))) + (message jest-test-not-found-message)))) +#+end_src + +*** web-mode +[[https://web-mode.org/][web-mode.el]] is a major mode to edit various web templates. + +Trying this one out instead of vue-mode and svelte-mode, because this one seems to have better support for tree-sitter and generally less problems. + +#+begin_src emacs-lisp +(use-package web-mode + :straight t + :commands (web-mode) + :init + (add-to-list 'auto-mode-alist '("\\.svelte\\'" . web-mode)) + (add-to-list 'auto-mode-alist '("\\.vue\\'" . web-mode)) + :config + (add-hook 'web-mode-hook 'smartparens-mode) + (add-hook 'web-mode-hook 'hs-minor-mode) + (my/set-smartparens-indent 'web-mode)) +#+end_src + +Hooking this up with lsp. +#+begin_src emacs-lisp +(setq my/web-mode-lsp-extensions + `(,(rx ".svelte" eos) + ,(rx ".vue" eos))) + +(defun my/web-mode-lsp () + (when (seq-some + (lambda (regex) (string-match-p regex (buffer-name))) + my/web-mode-lsp-extensions) + (lsp-deferred))) + +(add-hook 'web-mode-hook #'my/web-mode-lsp) +#+end_src + +Vue settings +#+begin_src emacs-lisp +(defun my/web-mode-vue-setup () + (when (string-match-p (rx ".vue" eos) (buffer-name)) + (setq-local web-mode-script-padding 0))) + +(add-hook 'web-mode-hook 'my/web-mode-vue-setup) +#+end_src +*** OFF (OFF) Vue.js +#+begin_src emacs-lisp :noweb yes +(use-package vue-mode + :straight t + :disabled + :mode "\\.vue\\'" + :config + (add-hook 'vue-mode-hook #'hs-minor-mode) + (add-hook 'vue-mode-hook #'smartparens-mode) + (my/set-smartparens-indent 'vue-mode) + (add-hook 'vue-mode-hook (lambda () (set-face-background 'mmm-default-submode-face nil))) + <>) + +(with-eval-after-load 'editorconfig + (add-to-list 'editorconfig-indentation-alist + '(vue-mode css-indent-offset + js-indent-level + sgml-basic-offset + ssass-tab-width + typescript-indent-level + emmet-indentation + vue-html-extra-indent))) +#+end_src +**** mmm-mode fix +References: +- [[https://github.com/purcell/mmm-mode/issues/112][mmm-mode issue]] + +#+begin_src emacs-lisp :noweb-ref override-mmm-mode-func :tangle no +(defun mmm-syntax-propertize-function (start stop) + (let ((saved-mode mmm-current-submode) + (saved-ovl mmm-current-overlay)) + (mmm-save-changed-local-variables + mmm-current-submode mmm-current-overlay) + (unwind-protect + (mapc (lambda (elt) + (let* ((mode (car elt)) + (func (get mode 'mmm-syntax-propertize-function)) + (beg (cadr elt)) (end (nth 2 elt)) + (ovl (nth 3 elt)) + syntax-ppss-cache + syntax-ppss-last) + (goto-char beg) + (mmm-set-current-pair mode ovl) + (mmm-set-local-variables mode mmm-current-overlay) + (save-restriction + (if mmm-current-overlay + (narrow-to-region (overlay-start mmm-current-overlay) + (overlay-end mmm-current-overlay)) + (narrow-to-region beg end)) + (cond + (func + (funcall func beg end)) + (font-lock-syntactic-keywords + (let ((syntax-propertize-function nil)) + (font-lock-fontify-syntactic-keywords-region beg end)))) + (run-hook-with-args 'mmm-after-syntax-propertize-functions + mmm-current-overlay mode beg end)))) + (mmm-regions-in start stop)) + (mmm-set-current-pair saved-mode saved-ovl) + (mmm-set-local-variables (or saved-mode mmm-primary-mode) saved-ovl)))) +#+end_src +*** OFF (OFF) Svelte +Had some problems with this and tree-sitter. Web-mode seems to be doing better. + +#+begin_src emacs-lisp +(use-package svelte-mode + :straight t + :mode "\\.svelte\\'" + :disabled + :config + (add-hook 'svelte-mode-hook 'my/set-flycheck-eslint) + (add-hook 'svelte-mode-hook #'smartparens-mode) + (my/set-smartparens-indent 'svelte-mode) + ;; I have my own Emmet + (setq lsp-svelte-plugin-css-completions-emmet nil) + (setq lsp-svelte-plugin-html-completions-emmet nil)) +#+end_src +*** SCSS +#+begin_src emacs-lisp +(add-hook 'scss-mode-hook #'smartparens-mode) +(add-hook 'scss-mode-hook #'hs-minor-mode) +(my/set-smartparens-indent 'scss-mode) +#+end_src +*** PHP +#+begin_src emacs-lisp +(use-package php-mode + :straight t + :mode "\\.php\\'") +#+end_src +** LaTeX +*** AUCTeX +The best LaTeX editing environment I've found so far. + +References: +- [[https://www.gnu.org/software/auctex/][AUCTeX homepage]] + +#+begin_src emacs-lisp :noweb yes +(use-package tex + :straight auctex + :defer t + :config + (setq-default TeX-auto-save t) + (setq-default TeX-parse-self t) + (TeX-PDF-mode) + ;; Use XeLaTeX & stuff + (setq-default TeX-engine 'xetex) + (setq-default TeX-command-extra-options "-shell-escape") + (setq-default TeX-source-correlate-method 'synctex) + (TeX-source-correlate-mode) + (setq-default TeX-source-correlate-start-server t) + (setq-default LaTeX-math-menu-unicode t) + + (setq-default font-latex-fontify-sectioning 1.3) + + ;; Scale preview for my DPI + (setq-default preview-scale-function 1.4) + (when (boundp 'tex--prettify-symbols-alist) + (assoc-delete-all "--" tex--prettify-symbols-alist) + (assoc-delete-all "---" tex--prettify-symbols-alist)) + + (add-hook 'LaTeX-mode-hook + (lambda () + (TeX-fold-mode 1) + (outline-minor-mode))) + + (add-to-list 'TeX-view-program-selection + '(output-pdf "Zathura")) + + ;; Do not run lsp within templated TeX files + (add-hook 'LaTeX-mode-hook + (lambda () + (unless (string-match "\.hogan\.tex$" (buffer-name)) + (lsp)) + (setq-local lsp-diagnostic-package :none) + (setq-local flycheck-checker 'tex-chktex))) + + (add-hook 'LaTeX-mode-hook #'rainbow-delimiters-mode) + (add-hook 'LaTeX-mode-hook #'smartparens-mode) + (add-hook 'LaTeX-mode-hook #'prettify-symbols-mode) + + (my/set-smartparens-indent 'LaTeX-mode) + (require 'smartparens-latex) + + (general-nmap + :keymaps '(LaTeX-mode-map latex-mode-map) + "RET" 'TeX-command-run-all + "C-c t" 'orgtbl-mode) + + <> + <> + <> + <>) +#+end_src +*** BibTeX +#+begin_src emacs-lisp +(use-package ivy-bibtex + :commands (ivy-bibtex) + :straight t + :init + (my-leader-def "fB" 'ivy-bibtex)) + +(add-hook 'bibtex-mode 'smartparens-mode) +#+end_src +*** Import *.sty +A function to import =.sty= files to the LaTeX document. + +#+begin_src emacs-lisp +(defun my/list-sty () + (reverse + (sort + (seq-filter + (lambda (file) (if (string-match ".*\.sty$" file) 1 nil)) + (directory-files + (seq-some + (lambda (dir) + (if (and + (f-directory-p dir) + (seq-some + (lambda (file) (string-match ".*\.sty$" file)) + (directory-files dir)) + ) dir nil)) + (list "./styles" "../styles/" "." "..")) :full)) + (lambda (f1 f2) + (let ((f1b (file-name-base f1)) + (f1b (file-name-base f2))) + (cond + ((string-match-p ".*BibTex" f1) t) + ((and (string-match-p ".*Locale" f1) (not (string-match-p ".*BibTex" f2))) t) + ((string-match-p ".*Preamble" f2) t) + (t (string-lessp f1 f2)))))))) + +(defun my/import-sty () + (interactive) + (insert + (apply #'concat + (cl-mapcar + (lambda (file) (concat "\\usepackage{" (file-name-sans-extension (file-relative-name file default-directory)) "}\n")) + (my/list-sty))))) + +(defun my/import-sty-org () + (interactive) + (insert + (apply #'concat + (cl-mapcar + (lambda (file) (concat "#+LATEX_HEADER: \\usepackage{" (file-name-sans-extension (file-relative-name file default-directory)) "}\n")) + (my/list-sty))))) +#+end_src +*** Snippets +| Note | Type | +|------+-----------------------------------------------------------------| +| TODO | Move yasnippet snippets here? Maybe extract to a separate file? | +**** Greek letters +Autogenerate snippets for greek letters. I have a few blocks like this because it's faster & more flexible than usual yasnippet snippets. + +Noweb points to the AUCTeX config block. + +#+begin_src emacs-lisp :noweb-ref init-greek-latex-snippets +(setq my/greek-alphabet + '(("a" . "\\alpha") + ("b" . "\\beta" ) + ("g" . "\\gamma") + ("d" . "\\delta") + ("e" . "\\epsilon") + ("z" . "\\zeta") + ("h" . "\\eta") + ("o" . "\\theta") + ("i" . "\\iota") + ("k" . "\\kappa") + ("l" . "\\lambda") + ("m" . "\\mu") + ("n" . "\\nu") + ("x" . "\\xi") + ("p" . "\\pi") + ("r" . "\\rho") + ("s" . "\\sigma") + ("t" . "\\tau") + ("u" . "\\upsilon") + ("f" . "\\phi") + ("c" . "\\chi") + ("v" . "\\psi") + ("g" . "\\omega"))) + +(setq my/latex-greek-prefix "'") + +;; The same for capitalized letters +(dolist (elem my/greek-alphabet) + (let ((key (car elem)) + (value (cdr elem))) + (when (string-equal key (downcase key)) + (add-to-list 'my/greek-alphabet + (cons + (capitalize (car elem)) + (concat + (substring value 0 1) + (capitalize (substring value 1 2)) + (substring value 2))))))) + +(yas-define-snippets + 'latex-mode + (mapcar + (lambda (elem) + (list (concat my/latex-greek-prefix (car elem)) (cdr elem) (concat "Greek letter " (car elem)))) + my/greek-alphabet)) +#+end_src +**** English letters +#+begin_src emacs-lisp :noweb-ref init-english-latex-snippets +(setq my/english-alphabet + '("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z")) + +(dolist (elem my/english-alphabet) + (when (string-equal elem (downcase elem)) + (add-to-list 'my/english-alphabet (upcase elem)))) + +(setq my/latex-mathbb-prefix "`") + +(yas-define-snippets + 'latex-mode + (mapcar + (lambda (elem) + (list (concat my/latex-mathbb-prefix elem) (concat "\\mathbb{" elem "}") (concat "Mathbb letter " elem))) + my/english-alphabet)) +#+end_src +**** Math symbols +#+begin_src emacs-lisp :noweb-ref init-math-latex-snippets +(setq my/latex-math-symbols + '(("x" . "\\times") + ("." . "\\cdot") + ("v" . "\\forall") + ("s" . "\\sum_{$1}^{$2}$0") + ("p" . "\\prod_{$1}^{$2}$0") + ("d" . "\\partial") + ("e" . "\\exists") + ("i" . "\\int_{$1}^{$2}$0") + ("c" . "\\cap") + ("u" . "\\cup") + ("0" . "\\emptyset") + ("^" . "\\widehat{$1}$0") + ("_" . "\\overline{$1}$0") + ("~" . "\\sim") + ("|" . "\\mid") + ("_|" . "\\perp"))) + +(setq my/latex-math-prefix ";") + +(yas-define-snippets + 'latex-mode + (mapcar + (lambda (elem) + (let ((key (car elem)) + (value (cdr elem))) + (list (concat my/latex-math-prefix key) value (concat "Math symbol " value)))) + my/latex-math-symbols)) +#+end_src +**** Section snippets +Section snippets. The code turned out to be more complicated than just writing the snippets by hand. + +#+begin_src emacs-lisp :noweb-ref init-section-latex-snippets +(setq my/latex-section-snippets + '(("ch" . "\\chapter{$1}") + ("sec" . "\\section{$1}") + ("ssec" . "\\subsection{$1}") + ("sssec" . "\\subsubsection{$1}") + ("par" . "\\paragraph{$1}}"))) + +(setq my/latex-section-snippets + (mapcar + (lambda (elem) + `(,(car elem) + ,(cdr elem) + ,(progn + (string-match "[a-z]+" (cdr elem)) + (match-string 0 (cdr elem))))) + my/latex-section-snippets)) + +(dolist (elem my/latex-section-snippets) + (let* ((key (nth 0 elem)) + (value (nth 1 elem)) + (desc (nth 2 elem)) + (star-index (string-match "\{\$1\}" value))) + (add-to-list 'my/latex-section-snippets + `(,(concat key "*") + ,(concat + (substring value 0 star-index) + "*" + (substring value star-index)) + ,(concat desc " with *"))) + (add-to-list 'my/latex-section-snippets + `(,(concat key "l") + ,(concat value "%\n\\label{sec:$2}") + ,(concat desc " with label"))))) + +(dolist (elem my/latex-section-snippets) + (setf (nth 1 elem) (concat (nth 1 elem) "\n$0"))) + +(yas-define-snippets + 'latex-mode + my/latex-section-snippets) +#+end_src +** Other markup languages +*** Markdown +#+begin_src emacs-lisp +(use-package markdown-mode + :straight t + :mode "\\.md\\'" + :config + (setq markdown-command + (concat + "pandoc" + " --from=markdown --to=html" + " --standalone --mathjax --highlight-style=pygments" + " --css=pandoc.css" + " --quiet" + )) + (setq markdown-live-preview-delete-export 'delete-on-export) + (setq markdown-asymmetric-header t) + (setq markdown-open-command "/home/pavel/bin/scripts/chromium-sep") + (add-hook 'markdown-mode-hook #'smartparens-mode) (general-define-key - :states '(normal) - :keymaps 'eshell-mode-map - (kbd "C-h") 'evil-window-left - (kbd "C-l") 'evil-window-right - (kbd "C-k") 'evil-window-up - (kbd "C-j") 'evil-window-down)) + :keymaps 'markdown-mode-map + "M-" 'markdown-promote + "M-" 'markdown-demote)) -(use-package eshell - :ensure nil - :after evil-collection - :commands (eshell) +;; (use-package livedown +;; :straight (:host github :repo "shime/emacs-livedown") +;; :commands livedown-preview +;; :config +;; (setq livedown-browser "qutebrowser")) + +#+end_src +*** PlantUML +| Guix dependency | +|-----------------| +| plantuml | + +#+begin_src emacs-lisp +(use-package plantuml-mode + :straight t + :mode "(\\.\\(plantuml?\\|uml\\|puml\\)\\'" :config - (add-hook 'eshell-first-time-mode-hook 'my/configure-eshell 90) - (when my/slow-ssh - (add-hook 'eshell-mode-hook - (lambda () - (setq-local company-idle-delay 1000)))) - (setq eshell-banner-message "")) + (setq plantuml-executable-path "/home/pavel/.guix-extra-profiles/emacs/emacs/bin/plantuml") + (setq plantuml-default-exec-mode 'executable) + (setq plantuml-indent-level 2) + (setq my/plantuml-indent-regexp-return "^\s*return\s+.+$") + (add-to-list + 'plantuml-indent-regexp-end + my/plantuml-indent-regexp-return) + (add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode)) + (add-to-list 'auto-mode-alist '("\\.uml\\'" . plantuml-mode)) + (add-hook 'plantuml-mode-hook #'smartparens-mode)) -(use-package aweshell - :straight (:repo "manateelazycat/aweshell" :host github) - :after eshell +(general-nmap + :keymaps 'plantuml-mode-map + "RET" 'plantuml-preview) +#+end_src +*** LanguageTool +LanguageTool is a great offline spell checker. For some reason, the download link is nowhere to be found on the home page, so it is listed in the references as well. + +References: +- [[https://languagetool.org/][LanguageTool homepage]] +- [[https://dev.languagetool.org/http-server][LanguageTool http server]] +#+begin_src emacs-lisp +(use-package langtool + :straight t + :commands (langtool-check) :config - (setq eshell-highlight-prompt nil) - (setq eshell-prompt-function 'epe-theme-pipeline)) + (setq langtool-language-tool-server-jar "/home/pavel/bin/LanguageTool-5.4/languagetool-server.jar") + (setq langtool-mother-tongue "ru") + (setq langtool-default-language "en-US")) -(use-package eshell-info-banner +(my-leader-def + :infix "L" + "" '(:which-key "languagetool") + "c" 'langtool-check + "s" 'langtool-server-stop + "d" 'langtool-check-done + "n" 'langtool-goto-next-error + "p" 'langtool-goto-previous-error + "l" 'langtool-correct-buffer) +#+end_src +** Lisp +These are your father's parentheses. Elegant weapons for a more... civilized age. +*** Meta Lisp +Some packages for editing various Lisps. +#+begin_src emacs-lisp +(use-package lispy + :commands (lispy-mode) + :straight t) + +(use-package lispyville + :hook (lispy-mode . lispyville-mode) + :straight t) + +(sp-with-modes sp-lisp-modes + (sp-local-pair "'" nil :actions nil)) +#+end_src +*** Emacs Lisp +**** Package Lint +A package that checks for the metadata in Emacs Lisp packages. + +#+begin_src emacs-lisp +(use-package flycheck-package + :straight t + :after flycheck + :config + (flycheck-package-setup)) +#+end_src +**** General settings +#+begin_src emacs-lisp +(add-hook 'emacs-lisp-mode-hook #'aggressive-indent-mode) +;; (add-hook 'emacs-lisp-mode-hook #'smartparens-strict-mode) +(add-hook 'emacs-lisp-mode-hook #'lispy-mode) +#+end_src +*** Common lisp +**** SLIME +#+begin_src emacs-lisp +(use-package slime + :straight t + :commands (slime) + :config + (setq inferior-lisp-program "sbcl") + (add-hook 'slime-repl-mode 'smartparens-mode)) +#+end_src +**** General settings +#+begin_src emacs-lisp +(add-hook 'lisp-mode-hook #'aggressive-indent-mode) +;; (add-hook 'emacs-lisp-mode-hook #'smartparens-strict-mode) +(add-hook 'lisp-mode-hook #'lispy-mode) +#+end_src +*** Clojure +#+begin_src emacs-lisp +(use-package clojure-mode + :straight t + :mode "\\.clj[sc]?\\'" + :config + ;; (add-hook 'clojure-mode-hook #'smartparens-strict-mode) + (add-hook 'clojure-mode-hook #'lispy-mode) + (add-hook 'clojure-mode-hook #'aggressive-indent-mode)) + +(use-package cider + :mode "\\.clj[sc]?\\'" + :straight t) +#+end_src +*** Hy +Python requirements: +- =hy= +- =jedhy= + +#+begin_src emacs-lisp +(use-package hy-mode + :straight t + :mode "\\.hy\\'" + :config + (add-hook 'hy-mode-hook #'lispy-mode) + (add-hook 'hy-mode-hook #'aggressive-indent-mode)) +#+end_src +*** Scheme +#+begin_src emacs-lisp +(use-package geiser + :straight t + :if (not my/lowpower) + :commands (geiser run-geiser) + :config + (setq geiser-default-implementation 'guile)) + +(use-package geiser-guile + :straight t + :after geiser) + +(add-hook 'scheme-mode-hook #'aggressive-indent-mode) +(add-hook 'scheme-mode-hook #'lispy-mode) +#+end_src +*** CLIPS +An honorary Lisp + +#+begin_src emacs-lisp +(use-package clips-mode + :straight t + :mode "\\.cl\\'" + :config + (add-hook 'clips-mode 'lispy-mode)) +#+end_src +** Python +Use [[https://github.com/Microsoft/python-language-server][Microsoft Language Server for Python]]. + +For some reason it doesn't use pipenv python executable, so here is a small workaround. +#+begin_src emacs-lisp +(setq my/pipenv-python-alist '()) + +(defun my/get-pipenv-python () + (let ((default-directory (projectile-project-root))) + (if (file-exists-p "Pipfile") + (let ((asc (assoc default-directory my/pipenv-python-alist))) + (if asc + (cdr asc) + (let ((python-executable + (string-trim (shell-command-to-string "PIPENV_IGNORE_VIRTUALENVS=1 pipenv run which python 2>/dev/null")))) + (if (string-match-p ".*not found.*" python-executable) + (message "Pipfile found, but not pipenv executable!") + (message (format "Found pipenv python: %s" python-executable)) + (add-to-list 'my/pipenv-python-alist (cons default-directory python-executable)) + python-executable)))) + "python"))) + +(use-package lsp-pyright + :straight t :defer t :if (not my/slow-ssh) - :straight (eshell-info-banner :type git - :host github - :repo "phundrak/eshell-info-banner.el") - :hook (eshell-banner-load . eshell-info-banner-update-banner)) + :hook (python-mode . (lambda () + (require 'lsp-pyright) + (setq-local lsp-pyright-python-executable-cmd (my/get-pipenv-python)) + (lsp)))) -(when my/slow-ssh - (general-nmap "`" 'aweshell-dedicated-toggle) - (general-nmap "~" 'eshell)) +(add-hook 'python-mode-hook #'smartparens-mode) +(add-hook 'python-mode-hook #'hs-minor-mode) +#+end_src +*** pipenv +[[https://github.com/pypa/pipenv][Pipenv]] is a package manager for Python. + +Automatically creates & manages virtualenvs and stores data in =Pipfile= and =Pipfile.lock= (like npm's =package.json= and =package-lock.json=). + +#+begin_src emacs-lisp +(use-package pipenv + :straight t + :hook (python-mode . pipenv-mode) + :if (not my/slow-ssh) + :init + (setq + pipenv-projectile-after-switch-function + #'pipenv-projectile-after-switch-extended)) +#+end_src +*** yapf +[[https://github.com/google/yapf][yapf]] is a formatter for Python files. + +| Guix dependency | +|-----------------| +| python-yapf | + +References: +- [[https://github.com/google/yapf][yapf repo]] +- [[https://github.com/JorisE/yapfify][yapfify.el repo]] +#+begin_src emacs-lisp +(use-package yapfify + :straight (:repo "JorisE/yapfify" :host github) + :commands (yapfify-region + yapfify-buffer + yapfify-region-or-buffer + yapf-mode)) +#+end_src + +Global config: +#+begin_src conf-windows :tangle .config/yapf/style :comments link +[style] +based_on_style = facebook +column_limit = 80 +#+end_src +*** isort +[[https://github.com/PyCQA/isort][isort]] is a Python package to sort Python imports. + +| Guix dependency | +|-----------------| +| python-isort | + +References: +- [[https://pycqa.github.io/isort/][isort docs]] +- [[https://github.com/paetzke/py-isort.el][py-isort.el repo]] + +#+begin_src emacs-lisp +(use-package py-isort + :straight t + :commands (py-isort-buffer py-isort-region)) +#+end_src + +The following bindings calls yapf & isort on the buffer +#+begin_src emacs-lisp +(my-leader-def + :keymaps 'python-mode-map + "rr" (lambda () + (interactive) + (unless (and (fboundp #'org-src-edit-buffer-p) (org-src-edit-buffer-p)) + (py-isort-buffer)) + (yapfify-buffer))) +#+end_src +*** sphinx-doc +A package to generate sphinx-compatible docstrings. + +#+begin_src emacs-lisp +(use-package sphinx-doc + :straight t + :hook (python-mode . sphinx-doc-mode) + :config + (my-leader-def + :keymaps 'sphinx-doc-mode-map + "rd" 'sphinx-doc)) +#+end_src +*** pytest +[[https://docs.pytest.org/en/6.2.x/][pytest]] is an unit testing framework for Python. + +Once again a function to set pytest executable from pipenv. + +References: +- [[https://docs.pytest.org/en/6.2.x/][pytest docs]] +- [[https://github.com/wbolster/emacs-python-pytest][emacs-python-pytest]] + +#+begin_src emacs-lisp :noweb yes +(defun my/set-pipenv-pytest () + (setq-local + python-pytest-executable + (concat (my/get-pipenv-python) " -m pytest"))) + +(use-package python-pytest + :straight t + :commands (python-pytest-dispatch) + :init + (my-leader-def + :keymaps 'python-mode-map + :infix "t" + "t" 'python-pytest-dispatch) + :config + <> + (add-hook 'python-mode-hook #'my/set-pipenv-pytest) + (when (derived-mode-p 'python-mode) + (my/set-pipenv-pytest))) +#+end_src +**** Fix comint buffer width +For some reason default comint output width is way too large. + +To fix that, I've modified the following function in the =python-pytest= package. +#+begin_src emacs-lisp :noweb-ref override-pytest-run :tangle no +(cl-defun python-pytest--run-as-comint (&key command) + "Run a pytest comint session for COMMAND." + (let* ((buffer (python-pytest--get-buffer)) + (process (get-buffer-process buffer))) + (with-current-buffer buffer + (when (comint-check-proc buffer) + (unless (or compilation-always-kill + (yes-or-no-p "Kill running pytest process?")) + (user-error "Aborting; pytest still running"))) + (when process + (delete-process process)) + (let ((inhibit-read-only t)) + (erase-buffer)) + (unless (eq major-mode 'python-pytest-mode) + (python-pytest-mode)) + (compilation-forget-errors) + (display-buffer buffer) + (setq command (format "export COLUMNS=%s; %s" + (- (window-width (get-buffer-window buffer)) 5) + command)) + (insert (format "cwd: %s\ncmd: %s\n\n" default-directory command)) + (setq python-pytest--current-command command) + (when python-pytest-pdb-track + (add-hook + 'comint-output-filter-functions + 'python-pdbtrack-comint-output-filter-function + nil t)) + (run-hooks 'python-pytest-setup-hook) + (make-comint-in-buffer "pytest" buffer "bash" nil "-c" command) + (run-hooks 'python-pytest-started-hook) + (setq process (get-buffer-process buffer)) + (set-process-sentinel process #'python-pytest--process-sentinel)))) +#+end_src +*** code-cells +Support for text with magic comments. + +#+begin_src emacs-lisp +(use-package code-cells + :straight t + :commands (code-cells-mode)) +#+end_src +*** tensorboard +A function to start up [[https://www.tensorflow.org/tensorboard][TensorBoard]]. + +#+begin_src emacs-lisp +(setq my/tensorboard-buffer "TensorBoard-out") + +(defun my/tensorboard () + (interactive) + (start-process + "tensorboard" + my/tensorboard-buffer + "tensorboard" + "serve" + "--logdir" + (car (find-file-read-args "Directory: " t))) + (display-buffer my/tensorboard-buffer)) +#+end_src +** Java +#+begin_src emacs-lisp +(use-package lsp-java + :straight t + :after (lsp) + :config + (setq lsp-java-jdt-download-url "https://download.eclipse.org/jdtls/milestones/0.57.0/jdt-language-server-0.57.0-202006172108.tar.gz")) + +(add-hook 'java-mode-hook #'smartparens-mode) +;; (add-hook 'java-mode-hook #'hs-minor-mode) +(my/set-smartparens-indent 'java-mode) +#+end_src +** Go +#+begin_src emacs-lisp +(use-package go-mode + :straight t + :mode "\\.go\\'" + :config + (my/set-smartparens-indent 'go-mode) + (add-hook 'go-mode-hook #'smartparens-mode) + (add-hook 'go-mode-hook #'hs-minor-mode)) +#+end_src +** .NET +*** C# +| Guix dependencies | Disabled | +|-------------------+----------| +| omnisharp | t | +| dotnet | t | + +#+begin_src emacs-lisp +(use-package csharp-mode + :straight t + :mode "\\.cs\\'" + :config + (setq lsp-csharp-server-path (executable-find "omnisharp-wrapper")) + (add-hook 'csharp-mode-hook #'csharp-tree-sitter-mode) + (add-hook 'csharp-tree-sitter-mode-hook #'smartparens-mode) + (add-hook 'csharp-mode-hook #'hs-minor-mode) + (my/set-smartparens-indent 'csharp-tree-sitter-mode)) +#+end_src +*** MSBuild +#+begin_src emacs-lisp +(use-package csproj-mode + :straight t + :mode "\\.csproj\\'" + :config + (add-hook 'csproj-mode #'smartparens-mode)) +#+end_src +** fish +#+begin_src emacs-lisp +(use-package fish-mode + :straight t + :mode "\\.fish\\'" + :config + (add-hook 'fish-mode-hook #'smartparens-mode)) +#+end_src +** sh +#+begin_src emacs-lisp +(add-hook 'sh-mode-hook #'smartparens-mode) +#+end_src +** Haskell +#+begin_src emacs-lisp +(use-package haskell-mode + :straight t + :mode "\\.hs\\'") + +(use-package lsp-haskell + :straight t + :after (lsp haskell-mode)) +#+end_src +** Lua +#+begin_src emacs-lisp +(use-package lua-mode + :straight t + :mode "\\.lua\\'" + :hook (lua-mode . smartparens-mode)) + +(my/set-smartparens-indent 'lua-mode) +#+end_src +** JSON +#+begin_src emacs-lisp +(use-package json-mode + :straight t + :mode "\\.json\\'" + :config + (add-hook 'json-mode #'smartparens-mode) + (add-hook 'json-mode #'hs-minor-mode) + (my/set-smartparens-indent 'json-mode)) +#+end_src +** SQL +[[https://github.com/zeroturnaround/sql-formatter][sql-formatter]] is a nice JavaScript package for pretty-printing SQL queries. It is not packaged for Emacs, so the easiest way to use it seems to be to define a custom formatter via [[https://github.com/purcell/emacs-reformatter][reformatter]]. + +Also, I've a simple function to switch dialects because I often alternate between them. + +So far I didn't find a nice SQL client for Emacs, but I occasionally run SQL queries in Org Mode, so this qute package is handy. + +#+begin_src emacs-lisp +(setq my/sqlformatter-dialect-choice + '("db2" "mariadb" "mysql" "n1ql" "plsql" "postgresql" "redshift" "spark" "sql" "tsql")) + +(setq my/sqlformatter-dialect "postgresql") + +(defun my/sqlformatter-set-dialect () + "Set dialect for sql-formatter" + (interactive) + (setq my/sqlformatter-dialect + (completing-read "Dialect: " my/sqlformatter-dialect-choice))) + +(reformatter-define sqlformat + :program (executable-find "sql-formatter") + :args `("-l" ,my/sqlformatter-dialect, "-u")) + +(my-leader-def + :keymaps '(sql-mode-map) + "rr" #'sqlformat-buffer) +#+end_src +** YAML +#+begin_src emacs-lisp +(use-package yaml-mode + :straight t + :mode "\\.yml\\'" + :config + (add-hook 'yaml-mode-hook 'smartparens-mode) + (add-hook 'yaml-mode-hook 'highlight-indent-guides-mode) + (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))) +#+end_src +** .env +#+begin_src emacs-lisp +(use-package dotenv-mode + :straight t + :mode "\\.env\\..*\\'") +#+end_src +** CSV +#+begin_src emacs-lisp +(use-package csv-mode + :straight t + :mode "\\.csv\\'") +#+end_src +** Docker +#+begin_src emacs-lisp +(use-package dockerfile-mode + :mode "Dockerfile\\'" + :straight t + :config + (add-hook 'dockerfile-mode 'smartparens-mode)) +#+end_src +** crontab +#+begin_src emacs-lisp +(use-package crontab-mode + :straight t) #+end_src * Org Mode The best feature of Emacs. Just after every other best feature of Emacs, probably. @@ -3801,1500 +4740,410 @@ emacs -Q --batch -l run-tangle.el #+end_src I have added this line to yadm's =post_alt= hook, so tangle is run after =yadm alt= -* Programming -** General setup -*** LSP -LSP-mode provides an IDE-like experience for Emacs - real-time diagnostic, code actions, intelligent autocompletion, etc. +* Applications +** Dired +Dired is a built-in file manager. I currently use it as my primary file manager. + +*** Basic config & keybindings +My config mostly follows ranger's and vifm's keybindings which I'm used to. -References: -- [[https://emacs-lsp.github.io/lsp-mode/][lsp-mode homepage]] -**** Setup #+begin_src emacs-lisp -(use-package lsp-mode - :straight t - :if (not (or my/slow-ssh my/is-termux my/remote-server)) - :hook ( - (typescript-mode . lsp) - (js-mode . lsp) - (vue-mode . lsp) - (go-mode . lsp) - (svelte-mode . lsp) - ;; (python-mode . lsp) - (json-mode . lsp) - (haskell-mode . lsp) - (haskell-literate-mode . lsp) - (java-mode . lsp) - ;; (csharp-mode . lsp) - ) - :commands lsp - :init - (setq lsp-keymap-prefix nil) +(use-package dired + :ensure nil + :custom ((dired-listing-switches "-alh --group-directories-first")) + :commands (dired) :config - (setq lsp-idle-delay 1) - (setq lsp-eslint-server-command '("node" "/home/pavel/.emacs.d/.cache/lsp/eslint/unzipped/extension/server/out/eslintServer.js" "--stdio")) - (setq lsp-eslint-run "onSave") - (setq lsp-signature-render-documentation nil) - ;; (lsp-headerline-breadcrumb-mode nil) - (setq lsp-headerline-breadcrumb-enable nil) - (add-to-list 'lsp-language-id-configuration '(svelte-mode . "svelte"))) - -(use-package lsp-ui - :straight t - :commands lsp-ui-mode - :config - (setq lsp-ui-doc-delay 2) - (setq lsp-ui-sideline-show-hover nil)) -#+end_src -**** Integrations -The only integration left now is treemacs. - -Origami should've leveraged LSP folding, but it was too unstable at the moment I tried it. -#+begin_src emacs-lisp -;; (use-package helm-lsp -;; :straight t -;; :commands helm-lsp-workspace-symbol) - -;; (use-package origami -;; :straight t -;; :hook (prog-mode . origami-mode)) - -;; (use-package lsp-origami -;; :straight t -;; :config -;; (add-hook 'lsp-after-open-hook #'lsp-origami-try-enable)) - -(use-package lsp-treemacs - :after (lsp) - :straight t - :commands lsp-treemacs-errors-list) -#+end_src -**** Keybindings -#+begin_src emacs-lisp -(my-leader-def - :infix "l" - "" '(:which-key "lsp") - "d" 'lsp-ui-peek-find-definitions - "r" 'lsp-rename - "u" 'lsp-ui-peek-find-references - "s" 'lsp-ui-find-workspace-symbol - "l" 'lsp-execute-code-action - "e" 'list-flycheck-errors) -#+end_src -*** Flycheck -A syntax checking extension for Emacs. Integrates with LSP-mode, but can also use various standalone checkers. - -References: -- [[https://www.flycheck.org/en/latest/][Flycheck homepage]] - -#+begin_src emacs-lisp -(use-package flycheck - :straight t - :config - (global-flycheck-mode) - (setq flycheck-check-syntax-automatically '(save idle-buffer-switch mode-enabled)) - ;; (add-hook 'evil-insert-state-exit-hook - ;; (lambda () - ;; (if flycheck-checker - ;; (flycheck-buffer)) - ;; )) - (advice-add 'flycheck-eslint-config-exists-p :override (lambda() t)) - (add-to-list 'display-buffer-alist - `(,(rx bos "*Flycheck errors*" eos) - (display-buffer-reuse-window - display-buffer-in-side-window) - (side . bottom) - (reusable-frames . visible) - (window-height . 0.33)))) -#+end_src -*** Tree Sitter -An incremental code parsing system, constructing a syntax tree at runtime. - -Right now it doesn't do much except provide a better syntax highlighting than regexes, but this integration is a rather recent development. There are already some major modes built on top of this thing. - -Also, it seems to break if ran from mmm-mode, so there is a small workaround. - -References: -- [[https://tree-sitter.github.io/tree-sitter/][Tree-sitter library]] -- [[https://ubolonton.github.io/emacs-tree-sitter/][Emacs Tree-sitter]] - -#+begin_src emacs-lisp -(defun my/tree-sitter-if-not-mmm () - (when (not (and (boundp 'mmm-temp-buffer-name) - (string-equal mmm-temp-buffer-name (buffer-name)))) - (tree-sitter-mode) - (tree-sitter-hl-mode))) - -(use-package tree-sitter - :straight t - :if (not my/remote-server) - :hook ((typescript-mode . my/tree-sitter-if-not-mmm) - (js-mode . my/tree-sitter-if-not-mmm) - (python-mode . tree-sitter-mode) - (python-mode . tree-sitter-hl-mode) - (csharp-mode . tree-sitter-mode))) - -(use-package tree-sitter-langs - :straight t - :after tree-sitter) -#+end_src -*** DAP -An Emacs client for Debugger Adapter Protocol. - -As of time of this writing, I mostly debug TypeScript, so the main competitor is Chrome Inspector for node.js. - -References: -- [[https://emacs-lsp.github.io/dap-mode/][dap-mode homepage]] -#+begin_src emacs-lisp -(use-package dap-mode - :straight t - :commands (dap-debug) - :init - (setq lsp-enable-dap-auto-configure nil) - :config - - (setq dap-ui-variable-length 100) - (setq dap-auto-show-output nil) - (require 'dap-node) - (dap-node-setup) - - (require 'dap-chrome) - (dap-chrome-setup) - - (require 'dap-python) - - (dap-mode 1) - (dap-ui-mode 1) - (dap-tooltip-mode 1) - (tooltip-mode 1)) -#+end_src - -**** Controls -I don't like some keybindings in the built-in hydra, and there seems to be no easy way to modify the existing hydra, so I create my own. I tried to use transient, but the transient buffer seems to conflict with special buffers of DAP, and hydra does not. - -Also, I want the hydra to toggle UI windows instead of just opening them, so here is macro that defines such functions: -#+begin_src emacs-lisp -(with-eval-after-load 'dap-mode - (defmacro my/define-dap-ui-window-toggler (name) - `(defun ,(intern (concat "my/dap-ui-toggle-" name)) () - ,(concat "Toggle DAP " name "buffer") - (interactive) - (if-let (window (get-buffer-window ,(intern (concat "dap-ui--" name "-buffer")))) - (quit-window nil window) - (,(intern (concat "dap-ui-" name)))))) - - (my/define-dap-ui-window-toggler "locals") - (my/define-dap-ui-window-toggler "expressions") - (my/define-dap-ui-window-toggler "sessions") - (my/define-dap-ui-window-toggler "breakpoints") - (my/define-dap-ui-window-toggler "repl")) -#+end_src - -And here is the hydra: -#+begin_src emacs-lisp -(defhydra my/dap-hydra (:color pink :hint nil :foreign-keys run) - " -^Stepping^ ^UI^ ^Switch^ ^Breakpoints^ ^Debug^ ^Expressions -^^^^^^^^------------------------------------------------------------------------------------------------------------------------------------------ -_n_: Next _uc_: Controls _ss_: Session _bb_: Toggle _dd_: Debug _ee_: Eval -_i_: Step in _ue_: Expressions _st_: Thread _bd_: Delete _dr_: Debug recent _er_: Eval region -_o_: Step out _ul_: Locals _sf_: Stack frame _ba_: Add _dl_: Debug last _es_: Eval thing at point -_c_: Continue _ur_: REPL _su_: Up stack frame _bc_: Set condition _de_: Edit debug template _ea_: Add expression -_r_: Restart frame _uo_: Output _sd_: Down stack frame _bh_: Set hit count _Q_: Disconnect _ed_: Remove expression - _us_: Sessions _sF_: Stack frame filtered _bl_: Set log message _eu_: Refresh expressions - _ub_: Breakpoints " - - ("n" dap-next) - ("i" dap-step-in) - ("o" dap-step-out) - ("c" dap-continue) - ("r" dap-restart-frame) - ("uc" dap-ui-controls-mode) - ("ue" my/dap-ui-toggle-expressions) - ("ul" my/dap-ui-toggle-locals) - ("ur" my/dap-ui-toggle-repl) - ("uo" dap-ui-go-to-output-buffer) - ("us" my/dap-ui-toggle-sessions) - ("ub" my/dap-ui-toggle-breakpoints) - ("ss" dap-switch-session) - ("st" dap-switch-thread) - ("sf" dap-switch-stack-frame) - ("sF" my/dap-switch-stack-frame) - ("su" dap-up-stack-frame) - ("sd" dap-down-stack-frame) - ("bb" dap-breakpoint-toggle) - ("ba" dap-breakpoint-add) - ("bd" dap-breakpoint-delete) - ("bc" dap-breakpoint-condition) - ("bh" dap-breakpoint-hit-condition) - ("bl" dap-breakpoint-log-message) - ("dd" dap-debug) - ("dr" dap-debug-recent) - ("dl" dap-debug-last) - ("de" dap-debug-edit-template) - ("ee" dap-eval) - ("ea" dap-ui-expressions-add) - ("er" dap-eval-region) - ("es" dap-eval-thing-at-point) - ("ed" dap-ui-expressions-remove) - ("eu" dap-ui-expressions-refresh) - ("q" nil "quit" :color blue) - ("Q" dap-disconnect :color red)) - -(my-leader-def "d" #'my/dap-hydra/body) -#+end_src -**** UI Fixes -There are some problems with DAP UI in my setup. - -First, DAP uses Treemacs buffers quite extensively, and they hide the doom modeline for some reason, so I can't tell which buffer is active and can't see borders between buffers. - -Second, lines are truncated in some strange way, but calling =toggle-truncate-lines= seems to fix that. - -So I define a macro that creates a function that I can further use in an advice. - -#+begin_src emacs-lisp -(defvar my/dap-mode-buffer-fixed nil) - -(with-eval-after-load 'dap-mode - (defmacro my/define-dap-tree-buffer-fixer (buffer-var buffer-name) - `(defun ,(intern (concat "my/fix-dap-ui-" buffer-name "-buffer")) (&rest _) - (with-current-buffer ,buffer-var - (unless my/dap-mode-buffer-fixed - (toggle-truncate-lines 1) - (doom-modeline-set-modeline 'info) - (setq-local my/dap-mode-buffer-fixed t))))) - - (my/define-dap-tree-buffer-fixer dap-ui--locals-buffer "locals") - (my/define-dap-tree-buffer-fixer dap-ui--expressions-buffer "expressions") - (my/define-dap-tree-buffer-fixer dap-ui--sessions-buffer "sessions") - (my/define-dap-tree-buffer-fixer dap-ui--breakpoints-buffer "breakpoints") - - (advice-add 'dap-ui-locals :after #'my/fix-dap-ui-locals-buffer) - (advice-add 'dap-ui-expressions :after #'my/fix-dap-ui-expressions-buffer) - (advice-add 'dap-ui-sessions :after #'my/fix-dap-ui-sessions-buffer) - (advice-add 'dap-ui-breakpoints :after #'my/fix-dap-ui-breakpoints-buffer)) -#+end_src -**** Helper functions -Some helper functions that make debugging with DAP easier. - -DAP seems to mess with window parameters from time to time. This function clears "bad" window parameters. -#+begin_src emacs-lisp -(defun my/clear-bad-window-parameters () - "Clear window parameters that interrupt my workflow." - (interactive) - (let ((window (get-buffer-window (current-buffer)))) - (set-window-parameter window 'no-delete-other-windows nil))) -#+end_src - -A function to kill a value from a treemacs node. -#+begin_src emacs-lisp -(defun my/dap-yank-value-at-point (node) - (interactive (list (treemacs-node-at-point))) - (kill-new (message (plist-get (button-get node :item) :value)))) -#+end_src - -A function to open a value from a treemacs node in a new buffer. -#+begin_src emacs-lisp -(defun my/dap-display-value (node) - (interactive (list (treemacs-node-at-point))) - (let ((value (plist-get (button-get node :item) :value))) - (when value - (let ((buffer (generate-new-buffer "dap-value"))) - (with-current-buffer buffer - (insert value)) - (select-window (display-buffer buffer)))))) -#+end_src -**** Improved stack frame switching -One significant improvement over Chrome Inspector for my particular stack is an ability to filter the stack frame list, for instance to see only frames that relate to my current project. - -So, here are functions that customize the filters: -#+begin_src emacs-lisp -(with-eval-after-load 'dap-mode - (setq my/dap-stack-frame-filters - `(("node_modules,node:internal" . ,(rx (or "node_modules" "node:internal"))) - ("node_modules" . ,(rx (or "node_modules"))) - ("node:internal" . ,(rx (or "node:internal"))))) - - (setq my/dap-stack-frame-current-filter (cdar my/dap-stack-frame-filters)) - - (defun my/dap-stack-frame-filter-set () - (interactive) - (setq my/dap-stack-frame-current-filter - (cdr - (assoc - (completing-read "Filter: " my/dap-stack-frame-filters) - my/dap-stack-frame-filters)))) - - (defun my/dap-stack-frame-filter (frame) - (when-let (path (dap--get-path-for-frame frame)) - (not (string-match my/dap-stack-frame-current-filter path))))) -#+end_src - -And here is a version of =dap-switch-stack-frame= that uses the said filter. -#+begin_src emacs-lisp -(defun my/dap-switch-stack-frame () - "Switch stackframe by selecting another stackframe stackframes from current thread." - (interactive) - (when (not (dap--cur-session)) - (error "There is no active session")) - - (-if-let (thread-id (dap--debug-session-thread-id (dap--cur-session))) - (-if-let (stack-frames - (gethash - thread-id - (dap--debug-session-thread-stack-frames (dap--cur-session)))) - (let* ((index 0) - (stack-framces-filtered - (-filter - #'my/dap-stack-frame-filter - stack-frames)) - (new-stack-frame - (dap--completing-read - "Select active frame: " - stack-framces-filtered - (-lambda ((frame &as &hash "name")) - (if-let (frame-path (dap--get-path-for-frame frame)) - (format "%s: %s (in %s)" - (cl-incf index) name frame-path) - (format "%s: %s" (cl-incf index) name))) - nil - t))) - (dap--go-to-stack-frame (dap--cur-session) new-stack-frame)) - (->> (dap--cur-session) - dap--debug-session-name - (format "Current session %s is not stopped") - error)) - (error "No thread is currently active %s" (dap--debug-session-name (dap--cur-session))))) -#+end_src -**** Debug templates -Some debug templates I frequently use. - -#+begin_src emacs-lisp -(with-eval-after-load 'dap-mode - (dap-register-debug-template - "Node::Nest.js" - (list :type "node" - :request "attach" - :name "Node::Attach" - :port 9229 - :outFiles ["${workspaceFolder}/dist/**/*.js"] - :sourceMaps t - :program "${workspaceFolder}/src/app.ts")) - (dap-register-debug-template - "Node::Babel" - (list :type "node" - :request "attach" - :name "Node::Attach" - :port 9229 - :program "${workspaceFolder}/dist/bin/www.js"))) - -#+end_src -*** OFF (OFF) TabNine -A ML-based autocompletion system. - -More often than not gives really good results, but is slow as hell & consumes a lot of RAM. Also, LSP-provided completions were more useful in my experience. - -References: -- [[https://www.tabnine.com/][TabNine Homepage]] -#+begin_src emacs-lisp :tangle no -(use-package company-tabnine - :straight t - :if (not my/lowpower) - :after company - :config - (add-to-list 'company-backends #'company-tabnine)) -#+end_src -*** OFF (OFF) Code Compass -A set of code analyzing tools. - -References: -- [[https://github.com/ag91/code-compass][code-compass repo]] - -**** Dependencies -#+begin_src emacs-lisp :tangle no -(use-package async - :straight t) -(use-package dash - :straight t) -(use-package f - :straight t) -(use-package s - :straight t) -(use-package simple-httpd - :straight t) -#+end_src -**** Plugin -#+begin_src emacs-lisp :tangle no -(use-package code-compass - :straight ( - :repo "ag91/code-compass" - :files ("code-compass.el") - :branch "main" - )) -#+end_src -*** Reformatter -A general-purpose package to run formattters on files. While the most popular formatters are already packaged for Emacs, those that aren't can be invoked with this package. - -#+begin_src emacs-lisp -(use-package reformatter - :straight t) -#+end_src -*** General additional config -Make smartparens behave the way I like for C-like languages. -#+begin_src emacs-lisp -(defun my/set-smartparens-indent (mode) - (sp-local-pair mode "{" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET"))) - (sp-local-pair mode "[" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET"))) - (sp-local-pair mode "(" nil :post-handlers '(("|| " "SPC") ("||\n[i]" "RET")))) -#+end_src - -Override flycheck checker with eslint. -#+begin_src emacs-lisp -(defun my/set-flycheck-eslint() - "Override flycheck checker with eslint." - (setq-local lsp-diagnostic-package :none) - (setq-local flycheck-checker 'javascript-eslint)) -#+end_src -** Web development -Configs for various web development technologies I'm using. -*** Emmet -[[https://emmet.io/][Emmet]] is a toolkit which greatly speeds up typing HTML & CSS. - -| Type | Note | -|------+---------------------------------------------------| -| TODO | make expand div[disabled] as
| - -My bit of config here: -- makes Emmet activate only in certain mmm-mode submodes. -- makes =TAB= the only key I have to use - -#+begin_src emacs-lisp -(use-package emmet-mode - :straight t - :hook ((vue-html-mode . emmet-mode) - (svelte-mode . emmet-mode) - (web-mode . emmet-mode) - (html-mode . emmet-mode) - (css-mode . emmet-mode) - (scss-mode . emmet-mode)) - :config - ;; (setq emmet-indent-after-insert nil) - (setq my/emmet-mmm-submodes '(vue-html-mode css-mode)) - (defun my/emmet-or-tab (&optional arg) - (interactive) - (if (and - (boundp 'mmm-current-submode) - mmm-current-submode - (not (member mmm-current-submode my/emmet-mmm-submodes))) - (indent-for-tab-command arg) - (or (emmet-expand-line arg) - (emmet-go-to-edit-point 1) - (indent-for-tab-command arg)))) - (general-imap :keymaps 'emmet-mode-keymap - "TAB" 'my/emmet-or-tab - "" 'emmet-prev-edit-point)) -#+end_src -*** Prettier -#+begin_src emacs-lisp -(use-package prettier - :commands (prettier-prettify) - :straight t - :init - (my-leader-def - :keymaps '(js-mode-map web-mode-map typescript-mode-map vue-mode-map svelte-mode-map) - "rr" #'prettier-prettify)) -#+end_src -*** TypeScript -#+begin_src emacs-lisp -(use-package typescript-mode - :straight t - :mode "\\.ts\\'" - :config - (add-hook 'typescript-mode-hook #'smartparens-mode) - (add-hook 'typescript-mode-hook #'rainbow-delimiters-mode) - (add-hook 'typescript-mode-hook #'hs-minor-mode) - (my/set-smartparens-indent 'typescript-mode)) -#+end_src -*** JavaScript -#+begin_src emacs-lisp -(add-hook 'js-mode-hook #'smartparens-mode) -(add-hook 'js-mode-hook #'hs-minor-mode) -(my/set-smartparens-indent 'js-mode) -#+end_src -*** Jest -#+begin_src emacs-lisp -(use-package jest-test-mode - :straight t - :hook ((typescript-mode . jest-test-mode) - (js-mode . jest-test-mode)) - :config - (my-leader-def - :keymaps 'jest-test-mode-map - :infix "t" - "t" 'jest-test-run-at-point - "r" 'jest-test-run - "a" 'jest-test-run-all-tests)) -#+end_src - -#+begin_src emacs-lisp -(defun my/jest-test-run-at-point-copy () - "Run the top level describe block of the current buffer's point." - (interactive) - (let ((filename (jest-test-find-file)) - (example (jest-test-example-at-point))) - (if (and filename example) - (jest-test-from-project-directory filename - (let ((jest-test-options (seq-concatenate 'list jest-test-options (list "-t" example)))) - (kill-new (jest-test-command filename)))) - (message jest-test-not-found-message)))) -#+end_src - -*** web-mode -[[https://web-mode.org/][web-mode.el]] is a major mode to edit various web templates. - -Trying this one out instead of vue-mode and svelte-mode, because this one seems to have better support for tree-sitter and generally less problems. - -#+begin_src emacs-lisp -(use-package web-mode - :straight t - :init - (add-to-list 'auto-mode-alist '("\\.svelte\\'" . web-mode)) - (add-to-list 'auto-mode-alist '("\\.vue\\'" . web-mode)) - :config - (add-hook 'web-mode-hook 'smartparens-mode) - (add-hook 'web-mode-hook 'hs-minor-mode) - (my/set-smartparens-indent 'web-mode)) -#+end_src - -Hooking this up with lsp. -#+begin_src emacs-lisp -(setq my/web-mode-lsp-extensions - `(,(rx ".svelte" eos) - ,(rx ".vue" eos))) - -(defun my/web-mode-lsp () - (when (seq-some - (lambda (regex) (string-match-p regex (buffer-name))) - my/web-mode-lsp-extensions) - (lsp-deferred))) - -(add-hook 'web-mode-hook #'my/web-mode-lsp) -#+end_src - -Vue settings -#+begin_src emacs-lisp -(defun my/web-mode-vue-setup () - (when (string-match-p (rx ".vue" eos) (buffer-name)) - (setq-local web-mode-script-padding 0))) - -(add-hook 'web-mode-hook 'my/web-mode-vue-setup) -#+end_src -*** OFF (OFF) Vue.js -#+begin_src emacs-lisp :noweb yes -(use-package vue-mode - :straight t - :disabled - :mode "\\.vue\\'" - :config - (add-hook 'vue-mode-hook #'hs-minor-mode) - (add-hook 'vue-mode-hook #'smartparens-mode) - (my/set-smartparens-indent 'vue-mode) - (add-hook 'vue-mode-hook (lambda () (set-face-background 'mmm-default-submode-face nil))) - <>) - -(with-eval-after-load 'editorconfig - (add-to-list 'editorconfig-indentation-alist - '(vue-mode css-indent-offset - js-indent-level - sgml-basic-offset - ssass-tab-width - typescript-indent-level - emmet-indentation - vue-html-extra-indent))) -#+end_src -**** mmm-mode fix -References: -- [[https://github.com/purcell/mmm-mode/issues/112][mmm-mode issue]] - -#+begin_src emacs-lisp :noweb-ref override-mmm-mode-func :tangle no -(defun mmm-syntax-propertize-function (start stop) - (let ((saved-mode mmm-current-submode) - (saved-ovl mmm-current-overlay)) - (mmm-save-changed-local-variables - mmm-current-submode mmm-current-overlay) - (unwind-protect - (mapc (lambda (elt) - (let* ((mode (car elt)) - (func (get mode 'mmm-syntax-propertize-function)) - (beg (cadr elt)) (end (nth 2 elt)) - (ovl (nth 3 elt)) - syntax-ppss-cache - syntax-ppss-last) - (goto-char beg) - (mmm-set-current-pair mode ovl) - (mmm-set-local-variables mode mmm-current-overlay) - (save-restriction - (if mmm-current-overlay - (narrow-to-region (overlay-start mmm-current-overlay) - (overlay-end mmm-current-overlay)) - (narrow-to-region beg end)) - (cond - (func - (funcall func beg end)) - (font-lock-syntactic-keywords - (let ((syntax-propertize-function nil)) - (font-lock-fontify-syntactic-keywords-region beg end)))) - (run-hook-with-args 'mmm-after-syntax-propertize-functions - mmm-current-overlay mode beg end)))) - (mmm-regions-in start stop)) - (mmm-set-current-pair saved-mode saved-ovl) - (mmm-set-local-variables (or saved-mode mmm-primary-mode) saved-ovl)))) -#+end_src -*** OFF (OFF) Svelte -Had some problems with this and tree-sitter. Web-mode seems to be doing better. - -#+begin_src emacs-lisp -(use-package svelte-mode - :straight t - :mode "\\.svelte\\'" - :disabled - :config - (add-hook 'svelte-mode-hook 'my/set-flycheck-eslint) - (add-hook 'svelte-mode-hook #'smartparens-mode) - (my/set-smartparens-indent 'svelte-mode) - ;; I have my own Emmet - (setq lsp-svelte-plugin-css-completions-emmet nil) - (setq lsp-svelte-plugin-html-completions-emmet nil)) -#+end_src -*** SCSS -#+begin_src emacs-lisp -(add-hook 'scss-mode-hook #'smartparens-mode) -(add-hook 'scss-mode-hook #'hs-minor-mode) -(my/set-smartparens-indent 'scss-mode) -#+end_src -*** PHP -#+begin_src emacs-lisp -(use-package php-mode - :straight t - :mode "\\.php\\'") -#+end_src -** LaTeX -*** AUCTeX -The best LaTeX editing environment I've found so far. - -References: -- [[https://www.gnu.org/software/auctex/][AUCTeX homepage]] - -#+begin_src emacs-lisp :noweb yes -(use-package tex - :straight auctex - :defer t - :config - (setq-default TeX-auto-save t) - (setq-default TeX-parse-self t) - (TeX-PDF-mode) - ;; Use XeLaTeX & stuff - (setq-default TeX-engine 'xetex) - (setq-default TeX-command-extra-options "-shell-escape") - (setq-default TeX-source-correlate-method 'synctex) - (TeX-source-correlate-mode) - (setq-default TeX-source-correlate-start-server t) - (setq-default LaTeX-math-menu-unicode t) - - (setq-default font-latex-fontify-sectioning 1.3) - - ;; Scale preview for my DPI - (setq-default preview-scale-function 1.4) - (when (boundp 'tex--prettify-symbols-alist) - (assoc-delete-all "--" tex--prettify-symbols-alist) - (assoc-delete-all "---" tex--prettify-symbols-alist)) - - (add-hook 'LaTeX-mode-hook + (setq dired-dwim-target t) + (setq wdired-allow-to-change-permissions t) + (setq wdired-create-parent-directories t) + (setq dired-recursive-copies 'always) + (setq dired-recursive-deletes 'always) + (setq dired-kill-when-opening-new-dired-buffer t) + (add-hook 'dired-mode-hook (lambda () - (TeX-fold-mode 1) - (outline-minor-mode))) - - (add-to-list 'TeX-view-program-selection - '(output-pdf "Zathura")) - - ;; Do not run lsp within templated TeX files - (add-hook 'LaTeX-mode-hook - (lambda () - (unless (string-match "\.hogan\.tex$" (buffer-name)) - (lsp)) - (setq-local lsp-diagnostic-package :none) - (setq-local flycheck-checker 'tex-chktex))) - - (add-hook 'LaTeX-mode-hook #'rainbow-delimiters-mode) - (add-hook 'LaTeX-mode-hook #'smartparens-mode) - (add-hook 'LaTeX-mode-hook #'prettify-symbols-mode) - - (my/set-smartparens-indent 'LaTeX-mode) - (require 'smartparens-latex) - - (general-nmap - :keymaps '(LaTeX-mode-map latex-mode-map) - "RET" 'TeX-command-run-all - "C-c t" 'orgtbl-mode) - - <> - <> - <> - <>) -#+end_src -*** BibTeX -#+begin_src emacs-lisp -(use-package ivy-bibtex - :commands (ivy-bibtex) - :straight t - :init - (my-leader-def "fB" 'ivy-bibtex)) - -(add-hook 'bibtex-mode 'smartparens-mode) -#+end_src -*** Import *.sty -A function to import =.sty= files to the LaTeX document. - -#+begin_src emacs-lisp -(defun my/list-sty () - (reverse - (sort - (seq-filter - (lambda (file) (if (string-match ".*\.sty$" file) 1 nil)) - (directory-files - (seq-some - (lambda (dir) - (if (and - (f-directory-p dir) - (seq-some - (lambda (file) (string-match ".*\.sty$" file)) - (directory-files dir)) - ) dir nil)) - (list "./styles" "../styles/" "." "..")) :full)) - (lambda (f1 f2) - (let ((f1b (file-name-base f1)) - (f1b (file-name-base f2))) - (cond - ((string-match-p ".*BibTex" f1) t) - ((and (string-match-p ".*Locale" f1) (not (string-match-p ".*BibTex" f2))) t) - ((string-match-p ".*Preamble" f2) t) - (t (string-lessp f1 f2)))))))) - -(defun my/import-sty () - (interactive) - (insert - (apply #'concat - (cl-mapcar - (lambda (file) (concat "\\usepackage{" (file-name-sans-extension (file-relative-name file default-directory)) "}\n")) - (my/list-sty))))) - -(defun my/import-sty-org () - (interactive) - (insert - (apply #'concat - (cl-mapcar - (lambda (file) (concat "#+LATEX_HEADER: \\usepackage{" (file-name-sans-extension (file-relative-name file default-directory)) "}\n")) - (my/list-sty))))) -#+end_src -*** Snippets -| Note | Type | -|------+-----------------------------------------------------------------| -| TODO | Move yasnippet snippets here? Maybe extract to a separate file? | -**** Greek letters -Autogenerate snippets for greek letters. I have a few blocks like this because it's faster & more flexible than usual yasnippet snippets. - -Noweb points to the AUCTeX config block. - -#+begin_src emacs-lisp :noweb-ref init-greek-latex-snippets -(setq my/greek-alphabet - '(("a" . "\\alpha") - ("b" . "\\beta" ) - ("g" . "\\gamma") - ("d" . "\\delta") - ("e" . "\\epsilon") - ("z" . "\\zeta") - ("h" . "\\eta") - ("o" . "\\theta") - ("i" . "\\iota") - ("k" . "\\kappa") - ("l" . "\\lambda") - ("m" . "\\mu") - ("n" . "\\nu") - ("x" . "\\xi") - ("p" . "\\pi") - ("r" . "\\rho") - ("s" . "\\sigma") - ("t" . "\\tau") - ("u" . "\\upsilon") - ("f" . "\\phi") - ("c" . "\\chi") - ("v" . "\\psi") - ("g" . "\\omega"))) - -(setq my/latex-greek-prefix "'") - -;; The same for capitalized letters -(dolist (elem my/greek-alphabet) - (let ((key (car elem)) - (value (cdr elem))) - (when (string-equal key (downcase key)) - (add-to-list 'my/greek-alphabet - (cons - (capitalize (car elem)) - (concat - (substring value 0 1) - (capitalize (substring value 1 2)) - (substring value 2))))))) - -(yas-define-snippets - 'latex-mode - (mapcar - (lambda (elem) - (list (concat my/latex-greek-prefix (car elem)) (cdr elem) (concat "Greek letter " (car elem)))) - my/greek-alphabet)) -#+end_src -**** English letters -#+begin_src emacs-lisp :noweb-ref init-english-latex-snippets -(setq my/english-alphabet - '("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z")) - -(dolist (elem my/english-alphabet) - (when (string-equal elem (downcase elem)) - (add-to-list 'my/english-alphabet (upcase elem)))) - -(setq my/latex-mathbb-prefix "`") - -(yas-define-snippets - 'latex-mode - (mapcar - (lambda (elem) - (list (concat my/latex-mathbb-prefix elem) (concat "\\mathbb{" elem "}") (concat "Mathbb letter " elem))) - my/english-alphabet)) -#+end_src -**** Math symbols -#+begin_src emacs-lisp :noweb-ref init-math-latex-snippets -(setq my/latex-math-symbols - '(("x" . "\\times") - ("." . "\\cdot") - ("v" . "\\forall") - ("s" . "\\sum_{$1}^{$2}$0") - ("p" . "\\prod_{$1}^{$2}$0") - ("d" . "\\partial") - ("e" . "\\exists") - ("i" . "\\int_{$1}^{$2}$0") - ("c" . "\\cap") - ("u" . "\\cup") - ("0" . "\\emptyset") - ("^" . "\\widehat{$1}$0") - ("_" . "\\overline{$1}$0") - ("~" . "\\sim") - ("|" . "\\mid") - ("_|" . "\\perp"))) - -(setq my/latex-math-prefix ";") - -(yas-define-snippets - 'latex-mode - (mapcar - (lambda (elem) - (let ((key (car elem)) - (value (cdr elem))) - (list (concat my/latex-math-prefix key) value (concat "Math symbol " value)))) - my/latex-math-symbols)) -#+end_src -**** Section snippets -Section snippets. The code turned out to be more complicated than just writing the snippets by hand. - -#+begin_src emacs-lisp :noweb-ref init-section-latex-snippets -(setq my/latex-section-snippets - '(("ch" . "\\chapter{$1}") - ("sec" . "\\section{$1}") - ("ssec" . "\\subsection{$1}") - ("sssec" . "\\subsubsection{$1}") - ("par" . "\\paragraph{$1}}"))) - -(setq my/latex-section-snippets - (mapcar - (lambda (elem) - `(,(car elem) - ,(cdr elem) - ,(progn - (string-match "[a-z]+" (cdr elem)) - (match-string 0 (cdr elem))))) - my/latex-section-snippets)) - -(dolist (elem my/latex-section-snippets) - (let* ((key (nth 0 elem)) - (value (nth 1 elem)) - (desc (nth 2 elem)) - (star-index (string-match "\{\$1\}" value))) - (add-to-list 'my/latex-section-snippets - `(,(concat key "*") - ,(concat - (substring value 0 star-index) - "*" - (substring value star-index)) - ,(concat desc " with *"))) - (add-to-list 'my/latex-section-snippets - `(,(concat key "l") - ,(concat value "%\n\\label{sec:$2}") - ,(concat desc " with label"))))) - -(dolist (elem my/latex-section-snippets) - (setf (nth 1 elem) (concat (nth 1 elem) "\n$0"))) - -(yas-define-snippets - 'latex-mode - my/latex-section-snippets) -#+end_src -** Other markup languages -*** Markdown -#+begin_src emacs-lisp -(use-package markdown-mode - :straight t - :mode "\\.md\\'" - :config - (setq markdown-command - (concat - "pandoc" - " --from=markdown --to=html" - " --standalone --mathjax --highlight-style=pygments" - " --css=pandoc.css" - " --quiet" - )) - (setq markdown-live-preview-delete-export 'delete-on-export) - (setq markdown-asymmetric-header t) - (setq markdown-open-command "/home/pavel/bin/scripts/chromium-sep") - (add-hook 'markdown-mode-hook #'smartparens-mode) + (setq truncate-lines t) + (visual-line-mode nil))) (general-define-key - :keymaps 'markdown-mode-map - "M-" 'markdown-promote - "M-" 'markdown-demote)) + :states '(normal) + :keymaps 'dired-mode-map + "h" 'dired-up-directory + "l" 'dired-find-file + "=" 'dired-narrow + "-" 'dired-create-empty-file + "~" 'vterm + "" 'dired-up-directory + "" 'dired-find-file + "M-" 'dired-open-xdg)) -;; (use-package livedown -;; :straight (:host github :repo "shime/emacs-livedown") -;; :commands livedown-preview -;; :config -;; (setq livedown-browser "qutebrowser")) - -#+end_src -*** PlantUML -| Guix dependency | -|-----------------| -| plantuml | - -#+begin_src emacs-lisp -(use-package plantuml-mode - :straight t - :mode "(\\.\\(plantuml?\\|uml\\|puml\\)\\'" - :config - (setq plantuml-executable-path "/home/pavel/.guix-extra-profiles/emacs/emacs/bin/plantuml") - (setq plantuml-default-exec-mode 'executable) - (setq plantuml-indent-level 2) - (setq my/plantuml-indent-regexp-return "^\s*return\s+.+$") - (add-to-list - 'plantuml-indent-regexp-end - my/plantuml-indent-regexp-return) - (add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode)) - (add-to-list 'auto-mode-alist '("\\.uml\\'" . plantuml-mode)) - (add-hook 'plantuml-mode-hook #'smartparens-mode)) - -(general-nmap - :keymaps 'plantuml-mode-map - "RET" 'plantuml-preview) -#+end_src -*** LanguageTool -LanguageTool is a great offline spell checker. For some reason, the download link is nowhere to be found on the home page, so it is listed in the references as well. - -References: -- [[https://languagetool.org/][LanguageTool homepage]] -- [[https://dev.languagetool.org/http-server][LanguageTool http server]] -#+begin_src emacs-lisp -(use-package langtool - :straight t - :commands (langtool-check) - :config - (setq langtool-language-tool-server-jar "/home/pavel/bin/LanguageTool-5.4/languagetool-server.jar") - (setq langtool-mother-tongue "ru") - (setq langtool-default-language "en-US")) +(defun my/dired-home () + "Open dired at $HOME" + (interactive) + (dired (expand-file-name "~"))) (my-leader-def - :infix "L" - "" '(:which-key "languagetool") - "c" 'langtool-check - "s" 'langtool-server-stop - "d" 'langtool-check-done - "n" 'langtool-goto-next-error - "p" 'langtool-goto-previous-error - "l" 'langtool-correct-buffer) + "ad" #'dired + "aD" #'my/dired-home) #+end_src -** Lisp -These are your father's parentheses. Elegant weapons for a more... civilized age. -*** Meta Lisp -Some packages for editing various Lisps. +*** Addons +I used to use [[https://www.emacswiki.org/emacs/DiredPlus][dired+]], which provides a lot of extensions for dired functionality, but it also creates some new problems, so I opt out of it. Fortunately, the one feature I want from this package - adding more colors to dired buffers - is available as a separate package. + #+begin_src emacs-lisp -(use-package lispy - :commands (lispy-mode) +(use-package diredfl + :straight t + :after dired + :config + (diredfl-global-mode 1)) +#+end_src + ++Reuse the current dired buffer instead of spamming new ones.+ Looks like not neccesary with Emacs 28.1 +#+begin_src emacs-lisp +(use-package dired-single + :after dired + :disabled :straight t) + #+end_src -(use-package lispyville - :hook (lispy-mode . lispyville-mode) - :straight t) +Display icons for files. -(sp-with-modes sp-lisp-modes - (sp-local-pair "'" nil :actions nil)) -#+end_src -*** Emacs Lisp -**** Package Lint -A package that checks for the metadata in Emacs Lisp packages. +| Note | Type | +|-----------+----------------------------------------------------------| +| *ACHTUNG* | This plugin is slow as hell with TRAMP or in =gnu/store= | #+begin_src emacs-lisp -(use-package flycheck-package +(use-package all-the-icons-dired :straight t - :after flycheck + :if (not (or my/lowpower my/slow-ssh (not (display-graphic-p)))) + :hook (dired-mode . (lambda () + (unless (string-match-p "/gnu/store" default-directory) + (all-the-icons-dired-mode)))) :config - (flycheck-package-setup)) + (advice-add 'dired-add-entry :around #'all-the-icons-dired--refresh-advice) + (advice-add 'dired-remove-entry :around #'all-the-icons-dired--refresh-advice) + (advice-add 'dired-kill-subdir :around #'all-the-icons-dired--refresh-advice)) #+end_src -**** General settings + +Provides stuff like =dired-open-xdg= #+begin_src emacs-lisp -(add-hook 'emacs-lisp-mode-hook #'aggressive-indent-mode) -;; (add-hook 'emacs-lisp-mode-hook #'smartparens-strict-mode) -(add-hook 'emacs-lisp-mode-hook #'lispy-mode) -#+end_src -*** Common lisp -**** SLIME -#+begin_src emacs-lisp -(use-package slime +(use-package dired-open :straight t + :commands (dired-open-xdg)) +#+end_src + +vifm-like filter +#+begin_src emacs-lisp +(use-package dired-narrow + :straight t + :commands (dired-narrow) :config - (setq inferior-lisp-program "sbcl") - (add-hook 'slime-repl-mode 'smartparens-mode)) + (general-define-key + :keymaps 'dired-narrow-map + [escape] 'keyboard-quit)) #+end_src -**** General settings + +Display git info, such as the last commit for file and stuff. It's pretty useful but also slows down Dired a bit, hence I don't turn it out by default. #+begin_src emacs-lisp -(add-hook 'lisp-mode-hook #'aggressive-indent-mode) -;; (add-hook 'emacs-lisp-mode-hook #'smartparens-strict-mode) -(add-hook 'lisp-mode-hook #'lispy-mode) -#+end_src -*** Clojure -#+begin_src emacs-lisp -(use-package clojure-mode +(use-package dired-git-info :straight t - :mode "\\.clj[sc]?\\'" + :after dired + :if (not my/slow-ssh) :config - ;; (add-hook 'clojure-mode-hook #'smartparens-strict-mode) - (add-hook 'clojure-mode-hook #'lispy-mode) - (add-hook 'clojure-mode-hook #'aggressive-indent-mode)) - -(use-package cider - :mode "\\.clj[sc]?\\'" - :straight t) + (general-define-key + :keymap 'dired-mode-map + :states '(normal emacs) + ")" 'dired-git-info-mode)) #+end_src -*** Hy -Python requirements: -- =hy= -- =jedhy= +*** Subdirectories +Subdirectories are one of the interesting features of Dired. It allows displaying multiple folders on the same window. + +I add my own keybindings and some extra functionality. #+begin_src emacs-lisp -(use-package hy-mode - :straight t - :mode "\\.hy\\'" +(defun my/dired-open-this-subdir () + (interactive) + (dired (dired-current-directory))) + +(defun my/dired-kill-all-subdirs () + (interactive) + (let ((dir dired-directory)) + (kill-buffer (current-buffer)) + (dired dir))) + +(with-eval-after-load 'dired + (general-define-key + :states '(normal) + :keymaps 'dired-mode-map + "s" nil + "ss" 'dired-maybe-insert-subdir + "sl" 'dired-maybe-insert-subdir + "sq" 'dired-kill-subdir + "sk" 'dired-prev-subdir + "sj" 'dired-next-subdir + "sS" 'my/dired-open-this-subdir + "sQ" 'my/dired-kill-all-subdirs + (kbd "TAB") 'dired-hide-subdir)) +#+end_src +*** TRAMP +TRAMP is a package that provides remote editing capacities. It is particularly useful for remote server management. + +One of the reasons why TRAMP may be slow is that some plugins do too many requests to the filesystem. To debug these issues, set the following variable to 6: +#+begin_src emacs-lisp +(setq tramp-verbose 1) +#+end_src + +To check if a file is remote, you can use ~file-remote-p~. E.g. ~(file-remote-p default-directory)~ for a current buffer. The problem with this approach is that it's rather awkward to add these checks in every hook, especially for global modes, so for now, I just set an environment variable for Emacs which disables these modes. + +So far I have found the following problematic plugins: +| Plugin | Note | Solution | +|---------------------+------------------------------------------+-------------------------------| +| editorconfig | looks for .editorconfig in the file tree | do not enable globally | +| all-the-icons-dired | runs test on every file in the directory | disable | +| projectile | looks for .git, .svn, etc | advice ~projectile-file-name~ | +| lsp | does a whole lot of stuff | disable | +| git-gutter | runs git | disable | +| vterm | no proper TRAMP integration | use eshell or shell | + +At any rate, it's usable, although not perfect. + +Some other optimization settings: +#+begin_src emacs-lisp +(setq remote-file-name-inhibit-cache nil) +(setq vc-ignore-dir-regexp + (format "\\(%s\\)\\|\\(%s\\)" + vc-ignore-dir-regexp + tramp-file-name-regexp)) +#+end_src + +Set the default shell to =bin/bash= for TRAMP or on a remote server. +#+begin_src emacs-lisp +(when (or my/remote-server my/slow-ssh) + (setq explicit-shell-file-name "/bin/bash")) +#+end_src + +Also, here is a hack to make TRAMP find =ls= on Guix: +#+begin_src emacs-lisp +(with-eval-after-load 'tramp + (setq tramp-remote-path + (append tramp-remote-path + '(tramp-own-remote-path)))) +#+end_src +*** Bookmarks +A simple bookmark list for Dired, mainly to use with TRAMP. I may look into a proper bookmarking system later. + +Bookmarks are listed in the [[file:.emacs.d/private.el][private.el]] file, which has an expression like this: +#+begin_example emacs-lisp :tangle no +(setq my/dired-bookmarks + '(("sudo" . "/sudo::/"))) +#+end_example + +The file itself is encrypted with yadm. +#+begin_src emacs-lisp +(defun my/dired-bookmark-open () + (interactive) + (let ((bookmarks + (mapcar + (lambda (el) (cons (format "%-30s %s" (car el) (cdr el)) (cdr el))) + my/dired-bookmarks))) + (dired + (cdr + (assoc + (completing-read "Dired: " bookmarks nil nil "^") + bookmarks))))) +#+end_src +** Shells +*** vterm +My terminal emulator of choice. + +References: +- [[https://github.com/akermu/emacs-libvterm][emacs-libvterm repo]] +**** Configuration +I use the package from the Guix repository to avoid building libvterm. + +#+begin_src emacs-lisp +(use-package vterm + ;; :straight t + :commands (vterm vterm-other-window) :config - (add-hook 'hy-mode-hook #'lispy-mode) - (add-hook 'hy-mode-hook #'aggressive-indent-mode)) + (setq vterm-kill-buffer-on-exit t) + + (add-hook 'vterm-mode-hook + (lambda () + (setq-local global-display-line-numbers-mode nil) + (display-line-numbers-mode 0))) + + + (advice-add 'evil-collection-vterm-insert + :before (lambda (&rest args) + (ignore-errors + (apply #'vterm-reset-cursor-point args)))) + + (general-define-key + :keymaps 'vterm-mode-map + "M-q" 'vterm-send-escape + + "C-h" 'evil-window-left + "C-l" 'evil-window-right + "C-k" 'evil-window-up + "C-j" 'evil-window-down + + "C-" 'evil-window-right + "C-" 'evil-window-left + "C-" 'evil-window-up + "C-" 'evil-window-down + + "M-" 'vterm-send-left + "M-" 'vterm-send-right + "M-" 'vterm-send-up + "M-" 'vterm-send-down) + + (general-define-key + :keymaps 'vterm-mode-map + :states '(normal insert) + "" 'vterm-beginning-of-line + "" 'vterm-end-of-line) + + (general-define-key + :keymaps 'vterm-mode-map + :states '(insert) + "C-r" 'vterm-send-C-r + "C-k" 'vterm-send-C-k + "C-j" 'vterm-send-C-j + "M-l" 'vterm-send-right + "M-h" 'vterm-send-left + "M-k" 'vterm-send-up + "M-j" 'vterm-send-down)) #+end_src -*** Scheme +**** Subterminal +Open a terminal in the lower third of the frame with the =`= key. + #+begin_src emacs-lisp -(use-package geiser +(add-to-list 'display-buffer-alist + `(,"vterm-subterminal.*" + (display-buffer-reuse-window + display-buffer-in-side-window) + (side . bottom) + (reusable-frames . visible) + (window-height . 0.33))) + +(defun my/toggle-vterm-subteminal () + "Toogle subteminal." + (interactive) + (let + ((vterm-window + (seq-find + (lambda (window) + (string-match + "vterm-subterminal.*" + (buffer-name (window-buffer window)))) + (window-list)))) + (if vterm-window + (if (eq (get-buffer-window (current-buffer)) vterm-window) + (kill-buffer (current-buffer)) + (select-window vterm-window)) + (vterm-other-window "vterm-subterminal")))) + +(unless my/slow-ssh + (general-nmap "`" 'my/toggle-vterm-subteminal) + (general-nmap "~" 'vterm)) +#+end_src +**** Dired integration +A function to get pwd for vterm. Couldn't find a built-in function for some reason, but this seems to be working fine: + +#+begin_src emacs-lisp +(defun my/vterm-get-pwd () + (if vterm--process + (file-truename (format "/proc/%d/cwd" (process-id vterm--process))) + default-directory)) +#+end_src + +Now we can open dired for vterm pwd: +#+begin_src emacs-lisp +(defun my/vterm-dired-other-window () + "Open dired in vterm pwd in other window" + (interactive) + (dired-other-window (my/vterm-get-pwd))) + +(defun my/vterm-dired-replace () + "Replace vterm with dired" + (interactive) + (let ((pwd (my/vterm-get-pwd))) + (kill-process vterm--process) + (dired pwd))) +#+end_src + +The second function is particularly handy because that way I can alternate between vterm and dired. + +Keybindings: +#+begin_src emacs-lisp +(with-eval-after-load 'vterm + (general-define-key + :keymaps 'vterm-mode-map + :states '(normal) + "gd" #'my/vterm-dired-other-window + "gD" #'my/vterm-dired-replace)) +#+end_src +**** With-editor integration +A package used by Magit to use the current Emacs instance as the =$EDITOR=. + +That is, with the help of [[file:Console.org::Functions][this function]], I can just write =e =, edit the file, and then return to the same vterm buffer. No more running vim inside Emacs. + +#+begin_src emacs-lisp +(use-package with-editor :straight t - :if (not my/lowpower) + :after (vterm) :config - (setq geiser-default-implementation 'guile)) - -(use-package geiser-guile - :straight t - :after geiser) - -(add-hook 'scheme-mode-hook #'aggressive-indent-mode) -(add-hook 'scheme-mode-hook #'lispy-mode) + (add-hook 'vterm-mode-hook 'with-editor-export-editor)) #+end_src -*** CLIPS -An honorary Lisp - +*** Eshell +A shell written in Emacs lisp. I don't use it as of now, but keep the config just in case. #+begin_src emacs-lisp -(use-package clips-mode - :straight t - :mode "\\.cl\\'" +(defun my/configure-eshell () + (add-hook 'eshell-pre-command-hook 'eshell-save-some-history) + (add-to-list 'eshell-output-filter-functions 'eshell-truncate-buffer) + (setq eshell-history-size 10000) + (setq eshell-hist-ingnoredups t) + (setq eshell-buffer-maximum-lines 10000) + + (evil-define-key '(normal insert visual) eshell-mode-map (kbd "") 'eshell-bol) + (evil-define-key '(normal insert visual) eshell-mode-map (kbd "C-r") 'counsel-esh-history) + (general-define-key + :states '(normal) + :keymaps 'eshell-mode-map + (kbd "C-h") 'evil-window-left + (kbd "C-l") 'evil-window-right + (kbd "C-k") 'evil-window-up + (kbd "C-j") 'evil-window-down)) + +(use-package eshell + :ensure nil + :after evil-collection + :commands (eshell) :config - (add-hook 'clips-mode 'lispy-mode)) -#+end_src -** Python -Use [[https://github.com/Microsoft/python-language-server][Microsoft Language Server for Python]]. + (add-hook 'eshell-first-time-mode-hook 'my/configure-eshell 90) + (when my/slow-ssh + (add-hook 'eshell-mode-hook + (lambda () + (setq-local company-idle-delay 1000)))) + (setq eshell-banner-message "")) -For some reason it doesn't use pipenv python executable, so here is a small workaround. -#+begin_src emacs-lisp -(setq my/pipenv-python-alist '()) +(use-package aweshell + :straight (:repo "manateelazycat/aweshell" :host github) + :after eshell + :config + (setq eshell-highlight-prompt nil) + (setq eshell-prompt-function 'epe-theme-pipeline)) -(defun my/get-pipenv-python () - (let ((default-directory (projectile-project-root))) - (if (file-exists-p "Pipfile") - (let ((asc (assoc default-directory my/pipenv-python-alist))) - (if asc - (cdr asc) - (let ((python-executable - (string-trim (shell-command-to-string "PIPENV_IGNORE_VIRTUALENVS=1 pipenv run which python 2>/dev/null")))) - (if (string-match-p ".*not found.*" python-executable) - (message "Pipfile found, but not pipenv executable!") - (message (format "Found pipenv python: %s" python-executable)) - (add-to-list 'my/pipenv-python-alist (cons default-directory python-executable)) - python-executable)))) - "python"))) - -(use-package lsp-pyright - :straight t +(use-package eshell-info-banner :defer t :if (not my/slow-ssh) - :hook (python-mode . (lambda () - (require 'lsp-pyright) - (setq-local lsp-pyright-python-executable-cmd (my/get-pipenv-python)) - (lsp)))) + :straight (eshell-info-banner :type git + :host github + :repo "phundrak/eshell-info-banner.el") + :hook (eshell-banner-load . eshell-info-banner-update-banner)) -(add-hook 'python-mode-hook #'smartparens-mode) -(add-hook 'python-mode-hook #'hs-minor-mode) +(when my/slow-ssh + (general-nmap "`" 'aweshell-dedicated-toggle) + (general-nmap "~" 'eshell)) #+end_src -*** pipenv -[[https://github.com/pypa/pipenv][Pipenv]] is a package manager for Python. - -Automatically creates & manages virtualenvs and stores data in =Pipfile= and =Pipfile.lock= (like npm's =package.json= and =package-lock.json=). - -#+begin_src emacs-lisp -(use-package pipenv - :straight t - :hook (python-mode . pipenv-mode) - :if (not my/slow-ssh) - :init - (setq - pipenv-projectile-after-switch-function - #'pipenv-projectile-after-switch-extended)) -#+end_src -*** yapf -[[https://github.com/google/yapf][yapf]] is a formatter for Python files. - -| Guix dependency | -|-----------------| -| python-yapf | - -References: -- [[https://github.com/google/yapf][yapf repo]] -- [[https://github.com/JorisE/yapfify][yapfify.el repo]] -#+begin_src emacs-lisp -(use-package yapfify - :straight (:repo "JorisE/yapfify" :host github) - :commands (yapfify-region - yapfify-buffer - yapfify-region-or-buffer - yapf-mode)) -#+end_src - -Global config: -#+begin_src conf-windows :tangle .config/yapf/style :comments link -[style] -based_on_style = facebook -column_limit = 80 -#+end_src -*** isort -[[https://github.com/PyCQA/isort][isort]] is a Python package to sort Python imports. - -| Guix dependency | -|-----------------| -| python-isort | - -References: -- [[https://pycqa.github.io/isort/][isort docs]] -- [[https://github.com/paetzke/py-isort.el][py-isort.el repo]] - -#+begin_src emacs-lisp -(use-package py-isort - :straight t - :commands (py-isort-buffer py-isort-region)) -#+end_src - -The following bindings calls yapf & isort on the buffer -#+begin_src emacs-lisp -(my-leader-def - :keymaps 'python-mode-map - "rr" (lambda () - (interactive) - (unless (and (fboundp #'org-src-edit-buffer-p) (org-src-edit-buffer-p)) - (py-isort-buffer)) - (yapfify-buffer))) -#+end_src -*** sphinx-doc -A package to generate sphinx-compatible docstrings. - -#+begin_src emacs-lisp -(use-package sphinx-doc - :straight t - :hook (python-mode . sphinx-doc-mode) - :config - (my-leader-def - :keymaps 'sphinx-doc-mode-map - "rd" 'sphinx-doc)) -#+end_src -*** pytest -[[https://docs.pytest.org/en/6.2.x/][pytest]] is an unit testing framework for Python. - -Once again a function to set pytest executable from pipenv. - -References: -- [[https://docs.pytest.org/en/6.2.x/][pytest docs]] -- [[https://github.com/wbolster/emacs-python-pytest][emacs-python-pytest]] - -#+begin_src emacs-lisp :noweb yes -(defun my/set-pipenv-pytest () - (setq-local - python-pytest-executable - (concat (my/get-pipenv-python) " -m pytest"))) - -(use-package python-pytest - :straight t - :commands (python-pytest-dispatch) - :init - (my-leader-def - :keymaps 'python-mode-map - :infix "t" - "t" 'python-pytest-dispatch) - :config - <> - (add-hook 'python-mode-hook #'my/set-pipenv-pytest) - (when (derived-mode-p 'python-mode) - (my/set-pipenv-pytest))) -#+end_src -**** Fix comint buffer width -For some reason default comint output width is way too large. - -To fix that, I've modified the following function in the =python-pytest= package. -#+begin_src emacs-lisp :noweb-ref override-pytest-run :tangle no -(cl-defun python-pytest--run-as-comint (&key command) - "Run a pytest comint session for COMMAND." - (let* ((buffer (python-pytest--get-buffer)) - (process (get-buffer-process buffer))) - (with-current-buffer buffer - (when (comint-check-proc buffer) - (unless (or compilation-always-kill - (yes-or-no-p "Kill running pytest process?")) - (user-error "Aborting; pytest still running"))) - (when process - (delete-process process)) - (let ((inhibit-read-only t)) - (erase-buffer)) - (unless (eq major-mode 'python-pytest-mode) - (python-pytest-mode)) - (compilation-forget-errors) - (display-buffer buffer) - (setq command (format "export COLUMNS=%s; %s" - (- (window-width (get-buffer-window buffer)) 5) - command)) - (insert (format "cwd: %s\ncmd: %s\n\n" default-directory command)) - (setq python-pytest--current-command command) - (when python-pytest-pdb-track - (add-hook - 'comint-output-filter-functions - 'python-pdbtrack-comint-output-filter-function - nil t)) - (run-hooks 'python-pytest-setup-hook) - (make-comint-in-buffer "pytest" buffer "bash" nil "-c" command) - (run-hooks 'python-pytest-started-hook) - (setq process (get-buffer-process buffer)) - (set-process-sentinel process #'python-pytest--process-sentinel)))) -#+end_src -*** code-cells -Support for text with magic comments. - -#+begin_src emacs-lisp -(use-package code-cells - :straight t - :commands (code-cells-mode)) -#+end_src -*** tensorboard -A function to start up [[https://www.tensorflow.org/tensorboard][TensorBoard]]. - -#+begin_src emacs-lisp -(setq my/tensorboard-buffer "TensorBoard-out") - -(defun my/tensorboard () - (interactive) - (start-process - "tensorboard" - my/tensorboard-buffer - "tensorboard" - "serve" - "--logdir" - (car (find-file-read-args "Directory: " t))) - (display-buffer my/tensorboard-buffer)) -#+end_src -** Java -#+begin_src emacs-lisp -(use-package lsp-java - :straight t - :after (lsp) - :config - (setq lsp-java-jdt-download-url "https://download.eclipse.org/jdtls/milestones/0.57.0/jdt-language-server-0.57.0-202006172108.tar.gz")) - -(add-hook 'java-mode-hook #'smartparens-mode) -;; (add-hook 'java-mode-hook #'hs-minor-mode) -(my/set-smartparens-indent 'java-mode) -#+end_src -** Go -#+begin_src emacs-lisp -(use-package go-mode - :straight t - :mode "\\.go\\'" - :config - (my/set-smartparens-indent 'go-mode) - (add-hook 'go-mode-hook #'smartparens-mode) - (add-hook 'go-mode-hook #'hs-minor-mode)) -#+end_src -** .NET -*** C# -| Guix dependencies | Disabled | -|-------------------+----------| -| omnisharp | t | -| dotnet | t | - -#+begin_src emacs-lisp -(use-package csharp-mode - :straight t - :mode "\\.cs\\'" - :config - (setq lsp-csharp-server-path (executable-find "omnisharp-wrapper")) - (add-hook 'csharp-mode-hook #'csharp-tree-sitter-mode) - (add-hook 'csharp-tree-sitter-mode-hook #'smartparens-mode) - (add-hook 'csharp-mode-hook #'hs-minor-mode) - (my/set-smartparens-indent 'csharp-tree-sitter-mode)) -#+end_src -*** MSBuild -#+begin_src emacs-lisp -(use-package csproj-mode - :straight t - :mode "\\.csproj\\'" - :config - (add-hook 'csproj-mode #'smartparens-mode)) -#+end_src -** fish -#+begin_src emacs-lisp -(use-package fish-mode - :straight t - :mode "\\.fish\\'" - :config - (add-hook 'fish-mode-hook #'smartparens-mode)) -#+end_src -** sh -#+begin_src emacs-lisp -(add-hook 'sh-mode-hook #'smartparens-mode) -#+end_src -** Haskell -#+begin_src emacs-lisp -(use-package haskell-mode - :straight t - :mode "\\.hs\\'") - -(use-package lsp-haskell - :straight t - :after (lsp haskell-mode)) -#+end_src -** Lua -#+begin_src emacs-lisp -(use-package lua-mode - :straight t - :mode "\\.lua\\'" - :hook (lua-mode . smartparens-mode)) - -(my/set-smartparens-indent 'lua-mode) -#+end_src -** JSON -#+begin_src emacs-lisp -(use-package json-mode - :straight t - :mode "\\.json\\'" - :config - (add-hook 'json-mode #'smartparens-mode) - (add-hook 'json-mode #'hs-minor-mode) - (my/set-smartparens-indent 'json-mode)) -#+end_src -** SQL -[[https://github.com/zeroturnaround/sql-formatter][sql-formatter]] is a nice JavaScript package for pretty-printing SQL queries. It is not packaged for Emacs, so the easiest way to use it seems to be to define a custom formatter via [[https://github.com/purcell/emacs-reformatter][reformatter]]. - -Also, I've a simple function to switch dialects because I often alternate between them. - -So far I didn't find a nice SQL client for Emacs, but I occasionally run SQL queries in Org Mode, so this qute package is handy. - -#+begin_src emacs-lisp -(setq my/sqlformatter-dialect-choice - '("db2" "mariadb" "mysql" "n1ql" "plsql" "postgresql" "redshift" "spark" "sql" "tsql")) - -(setq my/sqlformatter-dialect "postgresql") - -(defun my/sqlformatter-set-dialect () - "Set dialect for sql-formatter" - (interactive) - (setq my/sqlformatter-dialect - (completing-read "Dialect: " my/sqlformatter-dialect-choice))) - -(reformatter-define sqlformat - :program (executable-find "sql-formatter") - :args `("-l" ,my/sqlformatter-dialect, "-u")) - -(my-leader-def - :keymaps '(sql-mode-map) - "rr" #'sqlformat-buffer) -#+end_src -** YAML -#+begin_src emacs-lisp -(use-package yaml-mode - :straight t - :mode "\\.yml\\'" - :config - (add-hook 'yaml-mode-hook 'smartparens-mode) - (add-hook 'yaml-mode-hook 'highlight-indent-guides-mode) - (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))) -#+end_src -** .env -#+begin_src emacs-lisp -(use-package dotenv-mode - :straight t - :mode "\\.env\\..*\\'") -#+end_src -** CSV -#+begin_src emacs-lisp -(use-package csv-mode - :straight t - :mode "\\.csv\\'") -#+end_src -** OFF (OFF) PDF -A decent package to view PDFs in Emacs, but I prefer Zathura. - -References: -- https://github.com/vedang/pdf-tools/ - -#+begin_src emacs-lisp :tangle no -(use-package pdf-tools - :straight t - :commands (pdf-tools-install)) -#+end_src -** Docker -#+begin_src emacs-lisp -(use-package dockerfile-mode - :mode "Dockerfile\\'" - :straight t - :config - (add-hook 'dockerfile-mode 'smartparens-mode)) -#+end_src -** crontab -#+begin_src emacs-lisp -(use-package crontab-mode - :straight t) -#+end_src -* Apps & Misc ** Managing dotfiles A bunch of functions for managing dotfiles with yadm. @@ -6175,8 +6024,9 @@ My package for doing Pomodoro timer. #+begin_src emacs-lisp (use-package pomm - :straight (:host github :repo "SqrtMinusOne/pomm.el" :files (:defaults "resources")) - ;; :straight (:local-repo "~/Code/Emacs/pomm" :files (:defaults "resources")) + ;; :straight (:host github :repo "SqrtMinusOne/pomm.el" :files (:defaults "resources")) + :straight (:local-repo "~/Code/Emacs/pomm" :files (:defaults "resources")) + :commands (pomm) :init (my-leader-def "ap" #'pomm) :config