;;; System (add-to-list 'load-path (expand-file-name "~/.emacs.d/site-lisp")) ;; Platform specific configuration (cond ((equal system-type 'darwin) (setenv "PATH" (concat (getenv "PATH") ":/usr/local/bin")) (setq exec-path (append exec-path '("/usr/local/bin"))) (setq dired-listing-switches "-al") (scroll-bar-mode -1) (global-set-key [home] 'move-beginning-of-line) (global-set-key [end] 'move-end-of-line)) ((or (equal system-type 'gnu/linux) (equal system-type 'gnu/kfreebsd)) (setq dired-listing-switches "-al --time-style=long-iso") (scroll-bar-mode (quote right)))) ;; Set basic emacs variables (setq-default gc-cons-threshold 100000000 backup-by-copying t backup-directory-alist `((".*" . ,temporary-file-directory)) auto-save-file-name-transforms `((".*" ,temporary-file-directory t)) scheme-program-name "mzscheme" browse-url-generic-program (executable-find "sensible-browser") browse-url-browser-function 'browse-url-generic) ;; Hide dired details by default for a shiner experience (add-hook 'dired-mode-hook (lambda () (dired-hide-details-mode))) ;;; Packages (require 'package) ;; (add-to-list 'package-archives '("stable.melpa" . "https://stable.melpa.org/packages/")) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) ;; (add-to-list 'package-archive-priorities '("stable.melpa" . 8)) ;; (add-to-list 'package-archive-priorities '("gnu" . 6)) ;; (add-to-list 'package-archive-priorities '("nongnu" . 2)) (unless (package-installed-p 'use-package) (progn (package-refresh-contents) (package-install 'use-package))) (setq use-package-always-ensure t) ;; (use-package ansi-color :commands compile :after (ivy) :config (counsel-mode)) (use-package counsel :after (ivy) :config (counsel-mode)) (use-package counsel-gtags :commands ggtags-mode) (use-package counsel-projectile :after (counsel projectile)) (use-package diff-hl) (use-package diminish) (use-package dpkg-dev-el :commands debian-changelog-mode) (use-package flyspell :commands flyspell-mode) (use-package flyspell-correct-ivy :after (flyspell ivy) :commands flyspell-mode) (use-package ggtags :commands ggtags-mode) (use-package git-gutter-fringe) (use-package glsl-mode :commands glsl-mode) (use-package ivy :config (ivy-mode)) (use-package json-mode :commands json-mode) ;; (use-package lsp-mode ;; :config ;; (progn ;; (setq lsp-clients-clangd-args '("-j=4" "-background-index" "-log=error")) ;; (lsp-register-client ;; (make-lsp-client :new-connection (lsp-tramp-connection "clangd") ;; :major-modes '(c-mode c++-mode) ;; :remote? t ;; :server-id 'clangd-remote)))) (use-package magit :commands magit-status :after (diff-hl) :bind ("C-c m" . magit-status) :config (define-key magit-mode-map (kbd "C-") nil)) (use-package markdown-mode :commands markdown-mode) (use-package meson-mode :commands meson-mode) (use-package pdf-tools :magic ("%PDF" . pdf-view-mode) :config (pdf-tools-install)) (use-package prettier :commands prettier-prettify) (use-package projectile :config (projectile-mode)) (use-package quack :commands scheme-mode) (use-package rainbow-delimiters :commands prog-mode) (use-package spaceline) (use-package swiper :commands swiper) (use-package tramp) (use-package yaml-mode :commands yaml-mode) (require 'spaceline-config) (require 'turtle-mode "turtle-mode/turtle-mode.el") ;;; Basic editor and modeline configuration (defalias 'yes-or-no-p 'y-or-n-p) (setq-default tab-width 4) (setq-default indent-tabs-mode nil) (setq-default scroll-margin 3) (spaceline-toggle-buffer-size-off) (spaceline-toggle-hud-off) (spaceline-toggle-buffer-encoding-abbrev-off) (diminish 'abbrev-mode "") (diminish 'auto-fill-function "↵") (diminish 'auto-revert-mode "↻") (diminish 'compilation-in-progress "⚙") (diminish 'counsel-mode "") (diminish 'flyspell-mode "✓") (diminish 'ggtags-mode "☚") (diminish 'eldoc-mode "?") (diminish 'ivy-mode "") (setq spaceline-minor-modes-separator " ") (spaceline-define-segment version-control "Version control information." (when vc-mode (powerline-raw (s-trim (concat vc-mode (when (buffer-file-name) (pcase (vc-state (buffer-file-name)) (`up-to-date " ") (`edited " *") (`added " +") (`unregistered " ?") (`removed " -") (`needs-merge " !") (`needs-update " ^") (`ignored " I") (_ " ?")))))))) (spaceline-define-segment buffer-position "Buffer position in percent" (format "%3d%%%% " (/ (* 100 (- (line-number-at-pos) 1)) (max 1 (count-lines (point-min) (point-max)))))) (spaceline-define-segment line-column "The current line and column numbers." (if (eq major-mode 'pdf-view-mode) ;; Show page number and count for PDF documents (concat (number-to-string (pdf-view-current-page)) "/" (number-to-string (pdf-cache-number-of-pages))) mode-line-position "%l :%2c")) (add-hook 'magit-pre-refresh-hook 'diff-hl-magit-pre-refresh) (add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh) ;; Always try to open files in smerge mode if they seem to have conflicts (defun smerge-try-smerge () (save-excursion (goto-char (point-min)) (when (re-search-forward "^<<<<<<< " nil t) (require 'smerge-mode) (smerge-mode 1)))) (add-hook 'find-file-hook 'smerge-try-smerge t) (add-hook 'after-revert-hook 'smerge-try-smerge t) ;;; Variables (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. '(Man-switches "--nj") '(auth-source-save-behavior nil) '(auto-revert-interval 1) '(backup-by-copying t) '(backup-directory-alist `((".*" \, temporary-file-directory))) '(browse-url-browser-function 'browse-url-firefox) '(browse-url-firefox-new-window-is-tab t) '(browse-url-generic-program "firefox") '(column-number-mode t) '(compilation-error-screen-columns nil) '(compilation-scroll-output t) '(css-indent-offset 2) '(cursor-in-non-selected-windows 'hollow) '(custom-enabled-themes '(drobillized)) '(custom-safe-themes '("6882409e05d462b9dd7cc649c30f9b5784e20d3728fbeab13f3f7a7c31e81023" default)) '(delete-old-versions t) '(delete-selection-mode t) '(dired-omit-files "^\\.?#\\|^\\.$\\|^\\.\\.\\|^\\..*$") '(diredp-hide-details-initially-flag t) '(diredp-wrap-around-flag nil) '(erc-autojoin-channels-alist '((".*\\.oftc.net" "#mesonbuild") (".*\\.libera.chat" "#ardour-dev" "#ingen" "#lv2" "#lobsters"))) '(erc-autojoin-mode t) '(erc-insert-timestamp-function 'ks-timestamp t) '(erc-join-buffer 'bury) '(erc-log-channels-directory "~/.erc/logs") '(erc-log-insert-log-on-open t) '(erc-log-mode t) '(erc-mode-hook '(erc-munge-invisibility-spec erc-move-to-prompt-setup pcomplete-erc-setup erc-button-setup erc-imenu-setup toggle-word-wrap)) '(erc-mode-line-format "%t") '(erc-modules '(autojoin button completion irccontrols list log match menu move-to-prompt netsplit networks noncommands readonly ring stamp track)) '(erc-nick-uniquifier "") '(erc-prompt ">") '(erc-server "irc.libera.chat") '(erc-track-exclude-server-buffer t) '(erc-track-exclude-types '("JOIN" "NICK" "PART" "QUIT" "MODE" "333" "353" "324" "329" "332" "477")) '(erc-try-new-nick-p nil) '(fill-column 79) '(font-lock-maximum-decoration t) '(frame-background-mode 'dark) '(frame-inhibit-implied-resize t) '(fringe-mode '(nil . 0) nil (fringe)) '(gc-cons-threshold 10000000) '(global-diff-hl-mode t) '(global-git-gutter-mode t) '(grep-find-command "find . -type f -not -name \"*.svn-base\" -print0 | xargs -0 grep -I -n -s -F ") '(indicate-empty-lines t) '(inhibit-startup-screen t) '(initial-major-mode 'fundamental-mode) '(ivy-magic-tilde nil) '(jabber-account-list '(("david.e.robillard@gmail.com" (:network-server . "talk.google.com") (:port . 5223) (:connection-type . ssl)))) '(jabber-chat-buffer-show-avatar nil) '(js-indent-level 2) '(jshint-mode-node-program "nodejs") '(latex-run-command "pdflatex") '(magit-auto-revert-mode nil) '(magit-commit-show-diff nil) '(magit-diff-refine-hunk 'all) '(menu-bar-mode nil) '(ns-use-srgb-colorspace nil) '(package-selected-packages '(debian-el dpkg-dev-el scss-mode typescript-mode prettier vue-mode python-black quack vterm ace-window cython-mode groovy-mode jenkins qml-mode ninja-mode bison-mode csv-mode apache-mode auctex clang-format cmake-mode counsel-gtags counsel-projectile diff-hl diminish dired-rainbow dockerfile-mode flyspell-correct-ivy ggtags git-gutter-fringe glsl-mode ivy jinja2-mode json-mode magit markdown-mode meson-mode n3-mode pdf-tools pkgbuild-mode projectile rainbow-delimiters rust-mode spaceline swift-mode ttl-mode use-package yaml-mode)) '(pdf-view-midnight-colors '("#C3D1D1" . "#141414")) '(powerline-default-separator nil) '(projectile-completion-system 'ivy) '(projectile-enable-caching t) '(projectile-mode-line-function (lambda nil (format "%s%s" projectile-mode-line-prefix (or (projectile-project-name) "-")))) '(projectile-mode-line-prefix "") '(projectile-use-git-grep t) '(python-black-extra-args '("-l 79")) '(quack-pretty-lambda-p t) '(quack-run-scheme-always-prompts-p t) '(savehist-mode t) '(scroll-bar-mode nil) '(scroll-conservatively 5) '(send-mail-function 'sendmail-send-it) '(show-paren-mode t) '(speedbar-use-images nil) '(split-window-preferred-function 'split-window-horizontally) '(tool-bar-mode nil) '(ttl-electric-punctuation t) '(typescript-indent-level 2) '(version-control t) '(visible-bell nil) '(window-divider-default-bottom-width 1) '(window-divider-default-right-width 1) '(window-divider-mode t)) (if (eq system-type 'windows-nt) (setq diff-command "C:/Program Files/Git/usr/bin/diff.exe")) (setq ring-bell-function (lambda () (let ((orig-fg (face-foreground 'mode-line))) (set-face-foreground 'mode-line "#F2804F") (run-with-idle-timer 0.1 nil (lambda (fg) (set-face-foreground 'mode-line fg)) orig-fg)))) ;;; Colours (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. '(default ((t (:background "#141414" :foreground "#C3D1D1" :height 140 :family "DejaVu Sans Mono"))))) ;;; Windows (defun compile-autoclose (buffer string) "Close compilation window on success" (cond ((and (string-match "compilation" (buffer-name buffer)) (string-match "finished" string)) (bury-buffer "*compilation*") (message "Build successful.")) (t (message "Compilation exited abnormally: %s" string)))) (defun rotate-windows () "Rotate windows" (interactive) (if (> (count-windows) 1) (let ((i 0) (num-windows (count-windows))) (while (< i (- num-windows 1)) (let* ((w1 (elt (window-list) i)) (w2 (elt (window-list) (% (+ i 1) num-windows))) (b1 (window-buffer w1)) (b2 (window-buffer w2)) (s1 (window-start w1)) (s2 (window-start w2))) (set-window-buffer w1 b2) (set-window-buffer w2 b1) (set-window-start w1 s2) (set-window-start w2 s1) (setq i (+ i 1))))))) (setq split-height-threshold nil) (setq split-width-threshold 0) (add-hook 'compilation-finish-functions #'compile-autoclose) ;; Remove slow Maven regexp that makes the compilation buffer clunky (setq compilation-error-regexp-alist (delete 'maven compilation-error-regexp-alist)) ;; Add matcher for glibc assertion failures (add-to-list 'compilation-error-regexp-alist '("[[:print:]]+: \\([^:]+\\):\\([[:digit:]]+\\):.*Assertion.* failed.\n$" 1 2)) ;;; Key bindings (windmove-default-keybindings) (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map) (global-set-key (kbd "C-") 'previous-buffer) (global-set-key (kbd "C-") 'next-buffer) (global-set-key (kbd "C-") 'next-window-any-frame) (global-set-key (kbd "C-") 'previous-window-any-frame) (global-set-key (kbd "C-b") 'compile) (global-set-key (kbd "C-m") 'newline-and-indent) (global-set-key (kbd "C-n") 'next-error) (global-set-key (kbd "C-p") 'previous-error) (global-set-key (kbd "C-s") 'swiper) (global-set-key (kbd "C-c <") 'first-error) (global-set-key (kbd "C-c =") 'set-variable) (global-set-key (kbd "C-c I") 'clang-format-region) (global-set-key (kbd "C-c P") 'prettier-prettify) (global-set-key (kbd "C-c R") 'replace-regexp) (global-set-key (kbd "C-c a") 'align) (global-set-key (kbd "C-c b") 'magit-blame) (global-set-key (kbd "C-c c") 'comment-region) (global-set-key (kbd "C-c d") 'svn-status-show-svn-diff) (global-set-key (kbd "C-c e") 'erc-track-switch-buffer) (global-set-key (kbd "C-c f") 'ff-find-other-file) (global-set-key (kbd "C-c g") 'grep-find) (global-set-key (kbd "C-c h") 'mark-defun) (global-set-key (kbd "C-c i") 'clang-format-buffer) (global-set-key (kbd "C-c m") 'magit-status) (global-set-key (kbd "C-c o") 'ace-window) (global-set-key (kbd "C-c r") 'replace-string) (global-set-key (kbd "C-c s") 'sort-lines) (global-set-key (kbd "C-c t") 'toggle-truncate-lines) (global-set-key (kbd "C-c u") 'uncomment-region) (global-set-key (kbd "C-c w") 'rotate-windows) (global-set-key (kbd "C-c SPC") 'set-mark-command) ;;; File modes (add-hook 'prog-mode-hook #'rainbow-delimiters-mode) ;; C/C++ (defconst my-c-style '((c-block-comment-prefix . " ") (c-comment-only-line-offset . 0) (c-auto-align-backslashes . nil) (c-label-minimum-indentation . 0) (c-hungry-delete-key . t) (c-indent-comments-syntactically-p . nil) (c-hanging-braces-alist . ((brace-list-open after) (defun-open after) (defun-close before after) (class-open after) (class-close before after) (namespace-open after) (inline-open after) (inline-close before after) (block-open after) (block-close . c-snug-do-while) (extern-lang-open after) (extern-lang-close after) (statement-case-open after) (substatement-open after))) (c-hanging-colons-alist . ((case-label) (label after) (access-label after) (member-init-intro before) (inher-intro))) (c-hanging-semi&comma-criteria . (c-semi&comma-no-newlines-for-oneline-inliners c-semi&comma-inside-parenlist c-semi&comma-no-newlines-before-nonblanks)) (c-cleanup-list . (brace-catch-brace brace-else-brace brace-elseif-brace compact-empty-funcall defun-close-semi empty-defun-braces list-close-comma one-liner-defun scope-operator)) (c-offsets-alist . ((func-decl-cont . ++) (member-init-intro . +) (inher-intro . ++) (comment-intro . 0) (arglist-close . c-lineup-arglist) (topmost-intro . 0) (block-open . 0) (inline-open . 0) (substatement-open . 0) (label . /) (case-label . 0) (statement-case-open . +) (statement-case-intro . +) (access-label . -) (innamespace . 0) (inextern-lang . 0) (extern-lang-open . 0) (label . -))))) (c-add-style "drobilla" my-c-style) (defun my-c-mode-common-hook () "C mode for people with taste." (auto-fill-mode 1) (abbrev-mode -1) (set-fill-column 79) (setq tab-width 4) (setq indent-tabs-mode t) (setq truncate-lines t) (setq show-trailing-whitespace t) (c-set-style "drobilla")) (add-hook 'c-mode-common-hook 'my-c-mode-common-hook) (add-hook 'c++-mode-common-hook 'my-c-mode-common-hook) ;;; Code formatting (use-package clang-format :after (s) :commands (clang-format-buffer clang-format-region) :hook (c-mode-common . clang-format-c-mode-hook)) (defun get-clang-format-option (config-str field is-num) "Retrieve a config option from a clang-format config." (cond (is-num (let ((primary-match (s-match (concat "^" field ":[ \t]*[0-9]+") config-str))) (if primary-match (string-to-number (car (s-match "[0-9]+" (car primary-match)))) 0))) (t (let ((primary-match (s-match (concat "^" field ":[ \t]*[A-Za-z]+") config-str))) (if primary-match (car (s-match "[A-Za-z]+$" (car primary-match))) ""))))) (defun clang-format-c-mode-hook () "Load C family configuration from clang-format configuration." (let* ((clang-format-config (shell-command-to-string "clang-format -dump-config")) (c-offset (get-clang-format-option clang-format-config "IndentWidth" t)) (tabs-str (get-clang-format-option clang-format-config "UseTab" nil)) (base-style (get-clang-format-option clang-format-config "BasedOnStyle" nil))) (progn (if (> c-offset 0) (setq-local c-basic-offset c-offset) (if (not (equal "" base-style)) (cond ((or (equal "LLVM" base-style) (equal "Google" base-style) (equal "Chromium" base-style) (equal "Mozilla" base-style)) (setq-local c-basic-offset 2)) ((equal "WebKit" base-style) (setq-local c-basic-offset 4))))) (if (not (equal "" tabs-str)) (if (not (string-equal "Never" tabs-str)) (setq-local indent-tabs-mode t) (setq-local indent-tabs-mode nil)) (if (not (equal "" base-style)) (cond ((or (equal "LLVM" base-style) (equal "Google" base-style) (equal "Chromium" base-style) (equal "Mozilla" base-style) (equal "WebKit" base-style)) (setq-local indent-tabs-mode nil)))))))) ;; Python (add-hook 'python-mode-hook (lambda () (setq tab-width 4) (setq indent-tabs-mode nil) (setq show-trailing-whitespace t))) ;; Turtle (add-hook 'turtle-mode-hook (lambda () (setq tab-width 4) (setq indent-tabs-mode t) (setq show-trailing-whitespace t))) ;; Dired (add-hook 'dired-mode-hook (lambda () (dired-hide-details-mode))) ;; IRC (make-variable-buffer-local (defvar erc-last-datestamp nil)) ;; Show minute timestamps on the left and a date header when they change (defun ks-timestamp (string) (erc-insert-timestamp-left string) (let ((datestamp (erc-format-timestamp (current-time) erc-datestamp-format))) (unless (string= datestamp erc-last-datestamp) (erc-insert-timestamp-left datestamp) (setq erc-last-datestamp datestamp)))) (setq erc-datestamp-format "[%Y-%m-%d %a]\n" erc-insert-timestamp-function 'ks-timestamp) ;; PDF (defun my-doc-view-hook () (auto-revert-mode) (blink-cursor-mode -1)) (add-hook 'doc-view-mode-hook 'my-doc-view-hook) (add-hook 'pdf-view-mode-hook 'my-doc-view-hook) ;; Shell (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on) (add-to-list 'comint-output-filter-functions 'ansi-color-process-output) ;; Compilation (defun colorize-compilation-buffer () (let ((inhibit-read-only t)) (ansi-color-apply-on-region (point-min) (point-max)))) ;; (add-hook 'compilation-filter-hook 'colorize-compilation-buffer) ;; Associations (add-to-list 'auto-mode-alist '("\\.ipp\\'" . c++-mode)) (add-to-list 'auto-mode-alist '("\\.pl\\'" . prolog-mode)) (add-to-list 'auto-mode-alist '("\\.n3\\'" . turtle-mode)) (add-to-list 'auto-mode-alist '("\\.ttl\\'" . turtle-mode)) (add-to-list 'auto-mode-alist '("\\.owl\\'" . turtle-mode)) (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode)) (add-to-list 'auto-mode-alist '("\\.pdf\\'" . pdf-view-mode)) (add-to-list 'auto-mode-alist '("\\.gyp\\'" . python-mode)) (add-to-list 'auto-mode-alist '("\\.gypi\\'" . python-mode)) (add-to-list 'auto-mode-alist '("\\.jsonld\\'" . json-mode)) (add-to-list 'auto-mode-alist '("\\.tesc\\'" . glsl-mode)) (add-to-list 'auto-mode-alist '("\\.tese\\'" . glsl-mode)) (add-to-list 'auto-mode-alist '("\\.m\\'" . objc-mode)) (add-to-list 'auto-mode-alist '("\\.mm\\'" . objc-mode)) (add-to-list 'auto-mode-alist '("\\.mjs\\'" . javascript-mode)) (add-to-list 'auto-mode-alist '("\\.mts\\'" . typescript-mode)) (add-to-list 'auto-mode-alist '("\\.ipp\\'" . c++-mode)) (add-to-list 'auto-mode-alist '("\\.clang-format\\'" . yaml-mode)) (add-to-list 'auto-mode-alist '("\\.clang-tidy\\'" . yaml-mode)) (add-to-list 'auto-mode-alist '("\\NEWS" . debian-changelog-mode)) ;;; Launch (spaceline-spacemacs-theme) (server-start)