(require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (require 'use-package) ;; helper functions ;; ===== (defun my/format-elisp-buffer () "Format the whole elisp buffer." (interactive) (save-excursion (indent-region (point-min) (point-max)))) (defun my/setup-elisp-formatting-key () "Set up the formatting key for Emacs Lisp buffers." (local-set-key (kbd "C-c f") 'my/format-elisp-buffer)) (add-hook 'emacs-lisp-mode-hook #'my/setup-elisp-formatting-key) (defun my/swiper-query-replace () "Run `query-replace-regexp' on Swiper results." (interactive) (if (not (window-minibuffer-p)) (user-error "Call this from swiper") (let* ((enable-recursive-minibuffers t) (from (ivy--regex ivy-text)) (to (query-replace-read-to from (concat "Query replace (regexp " from ") with: ") t))) (ivy-exit-with-action (lambda (_) (let ((case-fold-search (ivy--case-fold-p ivy-text))) (query-replace-regexp from to))))))) (defun my/visit-todo () "Visit TODO.org in home" (interactive) (find-file "~/TODO.org")) (defun my/reload-init-file () "Reload the Emacs init file." (interactive) (load-file user-init-file)) (defun my/reload-org-config () "Reload the org configuration." (interactive) (my/org-config) (message "Org configuration reloaded")) (defun my-org-agenda-format-item (item) "Format an agenda or TODO item without the filename, but keep the keyword." (let* ((marker (or (get-text-property 0 'org-marker item) (get-text-property 0 'org-hd-marker item))) (line (when marker (org-with-point-at marker (buffer-substring (line-beginning-position) (line-end-position))))) (todo-keyword (when marker (org-with-point-at marker (org-get-todo-state)))) (truncated-line (when line (replace-regexp-in-string "^\\[#[A-Z]\\] " "" line)))) (if truncated-line (let ((clean-item (replace-regexp-in-string "^\\(\\*+ \\)" "" truncated-line))) (if todo-keyword (concat todo-keyword " " (replace-regexp-in-string (concat "^" todo-keyword " ?") "" clean-item)) clean-item)) item))) (defun my/kill-all-org-agenda-buffers () "Close all org-agenda-related buffers." (interactive) (dolist (buffer (buffer-list)) (with-current-buffer buffer (when (or (derived-mode-p 'org-agenda-mode) (and (buffer-file-name) (member (buffer-file-name) (org-agenda-files)))) (kill-buffer buffer)))) (message "Closed all org-agenda-related buffers.")) (defun my/org-config () (setq org-agenda-inhibit-startup t org-todo-keywords '((sequence "HOLD(h)" "TODO(t)" "|" "DONE(d)" "CNCL(x)")) org-todo-keyword-faces '(("HOLD" . (:foreground "orange" :weight bold)) ("TODO" . (:foreground "red" :weight bold)) ("DONE" . (:foreground "green" :weight bold)) ("CNCL" . (:foreground "gray" :weight bold))) org-agenda-files (append (list "~/TODO.org") (directory-files-recursively "~/notes" "\\.org$")) org-agenda-prefix-format '((agenda . " %i ") (todo . " %i ") (tags . " %i ") (search . " %i ")) org-agenda-hide-tags-regexp "." org-agenda-todo-keyword-format "%s") (advice-add 'org-agenda-format-item-line :filter-return #'my-org-agenda-format-item) (advice-add 'org-agenda-format-item :filter-return #'my-org-agenda-format-item)) (defun my/org-refile-config () (setq org-refile-targets '((nil :maxlevel . 9) ("~/TODO.org" :maxlevel . 9))) (setq org-refile-use-outline-path 'file) (setq org-outline-path-complete-in-steps nil) (setq org-refile-allow-creating-parent-nodes 'confirm)) (defun my/org-capture-config () (setq org-capture-templates '(("t" "TODO" entry (file "~/TODO.org") "* TODO %?\n %i\n %a" :prepend t)))) (defun my/refresh-org-agenda-files () (interactive) (setq org-agenda-files (append (list "~/TODO.org") (directory-files-recursively "~/notes" "\\.org$")))) (use-package emacs :init (tool-bar-mode -1) (require 'server) (unless (server-running-p) (server-start)) (setq gc-cons-threshold 100000000 read-process-output-max (* 1024 1024) custom-file (concat user-emacs-directory "custom.el") create-lockfiles nil tab-always-indent 'complete mac-command-modifier 'super backup-directory-alist `((".*" . ,(concat user-emacs-directory "backup"))) delete-old-versions t kept-new-versions 20 kept-old-versions 2 version-control t delete-old-versions t backup-by-copying t focus-follows-mouse t mouse-autoselect-window t enable-recursive-minibuffers t warning-minimum-level :emergency inhibit-startup-screen t completion-cycle-threshold 3 text-mode-ispell-word-completion nil text-mode-ispell-word-completion nil read-extended-command-predicate #'command-completion-default-include-p read-extended-command-predicate #'command-completion-default-include-p minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt)) (load-theme 'misterioso) (put 'upcase-region 'disabled nil) (put 'erase-buffer 'disabled nil) (put 'narrow-to-region 'disabled nil) (put 'narrow-to-defun 'disabled nil) (put 'narrow-to-page 'disabled nil) (put 'widen 'disabled nil) (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) (setq hippie-expand-try-functions-list '(try-expand-dabbrev try-expand-dabbrev-all-buffers try-expand-dabbrev-from-kill try-complete-file-name-partially try-complete-file-name try-expand-all-abbrevs try-expand-list try-expand-line try-complete-lisp-symbol-partially try-complete-lisp-symbol)) (global-unset-key (kbd "C-x n")) (global-set-key (kbd "") 'speedbar) (global-set-key (kbd "M-/") 'hippie-expand) (with-eval-after-load 'swiper (define-key swiper-map (kbd "M-%") #'my/swiper-query-replace)) (global-set-key (kbd "C-=") 'multi-vterm-dedicated-toggle) (global-set-key (kbd "C-x r") 'replace-regexp) (global-set-key (kbd "C-x R") 'replace-string) (global-set-key (kbd "C-x c O") 'my/reload-org-config) (global-set-key (kbd "C-x c r") #'my/reload-init-file) (global-set-key (kbd "C-x E n p") #'narrow-to-page) (global-set-key (kbd "C-x E n f") #'narrow-to-defun) (global-set-key (kbd "C-x E n r") #'narrow-to-region) (global-set-key (kbd "C-x E w") #'widen) (when (file-exists-p custom-file) (load custom-file))) (use-package async :ensure t) (use-package async-status :ensure t) (use-package dash :ensure t :defer t) (use-package multiple-cursors :ensure t :defer t :init (multiple-cursors-mode 1) :bind (("C-S-c C-S-c" . 'mc/edit-lines) ("C->" . 'mc/mark-next-like-this) ("C-<" . 'mc/mark-previous-like-this) ("C-c C->" . 'mc/mark-all-like-this))) ;; minibuffer ;; === (use-package which-key :ensure t :defer t :init (which-key-mode)) ;; eye candy ;; === (use-package doom-modeline :ensure t :init (doom-modeline-mode 1)) (use-package nerd-icons :ensure t :defer t) (use-package nerd-icons-dired :ensure t :defer t :hook (dired-mode . nerd-icons-dired-mode)) (use-package nerd-icons-completion :ensure t :defer t) (use-package nerd-icons-ibuffer :ensure t :defer t) (use-package unicode-fonts :ensure t :defer t) ;; org-mode ;; === (use-package org :ensure t :bind (("C-x O a" . org-agenda) ("C-x O c" . org-capture) ("C-x O t" . my/visit-todo) ("C-x O k" . my/kill-all-org-agenda-buffers)) :mode ("\\.org\\'" . org-mode) :config (my/org-config) (my/org-refile-config) (my/org-capture-config) (run-with-idle-timer 300 t #'my/refresh-org-agenda-files)) ;; knowledge management ;; === (use-package denote :ensure t :bind (("C-x n f" . #'denote-open-or-create) ("C-x n n" . #'denote) ("C-x n c" . #'denote-region) ("C-x n !" . #'denote-date) ("C-x n z" . #'denote-signature) ("C-x n s" . #'denote-subdirectory) ("C-x n S-n" . #'denote-type) ("C-x n t" . #'denote-template) ("C-x n l l" . #'denote-link) ("C-x n l a" . #'denote-add-links) ("C-x n l f" . #'denote-find-link) ("C-x n b l" . #'denote-backlinks) ("C-x n b f" . #'denote-find-backlink) ("C-x n r r" . #'denote-rename-file) ("C-x n r f" . #'denote-rename-file-using-front-matter)) :config ;; Key bindings specifically for Dired. (let ((map dired-mode-map)) (define-key map (kbd "C-x n d") #'denote-dired-mode) (define-key map (kbd "C-x n i") #'denote-link-dired-marked-notes) (define-key map (kbd "C-x n k") #'denote-dired-rename-marked-files-with-keywords) (define-key map (kbd "C-x n r r") #'denote-dired-rename-files) (define-key map (kbd "C-x n r f") #'denote-dired-rename-marked-files-using-front-matter)) (setq denote-directory (expand-file-name "~/notes/") denote-save-buffers nil denote-known-keywords '("emacs" "golang" "dev") denote-infer-keywords t denote-sort-keywords t denote-file-type nil denote-prompts '(title keywords) denote-excluded-directories-regexp nil denote-excluded-keywords-regexp nil denote-rename-confirmations '(rewrite-front-matter modify-file-name) denote-date-prompt-use-org-read-date t denote-date-format nil denote-backlinks-show-context t) (denote-rename-buffer-mode 1) (with-eval-after-load 'org-capture (setq denote-org-capture-specifiers "%l\n%i\n%?") (add-to-list 'org-capture-templates '("n" "New note (with denote.el)" plain (file denote-last-path) #'denote-org-capture :no-save t :immediate-finish nil :kill-buffer t :jump-to-captured t)))) ;; version control ;; === (use-package magit :ensure t :defer t :bind ("C-c C-g" . magit-status) :commands (magit-status-here magit-get-current-branch) :custom (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)) ;; diagramming ;; === (use-package graphviz-dot-mode :ensure t :defer t :config (with-eval-after-load 'org (org-babel-do-load-languages 'org-babel-load-languages '((dot . t))))) (use-package plantuml-mode :ensure t :config (setq plantuml-default-exec-mode 'jar plantuml-jar-path "/usr/share/plantuml/plantuml.jar" org-plantuml-jar-path (expand-file-name "/usr/share/plantuml/plantuml.jar")) (with-eval-after-load 'org (org-babel-do-load-languages 'org-babel-load-languages '((plantuml . t))))) ;; coding ;; === (use-package go-mode :ensure t :defer t :mode (("\\.go$" . go-mode))) (use-package yaml-mode :ensure t :defer t :mode (("\\.yml$" . yaml-mode))) (use-package json-mode :ensure t :defer t :mode (("\\.json$" . json-mode))) (use-package php-mode :ensure t :defer t :mode (("\\.php$" . php-mode))) (use-package python-mode :ensure t :defer t :mode (("BUILD\\'" . python-mode) ;; please BUILD config ("\\.py$" . python-mode))) (use-package mmm-mode :ensure t :defer t) (use-package multi-web-mode :ensure t :defer t) (use-package protobuf-mode :ensure t :defer t) (use-package rego-mode :ensure t :defer t) (use-package kotlin-mode :ensure t :defer t) (use-package fic-mode :ensure t :defer t) (use-package flycheck :ensure t :defer t) (use-package eglot :ensure t :hook ((python-mode . eglot-ensure) (rust-mode . eglot-ensure) (c-mode . eglot-ensure) (c++-mode . eglot-ensure) (js-mode . eglot-ensure) (typescript-mode . eglot-ensure)) :config (setq eglot-autoshutdown t) (setq eglot-sync-connect 1) (setq eglot-connect-timeout 10) (setq eglot-autoreconnect t) (setq completion-category-defaults nil) (setq completion-category-overrides '((eglot (styles orderless)))) (setq eglot-completion-style 'orderless) (setq eglot-completion-provider :company) (with-eval-after-load 'orderless (setq orderless-matching-styles '(orderless-flex orderless-regexp orderless-initialism))) :bind (:map eglot-mode-map ("s-l a" . eglot-code-actions) ("s-l r" . eglot-rename) ("s-l f" . eglot-format) ("s-l d" . eglot-find-declaration) ("s-l i" . eglot-find-implementation) ("s-l t" . eglot-find-typeDefinition))) ;; navigation ;; === (use-package ace-jump-mode :ensure t :defer t :bind (("C-x j j" . ace-jump-mode) ("C-x j p" . 'ace-jump-mode-pop-mark))) ;; api testing ;; === (use-package plz :ensure t) ;; search & narrow ;; === (use-package ivy :ensure t :config (setq ivy-re-builders-alist '((swiper . ivy--regex-plus) (t . orderless-ivy-re-builder))) (setq ivy-initial-inputs-alist nil) (setq orderless-matching-styles '(orderless-flex orderless-literal orderless-regexp))) (use-package counsel :ensure t :after ivy :config (counsel-mode 1) (setq counsel-grep-base-command "rg -i -M 120 --no-heading --line-number --color never '%s' %s") (setq counsel-rg-base-command "rg -i -M 120 --no-heading --line-number --color never %s .") ;; Replace vanilla commands with Counsel versions :bind (("C-x C-f" . counsel-find-file) ("M-x" . counsel-M-x) ("C-x b" . counsel-switch-buffer) ("C-x C-b" . counsel-ibuffer) ("C-h f" . counsel-describe-function) ("C-h v" . counsel-describe-variable) ("C-h l" . counsel-find-library) ("C-h i" . counsel-info-lookup-symbol) ("C-x r b" . counsel-bookmark) ("C-c g" . counsel-git) ("C-c j" . counsel-git-grep) ("C-c k" . counsel-ag) ("C-c r" . counsel-rg) ("C-x 8 RET" . counsel-unicode-char) ("C-c s" . counsel-grep-or-swiper) :map minibuffer-local-map ("C-r" . counsel-minibuffer-history))) (use-package projectile :ensure t :diminish projectile-mode :init (projectile-mode) :config (setq projectile-completion-system 'ivy projectile-enable-caching t projectile-indexing-method 'hybrid) (when (executable-find "fd") (setq projectile-generic-command (format "%s . -0 --type f --color=never" (executable-find "fd")))) :bind-keymap ("C-x p" . projectile-command-map)) (use-package counsel-projectile :ensure t :after (counsel projectile) :config (counsel-projectile-mode 1) :bind (:map projectile-command-map ("f" . counsel-projectile-find-file) ("g" . counsel-projectile-grep) ("s" . counsel-projectile-switch-project) ("b" . counsel-projectile-switch-to-buffer) ("d" . projectile-dired) ("/" . counsel-projectile-rg) ("4 b" . counsel-projectile-switch-to-buffer-other-window) ("4 d" . projectile-dired-other-window) ("5 b" . counsel-projectile-switch-to-buffer-other-frame) ("5 d" . projectile-dired-other-frame))) (use-package ivy-prescient :ensure t :after counsel :config (ivy-prescient-mode 1) (prescient-persist-mode 1) (setq ivy-prescient-enable-filtering nil) (setq ivy-prescient-enable-sorting t)) (use-package orderless :ensure t :custom (completion-styles '(orderless basic)) (completion-category-overrides '((file (styles basic partial-completion))))) ;; completion ;; === (use-package company :ensure t :hook (after-init . global-company-mode) :config (setq company-idle-delay 0.1 company-minimum-prefix-length 1 company-tooltip-align-annotations t company-tooltip-limit 10 company-tooltip-flip-when-above t company-require-match nil company-dabbrev-downcase nil company-dabbrev-ignore-case t)) (use-package company-box :ensure t :hook (company-mode . company-box-mode)) (use-package swiper :ensure t :after ivy :bind (("C-s" . swiper) ("C-r" . swiper-backward) :map swiper-map ("M-%" . swiper-query-replace)))