summaryrefslogtreecommitdiffstats
path: root/emacs
diff options
context:
space:
mode:
Diffstat (limited to 'emacs')
-rw-r--r--emacs/init.el317
-rw-r--r--emacs/user-lisp/modeline.el140
2 files changed, 457 insertions, 0 deletions
diff --git a/emacs/init.el b/emacs/init.el
new file mode 100644
index 0000000..9e26acd
--- /dev/null
+++ b/emacs/init.el
@@ -0,0 +1,317 @@
+;; -*- lexical-binding: t; -*-
+
+(require 'package)
+(setq package-check-signature nil
+ package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
+ ("nongnu" . "https://elpa.nongnu.org/packages/")
+ ("melpa" . "https://melpa.org/packages/")))
+(package-initialize)
+(unless package-archive-contents
+ (package-refresh-contents))
+
+(require 'use-package)
+(require 'seq)
+(require 'treesit)
+
+(setq use-package-always-ensure t
+ inhibit-startup-screen t
+ initial-scratch-message nil
+ initial-buffer-choice nil
+ ring-bell-function #'ignore
+ use-short-answers t
+ create-lockfiles nil
+ make-backup-files nil
+ auto-save-default nil
+ select-enable-clipboard t
+ select-enable-primary nil
+ save-interprogram-paste-before-kill nil
+ confirm-nonexistent-file-or-buffer nil
+ switch-to-buffer-obey-display-actions t
+ custom-file (expand-file-name "custom.el" user-emacs-directory)
+ display-line-numbers-type 'relative
+ mouse-wheel-scroll-amount '(3 ((shift) . 1))
+ mouse-wheel-progressive-speed nil
+ mouse-wheel-scroll-amount-horizontal '(3 . 1)
+ pixel-scroll-precision-mode nil
+ split-height-threshold nil
+ split-width-threshold nil)
+
+(setq initial-major-mode 'text-mode)
+(setq initial-buffer-choice t)
+
+(setq-default indent-tabs-mode nil
+ tab-width 4)
+
+(menu-bar-mode -1)
+
+(when (file-exists-p custom-file)
+ (load custom-file))
+
+(global-display-line-numbers-mode 1)
+(column-number-mode 1)
+(electric-pair-mode 1)
+(show-paren-mode 1)
+(save-place-mode 1)
+(recentf-mode 1)
+(savehist-mode 1)
+(xterm-mouse-mode 1)
+
+(use-package vertico
+ :init
+ (vertico-mode 1))
+
+(use-package marginalia
+ :init
+ (marginalia-mode 1))
+
+(use-package which-key
+ :init
+ (which-key-mode 1))
+
+(use-package orderless
+ :custom
+ (completion-styles '(orderless basic)))
+
+(use-package consult
+ :bind (("C-x b" . consult-buffer)
+ ("M-s r" . consult-ripgrep)
+ ("M-s l" . consult-line)))
+
+(use-package corfu
+ :custom
+ (corfu-auto t)
+ (corfu-auto-prefix 2)
+ :init
+ (global-corfu-mode 1))
+
+(use-package evil
+ :init
+ (setq evil-want-keybinding nil
+ evil-want-C-u-scroll t
+ evil-want-Y-yank-to-eol t
+ evil-undo-system 'undo-redo
+ evil-shift-width 4
+ evil-visual-x-select-clipboard nil)
+ :config
+ (evil-mode 1)
+ (setq evil-echo-state nil))
+
+(use-package evil-collection
+ :after evil
+ :config
+ (evil-collection-init))
+
+(use-package evil-surround
+ :after evil
+ :config
+ (global-evil-surround-mode 1))
+
+(use-package evil-commentary
+ :after evil
+ :config
+ (evil-commentary-mode 1))
+
+(make-directory "~/notes/" t)
+
+(use-package vterm)
+
+(use-package elcord
+ :config
+ (elcord-mode 1))
+
+(use-package org
+ :ensure nil
+ :custom
+ (org-directory "~/notes/")
+ (org-agenda-files '("~/notes/"))
+ (org-default-notes-file "~/notes/inbox.org")
+ (org-startup-indented t)
+ (org-log-done 'time)
+ (org-todo-keywords
+ '((sequence "TODO(t)" "NEXT(n)" "WAIT(w)" "|" "DONE(d)" "CANC(c)")))
+ (org-capture-templates
+ '(("t" "Todo" entry
+ (file+headline "~/notes/inbox.org" "Tasks")
+ "* TODO %?\n %U\n")
+ ("i" "Idea" entry
+ (file+headline "~/notes/inbox.org" "Ideas")
+ "* %?\n %U\n")))
+ :config
+ (require 'org-tempo)
+ (add-hook 'org-mode-hook #'visual-line-mode))
+
+(use-package evil-org
+ :after (evil org)
+ :hook (org-mode . evil-org-mode)
+ :config
+ (require 'evil-org-agenda)
+ (evil-org-agenda-set-keys))
+
+(use-package denote
+ :custom
+ (denote-directory "~/notes/")
+ (denote-file-type 'org))
+
+(use-package consult-denote
+ :after (consult denote)
+ :config
+ (consult-denote-mode 1))
+
+(use-package eglot
+ :ensure nil
+ :hook ((c-mode . eglot-ensure)
+ (c++-mode . eglot-ensure)
+ (rust-mode . eglot-ensure)
+ (go-mode . eglot-ensure)
+ (zig-mode . eglot-ensure))
+ :config
+ (add-to-list
+ 'eglot-server-programs
+ '((c-mode c++-mode) . ("clangd" "--background-index" "--header-insertion=never")))
+ (add-to-list 'eglot-server-programs '(zig-mode . ("zls"))))
+
+(use-package flymake
+ :ensure nil
+ :hook (prog-mode . flymake-mode))
+
+(use-package rust-mode
+ :mode "\\.rs\\'")
+
+(use-package go-mode
+ :mode "\\.go\\'")
+
+(use-package zig-mode
+ :mode "\\.zig\\'")
+
+(require 'warnings)
+(add-to-list 'warning-suppress-types '(bytecomp))
+
+(defvar coast-treesit-language-sources
+ '((bash . ("https://github.com/tree-sitter/tree-sitter-bash" "src"))
+ (c . ("https://github.com/tree-sitter/tree-sitter-c" "src"))
+ (cpp . ("https://github.com/tree-sitter/tree-sitter-cpp" "src"))
+ (css . ("https://github.com/tree-sitter/tree-sitter-css" "src"))
+ (go . ("https://github.com/tree-sitter/tree-sitter-go" "src"))
+ (haskell . ("https://github.com/tree-sitter/tree-sitter-haskell" "src"))
+ (html . ("https://github.com/tree-sitter/tree-sitter-html" "src"))
+ (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript" "src"))
+ (json . ("https://github.com/tree-sitter/tree-sitter-json" "src"))
+ (lua . ("https://github.com/tree-sitter-grammars/tree-sitter-lua" "src"))
+ (make . ("https://github.com/tree-sitter-grammars/tree-sitter-make" "src"))
+ (markdown . ("https://github.com/tree-sitter/tree-sitter-markdown" "src"))
+ (python . ("https://github.com/tree-sitter/tree-sitter-python" "src"))
+ (rust . ("https://github.com/tree-sitter/tree-sitter-rust" "src"))
+ (toml . ("https://github.com/tree-sitter/tree-sitter-toml" "src"))
+ (tsx . ("https://github.com/tree-sitter/tree-sitter-typescript" "tsx/src"))
+ (typescript . ("https://github.com/tree-sitter/tree-sitter-typescript" "typescript/src"))
+ (yaml . ("https://github.com/tree-sitter-grammars/tree-sitter-yaml" "src"))))
+
+(defun coast-treesit-install (language)
+ (let* ((source (alist-get language coast-treesit-language-sources))
+ (url (car source))
+ (subdir (cadr source)))
+ (when source
+ (add-to-list
+ 'treesit-language-source-alist
+ (if subdir
+ (list language url nil subdir)
+ (list language url)))
+ (treesit-install-language-grammar language))))
+
+(defun my/make-terminal-transparent (&optional frame)
+ (unless (display-graphic-p frame)
+ (let ((target-frame (or frame (selected-frame)))
+ (faces '(default line-number line-number-current-line fringe
+ window-divider vertical-border hl-line)))
+ (dolist (face faces)
+ (when (facep face)
+ (set-face-background face "unspecified-bg" target-frame)))
+ (set-terminal-parameter (frame-terminal target-frame)
+ 'background-mode 'dark))))
+
+(add-hook 'window-setup-hook #'my/make-terminal-transparent)
+(add-hook 'after-make-frame-functions #'my/make-terminal-transparent)
+(advice-add 'load-theme :after
+ (lambda (&rest _) (my/make-terminal-transparent)))
+
+(use-package doom-themes)
+
+(defun coast/remove-scratch-buffer ()
+ (let ((buffer (get-buffer "*scratch*")))
+ (when (and buffer
+ (not (buffer-modified-p buffer))
+ (not (get-buffer-window buffer t)))
+ (kill-buffer buffer))))
+
+(add-hook 'after-init-hook #'coast/remove-scratch-buffer)
+
+(defun coast-treesit-install-missing ()
+ (dolist (language (mapcar #'car coast-treesit-language-sources))
+ (unless (treesit-language-available-p language)
+ (condition-case nil
+ (coast-treesit-install language)
+ (error nil)))))
+
+(add-hook 'after-init-hook #'coast-treesit-install-missing)
+
+(add-hook 'emacs-startup-hook
+ (lambda ()
+ (delete-other-windows)))
+
+(add-to-list 'load-path "/home/coast/.emacs.d/user-lisp")
+(require 'modeline)
+
+(use-package treemacs
+ :ensure t
+ :defer t
+ :config
+ (setq treemacs-collapse-dirs (if treemacs-python-executable 3 0)
+ treemacs-deferred-git-apply-delay 0.5
+ treemacs-directory-name-transformer #'identity
+ treemacs-display-in-side-window t
+ treemacs-eldoc-display 'simple
+ treemacs-file-event-delay 5000
+ treemacs-file-follow-delay 0.2
+ treemacs-follow-after-init t
+ treemacs-expand-after-init t
+ treemacs-indentation 2
+ treemacs-indentation-string " "
+ treemacs-is-other-window nil
+ treemacs-max-git-entries 5000
+ treemacs-no-png-images nil
+ treemacs-persist-file (expand-file-name ".cache/treemacs-persist" user-emacs-directory)
+ treemacs-recenter-distance 0.1
+ treemacs-file-watch-mode t
+ treemacs-fringe-indicator-mode 'always
+ treemacs-hide-gitignored-files-mode nil
+ treemacs-width 30)
+
+ (treemacs-resize-icons 11)
+ (treemacs-follow-mode t)
+ (treemacs-project-follow-mode t)
+ (treemacs-filewatch-mode t)
+ (treemacs-hide-gitignored-files-mode -1))
+
+(use-package treemacs-evil
+ :after (treemacs evil)
+ :ensure t)
+
+(use-package treemacs-icons-dired
+ :hook (dired-mode . treemacs-icons-dired-mode)
+ :ensure t)
+
+(use-package treemacs-magit
+ :after (treemacs magit)
+ :ensure t)
+
+(defun my/treemacs-open-current-dir ()
+ "Toggle Treemacs open to current directory/project."
+ (interactive)
+ (require 'treemacs)
+ (let ((state (treemacs-current-visibility)))
+ (if (eq state 'visible)
+ (treemacs)
+ (treemacs-add-and-display-current-project-exclusively))))
+
+(with-eval-after-load 'evil
+ (evil-define-key 'normal 'global (kbd "SPC e") #'my/treemacs-open-current-dir))
diff --git a/emacs/user-lisp/modeline.el b/emacs/user-lisp/modeline.el
new file mode 100644
index 0000000..627584c
--- /dev/null
+++ b/emacs/user-lisp/modeline.el
@@ -0,0 +1,140 @@
+;; -*- lexical-binding: t; -*-
+
+(require 'cl-lib)
+(require 'subr-x)
+
+(defvar my/ml-icons t
+ "Non-nil uses Nerd Font glyphs, nil falls back to ASCII.")
+
+;; Transparent background, white text
+(set-face-attribute 'mode-line nil
+ :background "unspecified-bg" :foreground "white"
+ :box nil :inverse-video nil :underline nil :overline nil)
+(set-face-attribute 'mode-line-inactive nil
+ :background "unspecified-bg" :foreground "brightblack"
+ :box nil :inverse-video nil :underline nil :overline nil)
+
+;;;; git diff counts (+added ~modified -removed), refreshed on open and save
+(defvar-local my/ml-diff-stat nil)
+
+(defun my/ml-diff-update ()
+ (setq my/ml-diff-stat nil)
+ (when (and buffer-file-name
+ (not (file-remote-p buffer-file-name))
+ (eq (vc-backend buffer-file-name) 'Git))
+ (let ((file buffer-file-name)
+ (default-directory (file-name-directory buffer-file-name))
+ (a 0) (m 0) (r 0))
+ (with-temp-buffer
+ (when (eq 0 (process-file "git" nil t nil "diff" "-U0" "--no-color"
+ "--no-ext-diff" "--" file))
+ (goto-char (point-min))
+ (while (re-search-forward
+ "^@@ -[0-9]+\\(?:,\\([0-9]+\\)\\)? \\+[0-9]+\\(?:,\\([0-9]+\\)\\)? @@"
+ nil t)
+ (let ((o (if (match-string 1) (string-to-number (match-string 1)) 1))
+ (n (if (match-string 2) (string-to-number (match-string 2)) 1)))
+ (cond ((= o 0) (cl-incf a n))
+ ((= n 0) (cl-incf r o))
+ (t (cl-incf m (min o n))
+ (cl-incf a (max 0 (- n o)))
+ (cl-incf r (max 0 (- o n)))))))))
+ (setq my/ml-diff-stat (list a m r)))))
+
+(add-hook 'find-file-hook #'my/ml-diff-update)
+(add-hook 'after-save-hook #'my/ml-diff-update)
+(add-hook 'after-revert-hook #'my/ml-diff-update)
+
+;;;; components
+(defun my/ml-state ()
+ (if (bound-and-true-p evil-local-mode) evil-state 'emacs))
+
+(defun my/ml-block (text)
+ (propertize text 'face '(:foreground "black" :background "white" :weight bold)))
+
+(defun my/ml-mode ()
+ (my/ml-block
+ (format " %s "
+ (pcase (my/ml-state)
+ ('normal "NORMAL")
+ ('insert "INSERT")
+ ('visual (pcase (bound-and-true-p evil-visual-selection)
+ ('line "V-LINE") ('block "V-BLOCK") (_ "VISUAL")))
+ ('replace "REPLACE")
+ ('operator "O-PENDING")
+ ('motion "MOTION")
+ (_ "EMACS")))))
+
+(defun my/ml-branch ()
+ (when (and vc-mode (stringp vc-mode))
+ (concat (if my/ml-icons "\ue0a0 " "")
+ (replace-regexp-in-string "\\`[ ]*[A-Za-z]+[-:@!?]" "" vc-mode))))
+
+(defun my/ml-diff ()
+ (when my/ml-diff-stat
+ (pcase-let ((`(,a ,m ,r) my/ml-diff-stat))
+ (let ((parts (delq nil (list (and (> a 0) (format "+%d" a))
+ (and (> m 0) (format "~%d" m))
+ (and (> r 0) (format "-%d" r))))))
+ (when parts (string-join parts " "))))))
+
+(defun my/ml-diag ()
+ (when (bound-and-true-p flymake-mode)
+ (let ((e 0) (w 0) (i 0))
+ (dolist (d (flymake-diagnostics))
+ (let ((ty (flymake-diagnostic-type d)))
+ (cond ((memq ty '(:error eglot-error)) (cl-incf e))
+ ((memq ty '(:warning eglot-warning)) (cl-incf w))
+ ((memq ty '(:note eglot-note)) (cl-incf i)))))
+ (let ((parts (delq nil
+ (list (and (> e 0) (format "%s%d" (if my/ml-icons "\U000F015A " "E:") e))
+ (and (> w 0) (format "%s%d" (if my/ml-icons "\U000F002A " "W:") w))
+ (and (> i 0) (format "%s%d" (if my/ml-icons "\U000F02FD " "I:") i))))))
+ (when parts (string-join parts " "))))))
+
+(defun my/ml-file ()
+ (concat (buffer-name)
+ (cond (buffer-read-only " [-]")
+ ((buffer-modified-p) " [+]")
+ (t ""))))
+
+(defun my/ml-encoding ()
+ (replace-regexp-in-string "-\\(unix\\|dos\\|mac\\)\\'" ""
+ (symbol-name (or buffer-file-coding-system 'utf-8))))
+
+(defun my/ml-eol ()
+ (pcase (coding-system-eol-type (or buffer-file-coding-system 'utf-8-unix))
+ (1 (if my/ml-icons "\ue70f" "dos"))
+ (2 (if my/ml-icons "\uf179" "mac"))
+ (_ (if my/ml-icons "\uf17c" "unix"))))
+
+(defun my/ml-filetype ()
+ (string-remove-suffix "-mode" (symbol-name major-mode)))
+
+(defun my/ml-loc (block)
+ (let ((s (format " %s:%-2d " (format-mode-line "%3l") (1+ (current-column)))))
+ (if block (my/ml-block s) s)))
+
+(defun my/ml-section (items)
+ (let ((items (cl-remove-if (lambda (s) (or (null s) (string-empty-p s))) items)))
+ (if items (concat " " (string-join items " | ") " ") "")))
+
+;;;; assembly
+(defun my/ml-format ()
+ (let* ((active (mode-line-window-selected-p))
+ (left (if active
+ (concat (my/ml-mode)
+ (my/ml-section (list (my/ml-branch) (my/ml-diff) (my/ml-diag)))
+ (my/ml-section (list (my/ml-file))))
+ (my/ml-section (list (my/ml-file)))))
+ (right (if active
+ (concat (my/ml-section (list (my/ml-encoding) (my/ml-eol) (my/ml-filetype)))
+ (my/ml-loc t))
+ (my/ml-loc nil)))
+ (fill (propertize " " 'display
+ `((space :align-to (- right ,(string-width right)))))))
+ (concat left fill right)))
+
+(setq-default mode-line-format '((:eval (my/ml-format))))
+
+(provide 'modeline)