;;; -*- lexical-binding: t -*- (defvar bootstrap-version) (let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) (bootstrap-version 5)) (unless (file-exists-p bootstrap-file) (with-current-buffer (url-retrieve-synchronously "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" 'silent 'inhibit-cookies) (goto-char (point-max)) (eval-print-last-sexp))) (load bootstrap-file nil 'nomessage)) (straight-use-package 'use-package) (eval-when-compile (require 'use-package)) (setq my/slow-ssh (or (string= (getenv "IS_TRAMP") "true"))) (setq my/remote-server (or (string= (getenv "IS_REMOTE") "true") (string= (system-name) "dev-digital") (string= (system-name) "violet") (string= (system-name) "viridian"))) (setq my/is-termux (string-match-p (rx (* nonl) "com.termux" (* nonl)) (getenv "HOME"))) (setenv "IS_EMACS" "true") (defmacro with-eval-after-load-norem (file &rest body) (declare (indent 1) (debug (form def-body))) `(unless my/remote-server (with-eval-after-load ,file ,@body))) (setq my/emacs-started nil) (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 my/emacs-started t)) ;; (setq use-package-verbose t) (setq gc-cons-threshold 80000000) (setq read-process-output-max (* 1024 1024)) (add-hook 'emacs-startup-hook (lambda () (if (boundp 'after-focus-change-function) (add-function :after after-focus-change-function (lambda () (unless (frame-focus-state) (garbage-collect)))) (add-hook 'after-focus-change-function 'garbage-collect)))) (defun my/get-ram-usage-async (callback) (let* ((temp-buffer (generate-new-buffer "*ps*")) (proc (start-process "ps" temp-buffer "ps" "-p" (number-to-string (emacs-pid)) "-o" "rss"))) (set-process-sentinel proc (lambda (process _msg) (when (eq (process-status process) 'exit) (let* ((output (with-current-buffer temp-buffer (buffer-string))) (usage (string-to-number (nth 1 (split-string output "\n"))))) (ignore-errors (funcall callback usage))) (kill-buffer temp-buffer)))))) (defun my/ram-usage () (interactive) (my/get-ram-usage-async (lambda (data) (message "%f Gb" (/ (float data) 1024 1024))))) (use-package micromamba :straight (:local-repo "~/10-19 Code/12 My Emacs Packages/12.12 micromamba.el") :if (executable-find "micromamba") :config (micromamba-activate "general")) (setq custom-file (concat user-emacs-directory "custom.el")) (load custom-file 'noerror) (setq auth-source-debug nil) (let ((private-file (expand-file-name "private.el" user-emacs-directory))) (when (file-exists-p private-file) (load-file private-file))) (use-package no-littering :straight t) (setq confirm-kill-emacs 'y-or-n-p) (use-package general :straight t :config (general-evil-setup)) (use-package which-key :config (setq which-key-idle-delay 0.3) (setq which-key-popup-type 'frame) (which-key-mode) (which-key-setup-side-window-bottom) (set-face-attribute 'which-key-local-map-description-face nil :weight 'bold) :straight t) (defun my/dump-bindings-recursive (prefix &optional level buffer) (dolist (key (which-key--get-bindings (kbd prefix))) (with-current-buffer buffer (when level (insert (make-string level ? ))) (insert (apply #'format "%s%s%s\n" key))) (when (string-match-p (rx bos "+" (* nonl)) (substring-no-properties (elt key 2))) (my/dump-bindings-recursive (concat prefix " " (substring-no-properties (car key))) (+ 2 (or level 0)) buffer)))) (defun my/dump-bindings (prefix) "Dump keybindings starting with PREFIX in a tree-like form." (interactive "sPrefix: ") (let ((buffer (get-buffer-create "bindings"))) (with-current-buffer buffer (erase-buffer)) (my/dump-bindings-recursive prefix 0 buffer) (with-current-buffer buffer (goto-char (point-min))) (switch-to-buffer-other-window buffer))) (use-package evil :straight t :init (setq evil-want-integration t) (setq evil-want-C-u-scroll t) (setq evil-want-keybinding nil) (setq evil-search-module 'evil-search) (setq evil-split-window-below t) (setq evil-vsplit-window-right t) (unless (display-graphic-p) (setq evil-want-C-i-jump nil)) :config (evil-mode 1) ;; (setq evil-respect-visual-line-mode t) (evil-set-undo-system 'undo-tree)) (use-package evil-surround :straight t :after evil :config (global-evil-surround-mode 1)) (use-package evil-commentary :straight t :after evil :config (evil-commentary-mode)) (use-package evil-quickscope :straight t :after evil :config :hook ((prog-mode . turn-on-evil-quickscope-mode) (LaTeX-mode . turn-on-evil-quickscope-mode) (org-mode . turn-on-evil-quickscope-mode))) (use-package evil-numbers :straight t :commands (evil-numbers/inc-at-pt evil-numbers/dec-at-pt) :init (general-nmap "g+" 'evil-numbers/inc-at-pt "g-" 'evil-numbers/dec-at-pt)) (use-package evil-lion :straight t :config (setq evil-lion-left-align-key (kbd "g a")) (setq evil-lion-right-align-key (kbd "g A")) (evil-lion-mode)) (use-package evil-matchit :straight t :disabled :config (global-evil-matchit-mode 1)) (defun my/evil-ex-search-word-forward-other-window (count &optional symbol) (interactive (list (prefix-numeric-value current-prefix-arg) evil-symbol-word-search)) (save-excursion (evil-ex-start-word-search nil 'forward count symbol)) (other-window 1) (evil-ex-search-next)) (general-define-key :states '(normal) "&" #'my/evil-ex-search-word-forward-other-window) (use-package evil-collection :straight t :after evil :config (evil-collection-init '(eww devdocs proced emms pass calendar dired ivy debug guix calc docker ibuffer geiser pdf info elfeed edebug bookmark company vterm flycheck profiler cider explain-pause-mode notmuch custom xref eshell helpful compile comint git-timemachine magit prodigy slime forge deadgrep vc-annonate telega doc-view))) (use-package avy :straight t :config (setq avy-timeout-seconds 0.5) (setq avy-ignored-modes '(image-mode doc-view-mode pdf-view-mode exwm-mode)) (general-define-key :states '(normal motion) "-" nil "--" #'avy-goto-char-2 "-=" #'avy-goto-symbol-1)) (use-package ace-link :straight t :commands (ace-link-info ace-link-help ace-link-woman ace-link-eww)) (defun minibuffer-keyboard-quit () "Abort recursive edit. In Delete Selection mode, if the mark is active, just deactivate it; then it takes a second \\[keyboard-quit] to abort the minibuffer." (interactive) (if (and delete-selection-mode transient-mark-mode mark-active) (setq deactivate-mark t) (when (get-buffer "*Completions*") (delete-windows-on "*Completions*")) (abort-recursive-edit))) (defun my/escape-key () (interactive) (evil-ex-nohighlight) (keyboard-quit)) (general-define-key :keymaps '(normal visual global) [escape] #'my/escape-key) (general-define-key :keymaps '(minibuffer-local-map minibuffer-local-ns-map minibuffer-local-completion-map minibuffer-local-must-match-map minibuffer-local-isearch-map) [escape] 'minibuffer-keyboard-quit) (general-def :states '(normal insert visual) "" 'beginning-of-line "" 'end-of-line) (general-create-definer my-leader-def :keymaps 'override :prefix "SPC" :states '(normal motion emacs)) (general-def :states '(normal motion emacs) "SPC" nil "M-SPC" (general-key "SPC")) (general-def :states '(insert) "M-SPC" (general-key "SPC" :state 'normal)) (my-leader-def "?" 'which-key-show-top-level) (my-leader-def "E" 'eval-expression) (general-def :states '(insert) " e" #'eval-expression) (my-leader-def "SPC" '(:wk "second level") "SPC x" '(:wk "ctl-x") "SPC x" ctl-x-map) (my-leader-def "a" '(:which-key "apps")) (general-def :keymaps 'universal-argument-map "M-u" 'universal-argument-more) (general-def :keymaps 'override :states '(normal motion emacs insert visual) "M-u" 'universal-argument) (my-leader-def :infix "P" "" '(:which-key "profiler") "s" 'profiler-start "e" 'profiler-stop "p" 'profiler-report) (general-define-key :keymaps 'override "C-" 'evil-window-right "C-" 'evil-window-left "C-" 'evil-window-up "C-" 'evil-window-down "C-h" 'evil-window-left "C-l" 'evil-window-right "C-k" 'evil-window-up "C-j" 'evil-window-down "C-x h" 'previous-buffer "C-x l" 'next-buffer) (general-define-key :keymaps 'evil-window-map "x" 'kill-buffer-and-window "d" 'kill-current-buffer) (winner-mode 1) (general-define-key :keymaps 'evil-window-map "u" 'winner-undo "U" 'winner-redo) (my-leader-def :infix "b" "" '(:which-key "buffers") "s" '((lambda () (interactive) (switch-to-buffer (persp-scratch-buffer))) :which-key "*scratch*") "m" '((lambda () (interactive) (persp-switch-to-buffer "*Messages*")) :which-key "*Messages*") "l" 'next-buffer "h" 'previous-buffer "k" 'kill-buffer "b" 'persp-ivy-switch-buffer "r" 'revert-buffer "u" 'ibuffer) (general-nmap "gD" 'xref-find-definitions-other-window "gr" 'xref-find-references "gd" 'evil-goto-definition) (my-leader-def "fx" 'xref-find-apropos) (use-package xref :straight (:type built-in)) (general-nmap :keymaps '(hs-minor-mode-map outline-minor-mode-map) "ze" 'hs-hide-level "TAB" 'evil-toggle-fold) (defun my/zoom-in () "Increase font size by 10 points" (interactive) (set-face-attribute 'default nil :height (+ (face-attribute 'default :height) 10))) (defun my/zoom-out () "Decrease font size by 10 points" (interactive) (set-face-attribute 'default nil :height (- (face-attribute 'default :height) 10))) ;; change font size, interactively (global-set-key (kbd "C-+") 'my/zoom-in) (global-set-key (kbd "C-=") 'my/zoom-out) (unless my/remote-server (add-hook 'after-init-hook #'server-start)) (defmacro i3-msg (&rest args) `(start-process "emacs-i3-windmove" nil "i3-msg" ,@args)) (defun my/emacs-i3-windmove (dir) (let ((other-window (windmove-find-other-window dir))) (if (or (null other-window) (window-minibuffer-p other-window)) (i3-msg "focus" (symbol-name dir)) (windmove-do-window-select dir)))) (defun my/emacs-i3-direction-exists-p (dir) (cl-some (lambda (dir) (let ((win (windmove-find-other-window dir))) (and win (not (window-minibuffer-p win))))) (pcase dir ('width '(left right)) ('height '(up down))))) (defun my/emacs-i3-move-window (dir) (let ((other-window (windmove-find-other-window dir)) (other-direction (my/emacs-i3-direction-exists-p (pcase dir ('up 'width) ('down 'width) ('left 'height) ('right 'height))))) (cond ((and other-window (not (window-minibuffer-p other-window))) (window-swap-states (selected-window) other-window)) (other-direction (evil-move-window dir)) (t (i3-msg "move" (symbol-name dir)))))) (defun my/emacs-i3-resize-window (dir kind value) (if (or (one-window-p) (not (my/emacs-i3-direction-exists-p dir))) (i3-msg "resize" (symbol-name kind) (symbol-name dir) (format "%s px or %s ppt" value value)) (setq value (/ value 2)) (pcase kind ('shrink (pcase dir ('width (evil-window-decrease-width value)) ('height (evil-window-decrease-height value)))) ('grow (pcase dir ('width (evil-window-increase-width value)) ('height (evil-window-increase-height value))))))) (use-package transpose-frame :straight t :commands (transpose-frame)) (defun my/emacs-i3-integration (command) (pcase command ((rx bos "focus") (my/emacs-i3-windmove (intern (elt (split-string command) 1)))) ((rx bos "move") (my/emacs-i3-move-window (intern (elt (split-string command) 1)))) ((rx bos "resize") (my/emacs-i3-resize-window (intern (elt (split-string command) 2)) (intern (elt (split-string command) 1)) (string-to-number (elt (split-string command) 3)))) ("layout toggle split" (transpose-frame)) ("split h" (evil-window-split)) ("split v" (evil-window-vsplit)) ("kill" (evil-quit)) (- (i3-msg command)))) (use-package aggressive-indent :commands (aggressive-indent-mode) :straight t) (setq my/trailing-whitespace-modes '(markdown-mode)) (require 'cl-extra) (add-hook 'before-save-hook (lambda () (unless (cl-some #'derived-mode-p my/trailing-whitespace-modes) (delete-trailing-whitespace)))) (setq tab-always-indent nil) (setq-default default-tab-width 4) (setq-default tab-width 4) (setq-default evil-indent-convert-tabs nil) (setq-default indent-tabs-mode nil) (setq-default evil-shift-round nil) (setq scroll-conservatively scroll-margin) (setq scroll-step 1) (setq scroll-preserve-screen-position t) (setq scroll-error-top-bottom t) (setq mouse-wheel-progressive-speed nil) (setq mouse-wheel-inhibit-click-time nil) (setq select-enable-clipboard t) (setq mouse-yank-at-point t) (setq backup-inhibited t) (setq auto-save-default nil) (use-package undo-tree :straight t :config (global-undo-tree-mode) (setq undo-tree-visualizer-diff t) (setq undo-tree-visualizer-timestamps t) (setq undo-tree-auto-save-history nil) (my-leader-def "u" 'undo-tree-visualize) (fset 'undo-auto-amalgamate 'ignore) (setq undo-limit 6710886400) (setq undo-strong-limit 100663296) (setq undo-outer-limit 1006632960)) (use-package yasnippet-snippets :disabled :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) (my-leader-def :keymaps 'yas-minor-mode-map :infix "es" "" '(:wk "yasnippet") "n" #'yas-new-snippet "s" #'yas-insert-snippet "v" #'yas-visit-snippet-file)) (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 :commands (visual-fill-column-mode) :config (add-hook 'visual-fill-column-mode-hook (lambda () (setq visual-fill-column-center-text t)))) (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) (my-leader-def "p" '(:keymap projectile-command-map :which-key "projectile")) (general-nmap "C-p" 'counsel-projectile-find-file) (use-package magit :straight t :commands (magit-status magit-file-dispatch) :init (my-leader-def "m" 'magit "M" 'magit-file-dispatch) :config (setq magit-blame-styles '((headings (heading-format . "%-20a %C %s\n")) (highlight (highlight-face . magit-blame-highlight)) (lines (show-lines . t) (show-message . t))))) (use-package forge :after magit :straight t :config (add-to-list 'forge-alist '("gitlab.etu.ru" "gitlab.etu.ru/api/v4" "gitlab.etu.ru" forge-gitlab-repository))) (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)) (use-package editorconfig :straight t :config (unless my/slow-ssh (editorconfig-mode 1)) (add-to-list 'editorconfig-indentation-alist '(emmet-mode emmet-indentation))) (recentf-mode 1) (save-place-mode nil) (defun my/deadgrep-fix-buffer-advice (fun &rest args) (let ((buf (apply fun args))) (with-current-buffer buf (toggle-truncate-lines 1)) buf)) (use-package deadgrep :straight t :commands (deadgrep) :config (advice-add #'deadgrep--buffer :around #'my/deadgrep-fix-buffer-advice)) (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) (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 perspective-exwm-switch-perspective my/persp-ivy-switch-buffer-other-window lsp-execute-code-action dired-recent-open)) ;; 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 "d" 'deadgrep "A" 'counsel-ag) (general-define-key :states '(insert normal) "C-y" 'counsel-yank-pop) (defun my/swiper-isearch () (interactive) (if current-prefix-arg (swiper-all) (swiper-isearch))) (my-leader-def "SPC SPC" 'ivy-resume) (my-leader-def "s" 'my/swiper-isearch) (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 0.125) (setq company-dabbrev-downcase nil) (setq company-show-numbers t)) (general-imap "C-SPC" 'company-complete) (use-package company-box :straight t :if (display-graphic-p) :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 "h" '(:keymap help-map :which-key "help")) (my-leader-def :infix "h" "" '(:which-key "help") "h" '(:keymap help-map :which-key "help-map") "f" 'helpful-function "k" 'helpful-key "v" 'helpful-variable "o" 'helpful-symbol "i" 'info) (general-define-key :keymaps 'help-map "f" 'helpful-function "k" 'helpful-key "v" 'helpful-variable "o" 'helpful-symbol) (use-package wakatime-mode :straight (:host github :repo "SqrtMinusOne/wakatime-mode") :if (not (or my/remote-server)) :config (setq wakatime-ignore-exit-codes '(0 1 102)) (advice-add 'wakatime-init :after (lambda () (setq wakatime-cli-path (expand-file-name "~/bin/wakatime-cli")))) ;; (setq wakatime-cli-path (executable-find "wakatime")) (global-wakatime-mode)) (use-package request :straight t) (use-package activity-watch-mode :straight t :if (not (or my/is-termux my/remote-server)) :config (global-activity-watch-mode)) (unless my/is-termux (tool-bar-mode -1) (menu-bar-mode -1) (scroll-bar-mode -1)) (when my/is-termux (menu-bar-mode -1)) ;; (set-frame-parameter (selected-frame) 'alpha '(90 . 90)) ;; (add-to-list 'default-frame-alist '(alpha . (90 . 90))) ;; (global-prettify-symbols-mode) (setq use-dialog-box nil) (setq inhibit-startup-screen t) (setq visible-bell 0) (defalias 'yes-or-no-p 'y-or-n-p) (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) (setq word-wrap 1) (global-visual-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 olivetti :straight t :if (display-graphic-p) :config (setq-default olivetti-body-width 86)) (use-package keycast :straight t :config (define-minor-mode keycast-mode "Keycast mode" :global t (if keycast-mode (progn (add-to-list 'global-mode-string '("" keycast-mode-line " ")) (add-hook 'pre-command-hook 'keycast--update t) ) (remove-hook 'pre-command-hook 'keycast--update) (setq global-mode-string (delete '("" keycast-mode-line " ") global-mode-string))))) (use-package doom-themes :straight t :config (setq doom-themes-enable-bold t doom-themes-enable-italic t) (if my/remote-server (load-theme 'doom-gruvbox t) (load-theme 'doom-palenight t)) (doom-themes-visual-bell-config) (setq doom-themes-treemacs-theme "doom-colors") (doom-themes-treemacs-config)) (defun my/color-join (r g b) "Build a color from R G B. Inverse of `color-values'." (format "#%02x%02x%02x" (ash r -8) (ash g -8) (ash b -8))) (defun my/color-blend (c1 c2 &optional alpha) "Blend the two colors C1 and C2 with ALPHA. C1 and C2 are in the format of `color-values'. ALPHA is a number between 0.0 and 1.0 which corresponds to the influence of C1 on the result." (setq alpha (or alpha 0.5)) (apply #'my/color-join (cl-mapcar (lambda (x y) (round (+ (* x alpha) (* y (- 1 alpha))))) c1 c2))) (deftheme my-theme-1) (defvar my/doom-theme-update-colors-hook nil) (defmacro my/use-doom-colors (&rest data) `(progn (add-hook 'my/doom-theme-update-colors-hook (lambda () (custom-theme-set-faces 'my-theme-1 ,@(cl-loop for i in data collect `(,'\` (,(car i) ((t (,@(cl-loop for (key value) on (cdr i) by #'cddr append `(,key (,'\, ,value)))))))))))) (when (and (fboundp 'doom-color) my/emacs-started) (my/update-my-theme)))) (defun my/update-my-theme (&rest _) (run-hooks 'my/doom-theme-update-colors-hook) (enable-theme 'my-theme-1)) (unless my/is-termux (advice-add 'load-theme :after #'my/update-my-theme) (when (fboundp 'doom-color) (my/update-my-theme)) (add-hook 'emacs-startup-hook #'my/update-my-theme)) (my/use-doom-colors (tab-bar-tab :background (doom-color 'bg) :foreground (doom-color 'yellow) :underline (doom-color 'yellow)) (tab-bar :background nil :foreground nil)) (use-package auto-dim-other-buffers :straight t :if (display-graphic-p) :config (auto-dim-other-buffers-mode t) (my/use-doom-colors (auto-dim-other-buffers-face :background (color-darken-name (doom-color 'bg) 3)))) (defun my/toggle-dark-light-theme () (interactive) (let ((is-dark (member 'doom-palenight custom-enabled-themes))) (if is-dark (progn (load-theme 'doom-one-light t) (disable-theme 'doom-palenight)) (load-theme 'doom-palenight t) (disable-theme 'doom-one-light)))) (with-eval-after-load 'ansi-color (my/use-doom-colors (ansi-color-black :foreground (doom-color 'base2) :background (doom-color 'base0)) (ansi-color-red :foreground (doom-color 'red) :background (doom-color 'red)) (ansi-color-green :foreground (doom-color 'green) :background (doom-color 'green)) (ansi-color-yellow :foreground (doom-color 'yellow) :background (doom-color 'yellow)) (ansi-color-blue :foreground (doom-color 'dark-blue) :background (doom-color 'dark-blue)) (ansi-color-magenta :foreground (doom-color 'violet) :background (doom-color 'violet)) (ansi-color-cyan :foreground (doom-color 'dark-cyan) :background (doom-color 'dark-cyan)) (ansi-color-white :foreground (doom-color 'base8) :background (doom-color 'base8)) (ansi-color-bright-black :foreground (doom-color 'base5) :background (doom-color 'base5)) (ansi-color-bright-red :foreground (doom-color 'orange) :background (doom-color 'orange)) (ansi-color-bright-green :foreground (doom-color 'teal) :background (doom-color 'teal)) (ansi-color-bright-yellow :foreground (doom-color 'yellow) :background (doom-color 'yellow)) (ansi-color-bright-blue :foreground (doom-color 'blue) :background (doom-color 'blue)) (ansi-color-bright-magenta :foreground (doom-color 'magenta) :background (doom-color 'magenta)) (ansi-color-bright-cyan :foreground (doom-color 'cyan) :background (doom-color 'cyan)) (ansi-color-bright-white :foreground (doom-color 'fg) :background (doom-color 'fg)))) (when (display-graphic-p) (if (x-list-fonts "JetBrainsMono Nerd Font") (set-frame-font "JetBrainsMono Nerd Font 10" nil t) (message "Install JetBrainsMono Nerd Font!"))) (when (display-graphic-p) (set-face-attribute 'variable-pitch nil :family "Cantarell" :height 1.0)) (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/remote-server)) :hook ((prog-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 :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) (setq doom-modeline-persp-icon nil) (setq doom-modeline-persp-name nil) (setq doom-modeline-display-misc-in-all-mode-lines nil) :config (setq doom-modeline-minor-modes nil) (setq doom-modeline-irc nil) (setq doom-modeline-buffer-state-icon nil) (doom-modeline-mode 1)) (use-package perspective :straight t :init ;; (setq persp-show-modestring 'header) (setq persp-sort 'created) (setq persp-suppress-no-prefix-key-warning t) :config (persp-mode) (my-leader-def "x" '(:keymap perspective-map :which-key "perspective")) (general-define-key :keymaps 'override :states '(normal emacs) "gt" 'persp-next "gT" 'persp-prev "gn" 'persp-switch "gN" 'persp-kill) (general-define-key :keymaps 'perspective-map "b" 'persp-ivy-switch-buffer "x" 'persp-ivy-switch-buffer "u" 'persp-ibuffer)) (defun my/persp-move-window-and-switch () (interactive) (let* ((buffer (current-buffer))) (call-interactively #'persp-switch) (persp-set-buffer (buffer-name buffer)) (switch-to-buffer buffer))) (defun my/persp-copy-window-and-switch () (interactive) (let* ((buffer (current-buffer))) (call-interactively #'persp-switch) (persp-add-buffer (buffer-name buffer)) (switch-to-buffer buffer))) (defun my/persp-ivy-switch-buffer-other-window (arg) (interactive "P") (declare-function ivy-switch-buffer-other-window "ivy.el") (persp--switch-buffer-ivy-counsel-helper arg (lambda () (ivy-read "Switch to buffer in other window: " #'internal-complete-buffer :keymap ivy-switch-buffer-map :preselect (buffer-name (other-buffer (current-buffer))) :action #'ivy--switch-buffer-other-window-action :matcher #'ivy--switch-buffer-matcher :caller 'ivy-switch-buffer)))) (with-eval-after-load 'perspective (general-define-key :keymaps 'perspective-map "m" #'my/persp-move-window-and-switch "f" #'my/persp-copy-window-and-switch)) (setq my/perspective-assign-alist '()) (defvar my/perspective-assign-ignore nil "If non-nil, ignore `my/perspective-assign'") (defun my/perspective-assign () (when-let* ((_ (not my/perspective-assign-ignore)) (rule (alist-get major-mode my/perspective-assign-alist))) (let ((workspace-index (car rule)) (persp-name (cadr rule)) (buffer (current-buffer))) (if (fboundp #'perspective-exwm-assign-window) (progn (perspective-exwm-assign-window :workspace-index workspace-index :persp-name persp-name) (when workspace-index (exwm-workspace-switch workspace-index)) (when persp-name (persp-switch persp-name))) (with-perspective persp-name (persp-set-buffer buffer)) (persp-switch-to-buffer buffer))))) (defun my/perspective-assign-ignore-advice (fun &rest args) (let ((my/perspective-assign-ignore t)) (apply fun args))) (add-hook 'after-change-major-mode-hook #'my/perspective-assign) (defmacro my/persp-add-rule (&rest body) (declare (indent 0)) (unless (= (% (length body) 3) 0) (error "Malformed body in my/persp-add-rule")) (let (result) (while body (let ((major-mode (pop body)) (workspace-index (pop body)) (persp-name (pop body))) (push `(add-to-list 'my/perspective-assign-alist '(,major-mode . (,workspace-index ,persp-name))) result))) `(progn ,@result))) (defmacro my/command-in-persp (command-name persp-name workspace-index &rest args) `'((lambda () (interactive) (when (and ,workspace-index (fboundp #'exwm-workspace-switch-create)) (exwm-workspace-switch-create ,workspace-index)) (persp-switch ,persp-name) (delete-other-windows) ,@args) :wk ,command-name)) (use-package treemacs :straight t :defer t :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 "q" #'treemacs-quit) (general-define-key :keymaps 'treemacs-mode-map :states '(normal emacs) "q" 'treemacs-quit)) (use-package treemacs-evil :after (treemacs evil) :straight t) (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) :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) (setq lsp-modeline-code-actions-enable nil) (setq lsp-modeline-diagnostics-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 (or my/remote-server my/is-termux)) :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 :if (not (or my/remote-server my/is-termux)) :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) (require 'dap-php) (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-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))))) (defun my/exwm-perspective-find-buffer (path) "Find a buffer with PATH in all EXWM perspectives. Returns ( . ) or nil." (let* ((buf (cl-loop for buf being buffers if (and (buffer-file-name buf) (f-equal-p (buffer-file-name buf) path)) return buf)) (target-workspace (and buf (cl-loop for frame in exwm-workspace--list if (with-selected-frame frame (cl-loop for persp-name being the hash-keys of (perspectives-hash) if (member buf (persp-buffers (gethash persp-name (perspectives-hash)))) return persp-name)) return (cl-position frame exwm-workspace--list))))) (when target-workspace (cons buf target-workspace)))) (defun my/dap--go-to-stack-frame-override (debug-session stack-frame) "Make STACK-FRAME the active STACK-FRAME of DEBUG-SESSION." (with-lsp-workspace (dap--debug-session-workspace debug-session) (when stack-frame (-let* (((&hash "line" line "column" column "name" name) stack-frame) (path (dap--get-path-for-frame stack-frame))) (setf (dap--debug-session-active-frame debug-session) stack-frame) ;; If we have a source file with path attached, open it and ;; position the point in the line/column referenced in the ;; stack trace. (if (and path (file-exists-p path)) (progn (let ((exwm-target (my/exwm-perspective-find-buffer path))) (if exwm-target (progn (unless (= (cdr exwm-target) exwm-workspace-current-index) (exwm-workspace-switch (cdr exwm-target))) (persp-switch-to-buffer (car exwm-target))) (select-window (get-mru-window (selected-frame) nil)) (find-file path))) (goto-char (point-min)) (forward-line (1- line)) (forward-char column)) (message "No source code for %s. Cursor at %s:%s." name line column)))) (run-hook-with-args 'dap-stack-frame-changed-hook debug-session))) (with-eval-after-load 'exwm (with-eval-after-load 'dap-mode (advice-add #'dap--go-to-stack-frame :override #'my/dap--go-to-stack-frame-override))) ;; (advice-remove #'dap--go-to-stack-frame #'my/dap--go-to-stack-frame-override) (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/copilot-tab () (interactive) (or (copilot-accept-completion) (when (my/should-run-emmet-p) (my/emmet-or-tab)) (when (and (eq evil-state 'normal) (or hs-minor-mode outline-minor-mode)) (evil-toggle-fold) t) (indent-for-tab-command))) (use-package copilot :straight (:host github :repo "SqrtMinusOne/copilot.el" :files ("dist" "*.el")) :commands (copilot-mode) :if (not (or my/remote-server my/is-termux)) :init (add-hook 'prog-mode-hook #'copilot-mode) :config (setq copilot-node-executable "/home/pavel/.conda/envs/traject/bin/node") (general-define-key :keymaps 'company-active-map "" #'my/copilot-tab) (general-define-key :keymaps 'copilot-mode-map "" #'my/copilot-tab "M-j" #'copilot-accept-completion-by-line "M-l" #'copilot-accept-completion-by-word) (setq copilot-lispy-integration 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)) (defun my/should-run-emmet-p () (and (bound-and-true-p emmet-mode) (or (and (derived-mode-p 'web-mode) (member (web-mode-language-at-pos) '("html" "css"))) (not (derived-mode-p 'web-mode))))) (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 (defun my/emmet-or-tab (&optional arg) (interactive) (if (my/should-run-emmet-p) (or (emmet-expand-line arg) (emmet-go-to-edit-point 1) (indent-for-tab-command arg)) (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 "d" #'jest-test-debug-run-at-point "r" #'jest-test-run "a" #'jest-test-run-all-tests) (defmacro my/jest-test-with-debug-flags (form) "Execute FORM with debugger flags set." (declare (indent 0)) `(let ((jest-test-options (seq-concatenate 'list jest-test-options (list "--runInBand") )) (jest-test-npx-options (seq-concatenate 'list jest-test-npx-options (list "--node-options" "--inspect-brk")))) ,form)) (defun my/jest-test-debug () "Run the test with an inline debugger attached." (interactive) (my/jest-test-with-debug-flags (jest-test-run))) (defun my/jest-test-debug-rerun-test () "Run the test with an inline debugger attached." (interactive) (my/jest-test-with-debug-flags (jest-test-rerun-test))) (defun my/jest-test-debug-run-at-point () "Run the test with an inline debugger attached." (interactive) (my/jest-test-with-debug-flags (jest-test-run-at-point))) (advice-add #'jest-test-debug :override #'my/jest-test-debug) (advice-add #'jest-test-debug-rerun-test :override #'my/jest-test-debug-rerun-test) (advice-add #'jest-test-debug-run-at-point :override #'my/jest-test-debug-run-at-point)) (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-unit-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 :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) (setq web-mode-auto-pairs nil)) (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 (&rest _) (when (string-match-p (rx ".vue" eos) (buffer-name)) (setq-local web-mode-script-padding 0) (setq-local web-mode-style-padding 0) (setq-local create-lockfiles nil) (setq-local web-mode-enable-auto-pairing nil))) (add-hook 'web-mode-hook 'my/web-mode-vue-setup) (add-hook 'editorconfig-after-apply-functions 'my/web-mode-vue-setup) (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\\'" :config (add-hook 'php-mode-hook #'smartparens-mode) (add-hook 'php-mode-hook #'lsp) (my/set-smartparens-indent 'php-mode)) (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) (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)) (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) (general-define-key :keymaps 'markdown-mode-map "M-" 'markdown-promote "M-" 'markdown-demote)) ;; (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 subed :straight (:host github :repo "rndusr/subed" :files ("subed/*.el") :build (:not native-compile)) :config (general-define-key :keymaps '(subed-mode-map subed-vtt-mode-map) :states '(normal) "gp" #'subed-mpv-toggle-pause)) (use-package lsp-ltex :straight t :after (lsp) :init (setq lsp-ltex-version "15.2.0") (setq lsp-ltex-check-frequency "save")) (defun my/ltex-lang () (interactive) (setq lsp-ltex-language (completing-read "Language: " '("en-US" "ru-RU" "de-DE"))) (lsp-workspace-restart (lsp--read-workspace))) (defun my/ltex-need-p () (let ((file-name (buffer-file-name))) (cond ((null file-name) nil) ((string-match-p (rx "/home/pavel/" (+ alnum) ".org" eos) file-name) nil) ((string-match-p (rx (literal org-directory) "/" (or "roam" "inbox-notes" "literature-notes" "journal")) file-name) t) ((string-match-p (rx (literal org-directory)) file-name) nil) ((string-match-p (rx (literal (expand-file-name user-emacs-directory))) file-name) nil) (t t)))) (defun my/text-mode-lsp-maybe () (when (my/ltex-need-p) (lsp))) (add-hook 'text-mode-hook #'my/text-mode-lsp-maybe) (use-package langtool :straight t :commands (langtool-check) :config (setq langtool-language-tool-server-jar "/home/pavel/bin/LanguageTool-5.7/languagetool-server.jar") (setq langtool-mother-tongue "ru") (setq langtool-default-language "en-US")) (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 reverso :straight (:host github :repo "SqrtMinusOne/reverso.el") :init (my-leader-def "ar" #'reverso) :config (setq reverso-languages '(russian english german))) (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) (defun advice-unadvice (sym) "Remove all advices from symbol SYM." (interactive "aFunction symbol: ") (advice-mapc (lambda (advice _props) (advice-remove sym advice)) sym)) (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 :after clojure-mode :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 :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\\'" :disabled t :config (add-hook 'clips-mode 'lispy-mode)) (use-package ein :straight t) (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) :hook (python-mode . (lambda () (require 'lsp-pyright) (setq-local lsp-pyright-python-executable-cmd (my/get-pipenv-python)) (lsp)))) (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) :disabled :commands (yapfify-region yapfify-buffer yapfify-region-or-buffer yapf-mode)) (use-package python-black :straight t :commands (python-black-buffer) :config (setq python-black-command "black")) (use-package py-isort :straight t :commands (py-isort-buffer py-isort-region)) (my-leader-def :keymaps 'python-mode-map "rr" (lambda () (interactive) (save-excursion (unless (and (fboundp #'org-src-edit-buffer-p) (org-src-edit-buffer-p)) (py-isort-buffer)) (python-black-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 code-cells-convert-ipynb)) (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 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)) (use-package csv-mode :straight t :mode "\\.csv\\'") (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 gitignore-templates :straight t :commands (gitignore-templates-insert gitignore-templates-new-file)) (use-package dockerfile-mode :mode "Dockerfile\\'" :straight t :config (add-hook 'dockerfile-mode 'smartparens-mode)) (use-package jenkinsfile-mode :straight t :config (add-hook 'jenkinsfile-mode-hook #'smartparens-mode) (my/set-smartparens-indent 'jenkinsfile-mode)) (use-package crontab-mode :straight t) (use-package nginx-mode :straight t :config (my/set-smartparens-indent 'nginx-mode)) (add-hook 'sh-mode-hook #'smartparens-mode) (use-package fish-mode :straight t :mode "\\.fish\\'" :config (add-hook 'fish-mode-hook #'smartparens-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)) (my-leader-def :keymaps '(sql-mode-map) "rr" #'sqlformat-buffer) (use-package sparql-mode :straight t) (use-package graphql-mode :straight t) (defun my/doc-view-setup () (display-line-numbers-mode -1) (undo-tree-mode -1)) (use-package doc-view :straight (:type built-in) :config (setq doc-view-resolution 300) (add-hook 'doc-view-mode-hook #'my/doc-view-setup) (general-define-key :states '(normal) :keymaps '(doc-view-mode-map) "j" #'doc-view-next-line-or-next-page "k" #'doc-view-previous-line-or-previous-page)) (use-package x509-mode :straight t) (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 haskell-mode :straight t :mode "\\.hs\\'") (use-package lsp-haskell :straight t :after (lsp haskell-mode)) (use-package nix-mode :straight t :mode "\\.nix\\'" :config (add-hook 'nix-mode-hook #'smartparens-mode) (my/set-smartparens-indent 'nix-mode)) (use-package lua-mode :straight t :mode "\\.lua\\'" :hook (lua-mode . smartparens-mode)) (my/set-smartparens-indent 'lua-mode) (use-package org :straight (:type built-in) :if (not my/remote-server) :defer t :init (setq org-directory (expand-file-name "~/Documents/org-mode")) (unless (file-exists-p org-directory) (mkdir org-directory t)) :config (setq org-startup-indented (not my/is-termux)) (setq org-return-follows-link t) (setq org-src-tab-acts-natively nil) (add-hook 'org-mode-hook 'smartparens-mode) (add-hook 'org-agenda-mode-hook (lambda () (visual-line-mode -1) (toggle-truncate-lines 1) (display-line-numbers-mode 0))) (add-hook 'org-mode-hook (lambda () (rainbow-delimiters-mode -1)))) (with-eval-after-load-norem 'org (require 'org-crypt) (org-crypt-use-before-save-magic) (setq org-tags-exclude-from-inheritance '("crypt")) (setq org-crypt-key "C1EC867E478472439CC82410DE004F32AFA00205")) (defun my/epa--select-keys-around (fun prompt keys) (if (= (seq-length keys) 1) keys (funcall fun prompt keys))) (with-eval-after-load-norem 'epa (advice-add #'epa--select-keys :around #'my/epa--select-keys-around)) (unless my/remote-server (setq epa-file-encrypt-to '("DE004F32AFA00205"))) (use-package org-contrib :straight (org-contrib :type git :repo "https://git.sr.ht/~bzg/org-contrib" :build t) :after (org) :if (not my/remote-server) :config (require 'ox-extra) (ox-extras-activate '(latex-header-blocks ignore-headlines))) (unless (or my/remote-server my/is-termux) (use-package ol-notmuch :straight t :after (org notmuch))) (with-eval-after-load 'org (require 'org-tempo) (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")) (add-to-list 'org-structure-template-alist '("py" . "src python")) (add-to-list 'org-structure-template-alist '("sq" . "src sql"))) (use-package evil-org :straight t :hook (org-mode . evil-org-mode) :config (add-hook 'evil-org-mode-hook (lambda () (evil-org-set-key-theme '(navigation insert textobjects additional calendar todo)))) (add-to-list 'evil-emacs-state-modes 'org-agenda-mode) (require 'evil-org-agenda) (evil-org-agenda-set-keys)) (use-package jupyter :straight t :after (org) :if (not (or my/remote-server my/is-termux))) (defun my/jupyter-refresh-kernelspecs () "Refresh Jupyter kernelspecs" (interactive) (jupyter-available-kernelspecs t)) (defun my/jupyter-refesh-langs () "Refresh Jupyter languages" (interactive) (org-babel-jupyter-aliases-from-kernelspecs t)) (use-package ob-hy :after (org) :if (not my/remote-server) :straight t) (setq my/org-view-html-tmp-dir "/tmp/org-html-preview/") (use-package f :straight t) (defun my/org-view-html () (interactive) (let ((elem (org-element-at-point)) (temp-file-path (concat my/org-view-html-tmp-dir (number-to-string (random (expt 2 32))) ".html"))) (cond ((not (eq 'export-block (car elem))) (message "Not in an export block!")) ((not (string-equal (plist-get (car (cdr elem)) :type) "HTML")) (message "Export block is not HTML!")) (t (progn (f-mkdir my/org-view-html-tmp-dir) (f-write (plist-get (car (cdr elem)) :value) 'utf-8 temp-file-path) (start-process "org-html-preview" nil "xdg-open" temp-file-path)))))) (with-eval-after-load 'org (setq org-plantuml-executable-path "/home/pavel/.guix-extra-profiles/emacs/emacs/bin/plantuml") (setq org-plantuml-exec-mode 'plantuml) (add-to-list 'org-src-lang-modes '("plantuml" . plantuml))) (use-package restclient :if (not my/remote-server) :straight t) (use-package ob-restclient :after (org restclient) :if (not my/remote-server) :straight t) (with-eval-after-load-norem 'org (org-babel-do-load-languages 'org-babel-load-languages `((emacs-lisp . t) (python . t) (sql . t) ;; (typescript .t) (hy . t) (shell . t) (plantuml . t) (octave . t) ,@(unless my/is-termux '((jupyter . t))) (sparql . t))) (add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images)) (with-eval-after-load 'ob-jupyter (org-babel-jupyter-override-src-block "python") (org-babel-jupyter-override-src-block "hy")) (add-hook 'org-src-mode-hook (lambda () ;; (hs-minor-mode -1) ;; (electric-indent-local-mode -1) ;; (rainbow-delimiters-mode -1) (highlight-indent-guides-mode -1))) (use-package ob-async :straight t :after (org) :config (setq ob-async-no-async-languages-alist '("python" "hy" "jupyter-python" "jupyter-octave" "restclient"))) (setq my/jupyter-runtime-folder (expand-file-name "~/.local/share/jupyter/runtime")) (defun my/get-open-ports () (mapcar #'string-to-number (split-string (shell-command-to-string "ss -tulpnH | awk '{print $5}' | sed -e 's/.*://'") "\n"))) (defun my/list-jupyter-kernel-files () (mapcar (lambda (file) (cons (car file) (cdr (assq 'shell_port (json-read-file (car file)))))) (sort (directory-files-and-attributes my/jupyter-runtime-folder t ".*kernel.*json$") (lambda (x y) (not (time-less-p (nth 6 x) (nth 6 y))))))) (defun my/select-jupyter-kernel () (let ((ports (my/get-open-ports)) (files (my/list-jupyter-kernel-files))) (completing-read "Jupyter kernels: " (seq-filter (lambda (file) (member (cdr file) ports)) files)))) (defun my/insert-jupyter-kernel () "Insert a path to an active Jupyter kernel into the buffer" (interactive) (insert (my/select-jupyter-kernel))) (defun my/jupyter-connect-repl () "Open an emacs-jupyter REPL, connected to a Jupyter kernel" (interactive) (jupyter-connect-repl (my/select-jupyter-kernel) nil nil nil t)) (defun my/jupyter-qtconsole () "Open Jupyter QtConsole, connected to a Jupyter kernel" (interactive) (start-process "jupyter-qtconsole" nil "setsid" "jupyter" "qtconsole" "--existing" (file-name-nondirectory (my/select-jupyter-kernel)))) (defun my/jupyter-cleanup-kernels () (interactive) (let* ((ports (my/get-open-ports)) (files (my/list-jupyter-kernel-files)) (to-delete (seq-filter (lambda (file) (not (member (cdr file) ports))) files))) (when (and (length> to-delete 0) (y-or-n-p (format "Delete %d files?" (length to-delete)))) (dolist (file to-delete) (delete-file (car file)))))) (defun my/jupyter-org-scalar (value) (cond ((stringp value) value) (t (jupyter-org-scalar value)))) (define-minor-mode my/emacs-jupyter-raw-output "Make emacs-jupyter do raw output") (defun my/jupyter-org-scalar-around (fun value) (if my/emacs-jupyter-raw-output (my/jupyter-org-scalar value) (funcall fun value))) (with-eval-after-load 'jupyter (advice-add 'jupyter-org-scalar :around #'my/jupyter-org-scalar-around)) (defun my/org-strip-results (data) (replace-regexp-in-string ":\\(RESULTS\\|END\\):\n" "" data)) (defun my/org-caption-wrap (data &optional name caption attrs strip-drawer src-wrap) (let* ((data-s (if (and strip-drawer (not (string-empty-p strip-drawer))) (my/org-strip-results data) data)) (drawer-start (if (string-match-p "^:RESULTS:.*" data-s) 10 0))) (concat (substring data-s 0 drawer-start) (and name (not (string-empty-p name)) (concat "#+NAME:" name "\n")) (and caption (not (string-empty-p caption)) (concat "#+CAPTION:" caption "\n")) (and attrs (not (string-empty-p attrs)) (concat "#+ATTR_LATEX:" attrs "\n")) (if (and src-wrap (not (string-empty-p src-wrap))) (concat "#+begin_src " src-wrap "\n" (substring data-s drawer-start) (when (not (string-match-p ".*\n" data-s)) "\n") "#+end_src") (substring data-s drawer-start))))) (defun my/babel-ansi () (when-let ((beg (org-babel-where-is-src-block-result nil nil))) (save-excursion (goto-char beg) (when (looking-at org-babel-result-regexp) (let ((end (org-babel-result-end)) (ansi-color-context-region nil)) (ansi-color-apply-on-region beg end)))))) (define-minor-mode org-babel-ansi-colors-mode "Apply ANSI color codes to Org Babel results." :global t :after-hook (if org-babel-ansi-colors-mode (add-hook 'org-babel-after-execute-hook #'my/babel-ansi) (remove-hook 'org-babel-after-execute-hook #'my/babel-ansi))) (defun my/org-babel-execute-buffer-below (&optional arg) (interactive "P") (org-babel-eval-wipe-error-buffer) (let ((point (point))) (org-save-outline-visibility t (org-babel-map-executables nil (when (>= (point) point) (if (memq (org-element-type (org-element-context)) '(babel-call inline-babel-call)) (org-babel-lob-execute-maybe) (org-babel-execute-src-block arg))))))) (defun my/org-babel-execute-buffer-above (&optional arg) (interactive "P") (org-babel-eval-wipe-error-buffer) (let ((point (point))) (org-save-outline-visibility t (org-babel-map-executables nil (when (<= (point) point) (if (memq (org-element-type (org-element-context)) '(babel-call inline-babel-call)) (org-babel-lob-execute-maybe) (org-babel-execute-src-block arg))))))) (with-eval-after-load 'org (general-define-key :keymaps 'org-babel-map "B" #'my/org-babel-execute-buffer-below "A" #'my/org-babel-execute-buffer-above) (my-leader-def :keymaps 'org-mode-map "SPC b" '(:wk "org-babel") "SPC b" org-babel-map)) (defun my/org-prj-dir (path) (expand-file-name path (org-entry-get nil "PRJ-DIR" t))) (use-package hide-mode-line :straight t :after (org-present)) (defun my/present-next-with-latex () (interactive) (org-present-next) (org-latex-preview '(16))) (defun my/present-prev-with-latex () (interactive) (org-present-prev) (org-latex-preview '(16))) (use-package org-present :straight (:host github :repo "rlister/org-present") :if (not my/remote-server) :commands (org-present) :config (general-define-key :keymaps 'org-present-mode-keymap "" 'my/present-next-with-latex "" 'my/present-prev-with-latex) (setq org-present-mode-hook (list (lambda () (blink-cursor-mode 0) (org-present-big) (org-bars-mode -1) ;; (org-display-inline-images) (org-present-hide-cursor) (org-present-read-only) (display-line-numbers-mode 0) (hide-mode-line-mode +1) (setq-local org-format-latex-options (plist-put org-format-latex-options :scale (* org-present-text-scale my/org-latex-scale 0.5))) ;; (org-latex-preview '(16)) ;; TODO ^somehow this stucks at running LaTeX^ (setq-local olivetti-body-width 60) (olivetti-mode 1)))) (setq org-present-mode-quit-hook (list (lambda () (blink-cursor-mode 1) (org-present-small) (org-bars-mode 1) ;; (org-remove-inline-images) (org-present-show-cursor) (org-present-read-write) (display-line-numbers-mode 1) (hide-mode-line-mode 0) (setq-local org-format-latex-options (plist-put org-format-latex-options :scale my/org-latex-scale)) (org-latex-preview '(64)) (olivetti-mode -1) (setq-local olivetti-body-width (default-value 'olivetti-body-width)))))) (use-package org-make-toc :after (org) :if (not my/remote-server) :commands (org-make-toc org-make-toc-insert org-make-toc-set org-make-toc-at-point) :straight t) (use-package org-attach-screenshot :commands (org-attach-screenshot) :straight t) (use-package org-transclusion :after org :straight (:host github :repo "nobiot/org-transclusion") :config (add-to-list 'org-transclusion-extensions 'org-transclusion-indent-mode) (require 'org-transclusion-indent-mode) (general-define-key :keymaps '(org-transclusion-map) :states '(normal) "RET" #'org-transclusion-open-source "gr" #'org-transclusion-refresh) (general-define-key :keymaps '(org-mode-map) :states 'normal "C-c t a" #'org-transclusion-add "C-c t A" #'org-transclusion-add-all "C-c t t" #'org-transclusion-mode)) (use-package edraw-org :straight (:host github :repo "misohena/el-easydraw") :if (and (not my/is-termux) (not my/remote-server)) :after (org) :config (edraw-org-setup-default)) (defun my/export-org-tables-to-csv () (interactive) (org-table-map-tables (lambda () (when-let (name (plist-get (cadr (org-element-at-point)) :name)) (org-table-export (concat (file-name-directory (buffer-file-name)) name ".csv") "orgtbl-to-csv"))))) (defun my/update-org-agenda () (interactive) (let ((project-files (mapcar (lambda (f) (concat org-directory "/projects/" f)) (seq-filter (lambda (f) (not (member f '("." "..")))) (directory-files (concat org-directory "/projects")))))) (setq org-agenda-files `("inbox.org" "misc/habit.org" "contacts.org" ,@project-files)) (setq org-refile-targets `(,@(mapcar (lambda (f) `(,f . (:tag . "refile"))) project-files))) (when (file-exists-p (concat org-directory "/scripts/refile.el")) (load-file (concat org-directory "/scripts/refile.el")) (run-hooks 'my/org-refile-hooks)))) (with-eval-after-load-norem 'org (setq org-roam-directory (concat org-directory "/roam")) (my/update-org-agenda) ;; (setq org-default-notes-file (concat org-directory "/notes.org")) ) (setq org-refile-use-outline-path 'file) (setq org-outline-path-complete-in-steps nil) (defun my/generate-inbox-note-name () (format "%s/inbox-notes/%s%s.org" org-directory (format-time-string "%Y%m%d%H%M%S") (let ((note-name (read-string "Note name: "))) (if (not (string-empty-p note-name)) (string-replace " " "-" (concat "-" (downcase note-name))) "")))) (setq org-capture-templates `(("i" "Inbox" entry (file "inbox.org") ,(concat "* TODO %?\n" "/Entered on/ %U")) ("e" "email" entry (file "inbox.org") ,(concat "* TODO %:from %:subject \n" "/Entered on/ %U\n" "/Received on/ %:date-timestamp-inactive\n" "%a\n")) ("f" "elfeed" entry (file "inbox.org") ,(concat "* TODO %:elfeed-entry-title\n" "/Entered on/ %U\n" "%a\n")) ("n" "note" plain (file my/generate-inbox-note-name) ,(concat "#+TODO: PROCESSED(p)\n" "\n" "* %?\n" "/Entered on/ %U")))) (use-package org-ql :after (org) :if (not my/remote-server) :straight (:fetcher github :repo "alphapapa/org-ql" :files (:defaults (:exclude "helm-org-ql.el"))) :init ;; See https://github.com/alphapapa/org-ql/pull/237 (setq org-ql-regexp-part-ts-time (rx " " (repeat 1 2 digit) ":" (repeat 2 digit) (optional "-" (repeat 1 2 digit) ":" (repeat 2 digit))))) (use-package org-habit-stats :straight (:host github :repo "ml729/org-habit-stats") :after (org) :config (general-define-key :keymaps '(org-habit-stats-mode-map) :states '(normal emacs) "q" #'org-habit-stats-exit "<" #'org-habit-stats-calendar-scroll-left ">" #'org-habit-stats-calendar-scroll-right "[" #'org-habit-stats-scroll-graph-left "]" #'org-habit-stats-scroll-graph-right "{" #'org-habit-stats-scroll-graph-left-big "}" #'org-habit-stats-scroll-graph-right-big "." #'org-habit-stats-view-next-habit "," #'org-habit-stats-view-previous-habit)) (defun my/org-match-at-point-p (match) "Return non-nil if headline at point matches MATCH. Here MATCH is a match string of the same format used by `org-tags-view'." (funcall (cdr (org-make-tags-matcher match)) (org-get-todo-state) (org-get-tags-at) (org-reduced-level (org-current-level)))) (defun my/org-agenda-skip-without-match (match) "Skip current headline unless it matches MATCH. Return nil if headline containing point matches MATCH (which should be a match string of the same format used by `org-tags-view'). If headline does not match, return the position of the next headline in current buffer. Intended for use with `org-agenda-skip-function', where this will skip exactly those headlines that do not match." (save-excursion (unless (org-at-heading-p) (org-back-to-heading)) (let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))) (if (my/org-match-at-point-p match) nil next-headline)))) (defun my/org-scheduled-get-time () (let ((scheduled (org-get-scheduled-time (point)))) (if scheduled (format-time-string "%Y-%m-%d" scheduled) ""))) (setq org-agenda-hide-tags-regexp (rx (or "org" "refile" "habit"))) (setq org-agenda-custom-commands `(("p" "My outline" ((agenda "" ((org-agenda-skip-function '(my/org-agenda-skip-without-match "-habit")))) (tags-todo "inbox" ((org-agenda-overriding-header "Inbox") (org-agenda-prefix-format " %i %-12:c") (org-agenda-hide-tags-regexp "."))) (tags-todo "+waitlist+SCHEDULED<=\"<+14d>\"" ((org-agenda-overriding-header "Waitlist") (org-agenda-hide-tags-regexp "waitlist") (org-agenda-prefix-format " %i %-12:c %-12(my/org-scheduled-get-time)"))) (tags-todo "habit+SCHEDULED<=\"<+0d>\"" ((org-agenda-overriding-header "Habits") (org-agenda-prefix-format " %i %-12:c") (org-agenda-hide-tags-regexp "."))))))) (setq my/org-alert-notify-times '(600 60)) (setq my/org-alert--alerts (make-hash-table :test #'equal)) (defun my/org-alert--is-scheduled (label time) "Check if LABEL is scheduled to be shown an TIME." (gethash (cons label time) my/org-alert--alerts nil)) (defun my/org-alert--schedule (label time) "Schedule LABEL to be shown at TIME, unless it's already scheduled." (unless (my/org-alert--is-scheduled label time) (puthash (cons label time) (run-at-time time nil (lambda () (alert label :title "PROXIMITY ALERT"))) my/org-alert--alerts))) (defun my/org-alert-cleanup (&optional keys) "Unschedule items that do not appear in KEYS. KEYS is a list of cons cells like (