;;; common.el --- Common programming settings. -*- lexical-binding: t; -*- ;;; Commentary: ;;; Code: (require 'basics/package-management) (require 'basics/global-variables) (require 'misc/completion) (use-package emacs :straight (:type built-in) :demand t :after (compile) :defines (compilation-mode-map) :custom (compilation-scroll-output 'first-error) :config (progn (setq-default indent-tabs-mode nil ; Set default indentation. tab-width 4) (electric-pair-mode t) ; Auto-type closing brackets. (defun my/clangd-version () "Returns the version of clangd as float." (string-to-number (nth 2 (split-string (shell-command-to-string "clangd --version"))))) (which-function-mode)) :bind (("C-:" . ff-find-other-file) ; Switch between header and source. (:map compilation-mode-map ("" . compilation-previous-error) ("" . compilation-next-error)))) ;; Guess indentation and if spaces or tabs are to be used. (use-package dtrt-indent :after (editorconfig) :diminish dtrt-indent-mode :hook ((dtrt-indent-mode . editorconfig-apply) (prog-mode . dtrt-indent-mode))) ;; Online documentation mode. (use-package eldoc :diminish eldoc-mode :hook (prog-mode . turn-on-eldoc-mode)) ;; Syntax checking with many plugins. (use-package flycheck :unless slow-computer :demand t :functions (flycheck-add-mode) :diminish flycheck-mode :custom ((flycheck-cppcheck-checks '("style" "warning" "information")) (flycheck-emacs-lisp-load-path 'inherit) ; Use load-path of Emacs. (flycheck-idle-change-delay 2.0)) :config (progn (global-flycheck-mode) (flycheck-add-mode 'html-tidy 'web-mode) (flycheck-add-mode 'css-csslint 'web-mode)) :bind (:map flycheck-mode-map ("" . flycheck-previous-error) ("" . flycheck-next-error) ("" . flycheck-list-errors))) ;; Automatic project management. (use-package projectile :unless slow-computer :demand t :after (treemacs ivy window-purpose f) :functions (treemacs-collapse-other-projects treemacs-toggle-node my/projectile-kill-buffers purpose-set-window-purpose-dedicated-p) :diminish projectile-mode :init (progn (defun my/projectile-enable-caching? (&rest args) "Turn on caching for certain projects. Ignores ARGS." (if (string= (projectile-project-name) ".emacs.d") (progn (message "Turning on caching for \"%s\"." (projectile-project-name)) (setq-local projectile-enable-caching t)) (kill-local-variable 'projectile-enable-caching))) (advice-add 'projectile-find-file :before #'my/projectile-enable-caching?) (advice-add 'counsel-projectile-find-file :before #'my/projectile-enable-caching?) (defun my/switch-project () "Find file in project, add project to `treemacs' and collapse other projects." (if (member 'counsel-projectile-mode minor-mode-list) (counsel-projectile-find-file) (projectile-find-file)) (when (>= (frame-width) 120) (treemacs-add-and-display-current-project) (treemacs-collapse-other-projects) (other-window 1))) (defun my/projectile-kill-buffers () "Kill project buffers and delete other windows." (interactive) (projectile-kill-buffers) (delete-other-windows) (purpose-set-window-purpose-dedicated-p nil nil))) :custom ((projectile-switch-project-action 'my/switch-project) (projectile-completion-system 'ivy) (projectile-indexing-method 'hybrid) ; Allow filtering. (projectile-globally-ignored-file-suffixes '("~" "#")) (projectile-enable-cmake-presets t)) :config (progn (projectile-mode +1) ;; Mark variables as safe. Prevents prompts with .dir-locals.el. (put 'projectile-project-compilation-cmd 'safe-local-variable #'stringp) (put 'projectile-project-configure-cmd 'safe-local-variable #'stringp) ;; Auto-search for projects. (if (f-directory? "~/Projekte") (setq projectile-project-search-path '("~/Projekte"))) (push "backups" projectile-globally-ignored-directories)) :bind (("C-c p" . 'projectile-command-map) (:map projectile-command-map ("k" . 'my/projectile-kill-buffers)) (:map projectile-mode-map ; Only override in projectile-mode. ("C-x C-f" . 'projectile-find-file)))) (use-package counsel-projectile :demand t :after (counsel projectile) :custom ((counsel-projectile-sort-files t)) :config (progn ;; I'm not exactly sure what I did here but it seems to work. (defun my/counsel-projectile-switch-project-action (project) "Call `my/switch-project'." (let ((projectile-switch-project-action 'my/switch-project)) (counsel-projectile-switch-project-by-name project))) (counsel-projectile-modify-action 'counsel-projectile-switch-project-action '((add ("Y" my/counsel-projectile-switch-project-action "open project in treemacs") 1))) ;; Overwrite keybindings and so on. (counsel-projectile-mode))) ;; Highlight TODO, FIXME, NOTE and so on. (use-package hl-todo :bind (:map hl-todo-mode-map ("C-c t" . hl-todo-occur)) :hook (prog-mode . hl-todo-mode)) ;; Better commenting. (use-package smart-comment :bind ("C-c c" . smart-comment)) ;; Toggle betweeen beginning/end of line and beginning/end of code. (use-package mwim :bind (("" . mwim-beginning-of-line-or-code) ("" . mwim-end-of-line-or-code))) ;; Needs to be here in order to diminish it. (use-package hideshow :defer 4 :diminish hs-minor-mode) ;; Fold code. (use-package fold-dwim :after (hideshow) :bind ("C-c f" . fold-dwim-toggle) :hook (prog-mode . hs-minor-mode)) ;; Highlight indentation. (use-package hl-indent :after (doom-themes whitespace) :config (progn (set-face-background 'hl-indent-face ; Reverse whitespace-space. (face-foreground 'whitespace-space)) (set-face-foreground 'hl-indent-face (face-background 'default))) :hook (prog-mode . hl-indent-mode)) ;; Jump to definition using grep. (use-package dumb-jump :after (ivy) :custom (dumb-jump-selector 'ivy) :config (add-hook 'xref-backend-functions #'dumb-jump-xref-activate)) ;; Support .editorconfig files. (use-package editorconfig :defer 2 :diminish editorconfig-mode :config (editorconfig-mode 1)) (use-package smerge-mode :defines (smerge-mode-map) :bind (:map smerge-mode-map ("" . smerge-prev) ("" . smerge-next) ("" . smerge-resolve) ("C-" . smerge-keep-upper) ("C-" . smerge-keep-lower))) (use-package copyright :config (defun my/maybe-copyright-update () "Update existing copyright notice to indicate the current year if mode is derived from prog-mode." (if (and my/reformat-save (derived-mode-p 'prog-mode)) (copyright-update))) :hook (before-save . my/maybe-copyright-update)) ;; Highlights parentheses, brackets or braces according to their depth. (use-package rainbow-delimiters :custom (rainbow-delimiters-max-face-count 2) :custom-face (rainbow-delimiters-depth-1-face ((t (:inherit rainbow-delimiters-base-face :foreground "LightPink")))) (rainbow-delimiters-depth-2-face ((t (:inherit rainbow-delimiters-base-face :foreground "LightGreen")))) (rainbow-delimiters-depth-3-face ((t (:inherit rainbow-delimiters-base-face :foreground "MediumPurple1")))) (rainbow-delimiters-depth-4-face ((t (:inherit rainbow-delimiters-base-face :foreground "LightSkyBlue")))) :hook (prog-mode . rainbow-delimiters-mode)) ;; Make bug references clickable. (use-package bug-reference :straight (:type built-in) :config (put 'bug-reference-url-format 'safe-local-variable #'stringp) :hook (prog-mode . bug-reference-prog-mode)) (use-package diff :straight (:type built-in) :hook (diff-mode . (lambda () (setq-local my/reformat-save nil)))) ;; Insert SPDX license identifiers. (use-package spdx :custom((spdx-copyright-holder 'auto) (spdx-project-detection 'auto)) :bind (:map prog-mode-map ("C-c i l" . spdx-insert-spdx))) (provide 'programming/common) ;;; common.el ends here