;;; .emacs --- My .emacs config file -*- lexical-binding: t; -*- ;;; Commentary: Optimized configuration by Claude ;;; Code: ;;; ============================================================================ ;;; PERFORMANCE OPTIMIZATIONS ;;; ============================================================================ ;; Minimize garbage collection during startup (setq gc-cons-threshold most-positive-fixnum) ;; Lower threshold back to 8 MiB after startup (add-hook 'emacs-startup-hook (lambda () (setq gc-cons-threshold (* 50 1024 1024)))) ;; Keep LSP and redisplay responsive on slower machines. (setq read-process-output-max (* 4 1024 1024) redisplay-skip-fontification-on-input t) ;; Reduce unnecessary redraw work in inactive windows. (setq-default cursor-in-non-selected-windows nil highlight-nonselected-windows nil) ;; Fast scrolling (setq fast-but-imprecise-scrolling t) (pixel-scroll-precision-mode 1) ;;; ============================================================================ ;;; UI CONFIGURATION ;;; ============================================================================ ;; Remove UI clutter (setq inhibit-startup-message t) (tool-bar-mode -1) (menu-bar-mode -1) (scroll-bar-mode -1) (global-hl-line-mode t) ;; Line numbers (setq-default display-line-numbers 'relative) (global-display-line-numbers-mode) ;; Font configuration (set-frame-font "Consolas 12" nil t) (add-to-list 'default-frame-alist '(font . "Consolas 12")) (set-face-attribute 'default t :font "Consolas 12") ;; Theme ;; Theme is loaded after package initialization so package themes are available. ;;; ============================================================================ ;;; PACKAGE MANAGEMENT ;;; ============================================================================ (setq package-enable-at-startup nil) (setq package-install-upgrade-built-in t) (require 'cl-lib) (require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (package-initialize) ;; Install and require essential packages (defvar vaino-required-packages '(use-package modus-themes avk-emacs-themes ef-themes helm org hl-todo general doom-modeline flycheck pyvenv latex-extra gscholar-bibtex haskell-mode meson-mode glsl-mode org-autolist lsp-mode kind-icon diff-hl helm-xref lsp-latex yasnippet verilog-mode corfu corfu-candidate-overlay helm-gtags lsp-java jtsx vertico orderless marginalia consult)) (unless (cl-every #'package-installed-p vaino-required-packages) (package-refresh-contents)) (dolist (package vaino-required-packages) (unless (package-installed-p package) (package-install package))) (load-theme 'ef-elea-dark t) (require 'use-package) (setq use-package-always-ensure t) ;;; ============================================================================ ;;; GENERAL SETTINGS ;;; ============================================================================ ;; Indentation (setq-default indent-tabs-mode nil tab-width 4 c-basic-offset 4 c-default-style "linux" lisp-indent-offset 4) (setq tab-always-indent 'complete) ;; Word wrap and auto-fill (setq-default word-wrap t fill-column 72) (add-hook 'text-mode-hook #'auto-fill-mode) ;; Backup files (setq backup-directory-alist `(("." . "~/.emacs.d/saves"))) ;; Misc (delete-selection-mode 1) (require 'font-lock) (global-font-lock-mode 1) (setq font-lock-maximum-decoration t) (save-place-mode 1) (recentf-mode 1) (savehist-mode 1) (global-so-long-mode 1) (setq recentf-max-saved-items 200 recentf-auto-cleanup 'never) ;;; ============================================================================ ;;; KEY BINDINGS ;;; ============================================================================ (global-set-key (kbd "C-") 'completion-at-point) (global-set-key (kbd "C-c l") #'org-store-link) (global-set-key (kbd "C-c a") #'org-agenda) (global-set-key (kbd "C-c c") #'org-capture) (define-key emacs-lisp-mode-map (kbd "C-c C-b") 'eval-buffer) ;;; ============================================================================ ;;; MINIBUFFER STACK ;;; ============================================================================ (use-package vertico :custom (enable-recursive-minibuffers t) (read-file-name-completion-ignore-case t) (read-buffer-completion-ignore-case t) (completion-ignore-case t) :init (vertico-mode 1) :bind (:map vertico-map ("RET" . vertico-directory-enter) ("DEL" . vertico-directory-delete-char) ("M-DEL" . vertico-directory-delete-word)) :config (require 'vertico-directory)) (use-package orderless :custom (completion-styles '(orderless basic)) (completion-category-defaults nil) (completion-category-overrides '((file (styles basic partial-completion))))) (use-package marginalia :init (marginalia-mode 1)) (use-package consult :bind (("C-x b" . consult-buffer) ("C-x C-r" . consult-recent-file) ("M-y" . consult-yank-pop) ("M-g g" . consult-goto-line) ("M-g i" . consult-imenu) ("M-s l" . consult-line) ("M-s r" . consult-ripgrep)) :config (setq xref-show-xrefs-function #'consult-xref xref-show-definitions-function #'consult-xref)) ;; Helm gtags (add-hook 'c-mode-hook 'helm-gtags-mode) (add-hook 'c++-mode-hook 'helm-gtags-mode) (add-hook 'asm-mode-hook 'helm-gtags-mode) (with-eval-after-load "helm-gtags" (define-key helm-gtags-mode-map (kbd "M-t") 'helm-gtags-find-tag) (define-key helm-gtags-mode-map (kbd "M-r") 'helm-gtags-find-rtag) (define-key helm-gtags-mode-map (kbd "M-s") 'helm-gtags-find-symbol) (define-key helm-gtags-mode-map (kbd "M-g M-p") 'helm-gtags-parse-file) (define-key helm-gtags-mode-map (kbd "C-c <") 'helm-gtags-previous-history) (define-key helm-gtags-mode-map (kbd "C-c >") 'helm-gtags-next-history) (define-key helm-gtags-mode-map (kbd "M-,") 'helm-gtags-pop-stack)) ;;; ============================================================================ ;;; COMPLETION (CORFU) ;;; ============================================================================ (use-package corfu :custom ;; Popup completions automatically while typing (after 2 chars, 0.15s ;; idle). C- below still forces completion at any time. (corfu-auto t) (corfu-auto-delay 0.15) (corfu-auto-prefix 2) (corfu-quit-at-boundary nil) (corfu-quit-no-match nil) :init (global-corfu-mode)) (use-package corfu-candidate-overlay :after corfu :config (corfu-candidate-overlay-mode +1) (global-set-key (kbd "C-") 'corfu-candidate-overlay-complete-at-point)) (use-package kind-icon :after corfu :custom (kind-icon-default-face 'corfu-default) (kind-icon-use-icons t) :config (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter)) ;;; ============================================================================ ;;; LSP MODE ;;; ============================================================================ (use-package lsp-mode :hook ((c-mode c++-mode) . lsp) :commands lsp) (use-package lsp-ui :commands lsp-ui-mode) ;; LSP Python settings (setq lsp-pylsp-plugins-black-enabled t) ;; LSP Latex (use-package lsp-latex :hook (((tex-mode plain-tex-mode latex-mode TeX-mode LaTeX-mode) . lsp-deferred))) ;; LSP for Verilog (only when the verible server is actually installed) (if (executable-find "verible-verilog-ls") (progn (with-eval-after-load 'lsp-mode (add-to-list 'lsp-language-id-configuration '(verilog-mode . "verilog")) (lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection "verible-verilog-ls") :major-modes '(verilog-mode) :server-id 'verible-ls))) (add-hook 'verilog-mode-hook 'lsp)) (message "verible-verilog-ls not found; Verilog LSP disabled")) (use-package vhdl-mode :defer t :config (setq lsp-vhdl-server 'ghdl-ls lsp-vhdl-server-path (executable-find "ghdl-ls") lsp-vhdl--params nil) (require 'lsp-vhdl) :hook (vhdl-mode . (lambda() (lsp t) (flycheck-mode t)))) ;;; ============================================================================ ;;; EGLOT (ALTERNATIVE LSP CLIENT) ;;; ============================================================================ (use-package eglot ;; NOTE: python-mode is deliberately NOT hooked here. Mode hooks run ;; before .dir-locals.el applies, so this would always connect to the ;; system pylsp. Python eglot is started per-project from ;; .dir-locals.el (micromamba envs) -- see emacs_setup README. :hook (((clojure-mode clojurec-mode clojurescript-mode java-mode scala-mode) . eglot-ensure) ((cider-mode eglot-managed-mode) . eglot-disable-in-cider)) :preface (defun eglot-disable-in-cider () (when (eglot-managed-p) (if (bound-and-true-p cider-mode) (progn (remove-hook 'completion-at-point-functions 'eglot-completion-at-point t) (remove-hook 'xref-backend-functions 'eglot-xref-backend t)) (add-hook 'completion-at-point-functions 'eglot-completion-at-point nil t) (add-hook 'xref-backend-functions 'eglot-xref-backend nil t)))) :custom (eglot-autoshutdown t) (eglot-events-buffer-size 0) (eglot-extend-to-xref nil) (eglot-ignored-server-capabilities '(:colorProvider :foldingRangeProvider)) (eglot-stay-out-of '(yasnippet))) ;; Eglot for C/C++ (alternative to lsp-mode setup above) ;; Note: You're using both lsp-mode and eglot for C/C++, choose one (with-eval-after-load 'eglot (add-to-list 'eglot-server-programs '((c++-mode c-mode) "clangd"))) ;;; ============================================================================ ;;; PROGRAMMING MODES ;;; ============================================================================ ;; C/C++ (use-package cc-mode :init (add-hook 'c-mode-hook (lambda () (add-to-list 'auto-mode-alist '("\\.h\\'" . c-mode)) (setq-local c-default-style "linux"))) (add-hook 'c++-mode-hook (lambda () (add-to-list 'auto-mode-alist '("\\.hpp\\'" . c++-mode)) (setq-local c-default-style "linux"))) :mode (("\\.c\\'" . c-mode) ("\\.cpp\\'" . c++-mode) ("\\.cu\\'" . c++-mode))) ;; Yasnippet (add-hook 'prog-mode-hook #'yas-minor-mode) (yas-global-mode 1) (yas-reload-all) ;; Flycheck (add-hook 'after-init-hook #'global-flycheck-mode) ;; Haskell - disable eldoc (add-hook 'haskell-mode-hook #'(lambda () (eldoc-mode -1))) ;; Octave (add-to-list 'auto-mode-alist '("\\.m\\'" . octave-mode)) ;;; ============================================================================ ;;; HL-TODO ;;; ============================================================================ (setq hl-todo-keyword-faces '(("TODO" . "#FF0000") ("FIXME" . "#FF0000") ("DEBUG" . "#A020F0") ("GOTCHA" . "#FF4500") ("STUB" . "#1E90FF") ("STARTED" . "#E6B400"))) (global-hl-todo-mode) (use-package diff-hl :hook ((prog-mode text-mode conf-mode) . diff-hl-mode)) ;;; ============================================================================ ;;; DOOM MODELINE ;;; ============================================================================ (use-package doom-modeline :init (setq doom-modeline-height 28 doom-modeline-bar-width 4 doom-modeline-window-width-limit 110 doom-modeline-buffer-file-name-style 'relative-to-project doom-modeline-icon t doom-modeline-major-mode-icon t doom-modeline-major-mode-color-icon t doom-modeline-buffer-state-icon t doom-modeline-buffer-modification-icon t doom-modeline-minor-modes nil doom-modeline-check 'auto doom-modeline-lsp t doom-modeline-project-name t doom-modeline-modal t doom-modeline-battery nil doom-modeline-time t doom-modeline-time-icon t doom-modeline-buffer-encoding nil doom-modeline-indent-info nil doom-modeline-position-column-line-format '("%l:%c") display-time-24hr-format t display-time-default-load-average nil) :config (display-time-mode 1) (doom-modeline-mode 1)) ;;; ============================================================================ ;;; ORG MODE ;;; ============================================================================ (setq org-element-use-cache nil) ;; Hide #+TITLE: (setq org-hidden-keywords '(title)) ;; Org appearance (setq org-startup-indented t org-pretty-entities t org-hide-emphasis-markers t org-startup-with-inline-images t org-image-actual-width '(300)) ;; Org autolist (add-hook 'org-mode-hook (lambda () (org-autolist-mode))) ;; Org agenda (setq org-todo-keywords '((sequence "TODO" "NEXT" "REVISE" "HOLD" "DONE"))) ;; Org babel (org-babel-do-load-languages 'org-babel-load-languages '((ditaa . t))) ;; Custom org-dblock for weekly time tracking (require 'cl-lib) (require 'org-clock) (defun org-dblock-write:weekly (params) (cl-flet ((fmttm (tm) (format-time-string (org-time-stamp-format t t) tm))) (let ((file (or (plist-get params :file) (buffer-file-name))) (start (seconds-to-time (org-matcher-time (plist-get params :tstart)))) (end (seconds-to-time (org-matcher-time (plist-get params :tend))))) (while (time-less-p start end) (let ((next-week (time-add start (date-to-time "1970-01-08T00:00Z"))) (week-begin (line-beginning-position)) (daysworksum 0)) (insert "\nWeekly Table from " (fmttm start) "\n") (insert "| Day of Week | Time |\n|-\n") (while (time-less-p start next-week) (let* ((next-day (time-add start (date-to-time "1970-01-02T00:00Z"))) (minutes (with-current-buffer (find-file-noselect file) (cadr (org-clock-get-table-data file (list :maxlevel 0 :tstart (fmttm start) :tend (fmttm next-day))))))) (insert "|" (format-time-string "%a" start) "|" (format "%d" minutes) "|\n") (org-table-align) (setq daysworksum (+ minutes daysworksum)) (setq start next-day))) (insert "| Avg. | " (format "%.2f" (float (/ daysworksum 7))) "|\n") (org-table-align) (when (equal daysworksum 0) (delete-region week-begin (line-beginning-position)))))))) ;;; ============================================================================ ;;; LATEX/AUCTEX ;;; ============================================================================ (require 'latex) (setq TeX-auto-save t TeX-parse-self t latex-run-command "latexmk" TeX-process-asynchronous t TeX-check-TeX nil TeX-engine 'default TeX-engine-alist '((default "Tectonic" "latexmk -pdf -shell-escape -interaction=nonstopmode -f %t" "latexmk -pdf -shell-escape -interaction=nonstopmode -f %t" nil))) (setq-default TeX-master nil) (defun vaino-tectonic-command (file) (concat "tectonic -Z search-path=$(dirname $(kpsewhich biblatex.sty)) " file)) (add-hook 'LaTeX-mode-hook (lambda () (add-to-list 'TeX-command-list '("XeLaTeX" "%`xelatex%(mode)%' -shell-escape %t" TeX-run-TeX nil t)) (add-to-list 'TeX-command-list `("Tectonic" ,(vaino-tectonic-command "%t") TeX-run-TeX nil (latex-mode doctex-mode) :help "Run Tectonic")) (setq TeX-command-default "LaTeX" TeX-save-query nil TeX-show-compilation t) (TeX-fold-mode 1))) ;; LaTeX source correlation (add-hook 'LaTeX-mode-hook #'TeX-source-correlate-mode) (with-eval-after-load 'latex (define-key TeX-source-correlate-map [C-down-mouse-1] #'TeX-view-mouse)) ;;; ============================================================================ ;;; CUSTOM VARIABLES (GENERATED BY CUSTOM) ;;; ============================================================================ (custom-set-variables ;; custom-set-variables was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. '(LaTeX-command-style '(("" "%(latex)"))) '(TeX-command-Biber "Biber") '(TeX-command-list '(("XeLaTeX" "%`xelatex%(mode)%' -shell-escape %t" TeX-run-TeX nil t) ("TeX" "%(PDF)%(tex) %(file-line-error) %`%(extraopts) %S%(PDFout)%(mode)%' %(output-dir) %t" TeX-run-TeX nil (plain-tex-mode texinfo-mode ams-tex-mode) :help "Run plain TeX") ("LaTeX" "latexmk -pdf -shell-escape -interaction=nonstopmode -f %t" TeX-run-TeX nil (latex-mode doctex-mode) :help "Run LaTeX") ("Makeinfo" "makeinfo %(extraopts) %(o-dir) %t" TeX-run-compile nil (texinfo-mode) :help "Run Makeinfo with Info output") ("Makeinfo HTML" "makeinfo %(extraopts) %(o-dir) --html %t" TeX-run-compile nil (texinfo-mode) :help "Run Makeinfo with HTML output") ("AmSTeX" "amstex %(PDFout) %`%(extraopts) %S%(mode)%' %(output-dir) %t" TeX-run-TeX nil (ams-tex-mode) :help "Run AMSTeX") ("ConTeXt" "%(cntxcom) --once --texutil %(extraopts) %(execopts)%t" TeX-run-TeX nil (context-mode) :help "Run ConTeXt once") ("ConTeXt Full" "%(cntxcom) %(extraopts) %(execopts)%t" TeX-run-TeX nil (context-mode) :help "Run ConTeXt until completion") ("BibTeX" "bibtex %(O?aux)" TeX-run-BibTeX nil (plain-tex-mode latex-mode doctex-mode context-mode texinfo-mode ams-tex-mode) :help "Run BibTeX") ("Biber" "/usr/bin/vendor_perl/biber %(output-dir) %s.bcf" TeX-run-Biber nil (plain-tex-mode latex-mode doctex-mode texinfo-mode ams-tex-mode) :help "Run Biber") ("Texindex" "texindex %s.??" TeX-run-command nil (texinfo-mode) :help "Run Texindex") ("Texi2dvi" "%(PDF)texi2dvi %t" TeX-run-command nil (texinfo-mode) :help "Run Texi2dvi or Texi2pdf") ("View" "%V" TeX-run-discard-or-function t t :help "Run Viewer") ("Print" "%p" TeX-run-command t t :help "Print the file") ("Queue" "%q" TeX-run-background nil t :help "View the printer queue" :visible TeX-queue-command) ("File" "%(o?)dvips %d -o %f " TeX-run-dvips t (plain-tex-mode latex-mode doctex-mode texinfo-mode ams-tex-mode) :help "Generate PostScript file") ("Dvips" "%(o?)dvips %d -o %f " TeX-run-dvips nil (plain-tex-mode latex-mode doctex-mode texinfo-mode ams-tex-mode) :help "Convert DVI file to PostScript") ("Dvipdfmx" "dvipdfmx -o %(O?pdf) %d" TeX-run-dvipdfmx nil (plain-tex-mode latex-mode doctex-mode texinfo-mode ams-tex-mode) :help "Convert DVI file to PDF with dvipdfmx") ("Ps2pdf" "ps2pdf %f %(O?pdf)" TeX-run-ps2pdf nil (plain-tex-mode latex-mode doctex-mode texinfo-mode ams-tex-mode) :help "Convert PostScript file to PDF") ("Glossaries" "makeglossaries %(d-dir) %s" TeX-run-command nil (plain-tex-mode latex-mode doctex-mode texinfo-mode ams-tex-mode) :help "Run makeglossaries to create glossary file") ("Index" "makeindex %(O?idx)" TeX-run-index nil (plain-tex-mode latex-mode doctex-mode texinfo-mode ams-tex-mode) :help "Run makeindex to create index file") ("upMendex" "upmendex %(O?idx)" TeX-run-index t (plain-tex-mode latex-mode doctex-mode texinfo-mode ams-tex-mode) :help "Run upmendex to create index file") ("Xindy" "texindy %s" TeX-run-command nil (plain-tex-mode latex-mode doctex-mode texinfo-mode ams-tex-mode) :help "Run xindy to create index file") ("Check" "lacheck %s" TeX-run-compile nil (latex-mode) :help "Check LaTeX file for correctness") ("ChkTeX" "chktex -v6 %s" TeX-run-compile nil (latex-mode) :help "Check LaTeX file for common mistakes") ("Spell" "(TeX-ispell-document \"\")" TeX-run-function nil t :help "Spell-check the document") ("Clean" "TeX-clean" TeX-run-function nil t :help "Delete generated intermediate files") ("Clean All" "(TeX-clean t)" TeX-run-function nil t :help "Delete generated intermediate and output files") ("Other" "" TeX-run-command t t :help "Run an arbitrary command"))) '(TeX-view-program-list '(("Sioyek" ("sioyek %o --reuse-window" (mode-io-correlate " --forward-search-file %b --forward-search-line %n --inverse-search \"emacsclient --no-wait +%2:%3 %1\"")) "sioyek"))) '(TeX-view-program-selection '(((output-dvi has-no-display-manager) "dvi2tty") ((output-dvi style-pstricks) "dvips and gv") (output-dvi "xdvi") (output-pdf "Sioyek") (output-html "xdg-open"))) '(bibtex-dialect 'biblatex) '(custom-safe-themes '("e410458d3e769c33e0865971deb6e8422457fad02bf51f7862fa180ccc42c032" "6b912e025527ffae0feb76217f1a3e494b0699e5219ab59ea4b3a36c319cea17" "36b57dcbe8262c52d3123ed30fa34e5ef6b355881674142162a8ca8e26124da9" "11873c4fbf465b956889adfa9182495db3bf214d9a70c0f858f07f6cc91cbd47" "eb7cd622a0916358a6ef6305e661c6abfad4decb4a7c12e73d6df871b8a195f8" "c414f69a02b719fb9867b41915cb49c853489930be280ce81385ff7b327b4bf6" "02fff7eedb18d38b8fd09a419c579570673840672da45b77fde401d8708dc6b5" default)) '(dired-listing-switches "-alFh") '(fast-but-imprecise-scrolling t) '(flycheck-c/c++-gcc-executable "/usr/bin/avr-gcc") '(flycheck-clang-language-standard nil) '(flycheck-python-flake8-executable "python3") '(flycheck-python-pycompile-executable "python3") '(flycheck-python-pylint-executable "python3") '(ignored-local-variable-values '((org-fontify-quote-and-verse-blocks . 1))) '(kind-icon-use-icons t) '(lsp-clients-svlangserver-formatCommand "/tools/verible-verilog-format") '(lsp-clients-svlangserver-launchConfiguration "/tools/verilator -sv --lint-only -Wall") '(magit-todos-scanner nil) '(org-agenda-files '("/home/vaino/git/orgs/vke.org" "/home/vaino/git/aalto/README.org" "/home/vaino/git/thesis/README.org" "/home/vaino/git/elec_e2530_project/README.org" "/home/vaino/git/orgs/main.org")) '(package-selected-packages '(all-the-icons avk-emacs-themes corfu-candidate-overlay dashboard diff-hl dockerfile-mode doom-modeline ef-themes elpher feature-mode flycheck-rust general glsl-mode go-mode gscholar-bibtex haskell-mode helm-gtags helm-xref jinx jtsx julia-mode kind-icon latex-extra lsp-java lsp-julia lsp-latex lsp-ui magit-todos marginalia meson-mode micromamba mozc olivetti orderless org-autolist outline-magic outshine protobuf-mode px pyvenv rust-mode scala-mode texfrag theme-changer verilog-ext vertico)) '(safe-local-variable-values '((eval setq flycheck-clang-include-path (list (expand-file-name "/usr/avr/include/"))) (python-shell-interpreter . "./pysph_env/bin/python") (flycheck-python-flake8-executable . "/home/vaino/git/sph/pysph_env/bin/python") (flycheck-python-pylint-executable . "/home/vaino/git/sph/pysph_env/bin/python"))) '(send-mail-function 'sendmail-send-it) '(warning-suppress-types '(((flycheck syntax-checker)) ((flycheck syntax-checker)) ((flycheck syntax-checker)) ((flycheck syntax-checker))))) (custom-set-faces ;; custom-set-faces was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. '(org-column ((t nil)))) (put 'upcase-region 'disabled nil) ;; Packages like go-mode reference lsp-mode/eglot functions they don't ;; require; native-comp warnings about those are harmless noise. Keep them ;; out of *Warnings*. (Must come AFTER custom-set-variables above, which ;; rewrites warning-suppress-types.) (add-to-list 'warning-suppress-types '(native-compiler)) ;;; PSL tree-sitter mode (add-to-list 'load-path "~/.emacs.d/psl-ts-mode") (require 'psl-ts-mode) (provide '.emacs) ;;; .emacs ends here