diff --git a/init.el b/init.el new file mode 100644 index 0000000..60690d2 --- /dev/null +++ b/init.el @@ -0,0 +1,1316 @@ +;;; -*- lexical-binding: t -*- +;;; DO NOT EDIT THIS FILE DIRECTLY +;;; EDIT ~init.org~ instead + +;; (setq byte-compile-warnings nil) +(defun tangle-init () + "If the current buffer is 'init.org' the code-blocks are tangled, and the tangled file is compiled." + (when (equal (buffer-file-name) + (expand-file-name (concat user-emacs-directory "init.org"))) + ;; Avoid running hooks when tangling. + (let ((prog-mode-hook nil)) + (org-babel-tangle) + (byte-compile-file (concat user-emacs-directory "init.el"))))) + +(add-hook 'after-save-hook 'tangle-init) + +(require 'package) + +(defvar my-packages + '(all-the-icons + anzu + base16-theme + better-defaults + company + company-go + counsel + counsel-projectile + diminish + dockerfile-mode + doom-themes + ein + eldoc-eval + elpy + expand-region + gitignore-mode + go-mode + go-playground + gorepl-mode + flycheck + iedit + ivy + ivy-hydra + json-mode + magit + material-theme + multiple-cursors + projectile + py-autopep8 + rainbow-delimiters + shrink-path + tide + typescript-mode + use-package + web-mode + which-key)) + +(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/")) +(add-to-list 'package-archives '("melpa-stable" . "http://stable.melpa.org/packages/")) + +(when (not package-archive-contents) + (package-refresh-contents)) +(package-initialize) + +(dolist (p my-packages) + (when (not (package-installed-p p)) + (package-install p))) + +(require 'better-defaults) + +;; Instead of the annoying giant warning icon, just flash the modeline. +;; (this happens when you do something like C-g) +(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)))) + +(defvar backup-dir (expand-file-name "~/.emacs.d/backup/")) +(defvar autosave-dir (expand-file-name "~/.emacs.d/autosave/")) + +(setq inhibit-startup-message t + initial-scratch-message nil + backup-directory-alist (list (cons ".*" backup-dir)) + auto-save-list-file-prefix autosave-dir + auto-save-file-name-transforms `((".*" ,autosave-dir t))) + +(menu-bar-mode 0) +(scroll-bar-mode 0) +(tool-bar-mode 0) + + +;; (load-theme 'doom-city-lights t) +;; (load-theme 'doom-dracula t) +;; (load-theme 'doom-nord t) +(load-theme 'doom-one t) +;; (load-theme 'doom-spacegrey t) +;; (load-theme 'base16-ocean t) +(load-theme 'base16-onedark t) +(global-linum-mode t) +(global-auto-revert-mode t) + +(defalias 'yes-or-no-p 'y-or-n-p) + +(require 'which-key) +(which-key-setup-minibuffer) +(which-key-mode) + +(require 'company) +(add-hook 'after-init-hook 'global-company-mode) + +(require 'diminish) +(diminish 'auto-revert-mode) +(eval-after-load "company" '(diminish 'company-mode)) +(eval-after-load "counsel" '(diminish 'counsel-mode)) +(eval-after-load "elpy" '(diminish 'elpy-mode)) +(eval-after-load "go-mode" '(diminish 'go-mode)) +(eval-after-load "go-playground" '(diminish 'go-playground-mode)) +(eval-after-load "gorepl-mode" '(diminish 'gorepl-mode)) +(eval-after-load "flycheck" '(diminish 'flycheck-mode)) +(eval-after-load "ivy" '(diminish 'ivy-mode)) +(eval-after-load "projectile" '(diminish 'projectile-mode)) +(eval-after-load "which-key" '(diminish 'which-key-mode)) + +(defun dired-mode-setup () + "Will run as hook for `dired-mode'." + (dired-hide-details-mode 1)) +(add-hook 'dired-mode-hook 'dired-mode-setup) + +(require 'ivy-hydra) +(require 'ivy) +(require 'swiper) + +(ivy-mode 1) +(counsel-mode) +(setq ivy-use-virtual-buffers t + enable-recursive-minibuffers t + ivy-height 25 + ivy-initial-inputs-alist nil + ivy-extra-directories nil) + +(global-set-key (kbd "C-s") 'swiper) +(global-set-key (kbd "C-c C-r") 'ivy-resume) +(global-set-key (kbd "M-x") 'counsel-M-x) +(global-set-key (kbd "C-x C-f") 'counsel-find-file) +(global-set-key (kbd "C-c g") 'counsel-git) +(global-set-key (kbd "C-c j") 'counsel-git-grep) +(global-set-key (kbd "C-c k") 'counsel-ag) +(define-key minibuffer-local-map (kbd "C-r") 'counsel-minibuffer-history) + +(defun ivy-open-current-typed-path () + (interactive) + (when ivy--directory + (let* ((dir ivy--directory) + (text-typed ivy-text) + (path (concat dir text-typed))) + (delete-minibuffer-contents) + (ivy--done path)))) + +(define-key ivy-minibuffer-map (kbd "") 'ivy-alt-done) +(define-key ivy-minibuffer-map (kbd "C-f") 'ivy-open-current-typed-path) + +(require 'magit) +(global-set-key (kbd "C-x g") 'magit-status) +(global-set-key (kbd "C-c g") 'magit-status) +(setq magit-completing-read-function 'ivy-completing-read) + +(require 'projectile) +(require 'counsel-projectile) + +(projectile-mode) +(setq projectile-mode-line '(:eval (format " %s" (projectile-project-name))) + projectile-remember-window-configs t + projectile-completion-system 'ivy) +(counsel-projectile-mode) + +(require 'rainbow-delimiters) +(global-flycheck-mode) + +(add-hook 'before-save-hook 'delete-trailing-whitespace) +(add-hook 'prog-mode-hook 'rainbow-delimiters-mode) + +(setq-default indent-tabs-mode nil + tab-width 4) +(defvaralias 'c-basic-offset 'tab-width) +(defvaralias 'cperl-indent-level 'tab-width) + +(electric-pair-mode 1) +(show-paren-mode 1) + +(require 'dockerfile-mode) +(add-to-list 'auto-mode-alist '("Dockerfile*\\'" . dockerfile-mode)) + +(require 'gitignore-mode) +(add-to-list 'auto-mode-alist '("gitignore\\'" . gitignore-mode)) + +(require 'json-mode) +(add-to-list 'auto-mode-alist '("\\.json\\'" . json-mode)) + +(require 'web-mode) +(add-to-list 'auto-mode-alist '("\\.html\\'" . web-mode)) + +(elpy-enable) +(setq python-shell-interpreter "jupyter" + python-shell-interpreter-args "console --simple-prompt") + +(when (require 'flycheck nil t) + (setq elpy-modules (delq 'elpy-module-flymake elpy-modules)) + (add-hook 'elpy-mode-hook 'flycheck-mode)) + +(require 'py-autopep8) +(setq py-autopep8-options '("--ignore=E501")) +(add-hook 'elpy-mode-hook 'py-autopep8-enable-on-save) + +(require 'go-mode) +(require 'go-playground) +(require 'gorepl-mode) +(require 'company-go) + +(add-to-list 'auto-mode-alist '("\\.go\\'" . go-mode)) +(add-hook 'go-mode-hook (lambda () + (add-hook 'before-save-hook 'gofmnt-before-save) + (local-set-key (kbd "M-.") 'godef-jump) + (local-set-key (kbd "M-,") 'pop-tag-mark) + (set (make-local-variable 'company-backends) '(company-go)) + (setq company-tooltip-limit 20 + company-idle-delay .3 + company-echo-delay 0 + company-begin-commands '(self-insert-command)) + (gorepl-mode))) +(defun set-exec-path-from-shell-PATH () + (let ((path-from-shell (replace-regexp-in-string + "[ \t\n]*$" + "" + (shell-command-to-string "$SHELL --login -i -c 'echo $PATH'")))) + (setenv "PATH" path-from-shell) + (setq eshell-path-env path-from-shell) + (setq exec-path (split-string path-from-shell path-separator)))) + +(when window-system (set-exec-path-from-shell-PATH)) + +(setenv "GOPATH" "/home/leviolson/go") +(add-to-list 'exec-path "/home/leviolson/go/bin") + +(defun setup-tide-mode () + "Tide setup function." + (interactive) + (tide-setup) + (flycheck-mode +1) + (setq flycheck-check-syntax-automatically '(save mode-enabled)) + (eldoc-mode +1) + (tide-hl-identifier-mode +1) + (company-mode +1)) + +;; aligns annotation to the right hand side +(setq company-tooltip-align-annotations t) + +;; formats the buffer before saving +(add-hook 'before-save-hook 'tide-format-before-save) + +(add-hook 'typescript-mode-hook #'setup-tide-mode) + +(require 'typescript-mode) +(require 'tide) + +(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-mode)) +(add-hook 'typescript-mode-hook + '(lambda () + (set (make-local-variable 'company-backends) '(company-tide)) + (setq company-tooltip-limit 20 + company-idle-delay .3 + company-echo-delay 0 + company-begin-commands '(self-insert-command) + tide-format-options '(:insertSpaceAfterFunctionKeywordForAnonymousFunctions t :placeOpenBraceOnNewLineForFunctions nil)) + (tide-setup))) + +(require 'web-mode) +(add-to-list 'auto-mode-alist '("\\.tsx\\'" . web-mode)) +(add-hook 'web-mode-hook + (lambda () + (when (string-equal "tsx" (file-name-extension buffer-file-name)) + (setup-tide-mode)))) +;; enable typescript-tslint checker +(flycheck-add-mode 'typescript-tslint 'web-mode) + +(require 'web-mode) +(add-to-list 'auto-mode-alist '("\\.jsx\\'" . web-mode)) +(add-hook 'web-mode-hook + (lambda () + (when (string-equal "jsx" (file-name-extension buffer-file-name)) + (setup-tide-mode)))) +;; configure jsx-tide checker to run after your default jsx checker +(flycheck-add-mode 'javascript-eslint 'web-mode) +(flycheck-add-next-checker 'javascript-eslint 'jsx-tide 'append) + +(org-babel-do-load-languages + 'org-babel-load-languages + '((js . t) + (shell . t) + (emacs-lisp . t))) + +(defvar org-src-tab-acts-natively) +(setq org-src-tab-acts-natively t) +;; (setenv "NODE_PATH" +;; (getenv "NODE_PATH")) + +(defvar org-confirm-babel-evaluate) + +(defun my-org-confirm-babel-evaluate (lang body) + "Execute certain languages without confirming. + Takes LANG to allow and BODY to execute." + (not (or (string= lang "js") + (string= lang "restclient") + (string= lang "emacs-lisp") + (string= lang "shell")))) +(setq org-confirm-babel-evaluate #'my-org-confirm-babel-evaluate) +(add-to-list 'org-structure-template-alist + (list "e" (concat "#+BEGIN_SRC emacs-lisp :results silent\n" + "\n" + "#+END_SRC"))) +(add-to-list 'org-structure-template-alist + (list "j" (concat "#+BEGIN_SRC js :cmd \"babel-node\"\n" + "\n" + "#+END_SRC"))) +(add-to-list 'org-structure-template-alist + (list "r" (concat "#+BEGIN_SRC restclient :results raw\n" + "\n" + "#+END_SRC"))) + +(defun find-user-init-file () + "Edit the `~/.emacs.d/init.org' file." + (interactive) + (find-file "~/.emacs.d/init.org")) + +(defun load-user-init-file () + "Reload the `~/.emacs.d/init.elc' file." + (interactive) + (load-file "~/.emacs.d/init.elc")) + +(defun jump-to-symbol-internal (&optional backwardp) + "Jumps to the next symbol near the point if such a symbol exists. If BACKWARDP is non-nil it jumps backward." + (let* ((point (point)) + (bounds (find-tag-default-bounds)) + (beg (car bounds)) (end (cdr bounds)) + (str (isearch-symbol-regexp (find-tag-default))) + (search (if backwardp 'search-backward-regexp + 'search-forward-regexp))) + (goto-char (if backwardp beg end)) + (funcall search str nil t) + (cond ((<= beg (point) end) (goto-char point)) + (backwardp (forward-char (- point beg))) + (t (backward-char (- end point)))))) + +(defun jump-to-previous-like-this () + "Jumps to the previous occurrence of the symbol at point." + (interactive) + (jump-to-symbol-internal t)) + +(defun jump-to-next-like-this () + "Jumps to the next occurrence of the symbol at point." + (interactive) + (jump-to-symbol-internal)) + + +(defun kill-this-buffer-unless-scratch () + "Works like `kill-this-buffer' unless the current buffer is the *scratch* buffer. In which case the buffer content is deleted and the buffer is buried." + (interactive) + (if (not (string= (buffer-name) "*scratch*")) + (kill-this-buffer) + (delete-region (point-min) (point-max)) + (switch-to-buffer (other-buffer)) + (bury-buffer "*scratch*"))) + +(defun backward-delete-to-word (arg) + "Delete words backward. With ARG, do this many times." + (interactive "p") + (delete-region (point) (progn (backward-to-word arg) (point)))) + +(defun comment-or-uncomment-region-or-line () + "Comments or uncomments the region or the current line if there's no active region." + (interactive) + (let (beg end) + (if (region-active-p) + (setq beg (region-beginning) end (region-end)) + (setq beg (line-beginning-position) end (line-end-position))) + (comment-or-uncomment-region beg end))) + +(defun new-line-below () + "Create a new line below current line." + (interactive) + (move-end-of-line 1) + (newline-and-indent)) + +(defun new-line-above () + "Create a new line above current line." + (interactive) + (move-beginning-of-line 1) + (newline) + (forward-line -1)) + +(defun duplicate-thing (comment) + "Duplicates the current line, or the region if active. If an argument (COMMENT) is given, the duplicated region will be commented out." + (interactive "P") + (save-excursion + (let ((start (if (region-active-p) (region-beginning) (point-at-bol))) + (end (if (region-active-p) (region-end) (point-at-eol)))) + (goto-char end) + (unless (region-active-p) + (newline)) + (insert (buffer-substring start end)) + (when comment (comment-region start end))))) + +(defun tidy () + "Ident, untabify and unwhitespacify current buffer, or region if active." + (interactive) + (let ((beg (if (region-active-p) (region-beginning) (point-min))) + (end (if (region-active-p) (region-end) (point-max)))) + (if (region-active-p) (message "Indenting Region") (message "Indenting File")) + (let ((inhibit-message t)) + (indent-region beg end)) + (whitespace-cleanup) + (untabify beg (if (< end (point-max)) end (point-max))))) + +(defun phil-columns () + "Good 'ol Phil-Columns." + (interactive) + (message "Good 'ol fill-columns") + (with-output-to-temp-buffer "*PHIL-COLUMN*" + (shell-command "mpv --no-video 'https://www.youtube.com/watch?v=YkADj0TPrJA&t=3m16s' > /dev/null 2>&1 & sleep 7; pkill mpv")) + (other-window 1) + (delete-window)) + +(declare-function first "Goto FIRST shell.") +(declare-function goto-non-shell-buffer "Goto something other than a shell buffer.") +(declare-function switch-shell "Switch shell.") + +(let ((last-shell "")) + (defun toggle-shell () + (interactive) + (cond ((string-match-p "^\\*shell<[1-9][0-9]*>\\*$" (buffer-name)) + (goto-non-shell-buffer)) + ((get-buffer last-shell) (switch-to-buffer last-shell)) + (t (shell (setq last-shell "*shell<1>*"))))) + + (defun switch-shell (n) + (let ((buffer-name (format "*shell<%d>*" n))) + (setq last-shell buffer-name) + (cond ((get-buffer buffer-name) + (switch-to-buffer buffer-name)) + (t (shell buffer-name) + (rename-buffer buffer-name))))) + + (defun goto-non-shell-buffer () + (let* ((r "^\\*shell<[1-9][0-9]*>\\*$") + (shell-buffer-p (lambda (b) (string-match-p r (buffer-name b)))) + (non-shells (cl-remove-if shell-buffer-p (buffer-list)))) + (when non-shells + (switch-to-buffer (first non-shells)))))) + + +(defadvice shell (after kill-with-no-query nil activate) + "." + (set-process-query-on-exit-flag (get-buffer-process ad-return-value) nil)) + +(declare-function comint-truncate-buffer ".") +(defun clear-comint () + "Run `comint-truncate-buffer' with the `comint-buffer-maximum-size' set to zero." + (interactive) + (let ((comint-buffer-maximum-size 0)) + (comint-truncate-buffer))) + +(defun c-setup () + "Compile." + (local-set-key (kbd "C-c C-c") 'compile)) + +(require 'company) +(add-hook 'comint-mode-hook (lambda () (local-set-key (kbd "C-l") 'clear-comint))) +(add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode) +(add-hook 'lisp-interaction-mode-hook 'turn-on-eldoc-mode) +(add-hook 'c-mode-common-hook 'c-setup) +(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode)) + +(defvar company-active-map (make-keymap) + "Company Mode keymap.") +(defvar custom-bindings (make-keymap) + "A keymap of custom bindings.") + +(define-key global-map (kbd "M-p") 'jump-to-previous-like-this) +(define-key global-map (kbd "M-n") 'jump-to-next-like-this) +(define-key global-map (kbd "M-") 'switch-to-next-buffer) +(define-key global-map (kbd "M-")'backward-delete-to-word) +(define-key global-map (kbd "C-")'backward-delete-to-word) + +(global-set-key (kbd "C-S-") 'mc/mark-next-like-this) +(global-set-key (kbd "C->") 'mc/mark-next-like-this) +(global-set-key (kbd "C-S-") 'mc/mark-previous-like-this) +(global-set-key (kbd "C-<") 'mc/mark-previous-like-this) +(global-set-key (kbd "C-c C->") 'mc/mark-all-like-this) +;; (dolist (n (number-sequence 1 9)) +;; (global-set-key (kbd (concat "M-" (int-to-string n))) +;; (lambda () (interactive) (switch-shell n)))) + +(define-key company-active-map (kbd "C-d") 'company-show-doc-buffer) +(define-key company-active-map (kbd "C-n") 'company-select-next) +(define-key company-active-map (kbd "C-p") 'company-select-previous) +(define-key company-active-map (kbd "") 'company-complete) + +(define-key custom-bindings (kbd "C-c p") 'counsel-projectile-switch-project) +(define-key custom-bindings (kbd "C-c f") 'counsel-projectile-find-file) +(define-key custom-bindings (kbd "C-c m") 'magit-status) +(define-key custom-bindings (kbd "C-c D") 'define-word-at-point) +(define-key custom-bindings (kbd "C-@") 'er/expand-region) +(define-key custom-bindings (kbd "C-#") 'er/contract-region) +(define-key custom-bindings (kbd "C-S-c C-S-c") 'mc/edit-lines) +(define-key custom-bindings (kbd "C-c b") 'ivy-switch-buffer) +(define-key custom-bindings (kbd "C-c l") 'org-store-link) +(define-key custom-bindings (kbd "C-c t") 'org-set-tags) +(define-key custom-bindings (kbd "M-u") 'upcase-dwim) +(define-key custom-bindings (kbd "M-c") 'capitalize-dwim) +(define-key custom-bindings (kbd "M-l") 'downcase-dwim) +(define-key custom-bindings (kbd "M-o") 'other-window) +(define-key custom-bindings (kbd "C-c s") 'ispell-word) +(define-key custom-bindings (kbd "C-c C-d") 'org-capture) +(define-key custom-bindings (kbd "C-c ") 'windmove-up) +(define-key custom-bindings (kbd "C-c ") 'windmove-down) +(define-key custom-bindings (kbd "C-c ") 'windmove-left) +(define-key custom-bindings (kbd "C-c ") 'windmove-right) +(define-key custom-bindings (kbd "C-c a") (lambda () (interactive) (org-agenda nil "n"))) +(define-key custom-bindings (kbd "C-c e") 'find-user-init-file) +(define-key custom-bindings (kbd "C-x f") 'phil-columns) +(define-key custom-bindings (kbd "C-x k") 'kill-this-buffer-unless-scratch) +(define-key custom-bindings (kbd "C-c d") 'duplicate-thing) +(define-key custom-bindings (kbd "C-c c") 'comment-or-uncomment-region-or-line) +(define-key custom-bindings (kbd "C-;") 'comment-or-uncomment-region-or-line) +(define-key custom-bindings (kbd "C-o") 'new-line-below) +(define-key custom-bindings (kbd "C-S-o") 'new-line-above) +(define-key custom-bindings (kbd "") 'tidy) +(define-key custom-bindings (kbd "M-q") 'kill-this-buffer) +(define-key custom-bindings (kbd "M-RET") '(lambda () (interactive) (term (getenv "SHELL")))) + + +(define-minor-mode custom-bindings-mode + "A mode that activates custom-bindings." + t nil custom-bindings) + +(cond ((member "PragmataPro" (font-family-list)) + (set-face-attribute 'default nil :font "PragmataPro-14"))) + +(require 'use-package) +(require 'anzu) +(require 'eldoc-eval) +(require 'iedit) +(require 'projectile) +(require 'all-the-icons) + +(defsubst doom--prepare-modeline-segments (segments) + (cl-loop for seg in segments + if (stringp seg) + collect seg + else + collect (list (intern (format "doom-modeline-segment--%s" (symbol-name seg)))))) + +(defvar doom--transient-counter 0) +(defmacro add-transient-hook! (hook &rest forms) + "Attaches transient forms to a HOOK. + +HOOK can be a quoted hook or a sharp-quoted function (which will be advised). + +These forms will be evaluated once when that function/hook is first invoked, +then it detaches itself." + (declare (indent 1)) + (let ((append (eq (car forms) :after)) + (fn (intern (format "doom-transient-hook-%s" (cl-incf doom--transient-counter))))) + `(when ,hook + (fset ',fn + (lambda (&rest _) + ,@forms + (cond ((functionp ,hook) (advice-remove ,hook #',fn)) + ((symbolp ,hook) (remove-hook ,hook #',fn))) + (unintern ',fn nil))) + (cond ((functionp ,hook) + (advice-add ,hook ,(if append :after :before) #',fn)) + ((symbolp ,hook) + (add-hook ,hook #',fn ,append)))))) + + +(defmacro add-hook! (&rest args) + "A convenience macro for `add-hook'. Takes, in order: + 1. Optional properties :local and/or :append, which will make the hook + buffer-local or append to the list of hooks (respectively), + 2. The hooks: either an unquoted major mode, an unquoted list of major-modes, + a quoted hook variable or a quoted list of hook variables. If unquoted, the + hooks will be resolved by appending -hook to each symbol. + 3. A function, list of functions, or body forms to be wrapped in a lambda. +Examples: + (add-hook! 'some-mode-hook 'enable-something) + (add-hook! some-mode '(enable-something and-another)) + (add-hook! '(one-mode-hook second-mode-hook) 'enable-something) + (add-hook! (one-mode second-mode) 'enable-something) + (add-hook! :append (one-mode second-mode) 'enable-something) + (add-hook! :local (one-mode second-mode) 'enable-something) + (add-hook! (one-mode second-mode) (setq v 5) (setq a 2)) + (add-hook! :append :local (one-mode second-mode) (setq v 5) (setq a 2)) +Body forms can access the hook's arguments through the let-bound variable +`args'." + (declare (indent defun) (debug t)) + (let ((hook-fn 'add-hook) + append-p local-p) + (while (keywordp (car args)) + (pcase (pop args) + (:append (setq append-p t)) + (:local (setq local-p t)) + (:remove (setq hook-fn 'remove-hook)))) + (let ((hooks (doom--resolve-hook-forms (pop args))) + (funcs + (let ((val (car args))) + (if (memq (car-safe val) '(quote function)) + (if (cdr-safe (cadr val)) + (cadr val) + (list (cadr val))) + (list args)))) + forms) + (dolist (fn funcs) + (setq fn (if (symbolp fn) + `(function ,fn) + `(lambda (&rest _) ,@args))) + (dolist (hook hooks) + (push (if (eq hook-fn 'remove-hook) + `(remove-hook ',hook ,fn ,local-p) + `(add-hook ',hook ,fn ,append-p ,local-p)) + forms))) + `(progn ,@(nreverse forms))))) + +(defmacro def-modeline-segment! (name &rest forms) + "Defines a modeline segment and byte compiles it." + (declare (indent defun) (doc-string 2)) + (let ((sym (intern (format "doom-modeline-segment--%s" name)))) + `(progn + (defun ,sym () ,@forms) + ,(unless (bound-and-true-p byte-compile-current-file) + `(let (byte-compile-warnings) + (byte-compile #',sym)))))) + +(defmacro def-modeline! (name lhs &optional rhs) + "Defines a modeline format and byte-compiles it. NAME is a symbol to identify +it (used by `doom-modeline' for retrieval). LHS and RHS are lists of symbols of +modeline segments defined with `def-modeline-segment!'. +Example: + (def-modeline! minimal + (bar matches \" \" buffer-info) + (media-info major-mode)) + (doom-set-modeline 'minimal t)" + (let ((sym (intern (format "doom-modeline-format--%s" name))) + (lhs-forms (doom--prepare-modeline-segments lhs)) + (rhs-forms (doom--prepare-modeline-segments rhs))) + `(progn + (defun ,sym () + (let ((lhs (list ,@lhs-forms)) + (rhs (list ,@rhs-forms))) + (let ((rhs-str (format-mode-line rhs))) + (list lhs + (propertize + " " 'display + `((space :align-to (- (+ right right-fringe right-margin) + ,(+ 1 (string-width rhs-str)))))) + rhs-str)))) + ,(unless (bound-and-true-p byte-compile-current-file) + `(let (byte-compile-warnings) + (byte-compile #',sym)))))) + +(defun doom-modeline (key) + "Returns a mode-line configuration associated with KEY (a symbol). Throws an +error if it doesn't exist." + (let ((fn (intern (format "doom-modeline-format--%s" key)))) + (when (functionp fn) + `(:eval (,fn))))) + +(defun doom-set-modeline (key &optional default) + "Set the modeline format. Does nothing if the modeline KEY doesn't exist. If +DEFAULT is non-nil, set the default mode-line for all buffers." + (when-let ((modeline (doom-modeline key))) + (setf (if default + (default-value 'mode-line-format) + (buffer-local-value 'mode-line-format (current-buffer))) + modeline))) + +(use-package eldoc-eval + :config + (defun +doom-modeline-eldoc (text) + (concat (when (display-graphic-p) + (+doom-modeline--make-xpm + (face-background 'doom-modeline-eldoc-bar nil t) + +doom-modeline-height + +doom-modeline-bar-width)) + text)) + + ;; Show eldoc in the mode-line with `eval-expression' + (defun +doom-modeline--show-eldoc (input) + "Display string STR in the mode-line next to minibuffer." + (with-current-buffer (eldoc-current-buffer) + (let* ((str (and (stringp input) input)) + (mode-line-format (or (and str (or (+doom-modeline-eldoc str) str)) + mode-line-format)) + mode-line-in-non-selected-windows) + (force-mode-line-update) + (sit-for eldoc-show-in-mode-line-delay)))) + (setq eldoc-in-minibuffer-show-fn #'+doom-modeline--show-eldoc) + + (eldoc-in-minibuffer-mode +1)) + +;; anzu and evil-anzu expose current/total state that can be displayed in the +;; mode-line. +(use-package anzu + :init + ;; (add-transient-hook! #'ex-start-search (require 'anzu)) + ;; (add-transient-hook! #'ex-start-word-search (require 'anzu)) + :config + (setq anzu-cons-mode-line-p nil + anzu-minimum-input-length 1 + anzu-search-threshold 250) + ;; Avoid anzu conflicts across buffers + (mapc #'make-variable-buffer-local + '(anzu--total-matched anzu--current-position anzu--state + anzu--cached-count anzu--cached-positions anzu--last-command + anzu--last-isearch-string anzu--overflow-p)) + ;; Ensure anzu state is cleared when searches & iedit are done + (add-hook 'isearch-mode-end-hook #'anzu--reset-status t) + ;; (add-hook '+evil-esc-hook #'anzu--reset-status t) + (add-hook 'iedit-mode-end-hook #'anzu--reset-status)) + + +;; Keep `+doom-modeline-current-window' up-to-date +(defvar +doom-modeline-current-window (frame-selected-window)) +(defun +doom-modeline|set-selected-window (&rest _) + "Sets `+doom-modeline-current-window' appropriately" + (when-let ((win (frame-selected-window))) + (unless (minibuffer-window-active-p win) + (setq +doom-modeline-current-window win)))) + +(add-hook 'window-configuration-change-hook #'+doom-modeline|set-selected-window) +(add-hook 'focus-in-hook #'+doom-modeline|set-selected-window) +(advice-add #'handle-switch-frame :after #'+doom-modeline|set-selected-window) +(advice-add #'select-window :after #'+doom-modeline|set-selected-window) + +;; fish-style modeline +(use-package shrink-path + :commands (shrink-path-prompt shrink-path-file-mixed)) + + +;; +;; Variables +;; + +(defvar +doom-modeline-height 29 + "How tall the mode-line should be (only respected in GUI emacs).") + +(defvar +doom-modeline-bar-width 3 + "How wide the mode-line bar should be (only respected in GUI emacs).") + +(defvar +doom-modeline-vspc + (propertize " " 'face 'variable-pitch) + "TODO") + +(defvar +doom-modeline-buffer-file-name-style 'truncate-upto-project + "Determines the style used by `+doom-modeline-buffer-file-name'. + +Given ~/Projects/FOSS/emacs/lisp/comint.el +truncate-upto-project => ~/P/F/emacs/lisp/comint.el +truncate-upto-root => ~/P/F/e/lisp/comint.el +truncate-all => ~/P/F/e/l/comint.el +relative-from-project => emacs/lisp/comint.el +relative-to-project => lisp/comint.el +file-name => comint.el") + +;; externs +(defvar anzu--state nil) +(defvar evil-mode nil) +(defvar evil-state nil) +(defvar evil-visual-selection nil) +(defvar iedit-mode nil) +(defvar all-the-icons-scale-factor) +(defvar all-the-icons-default-adjust) + + +;; +;; Custom faces +;; + +(defgroup +doom-modeline nil + "" + :group 'doom) + +(defface doom-modeline-buffer-path + '((t (:inherit (mode-line-emphasis bold)))) + "Face used for the dirname part of the buffer path." + :group '+doom-modeline) + +(defface doom-modeline-buffer-file + '((t (:inherit (mode-line-buffer-id bold)))) + "Face used for the filename part of the mode-line buffer path." + :group '+doom-modeline) + +(defface doom-modeline-buffer-modified + '((t (:inherit (error bold) :background nil))) + "Face used for the 'unsaved' symbol in the mode-line." + :group '+doom-modeline) + +(defface doom-modeline-buffer-major-mode + '((t (:inherit (mode-line-emphasis bold)))) + "Face used for the major-mode segment in the mode-line." + :group '+doom-modeline) + +(defface doom-modeline-highlight + '((t (:inherit mode-line-emphasis))) + "Face for bright segments of the mode-line." + :group '+doom-modeline) + +(defface doom-modeline-panel + '((t (:inherit mode-line-highlight))) + "Face for 'X out of Y' segments, such as `+doom-modeline--anzu', `+doom-modeline--evil-substitute' and +`iedit'" + :group '+doom-modeline) + +(defface doom-modeline-info + `((t (:inherit (success bold)))) + "Face for info-level messages in the modeline. Used by `*vc'." + :group '+doom-modeline) + +(defface doom-modeline-warning + `((t (:inherit (warning bold)))) + "Face for warnings in the modeline. Used by `*flycheck'" + :group '+doom-modeline) + +(defface doom-modeline-urgent + `((t (:inherit (error bold)))) + "Face for errors in the modeline. Used by `*flycheck'" + :group '+doom-modeline) + +;; Bar +(defface doom-modeline-bar '((t (:inherit highlight))) + "The face used for the left-most bar on the mode-line of an active window." + :group '+doom-modeline) + +(defface doom-modeline-eldoc-bar '((t (:inherit shadow))) + "The face used for the left-most bar on the mode-line when eldoc-eval is +active." + :group '+doom-modeline) + +(defface doom-modeline-inactive-bar '((t (:inherit warning :inverse-video t))) + "The face used for the left-most bar on the mode-line of an inactive window." + :group '+doom-modeline) + + +;; +;; Modeline helpers +;; + +(defsubst active () + (eq (selected-window) +doom-modeline-current-window)) + +;; Inspired from `powerline's `pl/make-xpm'. +(defun +doom-modeline--make-xpm (color height width) + "Create an XPM bitmap." + (propertize + " " 'display + (let ((data (make-list height (make-list width 1))) + (color (or color "None"))) + (create-image + (concat + (format "/* XPM */\nstatic char * percent[] = {\n\"%i %i 2 1\",\n\". c %s\",\n\" c %s\"," + (length (car data)) + (length data) + color + color) + (apply #'concat + (cl-loop with idx = 0 + with len = (length data) + for dl in data + do (cl-incf idx) + collect + (concat "\"" + (cl-loop for d in dl + if (= d 0) collect (string-to-char " ") + else collect (string-to-char ".")) + (if (eq idx len) "\"};" "\",\n"))))) + 'xpm t :ascent 'center)))) + +(defun +doom-modeline-buffer-file-name () + "Propertized `buffer-file-name' based on `+doom-modeline-buffer-file-name-style'." + (propertize + (pcase +doom-modeline-buffer-file-name-style + ('truncate-upto-project (+doom-modeline--buffer-file-name 'shrink)) + ('truncate-upto-root (+doom-modeline--buffer-file-name-truncate)) + ('truncate-all (+doom-modeline--buffer-file-name-truncate t)) + ('relative-to-project (+doom-modeline--buffer-file-name-relative)) + ('relative-from-project (+doom-modeline--buffer-file-name-relative 'include-project)) + ('file-name (propertize (file-name-nondirectory buffer-file-name) + 'face + (let ((face (or (and (buffer-modified-p) + 'doom-modeline-buffer-modified) + (and (active) + 'doom-modeline-buffer-file)))) + (when face `(:inherit ,face)))))) + 'help-echo buffer-file-truename)) + +(defun +doom-modeline--buffer-file-name-truncate (&optional truncate-tail) + "Propertized `buffer-file-name' that truncates every dir along path. +If TRUNCATE-TAIL is t also truncate the parent directory of the file." + (let ((dirs (shrink-path-prompt (file-name-directory buffer-file-truename))) + (active (active))) + (if (null dirs) + (propertize "%b" 'face (if active 'doom-modeline-buffer-file)) + (let ((modified-faces (if (buffer-modified-p) 'doom-modeline-buffer-modified))) + (let ((dirname (car dirs)) + (basename (cdr dirs)) + (dir-faces (or modified-faces (if active 'doom-modeline-project-root-dir))) + (file-faces (or modified-faces (if active 'doom-modeline-buffer-file)))) + (concat (propertize (concat dirname + (if truncate-tail (substring basename 0 1) basename) + "/") + 'face (if dir-faces `(:inherit ,dir-faces))) + (propertize (file-name-nondirectory buffer-file-name) + 'face (if file-faces `(:inherit ,file-faces))))))))) + +(defun +doom-modeline--buffer-file-name-relative (&optional include-project) + "Propertized `buffer-file-name' showing directories relative to project's root only." + (let ((root (projectile-project-root)) + (active (active))) + (if (null root) + (propertize "%b" 'face (if active 'doom-modeline-buffer-file)) + (let* ((modified-faces (if (buffer-modified-p) 'doom-modeline-buffer-modified)) + (relative-dirs (file-relative-name (file-name-directory buffer-file-truename) + (if include-project (concat root "../") root))) + (relative-faces (or modified-faces (if active 'doom-modeline-buffer-path))) + (file-faces (or modified-faces (if active 'doom-modeline-buffer-file)))) + (if (equal "./" relative-dirs) (setq relative-dirs "")) + (concat (propertize relative-dirs 'face (if relative-faces `(:inherit ,relative-faces))) + (propertize (file-name-nondirectory buffer-file-truename) + 'face (if file-faces `(:inherit ,file-faces)))))))) + +(defun +doom-modeline--buffer-file-name (truncate-project-root-parent) + "Propertized `buffer-file-name'. +If TRUNCATE-PROJECT-ROOT-PARENT is t space will be saved by truncating it down +fish-shell style. + +Example: +~/Projects/FOSS/emacs/lisp/comint.el => ~/P/F/emacs/lisp/comint.el" + (let* ((project-root (projectile-project-root)) + (file-name-split (shrink-path-file-mixed project-root + (file-name-directory buffer-file-truename) + buffer-file-truename)) + (active (active))) + (if (null file-name-split) + (propertize "%b" 'face (if active 'doom-modeline-buffer-file)) + (pcase-let ((`(,root-path-parent ,project ,relative-path ,filename) file-name-split)) + (let ((modified-faces (if (buffer-modified-p) 'doom-modeline-buffer-modified))) + (let ((sp-faces (or modified-faces (if active 'font-lock-comment-face))) + (project-faces (or modified-faces (if active 'font-lock-string-face))) + (relative-faces (or modified-faces (if active 'doom-modeline-buffer-path))) + (file-faces (or modified-faces (if active 'doom-modeline-buffer-file)))) + (let ((sp-props `(,@(if sp-faces `(:inherit ,sp-faces)) ,@(if active '(:weight bold)))) + (project-props `(,@(if project-faces `(:inherit ,project-faces)) ,@(if active '(:weight bold)))) + (relative-props `(,@(if relative-faces `(:inherit ,relative-faces)))) + (file-props `(,@(if file-faces `(:inherit ,file-faces))))) + (concat (propertize (if truncate-project-root-parent + root-path-parent + (abbreviate-file-name project-root)) + 'face sp-props) + (propertize (concat project "/") 'face project-props) + (if relative-path (propertize relative-path 'face relative-props)) + (propertize filename 'face file-props))))))))) + + +;; +;; Segments +;; + +(def-modeline-segment! buffer-default-directory + "Displays `default-directory'. This is for special buffers like the scratch +buffer where knowing the current project directory is important." + (let ((face (if (active) 'doom-modeline-buffer-path))) + (concat (if (display-graphic-p) " ") + (all-the-icons-octicon + "file-directory" + :face face + :v-adjust -0.05 + :height 1.25) + (propertize (concat " " (abbreviate-file-name default-directory)) + 'face face)))) + +;; +(def-modeline-segment! buffer-info + "Combined information about the current buffer, including the current working +directory, the file name, and its state (modified, read-only or non-existent)." + (concat (cond (buffer-read-only + (concat (all-the-icons-octicon + "lock" + :face 'doom-modeline-warning + :v-adjust -0.05) + " ")) + ((buffer-modified-p) + (concat (all-the-icons-faicon + "floppy-o" + :face 'doom-modeline-buffer-modified + :v-adjust -0.0575) + " ")) + ((and buffer-file-name + (not (file-exists-p buffer-file-name))) + (concat (all-the-icons-octicon + "circle-slash" + :face 'doom-modeline-urgent + :v-adjust -0.05) + " ")) + ((buffer-narrowed-p) + (concat (all-the-icons-octicon + "fold" + :face 'doom-modeline-warning + :v-adjust -0.05) + " "))) + (if buffer-file-name + (+doom-modeline-buffer-file-name) + "%b"))) + +;; +(def-modeline-segment! buffer-info-simple + "Display only the current buffer's name, but with fontification." + (propertize + "%b" + 'face (cond ((and buffer-file-name (buffer-modified-p)) + 'doom-modeline-buffer-modified) + ((active) 'doom-modeline-buffer-file)))) + +;; +(def-modeline-segment! buffer-encoding + "Displays the encoding and eol style of the buffer the same way Atom does." + (concat (pcase (coding-system-eol-type buffer-file-coding-system) + (0 "LF ") + (1 "CRLF ") + (2 "CR ")) + (let ((sys (coding-system-plist buffer-file-coding-system))) + (cond ((memq (plist-get sys :category) '(coding-category-undecided coding-category-utf-8)) + "UTF-8") + (t (upcase (symbol-name (plist-get sys :name)))))) + " ")) + +;; +(def-modeline-segment! major-mode + "The major mode, including process, environment and text-scale info." + (propertize + (concat (format-mode-line mode-name) + (when (stringp mode-line-process) + mode-line-process) + (and (featurep 'face-remap) + (/= text-scale-mode-amount 0) + (format " (%+d)" text-scale-mode-amount))) + 'face (if (active) 'doom-modeline-buffer-major-mode))) + +;; +(def-modeline-segment! vcs + "Displays the current branch, colored based on its state." + (when (and vc-mode buffer-file-name) + (let* ((backend (vc-backend buffer-file-name)) + (state (vc-state buffer-file-name backend))) + (let ((face 'mode-line-inactive) + (active (active)) + (all-the-icons-default-adjust -0.1)) + (concat " " + (cond ((memq state '(edited added)) + (if active (setq face 'doom-modeline-info)) + (all-the-icons-octicon + "git-compare" + :face face + :v-adjust -0.05)) + ((eq state 'needs-merge) + (if active (setq face 'doom-modeline-info)) + (all-the-icons-octicon "git-merge" :face face)) + ((eq state 'needs-update) + (if active (setq face 'doom-modeline-warning)) + (all-the-icons-octicon "arrow-down" :face face)) + ((memq state '(removed conflict unregistered)) + (if active (setq face 'doom-modeline-urgent)) + (all-the-icons-octicon "alert" :face face)) + (t + (if active (setq face 'font-lock-doc-face)) + (all-the-icons-octicon + "git-compare" + :face face + :v-adjust -0.05))) + " " + (propertize (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2)) + 'face (if active face)) + " "))))) + +;; +(defun +doom-ml-icon (icon &optional text face voffset) + "Displays an octicon ICON with FACE, followed by TEXT. Uses +`all-the-icons-octicon' to fetch the icon." + (concat (if vc-mode " " " ") + (when icon + (concat + (all-the-icons-material icon :face face :height 1.1 :v-adjust (or voffset -0.2)) + (if text +doom-modeline-vspc))) + (when text + (propertize text 'face face)) + (if vc-mode " " " "))) + +(def-modeline-segment! flycheck + "Displays color-coded flycheck error status in the current buffer with pretty +icons." + (when (boundp 'flycheck-last-status-change) + (pcase flycheck-last-status-change + ('finished (if flycheck-current-errors + (let-alist (flycheck-count-errors flycheck-current-errors) + (let ((sum (+ (or .error 0) (or .warning 0)))) + (+doom-ml-icon "do_not_disturb_alt" + (number-to-string sum) + (if .error 'doom-modeline-urgent 'doom-modeline-warning) + -0.25))) + (+doom-ml-icon "check" nil 'doom-modeline-info))) + ('running (+doom-ml-icon "access_time" nil 'font-lock-doc-face -0.25)) + ('no-checker (+doom-ml-icon "sim_card_alert" "-" 'font-lock-doc-face)) + ('errored (+doom-ml-icon "sim_card_alert" "Error" 'doom-modeline-urgent)) + ('interrupted (+doom-ml-icon "pause" "Interrupted" 'font-lock-doc-face))))) +;; ('interrupted (+doom-ml-icon "x" "Interrupted" 'font-lock-doc-face))))) + +;; +(defsubst doom-column (pos) + (save-excursion (goto-char pos) + (current-column))) + +(def-modeline-segment! selection-info + "Information about the current selection, such as how many characters and +lines are selected, or the NxM dimensions of a block selection." + (when (and (active) (or mark-active (eq evil-state 'visual))) + (let ((reg-beg (region-beginning)) + (reg-end (region-end))) + (propertize + (let ((lines (count-lines reg-beg (min (1+ reg-end) (point-max))))) + (cond ((or (bound-and-true-p rectangle-mark-mode) + (eq 'block evil-visual-selection)) + (let ((cols (abs (- (doom-column reg-end) + (doom-column reg-beg))))) + (format "%dx%dB" lines cols))) + ((eq 'line evil-visual-selection) + (format "%dL" lines)) + ((> lines 1) + (format "%dC %dL" (- (1+ reg-end) reg-beg) lines)) + (t + (format "%dC" (- (1+ reg-end) reg-beg))))) + 'face 'doom-modeline-highlight)))) + + +;; +(defun +doom-modeline--macro-recording () + "Display current Emacs or evil macro being recorded." + (when (and (active) (or defining-kbd-macro executing-kbd-macro)) + (let ((sep (propertize " " 'face 'doom-modeline-panel))) + (concat sep + (propertize (if (bound-and-true-p evil-this-macro) + (char-to-string evil-this-macro) + "Macro") + 'face 'doom-modeline-panel) + sep + (all-the-icons-octicon "triangle-right" + :face 'doom-modeline-panel + :v-adjust -0.05) + sep)))) + +(defsubst +doom-modeline--anzu () + "Show the match index and total number thereof. Requires `anzu', also +`evil-anzu' if using `evil-mode' for compatibility with `evil-search'." + (when (and anzu--state (not iedit-mode)) + (propertize + (let ((here anzu--current-position) + (total anzu--total-matched)) + (cond ((eq anzu--state 'replace-query) + (format " %d replace " total)) + ((eq anzu--state 'replace) + (format " %d/%d " here total)) + (anzu--overflow-p + (format " %s+ " total)) + (t + (format " %s/%d " here total)))) + 'face (if (active) 'doom-modeline-panel)))) + +(defsubst +doom-modeline--evil-substitute () + "Show number of matches for evil-ex substitutions and highlights in real time." + (when (and evil-mode + (or (assq 'evil-ex-substitute evil-ex-active-highlights-alist) + (assq 'evil-ex-global-match evil-ex-active-highlights-alist) + (assq 'evil-ex-buffer-match evil-ex-active-highlights-alist))) + (propertize + (let ((range (if evil-ex-range + (cons (car evil-ex-range) (cadr evil-ex-range)) + (cons (line-beginning-position) (line-end-position)))) + (pattern (car-safe (evil-delimited-arguments evil-ex-argument 2)))) + (if pattern + (format " %s matches " (how-many pattern (car range) (cdr range))) + " - ")) + 'face (if (active) 'doom-modeline-panel)))) + +(defun doom-themes--overlay-sort (a b) + (< (overlay-start a) (overlay-start b))) + +(defsubst +doom-modeline--iedit () + "Show the number of iedit regions matches + what match you're on." + (when (and iedit-mode iedit-occurrences-overlays) + (propertize + (let ((this-oc (or (let ((inhibit-message t)) + (iedit-find-current-occurrence-overlay)) + (progn (iedit-prev-occurrence) + (iedit-find-current-occurrence-overlay)))) + (length (length iedit-occurrences-overlays))) + (format " %s/%d " + (if this-oc + (- length + (length (memq this-oc (sort (append iedit-occurrences-overlays nil) + #'doom-themes--overlay-sort))) + -1) + "-") + length)) + 'face (if (active) 'doom-modeline-panel)))) + +(def-modeline-segment! matches + "Displays: 1. the currently recording macro, 2. A current/total for the +current search term (with anzu), 3. The number of substitutions being conducted +with `evil-ex-substitute', and/or 4. The number of active `iedit' regions." + (let ((meta (concat (+doom-modeline--macro-recording) + (+doom-modeline--anzu) + (+doom-modeline--evil-substitute) + (+doom-modeline--iedit)))) + (or (and (not (equal meta "")) meta) + (if buffer-file-name " %I ")))) + +;; TODO Include other information +(def-modeline-segment! media-info + "Metadata regarding the current file, such as dimensions for images." + (cond ((eq major-mode 'image-mode) + (cl-destructuring-bind (width . height) + (image-size (image-get-display-property) :pixels) + (format " %dx%d " width height))))) + +(def-modeline-segment! bar + "The bar regulates the height of the mode-line in GUI Emacs. +Returns \"\" to not break --no-window-system." + (if (display-graphic-p) + (+doom-modeline--make-xpm + (face-background (if (active) + 'doom-modeline-bar + 'doom-modeline-inactive-bar) + nil t) + +doom-modeline-height + +doom-modeline-bar-width) + "")) + + +;; +;; Mode lines +;; + +(def-modeline! main + (bar matches " " buffer-info " %l:%c %p " selection-info) + (buffer-encoding major-mode vcs flycheck)) + +(def-modeline! minimal + (bar matches " " buffer-info) + (media-info major-mode)) + +(def-modeline! special + (bar matches " " buffer-info-simple " %l:%c %p " selection-info) + (buffer-encoding major-mode flycheck)) + +(def-modeline! project + (bar buffer-default-directory) + (major-mode)) + +(def-modeline! media + (bar " %b ") + (media-info major-mode)) + + +;; +;; Hooks +;; + +(defun +doom-modeline|init () + "Set the default modeline." + (doom-set-modeline 'main t) + + ;; This scratch buffer is already created and doesn't get a modeline. For the + ;; love of Emacs, someone give the man a modeline! + (with-current-buffer "*scratch*" + (doom-set-modeline 'main))) + +(defun +doom-modeline|set-special-modeline () + (doom-set-modeline 'special)) + +(defun +doom-modeline|set-media-modeline () + (doom-set-modeline 'media)) + +(defun +doom-modeline|set-project-modeline () + (doom-set-modeline 'project)) + + +;; +;; Bootstrap +;; + +(add-hook 'emacs-startup-hook #'+doom-modeline|init) +;; (add-hook 'doom-scratch-buffer-hook #'+doom-modeline|set-special-modeline) +;; (add-hook '+doom-dashboard-mode-hook #'+doom-modeline|set-project-modeline) + +(add-hook 'image-mode-hook #'+doom-modeline|set-media-modeline) +(add-hook 'org-src-mode-hook #'+doom-modeline|set-special-modeline) +(add-hook 'circe-mode-hook #'+doom-modeline|set-special-modeline) diff --git a/init.elc b/init.elc new file mode 100644 index 0000000..0fc8336 Binary files /dev/null and b/init.elc differ