;; init.el --- Tyler Triplett -*- lexical-binding: t; -*- ;;; Commentary: ;;; package --- Summary (require 'package) (require 'cl-lib) ;;; code: (defvar my/toggle-disabled-modes '(term-mode eshell-mode shell-mode treemacs-mode dired-mode Buffer-menu-mode minibuffer-mode minibuffer-inactive-mode inferior-scheme-mode cider-repl-mode backtrace-mode eat-mode slime-repl-mode)) (defvar my/additional-files '(("https://ttrpl.org/file/raw/" . ("sludge-theme.el" ;; "mindre-theme.el" "moonfly-theme.el" "black-and-blue-theme.el")))) (defvar my/lsp-languages '(("C++" . (c++-mode . c++-mode-hook)) ("Clojure" . (clojure-mode . clojure-mode-hook)))) (defvar lsp-name->info (let ((table (make-hash-table :test 'equal))) (mapc (lambda (lang) (cl-destructuring-bind (name . info) lang (puthash name info table))) my/lsp-languages) table)) (defvar my/prev-register ?p "Register used to save the previous point.") (defvar my/lisp-dir "~/.emacs.d/lisp/") (defvar my/lsp-company-backends '(company-capf company-dabbrev-code company-dabbrev)) (defvar my/company-special '(c-mode-hook c++-mode-hook clojure-mode-hook)) (defvar my/global-lsp-modes-on '()) ;;; Functions (defun my/toggle-last-two-buffers () "Switch to previous buffer, when possible." (interactive) (when (my/can-toggle (current-buffer)) (let ((next (cl-find-if (lambda (buf) (my/can-toggle buf)) (cdr (buffer-list))))) (when next (switch-to-buffer next))))) (defun my/can-toggle (buf) "Current BUF can toggle." (not (with-current-buffer buf (derived-mode-p my/toggle-disabled-modes)))) (defun my/toggle-treemacs () "Switch using treemacs." (interactive) (when (eq (treemacs-current-visibility) 'visible) (treemacs-select-window))) (defun my/c++-indent-setup-alternate () "My prefered C++ style." (c-set-style "stroustrup") (setq c-basic-offset 5) (setq indent-tabs-mode nil) (c-set-offset 'statement-cont '++) (c-set-offset 'arglist-cont-nonempty '++) (c-set-offset 'statement-cont '(c-lineup-ternary-bodies ++)) (c-set-offset 'arglist-intro '+) (c-set-offset 'arglist-close 0) (c-set-offset 'inline-open 0) (c-set-offset 'func-decl-cont '++) (c-set-offset 'inline-close 0) (c-set-offset 'innamespace 0) (c-set-offset 'member-init-intro '+) (c-set-offset 'member-init-cont '(c-lineup-multi-inher +)) (c-set-offset 'inher-intro '+) (c-set-offset 'inher-cont '(c-lineup-multi-inher +))) (defun my/c++-indent-setup () "My prefered C++ style." (c-set-style "stroustrup") (setq c-basic-offset 8) (setq indent-tabs-mode nil) (setq c-noise-macro-names '("constexpr")) (c-set-offset 'statement-cont 4) (c-set-offset 'arglist-cont-nonempty 4) (c-set-offset 'statement-cont '(c-lineup-ternary-bodies 4)) (c-set-offset 'arglist-intro 4) (c-set-offset 'arglist-close 0) (c-set-offset 'inline-open 0) (c-set-offset 'func-decl-cont 4) (c-set-offset 'inline-close 0) (c-set-offset 'innamespace 0) (c-set-offset 'lambda-intro-cont 4) (c-set-offset 'brace-list-intro 4) (c-set-offset 'member-init-intro 4) (c-set-offset 'member-init-cont '(c-lineup-multi-inher 4)) (c-set-offset 'inher-intro 4) (c-set-offset 'inher-cont '(c-lineup-multi-inher 4))) (defun my/c-indent () "My prefered C style." (c-set-style "linux") (setq indent-tabs-mode nil)) (defun my/c++-doxygen-comments () "Triple slash single comments." (setq-local comment-start "/// " comment-end "" comment-start-skip "///+\\s-*") (setq-local comment-style 'extra-line)) (defun my/apply-daemon-settings (frame) "Apply my font settings for FRAME." (with-selected-frame frame (set-frame-font "Fragment Mono-12" t t) (set-frame-size frame 90 35))) (defun my/empty-buffer () "Create a new empty buffer." (interactive) (switch-to-buffer (generate-new-buffer "*empty-buffer*"))) (defun my/split (direction command) "Split window in DIRECTION and then run COMMAND." (interactive (list (completing-read "Direction: " '("right" "down") nil t) (read-command "Command to run: "))) (let ((new-window (if (or (string= direction "down") (string= direction "d")) (split-window-below) (split-window-right)))) (progn (select-window new-window) (if (commandp command) (call-interactively command) (funcall command))))) (defun my/make-move-window (v) "Return a command that move `V` windows." (lambda () (interactive) (other-window v t))) (defun my/make-scale (n) "Make an unevaluated function, where N is the amount." (lambda () (interactive) (text-scale-increase n))) (defun my/kill-all-buffers () "Kill all buffers except *scratch* and *Messages*." (interactive) (mapc (lambda (buffer) (unless (member (buffer-name buffer) '("*scratch*" "*Messages*")) (kill-buffer buffer))) (buffer-list))) (defun my/delete-window () "Kill the current buffer and delete its window." (interactive) (set-buffer-modified-p nil) (cond ((not (one-window-p)) (delete-window)) ((my/contains? major-mode my/toggle-disabled-modes) (switch-to-buffer (get-buffer-create "*scratch*"))))) (defun my/contains? (v l) "Return t when V in L." (if (null l) nil (let ((first (car l)) (rest (cdr l))) (if (equal v first) t (my/contains? v rest))))) (defun my/erase (v l) "Make a new list from L that does not contain V." (cond ((null l) '()) ((equal v (car l)) (my/erase v (cdr l))) (t (cons (car l) (my/erase v (cdr l)))))) (defun my/get-keys (hash) "Return keys from HASH." (let (keys) (maphash (lambda (k _) (push k keys)) hash) keys)) (defun my/enabled-lsp->string () "Return string of globally enabled LSP's." (when (not (null my/global-lsp-modes-on)) (concat " (Currently Enabled: " (mapconcat 'identity my/global-lsp-modes-on ", ") ")"))) (defun my/toggle-lsp (lsp) "Either enable or disable LSP globally." (interactive (list (completing-read (concat "Which LSP?" (my/enabled-lsp->string)) (my/get-keys lsp-name->info) nil t))) (if (my/contains? lsp my/global-lsp-modes-on) (progn (setq my/global-lsp-modes-on (my/erase lsp my/global-lsp-modes-on)) (cl-destructuring-bind (mode . hook) (gethash lsp lsp-name->info) (dolist (buf (buffer-list)) (with-current-buffer buf (when (and (bound-and-true-p lsp-mode) (equal major-mode mode)) (flycheck-mode 0) (lsp-disconnect)))) (remove-hook hook #'lsp))) (progn (push lsp my/global-lsp-modes-on) (cl-destructuring-bind (mode . hook) (gethash lsp lsp-name->info) (dolist (buf (buffer-list)) (with-current-buffer buf (when (and (not (bound-and-true-p lsp-mode)) (equal major-mode mode)) (flycheck-mode 1) (lsp)))) (add-hook hook #'lsp))))) (defun my/set-register () "Save a pointer to register." (interactive) (point-to-register my/prev-register)) (defun my/jump-register () "Jump to register." (interactive) (jump-to-register my/prev-register)) (defmacro my/let (name bindings &rest body) "Scheme-esque named let." (declare (indent 2)) (let ((vars (mapcar #'car bindings)) (vals (mapcar #'cadr bindings)) (prev (symbol-function name))) (unwind-protect `(progn (fset ',name (lambda ,vars ,@body)) (,name ,@vals)) (fset name prev)))) (defmacro -> (x &rest forms) "Clojure thread first macro" (if (null forms) x `(-> ,(if (listp (car forms)) (append (list (caar forms) x) (cdar forms)) (list (car forms) x)) ,@(cdr forms)))) (defmacro ->> (x &rest forms) "Clojure thread last macro" (if (null forms) x `(->> ,(if (listp (car forms)) (append (car forms) (list x)) (list (car forms) x)) ,@(cdr forms)))) (defalias 'open-guile-repl (lambda () (interactive) (my/split "right" (lambda () (run-scheme "guile"))))) (defalias 'open-term (lambda() (interactive) (my/split "right" (lambda () (eat))))) ;;; Packages (setq package-enable-at-startup nil) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (package-initialize) (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (require 'use-package) (setq use-package-always-ensure t) (use-package evil :init (setq evil-want-integration t evil-want-keybinding nil evil-undo-system 'undo-redo) :config (evil-mode 1) (setq evil-default-state 'emacs) (evil-set-initial-state 'text-mode 'normal) (evil-set-initial-state 'prog-mode 'normal) (define-key evil-normal-state-map (kbd "C-r") #'undo-redo) (define-key evil-normal-state-map (kbd "Q") 'evil-record-macro) (define-prefix-command 'my/evil-dot-prefix) (define-key evil-normal-state-map (kbd ".") 'my/evil-dot-prefix) (define-key my/evil-dot-prefix (kbd ",") #'my/set-register) (define-key my/evil-dot-prefix (kbd ".") #'my/jump-register) (setq evil-insert-state-cursor '(hbar . 3)) (with-eval-after-load 'counsel (define-key evil-normal-state-map (kbd "q") #'counsel-switch-buffer)) (with-eval-after-load 'swiper (define-key evil-normal-state-map (kbd "/") #'swiper) (define-key evil-visual-state-map (kbd "/") #'swiper)) (with-eval-after-load 'counsel (define-key evil-normal-state-map (kbd "?") #'counsel-ag) (define-key evil-visual-state-map (kbd "?") #'counsel-ag)) (with-eval-after-load 'treemacs (define-key evil-normal-state-map (kbd "<tab> <tab>") #'treemacs)) (with-eval-after-load 'evil-commentary (define-key evil-visual-state-map (kbd "gc") #'comment-line))) (use-package evil-commentary :config (evil-commentary-mode)) (use-package treemacs :bind (("<f2>" . treemacs)) :config (setq treemacs-width 40) (global-set-key (kbd "S-<iso-lefttab>") #'my/toggle-treemacs)) (use-package treemacs-evil :after (treemacs evil)) (use-package treemacs-icons-dired :hook (dired-mode . treemacs-icons-dired-enable-once) :ensure t) (use-package lsp-mode :commands lsp :config (setq lsp-enable-on-type-formatting nil) :after company) (use-package company :hook (after-init . global-company-mode) :config (setq company-idle-delay 0.2 company-minimum-prefix-length 1 company-selection-wrap-around t company-tooltip-align-annotations t) (mapc (lambda (hook) (add-hook hook (lambda () (setq-local company-backends my/lsp-company-backends)))) my/company-special) (define-key company-active-map (kbd "<escape>") 'company-abort)) (use-package company-box :after company :hook (company-mode . company-box-mode) :config (setq company-box-doc-enable t)) (use-package flycheck) (use-package cmake-mode) (use-package clojure-mode) (use-package slime) (use-package cider :config (setq cider-preferred-build-tool 'clojure-cli) (global-set-key (kbd "<f6>") (lambda () (interactive) (cider-jack-in-clj nil) 'cider-repl-mode))) (use-package eat :config (eat-eshell-mode) (setq eat-enable-mouse nil) (define-key eat-mode-map (kbd "C-S-v") 'eat-yank) (global-set-key (kbd "<f4>") #'open-term) (define-key eat-mode-map (kbd "<f4>") #'open-term) (define-key eat-mode-map (kbd "<f5>") #'open-guile-repl) (define-key eat-mode-map (kbd "<f1>") #'my/delete-window) (define-key eat-mode-map (kbd "<f12>") #'my/kill-all-buffers) (define-key eat-mode-map (kbd "M-<right>") (my/make-move-window 1)) (define-key eat-mode-map (kbd "M-<left>") (my/make-move-window -1))) (use-package ivy :diminish :bind (:map ivy-minibuffer-map) :config (ivy-mode 1) (setq ivy-use-virtual-buffers t) (setq ivy-count-format "(%d/%d) ") (setq ivy-use-selectable-prompt t) (setq enable-recursive-minibuffers t) (setq ivy-re-builders-alist '((counsel-find-file . ivy--regex-fuzzy) (t . ivy--regex-plus)))) (use-package counsel :after ivy :config (counsel-mode 1) (global-set-key (kbd "C-x C-f") #'counsel-find-file) (global-set-key (kbd "C-x d") #'counsel-dired)) (use-package swiper :after ivy) (use-package magit :commands (magit-status magit-blame) :bind (("C-x g" . magit-status))) (use-package treemacs-magit :after (treemacs magit)) (use-package markdown-mode) (use-package 2048-game) (use-package minions :init (minions-mode 1) :config (setq minions-mode-line-lighter " ^ ")) ;;; Some themes (use-package doom-themes :init (setq doom-themes-enable-bold t doom-themes-enable-italic t) :config (doom-themes-visual-bell-config) (doom-themes-org-config)) (use-package modus-themes :config (setq modus-themes-common-palette-overrides (append modus-themes-preset-overrides-cooler '((cursor blue-warmer) (fg-cursor blue-warmer) (bg-cursor blue-warmer) (bg-paren-match bg-lavender) (fg-paren-match fg-lavender) (bg-paren-expression bg-lavender) (fg-paren-expression fg-lavender)))) (load-theme 'modus-operandi-tinted t)) (use-package organic-green-theme) (use-package gruber-darker-theme) (use-package gruvbox-theme) (use-package doric-themes) ;;; custom elisp (unless (file-directory-p my/lisp-dir) (make-directory my/lisp-dir t)) ;;; download additional files (mapc (lambda (domain) (let ((url (car domain)) (files (cdr domain))) (mapc (lambda (file) (let ((path (concat my/lisp-dir file)) (complete-url (concat url file))) (unless (file-exists-p path) (url-copy-file complete-url path t)))) files))) my/additional-files) (add-to-list 'custom-theme-load-path my/lisp-dir) ; (use-package mindre-theme ; :load-path my/lisp-dir ; :custom ; (mindre-use-more-bold nil) ; (mindre-use-faded-lisp-parens t) ; (mindre-faded-lisp-parens-modes ; '(emacs-lisp-mode ; lisp-mode ; scheme-mode ; racket-mode ; clojure-mode)) ; :config ; ;; (load-theme 'mindre t) ; ) ;;; Settings (menu-bar-mode -1) (tool-bar-mode -1) (scroll-bar-mode -1) (show-paren-mode 1) (ido-mode 1) (global-font-lock-mode 1) (electric-pair-mode 1) (setq-default fill-column 80) (setq-default tab-width 4) (setq-default standard-indent 4) (setq-default indent-tabs-mode nil) (setq-default case-fold-search t) (setq-default search-upper-case nil) (setq-default truncate-lines t) (setq inferior-lisp-program "sbcl") (setq scheme-program-name "guile") (setq inhibit-startup-screen t) (setq search-highlight t) (setq lazy-highlight-cleanup nil) (setq make-backup-files nil) (setq auto-save-default nil) (setq select-enable-clipboard t) (setq visible-bell t) (setq show-paren-delay 0) (setq scroll-conservatively 101) (setq scroll-margin 2) (setq fast-but-imprecise-scrolling t) (setq eshell-prompt-function (lambda () (concat (abbreviate-file-name (eshell/pwd)) " λ "))) (add-to-list 'auto-mode-alist '("\\.tt\\'" . c++-mode)) (set-frame-font "CamingoCode-12" nil t) (when (daemonp) (add-hook 'after-make-frame-functions (lambda (frame) (select-frame-set-input-focus frame) (if (display-graphic-p frame) (my/apply-daemon-settings frame) (redraw-display))))) (mapc (lambda (hook) (add-hook hook (lambda () (display-fill-column-indicator-mode 1) (display-line-numbers-mode 1) (setq show-trailing-whitespace t)))) '(prog-mode-hook text-mode-hook)) (add-hook 'c++-mode-hook (lambda () (my/c++-doxygen-comments) (my/c++-indent-setup))) (add-hook 'c-mode-hook #'my/c-indent) ;;; Keybinds (global-set-key (kbd "<f3>") 'my/toggle-last-two-buffers) (global-set-key (kbd "C-+") (my/make-scale 1)) (global-set-key (kbd "C-_") (my/make-scale -1)) (global-set-key (kbd "C-)") (my/make-scale 0)) (global-set-key (kbd "C-<backspace>") 'backward-kill-word) (global-set-key (kbd "<f5>") 'open-guile-repl) (global-set-key (kbd "<f1>") 'my/delete-window) (global-set-key (kbd "<f12>") 'my/kill-all-buffers) (global-set-key (kbd "M-<right>") (my/make-move-window 1)) (global-set-key (kbd "M-<left>") (my/make-move-window -1)) (global-set-key (kbd "C-S-<left>") 'move-beginning-of-line) (global-set-key (kbd "C-S-<right>") 'move-end-of-line) (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. '(custom-safe-themes nil) '(package-selected-packages '(2048-game cider cmake-mode company-box counsel doom-themes doric-themes eat evil-commentary flycheck gruber-darker-theme gruvbox-theme lsp-mode minions modus-themes organic-green-theme slime treemacs-evil treemacs-icons-dired treemacs-magit))) (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. '(fill-column-indicator ((t (:foreground "#CCCCCC" :weight normal)))) '(multi-magit-repo-heading ((t (:inherit magit-section-heading :box nil)))) '(speedbar-selected-face ((t (:foreground "#119911" :underline t))))) (provide 'init) ;;; init.el ends here