;; ============================================================================ ;; SECTION 1: CORE EMACS CONFIGURATION ;; ============================================================================ ;; ----------------------------------------------------------------------------- ;; --- Startup & Initial Setup ;; ----------------------------------------------------------------------------- ;; Disable welcome startup screen (setq-default inhibit-startup-screen t) ;; Make all "yes or no" prompts show "y or n" instead (fset 'yes-or-no-p 'y-or-n-p) ;; Disable annoying bell (setq ring-bell-function 'ignore) ;; ----------------------------------------------------------------------------- ;; --- Editor Defaults ;; ----------------------------------------------------------------------------- ;; Text editing fundamentals (setq-default fill-column 90) (setq-default indent-tabs-mode nil) ; Use spaces instead of tabs (setq sentence-end-double-space nil) ; Single space after sentence (setq truncate-lines t) ; Don't wrap lines ;; Buffer and editing behavior (setq column-number-mode t) ; Show column numbers (setq size-indication-mode t) ; Show file size (setq blink-cursor-mode nil) ; No blinking cursor (setq undo-limit 8000000) ; Increase undo limits (setq undo-outer-limit 120000000) (setq undo-strong-limit 120000000) ;; Change whitespace which makes searching much better in texts with newlines. (setq search-whitespace-regexp "[ \t\r\n]+" replace-lax-whitespace t replace-regexp-lax-whitespace t) ;; Parentheses matching (show-paren-mode t) (setq show-paren-style 'mixed) ;; Tree-sitter support (setq treesit-max-buffer-size 4194304000) ;; ----------------------------------------------------------------------------- ;; --- File & Backup Management ;; ----------------------------------------------------------------------------- ;; Centralize all temporary files (defconst emacs-tmp-dir (format "%s/%s%s/" temporary-file-directory "emacs" (user-uid))) (setq backup-directory-alist `((".*" . ,emacs-tmp-dir))) (setq auto-save-file-name-transforms `((".*" ,emacs-tmp-dir t))) (setq auto-save-list-file-prefix emacs-tmp-dir) (setq image-dired-dir (format "%s/image-dired" emacs-tmp-dir)) ;; Backup and autosave settings (setq make-backup-files nil) ; Disable backup files (setq auto-save-default nil ; Disable auto-save auto-save-interval 3000 auto-save-timeout 60) ;; Lock file management (setq lock-file-name-transforms '(("\\`/.*/\\([^/]+\\)\\'" "/tmp/\\1" t))) ;; ----------------------------------------------------------------------------- ;; --- Remote File Access (Tramp) ;; ----------------------------------------------------------------------------- (setq remote-file-name-inhibit-auto-save-visited t) (setq remote-file-name-inhibit-cache nil) (setq remote-file-name-inhibit-locks t) (setq tramp-auto-save-directory emacs-tmp-dir) (setq tramp-copy-size-limit (* 1024 1024)) (setq tramp-persistency-file-name (format "%s/tramp" emacs-tmp-dir)) (setq tramp-use-scp-direct-remote-copying t) (setq tramp-use-ssh-controlmaster-options nil) (setq tramp-verbose 2) (connection-local-set-profile-variables 'remote-direct-async-process '((tramp-direct-async-process . t))) (connection-local-set-profiles '(:application tramp :protocol "scp") 'remote-direct-async-process) (setq magit-tramp-pipe-stty-settings 'pty) (with-eval-after-load 'tramp (with-eval-after-load 'compile (remove-hook 'compilation-mode-hook #'tramp-compile-disable-ssh-controlmaster-options))) ;; Disable version control for remote files (setq vc-ignore-dir-regexp (format "\\(%s\\)\\|\\(%s\\)" vc-ignore-dir-regexp tramp-file-name-regexp)) ;; ============================================================================ ;; SECTION 2: USER INTERFACE ;; ============================================================================ ;; ----------------------------------------------------------------------------- ;; --- Frame and Window Appearance ;; ----------------------------------------------------------------------------- ;; Disable GUI elements (tool-bar-mode -1) (scroll-bar-mode -1) ;(menu-bar-mode -1) ;; Frame title format: "filename [mode]" (setq frame-title-format '("%f [mode: %m]")) ;; Load theme (load-theme 'grandshell t) ;; ----------------------------------------------------------------------------- ;; --- Scrolling Configuration ;; ----------------------------------------------------------------------------- (setq redisplay-dont-pause t) ; Scroll line by line (setq scroll-margin 2) ; Lines at top/bottom (setq scroll-preserve-screen-position nil) (setq scroll-step 4) ; Keyboard scroll lines (setq smooth-scroll-margin 3) (setq smooth-scroll-strict-margins 't) ;; Mouse wheel settings (setq mouse-wheel-scroll-amount '(4 ((shift) . 4))) ; four line at a time (setq mouse-wheel-progressive-speed 't) ; accelerate scrolling (setq mouse-wheel-follow-mouse 't) ; scroll window under mouse ;; ----------------------------------------------------------------------------- ;; --- Color Theme and Faces ;; ----------------------------------------------------------------------------- (defun set-faces (&rest face-specs) "Set faces using custom-set-faces format but without customize." (dolist (spec face-specs) (face-spec-set (car spec) (cadr spec)))) (set-faces ;; Core faces '(default ((t (:foreground "white" :background "black")))) '(cursor ((t (:background "palegoldenrod")))) '(region ((t (:background "blue3")))) '(fringe ((t (:background "gray10")))) '(border ((t (:background "gray20")))) '(minibuffer-prompt ((t (:foreground "cyan")))) '(secondary-selection ((t (:background "SkyBlue4")))) ;; Font styles '(bold ((t (:weight bold)))) '(italic ((t (:slant italic)))) '(bold-italic ((t (:slant italic :weight bold)))) '(underline ((t (:underline "dark gray")))) '(shadow ((t (:foreground "gray60")))) '(link ((t (:foreground "turquoise" :underline t)))) ;; Status indicators '(success ((t (:foreground "green")))) '(warning ((t (:foreground "orange")))) '(error ((t (:foreground "red")))) ;; Mode line '(mode-line ((t (:foreground "white" :background "gray10" :height 135)))) '(mode-line-buffer-id ((t (:foreground "white" :background "gray10")))) '(mode-line-inactive ((t (:foreground "white" :background "gray10")))) '(modeline ((t (:foreground "white" :background "gray10")))) ;; Search and highlighting '(isearch ((t (:foreground "brown4" :background "palevioletred2")))) '(isearch-fail ((t (:background "black" :inherit font-lock-warning-face :inverse-video t)))) '(lazy-highlight ((t (:foreground "cyan" :background "black" :inverse-video t)))) '(match ((t (:foreground "dodgerblue" :background "black" :inverse-video t)))) '(highlight ((t (:inverse-video nil :background "#222299")))) ;; Syntax highlighting '(font-lock-builtin-face ((t (:foreground "LightSteelBlue")))) '(font-lock-comment-face ((t (:foreground "chocolate1")))) '(font-lock-comment-delimiter-face ((t (:inherit font-lock-comment-face :foreground "chocolate1")))) '(font-lock-constant-face ((t (:foreground "Aquamarine")))) '(font-lock-doc-face ((t (:inherit font-lock-string-face)))) '(font-lock-function-name-face ((t (:foreground "turquoise")))) '(font-lock-keyword-face ((t (:foreground "SteelBlue1")))) '(font-lock-preprocessor-face ((t (:foreground "Orchid")))) '(font-lock-string-face ((t (:foreground "salmon")))) '(font-lock-type-face ((t (:foreground "SeaGreen1")))) '(font-lock-variable-name-face ((t (:foreground "LightGoldenrod")))) '(font-lock-warning-face ((t (:foreground "Red" :weight bold)))) ;; Parentheses '(show-paren-match ((t (:foreground "#FFE200" :background nil :slant italic :weight bold)))) '(show-paren-mismatch ((t (:background "black" :inherit font-lock-warning-face :inverse-video t)))) ;; Whitespace '(trailing-whitespace ((t (:background "red" :underline nil)))) '(column-marker-1 ((t (:background "dark red" :weight bold)))) ;; Widgets and UI elements '(header-line ((t (:inherit mode-line :foreground "magenta" :background nil)))) '(widget-button ((t (:underline t)))) '(widget-field ((t (:background "gray20" :box (:line-width 1 :color "gray60"))))) '(which-func ((t (:foreground "dodgerblue" :background nil :weight bold)))) ;; Custom faces '(custom-variable-tag ((t (:foreground "dodgerblue")))) '(custom-group-tag ((t (:foreground "dodgerblue")))) '(custom-state-tag ((t (:foreground "green")))) ;; Mode-specific faces will be defined with their modes below... ) ;; ----------------------------------------------------------------------------- ;; --- Presentation Mode Functions ;; ----------------------------------------------------------------------------- (defun my-presentation-font () "Set the default font to be BIG (for presentations)." (interactive) (set-face-font 'default "-*-terminus-medium-r-*-*-28-*-*-*-*-*-*-*")) (defun my-presentation-light-font () "Set the default font to be BIG (for presentations) and switch to light theme." (interactive) (set-face-font 'default "-*-terminus-medium-r-*-*-28-*-*-*-*-*-*-*") (disable-theme 'mytheme) (disable-theme 'grandshell) (load-theme 'leuven t)) ;; Resize the whole frame, and not only a window ;; Adapted from https://stackoverflow.com/a/24714383/5103881 (defun acg/zoom-frame (&optional amt frame) "Increaze FRAME font size by amount AMT. Defaults to selected frame if FRAME is nil, and to 1 if AMT is nil." (interactive "p") (let* ((frame (or frame (selected-frame))) (font (face-attribute 'default :font frame)) (size (font-get font :size)) (amt (or amt 1)) (new-size (+ size amt))) (set-frame-font (font-spec :size new-size) t `(,frame)) (message "Frame's font new size: %d" new-size))) (defun acg/zoom-frame-out (&optional amt frame) "Call `acg/zoom-frame' with negative argument." (interactive "p") (acg/zoom-frame (- (or amt 1)) frame)) ;; ============================================================================ ;; SECTION 3: EXTERNAL TOOLS & INTEGRATIONS ;; ============================================================================ ;; ----------------------------------------------------------------------------- ;; --- Spell Checking (Hunspell) ;; ----------------------------------------------------------------------------- (setq ispell-program-name "hunspell") (setq flyspell-issue-welcome-flag nil) (setq ispell-local-dictionary "en_US") (setq ispell-local-dictionary-alist '((nil ; default "[A-Za-z]" "[^A-Za-z]" "[']" t ("-d" "en_US") nil utf-8) ("en_US" ; Yankee English "[A-Za-z]" "[^A-Za-z]" "[']" t ("-d" "en_US") nil utf-8) ("en_GB" ; British English "[A-Za-z]" "[^A-Za-z]" "[']" t ("-d" "en_GB") nil utf-8) ("de_DE" "[a-zäöüßA-ZÄÖÜ]" "[^a-zäöüßA-ZÄÖÜ]" "['-]" t ("-d" "de_DE") nil utf-8) )) ;; ----------------------------------------------------------------------------- ;; --- Compilation and Build Tools ;; ----------------------------------------------------------------------------- (require 'compile) (setq compilation-disable-input nil compilation-last-buffer nil compilation-scroll-output t compilation-always-kill t mode-compile-always-save-buffer-p t) ;; Grep configuration (setq grep-command "grep -nH " grep-find-ignored-directories '(".svn" ".git" ".hg" ".bzr" "extlib" "b" "build")) ;; ----------------------------------------------------------------------------- ;; --- Diff and Merge Tools ;; ----------------------------------------------------------------------------- (setq ediff-autostore-merges t) (setq ediff-window-setup-function 'ediff-setup-windows-plain) ;; Additional diff faces (set-faces '(diff-added ((t (:foreground "green")))) '(diff-changed ((t (:foreground "violet")))) '(diff-removed ((t (:foreground "orange")))) '(diff-header ((t (:foreground "cyan" :background nil)))) '(diff-file-header ((t (:foreground "dodgerblue" :background nil)))) '(diff-hunk-header ((t (:foreground "magenta")))) '(diff-refine-removed ((t (:inherit magit-diff-removed-highlight :foreground "red1")))) '(diff-refine-added ((t (:inherit magit-diff-added-highlight :foreground "deepskyblue")))) '(diff-hl-change ((t (:foreground "dodgerblue" :background "midnightblue")))) '(diff-hl-delete ((t (:foreground "pink" :background "maroon")))) '(diff-hl-insert ((t (:foreground "green" :background "darkgreen")))) '(diff-refine-added ((t (:foreground "medium spring green" :background "#003300" :inherit magit-diff-added-highlight)))) '(diff-refine-removed ((t (:foreground "#ffbbbb" :background "#330000" :inherit magit-diff-removed-highlight)))) ) ;; ============================================================================ ;; SECTION 4: PACKAGE MANAGEMENT & CORE EXTENSIONS ;; ============================================================================ ;; ----------------------------------------------------------------------------- ;; --- Navigation & Completion ;; ----------------------------------------------------------------------------- ;; Ido - Interactive completion (use-package ido :init (setq ido-everywhere t ido-enable-flex-matching t ido-virtual-buffers t ido-use-faces t ido-show-dot-for-dired t ido-default-file-method 'selected-window ido-default-buffer-method 'selected-window ido-auto-merge-delay-time 0.5 ido-auto-merge-work-directories-length -1) :config (ido-mode) ;; Ido faces (set-faces '(ido-first-match ((t (:foreground "gold" :weight bold)))) '(ido-only-match ((t (:foreground "green")))) '(ido-subdir ((t (:foreground "yellow"))))) ) ;; Smex - M-x enhancement (use-package smex :bind (("M-x" . smex)) :init (setq smex-save-file "~/.emacs.d/smex-items") :config (smex-initialize)) ;; Company - completion framework (use-package company :config (global-company-mode)) ;; ----------------------------------------------------------------------------- ;; --- Text Editing Enhancements ;; ----------------------------------------------------------------------------- ;; Multiple cursors (use-package iedit :bind (("C-\\" . iedit-mode))) ;; Expand region semantically (use-package hippie-exp :bind (("M-/" . hippie-expand)) :config (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))) ;; Yet another snippet extension for Emacs. (use-package yasnippet :init (setq yas-snippet-dirs '("~/.emacs.d/snippets/")) :config (yas-reload-all) (yas-global-mode 1)) ;; Clean up whitespace (use-package ethan-wspace :ensure t :diminish ethan-wspace-mode :config ;; Enable globally (global-ethan-wspace-mode 1) ;; Customize what to clean (setq mode-require-final-newline nil)) ; ethan-wspace handles this ;; Rainbow delimiters (use-package rainbow-delimiters) ;; Smooth scrolling (use-package smooth-scrolling) ;; ----------------------------------------------------------------------------- ;; --- Navigation & Bookmarks ;; ----------------------------------------------------------------------------- ;; Visible bookmarks (use-package bm :bind (("" . bm-next) ("" . bm-previous) ("" . bm-toggle)) :config (set-faces '(bm-face ((t (:background "#604000")))) '(bm-fringe-face ((t (:background "DarkOrange1"))))) ) ;; Go to last change (use-package goto-last-change :bind (("C-M-l" . goto-last-change))) ;; ----------------------------------------------------------------------------- ;; --- Search Tools ;; ----------------------------------------------------------------------------- ;; Ripgrep integration (use-package rg :ensure t :config ;; Set custom command line flags to ignore specific directories (setq rg-command-line-flags '("--multiline" "--glob=!build/" "--glob=!extlib/" "--glob=!doxygen-html/")) (rg-enable-default-bindings) (rg-define-search rg-dwim-current-dir-no-ask "Search for literal in files matching the current file under the current directory." :query ask :format literal :files current ;:dir current :confirm never) :bind (("C-c C-s" . rg-dwim-current-dir-no-ask))) ;; ----------------------------------------------------------------------------- ;; --- File Management ;; ----------------------------------------------------------------------------- ;; Enhanced dired (defun my-dired-mouse-find-file (event) "In dired, visit the file or directory name you click on." (interactive "e") (let (window pos file) (save-excursion (setq window (posn-window (event-end event)) pos (posn-point (event-end event))) (if (not (windowp window)) (error "No file chosen")) (set-buffer (window-buffer window)) (goto-char pos) (setq file (dired-get-file-for-visit))) (if (file-directory-p file) (or (and (cdr dired-subdir-alist) (dired-goto-subdir file)) (progn (select-window window) (dired file))) (select-window window) (find-file (file-name-sans-versions file t))))) (use-package dired :ensure nil :init (setq dired-dwim-target t) :bind (:map dired-mode-map ;; backspace ([backspace] . dired-up-directory) ;; for some reason mouse-2 = left click (mouse-1) ([mouse-2] . 'my-dired-mouse-find-file) ([M-mouse-2] . 'diredp-mouse-find-file-other-frame) ;; copy and paste of files. ("M-w" . dired-ranger-copy) ("C-w" . dired-ranger-move) ("C-y" . dired-ranger-paste))) ;; Colorful dired (use-package diredfl :ensure t :hook (dired-mode . diredfl-mode) :config (diredfl-global-mode 1) ;; Dired faces (set-faces ;; ;; dired+ mode TODO ;; '(diredp-dir-priv ((t (:foreground "#74FFFF")))) ;; '(diredp-file-name ((t (:foreground "white")))) ;; '(diredp-dir-name ((t (:foreground "#74FFFF")))) ;; '(diredp-omit-file-name ((t (:inherit diredp-ignored-file-name :strike-through nil)))) '(diredfl-dir-name ((t (:foreground "#74FFFF" :background "black")))) '(diredfl-dir-priv ((t (:foreground "#74FFFF" :background "black")))) '(diredfl-exec-priv ((t (:foreground "#8F7B61" :background "black")))) '(diredfl-file-name ((t nil))) '(diredfl-no-priv ((t (:background "black")))) '(diredfl-read-priv ((t (:foreground "#b96285" :background "black")))) '(diredfl-write-priv ((t (:foreground "#45bF49" :background "black"))))) ) ;; Enhanced buffer menu (defun my-ibuffer-keys () "Modify keymaps used by `ibuffer'." (local-set-key (kbd "") 'ibuffer-visit-buffer)) (add-hook 'ibuffer-hook 'my-ibuffer-keys) ;; ----------------------------------------------------------------------------- ;; --- Version Control (Git) ;; ----------------------------------------------------------------------------- ;; Magit - Git interface (use-package magit :init (setq magit-diff-arguments '("--ignore-all-space") magit-log-arguments '("--graph" "--color" "--decorate" "-n100") magit-no-confirm '(stage-all-changes unstage-all-changes amend-published) magit-pull-arguments nil magit-refs-show-commit-count 'all magit-status-buffer-switch-function 'switch-to-buffer magit-diff-refine-hunk 'all git-link-use-commit t) :bind (("" . magit-status) ("" . magit-blame-addition) ("" . magit-log-buffer-file)) :config ;; Magit faces (set-faces '(magit-diff-added ((t (:foreground "#33ff33")))) '(magit-diff-added-highlight ((t (:inherit magit-diff-added :weight normal)))) '(magit-diff-removed ((t (:inherit diff-changed :foreground "red")))) '(magit-diff-removed-highlight ((t (:inherit magit-diff-removed :weight normal)))) '(magit-section-highlight ((t (:foreground "goldenrod"))))) ) (add-hook 'magit-status-mode-hook (lambda () (define-key magit-status-mode-map "\M-2" (lambda() (interactive) (make-frame))))) ;; Enable spell checking in commit messages (add-hook 'git-commit-mode-hook 'turn-on-flyspell) ;; ----------------------------------------------------------------------------- ;; --- Project Management ;; ----------------------------------------------------------------------------- ;; Projectile (use-package projectile :ensure t :init (projectile-mode +1) :bind (:map projectile-mode-map ("C-c p" . projectile-command-map)) :config (setq projectile-project-search-path '("~/ebay/")) (setq projectile-switch-project-action 'projectile-dired)) ;; Directory environment variables (use-package direnv :config (direnv-mode)) ;; ----------------------------------------------------------------------------- ;; --- Utility Packages ;; ----------------------------------------------------------------------------- ;; Diminish - hide minor modes (use-package diminish) ;; AI coding assistant (use-package aidermacs :bind (("C-c a" . aidermacs-transient-menu))) ;; ============================================================================ ;; SECTION 5: PROGRAMMING SUPPORT ;; ============================================================================ ;; ----------------------------------------------------------------------------- ;; --- Language Server Protocol (LSP) ;; ----------------------------------------------------------------------------- (use-package eglot :config (setq eglot-ignored-server-capabilities '(:documentOnTypeFormattingProvider)) (add-to-list 'eglot-server-programs `((scala-mode scala-ts-mode) . ,(alist-get 'scala-mode eglot-server-programs))) :bind (:map eglot-mode-map ("C-c e r" . eglot-rename) ("S-" . company-complete)) :hook ((python-mode . eglot-ensure) (scala-mode . eglot-ensure) (scala-ts-mode . eglot-ensure) (typescript-ts-mode . eglot-ensure)) :config ;; Eglot faces (set-faces '(eglot-highlight-symbol-face ((t (:background "#502500" :inherit bold)))) '(eglot-inlay-hint-face ((t (:height 0.8 :foreground "IndianRed4" :inherit shadow))))) ) (add-hook 'eglot-managed-mode-hook (lambda () (eglot-inlay-hints-mode -1))) ;; ----------------------------------------------------------------------------- ;; --- C/C++ Configuration ;; ----------------------------------------------------------------------------- ;; C/C++ indentation settings (setq c-basic-offset 4) (setq c-default-style '((java-mode . "java") (awk-mode . "awk") (other . "k&r"))) (setq c-offsets-alist '((inline-open . +) (innamespace . +))) (setq c-tab-always-indent nil) ;; Hook for all c-like programming modes. (defun tb-c-common-hook () "Common setup for C-like modes." ;; Enable `direnv` environment switching. ;(direnv-update-environment) ;; flyspell mode for comments (flyspell-prog-mode) ;; Enable eglot. (eglot-ensure) (setq paragraph-start "^[ ]*\\(//+\\|\\**\\)[ ]*\\([ ]*$\\|@\\(param\\|return\\|throw\\)\\)\\|^\f")) (add-hook 'c-mode-common-hook 'tb-c-common-hook) (use-package cc-mode :bind (:map c++-mode-map ("C-c C-s" . rg-dwim-current-dir-no-ask))) ;; ----------------------------------------------------------------------------- ;; --- Python Configuration ;; ----------------------------------------------------------------------------- (use-package python-mode :defer t :bind (:map python-mode-map ("C-c C-s" . rg-dwim-current-dir-no-ask))) ;; ----------------------------------------------------------------------------- ;; --- Scala Configuration ;; ----------------------------------------------------------------------------- (add-to-list 'major-mode-remap-alist '(scala-mode . scala-ts-mode)) ;; Hook for Scala programming modes. (defun tb-scala-common-hook () "Common setup for Scala modes." ;; Enable `direnv` environment switching. ;(direnv-update-environment) ;; flyspell mode for comments (flyspell-prog-mode) ;; Enable eglot. (eglot-ensure) (setq paragraph-start "^[ ]*\\(//+\\|\\**\\)[ ]*\\([ ]*$\\|@\\(param\\|return\\|throw\\)\\)\\|^\f")) (add-hook 'scala-mode-hook 'tb-scala-common-hook) (add-hook 'scala-ts-mode-hook 'tb-scala-common-hook) ;; Scala3 compilation patterns (add-to-list 'compilation-error-regexp-alist 'scala3-error) (add-to-list 'compilation-error-regexp-alist-alist '(scala3-error "^\\[error\\].*?: \\(.*\\.scala\\):\\([0-9]+\\):\\([0-9]+\\)" 1 2 3)) (add-to-list 'compilation-error-regexp-alist 'scala3-warn) (add-to-list 'compilation-error-regexp-alist-alist '(scala3-warn "^\\[warn\\] -- Warning: \\(.*\\.scala\\):\\([0-9]+\\):\\([0-9]+\\)" 1 2 3)) ;; Compilation warning face (set-faces '(compilation-warning ((t (:foreground "magenta" :inherit warning))))) ;; ----------------------------------------------------------------------------- ;; --- Perl Configuration ;; ----------------------------------------------------------------------------- ;; Perl configuration (defalias 'perl-mode 'cperl-mode) (setq cperl-continued-brace-offset -4) (setq cperl-continued-statement-offset 4) (setq cperl-extra-newline-before-brace nil) (setq cperl-extra-newline-before-brace-multiline nil) (setq cperl-indent-level 4) (setq cperl-indent-parens-as-block t) (setq cperl-label-offset -4) (setq cperl-merge-trailing-else nil) ;; Perl faces (set-faces '(cperl-array-face ((t (:foreground "#5555ff" :weight bold)))) '(cperl-hash-face ((t (:foreground "orange" :slant italic :weight bold))))) ;; ----------------------------------------------------------------------------- ;; --- Typescript Languages ;; ----------------------------------------------------------------------------- (use-package typescript-ts-mode :ensure t :after eglot :config (setq typescript-ts-mode-indent-offset 4)) ;; ----------------------------------------------------------------------------- ;; --- Other Programming Languages ;; ----------------------------------------------------------------------------- ;; Quick loading of various modes (use-package arduino-mode :defer t) (use-package basic-mode :defer t) (use-package bison-mode :defer t) (use-package cmake-mode :defer t) (use-package coffee-mode :defer t) (use-package csharp-mode :defer t) (use-package groovy-mode :defer t :bind (:map groovy-mode-map ("C-c C-s" . ripgrep))) (use-package haskell-mode :defer t) (use-package jinja2-mode :defer t) (use-package lua-mode :defer t) (use-package nix-mode :defer t) (use-package php-mode :defer t) (use-package protobuf-mode :defer t) (use-package qml-mode :defer t) ;; Shell script configuration (setq sh-indent-after-continuation 'always) ;; Custom Cassini mode (define-generic-mode 'cassini-text-mode '("//" "#") '("false" "true" "container" "query") '(("+" . 'font-lock-operator) ("-" . 'font-lock-operator) ("*" . 'font-lock-operator) ("/" . 'font-lock-operator) ("==" . 'font-lock-operator) ("!=" . 'font-lock-operator) ("<" . 'font-lock-operator) (">" . 'font-lock-operator) ("<=" . 'font-lock-operator) (">=" . 'font-lock-operator) (";" . 'font-lock-builtin) ("[+-]?\\([0-9]*\\.[0-9]+\\|[0-9]+\\.[0-9]*\\)\\([eE][+-]?[0-9]+\\)?" . 'font-lock-constant-face) ("\\b0x[0-9a-fA-F]+\\b" . 'font-lock-constant-face) ("\\b[0-9]+\\b" . 'font-lock-constant-face) ("\\b[A-Za-z_][A-Za-z0-9_]*:" . 'font-lock-variable-name-face) ("\\b\\([A-Za-z_][A-Za-z0-9_]*\\)[:space:]*[({]" 1 'font-lock-function-name-face)) '("\\.cql\\.txt$" "\\.cql$") nil "A mode for Cassini Text files") ;; ============================================================================ ;; SECTION 6: DOCUMENT & TEXT MODES ;; ============================================================================ ;; ----------------------------------------------------------------------------- ;; --- Markup Languages ;; ----------------------------------------------------------------------------- ;; Markdown (use-package markdown-mode :mode ("\\.md\\'" . markdown-mode) :hook (markdown-mode . (lambda () (visual-line-mode 1) (flyspell-mode) (set-variable 'fill-column 100000))) :config (set-faces '(markdown-header-face-1 ((t (:inherit org-level-1)))) '(markdown-header-face-2 ((t (:inherit org-level-2)))) '(markdown-header-face-3 ((t (:inherit org-level-3)))) '(markdown-header-face-4 ((t (:inherit org-level-4)))))) ;; Web modes (use-package web-beautify) (use-package yaml-mode) (use-package apache-mode :defer t) (use-package nginx-mode :defer t) (use-package dockerfile-mode :defer t) (use-package csv-mode :defer t) (use-package pandoc-mode :defer t) ;; Web-related settings (setq css-indent-offset 2) (setq js-indent-level 2) ;; File associations (add-to-list 'auto-mode-alist '("\\.htt\\'" . html-mode)) (add-to-list 'auto-mode-alist '("\\.blog\\'" . html-mode)) ;; ----------------------------------------------------------------------------- ;; --- LaTeX Configuration ;; ----------------------------------------------------------------------------- (use-package latex :defer t :ensure auctex :config ;; BibTeX settings (setq bibtex-comma-after-last-field t) (setq bibtex-maintain-sorted-entries 'crossref) ;; Compilation settings (setq TeX-command-force "LaTeX") (setq TeX-command-list '(("LaTeX" "%`~/.emacs.d/flymake-pdflatex -shell-escape --synctex=1 %(mode)%' %t" TeX-run-TeX nil (latex-mode doctex-mode) :help "Run LaTeX") ("Makeinfo" "makeinfo %(extraopts) %t" TeX-run-compile nil (texinfo-mode) :help "Run Makeinfo with Info output") ("BibTeX" "bibtex %s" TeX-run-BibTeX nil t :help "Run BibTeX") ("Biber" "biber %s" TeX-run-Biber nil t :help "Run Biber") ("View" "%V" TeX-run-discard-or-function t t :help "Run Viewer") ("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"))) :bind (:map LaTeX-mode-map ("C-c C-a" . (lambda (arg) (interactive "P") (let ((TeX-command-force nil)) (TeX-command-master arg)))) ("C-M-r" . reftex-reference) ("C-M-c" . reftex-citation) ("M-S-" . reftex-toc)) :config ;; TeX faces (set-faces '(TeX-fold-unfolded-face ((t (:background "#151823")))))) (defun tb-latex-common-hook () "Add some latex macro keys" (interactive) (turn-on-reftex) (visual-line-mode 1) ;; show frames in section list -> very useful for beamer presentations (setq reftex-section-levels (cons '("begin{frame}" . 3) reftex-section-levels)) ;; auto folding of tikzpicture and algorithm environments in tex files (TeX-fold-mode 0) (add-hook 'find-file-hook 'TeX-fold-buffer t)) (add-hook 'TeX-mode-hook 'tb-latex-common-hook) (add-hook 'LaTeX-mode-hook 'tb-latex-common-hook) ;; RefTeX settings (setq reftex-ref-macro-prompt nil) (setq reftex-label-alist '(("theorem" ?t "thm:" "~\\ref{%s}" t ("theorem" "th.") -2) ("lemma" ?t "lem:" "~\\ref{%s}" t ("lemma" "lem") -2) ("algorithm" ?a "alg:" "~\\ref{%s}" t ("algorithm" "alg") -2))) ;; ----------------------------------------------------------------------------- ;; --- Org-Mode Configuration ;; ----------------------------------------------------------------------------- (use-package org :config ;; Agenda settings (setq org-agenda-columns-add-appointments-to-effort-sum t org-agenda-files '("/home/tb/0/org-tassen/") org-agenda-skip-deadline-if-done t org-agenda-skip-scheduled-if-done t org-agenda-skip-timestamp-if-done t) ;; Capture templates (setq org-capture-templates '(("t" "TODO" entry (file+headline "~/0/org-tassen/gtd.org" "Inbox") "* TODO %?\12%T\12%i" :prepend t :jump-to-captured t :empty-lines-before 1 :empty-lines-after 1))) ;; Link and export settings (setq org-confirm-shell-link-function nil org-link-shell-confirm-function nil org-link-frame-setup '((vm . vm-visit-folder-other-frame) (vm-imap . vm-visit-imap-folder-other-frame) (gnus . org-gnus-no-new-news) (file . find-file) (wl . wl-other-frame)) org-export-allow-bind-keywords t org-export-backends '(ascii html latex md) org-html-validation-link "") ;; Display settings (setq org-reverse-note-order t org-tab-follows-link t org-tags-column -80 org-time-clocksum-format '(:hours "%d" :require-hours t :minutes ":%02d" :require-minutes t) org-priority-faces '((65 . "red") (66 . "yellow") (67 . "chartreuse")) org-table-number-regexp "^\\([<>]?[-+^.,0-9]*[0-9][-+^.,0-9eEdDx()%:]*\\|[<>]?[-+]?0[xX][[:xdigit:].]+\\|[<>]?[-+]?[0-9]+#[0-9a-zA-Z.,]+\\|nan\\|[-+u]?inf\\)$") ;; Org faces (set-faces '(org-checkbox ((t (:inherit bold :background "DarkGoldenrod4")))) '(org-date ((t (:foreground "dark magenta" :underline nil)))) '(org-drawer ((t (:foreground "dark slate blue")))) '(org-headline-done ((t (:foreground "DarkOrange4")))) '(org-level-1 ((t (:foreground "navajo white")))) '(org-level-2 ((t (:extend nil :foreground "deep sky blue")))) '(org-level-3 ((t (:extend nil :foreground "DarkOrange1")))) '(org-link ((t (:inherit link :foreground "cyan1" :underline t)))) '(org-priority ((t nil))) '(org-table ((t (:foreground "light sky blue")))) '(org-tag ((t (:foreground "orchid")))) '(org-todo ((t (:inherit nil :foreground "chartreuse"))))) ) (add-hook 'org-mode-hook (lambda () (local-unset-key [(meta shift up)]) (local-unset-key [(meta shift down)]) (local-set-key [(control shift up)] 'org-move-subtree-up) (local-set-key [(control shift down)] 'org-move-subtree-down) (local-set-key [(control shift left)] 'org-promote-subtree) (local-set-key [(control shift right)] 'org-demote-subtree) (local-set-key [(control return)] 'org-insert-heading) (local-set-key [(meta control return)] 'org-time-stamp) (local-set-key [f5] 'org-html-export-to-html) (local-set-key [f6] 'org-latex-export-to-pdf))) ;; ----------------------------------------------------------------------------- ;; --- Accounting ;; ----------------------------------------------------------------------------- (set-faces '(beancount-account ((t (:foreground "DeepSkyBlue1" :inherit font-lock-builtin-face)))) '(beancount-directive ((t (:foreground "violet red" :inherit font-lock-keyword-face))))) ;; ============================================================================ ;; SECTION 7: UTILITY FUNCTIONS ;; ============================================================================ ;; ----------------------------------------------------------------------------- ;; --- Buffer Management ;; ----------------------------------------------------------------------------- (defun nuke-all-buffers () "Kill all buffers, leaving *scratch* only." (interactive) (mapcar (lambda (x) (kill-buffer x)) (buffer-list)) (delete-other-windows)) ;; ----------------------------------------------------------------------------- ;; --- System Integration ;; ----------------------------------------------------------------------------- (defun my-terminal (&optional arg) "Launch terminal in current directory." (interactive) (if (file-remote-p default-directory) (shell) (let ((terminal-cmd (getenv "TERMINAL"))) (when terminal-cmd ;; Split the command properly, handling spaces in paths (let ((args (split-string-and-unquote terminal-cmd))) (apply 'start-process "terminal" nil args)))))) ;; ----------------------------------------------------------------------------- ;; --- Compilation ;; ----------------------------------------------------------------------------- (defun my-compile (pfx) "Saves all unsaved buffers, and runs 'compile' with optional ede project customization." (interactive "p") (save-some-buffers t) (if (buffer-live-p compilation-last-buffer) (recompile) (let* ((fname (or (buffer-file-name (current-buffer)) default-directory)) (current-dir (file-name-directory fname)) (proj (ede-current-project current-dir))) (if proj (project-compile-project proj) (call-interactively 'compile))))) (defun tb-save-stage-and-format () "Save all files, stage all changes with Magit, and run git-clang-format." (interactive) (save-some-buffers t) (magit-stage-modified) (let ((default-directory (magit-toplevel))) (if default-directory (progn (message "Running git-clang-format...") (shell-command "git-clang-format")) (message "Not inside a git repository."))) (magit-refresh)) ;; ----------------------------------------------------------------------------- ;; --- Text Manipulation ;; ----------------------------------------------------------------------------- ;; Kill without adding to kill-ring (defun dove-backward-kill-word (&optional arg) "Backward kill word, but do not insert it into kill-ring" (interactive "P") (let ((end (point)) (beg (progn (backward-word arg) (point)))) (delete-region beg end))) (defun dove-forward-kill-word (&optional arg) "Forward kill word, but do not insert it into kill-ring" (interactive "P") (let ((beg (point)) (end (progn (forward-word arg) (point)))) (delete-region beg end))) ;; Case conversion (defun split-name (s) (split-string (let ((case-fold-search nil)) (downcase (replace-regexp-in-string "\\([a-z]\\)\\([A-Z]\\)" "\\1 \\2" s))) "[^A-Za-z0-9]+")) (defun camelcase (s) (mapconcat 'capitalize (split-name s) "")) (defun underscore (s) (mapconcat 'downcase (split-name s) "_")) (defun camelscore (s) (cond ((string-match-p "-" s) (colonize s)) ((string-match-p "_" s) (dasherize s)) (t (underscore s)))) (defun camelscore-word-at-point () (interactive) (let* ((case-fold-search nil) (beg (and (skip-chars-backward "[:alnum:]_") (point))) (end (and (skip-chars-forward "[:alnum:]_") (point))) (txt (buffer-substring beg end)) (cml (camelscore txt))) (if cml (progn (delete-region beg end) (insert cml))))) ;; JSON formatting (defun beautify-json () (interactive) (let ((b (if mark-active (min (point) (mark)) (point-min))) (e (if mark-active (max (point) (mark)) (point-max)))) (shell-command-on-region b e "python -mjson.tool" (current-buffer) t))) ;; Org-mode utilities (defun org-insert-now-timestamp() "Insert org mode timestamp at point with current date and time." (interactive) (org-insert-time-stamp (current-time) t)) ;; ----------------------------------------------------------------------------- ;; --- Number Manipulation ;; ----------------------------------------------------------------------------- (defun increment-number-decimal (&optional arg) "Increment the number forward from point by 'arg'." (interactive "p*") (save-excursion (save-match-data (let (inc-by field-width answer) (setq inc-by (if arg arg 1)) (skip-chars-backward "0123456789") (when (re-search-forward "[0-9]+" nil t) (setq field-width (- (match-end 0) (match-beginning 0))) (setq answer (+ (string-to-number (match-string 0) 10) inc-by)) (when (< answer 0) (setq answer (+ (expt 10 field-width) answer))) (replace-match (format (concat "%0" (int-to-string field-width) "d") answer))))))) (defun decrement-number-decimal (&optional arg) (interactive "p*") (increment-number-decimal (if arg (- arg) -1))) (defun increment-number-hexadecimal (&optional arg) "Increment the hexadecimal number forward from point by 'arg'." (interactive "p*") (save-excursion (save-match-data (let (inc-by field-width answer hex-format) (setq inc-by (if arg arg 1)) (skip-chars-backward "0123456789abcdefABCDEF") (when (re-search-forward "[0-9a-fA-F]+" nil t) (setq field-width (- (match-end 0) (match-beginning 0))) (setq answer (+ (string-to-number (match-string 0) 16) inc-by)) (when (< answer 0) (setq answer (+ (expt 16 field-width) answer))) (if (equal (match-string 0) (upcase (match-string 0))) (setq hex-format "X") (setq hex-format "x")) (replace-match (format (concat "%0" (int-to-string field-width) hex-format) answer))))))) (defun decrement-number-hexadecimal (&optional arg) (interactive "p*") (increment-number-hexadecimal (if arg (- arg) -1))) ;; ============================================================================ ;; SECTION 8: KEY BINDINGS ;; ============================================================================ ;; ----------------------------------------------------------------------------- ;; --- Window Management ;; ----------------------------------------------------------------------------- (require 'windmove) (windmove-default-keybindings) ;; Window navigation (global-set-key [M-left] 'windmove-left) (global-set-key [M-right] 'windmove-right) (global-set-key [M-up] 'windmove-up) (global-set-key [M-down] 'windmove-down) ;; Window resizing (global-set-key (kbd "S-C-") 'shrink-window-horizontally) (global-set-key (kbd "S-C-") 'enlarge-window-horizontally) (global-set-key (kbd "S-C-") 'shrink-window) (global-set-key (kbd "S-C-") 'enlarge-window) ;; Window operations (global-set-key "\M-`" 'delete-other-windows) (global-set-key "\M-2" 'make-frame) (global-set-key "\M-3" 'delete-frame) ;; ----------------------------------------------------------------------------- ;; --- Navigation & Editing ;; ----------------------------------------------------------------------------- ;; Basic navigation (global-set-key "\M-g" 'goto-line) (global-set-key (kbd "C-x f") 'find-file-at-point) ;; Buffer navigation (global-set-key [C-x C-b] 'buffer-menu) (global-set-key [M-S-up] 'ibuffer) (global-set-key [M-S-left] 'previous-buffer) (global-set-key [M-S-right] 'next-buffer) ;; Text manipulation (global-set-key (kbd "C-c SPC") 'comment-or-uncomment-region) (global-set-key [(meta backspace)] 'backward-kill-word) (global-set-key [(control backspace)] 'dove-backward-kill-word) (global-set-key [(meta delete)] 'kill-word) (global-set-key [(control delete)] 'dove-forward-kill-word) ;; ----------------------------------------------------------------------------- ;; --- Function Keys ;; ----------------------------------------------------------------------------- ;; F2 reserved for bookmarks (bm package) (global-set-key [f3] 'projectile-find-other-file) ; Switch between .cpp/.hpp (global-set-key [f4] 'my-terminal) ; Launch terminal (global-set-key [f5] 'my-compile) ; Compile (global-set-key [f6] 'tb-save-stage-and-format) ; Save, stage, format ;; German umlauts (global-set-key (kbd "") (lambda() (interactive) (insert ?\ä))) (global-set-key (kbd "") (lambda() (interactive) (insert ?\Ä))) (global-set-key (kbd "") (lambda() (interactive) (insert ?\ö))) (global-set-key (kbd "") (lambda() (interactive) (insert ?\Ö))) (global-set-key (kbd "") (lambda() (interactive) (insert ?\ü))) (global-set-key (kbd "") (lambda() (interactive) (insert ?\Ü))) (global-set-key (kbd "") (lambda() (interactive) (insert ?\ß))) ;; ----------------------------------------------------------------------------- ;; --- Mouse & Display ;; ----------------------------------------------------------------------------- ;; Mouse wheel (global-set-key (kbd "") (lambda (event) (interactive "e"))) (global-set-key (kbd "") (lambda (event) (interactive "e"))) ;; Frame zoom (global-set-key (kbd "C-x C-=") 'acg/zoom-frame) (global-set-key (kbd "C-x C--") 'acg/zoom-frame-out) (global-set-key (kbd "") 'acg/zoom-frame) (global-set-key (kbd "") 'acg/zoom-frame-out) ;; ----------------------------------------------------------------------------- ;; --- Special Commands ;; ----------------------------------------------------------------------------- (global-set-key (kbd "C-x K") 'nuke-all-buffers) ;; Shell/Comint (define-key comint-mode-map (kbd "") 'comint-previous-input) (define-key comint-mode-map (kbd "") 'comint-next-input) ;; ============================================================================ ;; THE END. ;; ============================================================================