@@ -0,0 +1,580 @@ | |||
(doom-load-envvars-file (concat doom-private-dir "env.el")) | |||
(setq doom-theme 'doom-catppuccin) | |||
(setq doom-font (font-spec :family "monospace" :size 13) | |||
doom-big-font (font-spec :family "monospace" :size 13) | |||
doom-variable-pitch-font (font-spec :family "sans-serif" :size 13)) | |||
(set-frame-parameter (selected-frame) 'alpha-background 85) | |||
(add-to-list 'default-frame-alist '(alpha-background . 85)) | |||
(setq evil-want-fine-undo t) | |||
(defun my/line-numbers-relative () | |||
(setq display-line-numbers 'relative)) | |||
(defun my/line-numbers-absolute () | |||
(setq display-line-numbers 'absolute)) | |||
(add-hook 'evil-insert-state-entry-hook #'my/line-numbers-absolute) | |||
(add-hook 'evil-insert-state-exit-hook #'my/line-numbers-relative) | |||
(use-package copilot | |||
:commands (copilot-complete)) | |||
(defun my/copilot-complete () | |||
(interactive) | |||
(copilot-complete) | |||
(my/hydra-copilot/body) | |||
(copilot-clear-overlay)) | |||
(defhydra my/hydra-copilot () | |||
"Copilot" | |||
("<return>" copilot-accept-completion "Accept" :color blue ) | |||
("<tab>" copilot-next-completion "Next" ) | |||
("<backtab>" copilot-previous-completion "Prev") | |||
("<escape>" copilot-clear-overlay "Cancel" :color blue)) | |||
(setq doom-scratch-initial-major-mode 'lisp-interaction-mode) | |||
(map! :leader | |||
"b" nil | |||
"f" nil | |||
"h" nil | |||
"p" nil | |||
"t" nil) | |||
(map! :map evil-org-mode-map | |||
:n "zc" nil) | |||
(map! | |||
:desc "Increase font size" :ni "C-=" #'text-scale-increase | |||
:desc "Decrease font size" :ni "C--" #'text-scale-decrease) | |||
(map! | |||
:desc "Copilot" :i "C-," #'my/copilot-complete) | |||
(map! :map minibuffer-mode-map | |||
:desc "Next history" "C-j" #'next-history-element | |||
:desc "Prev history" "C-k" #'previous-history-element) | |||
(map! :leader | |||
:desc "M-x" "x" #'counsel-M-x | |||
:desc "M-:" ";" #'pp-eval-expression) | |||
(map! :leader | |||
:desc "Find file" "." #'counsel-find-file | |||
:desc "Find dir" ">" #'+default/dired | |||
:desc "Find in project" "SPC" #'+ivy/projectile-find-file | |||
:desc "Find in project uncached" "C-SPC" #'my/projectile-find-file-nocache) | |||
(defun my/projectile-find-file-nocache () | |||
(interactive) | |||
(projectile-invalidate-cache nil) | |||
(+ivy/projectile-find-file)) | |||
(map! :leader | |||
:desc "Switch buffer" "," #'+vertico/switch-workspace-buffer | |||
:desc "Switch all buffers" ">" #'consult-buffer) | |||
(map! :leader | |||
:desc "Search online" "/" #'counsel-search) | |||
(map! :leader | |||
:prefix ("b" . "buffers") | |||
:desc "Switch buffer" "b" #'consult-buffer | |||
:desc "ibuffer" "i" #'ibuffer | |||
:desc "Kill buffer" "d" #'kill-current-buffer | |||
:desc "Kill all buffers" "D" #'doom/kill-all-buffers) | |||
(map! :leader | |||
:prefix ("f" . "files") | |||
:desc "Recent files" "r" #'consult-recent-file | |||
:desc "Find file" "f" #'counsel-find-file | |||
:desc "Find file as root" "u" #'doom/sudo-find-file | |||
:desc "Find package" "p" #'counsel-find-library | |||
:desc "Copy this file" "c" #'doom/copy-this-file | |||
:desc "Delete this file" "d" #'doom/delete-this-file | |||
:desc "Move this file" "m" #'doom/move-this-file | |||
:desc "Revert this file" "l" #'revert-buffer | |||
:desc "Copy file path" "y" #'+default/yank-buffer-path | |||
:desc "Copy project file path" "Y" #'+default/yank-buffer-path-relative-to-project | |||
:desc "Open scratch" "x" #'doom/open-scratch-buffer) | |||
(map! :leader | |||
:prefix ("f s" . "snippets") | |||
:desc "New snippet" "n" #'yas-new-snippet | |||
:desc "Edit snippet" "e" #'yas-visit-snippet-file | |||
:desc "Browse docs" "?" #'my/yas-browse-docs) | |||
(defun my/yas-browse-docs () | |||
(interactive) | |||
(browse-url "https://joaotavora.github.io/yasnippet")) | |||
(map! :leader | |||
:prefix ("f e" . "emacs") | |||
:desc "Find in config" "f" #'doom/find-file-in-private-config | |||
:desc "Reload config" "r" #'doom/reload | |||
:desc "Edit config" "c" #'my/edit-config | |||
:desc "Edit packages" "p" #'my/edit-packages | |||
:desc "Edit env" "e" #'my/edit-env | |||
:desc "Edit init" "i" #'my/edit-init) | |||
(defun my/edit-config () | |||
(interactive) | |||
(find-file (concat doom-private-dir "config.org"))) | |||
(defun my/edit-packages () | |||
(interactive) | |||
(find-file (concat doom-private-dir "packages.el"))) | |||
(defun my/edit-init () | |||
(interactive) | |||
(find-file (concat doom-private-dir "init.el"))) | |||
(defun my/edit-env () | |||
(interactive) | |||
(find-file (concat doom-private-dir "env.el"))) | |||
(define-derived-mode org-config-mode org-mode "Org config mode") | |||
(add-to-list 'auto-mode-alist '("config\\.org" . org-config-mode)) | |||
(map! :leader | |||
:prefix ("h" . "help") | |||
:desc "Apropos" "/" #'consult-apropos | |||
:desc "Apropos docs" "?" #'apropos-documentation | |||
:desc "Help at point" "p" #'helpful-at-point | |||
:desc "Help info" "h" #'info | |||
:desc "Help for help" "H" #'help-for-help | |||
:desc "Describe function" "f" #'counsel-describe-function | |||
:desc "Describe function key" "F" #'where-is | |||
:desc "Describe variable" "v" #'counsel-describe-variable | |||
:desc "Describe custom variable" "V" #'doom/help-custom-variable | |||
:desc "Describe command" "x" #'helpful-command | |||
:desc "Describe key" "k" #'describe-key-briefly | |||
:desc "Describe key fully" "K" #'describe-key | |||
:desc "Describe char" "'" #'describe-char | |||
:desc "Describe coding system" "\"" #'describe-coding-system | |||
:desc "Describe input method" "i" #'describe-input-method | |||
:desc "Emacs manual" "e" #'info-emacs-manual | |||
:desc "ASCII table" "a" #'my/ascii-table | |||
:desc "View messages" "e" #'view-echo-area-messages | |||
:desc "View keystrokes" "l" #'view-lossage) | |||
(defface my/ascii-table-highlight-face | |||
'((t (:foreground "pink"))) | |||
"Face for highlighting ASCII chars.") | |||
(defun my/ascii-table () | |||
"Display basic ASCII table (0 thru 128)." | |||
(interactive) | |||
(pop-to-buffer "*ASCII*") | |||
(erase-buffer) | |||
(setq buffer-read-only nil) | |||
(my/buffer-local-set-key "q" #'+popup/quit-window) | |||
(setq lower32 '("nul" "soh" "stx" "etx" "eot" "enq" "ack" "bel" | |||
"bs" "ht" "nl" "vt" "np" "cr" "so" "si" | |||
"dle" "dc1" "dc2" "dc3" "dc4" "nak" "syn" "etb" | |||
"can" "em" "sub" "esc" "fs" "gs" "rs" "us")) | |||
(save-excursion (let ((i -1)) | |||
(insert " Hex Dec Char | Hex Dec Char | Hex Dec Char | Hex Dec Char\n") | |||
(insert " ---------------+-----------------+-----------------+----------------\n") | |||
(while (< i 31) | |||
(insert (format "%4x %4d %4s | %4x %4d %4s | %4x %4d %4s | %4x %4d %4s\n" | |||
(setq i (+ 1 i)) i (elt lower32 i) | |||
(setq i (+ 32 i)) i (single-key-description i) | |||
(setq i (+ 32 i)) i (single-key-description i) | |||
(setq i (+ 32 i)) i (single-key-description i))) | |||
(overlay-put (make-overlay (- (point) 4) (- (point) 1)) 'face 'my/ascii-table-highlight-face) | |||
(overlay-put (make-overlay (- (point) 22) (- (point) 19)) 'face 'my/ascii-table-highlight-face) | |||
(overlay-put (make-overlay (- (point) 40) (- (point) 37)) 'face 'my/ascii-table-highlight-face) | |||
(overlay-put (make-overlay (- (point) 58) (- (point) 55)) 'face 'my/ascii-table-highlight-face) | |||
(setq i (- i 96)) | |||
)))) | |||
(set-popup-rule! "^\\*ASCII" | |||
:side 'right | |||
:select t | |||
:width 70) | |||
(map! :leader | |||
:prefix ("h d" . "doom") | |||
:desc "Doom manual" "d" #'doom/help | |||
:desc "Doom FAQ" "f" #'doom/help-faq | |||
:desc "Doom modules" "m" #'doom/help-modules | |||
:desc "Doom news" "n" #'doom/help-news | |||
:desc "Doom help search" "/" #'doom/help-search-headings | |||
:desc "Doom version" #'doom/version | |||
:desc "Doom package configuration" "p" #'doom/help-package-config | |||
:desc "Doom sandbox" "x" #'doom/sandbox) | |||
(map! :leader | |||
:prefix ("p" . "projects") | |||
:desc "Switch project" "p" #'counsel-projectile-switch-project | |||
:desc "Add new project" "a" #'projectile-add-known-project | |||
:desc "Remove project" "d" #'projectile-remove-known-project | |||
:desc "Find in project root" "." #'counsel-projectile-find-file | |||
:desc "Search in project" "/" #'+default/search-project | |||
:desc "Invalidate project cache" "i" #'projectile-invalidate-cache | |||
:desc "Run cmd in project root" "!" #'projectile-run-shell-command-in-root | |||
:desc "Run async cmd in project root" "&" #'projectile-run-async-shell-command-in-root) | |||
(defun my/projectile-find-in-root () | |||
(interactive) | |||
(counsel-find-file nil projectile-project-root)) | |||
(map! :leader | |||
:prefix ("t" . "toggle") | |||
;; Wrap | |||
:desc "Auto Wrap" "a" #'auto-fill-mode | |||
:desc "Wrap Indicator" "c" #'global-display-fill-column-indicator-mode | |||
:desc "Wrap Column" "C" #'set-fill-column | |||
:desc "Line Wrap" "w" #'visual-line-mode | |||
;; Modes | |||
:desc "Flycheck" "f" #'flycheck-mode | |||
;; Files | |||
:desc "Read-only" "r" #'read-only-mode) | |||
(defun my/auto-fill-mode (cols) | |||
(interactive)) | |||
(map! :leader | |||
:prefix-map ("w" . "window") | |||
;; Navigation | |||
:desc "Go..." "w" #'ace-window | |||
:desc "Go left" "h" #'evil-window-left | |||
:desc "Go down" "j" #'evil-window-down | |||
:desc "Go up" "k" #'evil-window-up | |||
:desc "Go right" "l" #'evil-window-right | |||
:desc "Go other" "o" #'other-window | |||
;; Layout | |||
:desc "Rotate up" "K" #'evil-window-rotate-upwards | |||
:desc "Rotate down" "J" #'evil-window-rotate-downwards | |||
;; Splits | |||
:desc "VSplit" "=" #'+evil/window-vsplit-and-follow | |||
:desc "HSplit" "-" #'+evil/window-split-and-follow | |||
:desc "Tear off" "t" #'tear-off-window | |||
;; History | |||
:desc "Undo" "u" #'winner-undo | |||
:desc "Redo" "U" #'winner-redo | |||
;; Misc | |||
:desc "Resize" "r" #'my/hydra-window-resize/body | |||
:desc "Balance" "b" #'balance-windows | |||
;; Management | |||
:desc "Kill window" "d" #'+workspace/close-window-or-workspace) | |||
;; TODO: Maybe check out: | |||
;; evil-window-mru | |||
(setq my/window-resize-step 3) | |||
(defun my/window-increase-height () | |||
(interactive) | |||
(evil-window-increase-height my/window-resize-step)) | |||
(defun my/window-decrease-height () | |||
(interactive) | |||
(evil-window-decrease-height my/window-resize-step)) | |||
(defun my/window-increase-width () | |||
(interactive) | |||
(evil-window-increase-width my/window-resize-step)) | |||
(defun my/window-decrease-width () | |||
(interactive) | |||
(evil-window-decrease-width my/window-resize-step)) | |||
(defhydra my/hydra-window-resize () | |||
"Resize window" | |||
("=" my/window-increase-height "++Height") | |||
("-" my/window-decrease-height "--Height") | |||
("<" my/window-decrease-width "--Width") | |||
(">" my/window-increase-width "++Width")) | |||
(map! :map org-config-mode-map | |||
:localleader | |||
:v :desc "Eval Region" "e" #'eval-region | |||
:n :desc "Eval Source" "e" #'my/org-config-eval-source) | |||
(defun my/org-config-eval-source () | |||
(interactive) | |||
(org-ctrl-c-ctrl-c) | |||
(org-babel-remove-result)) | |||
(map! :map rustic-mode-map | |||
:localleader | |||
:desc "Debug..." "d" #'my/rust/dap-hydra/body) | |||
(map! :map rustic-mode-map | |||
:desc "Pluralize import" "," #'my/rust/import-pluralize | |||
:desc "Singularize import" "<backspace>" #'my/rust/import-singularize | |||
:desc "Singularize import" "C-<backspace>" #'my/rust/import-c-singularize) | |||
(defhydra my/rust/dap-hydra (:color pink :hint nil :foreign-keys run) | |||
" | |||
^Stepping^ ^Switch^ ^Breakpoints^ ^Debug^ ^Eval | |||
^^^^^^^^---------------------------------------------------------------------------------------------------------------- | |||
_n_: Next _ss_: Session _bb_: Toggle _dd_: Debug binary _ee_: Eval | |||
_i_: Step in _st_: Thread _bd_: Delete _dr_: Restart debugging _es_: Eval thing at point | |||
_o_: Step out _sf_: Stack frame _ba_: Add _ea_: Add expression | |||
_c_: Continue _su_: Up stack frame _bc_: Set condition | |||
_Q_: Disconnect _sd_: Down stack frame _bh_: Set hit count | |||
_sl_: List locals _bl_: Set log message | |||
_sb_: List breakpoints | |||
_sS_: List sessions | |||
" | |||
("n" dap-next) | |||
("i" dap-step-in) | |||
("o" dap-step-out) | |||
("c" dap-continue) | |||
("r" dap-restart-frame) | |||
("ss" dap-switch-session) | |||
("st" dap-switch-thread) | |||
("sf" dap-switch-stack-frame) | |||
("su" dap-up-stack-frame) | |||
("sd" dap-down-stack-frame) | |||
("sl" dap-ui-locals) | |||
("sb" dap-ui-breakpoints) | |||
("sS" dap-ui-sessions) | |||
("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" my/rust/debug-binary) | |||
("dr" dap-debug-restart) | |||
("ee" dap-eval) | |||
("ea" dap-ui-expressions-add) | |||
("es" dap-eval-thing-at-point) | |||
("q" nil "quit" :color blue) | |||
("Q" dap-disconnect :color red)) | |||
(map! :prefix "z" | |||
:desc "Kill buffer" :n "x" #'kill-current-buffer | |||
:desc "Kill window" :n "c" #'+workspace/close-window-or-workspace) | |||
(map! :prefix "[" | |||
:desc "Start of fn" :n "f" #'beginning-of-defun) | |||
(map! :prefix "]" | |||
:desc "End of fn" :n "f" #'end-of-defun) | |||
(add-to-list 'projectile-globally-ignored-files "Cargo.lock") | |||
(defun my/rust/import-pluralize () | |||
"Convert a singular import into a brace-wrapped plural import." | |||
(interactive) | |||
(if (and | |||
(not (my/kbd!-p)) | |||
(my/insert-mode-p) | |||
(my/line-match-p | |||
;; use foo::bar::baz; | |||
(rx line-start "use " | |||
(+ (+ word) "::") | |||
(+ word) | |||
(? ";") line-end))) | |||
(kbd! "ESC vb S} f} i,") | |||
(insert ","))) | |||
(defun my/rust/import-singularize () | |||
"Convert a brace-wrapped plural import into a singular import." | |||
(interactive) | |||
(if (and | |||
(not (my/kbd!-p)) | |||
(my/insert-mode-p) | |||
(my/line-match-p | |||
;; use foo::bar::baz::{qux::quo,}; | |||
(rx line-start "use " | |||
(+ (+ word) "::") | |||
"{" (* (+ word) "::") (+ word) ",}" | |||
(? ";") line-end))) | |||
(kbd! "ESC l dF, ds} $i") | |||
(evil-delete-backward-char-and-join 1))) | |||
(defun my/rust/import-c-singularize () | |||
"Convert a brace-wrapped plural import into a singular import." | |||
(interactive) | |||
(if (and | |||
(not (my/kbd!-p)) | |||
(my/insert-mode-p) | |||
(my/line-match-p | |||
;; use foo::bar::baz::{qux::quo, }; | |||
(rx line-start | |||
"use " | |||
(+ (+ word) "::") | |||
"{" (* (+ word) "::") (+ word) "," (* whitespace) "}" | |||
(? ";") line-end))) | |||
(kbd! "ESC l dF, ds} $i") | |||
(backward-kill-word 1))) | |||
(defun my/rust/debug-config (args) | |||
(append | |||
`(:type "lldb-vscode" | |||
;; `(:type "lldb" | |||
:request "launch" | |||
:dap-server-path ,(list (executable-find "lldb-vscode")) | |||
;; :dap-server-path ,(list (executable-find "rust-lldb")) | |||
,@args))) | |||
;; use a::TestThin | |||
;; (:MIMode "gdb" | |||
;; :miDebuggerPath "gdb" | |||
;; :stopAtEntry t | |||
;; :externalConsole | |||
;; :json-false | |||
;; :type "cppdbg" | |||
;; :request "launch" | |||
;; :name "test test2" | |||
;; :args ["test2" "--exact" "--nocapture"] | |||
;; :cwd "/home/lain/Code/test/rust/debug" | |||
;; :sourceLanguages ["rust"] | |||
;; :program "/home/lain/Code/test/rust/debug/target/debug/deps/...") | |||
;; (require 'dap-cpptools) | |||
(defun my/rust/debug-binary (args) | |||
(interactive "sArgs: ") | |||
(let* ((root (projectile-project-root)) | |||
(name (projectile-project-name)) | |||
(target (concat root "target/debug/" name))) | |||
;; (rustic-cargo-build) | |||
(dap-debug | |||
(my/rust/debug-config | |||
`(:program ,target | |||
:cwd ,root | |||
:args ,(apply #'vector (split-string-and-unquote args))))))) | |||
(defun my/rust/debug-lsp-runnable (runnable) | |||
"Select and debug a RUNNABLE action." | |||
(interactive (list (lsp-rust-analyzer--select-runnable))) | |||
(-let (((&rust-analyzer:Runnable | |||
:args (&rust-analyzer:RunnableArgs :cargo-args :workspace-root? :executable-args) | |||
:label) runnable)) | |||
(pcase (aref cargo-args 0) | |||
("run" (aset cargo-args 0 "build")) | |||
("test" (when (-contains? (append cargo-args ()) "--no-run") | |||
(cl-callf append cargo-args (list "--no-run"))))) | |||
(->> (append (list (executable-find "cargo")) | |||
cargo-args | |||
(list "--message-format=json")) | |||
(s-join " ") | |||
(shell-command-to-string) | |||
(s-lines) | |||
(-keep (lambda (s) | |||
(condition-case nil | |||
(-let* ((json-object-type 'plist) | |||
((msg &as &plist :reason :executable) (json-read-from-string s))) | |||
(when (and executable (string= "compiler-artifact" reason)) | |||
executable)) | |||
(error)))) | |||
(funcall | |||
(lambda (artifact-spec) | |||
(pcase artifact-spec | |||
(`() (user-error "No compilation artifacts or obtaining the runnable artifacts failed")) | |||
(`(,spec) spec) | |||
(_ (user-error "Multiple compilation artifacts are not supported"))))) | |||
(list :name label | |||
:args executable-args | |||
:cwd workspace-root? | |||
;; :sourceLanguages ["rust"] | |||
:stopAtEntry t | |||
:stopAtEntry :json-true | |||
:externalConsole :json-false | |||
:program) | |||
(my/rust/debug-config) | |||
(dap-debug)))) | |||
(advice-add #'lsp-rust-analyzer-debug :override #'my/rust/debug-lsp-runnable) | |||
;; (setq projectile-project-search-path | |||
;; '("~/Code")) | |||
(let ((found (nth 0 (auth-source-search :host "kagi.com")))) | |||
(when found | |||
(let ((token (plist-get found :secret))) | |||
(when (functionp token) | |||
(setq token (funcall token))) | |||
(add-to-list | |||
'counsel-search-engines-alist | |||
`(kagi | |||
"https://duckduckgo.com/ac/" | |||
,(format "https://kagi.com/search?token=%s&q=" token) | |||
counsel--search-request-data-ddg)) | |||
(setq counsel-search-engine 'kagi)))) | |||
(load! "lisp/emacs-everywhere.el") | |||
(setq emacs-everywhere-paste-command '("xdotool" "key" "--clearmodifiers" "ctrl+v")) | |||
(setq emacs-everywhere-frame-parameters | |||
'((title . "Emacs Everywhere") | |||
(width . 120) | |||
(height . 36))) | |||
(defun my/line () | |||
(buffer-substring-no-properties | |||
(line-beginning-position) | |||
(line-end-position))) | |||
(defun my/line-match-p (regexp) | |||
(string-match-p regexp (my/line))) | |||
(defun my/insert-mode-p () | |||
(eq evil-state 'insert)) | |||
(defun my/normal-mode-p () | |||
(eq evil-state 'normal)) | |||
(defun my/kbd-replace (str) | |||
"Convert STR into a keyboard macro string by replacing terminal key sequences with GUI keycodes." | |||
(let ((kbd-regex '(("ESC" . "<escape>") | |||
("DEL" . "<delete>" ) | |||
("BS" . "<backspace>") | |||
("RET" . "<return>") | |||
("SPC" . "<SPC>") | |||
("TAB" . "<tab>")))) | |||
(my/replace-regexps-in-string str kbd-regex))) | |||
(setq my//kbd-p nil) | |||
(defun my/kbd!-p () (eq my//kbd-p t)) | |||
(defun kbd! (str) | |||
"Execute the key sequence defined by STR like a VIM macro." | |||
(let ((minibuffer-message-timeout 0)) | |||
(setq my//kbd-p t) | |||
(execute-kbd-macro (read-kbd-macro (my/kbd-replace str))) | |||
(setq my//kbd-p nil))) | |||
(defun my/buffer-local-set-key (key fn) | |||
(let ((mode (intern (format "%s-local-mode" (buffer-name)))) | |||
(map (intern (format "%s-local-mode-map" (buffer-name))))) | |||
(unless (boundp map) | |||
(set map (make-sparse-keymap)) | |||
(evil-make-overriding-map map 'normal)) | |||
(eval | |||
`(define-minor-mode ,mode | |||
"A minor mode for buffer-local keybinds." | |||
:keymap ,map)) | |||
(eval | |||
`(define-key ,map ,key #',fn)) | |||
(funcall mode t))) | |||
(defun my/replace-regexps-in-string (str regexps) | |||
"Replace all pairs of (regex . replacement) defined by REGEXPS in STR." | |||
(if (null regexps) | |||
str | |||
(my/replace-regexps-in-string | |||
(replace-regexp-in-string (caar regexps) (cdar regexps) str t) | |||
(cdr regexps)))) |
@@ -0,0 +1,733 @@ | |||
#+title: Config | |||
* Setup | |||
** Environment Variables | |||
#+BEGIN_SRC elisp | |||
(doom-load-envvars-file (concat doom-private-dir "env.el")) | |||
#+END_SRC | |||
* Appearance | |||
Set a nice theme and font. | |||
#+BEGIN_SRC elisp | |||
(setq doom-theme 'doom-catppuccin) | |||
(setq doom-font (font-spec :family "monospace" :size 13) | |||
doom-big-font (font-spec :family "monospace" :size 13) | |||
doom-variable-pitch-font (font-spec :family "sans-serif" :size 13)) | |||
#+END_SRC | |||
Sprinkle in a little background transparency. Instead of making the entire frame | |||
transparent (including the text) with =alpha=, we use the =alpha-background= | |||
frame parameter which just landed in the Emacs 29 development branch. | |||
#+BEGIN_SRC elisp | |||
(set-frame-parameter (selected-frame) 'alpha-background 85) | |||
(add-to-list 'default-frame-alist '(alpha-background . 85)) | |||
#+END_SRC | |||
* Editing | |||
** Evil | |||
#+BEGIN_SRC elisp | |||
(setq evil-want-fine-undo t) | |||
#+END_SRC | |||
*** Line Numbers | |||
Use relative line numbers in normal mode, and absolute line numbers in insert | |||
mode. | |||
#+BEGIN_SRC emacs-lisp | |||
(defun my/line-numbers-relative () | |||
(setq display-line-numbers 'relative)) | |||
(defun my/line-numbers-absolute () | |||
(setq display-line-numbers 'absolute)) | |||
(add-hook 'evil-insert-state-entry-hook #'my/line-numbers-absolute) | |||
(add-hook 'evil-insert-state-exit-hook #'my/line-numbers-relative) | |||
#+END_SRC | |||
** Copilot | |||
Add support for GitHub Copilot ([[*Copilot][keybinds]]). | |||
#+BEGIN_SRC elisp | |||
(use-package copilot | |||
:commands (copilot-complete)) | |||
(defun my/copilot-complete () | |||
(interactive) | |||
(copilot-complete) | |||
(my/hydra-copilot/body) | |||
(copilot-clear-overlay)) | |||
(defhydra my/hydra-copilot () | |||
"Copilot" | |||
("<return>" copilot-accept-completion "Accept" :color blue ) | |||
("<tab>" copilot-next-completion "Next" ) | |||
("<backtab>" copilot-previous-completion "Prev") | |||
("<escape>" copilot-clear-overlay "Cancel" :color blue)) | |||
#+END_SRC | |||
** Scratch | |||
Use =lisp-interaction-mode= by default for the scratch buffer. | |||
#+BEGIN_SRC elisp | |||
(setq doom-scratch-initial-major-mode 'lisp-interaction-mode) | |||
#+END_SRC | |||
* Keybinds | |||
** Unmaps | |||
Unmap a bunch of the default keybindings. | |||
#+BEGIN_SRC elisp | |||
(map! :leader | |||
"b" nil | |||
"f" nil | |||
"h" nil | |||
"p" nil | |||
"t" nil) | |||
(map! :map evil-org-mode-map | |||
:n "zc" nil) | |||
#+END_SRC | |||
** Global | |||
*** Font Size | |||
#+BEGIN_SRC elisp | |||
(map! | |||
:desc "Increase font size" :ni "C-=" #'text-scale-increase | |||
:desc "Decrease font size" :ni "C--" #'text-scale-decrease) | |||
#+END_SRC | |||
*** Copilot | |||
#+BEGIN_SRC elisp | |||
(map! | |||
:desc "Copilot" :i "C-," #'my/copilot-complete) | |||
#+END_SRC | |||
*** LSP | |||
#+BEGIN_SRC elisp | |||
#+END_SRC | |||
*** Minibuffer | |||
#+BEGIN_SRC elisp | |||
(map! :map minibuffer-mode-map | |||
:desc "Next history" "C-j" #'next-history-element | |||
:desc "Prev history" "C-k" #'previous-history-element) | |||
#+END_SRC | |||
** Leader | |||
*** Root | |||
**** Eval | |||
#+BEGIN_SRC elisp | |||
(map! :leader | |||
:desc "M-x" "x" #'counsel-M-x | |||
:desc "M-:" ";" #'pp-eval-expression) | |||
#+END_SRC | |||
**** Files | |||
#+BEGIN_SRC elisp | |||
(map! :leader | |||
:desc "Find file" "." #'counsel-find-file | |||
:desc "Find dir" ">" #'+default/dired | |||
:desc "Find in project" "SPC" #'+ivy/projectile-find-file | |||
:desc "Find in project uncached" "C-SPC" #'my/projectile-find-file-nocache) | |||
(defun my/projectile-find-file-nocache () | |||
(interactive) | |||
(projectile-invalidate-cache nil) | |||
(+ivy/projectile-find-file)) | |||
#+END_SRC | |||
**** Buffers | |||
#+BEGIN_SRC elisp | |||
(map! :leader | |||
:desc "Switch buffer" "," #'+vertico/switch-workspace-buffer | |||
:desc "Switch all buffers" ">" #'consult-buffer) | |||
#+END_SRC | |||
**** Search | |||
#+BEGIN_SRC elisp | |||
(map! :leader | |||
:desc "Search online" "/" #'counsel-search) | |||
#+END_SRC | |||
*** b: Buffers | |||
#+BEGIN_SRC elisp | |||
(map! :leader | |||
:prefix ("b" . "buffers") | |||
:desc "Switch buffer" "b" #'consult-buffer | |||
:desc "ibuffer" "i" #'ibuffer | |||
:desc "Kill buffer" "d" #'kill-current-buffer | |||
:desc "Kill all buffers" "D" #'doom/kill-all-buffers) | |||
#+END_SRC | |||
*** f: Files | |||
#+BEGIN_SRC elisp | |||
(map! :leader | |||
:prefix ("f" . "files") | |||
:desc "Recent files" "r" #'consult-recent-file | |||
:desc "Find file" "f" #'counsel-find-file | |||
:desc "Find file as root" "u" #'doom/sudo-find-file | |||
:desc "Find package" "p" #'counsel-find-library | |||
:desc "Copy this file" "c" #'doom/copy-this-file | |||
:desc "Delete this file" "d" #'doom/delete-this-file | |||
:desc "Move this file" "m" #'doom/move-this-file | |||
:desc "Revert this file" "l" #'revert-buffer | |||
:desc "Copy file path" "y" #'+default/yank-buffer-path | |||
:desc "Copy project file path" "Y" #'+default/yank-buffer-path-relative-to-project | |||
:desc "Open scratch" "x" #'doom/open-scratch-buffer) | |||
#+END_SRC | |||
**** s: Snippets | |||
#+BEGIN_SRC emacs-lisp | |||
(map! :leader | |||
:prefix ("f s" . "snippets") | |||
:desc "New snippet" "n" #'yas-new-snippet | |||
:desc "Edit snippet" "e" #'yas-visit-snippet-file | |||
:desc "Browse docs" "?" #'my/yas-browse-docs) | |||
#+END_SRC | |||
Add a command to open the YASnippet docs. | |||
#+BEGIN_SRC elisp | |||
(defun my/yas-browse-docs () | |||
(interactive) | |||
(browse-url "https://joaotavora.github.io/yasnippet")) | |||
#+END_SRC | |||
**** e: Emacs Files | |||
#+BEGIN_SRC elisp | |||
(map! :leader | |||
:prefix ("f e" . "emacs") | |||
:desc "Find in config" "f" #'doom/find-file-in-private-config | |||
:desc "Reload config" "r" #'doom/reload | |||
:desc "Edit config" "c" #'my/edit-config | |||
:desc "Edit packages" "p" #'my/edit-packages | |||
:desc "Edit env" "e" #'my/edit-env | |||
:desc "Edit init" "i" #'my/edit-init) | |||
#+END_SRC | |||
#+BEGIN_SRC elisp | |||
(defun my/edit-config () | |||
(interactive) | |||
(find-file (concat doom-private-dir "config.org"))) | |||
(defun my/edit-packages () | |||
(interactive) | |||
(find-file (concat doom-private-dir "packages.el"))) | |||
(defun my/edit-init () | |||
(interactive) | |||
(find-file (concat doom-private-dir "init.el"))) | |||
(defun my/edit-env () | |||
(interactive) | |||
(find-file (concat doom-private-dir "env.el"))) | |||
#+END_SRC | |||
Define a derived mode for editing the literate config so we can specify some | |||
keybindings specific to =config.org=. | |||
#+BEGIN_SRC elisp | |||
(define-derived-mode org-config-mode org-mode "Org config mode") | |||
(add-to-list 'auto-mode-alist '("config\\.org" . org-config-mode)) | |||
#+END_SRC | |||
*** h: Help | |||
#+BEGIN_SRC elisp | |||
(map! :leader | |||
:prefix ("h" . "help") | |||
:desc "Apropos" "/" #'consult-apropos | |||
:desc "Apropos docs" "?" #'apropos-documentation | |||
:desc "Help at point" "p" #'helpful-at-point | |||
:desc "Help info" "h" #'info | |||
:desc "Help for help" "H" #'help-for-help | |||
:desc "Describe function" "f" #'counsel-describe-function | |||
:desc "Describe function key" "F" #'where-is | |||
:desc "Describe variable" "v" #'counsel-describe-variable | |||
:desc "Describe custom variable" "V" #'doom/help-custom-variable | |||
:desc "Describe command" "x" #'helpful-command | |||
:desc "Describe key" "k" #'describe-key-briefly | |||
:desc "Describe key fully" "K" #'describe-key | |||
:desc "Describe char" "'" #'describe-char | |||
:desc "Describe coding system" "\"" #'describe-coding-system | |||
:desc "Describe input method" "i" #'describe-input-method | |||
:desc "Emacs manual" "e" #'info-emacs-manual | |||
:desc "ASCII table" "a" #'my/ascii-table | |||
:desc "View messages" "e" #'view-echo-area-messages | |||
:desc "View keystrokes" "l" #'view-lossage) | |||
#+END_SRC | |||
**** a: Ascii Table | |||
#+BEGIN_SRC elisp | |||
(defface my/ascii-table-highlight-face | |||
'((t (:foreground "pink"))) | |||
"Face for highlighting ASCII chars.") | |||
(defun my/ascii-table () | |||
"Display basic ASCII table (0 thru 128)." | |||
(interactive) | |||
(pop-to-buffer "*ASCII*") | |||
(erase-buffer) | |||
(setq buffer-read-only nil) | |||
(my/buffer-local-set-key "q" #'+popup/quit-window) | |||
(setq lower32 '("nul" "soh" "stx" "etx" "eot" "enq" "ack" "bel" | |||
"bs" "ht" "nl" "vt" "np" "cr" "so" "si" | |||
"dle" "dc1" "dc2" "dc3" "dc4" "nak" "syn" "etb" | |||
"can" "em" "sub" "esc" "fs" "gs" "rs" "us")) | |||
(save-excursion (let ((i -1)) | |||
(insert " Hex Dec Char | Hex Dec Char | Hex Dec Char | Hex Dec Char\n") | |||
(insert " ---------------+-----------------+-----------------+----------------\n") | |||
(while (< i 31) | |||
(insert (format "%4x %4d %4s | %4x %4d %4s | %4x %4d %4s | %4x %4d %4s\n" | |||
(setq i (+ 1 i)) i (elt lower32 i) | |||
(setq i (+ 32 i)) i (single-key-description i) | |||
(setq i (+ 32 i)) i (single-key-description i) | |||
(setq i (+ 32 i)) i (single-key-description i))) | |||
(overlay-put (make-overlay (- (point) 4) (- (point) 1)) 'face 'my/ascii-table-highlight-face) | |||
(overlay-put (make-overlay (- (point) 22) (- (point) 19)) 'face 'my/ascii-table-highlight-face) | |||
(overlay-put (make-overlay (- (point) 40) (- (point) 37)) 'face 'my/ascii-table-highlight-face) | |||
(overlay-put (make-overlay (- (point) 58) (- (point) 55)) 'face 'my/ascii-table-highlight-face) | |||
(setq i (- i 96)) | |||
)))) | |||
(set-popup-rule! "^\\*ASCII" | |||
:side 'right | |||
:select t | |||
:width 70) | |||
#+END_SRC | |||
**** d: Doom | |||
#+BEGIN_SRC elisp | |||
(map! :leader | |||
:prefix ("h d" . "doom") | |||
:desc "Doom manual" "d" #'doom/help | |||
:desc "Doom FAQ" "f" #'doom/help-faq | |||
:desc "Doom modules" "m" #'doom/help-modules | |||
:desc "Doom news" "n" #'doom/help-news | |||
:desc "Doom help search" "/" #'doom/help-search-headings | |||
:desc "Doom version" #'doom/version | |||
:desc "Doom package configuration" "p" #'doom/help-package-config | |||
:desc "Doom sandbox" "x" #'doom/sandbox) | |||
#+END_SRC | |||
*** p: Projects | |||
#+BEGIN_SRC elisp | |||
(map! :leader | |||
:prefix ("p" . "projects") | |||
:desc "Switch project" "p" #'counsel-projectile-switch-project | |||
:desc "Add new project" "a" #'projectile-add-known-project | |||
:desc "Remove project" "d" #'projectile-remove-known-project | |||
:desc "Find in project root" "." #'counsel-projectile-find-file | |||
:desc "Search in project" "/" #'+default/search-project | |||
:desc "Invalidate project cache" "i" #'projectile-invalidate-cache | |||
:desc "Run cmd in project root" "!" #'projectile-run-shell-command-in-root | |||
:desc "Run async cmd in project root" "&" #'projectile-run-async-shell-command-in-root) | |||
(defun my/projectile-find-in-root () | |||
(interactive) | |||
(counsel-find-file nil projectile-project-root)) | |||
#+END_SRC | |||
*** t: Toggle | |||
#+BEGIN_SRC elisp | |||
(map! :leader | |||
:prefix ("t" . "toggle") | |||
;; Wrap | |||
:desc "Auto Wrap" "a" #'auto-fill-mode | |||
:desc "Wrap Indicator" "c" #'global-display-fill-column-indicator-mode | |||
:desc "Wrap Column" "C" #'set-fill-column | |||
:desc "Line Wrap" "w" #'visual-line-mode | |||
;; Modes | |||
:desc "Flycheck" "f" #'flycheck-mode | |||
;; Files | |||
:desc "Read-only" "r" #'read-only-mode) | |||
#+END_SRC | |||
#+BEGIN_SRC elisp | |||
(defun my/auto-fill-mode (cols) | |||
(interactive)) | |||
#+END_SRC | |||
*** w: Window | |||
#+BEGIN_SRC elisp | |||
(map! :leader | |||
:prefix-map ("w" . "window") | |||
;; Navigation | |||
:desc "Go..." "w" #'ace-window | |||
:desc "Go left" "h" #'evil-window-left | |||
:desc "Go down" "j" #'evil-window-down | |||
:desc "Go up" "k" #'evil-window-up | |||
:desc "Go right" "l" #'evil-window-right | |||
:desc "Go other" "o" #'other-window | |||
;; Layout | |||
:desc "Rotate up" "K" #'evil-window-rotate-upwards | |||
:desc "Rotate down" "J" #'evil-window-rotate-downwards | |||
;; Splits | |||
:desc "VSplit" "=" #'+evil/window-vsplit-and-follow | |||
:desc "HSplit" "-" #'+evil/window-split-and-follow | |||
:desc "Tear off" "t" #'tear-off-window | |||
;; History | |||
:desc "Undo" "u" #'winner-undo | |||
:desc "Redo" "U" #'winner-redo | |||
;; Misc | |||
:desc "Resize" "r" #'my/hydra-window-resize/body | |||
:desc "Balance" "b" #'balance-windows | |||
;; Management | |||
:desc "Kill window" "d" #'+workspace/close-window-or-workspace) | |||
;; TODO: Maybe check out: | |||
;; evil-window-mru | |||
#+END_SRC | |||
#+BEGIN_SRC elisp | |||
(setq my/window-resize-step 3) | |||
(defun my/window-increase-height () | |||
(interactive) | |||
(evil-window-increase-height my/window-resize-step)) | |||
(defun my/window-decrease-height () | |||
(interactive) | |||
(evil-window-decrease-height my/window-resize-step)) | |||
(defun my/window-increase-width () | |||
(interactive) | |||
(evil-window-increase-width my/window-resize-step)) | |||
(defun my/window-decrease-width () | |||
(interactive) | |||
(evil-window-decrease-width my/window-resize-step)) | |||
(defhydra my/hydra-window-resize () | |||
"Resize window" | |||
("=" my/window-increase-height "++Height") | |||
("-" my/window-decrease-height "--Height") | |||
("<" my/window-decrease-width "--Width") | |||
(">" my/window-increase-width "++Width")) | |||
#+END_SRC | |||
** Local Leader | |||
*** Org Config | |||
#+BEGIN_SRC elisp | |||
(map! :map org-config-mode-map | |||
:localleader | |||
:v :desc "Eval Region" "e" #'eval-region | |||
:n :desc "Eval Source" "e" #'my/org-config-eval-source) | |||
(defun my/org-config-eval-source () | |||
(interactive) | |||
(org-ctrl-c-ctrl-c) | |||
(org-babel-remove-result)) | |||
#+END_SRC | |||
*** Rust | |||
#+BEGIN_SRC elisp | |||
(map! :map rustic-mode-map | |||
:localleader | |||
:desc "Debug..." "d" #'my/rust/dap-hydra/body) | |||
(map! :map rustic-mode-map | |||
:desc "Pluralize import" "," #'my/rust/import-pluralize | |||
:desc "Singularize import" "<backspace>" #'my/rust/import-singularize | |||
:desc "Singularize import" "C-<backspace>" #'my/rust/import-c-singularize) | |||
#+END_SRC | |||
#+BEGIN_SRC elisp | |||
(defhydra my/rust/dap-hydra (:color pink :hint nil :foreign-keys run) | |||
" | |||
^Stepping^ ^Switch^ ^Breakpoints^ ^Debug^ ^Eval | |||
^^^^^^^^---------------------------------------------------------------------------------------------------------------- | |||
_n_: Next _ss_: Session _bb_: Toggle _dd_: Debug binary _ee_: Eval | |||
_i_: Step in _st_: Thread _bd_: Delete _dr_: Restart debugging _es_: Eval thing at point | |||
_o_: Step out _sf_: Stack frame _ba_: Add _ea_: Add expression | |||
_c_: Continue _su_: Up stack frame _bc_: Set condition | |||
_Q_: Disconnect _sd_: Down stack frame _bh_: Set hit count | |||
_sl_: List locals _bl_: Set log message | |||
_sb_: List breakpoints | |||
_sS_: List sessions | |||
" | |||
("n" dap-next) | |||
("i" dap-step-in) | |||
("o" dap-step-out) | |||
("c" dap-continue) | |||
("r" dap-restart-frame) | |||
("ss" dap-switch-session) | |||
("st" dap-switch-thread) | |||
("sf" dap-switch-stack-frame) | |||
("su" dap-up-stack-frame) | |||
("sd" dap-down-stack-frame) | |||
("sl" dap-ui-locals) | |||
("sb" dap-ui-breakpoints) | |||
("sS" dap-ui-sessions) | |||
("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" my/rust/debug-binary) | |||
("dr" dap-debug-restart) | |||
("ee" dap-eval) | |||
("ea" dap-ui-expressions-add) | |||
("es" dap-eval-thing-at-point) | |||
("q" nil "quit" :color blue) | |||
("Q" dap-disconnect :color red)) | |||
#+END_SRC | |||
** Modes | |||
*** Evil | |||
**** z | |||
#+BEGIN_SRC elisp | |||
(map! :prefix "z" | |||
:desc "Kill buffer" :n "x" #'kill-current-buffer | |||
:desc "Kill window" :n "c" #'+workspace/close-window-or-workspace) | |||
#+END_SRC | |||
**** g | |||
**** [ | |||
#+BEGIN_SRC elisp | |||
(map! :prefix "[" | |||
:desc "Start of fn" :n "f" #'beginning-of-defun) | |||
(map! :prefix "]" | |||
:desc "End of fn" :n "f" #'end-of-defun) | |||
#+END_SRC | |||
*** Dap | |||
#+BEGIN_SRC elisp | |||
#+END_SRC | |||
* Languages | |||
** Rust | |||
*** General | |||
#+BEGIN_SRC elisp | |||
(add-to-list 'projectile-globally-ignored-files "Cargo.lock") | |||
#+END_SRC | |||
*** Editing | |||
#+BEGIN_SRC elisp | |||
(defun my/rust/import-pluralize () | |||
"Convert a singular import into a brace-wrapped plural import." | |||
(interactive) | |||
(if (and | |||
(not (my/kbd!-p)) | |||
(my/insert-mode-p) | |||
(my/line-match-p | |||
;; use foo::bar::baz; | |||
(rx line-start "use " | |||
(+ (+ word) "::") | |||
(+ word) | |||
(? ";") line-end))) | |||
(kbd! "ESC vb S} f} i,") | |||
(insert ","))) | |||
(defun my/rust/import-singularize () | |||
"Convert a brace-wrapped plural import into a singular import." | |||
(interactive) | |||
(if (and | |||
(not (my/kbd!-p)) | |||
(my/insert-mode-p) | |||
(my/line-match-p | |||
;; use foo::bar::baz::{qux::quo,}; | |||
(rx line-start "use " | |||
(+ (+ word) "::") | |||
"{" (* (+ word) "::") (+ word) ",}" | |||
(? ";") line-end))) | |||
(kbd! "ESC l dF, ds} $i") | |||
(evil-delete-backward-char-and-join 1))) | |||
(defun my/rust/import-c-singularize () | |||
"Convert a brace-wrapped plural import into a singular import." | |||
(interactive) | |||
(if (and | |||
(not (my/kbd!-p)) | |||
(my/insert-mode-p) | |||
(my/line-match-p | |||
;; use foo::bar::baz::{qux::quo, }; | |||
(rx line-start | |||
"use " | |||
(+ (+ word) "::") | |||
"{" (* (+ word) "::") (+ word) "," (* whitespace) "}" | |||
(? ";") line-end))) | |||
(kbd! "ESC l dF, ds} $i") | |||
(backward-kill-word 1))) | |||
#+END_SRC | |||
*** Debugging | |||
#+BEGIN_SRC elisp | |||
(defun my/rust/debug-config (args) | |||
(append | |||
`(:type "lldb-vscode" | |||
;; `(:type "lldb" | |||
:request "launch" | |||
:dap-server-path ,(list (executable-find "lldb-vscode")) | |||
;; :dap-server-path ,(list (executable-find "rust-lldb")) | |||
,@args))) | |||
;; use a::TestThin | |||
;; (:MIMode "gdb" | |||
;; :miDebuggerPath "gdb" | |||
;; :stopAtEntry t | |||
;; :externalConsole | |||
;; :json-false | |||
;; :type "cppdbg" | |||
;; :request "launch" | |||
;; :name "test test2" | |||
;; :args ["test2" "--exact" "--nocapture"] | |||
;; :cwd "/home/lain/Code/test/rust/debug" | |||
;; :sourceLanguages ["rust"] | |||
;; :program "/home/lain/Code/test/rust/debug/target/debug/deps/...") | |||
;; (require 'dap-cpptools) | |||
(defun my/rust/debug-binary (args) | |||
(interactive "sArgs: ") | |||
(let* ((root (projectile-project-root)) | |||
(name (projectile-project-name)) | |||
(target (concat root "target/debug/" name))) | |||
;; (rustic-cargo-build) | |||
(dap-debug | |||
(my/rust/debug-config | |||
`(:program ,target | |||
:cwd ,root | |||
:args ,(apply #'vector (split-string-and-unquote args))))))) | |||
(defun my/rust/debug-lsp-runnable (runnable) | |||
"Select and debug a RUNNABLE action." | |||
(interactive (list (lsp-rust-analyzer--select-runnable))) | |||
(-let (((&rust-analyzer:Runnable | |||
:args (&rust-analyzer:RunnableArgs :cargo-args :workspace-root? :executable-args) | |||
:label) runnable)) | |||
(pcase (aref cargo-args 0) | |||
("run" (aset cargo-args 0 "build")) | |||
("test" (when (-contains? (append cargo-args ()) "--no-run") | |||
(cl-callf append cargo-args (list "--no-run"))))) | |||
(->> (append (list (executable-find "cargo")) | |||
cargo-args | |||
(list "--message-format=json")) | |||
(s-join " ") | |||
(shell-command-to-string) | |||
(s-lines) | |||
(-keep (lambda (s) | |||
(condition-case nil | |||
(-let* ((json-object-type 'plist) | |||
((msg &as &plist :reason :executable) (json-read-from-string s))) | |||
(when (and executable (string= "compiler-artifact" reason)) | |||
executable)) | |||
(error)))) | |||
(funcall | |||
(lambda (artifact-spec) | |||
(pcase artifact-spec | |||
(`() (user-error "No compilation artifacts or obtaining the runnable artifacts failed")) | |||
(`(,spec) spec) | |||
(_ (user-error "Multiple compilation artifacts are not supported"))))) | |||
(list :name label | |||
:args executable-args | |||
:cwd workspace-root? | |||
;; :sourceLanguages ["rust"] | |||
:stopAtEntry t | |||
:stopAtEntry :json-true | |||
:externalConsole :json-false | |||
:program) | |||
(my/rust/debug-config) | |||
(dap-debug)))) | |||
(advice-add #'lsp-rust-analyzer-debug :override #'my/rust/debug-lsp-runnable) | |||
#+END_SRC | |||
** Go | |||
*** Debugging | |||
Setup: run =M-x dap-go-setup= | |||
* Tools | |||
** Projectile | |||
#+BEGIN_SRC elisp | |||
;; (setq projectile-project-search-path | |||
;; '("~/Code")) | |||
#+END_SRC | |||
** Counsel Search | |||
#+BEGIN_SRC elisp | |||
(let ((found (nth 0 (auth-source-search :host "kagi.com")))) | |||
(when found | |||
(let ((token (plist-get found :secret))) | |||
(when (functionp token) | |||
(setq token (funcall token))) | |||
(add-to-list | |||
'counsel-search-engines-alist | |||
`(kagi | |||
"https://duckduckgo.com/ac/" | |||
,(format "https://kagi.com/search?token=%s&q=" token) | |||
counsel--search-request-data-ddg)) | |||
(setq counsel-search-engine 'kagi)))) | |||
#+END_SRC | |||
* Apps | |||
** Emacs Everywhere | |||
#+BEGIN_SRC elisp | |||
(load! "lisp/emacs-everywhere.el") | |||
(setq emacs-everywhere-paste-command '("xdotool" "key" "--clearmodifiers" "ctrl+v")) | |||
(setq emacs-everywhere-frame-parameters | |||
'((title . "Emacs Everywhere") | |||
(width . 120) | |||
(height . 36))) | |||
#+END_SRC | |||
* Lisp | |||
** Editing | |||
#+BEGIN_SRC elisp | |||
(defun my/line () | |||
(buffer-substring-no-properties | |||
(line-beginning-position) | |||
(line-end-position))) | |||
(defun my/line-match-p (regexp) | |||
(string-match-p regexp (my/line))) | |||
#+END_SRC | |||
#+BEGIN_SRC elisp | |||
(defun my/insert-mode-p () | |||
(eq evil-state 'insert)) | |||
(defun my/normal-mode-p () | |||
(eq evil-state 'normal)) | |||
#+END_SRC | |||
** Keybindings | |||
#+BEGIN_SRC elisp | |||
(defun my/kbd-replace (str) | |||
"Convert STR into a keyboard macro string by replacing terminal key sequences with GUI keycodes." | |||
(let ((kbd-regex '(("ESC" . "<escape>") | |||
("DEL" . "<delete>" ) | |||
("BS" . "<backspace>") | |||
("RET" . "<return>") | |||
("SPC" . "<SPC>") | |||
("TAB" . "<tab>")))) | |||
(my/replace-regexps-in-string str kbd-regex))) | |||
(setq my//kbd-p nil) | |||
(defun my/kbd!-p () (eq my//kbd-p t)) | |||
(defun kbd! (str) | |||
"Execute the key sequence defined by STR like a VIM macro." | |||
(let ((minibuffer-message-timeout 0)) | |||
(setq my//kbd-p t) | |||
(execute-kbd-macro (read-kbd-macro (my/kbd-replace str))) | |||
(setq my//kbd-p nil))) | |||
#+END_SRC | |||
#+BEGIN_SRC elisp | |||
(defun my/buffer-local-set-key (key fn) | |||
(let ((mode (intern (format "%s-local-mode" (buffer-name)))) | |||
(map (intern (format "%s-local-mode-map" (buffer-name))))) | |||
(unless (boundp map) | |||
(set map (make-sparse-keymap)) | |||
(evil-make-overriding-map map 'normal)) | |||
(eval | |||
`(define-minor-mode ,mode | |||
"A minor mode for buffer-local keybinds." | |||
:keymap ,map)) | |||
(eval | |||
`(define-key ,map ,key #',fn)) | |||
(funcall mode t))) | |||
#+END_SRC | |||
** Regex | |||
#+BEGIN_SRC elisp | |||
(defun my/replace-regexps-in-string (str regexps) | |||
"Replace all pairs of (regex . replacement) defined by REGEXPS in STR." | |||
(if (null regexps) | |||
str | |||
(my/replace-regexps-in-string | |||
(replace-regexp-in-string (caar regexps) (cdar regexps) str t) | |||
(cdr regexps)))) | |||
#+END_SRC |
@@ -0,0 +1,2 @@ | |||
("DISPLAY=:0" | |||
"SSH_AUTH_SOCK=/run/user/1000/gnupg/S.gpg-agent.ssh") |
@@ -0,0 +1,189 @@ | |||
;;; init.el -*- lexical-binding: t; -*- | |||
;; This file controls what Doom modules are enabled and what order they load | |||
;; in. Remember to run 'doom sync' after modifying it! | |||
;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's | |||
;; documentation. There you'll find a "Module Index" link where you'll find | |||
;; a comprehensive list of Doom's modules and what flags they support. | |||
;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or | |||
;; 'C-c c k' for non-vim users) to view its documentation. This works on | |||
;; flags as well (those symbols that start with a plus). | |||
;; | |||
;; Alternatively, press 'gd' (or 'C-c c d') on a module to browse its | |||
;; directory (for easy access to its source code). | |||
(doom! :input | |||
;;chinese | |||
;;japanese | |||
;;layout ; auie,ctsrnm is the superior home row | |||
:completion | |||
company ; the ultimate code completion backend | |||
;;helm ; the *other* search engine for love and life | |||
;;ido ; the other *other* search engine... | |||
(ivy +prescient +icons) ; a search engine for love and life | |||
vertico ; the search engine of the future | |||
:ui | |||
;;deft ; notational velocity for Emacs | |||
doom ; what makes DOOM look the way it does | |||
doom-dashboard ; a nifty splash screen for Emacs | |||
doom-quit ; DOOM quit-message prompts when you quit Emacs | |||
(emoji +unicode) ; 🙂 | |||
hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW | |||
hydra | |||
;;indent-guides ; highlighted indent columns | |||
;;ligatures ; ligatures and symbols to make your code pretty again | |||
;;minimap ; show a map of the code on the side | |||
modeline ; snazzy, Atom-inspired modeline, plus API | |||
;;nav-flash ; blink cursor line after big motions | |||
;;neotree ; a project drawer, like NERDTree for vim | |||
ophints ; highlight the region an operation acts on | |||
(popup +defaults) ; tame sudden yet inevitable temporary windows | |||
;;tabs ; a tab bar for Emacs | |||
(treemacs +lsp) ; a project drawer, like neotree but cooler | |||
;;unicode ; extended unicode support for various languages | |||
vc-gutter ; vcs diff in the fringe | |||
vi-tilde-fringe ; fringe tildes to mark beyond EOB | |||
;;window-select ; visually switch windows | |||
workspaces ; tab emulation, persistence & separate workspaces | |||
;;zen ; distraction-free coding or writing | |||
:editor | |||
(evil +everywhere); come to the dark side, we have cookies | |||
;;file-templates ; auto-snippets for empty files | |||
fold ; (nigh) universal code folding | |||
format ; (+onsave) automated prettiness | |||
;;god ; run Emacs commands without modifier keys | |||
lispy ; vim for lisp, for people who don't like vim | |||
multiple-cursors ; editing in many places at once | |||
;;objed ; text object editing for the innocent | |||
;;parinfer ; turn lisp into python, sort of | |||
;;rotate-text ; cycle region at point between text candidates | |||
snippets ; my elves. They type so I don't have to | |||
;;word-wrap ; soft wrapping with language-aware indent | |||
:emacs | |||
dired ; making dired pretty [functional] | |||
electric ; smarter, keyword-based electric-indent | |||
;;ibuffer ; interactive buffer management | |||
undo ; persistent, smarter undo for your inevitable mistakes | |||
vc ; version-control and Emacs, sitting in a tree | |||
:term | |||
eshell ; the elisp shell that works everywhere | |||
;;shell ; simple shell REPL for Emacs | |||
;;term ; basic terminal emulator for Emacs | |||
;;vterm ; the best terminal emulation in Emacs | |||
:checkers | |||
syntax ; tasing you for every semicolon you forget | |||
;;(spell +flyspell) ; tasing you for misspelling mispelling | |||
;;grammar ; tasing grammar mistake every you make | |||
:tools | |||
;;ansible | |||
(debugger +lsp) ; FIXME stepping through code, to help you add bugs | |||
;;direnv | |||
docker | |||
editorconfig ; let someone else argue about tabs vs spaces | |||
;;ein ; tame Jupyter notebooks with emacs | |||
(eval +overlay) ; run code, run (also, repls) | |||
;;gist ; interacting with github gists | |||
lookup ; navigate your code and its documentation | |||
lsp ; M-x vscode | |||
(magit +forge) ; a git porcelain for Emacs | |||
make ; run make tasks from Emacs | |||
;;pass ; password manager for nerds | |||
pdf ; pdf enhancements | |||
;;prodigy ; FIXME managing external services & code builders | |||
;;rgb ; creating color strings | |||
taskrunner ; taskrunner for all your projects | |||
terraform ; infrastructure as code | |||
tmux ; an API for interacting with tmux | |||
;;upload ; map local to remote projects via ssh/ftp | |||
:os | |||
(:if IS-MAC macos) ; improve compatibility with macOS | |||
;;tty ; improve the terminal Emacs experience | |||
:lang | |||
;;agda ; types of types of types of types... | |||
;;beancount ; mind the GAAP | |||
(cc +lsp) ; C > C++ == 1 | |||
;;clojure ; java with a lisp | |||
;;common-lisp ; if you've seen one lisp, you've seen them all | |||
;;coq ; proofs-as-programs | |||
;;crystal ; ruby at the speed of c | |||
;;csharp ; unity, .NET, and mono shenanigans | |||
;;data ; config/data formats | |||
;;(dart +flutter) ; paint ui and not much else | |||
;;dhall | |||
elixir ; erlang done right | |||
;;elm ; care for a cup of TEA? | |||
emacs-lisp ; drown in parentheses | |||
;;erlang ; an elegant language for a more civilized age | |||
;;ess ; emacs speaks statistics | |||
;;factor | |||
;;faust ; dsp, but you get to keep your soul | |||
;;fsharp ; ML stands for Microsoft's Language | |||
;;fstar ; (dependent) types and (monadic) effects and Z3 | |||
;;gdscript ; the language you waited for | |||
(go +lsp) ; the hipster dialect | |||
(haskell +lsp) ; a language that's lazier than I am | |||
;;hy ; readability of scheme w/ speed of python | |||
;;idris ; a language you can depend on | |||
json ; At least it ain't XML | |||
(java +meghanada) ; the poster child for carpal tunnel syndrome | |||
javascript ; all(hope(abandon(ye(who(enter(here)))))) | |||
julia ; a better, faster MATLAB | |||
;;kotlin ; a better, slicker Java(Script) | |||
latex ; writing papers in Emacs has never been so fun | |||
;;lean ; for folks with too much to prove | |||
;;ledger ; be audit you can be | |||
lua ; one-based indices? one-based indices | |||
markdown ; writing docs for people to ignore | |||
;;nim ; python + lisp at the speed of c | |||
;;nix ; I hereby declare "nix geht mehr!" | |||
;;ocaml ; an objective camel | |||
org ; organize your plain life in plain text | |||
php ; perl's insecure younger brother | |||
;;plantuml ; diagrams for confusing people more | |||
;;purescript ; javascript, but functional | |||
(python +lsp +pyright) ; beautiful is better than ugly | |||
;;qt ; the 'cutest' gui framework ever | |||
;;racket ; a DSL for DSLs | |||
;;raku ; the artist formerly known as perl6 | |||
;;rest ; Emacs as a REST client | |||
;;rst ; ReST in peace | |||
;;(ruby +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"} | |||
(rust +lsp) ; Fe2O3.unwrap().unwrap().unwrap().unwrap() | |||
;;scala ; java, but good | |||
(scheme +guile) ; a fully conniving family of lisps | |||
(sh +fish) ; she sells {ba,z,fi}sh shells on the C xor | |||
;;sml | |||
;;solidity ; do you need a blockchain? No. | |||
;;swift ; who asked for emoji variables? | |||
;;terra ; Earth and Moon in alignment for performance. | |||
web ; the tubes | |||
yaml ; JSON, but readable | |||
;;zig ; C, but simpler | |||
;;(mu4e +org +gmail) | |||
;;notmuch | |||
;;(wanderlust +gmail) | |||
:app | |||
calendar | |||
;;emms | |||
everywhere ; *leave* Emacs!? You must be joking | |||
irc ; how neckbeards socialize | |||
;;(rss +org) ; emacs as an RSS reader | |||
;;twitter ; twitter client https://twitter.com/vnought | |||
:config | |||
literate | |||
(default +bindings +smartparens)) |
@@ -0,0 +1,546 @@ | |||
;;; emacs-everywhere.el --- System-wide popup windows for quick edits -*- lexical-binding: t; -*- | |||
;; Copyright (C) 2021 TEC | |||
;; Author: TEC <https://github.com/tecosaur> | |||
;; Maintainer: TEC <tec@tecosaur.com> | |||
;; Created: February 06, 2021 | |||
;; Modified: February 06, 2021 | |||
;; Version: 0.1.0 | |||
;; Keywords: conenience, frames | |||
;; Homepage: https://github.com/tecosaur/emacs-everywhere | |||
;; Package-Requires: ((emacs "26.3")) | |||
;;; License: | |||
;; This file is part of org-pandoc-import, which is not part of GNU Emacs. | |||
;; SPDX-License-Identifier: GPL-3.0-or-later | |||
;;; Commentary: | |||
;; System-wide popup Emacs windows for quick edits | |||
;;; Code: | |||
(require 'cl-lib) | |||
(require 'server) | |||
(defgroup emacs-everywhere () | |||
"Customise group for Emacs-everywhere." | |||
:group 'convenience) | |||
(define-obsolete-variable-alias | |||
'emacs-everywhere-paste-p 'emacs-everywhere-paste-command "0.1.0") | |||
(defvar emacs-everywhere--display-server | |||
(cond | |||
((eq system-type 'darwin) 'quartz) | |||
((memq system-type '(ms-dos windows-nt cygwin)) 'windows) | |||
((executable-find "loginctl") | |||
(pcase (string-trim | |||
(shell-command-to-string "loginctl show-session $(loginctl | grep $(whoami) | awk '{print $1}') -p Type") | |||
"Type=" "\n") | |||
("x11" 'x11) | |||
("wayland" 'wayland) | |||
(_ 'unknown))) | |||
(t 'unknown)) | |||
"The detected display server.") | |||
(defcustom emacs-everywhere-paste-command | |||
(pcase emacs-everywhere--display-server | |||
('quartz (list "osascript" "-e" "tell application \"System Events\" to keystroke \"v\" using command down")) | |||
('x11 (list "xdotool" "key" "--clearmodifiers" "Shift+Insert")) | |||
((or 'wayland 'unknown) | |||
(list "notify-send" | |||
"No paste command defined for emacs-everywhere" | |||
"-a" "Emacs" "-i" "emacs"))) | |||
"Command to trigger a system paste from the clipboard. | |||
This is given as a list in the form (CMD ARGS...). | |||
To not run any command, set to nil." | |||
:type '(set (repeat string) (const nil)) | |||
:group 'emacs-everywhere) | |||
(defcustom emacs-everywhere-copy-command | |||
(pcase emacs-everywhere--display-server | |||
('x11 (list "xclip" "-selection" "clipboard" "%f")) | |||
((and 'wayland (guard (executable-find "wl-copy"))) | |||
(list "sh" "-c" "wl-copy < %f"))) | |||
"Command to write to the system clipboard from a file (%f). | |||
This is given as a list in the form (CMD ARGS...). | |||
In the arguments, \"%f\" is treated as a placeholder for the path | |||
to the file. | |||
When nil, nothing is executed. | |||
`gui-select-text' is always called on the buffer content, however experience | |||
suggests that this can be somewhat flakey, and so an extra step to make sure | |||
it worked can be a good idea." | |||
:type '(set (repeat string) (const nil)) | |||
:group 'emacs-everywhere) | |||
(defcustom emacs-everywhere-window-focus-command | |||
(pcase emacs-everywhere--display-server | |||
('quartz (list "osascript" "-e" "tell application \"%w\" to activate")) | |||
('x11 (list "xdotool" "windowactivate" "--sync" "%w"))) | |||
"Command to refocus the active window when emacs-everywhere was triggered. | |||
This is given as a list in the form (CMD ARGS...). | |||
In the arguments, \"%w\" is treated as a placeholder for the window ID, | |||
as returned by `emacs-everywhere-app-id'. | |||
When nil, nothing is executed, and pasting is not attempted." | |||
:type '(set (repeat string) (const nil)) | |||
:group 'emacs-everywhere) | |||
(defcustom emacs-everywhere-markdown-windows | |||
'("Reddit" "Stack Exchange" "Stack Overflow" ; Sites | |||
"Discord" "Element" "Slack" "HedgeDoc" "HackMD" "Zulip" ; Web Apps | |||
"Pull Request" "Issue" "Comparing .*\\.\\.\\.") ; Github | |||
"For use with `emacs-everywhere-markdown-p'. | |||
Patterns which are matched against the window title." | |||
:type '(rep string) | |||
:group 'emacs-everywhere) | |||
(defcustom emacs-everywhere-markdown-apps | |||
'("Discord" "Element" "Fractal" "NeoChat" "Slack") | |||
"For use with `emacs-everywhere-markdown-p'. | |||
Patterns which are matched against the app name." | |||
:type '(rep string) | |||
:group 'emacs-everywhere) | |||
(defcustom emacs-everywhere-frame-name-format "Emacs Everywhere :: %s — %s" | |||
"Format string used to produce the frame name. | |||
Formatted with the app name, and truncated window name." | |||
:type 'string | |||
:group 'emacs-everywhere) | |||
(defcustom emacs-everywhere-init-hooks | |||
`(emacs-everywhere-set-frame-name | |||
emacs-everywhere-set-frame-position | |||
,(cond | |||
((executable-find "pandoc") #'org-mode) | |||
((fboundp 'markdown-mode) #'emacs-everywhere-major-mode-org-or-markdown) | |||
(t #'text-mode)) | |||
emacs-everywhere-insert-selection | |||
emacs-everywhere-remove-trailing-whitespace | |||
emacs-everywhere-init-spell-check) | |||
"Hooks to be run before function `emacs-everywhere-mode'." | |||
:type 'hook | |||
:group 'emacs-everywhere) | |||
(defcustom emacs-everywhere-final-hooks | |||
'(emacs-everywhere-remove-trailing-whitespace | |||
emacs-everywhere-return-converted-org-to-gfm) | |||
"Hooks to be run just before content is copied." | |||
:type 'hook | |||
:group 'emacs-everywhere) | |||
(defcustom emacs-everywhere-frame-parameters | |||
`((name . "emacs-everywhere") | |||
(width . 80) | |||
(height . 12)) | |||
"Parameters `make-frame' recognises to apply to the emacs-everywhere frame." | |||
:type 'list | |||
:group 'emacs-everywhere) | |||
(defcustom emacs-everywhere-file-dir | |||
temporary-file-directory | |||
"The default directory for temp files generated by `emacs-everywhere-filename-function'." | |||
:type 'string | |||
:group 'emacs-everywhere) | |||
(defcustom emacs-everywhere-file-patterns | |||
(let ((default-directory emacs-everywhere-file-dir)) | |||
(list (concat "^" (regexp-quote (file-truename "emacs-everywhere-"))) | |||
;; For qutebrowser 'editor.command' support | |||
(concat "^" (regexp-quote (file-truename "qutebrowser-editor-"))))) | |||
"A list of file regexps to activate `emacs-everywhere-mode' for." | |||
:type '(repeat regexp) | |||
:group 'emacs-everywhere) | |||
(defun emacs-everywhere-temp-filename (app-info) | |||
"Generate a temp file." | |||
(concat "emacs-everywhere-" | |||
(format-time-string "%Y%m%d-%H%M%S-" (current-time)) | |||
(emacs-everywhere-app-class app-info))) | |||
(defcustom emacs-everywhere-filename-function | |||
#'emacs-everywhere-temp-filename | |||
"A function which generates a file name for the buffer. | |||
The function is passed the result of `emacs-everywhere-app-info'. | |||
Make sure that it will be matched by `emacs-everywhere-file-patterns'." | |||
:type 'function | |||
:group 'emacs-everywhere) | |||
;; Semi-internal variables | |||
(defconst emacs-everywhere-osascript-accessibility-error-message | |||
"osascript is not allowed assistive access" | |||
"String to search for to determine if Emacs does not have accessibility rights.") | |||
(defvar-local emacs-everywhere-current-app nil | |||
"The current `emacs-everywhere-app'") | |||
;; Prevents buffer-local variable from being unset by major mode changes | |||
(put 'emacs-everywhere-current-app 'permanent-local t) | |||
(defvar-local emacs-everywhere--contents nil) | |||
;; Make the byte-compiler happier | |||
(declare-function org-in-src-block-p "org") | |||
(declare-function org-ctrl-c-ctrl-c "org") | |||
(declare-function org-export-to-buffer "ox") | |||
(declare-function evil-insert-state "evil-states") | |||
(declare-function spell-fu-buffer "spell-fu") | |||
(declare-function markdown-mode "markdown-mode") | |||
;;; Primary functionality | |||
;;;###autoload | |||
(defun emacs-everywhere (&optional file line column) | |||
"Lanuch the emacs-everywhere frame from emacsclient." | |||
(let ((app-info (emacs-everywhere-app-info))) | |||
(apply #'call-process "emacsclient" nil 0 nil | |||
(delq | |||
nil (list | |||
(when (server-running-p) | |||
(if server-use-tcp | |||
(concat "--server-file=" | |||
(shell-quote-argument | |||
(expand-file-name server-name server-auth-dir))) | |||
(concat "--socket-name=" | |||
(shell-quote-argument | |||
(expand-file-name server-name server-socket-dir))))) | |||
"-c" "-F" | |||
(prin1-to-string | |||
(cons (cons 'emacs-everywhere-app app-info) | |||
emacs-everywhere-frame-parameters)) | |||
(cond ((and line column) (format "+%d:%d" line column)) | |||
(line (format "+%d" line))) | |||
(or file | |||
(expand-file-name | |||
(funcall emacs-everywhere-filename-function app-info) | |||
emacs-everywhere-file-dir))))))) | |||
(defun emacs-everywhere-file-p (file) | |||
"Return non-nil if FILE should be handled by emacs-everywhere. | |||
This matches FILE against `emacs-everywhere-file-patterns'." | |||
(let ((file (file-truename file))) | |||
(cl-some (lambda (pattern) (string-match-p pattern file)) | |||
emacs-everywhere-file-patterns))) | |||
;;;###autoload | |||
(defun emacs-everywhere-initialise () | |||
"Entry point for the executable. | |||
APP is an `emacs-everywhere-app' struct." | |||
(let ((file (buffer-file-name (buffer-base-buffer)))) | |||
(when (and file (emacs-everywhere-file-p file)) | |||
(let ((app (or (frame-parameter nil 'emacs-everywhere-app) | |||
(emacs-everywhere-app-info)))) | |||
(setq-local emacs-everywhere-current-app app) | |||
(with-demoted-errors "Emacs Everywhere: error running init hooks, %s" | |||
(run-hooks 'emacs-everywhere-init-hooks)) | |||
(emacs-everywhere-mode 1) | |||
(setq emacs-everywhere--contents (buffer-string)))))) | |||
;;;###autoload | |||
(add-hook 'server-visit-hook #'emacs-everywhere-initialise) | |||
(add-hook 'server-done-hook #'emacs-everywhere-finish) | |||
(defvar emacs-everywhere-mode-initial-map | |||
(let ((keymap (make-sparse-keymap))) | |||
(define-key keymap (kbd "DEL") #'emacs-everywhere-erase-buffer) | |||
(define-key keymap (kbd "C-SPC") #'emacs-everywhere-erase-buffer) | |||
keymap) | |||
"Transient keymap invoked when an emacs-everywhere buffer is first created. | |||
Set to `nil' to prevent this transient map from activating in emacs-everywhere | |||
buffers.") | |||
(define-minor-mode emacs-everywhere-mode | |||
"Tweak the current buffer to add some emacs-everywhere considerations." | |||
:init-value nil | |||
:keymap `((,(kbd "C-c C-c") . emacs-everywhere-finish-or-ctrl-c-ctrl-c) | |||
(,(kbd "C-x 5 0") . emacs-everywhere-finish) | |||
(,(kbd "C-c C-k") . emacs-everywhere-abort)) | |||
;; line breaking | |||
(turn-off-auto-fill) | |||
(visual-line-mode t) | |||
;; DEL/C-SPC to clear (first keystroke only) | |||
(when (keymapp emacs-everywhere-mode-initial-map) | |||
(set-transient-map emacs-everywhere-mode-initial-map))) | |||
(defun emacs-everywhere-erase-buffer () | |||
"Delete the contents of the current buffer." | |||
(interactive) | |||
(delete-region (point-min) (point-max))) | |||
(defun emacs-everywhere-finish-or-ctrl-c-ctrl-c () | |||
"Finish emacs-everywhere session or invoke `org-ctrl-c-ctrl-c' in org-mode." | |||
(interactive) | |||
(if (and (eq major-mode 'org-mode) | |||
(org-in-src-block-p)) | |||
(org-ctrl-c-ctrl-c) | |||
(emacs-everywhere-finish))) | |||
(defun emacs-everywhere-finish (&optional abort) | |||
"Copy buffer content, close emacs-everywhere window, and maybe paste. | |||
Must only be called within a emacs-everywhere buffer. | |||
Never paste content when ABORT is non-nil." | |||
(interactive) | |||
(when emacs-everywhere-mode | |||
(when (equal emacs-everywhere--contents (buffer-string)) | |||
(setq abort t)) | |||
(unless abort | |||
(run-hooks 'emacs-everywhere-final-hooks) | |||
(gui-select-text (buffer-string)) | |||
(when emacs-everywhere-copy-command ; handle clipboard finicklyness | |||
(let ((inhibit-message t) | |||
(require-final-newline nil) | |||
write-file-functions) | |||
(write-file buffer-file-name) | |||
(apply #'call-process (car emacs-everywhere-copy-command) | |||
nil nil nil | |||
(mapcar (lambda (arg) | |||
(replace-regexp-in-string "%f" buffer-file-name arg)) | |||
(cdr emacs-everywhere-copy-command)))))) | |||
(sleep-for 0.01) ; prevents weird multi-second pause, lets clipboard info propagate | |||
(when emacs-everywhere-window-focus-command | |||
(let* ((window-id (emacs-everywhere-app-id emacs-everywhere-current-app)) | |||
(window-id-str (if (numberp window-id) (number-to-string window-id) window-id))) | |||
(apply #'call-process (car emacs-everywhere-window-focus-command) | |||
nil nil nil | |||
(mapcar (lambda (arg) | |||
(replace-regexp-in-string "%w" window-id-str arg)) | |||
(cdr emacs-everywhere-window-focus-command))) | |||
;; The frame only has this parameter if this package initialized the temp | |||
;; file its displaying. Otherwise, it was created by another program, likely | |||
;; a browser with direct EDITOR support, like qutebrowser. | |||
(when (and (frame-parameter nil 'emacs-everywhere-app) | |||
emacs-everywhere-paste-command | |||
(not abort)) | |||
(apply #'call-process (car emacs-everywhere-paste-command) | |||
nil nil nil (cdr emacs-everywhere-paste-command))))) | |||
;; Clean up after ourselves in case the buffer survives `server-buffer-done' | |||
;; (b/c `server-existing-buffer' is non-nil). | |||
(emacs-everywhere-mode -1) | |||
(server-buffer-done (current-buffer)))) | |||
(defun emacs-everywhere-abort () | |||
"Abort current emacs-everywhere session." | |||
(interactive) | |||
(set-buffer-modified-p nil) | |||
(emacs-everywhere-finish t)) | |||
;;; Window info | |||
(cl-defstruct emacs-everywhere-app | |||
"Metadata about the last focused window before emacs-everywhere was invoked." | |||
id class title geometry) | |||
(defun emacs-everywhere-app-info () | |||
"Return information on the active window." | |||
(let ((w (pcase system-type | |||
(`darwin (emacs-everywhere-app-info-osx)) | |||
(_ (emacs-everywhere-app-info-linux))))) | |||
(setf (emacs-everywhere-app-title w) | |||
(replace-regexp-in-string | |||
(format " ?-[A-Za-z0-9 ]*%s" | |||
(regexp-quote (emacs-everywhere-app-class w))) | |||
"" | |||
(replace-regexp-in-string | |||
"[^[:ascii:]]+" "-" (emacs-everywhere-app-title w)))) | |||
w)) | |||
(defun emacs-everywhere-call (command &rest args) | |||
"Execute COMMAND with ARGS synchronously." | |||
(with-temp-buffer | |||
(apply #'call-process command nil t nil (remq nil args)) | |||
(when (and (eq system-type 'darwin) | |||
(string-match-p emacs-everywhere-osascript-accessibility-error-message (buffer-string))) | |||
(call-process "osascript" nil nil nil | |||
"-e" (format "display alert \"emacs-everywhere\" message \"Emacs has not been granted accessibility permissions, cannot run emacs-everywhere! | |||
Please go to 'System Preferences > Security & Privacy > Privacy > Accessibility' and allow Emacs.\"" )) | |||
(error "MacOS accessibility error, aborting.")) | |||
(string-trim (buffer-string)))) | |||
(defun emacs-everywhere-app-info-linux () | |||
"Return information on the active window, on linux." | |||
(let ((window-id (emacs-everywhere-call "xdotool" "getactivewindow"))) | |||
(let ((app-name | |||
(car (split-string-and-unquote | |||
(string-trim-left | |||
(emacs-everywhere-call "xprop" "-id" window-id "WM_CLASS") | |||
"[^ ]+ = \"[^\"]+\", ")))) | |||
(window-title | |||
(car (split-string-and-unquote | |||
(string-trim-left | |||
(emacs-everywhere-call "xprop" "-id" window-id "_NET_WM_NAME") | |||
"[^ ]+ = ")))) | |||
(window-geometry | |||
(let ((info (mapcar (lambda (line) | |||
(split-string line ":" nil "[ \t]+")) | |||
(split-string | |||
(emacs-everywhere-call "xwininfo" "-id" window-id) "\n")))) | |||
(mapcar #'string-to-number | |||
(list (cadr (assoc "Absolute upper-left X" info)) | |||
(cadr (assoc "Absolute upper-left Y" info)) | |||
(cadr (assoc "Relative upper-left X" info)) | |||
(cadr (assoc "Relative upper-left Y" info)) | |||
(cadr (assoc "Width" info)) | |||
(cadr (assoc "Height" info))))))) | |||
(make-emacs-everywhere-app | |||
:id (string-to-number window-id) | |||
:class app-name | |||
:title window-title | |||
:geometry (list | |||
(if (= (nth 0 window-geometry) (nth 2 window-geometry)) | |||
(nth 0 window-geometry) | |||
(- (nth 0 window-geometry) (nth 2 window-geometry))) | |||
(if (= (nth 1 window-geometry) (nth 3 window-geometry)) | |||
(nth 1 window-geometry) | |||
(- (nth 1 window-geometry) (nth 3 window-geometry))) | |||
(nth 4 window-geometry) | |||
(nth 5 window-geometry)))))) | |||
(defvar emacs-everywhere--dir (file-name-directory load-file-name)) | |||
(defun emacs-everywhere-app-info-osx () | |||
"Return information on the active window, on osx." | |||
(emacs-everywhere-ensure-oscascript-compiled) | |||
(let ((default-directory emacs-everywhere--dir)) | |||
(let ((app-name (emacs-everywhere-call | |||
"osascript" "app-name")) | |||
(window-title (emacs-everywhere-call | |||
"osascript" "window-title")) | |||
(window-geometry (mapcar #'string-to-number | |||
(split-string | |||
(emacs-everywhere-call | |||
"osascript" "window-geometry") ", ")))) | |||
(make-emacs-everywhere-app | |||
:id app-name | |||
:class app-name | |||
:title window-title | |||
:geometry window-geometry)))) | |||
(defun emacs-everywhere-ensure-oscascript-compiled (&optional force) | |||
"Ensure that compiled oscascript files are present. | |||
Will always compile when FORCE is non-nil." | |||
(unless (and (file-exists-p "app-name") | |||
(file-exists-p "window-geometry") | |||
(file-exists-p "window-title") | |||
(not force)) | |||
(let ((default-directory emacs-everywhere--dir) | |||
(app-name | |||
"tell application \"System Events\" | |||
set frontAppName to name of first application process whose frontmost is true | |||
end tell | |||
return frontAppName") | |||
(window-geometry | |||
"tell application \"System Events\" | |||
set frontWindow to front window of (first application process whose frontmost is true) | |||
set windowPosition to (get position of frontWindow) | |||
set windowSize to (get size of frontWindow) | |||
end tell | |||
return windowPosition & windowSize") | |||
(window-title | |||
"set windowTitle to \"\" | |||
tell application \"System Events\" | |||
set frontAppProcess to first application process whose frontmost is true | |||
end tell | |||
tell frontAppProcess | |||
if count of windows > 0 then | |||
set windowTitle to name of front window | |||
end if | |||
end tell | |||
return windowTitle")) | |||
(dolist (script `(("app-name" . ,app-name) | |||
("window-geometry" . ,window-geometry) | |||
("window-title" . ,window-title))) | |||
(write-region (cdr script) nil (concat (car script) ".applescript")) | |||
(shell-command (format "osacompile -r scpt:128 -t osas -o %s %s" | |||
(car script) (concat (car script) ".applescript"))))))) | |||
;;; Secondary functionality | |||
(defun emacs-everywhere-set-frame-name () | |||
"Set the frame name based on `emacs-everywhere-frame-name-format'." | |||
(set-frame-name | |||
(format emacs-everywhere-frame-name-format | |||
(emacs-everywhere-app-class emacs-everywhere-current-app) | |||
(truncate-string-to-width | |||
(emacs-everywhere-app-title emacs-everywhere-current-app) | |||
45 nil nil "…")))) | |||
(defun emacs-everywhere-remove-trailing-whitespace () | |||
"Move point to the end of the buffer, and remove all trailing whitespace." | |||
(goto-char (max-char)) | |||
(delete-trailing-whitespace) | |||
(delete-char (- (skip-chars-backward "\n")))) | |||
(defun emacs-everywhere-set-frame-position () | |||
"Set the size and position of the emacs-everywhere frame." | |||
(cl-destructuring-bind (x . y) (mouse-absolute-pixel-position) | |||
(set-frame-position (selected-frame) | |||
(- x 100) | |||
(- y 50)))) | |||
(defun emacs-everywhere-insert-selection () | |||
"Insert the last text selection into the buffer." | |||
(if (eq system-type 'darwin) | |||
(progn | |||
(call-process "osascript" nil nil nil | |||
"-e" "tell application \"System Events\" to keystroke \"c\" using command down") | |||
(sleep-for 0.01) ; lets clipboard info propagate | |||
(yank)) | |||
(when-let ((selection (gui-get-selection 'PRIMARY 'UTF8_STRING))) | |||
(gui-backend-set-selection 'PRIMARY "") | |||
(insert selection))) | |||
(when (and (eq major-mode 'org-mode) | |||
(emacs-everywhere-markdown-p) | |||
(executable-find "pandoc")) | |||
(shell-command-on-region (point-min) (point-max) | |||
"pandoc -f markdown-auto_identifiers -t org" nil t) | |||
(deactivate-mark) (goto-char (point-max))) | |||
(cond ((bound-and-true-p evil-local-mode) (evil-insert-state)))) | |||
(defun emacs-everywhere-init-spell-check () | |||
"Run a spell check function on the buffer, using a relevant enabled mode." | |||
(cond ((bound-and-true-p spell-fu-mode) (spell-fu-buffer)) | |||
((bound-and-true-p flyspell-mode) (flyspell-buffer)))) | |||
(defun emacs-everywhere-markdown-p () | |||
"Return t if the original window is recognised as markdown-flavoured." | |||
(let ((title (emacs-everywhere-app-title emacs-everywhere-current-app)) | |||
(class (emacs-everywhere-app-class emacs-everywhere-current-app))) | |||
(or (cl-some (lambda (pattern) | |||
(string-match-p pattern title)) | |||
emacs-everywhere-markdown-windows) | |||
(cl-some (lambda (pattern) | |||
(string-match-p pattern class)) | |||
emacs-everywhere-markdown-apps)))) | |||
(defun emacs-everywhere-major-mode-org-or-markdown () | |||
"Use markdow-mode, when window is recognised as markdown-flavoured. | |||
Otherwise use `org-mode'." | |||
(if (emacs-everywhere-markdown-p) | |||
(markdown-mode) | |||
(org-mode))) | |||
(defcustom emacs-everywhere-org-export-options | |||
"#+property: header-args :exports both | |||
#+options: toc:nil\n" | |||
"A string inserted at the top of the Org buffer prior to export. | |||
This is with the purpose of setting #+property and #+options parameters. | |||
Should end in a newline to avoid interfering with the buffer content." | |||
:type 'string | |||
:group 'emacs-everywhere) | |||
(defvar org-export-show-temporary-export-buffer) | |||
(defun emacs-everywhere-return-converted-org-to-gfm () | |||
"When appropriate, convert org buffer to markdown." | |||
(when (and (eq major-mode 'org-mode) | |||
(emacs-everywhere-markdown-p)) | |||
(goto-char (point-min)) | |||
(insert emacs-everywhere-org-export-options) | |||
(let (org-export-show-temporary-export-buffer) | |||
(require 'ox-md) | |||
(org-export-to-buffer (if (featurep 'ox-gfm) 'gfm 'md) (current-buffer))))) | |||
(provide 'emacs-everywhere) | |||
;;; emacs-everywhere.el ends here |
@@ -0,0 +1,57 @@ | |||
;; -*- no-byte-compile: t; -*- | |||
;;; $DOOMDIR/packages.el | |||
;; To install a package with Doom you must declare them here and run 'doom sync' | |||
;; on the command line, then restart Emacs for the changes to take effect -- or | |||
;; use 'M-x doom/reload'. | |||
;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror: | |||
;(package! some-package) | |||
;; To install a package directly from a remote git repo, you must specify a | |||
;; `:recipe'. You'll find documentation on what `:recipe' accepts here: | |||
;; https://github.com/raxod502/straight.el#the-recipe-format | |||
;(package! another-package | |||
; :recipe (:host github :repo "username/repo")) | |||
;; If the package you are trying to install does not contain a PACKAGENAME.el | |||
;; file, or is located in a subdirectory of the repo, you'll need to specify | |||
;; `:files' in the `:recipe': | |||
;(package! this-package | |||
; :recipe (:host github :repo "username/repo" | |||
; :files ("some-file.el" "src/lisp/*.el"))) | |||
;; If you'd like to disable a package included with Doom, you can do so here | |||
;; with the `:disable' property: | |||
;(package! builtin-package :disable t) | |||
;; You can override the recipe of a built in package without having to specify | |||
;; all the properties for `:recipe'. These will inherit the rest of its recipe | |||
;; from Doom or MELPA/ELPA/Emacsmirror: | |||
;(package! builtin-package :recipe (:nonrecursive t)) | |||
;(package! builtin-package-2 :recipe (:repo "myfork/package")) | |||
;; Specify a `:branch' to install a package from a particular branch or tag. | |||
;; This is required for some packages whose default branch isn't 'master' (which | |||
;; our package manager can't deal with; see raxod502/straight.el#279) | |||
;(package! builtin-package :recipe (:branch "develop")) | |||
;; Use `:pin' to specify a particular commit to install. | |||
;(package! builtin-package :pin "1a2b3c4d5e") | |||
;; Doom's packages are pinned to a specific commit and updated from release to | |||
;; release. The `unpin!' macro allows you to unpin single packages... | |||
;(unpin! pinned-package) | |||
;; ...or multiple packages | |||
;(unpin! pinned-package another-pinned-package) | |||
;; ...Or *all* packages (NOT RECOMMENDED; will likely break things) | |||
;(unpin! t) | |||
(package! emacs-everywhere :ignore t) | |||
(package! doom-snippets :ignore t) | |||
(package! copilot | |||
:recipe (:host github :repo "zerolfx/copilot.el" | |||
:files ("dist" "copilot.el"))) |
@@ -0,0 +1,8 @@ | |||
# -*- mode: snippet -*- | |||
# name: src_elisp | |||
# key: <el | |||
# expand-env: ((yas-after-exit-snippet-hook #'org-edit-special)) | |||
# -- | |||
#+BEGIN_SRC elisp | |||
$0 | |||
#+END_SRC |
@@ -0,0 +1,154 @@ | |||
;;; doom-catppuccin-theme.el --- inspired by Catppuccin -*- lexical-binding: t; no-byte-compile: t; -*- | |||
(require 'doom-themes) | |||
;; | |||
;;; Variables | |||
(defgroup doom-catppuccin-theme nil | |||
"Options for the `doom-catppuccin' theme." | |||
:group 'doom-themes) | |||
(defcustom doom-catppuccin-brighter-modeline nil | |||
"If non-nil, more vivid colors will be used to style the mode-line." | |||
:group 'doom-catppuccin-theme | |||
:type 'boolean) | |||
(defcustom doom-catppuccin-brighter-comments nil | |||
"If non-nil, comments will be highlighted in more vivid colors." | |||
:group 'doom-catppuccin-theme | |||
:type 'boolean) | |||
(defcustom doom-catppuccin-padded-modeline doom-themes-padded-modeline | |||
"If non-nil, adds a 4px padding to the mode-line. | |||
Can be an integer to determine the exact padding." | |||
:group 'doom-catppuccin-theme | |||
:type '(choice integer boolean)) | |||
;; | |||
;;; Theme definition | |||
(def-doom-theme doom-catppuccin | |||
"A dark theme inspired by Catppuccin." | |||
;; name default 256 16 | |||
((bg '("#1e1e2e" "black" "black" )) | |||
(fg '("#d9e0ee" "#bfbfbf" "brightwhite" )) | |||
;; These are off-color variants of bg/fg, used primarily for `solaire-mode', | |||
;; but can also be useful as a basis for subtle highlights (e.g. for hl-line | |||
;; or region), especially when paired with the `doom-darken', `doom-lighten', | |||
;; and `doom-blend' helper functions. | |||
(bg-alt '("#1a1826" "black" "black" )) | |||
(fg-alt '("#d9e0ee" "#2d2d2d" "white" )) | |||
;; These should represent a spectrum from bg to fg, where base0 is a starker | |||
;; bg and base8 is a starker fg. For example, if bg is light grey and fg is | |||
;; dark grey, base0 should be white and base8 should be black. | |||
(base0 '("#161320" "black" "black" )) | |||
(base1 '("#1a1826" "#1e1e1e" "brightblack" )) | |||
(base2 '("#1e1e1e" "#2e2e2e" "brightblack" )) | |||
(base3 '("#302d41" "#262626" "brightblack" )) | |||
(base4 '("#575268" "#3f3f3f" "brightblack" )) | |||
(base5 '("#6e6c7e" "#525252" "brightblack" )) | |||
(base6 '("#988ba2" "#6b6b6b" "brightblack" )) | |||
(base7 '("#c3bac6" "#979797" "brightblack" )) | |||
(base8 '("#d9e0ee" "#dfdfdf" "white" )) | |||
(grey base4) | |||
(red '("#f28fad" "#ff6655" "red" )) | |||
(orange '("#f8bd96" "#dd8844" "brightred" )) | |||
(green '("#abe9b3" "#99bb66" "green" )) | |||
(teal '("#b5e8e0" "#44b9b1" "brightgreen" )) | |||
(yellow '("#fae3b0" "#ECBE7B" "yellow" )) | |||
(blue '("#96cdfb" "#51afef" "brightblue" )) | |||
(dark-blue '("#96cdfb" "#2257A0" "blue" )) | |||
(magenta '("#f5c2e7" "#c678dd" "brightmagenta")) | |||
(violet '("#ddb6f2" "#a9a1e1" "magenta" )) | |||
(cyan '("#89dceb" "#46D9FF" "brightcyan" )) | |||
(dark-cyan '("#89dceb" "#5699AF" "cyan" )) | |||
;; These are the "universal syntax classes" that doom-themes establishes. | |||
;; These *must* be included in every doom themes, or your theme will throw an | |||
;; error, as they are used in the base theme defined in doom-themes-base. | |||
(highlight magenta) | |||
(vertical-bar (doom-darken base1 0.1)) | |||
(selection dark-blue) | |||
(builtin teal) | |||
(comments (if doom-catppuccin-brighter-comments green base5)) | |||
(doc-comments (doom-lighten (if doom-catppuccin-brighter-comments green base5) 0.25)) | |||
(constants orange) | |||
(functions blue) | |||
(keywords magenta) | |||
(methods blue) | |||
(operators blue) | |||
(type yellow) | |||
(strings green) | |||
(variables cyan) | |||
;; (variables (doom-lighten magenta 0.4)) | |||
(numbers orange) | |||
(region `(,(doom-lighten (car bg-alt) 0.15) ,@(doom-lighten (cdr base1) 0.35))) | |||
(error red) | |||
(warning yellow) | |||
(success green) | |||
(vc-modified orange) | |||
(vc-added green) | |||
(vc-deleted red) | |||
;; These are extra color variables used only in this theme; i.e. they aren't | |||
;; mandatory for derived themes. | |||
(modeline-fg fg) | |||
(modeline-fg-alt base5) | |||
(modeline-bg (if doom-catppuccin-brighter-modeline | |||
(doom-darken blue 0.45) | |||
(doom-darken bg-alt 0.1))) | |||
(modeline-bg-alt (if doom-catppuccin-brighter-modeline | |||
(doom-darken blue 0.475) | |||
`(,(doom-darken (car bg-alt) 0.15) ,@(cdr bg)))) | |||
(modeline-bg-inactive `(,(car bg-alt) ,@(cdr base1))) | |||
(modeline-bg-inactive-alt `(,(doom-darken (car bg-alt) 0.1) ,@(cdr bg))) | |||
(-modeline-pad | |||
(when doom-catppuccin-padded-modeline | |||
(if (integerp doom-catppuccin-padded-modeline) doom-catppuccin-padded-modeline 4)))) | |||
;;;; Base theme face overrides | |||
(((line-number &override) :foreground base4) | |||
((line-number-current-line &override) :foreground fg) | |||
((font-lock-comment-face &override) | |||
:background (if doom-catppuccin-brighter-comments (doom-lighten bg 0.05))) | |||
(mode-line | |||
:background modeline-bg :foreground modeline-fg | |||
:box (if -modeline-pad `(:line-width ,-modeline-pad :color ,modeline-bg))) | |||
(mode-line-inactive | |||
:background modeline-bg-inactive :foreground modeline-fg-alt | |||
:box (if -modeline-pad `(:line-width ,-modeline-pad :color ,modeline-bg-inactive))) | |||
(mode-line-emphasis :foreground (if doom-catppuccin-brighter-modeline base8 highlight)) | |||
;;;; css-mode <built-in> / scss-mode | |||
(css-proprietary-property :foreground orange) | |||
(css-property :foreground magenta) | |||
(css-selector :foreground blue) | |||
;;;; doom-modeline | |||
(doom-modeline-bar :background (if doom-catppuccin-brighter-modeline modeline-bg highlight)) | |||
(doom-modeline-buffer-file :inherit 'mode-line-buffer-id :weight 'bold) | |||
(doom-modeline-buffer-path :inherit 'mode-line-emphasis :weight 'bold) | |||
(doom-modeline-buffer-project-root :foreground magenta :weight 'bold) | |||
;;;; ivy | |||
(ivy-current-match :background dark-blue :distant-foreground base0 :weight 'normal) | |||
;;;; LaTeX-mode | |||
(font-latex-math-face :foreground magenta) | |||
;;;; markdown-mode | |||
(markdown-markup-face :foreground base5) | |||
(markdown-header-face :inherit 'bold :foreground red) | |||
((markdown-code-face &override) :background (doom-lighten base3 0.05)) | |||
;;;; rjsx-mode | |||
) | |||
;;;; Base theme variable overrides- | |||
()) | |||
;;; doom-catppuccin-theme.el ends here |