;;; Emacs Config ;;;; indentation (setq sgml-basic-offset 4 standard-indent 2) (setq-default tab-width 4 indent-tabs-mode nil) (add-hook 'sh-mode-hook (lambda () (setq tab-width 4))) ;;;; various options (setq read-file-name-completion-ignore-case t inhibit-startup-screen t vc-follow-symlinks t custom-file (expand-file-name "~/.emacs.d/custom.el") gc-cons-threshold 100000000) (load-theme 'fred t) (savehist-mode 1) (show-paren-mode 1) (column-number-mode 1) (when (fboundp 'tool-bar-mode) (tool-bar-mode -1)) ;;;; not sure where to put this (defun open-thunar-in-current-directory () (interactive) (call-process "thunar" nil 0 nil ".")) ;;;; enable disabled functions (put 'upcase-region 'disabled nil) (put 'downcase-region 'disabled nil) (put 'narrow-to-region 'disabled nil) ;;;; save backups and autosaves in tmp (setq backup-directory-alist `((".*" . ,temporary-file-directory)) auto-save-file-name-transforms `((".*" ,temporary-file-directory t))) ;;; Packages ;;;; install/load quelpa (require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) (package-initialize) (setq quelpa-update-melpa-p nil) (unless (require 'quelpa nil t) (with-temp-buffer (url-insert-file-contents "https://raw.github.com/quelpa/quelpa/master/bootstrap.el") (eval-buffer))) ;;;; install quelpa-use-package (quelpa 'quelpa-use-package) (require 'quelpa-use-package) ;;;; internal packages (use-package ibuffer :bind ("C-x C-b" . ibuffer) :config (setq ibuffer-saved-filter-groups (quote (("default" ("emacs" (or (name . "^\\*scratch\\*$") (name . "^\\*Messages\\*$"))))))) (add-hook 'ibuffer-mode-hook (lambda () (ibuffer-auto-mode 1) (setq ibuffer-show-empty-filter-groups nil)))) (use-package compile :commands (compile recompile) :bind (("C-z" . recompile) ("C-S-z" . compile)) :config (setq compilation-scroll-output 'first-error) (require 'ansi-color) (add-hook 'compilation-filter-hook (lambda () (toggle-read-only 0) (ansi-color-apply-on-region compilation-filter-start (point)) (toggle-read-only 1))) (add-hook 'compilation-start-hook (lambda (x) (setq-local scroll-up-aggressively 0.0)))) (use-package verilog-mode :defer :config (setq verilog-indent-level 4 verilog-indent-level-behavioral 4 verilog-indent-level-declaration 4 verilog-indent-level-module 4 verilog-auto-newline nil verilog-linter "verilator --lint-only") (add-hook 'verilog-mode-hook (lambda () (setq indent-tabs-mode nil))) (add-to-list 'company-keywords-alist (cons 'verilog-mode verilog-keywords))) (use-package python :defer :config (when (executable-find "ipython") (setq python-shell-interpreter "ipython") (setq python-shell-interpreter-args "-i --simple-prompt") (add-to-list 'python-shell-completion-native-disabled-interpreters "ipython"))) (use-package tramp :bind ("C-c C-f" . find-file-as-root) :config (add-to-list 'tramp-remote-path 'tramp-own-remote-path) (add-to-list 'tramp-remote-path '"/home/adam/asgoldsmith/install/bin/") (setq tramp-default-method "ssh") (defun find-file-as-root () (interactive) (find-alternate-file (concat "/sudo::" (buffer-file-name))))) (use-package comint :config (setq-default comint-scroll-to-bottom-on-input t ; always insert at the bottom comint-scroll-to-bottom-on-output nil ; always add output at the bottom comint-scroll-show-maximum-output t ; scroll to show max possible output ;; comint-completion-autolist t ; show completion list when ambiguous comint-input-ignoredups t ; no duplicates in command history comint-completion-addsuffix t ; insert space/slash after file completion comint-buffer-maximum-size 20000 ; max length of the buffer in lines comint-get-old-input (lambda () "") ; what to run when i press enter on a ; line above the current prompt comint-input-ring-size 500) ; max shell history size (add-hook 'comint-mode-hook '(lambda () (setq-local show-trailing-whitespace nil)))) (use-package semantic :defer :hook (c-mode . semantic-mode) :config (setq semantic-default-submodes '(global-semantic-idle-scheduler-mode global-semanticdb-minor-mode global-semantic-decoration-mode global-semantic-highlight-func-mode global-semantic-show-unmatched-syntax-mode global-semantic-idle-summary-mode global-semantic-stickyfunc-mode global-semantic-idle-local-symbol-highlight-mode) semantic-idle-scheduler-idle-time 0.2) ; inhibit semantic outside of specific modes (setq semantic-inhibit-functions #'(lambda () (not (member major-mode '(c-mode cc-mode java-mode))))) (eval-after-load "cc-mode" '(define-key c-mode-map (kbd "M-.") 'semantic-ia-fast-jump))) (use-package term :config (add-hook 'term-mode-hook '(lambda () (setq-local ;if this is t, it breaks shell-command comint-prompt-read-only nil)))) (use-package gud :config (add-hook 'gud-mode-hook '(lambda () (setq-local comint-prompt-read-only t)))) (use-package org :defer :bind ((:map org-mode-map ("C-z" . org-latex-export-to-pdf-no-kr)) (:map org-src-mode-map ("C-z" . org-src-export-to-pdf))) :config ;; Make windmove work in org-mode: (add-hook 'org-shiftup-final-hook 'windmove-up) (add-hook 'org-shiftleft-final-hook 'windmove-left) (add-hook 'org-shiftdown-final-hook 'windmove-down) (add-hook 'org-shiftright-final-hook 'windmove-right) ;; enable line wraping (add-hook 'org-mode-hook '(lambda () (setq truncate-lines nil word-wrap t))) (defun org-latex-open-pdf () (interactive) (call-process "evince" nil 0 nil (org-latex-export-to-pdf))) (defun org-latex-export-to-pdf-no-kr () (interactive) (org-latex-export-to-pdf) (pop kill-ring)) ; remove most recent element of kill ring (defun org-src-export-to-pdf () (interactive) (org-src-in-org-buffer (org-latex-export-to-pdf-no-kr))) (setq org-confirm-babel-evaluate nil) (org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t) (dot . t) (python . t))) (add-to-list 'org-src-lang-modes '("dot" . graphviz-dot)) (defun org-insert-homework-header () "" (interactive) (yas-expand-snippet (yas-lookup-snippet "Homework Header" 'org-mode)))) (use-package windmove :config (windmove-default-keybindings)) (use-package help-mode :config ; bind "g" to revert help buffers with no prompt (bind-key "g" (lambda () (interactive) (revert-buffer t t)) help-mode-map)) (use-package files :config ; bind a key to revert buffers with no prompt (bind-key "C-x M-v" (lambda () (interactive) (revert-buffer t t t)))) (use-package prog-mode :config (add-hook 'prog-mode-hook #'(lambda () (setq-local show-trailing-whitespace t)))) (use-package graphviz-dot-mode :config ; don't auto-newline on semicolon (defun electric-graphviz-dot-semi () "Terminate line and indent next line." (interactive) (insert ";") (when (and graphviz-dot-auto-indent-on-semi (not (graphviz-dot-comment-or-string-p))) (save-excursion (beginning-of-line) (skip-chars-forward " \t") (graphviz-dot-indent-line)) (delete-horizontal-space)))) (use-package frame :config (defun suspend-frame () "If running in a secondary tty, call `suspend-tty', else nop" (interactive) (when (eq (framep (selected-frame)) t) (suspend-tty)))) (use-package cc-styles :config (setq c-default-style "linux" c-basic-offset 4) (c-set-offset `inline-open 0)) (use-package antlr-mode :mode "\\.g4\\'") (use-package paragraphs :bind (("M-p" . backward-paragraph) ("M-n" . forward-paragraph))) ;;;; external packages (required) (use-package company :ensure :config (global-company-mode) (setq company-idle-delay 0.1 company-dabbrev-downcase nil company-dabbrev-ignore-case nil) (bind-key "" 'company-manual-begin)) (use-package smart-mode-line :ensure :config (setq sml/no-confirm-load-theme t) (sml/setup) (sml/apply-theme 'respectful) (setq sml/replacer-regexp-list '(("^~/\\.dotfiles/" ":dots:") ("^:dots:emacs/\\.emacs\\.d/" ":ED:") ("^~/Documents/" ":Doc:") ("^~/Programs/" ":Prog:") ("^:Doc:WPI/" ":WPI:") ("^/sshx:ccc:" ">ccc:") ("^>ccc:/home/asgoldsmith" ":>ccc:~")) rm-blacklist '(" company" " Undo-Tree" " ivy" " 80col"))) (use-package avy :ensure :config (eval-after-load "isearch" '(define-key isearch-mode-map (kbd "C-'") 'avy-isearch)) :bind (("C-;" . avy-goto-char) ("C-'" . avy-goto-char-2))) (use-package smex :ensure :bind ("M-X" . smex-major-mode-commands)) (use-package swiper :ensure :bind (("C-s" . swiper) ("C-r" . swiper) ("C-c C-r" . ivy-resume) :map swiper-map ("C-r" . ivy-previous-line-or-history) :map ivy-minibuffer-map ("C-'" . ivy-avy)) :init (bind-key "C-S-s" 'isearch-forward) (bind-key "C-S-r" 'isearch-backward) :config (ivy-mode 1) (defun ivy-backward-delete-char () "Forward to `backward-delete-char'. Do less dumb things with directories On error (read-only), call `ivy-on-del-error-function'." (interactive) (if (and ivy--directory (= (minibuffer-prompt-end) (point))) (progn (let ((old-dir (file-name-nondirectory (directory-file-name (expand-file-name ivy--directory))))) (ivy--cd (file-name-directory (directory-file-name (expand-file-name ivy--directory)))) (insert old-dir)) (ivy--exhibit)) (condition-case nil (backward-delete-char 1) (error (when ivy-on-del-error-function (funcall ivy-on-del-error-function))))))) (use-package ivy-hydra :ensure) (use-package counsel :ensure :bind (("M-x" . counsel-M-x) ("C-M-y" . counsel-yank-pop) ("C-x C-f" . counsel-find-file) :map counsel-find-file-map (("C-M-i" . counsel-find-file-edit-path) ("C-DEL" . ivy-backward-kill-word) ("C-" . ivy-backward-kill-word) ("M-DEL" . counsel-up-directory) ("M-" . counsel-up-directory))) :init (bind-key "C-c C-c M-x" 'execute-extended-command) ;;normal M-x. :config (setq ivy-extra-directories nil) (setq ivy-re-builders-alist '((counsel-M-x . ivy--regex-fuzzy) (t . ivy--regex-plus))) (assq-delete-all 'counsel-M-x ivy-initial-inputs-alist) (defun counsel-find-file-edit-path () "Edit the current path in ivy find-file" (interactive) (let ((old-path (substring (concat (expand-file-name ivy--directory) ivy-text) 1 -1))) (ivy--cd "/") (insert old-path)))) (use-package ace-window :ensure :bind ("M-S-p" . ace-window)) (use-package undo-tree :ensure :config (bind-key "M-/" 'undo-tree-visualize) (global-undo-tree-mode)) (use-package hydra :ensure :config ;config is in separate file because it is really big (load-file "~/.emacs.d/init-hydra.el") :bind (("C-c w" . 'hydra-window/body) ("C-c s" . 'hydra-shortcuts/body) ("C-c a" . 'hydra-avy/body) ("C-c c" . 'hydra-mc-manual/body)) :bind* ("C-," . 'hydra-mc/body)) ; I like my binding, stop messing with it (use-package multiple-cursors :ensure) (use-package expand-region :ensure :bind ("C-=" . er/expand-region)) (use-package company-quickhelp :ensure :disabled :config (company-quickhelp-mode 1) (setq company-quickhelp-delay 0.5)) (use-package magit :ensure :bind ("C-x g" . magit-status)) (use-package popwin :ensure :disabled :config (popwin-mode 1) (delete 'help-mode popwin:special-display-config) (add-to-list 'popwin:special-display-config '(help-mode :stick t))) (use-package cat-mode :quelpa (cat-mode :fetcher github :repo "ad1217/emacs-cat-mode") :config (cat-mode 1) (bind-key "C-x C-M-C" 'kill-this-cat-kill-terminal) (eval-after-load "ibuffer" '(define-key ibuffer-mode-map (kbd "c") 'cat-set-ibuffer))) (use-package dired+ :quelpa (dired+ :fetcher url :url "https://www.emacswiki.org/emacs/download/dired+.el") :defer :init (setq diredp-hide-details-initially-flag nil) :config (toggle-diredp-find-file-reuse-dir 1)) (use-package outline-magic :ensure :demand :bind (:map outline-minor-mode-map ("M-" . outline-cycle))) (use-package column-enforce-mode :ensure :config :hook prog-mode) (use-package show-marks :ensure :config :bind ("C-S-" . backward-mark) :bind ("C-S-" . forward-mark) :bind ("C-S-" . show-marks)) (use-package immortal-scratch :ensure :config (setq immortal-scratch-switch-to-respawned-scratch t) (immortal-scratch-mode t)) (use-package frames-only-mode :ensure :config (frames-only-mode t) (menu-bar-mode 0) (defun split-window-below-i3 () "It's like `split-window-below', but uses i3 stuff" (interactive) (call-process "i3" nil nil nil "split v") (make-frame)) (defun split-window-right-i3 () "It's like `split-window-below', but uses i3 stuff" (interactive) (call-process "i3" nil nil nil "split h") (make-frame)) (bind-key "C-x 2" 'split-window-below-i3) (bind-key "C-x 3" 'split-window-right-i3)) (use-package crux :ensure :bind (("C-a" . crux-move-beginning-of-line))) (use-package lsp-mode :ensure :config (use-package company-lsp :ensure :config (push 'company-lsp company-backends)) (use-package lsp-ui :ensure :config (setq lsp-ui-sideline-ignore-duplicate t) (add-hook 'lsp-mode-hook 'lsp-ui-mode)) (use-package lsp-python ;; requires python-language-server and/or python2-language-server :hook (python-mode . lsp-python-enable)) (use-package lsp-java ;; requires eclipse jdt language server ("jdtls" in arch) :hook (java-mode . lsp-java-enable)) (use-package lsp-javascript-typescript ;; Requires javascript-typescript-langserver installed locally :hook ((js-mode . lsp-javascript-typescript-enable) (typescript-mode . lsp-javascript-typescript-enable) (js3-mode . lsp-javascript-typescript-enable) (rjsx-mode . lsp-javascript-typescript-enable))) (use-package lsp-html ;; requires vscode-html-languageserver-bin :hook ((html-mode . lsp-html-enable) (web-mode . lsp-html-enable))) (use-package lsp-css ;; requires vscode-css-languageserver-bin :hook ((css-mode . lsp-css-enable)))) ;;;; optional external packages (use-package arduino-mode :mode "\\.pde\\'" :mode "\\.ino\\'") (use-package circe :config (setq circe-default-nick "ad1217" circe-reduce-lurker-spam t) (enable-circe-color-nicks) (setq circe-network-options '(("Freenode" :tls t :nick "ad1217" :sasl-username "ad1217" :sasl-password "ablablop" :channels ("#emacs-circe" "#qutebrowser" "#archlinux" "##linux")) ("WPI" :host "irc.wpiirc.net" :port 9999 :use-tls t)) circe-default-part-message "")) (use-package company-c-headers :config (add-to-list 'company-backends 'company-c-headers)) (use-package company-statistics :config (company-statistics-mode)) (use-package dtrt-indent :config (dtrt-indent-global-mode 1)) (use-package gnuplot-mode :mode ("\\.gp$" . gnuplot-mode)) (use-package markdown-mode :config (setq markdown-command "markdown_py -x markdown.extensions.wikilinks -x markdown.extensions.smarty -x markdown.extensions.extra -x latex -x markdown.extensions.sane_lists -x markdown.extensions.toc -x markdown_checklist.extension -c ~/.emacs.d/markdownConfig.yml" markdown-enable-math t) :bind (:map markdown-mode-map ("" . markdown-demote) ("S-" . markdown-promote)) :mode "\\.md\\'") (use-package projectile :config (projectile-global-mode) (setq projectile-mode-line '(:eval (if (file-remote-p default-directory) " P" (format " P[%s]" (projectile-project-name))))) :bind (:map projectile-mode-map ("C-S-z" . projectile-compile-project))) (use-package scad-mode :mode "\\.scad$" :config (defun scad-compile (ext) "Compile current buffer using 'scad-command' and the extention 'ext'" (interactive (list (completing-read "Extension: " '("stl" "off" "amf" "dxf" "svg" "csg" "png")))) (compile (concat scad-command " -o " (file-name-sans-extension buffer-file-name) "." ext " " buffer-file-name))) :bind (:map scad-mode-map ("C-c z" . scad-compile))) (use-package smart-tabs-mode :config (smart-tabs-insinuate 'c 'c++ 'javascript)) (use-package todotxt-mode :commands (todotxt-open-file todotxt-mode) :bind ("C-c t" . todotxt-open-file) :init (setq todotxt-base-path (expand-file-name "~/Documents/todo") todotxt-default-file (concat todotxt-base-path "/todo.txt") todotxt-default-archive-file (concat todotxt-base-path "/done.txt")) (add-to-list 'auto-mode-alist `(,(concat todotxt-base-path "/.*\\.txt$") . todotxt-mode)) :config (setq todotxt-due-tag "due" todotxt-mode-keywords '(("^x .*$" 0 '(:foreground "gray80" :strike-through t)) ("^(A) " 0 '(:foreground "red")) ("^(B) " 0 '(:foreground "orange")) ("^(C) " 0 '(:foreground "teal")) ("^(D) " 0 '(:foreground "light green")) ("^(Y) " 0 '(:foreground "light grey")) ("([A-Z]+)" . font-lock-builtin-face) ("\\([a-zA-Z0-9_-]+\\):\\([a-zA-Z0-9._-]+\\)" . font-lock-variable-name-face) ("+\\w+" . font-lock-function-name-face) ("@\\w+" . font-lock-type-face) ("#important" 0 '(:foreground "orange red")) ; special tag ("#waiting" 0 '(:foreground "dark orange")) ; special tag ("#\\w+" . font-lock-comment-face) ("-\\([a-zA-Z_-]+\\)" . font-lock-variable-name-face) ("^[0-9]+-[0-9]+-[0-9]+" 0 '(:foreground "gray90")))) (defun todotxt-open-sub () "Opens the todotxt sub on current line" (interactive) (let ((line (thing-at-point 'line t))) (string-match "\\([^ ]+\\)/:\\([.A-Za-z0-9_]+\\)" line) (find-file (concat (match-string 1 line) "/" (match-string 2 line)))))) (use-package latex :bind (:map LaTeX-mode-map ("C-z" . latex-save-and-compile) ("C-c e" . tex-close-latex-block)) :config (setq-default TeX-command-extra-options "-shell-escape") (defun latex-save-and-compile () (interactive) (save-buffer) (TeX-command "LaTeX" 'TeX-master-file -1)) (add-hook 'LaTeX-mode-hook 'TeX-source-correlate-mode) (defun latex-tsv-to-table () "Converts tab-seperated-values to a LaTeX table." (interactive) (let ((beg (region-beginning)) (end-line (line-number-at-pos (region-end)))) (save-excursion (goto-line end-line) (indent-region beg (point-at-eol)) (replace-regexp "\t" " & " nil beg (point-at-eol)) (replace-regexp "$" " \\\\\\\\" nil beg (point-at-eol)) (align beg (point)))))) (use-package fasd :config (global-fasd-mode 1) (bind-key "C-x C-S-f" 'fasd-find-file) (setq fasd-enable-initial-prompt nil fasd-completing-read-function 'ivy-completing-read)) (use-package yasnippet :defer :init (add-hook 'LaTeX-mode-hook '(lambda () (yas-minor-mode) (define-key company-active-map "" 'company-to-yasnippet) (define-key (current-local-map) "" 'company-yasnippet))) :config (yas-reload-all) (defun company-to-yasnippet () (interactive) (company-abort) (call-interactively 'company-yasnippet))) (use-package highlight-indent-guides :config :hook (prog-mode . highlight-indent-guides-mode)) (use-package helm-dash :config (setq helm-dash-browser-func 'eww helm-dash-enable-debugging nil) :hook (python-mode . (lambda ()(setq-local helm-dash-docsets '("Python 3"))))) (use-package pkgbuild-mode :config (setq pkgbuild-user-full-name "Adam Goldsmith" pkgbuild-user-mail-address "contact@adamgoldsmith.name" pkgbuild-makepkg-command "PKGEXT='.pkg.tar' makepkg -mf")) (use-package mmm-mode :config (mmm-add-classes '((latex-python :submode python-mode ; :creation-hook (lambda () (local-set-key (kbd "C-z") 'latex-save-and-compile)) :face mmm-code-submode-face :front "\\\\begin{python}\n" :back "\\\\end{python}$"))) (mmm-add-mode-ext-class 'latex-mode nil 'latex-python) (defun python-shell-send-overlay () (interactive) (python-shell-send-region (previous-overlay-change (point)) (next-overlay-change (point)))) (add-hook 'mmm-python-submode-hook (lambda () (local-set-key (kbd "C-c C-c") 'python-shell-send-overlay)))) (use-package qml-mode :mode "\\.qml\\'") (use-package company-qml :config (add-to-list 'company-backends 'company-qml)) (use-package jdee :defer :config (setq jdee-server-dir "~/.emacs.d/jdee-server/target" jdee-mode-line-format mode-line-format)) (use-package web-mode :mode "\\.html?\\'" :config (setq web-mode-markup-indent-offset 2 web-mode-css-indent-offset 2 web-mode-code-indent-offset 2)) (use-package js2-mode :mode "\\.js\\'" :config (setq js2-basic-offset 2)) (use-package nm :bind (:map nm-mode-map ("n" . nm-read) ("G" . nm-update-remote)) :config (defun nm-read () "Mark message as read." (interactive) (nm-apply-to-result (lambda (q) (notmuch-tag q '("-unread")))) (nm-update-tags) (forward-line)) (defun nm-update-remote () "Pull email from remote mailbox" (interactive) (shell-command "muchsync ag") (nm-refresh)) (setq message-kill-buffer-on-exit t mail-host-address "adamgoldsmith.name" mail-specify-envelope-from t message-sendmail-envelope-from 'header message-send-mail-function 'message-send-mail-with-sendmail sendmail-program "/usr/bin/msmtp" notmuch-fcc-dirs "Sent +sent")) (use-package fortune-cookie :config ; change message every time scratch buffer created (setq initial-major-mode (lambda () (setq initial-scratch-message (concat (fortune-cookie-comment (fortune-cookie) fortune-cookie-comment-start) "\n\n")) (lisp-interaction-mode)))) (use-package git-timemachine :bind ("C-x M-g" . git-timemachine-toggle)) ;;; Local Variables (add-to-list 'safe-local-eval-forms '(outline-hide-body)) ;; Local Variables: ;; indent-tabs-mode: nil ;; eval: (outline-minor-mode) ;; eval: (outline-hide-body) ;; End: