;; Global configuration:
;; don't do the startup stuff
(setq initial-scratch-message "")
(setq inhibit-startup-message t)
(setq inhibit-startup-screen t)
;; don't show the menu bar
(menu-bar-mode 0)
(if (display-graphic-p)
(progn
(scroll-bar-mode 0)
(tool-bar-mode 0)))
;; set up sizing in a reasonable way
(setq column-number-mode t)
(setq default-tab-width 4)
(setq-default indent-tabs-mode nil)
(set-fill-column 120)
;; miscellaneous global config
(setq vc-follow-symlinks t)
(setq vc-handled-backends nil)
(setq require-final-newline t)
;; change backups to be less inline
(make-directory "~/.emacs-autosave" t)
(make-directory "~/.emacs-backups" t)
(setq auto-save-file-name-transforms '((".*" "~/.emacs-autosave/" t)))
(setq backup-directory-alist '(("." . "~/.emacs-backups")))
;; some disables
(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)
(put 'narrow-to-region 'disabled nil)
;; *elpa and package setup
(require 'package)
(package-initialize)
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/") t)
(add-to-list 'package-archives
'("gelpa" . "http://gelpa.gdritter.com/") t)
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(if (getenv "FORCE_REFRESH")
(package-refresh-contents))
(require 'use-package)
;; Text editing: Markdown, org, et cetera
;; associate markdown with more stuff
(use-package markdown-mode
:ensure t
:init
(progn
(add-to-list 'auto-mode-alist '("\\.text\\'" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
(add-hook 'markdown-mode-hook 'visual-line-mode)))
(add-hook 'rst-mode-hook 'visual-line-mode)
;; also pandoc specifically
(use-package pandoc-mode
:ensure t
:config (add-hook 'markdown-mode-hook 'pandoc-mode))
;; Evil, just in case:
(use-package evil :ensure t)
;; olivetti mode (for editing single prose files)
(use-package olivetti
:ensure t)
;; Org-mode
(use-package org
:ensure t
:init (add-hook 'org-mode-hook 'visual-line-mode))
;; Letting us easily move in outlines
(defun gdritter/add-meta-bindings ()
(let ((map outline-minor-mode-map))
(define-key map (kbd "M-<up>") 'outline-previous-visible-heading)
(define-key map (kbd "M-<down>") 'outline-next-visible-heading)))
(add-hook 'outline-minor-mode-hook 'gdritter/add-meta-bindings)
;; TeLML
(use-package telml-mode
:ensure t
:init
(add-hook 'telml-mode-hook 'visual-line-mode))
;; display Github-like emoji if we're in a text-editing mode of some kind
(defun gdritter/enable-emoji-hook ()
(if (member major-mode '(markdown-mode pandoc-mode text-mode telml-mode))
(emojify-mode)))
(use-package emojify
:ensure t
:init (add-hook 'after-change-major-mode-hook
'gdritter/enable-emoji-hook))
(use-package whitespace
:ensure t
:init
(progn
(setq whitespace-style '(face empty tabs trailing))
(global-whitespace-mode t)))
(use-package undo-tree :ensure t)
;; Special logic for handling Pandoc front-matter
;; Pandoc can begin with YAML metadata, and sometimes a pandoc file
;; will indicate which format it should be using. I'm not going to
;; write a full YAML parser in elisp! But usually, parsing simple
;; key-value pairs should be sufficient.
(defun gdritter/pandoc-parse-basic-meta-block ()
(let ((here (point)))
(goto-char 0)
(let ((rs
(if (re-search-forward "^---\n" nil t)
(let ((block-start (point)))
(if (re-search-forward "^\\(---\\|...\\)\n" nil t)
(progn (goto-char block-start)
(gdritter/pandoc-parse-kv-section))
(progn (message "no metadata block found")
nil))))))
(goto-char here)
rs)))
;; This tries to parse all the simple key: value forms it can
(defun gdritter/pandoc-parse-kv-section ()
(if (looking-at "^\\(---\\|...\\)\n")
'()
(let ((rs (re-search-forward "^\\([A-Za-z0-9_]+\\):[ ]*\\(.*\\)\n" nil t)))
(if rs
(cons (cons (match-string 1)
(match-string 2))
(gdritter/pandoc-parse-kv-section))
(forward-line 1)))))
;; This will try to dispatch which mode to open based on the
;; metadata block. If the metadata block doesn't contain a format
;; key, then it'll default to Markdown with Pandoc extensions.
(defun gdritter/pandoc-choose-mode ()
(interactive)
(let* ((meta (gdritter/pandoc-parse-basic-meta-block))
(format (assoc-string "format" meta))
(fmt (if format (cdr format) nil)))
(cond ((equal fmt "org") (org-mode))
((equal fmt "latex") (latex-mode))
((equal fmt "rst") (rst-mode))
((equal fmt "html") (web-mode))
(t (markdown-mode)))))
(add-to-list 'auto-mode-alist '("\\.page\\'" . gdritter/pandoc-choose-mode))
(add-to-list 'auto-mode-alist '("\\.pandoc\\'" . gdritter/pandoc-choose-mode))
;; magit!
(use-package magit
:ensure t
:defer t
:init (progn
(setq magit-last-seen-setup-instructions "1.4.0")))
;; LSP and dev environment stuff
(use-package eglot
:ensure t
:config
(progn
(add-hook 'c++-mode-hook 'eglot-ensure)
(add-hook 'rust-mode-hook 'eglot-ensure)
(add-hook 'python-mode-hook 'eglot-ensure)
(add-hook 'go-mode-hook 'eglot-ensure)
(add-hook 'ruby-mode-hook 'eglot-ensure)
(add-hook 'before-save-hook 'eglot-format)
(add-to-list
'eglot-server-programs
'(ruby-mode . ("rass" "sorbet_rubocop")))))
(use-package breadcrumb :ensure t)
(breadcrumb-mode)
(use-package yasnippet
:ensure t
:config (yas-global-mode 1))
(use-package dirvish
:ensure t
:config (dirvish-override-dired-mode))
;; for C and C++
(defconst gdritter/cc-style
'("cc-mode" (c-offsets-alist . ((innamespace . [0])))))
(c-add-style "gdritter/cc-style" gdritter/cc-style)
(setq c-default-style "gdritter/cc-style" c-basic-offset 4)
(c-set-offset 'substatement-open 0)
;; for web (HTML, JavaScript, TypeScript CSS)
(use-package web-mode
:ensure t
:init (progn
(mapcar (lambda (extension)
(add-to-list 'auto-mode-alist
`(,extension . web-mode)))
'("\\.html?\\'"
"\\.tpl\\.php\\'"
"\\.[agj]sp\\'"
"\\.as[cp]x\\'"
"\\.erb\\'"
"\\.mustache\\'"
"\\.djhtml\\'"))
(setq web-mode-markup-indent-offset 2)
(setq web-mode-css-indent-offset 2)
(setq web-mode-code-indent-offset 2)
(setq web-mode-attr-indent-offset 2)))
(use-package rjsx-mode :ensure t)
(setq js2-basic-offset 2)
(use-package typescript-mode
:ensure t
:init (add-to-list 'auto-mode-alist '("\\.tsx\\'" . typescript-mode)))
(setq-default typescript-indent-level 2)
;; for Ruby
(use-package ruby-mode :ensure t)
(add-to-list 'auto-mode-alist '("\\.rbi\\'" . ruby-mode))
(setq ruby-deep-indent-param nil)
(setq ruby-insert-encoding-magic-comment nil)
;; for Go
(use-package go-mode :ensure t)
(setq gofmt-command "goimports")
(add-hook 'before-save-hook 'gofmt-before-save)
;; for Rust
(use-package rust-mode
:ensure t
:init (setq rust-format-on-save t))
(use-package company
:ensure t)
(use-package cargo
:ensure t
:init (add-hook 'rust-mode-hook #'cargo-minor-mode))
(use-package flycheck-rust
:ensure t
:init (add-hook 'flycheck-mode-hook #'flycheck-rust-setup))
;; for Haskell
(use-package haskell-mode
:ensure t
:init
(progn
(setq haskell-mode-hook 'turn-on-haskell-simple-indent)
(add-to-list 'Info-default-directory-list "/usr/lib/emacs/haskell-mode/")
(setq haskell-mode-hook '(turn-on-haskell-indentation))
(add-hook 'haskell-mode-hook 'outline-minor-mode)
(setq outline-regexp "-- \\*+")))
(use-package dante
:ensure t
:commands 'dante-mode
:init
(add-hook 'haskell-mode-hook 'dante-mode)
(add-hook 'haskell-mode-hook 'flycheck-mode))
;; A slew of miscellaneous lesser-used modes
;; for redo syntax highlighting
(add-to-list 'auto-mode-alist '("\\.do\\'" . sh-mode))
;; for void linux template file highlighting
(add-to-list 'auto-mode-alist '("\\template\\'" . sh-mode))
;; for build-ish formats
(use-package dockerfile-mode :ensure t :defer t)
(use-package meson-mode :ensure t :defer t)
(use-package bazel
:ensure t
:init (add-to-list 'auto-mode-alist '("\\.sky\\'" . bazel-mode)))
;; for miscellaneous programming languages
(use-package lua-mode :ensure t :defer t :init (setq lua-indent-level 2))
(use-package fennel-mode :ensure t)
(use-package scala-mode :ensure t)
(use-package glsl-mode :ensure t :defer t)
(use-package ponylang-mode :ensure t :defer t)
(use-package tuareg :ensure t :defer t)
(use-package dash :ensure t)
(use-package dash-functional :ensure t)
;; various data format modes
(use-package toml-mode
:ensure t)
(use-package yaml-mode
:ensure t)
(use-package adnot-mode
:ensure t)
(use-package electric-boogaloo-mode
:ensure t)
;; for completions
(use-package ivy
:ensure t
:init (progn
(setq ivy-height-alist
(cons
(cons 't (lambda (_) (/ (frame-height) 2)))
'()))
(setq ivy-use-virtual-buffers t)))
(use-package counsel
:ensure t
:init (progn
(global-set-key (kbd "C-x C-f") #'counsel-find-file)
(global-set-key (kbd "C-x C-b") #'ivy-switch-buffer)
(with-eval-after-load 'counsel
(define-key counsel-find-file-map (kbd "C-l") #'counsel-up-directory))))
;; fonts, colors, and ligatures
(defvar *gdritter-ligature-list*
'(
;; equality operators
"==" "===" "!=" "!=="
;; comparison operators
"<=" ">=" "<=>"
;; scope
"::" ":::"
;; right arrows
"->" "-->" "=>" "==>"
;; left arrows
"<-" "<--" "<=" "<=="
;; various operators
"++" "--" "&&" "||" "&&=" "||=" "=~" ":="
;; shift operators
"<<" "<<<" ">>" ">>>"
;; comment syntaxes
"//" "///" "/*" "*/"
;; some haskell nonsense
"<>" ">>=" "=<<" ">=>" "<=<" "=>" "=<="
"<$" "<$>" "$>" "<+" "<+>" "+>" "<*" "<*>" "*>"
"<|>"
))
(when (display-graphic-p)
;; color theming
(use-package color-theme-modern
:ensure t
:init
(progn
(use-package zenburn-theme :ensure t)
(use-package solarized-theme :ensure t)
(use-package color-theme-sanityinc-tomorrow :ensure t)
(let ((theme (getenv "THEME")))
(cond
((string= theme "solarized-dark")
(load-theme 'solarized-dark t))
((string= theme "solarized-light")
(load-theme 'solarized-light t))
((string= theme "tomorrow")
(load-theme 'sanityinc-tomorrow-night t))
(t (load-theme 'zenburn t))))))
;; ligatures
(use-package ligature
:ensure t
:init
(progn
(ligature-set-ligatures 't *gdritter-ligature-list*)
(global-ligature-mode 't))))
;; spacing fixes!
(defun fix-spacing ()
(let ((here (point)))
(interactive)
(untabify (point-min) (point-max))
(replace-regexp "\s*$" "")
(goto-char here)
(princ "Fixing all spacing...")))
(setq gdritter/spacing-modes
'(scala-mode
c++-mode
asm-mode
haskell-mode
haskell-cabal-mode
emacs-lisp-mode
lisp-mode
scheme-mode
d-mode
erlang-mode
tuareg-mode))
(defun fix-spacing-hook ()
(when (member major-mode gdritter/spacing-modes)
(fix-spacing)))
(defun gdritter/change-whitespace-mode-hook ()
(if (member major-mode '(c-mode c++-mode go-mode org-mode))
(progn (setq whitespace-style '(face))
(global-whitespace-mode t))))
(add-hook 'before-save-hook 'fix-spacing-hook)
(add-hook 'after-change-major-mode-hook
'gdritter/change-whitespace-mode-hook)
;; some environment variable directives
(if (getenv "EVIL") (evil-mode))
;; Any machine-specific setup can go in an external
;; file. If it exists, we should load it:
(if (file-exists-p "~/.local.el")
(load "~/.local.el"))
;; The custom-set-variables stuff
(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.
'(package-selected-packages nil))
(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 (:family "Fira Code" :foundry "unknown" :slant normal :weight normal :height 120 :width normal))))
'(lsp-ui-doc-background ((t (:background "black"))))
'(lsp-ui-sideline-current-symbol ((t (:foreground "white" :weight ultra-bold :height 0.99)))))