;;; init.el --- tastytea's Emacs init file. ;;; Time-stamp: <2019-03-22 06:28:08 CET> ;;; Commentary: ;;; I am using this file with Emacs 26, but most of it will probably work with ;;; Emacs 24 and above. ;;; Code: ;;;;;;;;;;;;;;;;;;;; Packages ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (require 'package) ;; (add-to-list 'package-archives ;; '("melpa-stable" . "https://stable.melpa.org/packages/") t) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (package-initialize) ;; Add path for custom packages (add-to-list 'load-path "~/.emacs.d/custom-packages/") ;; Install use-package if necessary (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (eval-when-compile (require 'use-package)) ;; Always install packages if they are not present (require 'use-package-ensure) (setq use-package-always-ensure t) ;; autocompile files as needed. (use-package auto-compile :init ;; Use uncompiled file if it is newer than the compiled one (setq load-prefer-newer t) :config (auto-compile-on-load-mode)) ;; ;; Benchmark initialization ;; (use-package benchmark-init ;; :config ;; ;; To disable collection of benchmark data after init is done. ;; (add-hook 'after-init-hook 'benchmark-init/deactivate)) ;; Update packages if at least auto-package-update-interval (7) days have passed (use-package auto-package-update :config (setq auto-package-update-delete-old-versions t) ;; (setq auto-package-update-hide-results t) (auto-package-update-maybe)) ;;;;;;;;;;;;;;;;;;;; Global variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Determine if we run on a slow computer (defvar slow-computer nil) (if (member (system-name) '("steuerbeamter" "azimuth" "localhost")) (setq slow-computer t)) ; localhost is schnibble ;;;;;;;;;;;;;;;;;;;; Configure some essential things ;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Set garbage collection threshold to 100 MiB (or 20 MiB) to speed up init ;; It is reset at the end of the file (if slow-computer (setq gc-cons-threshold (* 20 1024 1024)) (setq gc-cons-threshold (* 100 1024 1024))) ;; Accelerate startup by not printing so much (setf inhibit-startup-screen t inhibit-startup-echo-area-message t inhibit-startup-message t) ;; Just type y/n instead of yes/no when prompted (defalias 'yes-or-no-p 'y-or-n-p) ;; Hide toolbar (tool-bar-mode -1) ;; Save cursor position (use-package saveplace :config (save-place-mode t)) ;; Delete selection when you start to write (delete-selection-mode t) ;; Save minibuffer history (savehist-mode t) ;; Save backups in ~/.emacs.d/ and keep more versions (setq backup-directory-alist `(("." . ,(concat user-emacs-directory "backups")))) (setq delete-old-versions t kept-new-versions 6 ;; kept-old-versions 2 version-control t) ;; ;; Needed for do-all-symbols ;; (use-package cl) ;; Personal information (setq user-login-name "tastytea" user-full-name "tastytea" user-mail-address "tastytea@tastytea.de") ;; kill-region (cut) and kill-ring-save (copy) act on the current line if no ;; text is visually selected ;; https://www.emacswiki.org/emacs/WholeLineOrRegion (put 'kill-ring-save 'interactive-form '(interactive (if (use-region-p) (list (region-beginning) (region-end)) (list (line-beginning-position) (line-beginning-position 2))))) (put 'kill-region 'interactive-form '(interactive (if (use-region-p) (list (region-beginning) (region-end)) (list (line-beginning-position) (line-beginning-position 2))))) ;; Banish customizations to another file (setq custom-file (concat user-emacs-directory "custom.el")) ;; Scoll 1 line at a time (setq mouse-wheel-scroll-amount '(1 ((shift) . 1))) ;; Scroll before cursor has reached top/bottom (use-package smooth-scrolling :config (smooth-scrolling-mode 1)) ;; Paste text where the cursor is, not where the mouse is. (setq mouse-yank-at-point t) ;; Put scrollbar to the right side (if (display-graphic-p) (set-scroll-bar-mode 'right)) ;;;;;;;;;;;;;;;;;;;; Keybindings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (use-package bind-key :config (bind-keys ;; Scroll in other window ("S-" . scroll-other-window-down) ("S-" . scroll-other-window) ;; Switch window ("C-" . other-window) ;; Reduce whitespace around point to 0 or 1, according to context ("C-" . fixup-whitespace) ;; Scroll without moving the cursor ("M-" . scroll-up-line) ("M-" . scroll-down-line))) ;;;;;;;;;;;;;;;;;;;; Programming / C++ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (use-package rtags :unless slow-computer :if (executable-find "llvm-config") :if (executable-find "clang++") :config (unless (and (rtags-executable-find "rc") (rtags-executable-find "rdm")) (progn (message "RTags is not installed!") (rtags-install))) (define-key c-mode-base-map (kbd "M-.") 'rtags-find-symbol-at-point) (define-key c-mode-base-map (kbd "M-,") 'rtags-find-references-at-point) (define-key c-mode-base-map (kbd "M-?") 'rtags-display-summary) (rtags-enable-standard-keybindings) :hook (c++-mode . (rtags-start-process-unless-running)) (c-mode . (rtags-start-process-unless-running)) (kill-emacs . rtags-quit-rdm)) (use-package flycheck-rtags :after (flycheck rtags) :demand t :config ;; ensure that we use only rtags checking ;; https://github.com/Andersbakken/rtags#optional-1 (defun setup-flycheck-rtags () (flycheck-select-checker 'rtags) (setq-local flycheck-highlighting-mode nil)) ; Can't disable RTags overlay :hook (c-mode-hook . #'setup-flycheck-rtags) (c++-mode-hook . #'setup-flycheck-rtags)) (use-package company-rtags :after (company rtags) :config ;; (setq rtags-autostart-diagnostics t) ;; (rtags-diagnostics) (setq rtags-completions-enabled t) (push 'company-rtags company-backends)) ;; cmake integration (use-package cmake-ide :unless slow-computer :config (setq cmake-ide-build-dir "build") (cmake-ide-setup)) ;;;;;;;;;;;;;;;;;;;; Programming / other ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Online documentation mode (use-package eldoc :hook (prog-mode . turn-on-eldoc-mode)) ;; Syntax checking (use-package flycheck :unless slow-computer :config (global-flycheck-mode)) ;; Autocompletion (use-package company :unless slow-computer :hook (after-init . global-company-mode)) ;; Fuzzy autocompletion (use-package company-flx :after company :config (company-flx-mode +1)) ;; Indentation (setq-default indent-tabs-mode nil tab-width 4) (setq c-default-style "linux" c-basic-offset 4) ;; Project management (use-package projectile :unless slow-computer :after neotree :config (projectile-mode +1) (setq projectile-switch-project-action 'neotree-projectile-action projectile-project-compilation-dir "build" projectile-project-configure-cmd "cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -G 'Unix Makefiles' .." projectile-project-compilation-cmd "cmake --build .") (defun projectile-kill-buffers-and-change-tabbar-grouping () "Kill project buffers and change tabbar-ruler grouping to user-buffers." (interactive) (projectile-kill-buffers) (tabbar-ruler-group-user-buffers)) :bind ("C-c p" . 'projectile-command-map) (:map projectile-command-map ("k" . 'projectile-kill-buffers-and-change-tabbar-grouping))) ;; Debugger (use-package realgud :config (defun load-realgud () (load-library "realgud")) :hook (c++-mode . load-realgud) (c-mode . load-realgud)) ;; Highlight TODO, FIXME, NOTE and so on. (use-package hl-todo :hook (prog-mode . hl-todo-mode)) ;; Better commenting (use-package smart-comment :bind ("C-x 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)) ;; Auto-type closing brackets (electric-pair-mode t) ;; Folding (use-package fold-dwim :bind ("" . fold-dwim-toggle) ("C-x t" . fold-dwim-toggle) :hook (prog-mode . hs-minor-mode)) ;; Highlight indentation levels (use-package highlight-indent-guides :config (setq highlight-indent-guides-method 'character highlight-indent-guides-responsive 'top) :hook (prog-mode . highlight-indent-guides-mode)) (use-package imenu-anywhere :after ido-completing-read+ :bind ("M-i" . imenu-anywhere)) ;;;;;;;;;;;;;;;;;;;; Appearance ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Icons (required by doom) (use-package all-the-icons :config (unless (file-exists-p "~/.local/share/fonts/all-the-icons.ttf") (all-the-icons-install-fonts t))) ;; Theme (use-package doom-themes :unless slow-computer :after (all-the-icons neotree) :config (load-theme 'doom-molokai t) (doom-themes-neotree-config) :custom (doom-neotree-file-icons 'icons)) ;; Modeline (use-package doom-modeline :after all-the-icons :init ;; Show column numbers in modeline (column-number-mode t) :config (setq doom-modeline-minor-modes t) :hook (after-init . doom-modeline-mode)) ;; Misc (set-face-font 'default "Source Code Pro") (global-hl-line-mode t) (if (>= emacs-major-version 26) (use-package display-line-numbers :config (global-display-line-numbers-mode))) (size-indication-mode) (show-paren-mode t) ;;;;;;;;;;;;;;;;;;;; Misc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Directory tree (use-package neotree :demand t :after all-the-icons :custom (neo-smart-open t) (neo-show-updir-line t) ; Disabled by doom-themes? (neo-window-width 30) ;; (setq neo-theme (if (display-graphic-p) 'icons 'arrow)) :bind ("" . neotree-toggle)) (use-package magit :unless slow-computer :init (use-package git-commit) :config (defun my-magit-kill-buffers (arg) "Restore window configuration and kill all Magit buffers." (interactive) (let ((buffers (magit-mode-get-buffers))) (magit-restore-window-configuration) (mapc #'kill-buffer buffers))) :bind ("C-x g" . magit-status) ("C-x M-g" . magit-dispatch) ;; (:map magit-status-mode-map ;; ("q" . my-magit-kill-buffers)) :custom ;; What's better, mapping q or binding the function here? (magit-bury-buffer-function 'my-magit-kill-buffers)) ;; Draw line in column 80 (use-package fill-column-indicator :after company :config ;; ;; TODO: Find out why I can't put this in :init or :config ;; (define-globalized-minor-mode global-fci-mode fci-mode ;; (lambda () (fci-mode t))) ;; (global-fci-mode t) ;; Fix bug with fci + company (defun on-off-fci-before-company(command) (when (string= "show" command) (turn-off-fci-mode)) (when (string= "hide" command) (turn-on-fci-mode))) (advice-add 'company-call-frontends :before #'on-off-fci-before-company) ;; Add global fci-mode :hook (prog-mode . fci-mode) (text-mode . fci-mode) :custom (fci-rule-column 80)) ;; Interactive substring matching (use-package ido :defer 1 :config (ido-mode t) (ido-everywhere t)) (use-package flx-ido :after ido :config (flx-ido-mode t) (setq ido-enable-flex-matching t ido-ignore-extensions t ido-use-virtual-buffers t)) ; Keep history of recently opened buffers ;; Replaces stock emacs completion with ido completion wherever it is possible (use-package ido-completing-read+ :unless slow-computer :after ido :config (ido-ubiquitous-mode t)) ;; Tab bar (use-package tabbar-ruler :unless slow-computer :after projectile :init (setq tabbar-ruler-global-tabbar t) :config ;; (tabbar-ruler-group-by-projectile-project) ; Group by projectile ;; (tabbar-ruler-group-buffer-groups) ; Group by file type (tabbar-ruler-group-user-buffers) ; Group by frame ;; (mode-icons-mode 0) ; Disable modeline symbols ;; I have to define these 2 times, don't know why. (set-face-attribute 'tabbar-selected nil :background "gray11" :foreground "light gray" :family "Sans Serif" :bold t) (set-face-attribute 'tabbar-unselected nil :background "gray18" :foreground "dark gray" :family "Sans Serif" :italic t) (add-hook 'projectile-after-switch-project-hook ; Does not work under :hook 'tabbar-ruler-group-by-projectile-project) :bind ("C-" . 'tabbar-ruler-tabbar-backward-tab) ("C-" . 'tabbar-ruler-tabbar-forward-tab) :custom-face ;; I Have to define these 2 times, don't know why. (tabbar-selected (nil :background "gray11" :foreground "light gray" :family "Sans Serif" :bold t)) (tabbar-unselected (nil :background "gray18" :foreground "dark gray" :family "Sans Serif" :italic t))) ;; Keybinding for whitespace, don't visualise newlines (use-package whitespace :config (delete 'newline-mark whitespace-style) ; $ at eol (delete 'lines whitespace-style) ; Don't paint lines red if too long. ;; Don't show dots in company menu (defun on-off-whitespace-before-company(command) (when (string= "show" command) (whitespace-mode -1)) (when (string= "hide" command) (whitespace-mode t))) (advice-add 'company-call-frontends :before #'on-off-whitespace-before-company) :bind ("C-x w" . 'whitespace-mode) :hook (prog-mode . whitespace-mode) :custom-face (whitespace-space ((nil :foreground "gray18")))) ;; Spell checking (use-package flyspell :config (defun toggle-flyspell () "Toggle flyspell-mode and run flyspell-buffer after activating" (interactive) (if (bound-and-true-p flyspell-mode) (flyspell-mode 0) (flyspell-mode) (flyspell-buffer))) (setq ispell-dictionary "english") :bind ("" . toggle-flyspell) :hook (c++-mode . flyspell-prog-mode) (c-mode . flyspell-prog-mode)) ;; Multiple cursors (use-package multiple-cursors :init (global-unset-key (kbd "M-")) :bind ("C-x M-m" . mc/edit-lines) ("M-" . mc/add-cursor-on-click)) ;; If 2 files with same name, append directory name after the filename (use-package uniquify :defer 1 :ensure nil ; Included in emacs :custom (uniquify-after-kill-buffer-p t) (uniquify-buffer-name-style 'post-forward) (uniquify-strip-common-suffix t)) ;; Delete old buffers ;; https://www.emacswiki.org/emacs/CleanBufferList (use-package midnight :init (setq midnight-delay 0) ; 0 seconds after "midnight" :config (setq midnight-period (* 1 60 60) ; Clean every 1 hours clean-buffer-list-delay-general 1 ; Clean normal bufs after 1d clean-buffer-list-delay-special (* 30 60) ; Clean special bufs after 30m clean-buffer-list-kill-regexps ; Add these to special buffers (nconc clean-buffer-list-kill-regexps '("\\`magit-?.*:" "\\.log\\'"))) (midnight-mode t)) ;; The string Time-stamp: <> in the first 8 lines of the file will be updated ;; with the current timestamp. (use-package time-stamp :config (setq time-stamp-format "%:y-%02m-%02d %02H:%02M:%02S %Z") :hook (before-save . time-stamp)) ;; Edit multiple regions in the same way simultaneously (use-package iedit :bind ("C-;" . iedit-mode)) (use-package easy-hugo :custom (easy-hugo-basedir "~/Projekte/www/blog.tastytea.de/") (easy-hugo-url "https://blog.tastytea.de") (easy-hugo-previewtime "300") (easy-hugo-postdir "content/posts") (easy-hugo-default-ext ".adoc") :bind ("C-c h" . easy-hugo) :mode ;; The mode is not turned on? ("\\`'\\*Easy-hugo\\*\\'" . easy-hugo-mode)) ;; Automatically insert text in new files (use-package autoinsert :init ;; I only use it in here for now (use-package yasnippet) (defun my/autoinsert-yas-expand() "Replace text in yasnippet template." (yas-minor-mode t) (yas-expand-snippet (buffer-string) (point-min) (point-max))) :config ;; (define-auto-insert "\.cpp" . ["c++" my/autoinsert-yas-expand]) (add-to-list 'auto-insert-alist '(("\\.\\(cpp\\|cc\\|cxx\\|c\\+\\+\\)\\'" . "C++ program") . ["cpp" my/autoinsert-yas-expand])) (add-to-list 'auto-insert-alist '(("\\.\\(hpp\\|hh\\|hxx\\|h\\+\\+\\)\\'" . "C++ header") . ["hpp" my/autoinsert-yas-expand])) :custom (auto-insert-directory (concat user-emacs-directory "auto-insert")) (auto-insert-query nil) ; Always insert :hook (find-file . auto-insert)) ;;;;;;;;;;;;;;;;;;;; File formats ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (use-package adoc-mode :mode (("\\.adoc" . adoc-mode))) (use-package markdown-mode :mode (("README\\.md\\'" . gfm-mode) ("\\.md\\'" . markdown-mode) ("\\.markdown\\'" . markdown-mode)) :init (setq markdown-command "markdown2")) (use-package crontab-mode :mode (("/cron\\.d/" . crontab-mode)) ("\\`'/etc/crontab\\'" . crontab-mode)) (use-package nginx-mode :defer t) (use-package company-nginx :after nginx-mode :hook (nginx-mode . company-nginx-keywords)) ;;;;;;;;;;;;;;;;;;;; Server / Remote editing ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Edit remote files (use-package tramp :unless slow-computer :defer 1 :config ;; ssh is faster than scp and supports ports (setq tramp-default-method "ssh") ;; Add verification code support (customize-set-variable 'tramp-password-prompt-regexp (concat "^.*" (regexp-opt '("passphrase" "Passphrase" "password" "Password" "Verification code") t) ".*:\0? *")) ;; Respect remote PATH (add-to-list 'tramp-remote-path 'tramp-own-remote-path)) ;; Run server if: ;; - Our EUID is not 0 ;; - We are not logged in via SSH ;; - It is not already running (unless (equal (user-real-uid) 0) (unless (getenv "SSH_CONNECTION") (use-package server :defer 1 :init (setq server-use-tcp t server-port 51313 server-auth-key "phahw2ohVoh0oopheish7IVie9desh8aequeenei3uo8wahShe%thuadaeNa4ieh") :config (unless (server-running-p) (server-start)) ))) ;; Set garbage collection threshold to original value (setq gc-cons-threshold (car (get 'gc-cons-threshold 'standard-value))) (provide 'init) ;;; init.el ends here