├── .zshenv ├── .hammerspoon ├── caffeine-active.png ├── caffeine-inactive.png ├── utils.lua ├── init.lua └── Spoons │ └── SpoonInstall.spoon │ └── init.lua ├── .gitconfig ├── .latexmkrc ├── .mpdconf ├── .emacs.d ├── lisp │ ├── init-locales.el │ ├── setup-flycheck.el │ ├── setup-yasnippet.el │ ├── setup-hydra.el │ ├── setup-jump.el │ ├── init-fonts.el │ ├── setup-spellcheck.el │ ├── setup-company.el │ ├── init-utils.el │ ├── init-mac.el │ ├── setup-music.el │ ├── setup-pdf.el │ ├── init-package.el │ ├── setup-git.el │ ├── init-core.el │ ├── init-frames.el │ ├── setup-projectile.el │ ├── setup-ivy.el │ ├── setup-tex.el │ ├── init-evil.el │ ├── init-editor.el │ ├── init-theme.el │ ├── init-ui.el │ ├── init-keybindings.el │ ├── init-windows.el │ └── setup-org.el ├── early-init.el └── init.el ├── .config ├── imapnotify │ ├── anand.iyer.p@gmail.com.js │ ├── bmail.js │ └── anand.padmanabha.iyer@gmail.com.js ├── afew │ └── config └── yabai │ └── yabairc ├── .msmtprc ├── .tmux.conf ├── .notmuch-config ├── .chunkwmrc ├── .dotfiles └── README.md ├── .vimrc ├── .mbsyncrc ├── .gitignore └── .zshrc /.zshenv: -------------------------------------------------------------------------------- 1 | export PATH="/usr/local/bin:/usr/local/sbin:$PATH" 2 | export PATH="$HOME/.cargo/bin:$PATH" 3 | -------------------------------------------------------------------------------- /.hammerspoon/caffeine-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anandpiyer/.dotfiles/HEAD/.hammerspoon/caffeine-active.png -------------------------------------------------------------------------------- /.hammerspoon/caffeine-inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anandpiyer/.dotfiles/HEAD/.hammerspoon/caffeine-inactive.png -------------------------------------------------------------------------------- /.gitconfig: -------------------------------------------------------------------------------- 1 | [user] 2 | email = anand.iyer@berkeley.edu 3 | [credential] 4 | helper = osxkeychain 5 | [core] 6 | excludesfile = /Users/api/.gitignore 7 | editor = emacsclient -c 8 | -------------------------------------------------------------------------------- /.latexmkrc: -------------------------------------------------------------------------------- 1 | # Generate pdf using pdflatex (-pdf) 2 | $pdf_mode = 1; 3 | 4 | # Use bibtex if a .bib file exists 5 | $bibtex_use = 1; 6 | 7 | $pdflatex = 'pdflatex -shell-escape -synctex=1 %O %S'; 8 | $pdf_previewer = 'open -a skim'; 9 | $clean_ext = "bbl rel out synctex.gz log %R-blx.bib %R.synctex.gz"; 10 | -------------------------------------------------------------------------------- /.mpdconf: -------------------------------------------------------------------------------- 1 | music_directory "~/Music/beets" 2 | playlist_directory "~/Music/beets" 3 | db_file "~/.mpd/mpd.db" 4 | log_file "~/.mpd/mpd.log" 5 | pid_file "~/.mpd/mpd.pid" 6 | state_file "~/.mpd/mpd.state" 7 | sticker_file "~/.mpd/sticker.sql" 8 | 9 | bind_to_address "127.0.0.1" 10 | port "6600" 11 | user "api" 12 | 13 | auto_update "yes" 14 | auto_update_depth "2" 15 | follow_outside_symlinks "yes" 16 | follow_inside_symlinks "yes" 17 | 18 | audio_output { 19 | type "osx" 20 | name "CoreAudio" 21 | mixer_type "software" 22 | } -------------------------------------------------------------------------------- /.emacs.d/lisp/init-locales.el: -------------------------------------------------------------------------------- 1 | ;;; init-locales.el --- locales settings -*- lexical-binding: t; -*- 2 | ;;; Commentary: 3 | ;;; Code: 4 | 5 | ;;------------------------------------------------------------------------------ 6 | ;; Prefer UTF-8 everywhere. 7 | ;;------------------------------------------------------------------------------ 8 | (set-language-environment 'utf-8) 9 | (prefer-coding-system 'utf-8) 10 | (set-default-coding-systems 'utf-8) 11 | (setq locale-coding-system 'utf-8) 12 | (set-terminal-coding-system 'utf-8) 13 | (set-keyboard-coding-system 'utf-8) 14 | (set-selection-coding-system 'utf-8) 15 | (setq-default buffer-file-coding-system 'utf-8) 16 | 17 | (provide 'init-locales) 18 | ;;; init-locales.el ends here 19 | -------------------------------------------------------------------------------- /.hammerspoon/utils.lua: -------------------------------------------------------------------------------- 1 | -- Merge two tables, overwriting entires in the first one 2 | -- in case of a conflict. 3 | function table_merge(t1, t2) 4 | for k,v in pairs(t2) do 5 | if type(v) == "table" then 6 | if type(t1[k] or false) == "table" then 7 | table_merge(t1[k] or {}, t2[k] or {}) 8 | else 9 | t1[k] = v 10 | end 11 | else 12 | t1[k] = v 13 | end 14 | end 15 | return t1 16 | end 17 | 18 | function table_concat(t1, t2) 19 | for i=1,#t2 do 20 | t1[#t1+1] = t2[i] 21 | end 22 | return t1 23 | end 24 | 25 | function table_length(t) 26 | local count = 0 27 | for _ in pairs(t) do count = count + 1 end 28 | return count 29 | end 30 | -------------------------------------------------------------------------------- /.config/imapnotify/anand.iyer.p@gmail.com.js: -------------------------------------------------------------------------------- 1 | var child_process = require('child_process'); 2 | 3 | function getStdout(cmd) { 4 | var stdout = child_process.execSync(cmd); 5 | return stdout.toString().trim(); 6 | } 7 | 8 | exports.host = "imap.gmail.com"; 9 | exports.port = 993; 10 | exports.tls = true; 11 | exports.tlsOptions = { "rejectUnauthorized": false }; 12 | exports.username = "anand.iyer.p@gmail.com"; 13 | exports.password = getStdout("security find-generic-password -s emacs-email -a anand.iyer.p@gmail.com -w") 14 | exports.onNotify = "afew -m; mbsync -q anand.iyer.p@gmail.com"; 15 | exports.onNotifyPost = {"mail": "terminal-notifier -message 'has new mail.' -title 'anand.iyer.p@gmail.com'; notmuch new; emacsclient -e '(mu4e-update-index)'"}; 16 | exports.boxes = ["INBOX"]; 17 | -------------------------------------------------------------------------------- /.config/imapnotify/bmail.js: -------------------------------------------------------------------------------- 1 | var child_process = require('child_process'); 2 | 3 | function getStdout(cmd) { 4 | var stdout = child_process.execSync(cmd); 5 | return stdout.toString().trim(); 6 | } 7 | 8 | exports.host = "imap.gmail.com"; 9 | exports.port = 993; 10 | exports.tls = true; 11 | exports.tlsOptions = { "rejectUnauthorized": false }; 12 | exports.username = "anand.iyer@berkeley.edu"; 13 | exports.password = getStdout("security find-generic-password -s emacs-email -a anand.iyer@berkeley.edu -w") 14 | exports.onNotify = "afew -m && mbsync --push -q bmail && mbsync --pull -q bmail"; 15 | exports.onNotifyPost = {"mail": "notmuch new && emacsclient -e '(mu4e-update-index)' && terminal-notifier -message 'has new mail.' -title 'berkeley.edu'"}; 16 | exports.boxes = ["INBOX"]; 17 | -------------------------------------------------------------------------------- /.config/imapnotify/anand.padmanabha.iyer@gmail.com.js: -------------------------------------------------------------------------------- 1 | var child_process = require('child_process'); 2 | 3 | function getStdout(cmd) { 4 | var stdout = child_process.execSync(cmd); 5 | return stdout.toString().trim(); 6 | } 7 | 8 | exports.host = "imap.gmail.com"; 9 | exports.port = 993; 10 | exports.tls = true; 11 | exports.tlsOptions = { "rejectUnauthorized": false }; 12 | exports.username = "anand.padmanabha.iyer@gmail.com"; 13 | exports.password = getStdout("security find-generic-password -s emacs-email -a anand.padmanabha.iyer@gmail.com -w") 14 | exports.onNotify = "afew -m; mbsync -q anand.padmanabha.iyer@gmail.com"; 15 | exports.onNotifyPost = {"mail": "terminal-notifier -message 'has new mail.' -title 'anand.padmanabha.iyer@gmail.com'; notmuch new; emacsclient -e '(mu4e-update-index)'"}; 16 | exports.boxes = ["INBOX"]; 17 | -------------------------------------------------------------------------------- /.emacs.d/early-init.el: -------------------------------------------------------------------------------- 1 | (unless noninteractive 2 | (defvar api--file-name-handler-alist file-name-handler-alist) 3 | (unless after-init-time 4 | (setq gc-cons-threshold (* 512 1024 1024) 5 | gc-cons-percentage 0.6 6 | file-name-handler-alist nil 7 | auto-window-vscroll nil) 8 | (defun api|reset-gc () 9 | (setq gc-cons-threshold (* 16 1024 1024) 10 | gc-cons-percentage 0.1 11 | file-name-handler-alist api--file-name-handler-alist)) 12 | (add-hook 'emacs-startup-hook #'api|reset-gc))) 13 | 14 | (setq user-emacs-directory (file-name-directory load-file-name) 15 | package-enable-at-startup nil 16 | ;;package-quickstart t 17 | load-prefer-newer noninteractive) 18 | 19 | (if (fboundp 'tool-bar-mode) (tool-bar-mode -1)) 20 | (if (fboundp 'scroll-bar-mode) (scroll-bar-mode -1)) 21 | (if (fboundp 'tooltip-mode) (tooltip-mode -1)) 22 | (unless (display-graphic-p) (menu-bar-mode -1)) 23 | -------------------------------------------------------------------------------- /.config/afew/config: -------------------------------------------------------------------------------- 1 | [ArchiveSentMailsFilter] 2 | 3 | [InboxFilter] 4 | 5 | [MailMover] 6 | folders = anand.ebiz@gmail.com/inbox anand.ebiz@gmail.com/all anand.padmanabha.iyer@gmail.com/inbox anand.padmanabha.iyer@gmail.com/all bmail/inbox bmail/all anand.iyer.p@gmail.com/inbox anand.iyer.p@gmail.com/all 7 | rename = True 8 | 9 | # rules 10 | anand.ebiz@gmail.com/inbox = 'tag:trash':anand.ebiz@gmail.com/trash 'NOT tag:inbox':anand.ebiz@gmail.com/all 11 | anand.ebiz@gmail.com/all = 'tag:trash':anand.ebiz@gmail.com/trash 12 | anand.padmanabha.iyer@gmail.com/inbox = 'tag:trash':anand.padmanabha.iyer@gmail.com/trash 'NOT tag:inbox':anand.padmanabha.iyer@gmail.com/all 13 | anand.padmanabha.iyer@gmail.com/all = 'tag:trash':anand.padmanabha.iyer@gmail.com/trash 14 | anand.iyer.p@gmail.com/inbox = 'tag:trash':anand.iyer.p@gmail.com/trash 'NOT tag:inbox':anand.iyer.p@gmail.com/all 15 | anand.iyer.p@gmail.com/all = 'tag:trash':anand.iyer.p@gmail.com/trash 16 | bmail/inbox = 'tag:trash':bmail/trash 'NOT tag:inbox':bmail/all 17 | bmail/all = 'tag:trash':bmail/trash -------------------------------------------------------------------------------- /.emacs.d/lisp/setup-flycheck.el: -------------------------------------------------------------------------------- 1 | ;;; setup-flycheck.el --- Flycheck -*- lexical-binding: t; -*- 2 | ;;; Commentary: 3 | ;;; Code: 4 | 5 | (use-package flycheck 6 | :diminish (flycheck-mode . " ⓢ") 7 | :commands (flycheck-mode 8 | flycheck-list-errors 9 | flycheck-buffer) 10 | :init 11 | ;; Turn on `flycheck-mode' for programming modes. 12 | (add-hook 'prog-mode-hook #'flycheck-mode) 13 | 14 | ;; Check the buffer when `ESC' is pressed. 15 | (defun api|flycheck-buffer () 16 | (when flycheck-mode 17 | (ignore-errors (flycheck-buffer)) 18 | nil)) 19 | 20 | (after! evil 21 | (add-hook '+evil-esc-hook #'api|flycheck-buffer t)) 22 | 23 | :config 24 | (setq flycheck-indication-mode 'right-fringe 25 | flycheck-check-syntax-automatically '(save idle mode-enabled)) 26 | 27 | (fringe-helper-define 'flycheck-fringe-bitmap-double-arrow 'center 28 | "...X...." 29 | "..XX...." 30 | ".XXX...." 31 | "XXXX...." 32 | ".XXX...." 33 | "..XX...." 34 | "...X....")) 35 | 36 | (provide 'setup-flycheck) 37 | 38 | ;;; setup-flycheck.el ends here 39 | -------------------------------------------------------------------------------- /.emacs.d/lisp/setup-yasnippet.el: -------------------------------------------------------------------------------- 1 | ;;; setup-yasnippet.el --- yanippet related setup -*- lexical-binding: t; -*- 2 | ;;; Commentary: 3 | ;;; Code: 4 | 5 | (use-package yasnippet 6 | :diminish yas-minor-mode 7 | :commands (yas-minor-mode yas-minor-mode-on yas-expand yas-expand-snippet 8 | yas-lookup-snippet yas-insert-snippet yas-new-snippet 9 | yas-visit-snippet-file snippet-mode) 10 | :preface (defvar yas-minor-mode-map (make-sparse-keymap)) 11 | :init 12 | (add-hook 'yas-minor-mode-hook #'yas-reload-all) 13 | (add-hook 'text-mode-hook #'yas-minor-mode-on) 14 | (add-hook 'prog-mode-hook #'yas-minor-mode-on) 15 | (add-hook 'latex-mode-hook #'yas-minor-mode-on) 16 | (add-hook 'snippet-mode-hook #'yas-minor-mode-on) 17 | (add-hook 'org-mode-hook #'yas-minor-mode-on) 18 | 19 | :config 20 | (setq yas-verbosity 0 21 | yas-also-auto-indent-first-line t 22 | yas-prompt-functions (delq 'yas-dropdown-prompt yas-prompt-functions) 23 | yas-triggers-in-field t) 24 | 25 | ;; fix an error caused by smartparens interfering with yasnippet bindings 26 | (advice-add #'yas-expand :before #'sp-remove-active-pair-overlay) 27 | 28 | ;; Exit snippets on ESC from normal mode 29 | (add-hook '+evil-esc-hook #'yas-exit-all-snippets)) 30 | 31 | ;(use-package yasnippet-snippets 32 | ;:defer t 33 | ; :after yasnippet) 34 | 35 | (provide 'setup-yasnippet) 36 | ;;; setup-yasnippet ends here 37 | -------------------------------------------------------------------------------- /.emacs.d/lisp/setup-hydra.el: -------------------------------------------------------------------------------- 1 | ;;; setup-hydra.el --- Hydra -*- lexical-binding: t; -*- 2 | ;; 3 | ;;; Commentary: 4 | ;; 5 | ;; Hydra related settings 6 | ;; 7 | ;;; Code: 8 | 9 | (defhydra api/themes-hydra (:hint nil :color pink :columns 3) 10 | " 11 | Themes 12 | 13 | ^Gruvbox^ ^Material^ ^Other^ ^Solarized^ 14 | ---------------------------------------------------- 15 | _g_: Dark _m_: Dark _z_: Zenburn _s_: Dark 16 | _G_: Light _M_: Light _s_: Seoul256 _S_: Light 17 | _n_: Nord 18 | " 19 | ("g" (load-theme 'gruvbox-dark-soft t)) 20 | ("G" (load-theme 'gruvbox-light t)) 21 | ("m" (load-theme 'material t)) 22 | ("M" (load-theme 'material-light t)) 23 | ("s" (load-theme 'solarized-dark t)) 24 | ("S" (load-theme 'solarized-light t)) 25 | ("z" (load-theme 'zenburn t)) 26 | ("s" (load-theme 'seoul256 t)) 27 | ("n" (load-theme 'nord t)) 28 | ("RET" nil "done" :color blue)) 29 | 30 | (use-package multiple-cursors 31 | :defer t) 32 | 33 | (defhydra api/multiple-cursors-hydra (:hint nil) 34 | " 35 | ^Up^ ^Down^ ^Miscellaneous^ 36 | ---------------------------------------------- 37 | [_p_] Next [_n_] Next [_l_] Edit lines 38 | [_P_] Skip [_N_] Skip [_a_] Mark all 39 | [_M-p_] Unmark [_M-n_] Unmark [_q_] Quit" 40 | ("l" mc/edit-lines :exit t) 41 | ("a" mc/mark-all-like-this :exit t) 42 | ("n" mc/mark-next-like-this) 43 | ("N" mc/skip-to-next-like-this) 44 | ("M-n" mc/unmark-next-like-this) 45 | ("p" mc/mark-previous-like-this) 46 | ("P" mc/skip-to-previous-like-this) 47 | ("M-p" mc/unmark-previous-like-this) 48 | ("q" nil)) 49 | 50 | (provide 'setup-hydra) 51 | ;;; setup-hydra.el ends here 52 | -------------------------------------------------------------------------------- /.msmtprc: -------------------------------------------------------------------------------- 1 | # Set default values for all following accounts. 2 | defaults 3 | auth on 4 | tls on 5 | logfile ~/.msmtp.log 6 | 7 | # Bmail (anand.iyer@berkeley.edu) 8 | account bmail 9 | host smtp.gmail.com 10 | port 587 11 | tls_certcheck off 12 | from anand.iyer@berkeley.edu 13 | user anand.iyer@berkeley.edu 14 | passwordeval "security find-generic-password -s emacs-email -a anand.iyer@berkeley.edu -w" 15 | 16 | # Bmail alias 17 | account bmail.cs : bmail 18 | from api@cs.berkeley.edu 19 | account bmail.eecs : bmail 20 | from api@eecs.berkeley.edu 21 | 22 | # Gmail (anand.padmanabha.iyer@gmail.com) 23 | account anand.padmanabha.iyer@gmail.com 24 | host smtp.gmail.com 25 | port 587 26 | tls_certcheck off 27 | from anand.padmanabha.iyer@gmail.com 28 | user anand.padmanabha.iyer@gmail.com 29 | passwordeval "security find-generic-password -s emacs-email -a anand.padmanabha.iyer@gmail.com -w" 30 | 31 | # Gmail (anand.iyer.p@gmail.com) 32 | account anand.iyer.p@gmail.com 33 | host smtp.gmail.com 34 | port 587 35 | tls_certcheck off 36 | from anand.iyer.p@gmail.com 37 | user anand.iyer.p@gmail.com 38 | passwordeval "security find-generic-password -s emacs-email -a anand.iyer.p@gmail.com -w" 39 | 40 | # Gmail (anand.ebiz@gmail.com) 41 | account anand.ebiz@gmail.com 42 | host smtp.gmail.com 43 | port 587 44 | tls_certcheck off 45 | from anand.ebiz@gmail.com 46 | user anand.ebiz@gmail.com 47 | passwordeval "security find-generic-password -s emacs-email -a anand.ebiz@gmail.com -w" 48 | 49 | # Set a default account 50 | account default : anand.iyer.p@gmail.com -------------------------------------------------------------------------------- /.emacs.d/lisp/setup-jump.el: -------------------------------------------------------------------------------- 1 | ;;; setup-jump.el -*- lexical-binding: t; -*- 2 | 3 | (use-package dumb-jump 4 | :commands (dumb-jump-go 5 | dumb-jump-go-other-window 6 | dumb-jump-go-prefer-external 7 | dumb-jump-go-prefer-external-other-window 8 | dumb-jump-go-prompt 9 | dumb-jump-quick-look 10 | dumb-jump-back) 11 | :init 12 | (after! hydra 13 | (defhydra api@dumb-jump (:color blue :columns 3) 14 | "Dumb Jump" 15 | ("j" dumb-jump-go "Go") 16 | ("o" dumb-jump-go-other-window "Other window") 17 | ("e" dumb-jump-go-prefer-external "Go external") 18 | ("x" dumb-jump-go-prefer-external-other-window "Go external other window") 19 | ("i" dumb-jump-go-prompt "Prompt") 20 | ("l" dumb-jump-quick-look "Quick look") 21 | ("b" dumb-jump-back "Back"))) 22 | :config 23 | (setq dumb-jump-selector 'helm)) 24 | 25 | (use-package avy 26 | :commands (avy-goto-char-2 avy-goto-line) 27 | :config 28 | (setq avy-all-windows nil 29 | avy-background t)) 30 | 31 | ;; (use-package ace-jump-helm-line 32 | ;; :defer t 33 | ;; :after helm 34 | ;; :init 35 | ;; (with-eval-after-load 'helm 36 | ;; (define-key helm-map (kbd "C-'") 'ace-jump-helm-line)) 37 | 38 | ;; ;; or if using key-chord-mode 39 | ;; ;; (eval-after-load "helm" 40 | ;; ;; '(key-chord-define helm-map "jj" 'ace-jump-helm-line)) 41 | ;; ;;(setq ace-jump-helm-line-style 'pre) 42 | ;; ;;(setq ace-jump-helm-line-background t) 43 | ;; (setq ace-jump-helm-line-default-action 'select) 44 | ;; (setq ace-jump-helm-line-select-key ?e) ;; this line is not needed 45 | ;; ;; Set the move-only and persistent keys 46 | ;; (setq ace-jump-helm-line-move-only-key ?o) 47 | ;; (setq ace-jump-helm-line-persistent-key ?p) 48 | ;; ;; enable hints preview 49 | ;; ;;(ace-jump-helm-line-autoshow-mode +1) 50 | ;; ;; use `linum-mode' to show 51 | ;; (setq ace-jump-helm-line-autoshow-mode-use-linum t)) 52 | 53 | (provide 'setup-jump) 54 | -------------------------------------------------------------------------------- /.emacs.d/lisp/init-fonts.el: -------------------------------------------------------------------------------- 1 | ;; init-fonts.el --- Fonts -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;;; Code: 6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7 | 8 | (defvar api-emacs-font-size 14) 9 | (defvar api-emacs-font (font-spec :family "PragmataPro" :size api-emacs-font-size)) 10 | (defvar api-emacs-variable-pitch-font (font-spec :family "PragmataPro")) 11 | (defvar api-emacs-fixed-pitch-font (font-spec :family "PragmataPro")) 12 | (defvar api-emacs-unicode-font (font-spec :family "PragmataPro")) 13 | (defvar api-emacs-fallback-font (font-spec :family "PragmataPro")) 14 | 15 | (use-package fonts 16 | :ensure nil 17 | :hook (after-init . api|set-fonts) 18 | :preface 19 | (defun api|set-fonts () 20 | (interactive) 21 | (set-face-attribute 'default t :font api-emacs-font) 22 | (set-frame-font api-emacs-font nil t) 23 | (set-fontset-font t 'unicode api-emacs-unicode-font) 24 | (set-face-attribute 'fixed-pitch nil 25 | :family api-emacs-fixed-pitch-font 26 | :height (* (+ api-emacs-font-size 2) 10)) 27 | 28 | (set-fontset-font "fontset-default" 29 | '(#x2776 . #x2793) api-emacs-fallback-font nil 'prepend) 30 | (set-fontset-font "fontset-default" 31 | '(#x24b6 . #x24fe) api-emacs-fallback-font nil 'prepend) 32 | (set-fontset-font "fontset-default" 33 | '(#x2295 . #x22a1) api-emacs-fallback-font nil 'prepend) 34 | (set-fontset-font "fontset-default" 35 | '(#x2190 . #x2200) api-emacs-fallback-font nil 'prepend)) 36 | :hook (after-init . api|set-fonts)) 37 | (provide 'init-fonts) 38 | 39 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 40 | ;;; init-fonts.el ends here 41 | -------------------------------------------------------------------------------- /.emacs.d/lisp/setup-spellcheck.el: -------------------------------------------------------------------------------- 1 | ;;; setup-spellcheck.el --- Spell check -*- lexical-binding: t; -*- 2 | ;;; Commentary: 3 | ;;; Code: 4 | 5 | ;;------------------------------------------------------------------------------ 6 | ;; `ispell': 7 | ;;------------------------------------------------------------------------------ 8 | (use-package ispell 9 | :ensure nil ; in-built 10 | :init 11 | (setq ispell-program-name (executable-find "aspell") 12 | ispell-extra-args '("--sug-mode=ultra" 13 | "--lang=en_US"))) 14 | 15 | ;;------------------------------------------------------------------------------ 16 | ;; `flyspell': 17 | ;;------------------------------------------------------------------------------ 18 | (use-package flyspell 19 | :ensure nil ; in-built 20 | :defer t 21 | :commands (flyspell-mode 22 | turn-on-flyspell) 23 | :init 24 | (dolist (hook '(prog-mode-hook 25 | latex-mode-hook 26 | text-mode-hook)) 27 | (add-hook hook #'turn-on-flyspell)) 28 | :bind (:map flyspell-mouse-map 29 | ("RET" . flyspell-correct-word) 30 | ([mouse-1] . flyspell-correct-word)) 31 | :config 32 | (setq flyspell-sort-corrections nil 33 | flyspell-issue-welcome-flag nil 34 | flyspell-issue-message-flag nil)) 35 | 36 | ;;------------------------------------------------------------------------------ 37 | ;; `flyspell-correct': 38 | ;;------------------------------------------------------------------------------ 39 | (use-package flyspell-correct 40 | :disabled 41 | :after (flyspell avy) 42 | :commands (flyspell-correct-next 43 | flyspell-correct-previous 44 | flyspell-correct-wrapper 45 | flyspell-correct-at-point)) 46 | 47 | (use-package flyspell-correct-popup 48 | :disabled 49 | :defer t 50 | :after flyspell-correct) 51 | ;:commands (flyspell-correct-word-generic 52 | ; flyspell-correct-previous-word-generic)) 53 | 54 | ;; (use-package flyspell-correct 55 | ;; :requires (flyspell-correct-helm flyspell-correct-popup) 56 | ;; :after (flyspell helm) 57 | ;; :commands (flyspell-correct-word-generic 58 | ;; flyspell-correct-previous-word-generic) 59 | ;; :config 60 | ;; (require 'flyspell-correct-helm) 61 | ;; (require 'flyspell-correct-popup) 62 | ;; (setq flyspell-popup-correct-delay 0.8)) 63 | 64 | (provide 'setup-spellcheck) 65 | ;;; setup-spellcheck.el ends here 66 | -------------------------------------------------------------------------------- /.emacs.d/lisp/setup-company.el: -------------------------------------------------------------------------------- 1 | ;;; setup-company.el --- Company related setup -*- lexical-binding: t; -*- 2 | ;;; Commentary: 3 | ;;; Code: 4 | 5 | (defvar company-mode/enable-yas t "Enable yasnippet for all backends.") 6 | 7 | (use-package company 8 | :diminish company-mode 9 | :commands (company-mode global-company-mode company-complete 10 | company-complete-common company-manual-begin company-grab-line) 11 | :init 12 | (add-hook 'emacs-startup-hook #'global-company-mode) 13 | :config 14 | (setq company-idle-delay 0.2 15 | company-minimum-prefix-length 3 16 | company-tooltip-limit 10 17 | company-dabbrev-downcase nil 18 | company-dabbrev-ignore-case nil 19 | company-dabbrev-code-other-buffers t 20 | company-tooltip-align-annotations t 21 | company-selection-wrap-around t 22 | company-require-match 'never 23 | company-global-modes '(not eshell-mode comint-mode erc-mode message-mode help-mode gud-mode) 24 | company-frontends '(company-pseudo-tooltip-frontend company-echo-metadata-frontend) 25 | company-backends '(company-capf company-dabbrev company-ispell) 26 | company-transformers '(company-sort-by-occurrence)) 27 | 28 | ;; fci-mode conflicts with company-mode, see: 29 | ;; https://github.com/company-mode/company-mode/issues/180 30 | ;; (defvar-local company-fci-mode-on-p nil) 31 | 32 | ;; (defun company-turn-off-fci (&rest ignore) 33 | ;; (when (boundp 'fci-mode) 34 | ;; (setq company-fci-mode-on-p fci-mode) 35 | ;; (when fci-mode (fci-mode -1)))) 36 | 37 | ;; (defun company-maybe-turn-on-fci (&rest ignore) 38 | ;; (when company-fci-mode-on-p (fci-mode 1))) 39 | 40 | ;; (add-hook 'company-completion-started-hook 'company-turn-off-fci) 41 | ;; (add-hook 'company-completion-finished-hook 'company-maybe-turn-on-fci) 42 | ;; (add-hook 'company-completion-cancelled-hook 'company-maybe-turn-on-fci) 43 | 44 | ;; Add yasnippet support for all company backends 45 | ;; https://github.com/syl20bnr/spacemacs/pull/179 46 | (defun company-mode/backend-with-yas (backend) 47 | (if (or (not company-mode/enable-yas) (and (listp backend) (member 'company-yasnippet backend))) 48 | backend 49 | (append (if (consp backend) backend (list backend)) 50 | '(:with company-yasnippet)))) 51 | 52 | (setq company-backends (mapcar #'company-mode/backend-with-yas company-backends)) 53 | (nconc company-backends '(company-yasnippet))) 54 | 55 | ;; (use-package helm-company 56 | ;; :after company 57 | ;; :config 58 | ;; (define-key company-active-map (kbd "C-/") 'helm-company)) 59 | 60 | (provide 'setup-company) 61 | ;;; setup-company.el ends here 62 | -------------------------------------------------------------------------------- /.emacs.d/lisp/init-utils.el: -------------------------------------------------------------------------------- 1 | ;;; init-utils.el --- helpers -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;;; Code: 6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7 | 8 | (defun api/byte-compile () 9 | "Byte compile all user init files." 10 | (interactive) 11 | (let (compile-targets) 12 | (setq compile-targets 13 | (nconc 14 | (nreverse (directory-files-recursively user-emacs-modules-directory "\\.el$")))) 15 | (push (expand-file-name "init.el" user-emacs-directory) compile-targets) 16 | 17 | (let ((byte-compile-warnings nil)) 18 | (dolist (target compile-targets) 19 | (byte-compile-file target))) 20 | ;;(load target t t) 21 | (message "Compilation complete. Restart Emacs to load."))) 22 | 23 | (defun remove-elc-on-save () 24 | "If we're saving an elisp file, likely the .elc is no longer valid." 25 | (add-hook 'after-save-hook 26 | (lambda () 27 | (if (file-exists-p (concat buffer-file-name "c")) 28 | (delete-file (concat buffer-file-name "c")))) 29 | nil 30 | t)) 31 | (add-hook 'emacs-lisp-mode-hook 'remove-elc-on-save) 32 | 33 | (defun api/clean-byte-compiled-files () 34 | "Delete all compiled elc files excluding packages." 35 | (interactive) 36 | (let ((targets (append (list (expand-file-name "init.elc" user-emacs-directory)) 37 | (directory-files-recursively user-emacs-modules-directory "\\.elc$"))) 38 | (default-directory user-emacs-directory)) 39 | (unless (cl-loop for path in targets 40 | if (file-exists-p path) 41 | collect path 42 | and do (delete-file path) 43 | and do (message "✓ Deleted %s" (file-relative-name path))) 44 | (message "Everything is clean")))) 45 | 46 | ;;------------------------------------------------------------------------------ 47 | ;; Allow loading packages after some other packages. 48 | ;;------------------------------------------------------------------------------ 49 | (defmacro after! (feature &rest body) 50 | "After FEATURE is loaded, evaluate BODY. Supress warnings during compilation." 51 | (declare (indent defun) (debug t)) 52 | `(,(if (or (not (bound-and-true-p byte-compile-current-file)) 53 | (if (symbolp feature) 54 | (require feature nil :no-error) 55 | (load feature :no-message :no-error))) 56 | #'progn 57 | #'with-no-warnings) 58 | (with-eval-after-load ',feature ,@body))) 59 | 60 | (provide 'init-utils) 61 | 62 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 63 | ;;; init-utils.el ends here 64 | -------------------------------------------------------------------------------- /.config/yabai/yabairc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # the scripting-addition must be loaded manually if 4 | # you are running yabai on macOS Big Sur. Uncomment 5 | # the following line to have the injection performed 6 | # when the config is executed during startup. 7 | # 8 | # for this to work you must configure sudo such that 9 | # it will be able to run the command without password 10 | # 11 | # see this wiki page for information: 12 | # - https://github.com/koekeishiya/yabai/wiki/Installing-yabai-(latest-release) 13 | # 14 | # sudo yabai --load-sa 15 | # yabai -m signal --add event=dock_did_restart action="sudo yabai --load-sa" 16 | 17 | # global settings 18 | yabai -m config mouse_follows_focus off 19 | yabai -m config focus_follows_mouse off 20 | yabai -m config window_placement second_child 21 | yabai -m config window_topmost off 22 | yabai -m config window_shadow on 23 | yabai -m config window_opacity off 24 | yabai -m config window_opacity_duration 0.0 25 | yabai -m config active_window_opacity 1.0 26 | yabai -m config normal_window_opacity 0.90 27 | yabai -m config window_border off 28 | yabai -m config window_border_width 6 29 | yabai -m config active_window_border_color 0xff775759 30 | yabai -m config normal_window_border_color 0xff555555 31 | yabai -m config insert_feedback_color 0xffd75f5f 32 | yabai -m config split_ratio 0.50 33 | yabai -m config auto_balance off 34 | yabai -m config mouse_modifier ctrl 35 | yabai -m config mouse_action1 move 36 | yabai -m config mouse_action2 resize 37 | yabai -m config mouse_drop_action swap 38 | 39 | # general space settings 40 | yabai -m config layout bsp 41 | yabai -m config top_padding 05 42 | yabai -m config bottom_padding 05 43 | yabai -m config left_padding 05 44 | yabai -m config right_padding 05 45 | yabai -m config window_gap 06 46 | 47 | # Rules 48 | yabai -m rule --add title='^System Preferences$' manage=off 49 | yabai -m rule --add title='Copy' manage=off 50 | yabai -m rule --add title='Print' manage=off 51 | yabai -m rule --add app='App Store' manage=off 52 | yabai -m rule --add app='Fantastical$' manage=off 53 | yabai -m rule --add app="thinkorswim$" manage=off 54 | yabai -m rule --add app='Parallels Desktop' manage=off 55 | yabai -m rule --add app='Microsoft Teams' manage=off 56 | yabai -m rule --add app='Microsoft Outlook' manage=off 57 | yabai -m rule --add title='• Calendar • api@microsoft.com$' manage=off 58 | yabai -m rule --add app='Emacs' manage=on space=3 59 | 60 | echo "yabai configuration loaded.." 61 | -------------------------------------------------------------------------------- /.emacs.d/lisp/init-mac.el: -------------------------------------------------------------------------------- 1 | ;;; init-mac.el --- Mac specific settings -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;; Taken from doom-emacs. 6 | 7 | ;;; Code: 8 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 9 | 10 | (setq mac-command-modifier 'super 11 | ;;mac-right-control-modifier 'hyper 12 | mac-function-modifier 'hyper ; make Fn key do Hyper 13 | mac-option-modifier 'hyper ; make option do Hyper 14 | 15 | ;; clipboard 16 | x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING) 17 | ;; Use a shared clipboard 18 | select-enable-clipboard t 19 | select-enable-primary t 20 | 21 | mac-redisplay-dont-reset-vscroll t 22 | mac-mouse-wheel-smooth-scroll nil 23 | mouse-wheel-scroll-amount '(5 ((shift) . 2)) ; one line at a time 24 | mouse-wheel-progressive-speed nil ; don't accelerate scrolling 25 | 26 | ;; NOTE Meaningless to railwaycat's emacs-mac build 27 | ns-use-native-fullscreen nil 28 | ;; Don't open files from the workspace in a new frame 29 | ns-pop-up-frames nil) 30 | 31 | ;; https://www.reddit.com/r/emacs/comments/8ph0hq/i_have_converted_from_the_mac_port_to_the_ns_port/ 32 | ;; Will at least display native Unicode emojis if the multicolor font 33 | ;; patch is applied 34 | (set-fontset-font "fontset-default" 'unicode "Apple Color Emoji" nil 'prepend) 35 | (setq frame-title-format "%b" 36 | ns-use-mwheel-momentum t 37 | ns-use-mwheel-acceleration t 38 | ;;pixel-scroll-mode t 39 | mouse-wheel-flip-direction t 40 | mouse-wheel-tilt-scroll t 41 | ;; MacPorts emacs-app port bug 42 | ;;x-colors (ns-list-colors) 43 | ) 44 | 45 | (after! evil 46 | ;; stop copying each visual state move to the clipboard: 47 | ;; https://bitbucket.org/lyro/evil/issue/336/osx-visual-state-copies-the-region-on 48 | ;; Most of this code grokked from: 49 | ;; http://stackoverflow.com/questions/15873346/elisp-rename-macro 50 | (advice-add #'evil-visual-update-x-selection :override #'ignore)) 51 | 52 | ;;------------------------------------------------------------------------------ 53 | ;; `exec-path-from-shell': 54 | ;;------------------------------------------------------------------------------ 55 | (use-package exec-path-from-shell 56 | ;;:disabled 57 | :if (display-graphic-p) 58 | :init 59 | (when (require 'exec-path-from-shell nil t) 60 | (setq exec-path-from-shell-check-startup-files nil 61 | exec-path-from-shell-arguments (delete "-i" exec-path-from-shell-arguments)) 62 | (exec-path-from-shell-initialize))) 63 | 64 | (provide 'init-mac) 65 | 66 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 67 | ;;; init-mac.el ends here 68 | -------------------------------------------------------------------------------- /.tmux.conf: -------------------------------------------------------------------------------- 1 | #run-shell "powerline-daemon -q" 2 | #source-file "/usr/local/lib/python2.7/site-packages/powerline/bindings/tmux/powerline.conf" 3 | 4 | #Start windows and pane numbering with index 1 instead of 0 5 | set -g base-index 1 6 | setw -g pane-base-index 1 7 | 8 | # re-number windows when one is closed 9 | set -g renumber-windows on 10 | 11 | # highlight window when it has new activity 12 | setw -g monitor-activity on 13 | set -g visual-activity on 14 | 15 | # Show times longer than supposed 16 | set -g display-panes-time 2000 17 | 18 | # Split horiziontal and vertical splits, instead of % and " 19 | # Also open them in the same directory 20 | bind-key v split-window -h -c '#{pane_current_path}' 21 | bind-key s split-window -v -c '#{pane_current_path}' 22 | 23 | # Mouse mode on 24 | set -g mouse on 25 | 26 | # Vim style copy paste 27 | #setw -g mode-keys vi 28 | #bind-key -t vi-copy v begin-selection 29 | #bind-key -t vi-copy y copy-pipe "pbcopy" 30 | #unbind -t vi-copy Enter 31 | #bind-key -t vi-copy Enter copy-pipe "pbcopy" 32 | # Use vim keybindings in copy mode 33 | setw -g mode-keys vi 34 | # Select and copy with v and y, instead of default space and enter 35 | bind-key -T edit-mode-vi Up send-keys -X history-up 36 | bind-key -T edit-mode-vi Down send-keys -X history-down 37 | unbind-key -T copy-mode-vi Space ; bind-key -T copy-mode-vi v send-keys -X begin-selection 38 | unbind-key -T copy-mode-vi Enter ; bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "reattach-to-user-namespace pbcopy" 39 | unbind-key -T copy-mode-vi C-v ; bind-key -T copy-mode-vi C-v send-keys -X rectangle-toggle 40 | unbind-key -T copy-mode-vi [ ; bind-key -T copy-mode-vi [ send-keys -X begin-selection 41 | unbind-key -T copy-mode-vi ] ; bind-key -T copy-mode-vi ] send-keys -X copy-selection 42 | 43 | # Set title 44 | set -g set-titles on 45 | set -g set-titles-string "#T" 46 | 47 | set -g @resurrect-capture-pane-contents 'on' 48 | set -g @resurrect-strategy-vim 'session' 49 | set -g @resurrect-strategy-nvim 'session' 50 | 51 | set -g status-right '#{prefix_highlight} | %a %Y-%m-%d %H:%M' 52 | set -g @prefix_highlight_show_copy_mode 'on' 53 | 54 | set -g @continuum-save-interval '15' 55 | set -g @continuum-restore 'on' 56 | 57 | #------------------------------------------------------------------------------ 58 | # Plugins 59 | #------------------------------------------------------------------------------ 60 | set -g @plugin 'tmux-plugins/tpm' 61 | set -g @plugin 'tmux-plugins/tmux-resurrect' 62 | #set -g @plugin 'tmux-plugins/tmux-continuum' 63 | set -g @plugin 'tmux-plugins/tmux-sensible' 64 | set -g @plugin 'tmux-plugins/tmux-prefix-highlight' 65 | set -g @plugin 'tmux-plugins/tmux-copycat' 66 | set -g @plugin 'tmux-plugins/tmux-yank' 67 | 68 | run '~/.tmux/plugins/tpm/tpm' 69 | -------------------------------------------------------------------------------- /.notmuch-config: -------------------------------------------------------------------------------- 1 | # .notmuch-config - Configuration file for the notmuch mail system 2 | # 3 | # For more information about notmuch, see https://notmuchmail.org 4 | 5 | # Database configuration 6 | # 7 | # The only value supported here is 'path' which should be the top-level 8 | # directory where your mail currently exists and to where mail will be 9 | # delivered in the future. Files should be individual email messages. 10 | # Notmuch will store its database within a sub-directory of the path 11 | # configured here named ".notmuch". 12 | # 13 | 14 | [database] 15 | path=/Users/api/Maildir 16 | 17 | # User configuration 18 | # 19 | # Here is where you can let notmuch know how you would like to be 20 | # addressed. Valid settings are 21 | # 22 | # name Your full name. 23 | # primary_email Your primary email address. 24 | # other_email A list (separated by ';') of other email addresses 25 | # at which you receive email. 26 | # 27 | # Notmuch will use the various email addresses configured here when 28 | # formatting replies. It will avoid including your own addresses in the 29 | # recipient list of replies, and will set the From address based on the 30 | # address to which the original email was addressed. 31 | # 32 | 33 | [user] 34 | name=Anand 35 | primary_email=anand.iyer.p@gmail.com 36 | other_email=anand.padmanabha.iyer@gmail.com;anand.ebiz@gmail.com;anand.iyer@berkeley.edu;api@cs.berkeley.edu;api@eecs.berkeley.edu 37 | 38 | # Configuration for "notmuch new" 39 | # 40 | # The following options are supported here: 41 | # 42 | # tags A list (separated by ';') of the tags that will be 43 | # added to all messages incorporated by "notmuch new". 44 | # 45 | # ignore A list (separated by ';') of file and directory names 46 | # that will not be searched for messages by "notmuch new". 47 | # 48 | # NOTE: *Every* file/directory that goes by one of those 49 | # names will be ignored, independent of its depth/location 50 | # in the mail store. 51 | # 52 | 53 | [new] 54 | tags=new 55 | ignore=*.json 56 | 57 | # Search configuration 58 | # 59 | # The following option is supported here: 60 | # 61 | # exclude_tags 62 | # A ;-separated list of tags that will be excluded from 63 | # search results by default. Using an excluded tag in a 64 | # query will override that exclusion. 65 | # 66 | 67 | [search] 68 | exclude_tags=deleted;spam; 69 | 70 | # Maildir compatibility configuration 71 | # 72 | # The following option is supported here: 73 | # 74 | # synchronize_flags Valid values are true and false. 75 | # 76 | # If true, then the following maildir flags (in message filenames) 77 | # will be synchronized with the corresponding notmuch tags: 78 | # 79 | # Flag Tag 80 | # ---- ------- 81 | # D draft 82 | # F flagged 83 | # P passed 84 | # R replied 85 | # S unread (added when 'S' flag is not present) 86 | # 87 | # The "notmuch new" command will notice flag changes in filenames 88 | # and update tags, while the "notmuch tag" and "notmuch restore" 89 | # commands will notice tag changes and update flags in filenames 90 | # 91 | 92 | [maildir] 93 | synchronize_flags=true 94 | -------------------------------------------------------------------------------- /.emacs.d/init.el: -------------------------------------------------------------------------------- 1 | ;;; init.el --- Emacs configuration of Anand Iyer -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;;; Code: 6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7 | 8 | (defconst user-emacs-config-directory 9 | (expand-file-name (concat user-emacs-directory "config/")) 10 | "Directory for storing user's local files.") 11 | 12 | (defconst user-emacs-modules-directory 13 | (expand-file-name (concat user-emacs-directory "lisp/")) 14 | "Directory for storing modules.") 15 | 16 | (defconst user-emacs-data-directory 17 | (expand-file-name (concat user-emacs-directory "data/")) 18 | "Directory where cache files are stored.") 19 | 20 | (defconst user-emacs-temp-directory 21 | (expand-file-name (concat user-emacs-directory "tmp/")) 22 | "Directory where temp files are stored.") 23 | 24 | (defconst org-root-directory 25 | "~/Library/Mobile Documents/iCloud~com~appsonthemove~beorg/Documents/org-mode/" 26 | "Directory where org files are stored.") 27 | 28 | (setq-default load-prefer-newer t) 29 | 30 | (eval-and-compile 31 | 32 | ;; Temporarily change GC threshold and file handler alist. 33 | (when (version< emacs-version "27.0") 34 | (unless (or after-init-time noninteractive) 35 | (defvar api--file-name-handler-alist file-name-handler-alist) 36 | (setq gc-cons-threshold (* 512 1024 1024) 37 | gc-cons-percentage 1.0 38 | file-name-handler-alist nil) 39 | (defun api|reset-gc() 40 | (setq gc-cons-threshold (* 16 1024 1024) 41 | gc-cons-percentage 0.1 42 | file-name-handler-alist api--file-name-handler-alist)) 43 | (add-hook 'emacs-startup-hook #'api|reset-gc))) 44 | 45 | (add-to-list 'load-path user-emacs-modules-directory) 46 | 47 | (require 'cl-lib) 48 | 49 | ;; useful functions and macros. 50 | (require 'init-utils) 51 | ;; calls (package-initialize) 52 | (require 'init-package) 53 | (require 'init-core) 54 | (require 'init-theme) 55 | (require 'init-fonts) 56 | (require 'init-ui) 57 | (require 'init-frames) 58 | (require 'init-windows) 59 | (require 'init-modeline) 60 | (require 'init-mac) 61 | (require 'init-editor) 62 | (require 'init-evil) 63 | (require 'init-keybindings) 64 | 65 | ;;(require 'setup-helm) 66 | (require 'setup-ivy) 67 | 68 | ;; Packages. 69 | (require 'setup-company) 70 | (require 'setup-flycheck) 71 | (require 'setup-yasnippet) 72 | (require 'setup-projectile) 73 | (require 'setup-spellcheck) 74 | (require 'setup-jump) 75 | (require 'setup-git) 76 | (require 'setup-org) 77 | (require 'setup-pdf) 78 | (require 'setup-tex) 79 | ;;(require 'setup-scala) 80 | (require 'setup-email) 81 | ;;(require 'setup-music) 82 | 83 | ;; Let emacsclients connect. 84 | (require 'server) 85 | (unless (server-running-p) (server-start)) 86 | 87 | (when (file-exists-p custom-file) 88 | (load custom-file)) 89 | 90 | (require 'init-locales)) 91 | 92 | (provide 'init) 93 | 94 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 95 | ;;; init.el ends here 96 | -------------------------------------------------------------------------------- /.emacs.d/lisp/setup-music.el: -------------------------------------------------------------------------------- 1 | ;;; setup-music.el --- Music control with Emacs -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;;; Code: 6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7 | 8 | (setq mpc-host "localhost:6600") 9 | 10 | ;;------------------------------------------------------------------------------ 11 | ;; `emms': Emacs Multimedia System 12 | ;;------------------------------------------------------------------------------ 13 | (use-package emms 14 | :commands (emms 15 | emms-add-directory-tree 16 | emms-player-mpd-connect 17 | emms-cache-set-from-mpd-all 18 | emms-smart-browse 19 | emms-pause 20 | emms-next) 21 | :init 22 | (defun api/connect-to-music-daemon () 23 | "Connect to MPD." 24 | (interactive) 25 | (emms-player-mpd-connect) 26 | (emms-cache-set-from-mpd-all) 27 | (message "EMMS connected to MPD!")) 28 | ;;(add-hook 'emacs-startup-hook #'api/connect-to-music-daemon) 29 | :config 30 | (require 'emms-setup) 31 | (require 'emms-player-mpd) 32 | (emms-all) 33 | (api/connect-to-music-daemon) 34 | (setq emms-source-file-default-directory "~/Music/beets/" 35 | emms-info-asynchronously t 36 | emms-show-format "♪ %s" 37 | emms-seek-seconds 5 38 | emms-player-list '(emms-player-mpd) 39 | emms-info-functions '(emms-info-mpd) 40 | emms-player-mpd-music-directory "~/Music/beets/" 41 | emms-player-mpd-server-name "localhost" 42 | emms-player-mpd-server-port "6600") 43 | 44 | (require 'emms-mode-line) 45 | (emms-mode-line 1) 46 | (require 'emms-playing-time) 47 | (emms-playing-time 1) 48 | 49 | (add-hook 'emms-browser-mode-hook 'evil-emacs-state) 50 | (add-hook 'emms-playlist-mode-hook 'evil-emacs-state)) 51 | 52 | ;;------------------------------------------------------------------------------ 53 | ;; `mingus': Frontend for GNU Emacs to the Music Player daemon. 54 | ;;------------------------------------------------------------------------------ 55 | (use-package mingus 56 | :disabled ;; doesn't play well with mu4e. 57 | :commands (mingus 58 | mingus-browse) 59 | :init 60 | (setq mingus-mode-always-modeline t 61 | mingus-mode-line-show-status t 62 | mingus-mode-line-show-elapsed-time t 63 | mingus-mode-line-show-volume nil 64 | mingus-mode-line-separator 65 | (if window-system 66 | " ● " 67 | " + ")) 68 | (add-hook 'mingus-browse-hook 'evil-emacs-state t) 69 | (add-hook 'mingus-playlist-hooks 'evil-emacs-state t)) 70 | 71 | ;;------------------------------------------------------------------------------ 72 | ;; `simple-mpc': Very simple frontend for MPD. 73 | ;;------------------------------------------------------------------------------ 74 | (use-package simple-mpc 75 | :commands (simple-mpc) 76 | :config 77 | (evil-set-initial-state 'simple-mpc-mode 'emacs)) 78 | 79 | (provide 'setup-music) 80 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 81 | ;;; setup-music.el ends here 82 | -------------------------------------------------------------------------------- /.chunkwmrc: -------------------------------------------------------------------------------- 1 | ##!/bin/bash 2 | 3 | # 4 | # NOTE: specify the absolutepath of the file to use for logging. 5 | # 'stdout' and 'stderr' are valid values. 6 | # 7 | 8 | chunkc core::log_file stdout 9 | 10 | # 11 | # NOTE: specify the desired level of logging. 12 | # 13 | # - none, debug, warn, error 14 | # 15 | 16 | chunkc core::log_level warn 17 | 18 | # 19 | # NOTE: specify the absolutepath to the directory to use when 20 | # loading a plugin. '~' expansion is supported. 21 | 22 | chunkc core::plugin_dir /usr/local/opt/chunkwm/share/chunkwm/plugins 23 | 24 | # 25 | # NOTE: if enabled, chunkwm will monitor the specified plugin_dir 26 | # and automatically reload any '.so' file that is changed. 27 | # 28 | 29 | chunkc core::hotload 1 30 | 31 | # 32 | # NOTE: the following are config variables for the chunkwm-tiling plugin. 33 | # 34 | 35 | chunkc set global_desktop_mode bsp 36 | 37 | chunkc set global_desktop_offset_top 2 38 | chunkc set global_desktop_offset_bottom 2 39 | chunkc set global_desktop_offset_left 2 40 | chunkc set global_desktop_offset_right 2 41 | chunkc set global_desktop_offset_gap 2 42 | 43 | # 44 | # NOTE: shell commands require escaped quotes 45 | # to pass value containing a whitespace. 46 | # 47 | 48 | chunkc set desktop_padding_step_size 10.0 49 | chunkc set desktop_gap_step_size 5.0 50 | 51 | chunkc set bsp_spawn_left 0 52 | chunkc set bsp_optimal_ratio 1.618 53 | chunkc set bsp_split_mode optimal 54 | chunkc set bsp_split_ratio 0.5 55 | 56 | chunkc set monitor_focus_cycle 1 57 | chunkc set window_focus_cycle monitor 58 | 59 | chunkc set mouse_follows_focus intrinsic 60 | chunkc set window_float_next 0 61 | chunkc set window_region_locked 1 62 | 63 | chunkc set mouse_move_window \"ctrl cmd alt\" 64 | chunkc set mouse_resize_window \"ctrl cmd shift alt\" 65 | chunkc set mouse_motion_interval 35 66 | 67 | chunkc set preselect_border_color 0xffd75f5f 68 | chunkc set preselect_border_width 5 69 | 70 | # 71 | # NOTE: the following are config variables for the chunkwm-border plugin. 72 | # 73 | 74 | chunkc set focused_border_color 0xffc0b18b 75 | chunkc set focused_border_width 5 76 | chunkc set focused_border_radius 0 77 | chunkc set focused_border_skip_floating 0 78 | 79 | 80 | # 81 | # NOTE: the following are config variables for the chunkwm-ffm plugin. 82 | # 83 | 84 | chunkc set ffm_bypass_modifier \"ctrl cmd alt\" 85 | #chunkc set ffm_bypass_modifier fn 86 | 87 | # 88 | # NOTE: specify plugins to load when chunkwm starts. 89 | # if chunkc plugin_dir is not set, the absolutepath is necessary. 90 | # 91 | 92 | chunkc core::load tiling.so 93 | chunkc core::load ffm.so 94 | #chunkc core::load border.so 95 | 96 | # 97 | # Rules for the tiling plugin 98 | # 99 | 100 | chunkc tiling::rule --owner Finder --name Copy --state float 101 | chunkc tiling::rule --owner \"App Store\" --state float 102 | chunkc tiling::rule --owner Fantastical --state float 103 | #chunkc tiling::rule --owner Emacs --except "^$" --state tile 104 | -------------------------------------------------------------------------------- /.dotfiles/README.md: -------------------------------------------------------------------------------- 1 | # Keep dotfiles where they belong and avoid symlinks entirely. 2 | 3 | This arrangement of dotfiles is taken from [here](https://news.ycombinator.com/item?id=11070797) and [here](https://developer.atlassian.com/blog/2016/02/best-way-to-store-dotfiles-git-bare-repo/). The idea is to keep all the dotfiles at their original locations, and avoid symlinks entirely (as opposed to the general approach of putting all config files in one directory and symlinking them with a script or GNU stow). Basically, we create a bare git repo and set the work-tree to be our `$HOME` directory. Then everytime we add a new config file to this repo, we do so specifying this work-tree (we make this easy by defining an alias command). This lets us keep the config files at their original locations, while also allowing them to be under version control. Here's how to do it: 4 | 5 | ## First time setup 6 | ``` 7 | git init --bare $HOME/.dotfiles 8 | alias dotfiles='/usr/local/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME' 9 | dotfiles config --local status.showUntrackedFiles no 10 | dotfiles remote add origin git@github.com:anandpiyer/.dotfiles.git 11 | ``` 12 | You'll need to change the remote URL to your git repo. You should also add the `dotfiles` alias command to your `.bashrc` or `.zshrc`. Now, you can use the `dotfiles` command to do git operation from anywhere in your $HOME directory: 13 | 14 | ### Operations 15 | ``` 16 | cd $HOME 17 | dotfiles add .tmux.conf 18 | dotfiles commit -m "Add .tmux.conf" 19 | dotfiles push 20 | ``` 21 | ## New machine setup 22 | To set up a new machine, clone the repo to a temporary directory. This is because you might have some default config files in your $HOME which will cause a normal clone to fail. 23 | ``` 24 | git clone --separate-git-dir=$HOME/.dotfiles https://github.com/anandpiyer/.dotfiles.git tmpdotfiles 25 | rsync --recursive --verbose --exclude '.git' tmpdotfiles/ $HOME/ 26 | rm -r tmpdotfiles 27 | ``` 28 | ## Apps I use 29 | 30 | ### [FASD](https://github.com/clvv/fasd) + [FZF](https://github.com/junegunn/fzf) 31 | I use this combination to define a bunch of [zsh auto-functions](https://github.com/anandpiyer/.dotfiles/blob/master/.zshrc). For example, function `e` opens any file in `$EDITOR` (Emacs) using `fasd` (if `e` has no arguments) or `fzf` to filter the output of `fasd` (if `e` is used with an argument). Similarly, `o` opens finder and `j` jumps to directories using fuzzy matching. 32 | 33 | ### [Hammerspoon](http://www.hammerspoon.org/) 34 | Hammerspoon is used for both window management and app management. Specifically, I assign key combinations to my most frequently used apps for quick switching (e.g., hyper+e launches or focuses my Emacs). I also [use it](https://github.com/anandpiyer/.dotfiles/blob/b2ec2a12dfe6b8917e0304b728d680c06b06f5ba/.hammerspoon/init.lua#L20) to achieve Caffeine's functionality. 35 | 36 | ### [Karabiner-Elements](https://pqrs.org/osx/karabiner/) 37 | I use Karabiner-Elements for key remapping. Specifically, I remap my capslock 38 | key to both Esc (when pressed and released) and ctrl (when 39 | held). Since this frees my ctrl key, I remap ctrl to be my 40 | hyper key (shift+ctrl+option). This 41 | gives me two modifier keys: hyper and cmd+hyper. 42 | -------------------------------------------------------------------------------- /.emacs.d/lisp/setup-pdf.el: -------------------------------------------------------------------------------- 1 | ;;; setup-pdf.el --- PDF -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;;; Code: 6 | 7 | ;;------------------------------------------------------------------------------ 8 | ;; `pdf-tools': 9 | ;;------------------------------------------------------------------------------ 10 | ;; use brew to install pdf-tools so that epdfinfo gets installed properly: 11 | ;; brew install pdf-tools 12 | ;; and set the path to epdfinfo from brew installation. To upgrade, do 13 | ;; 'brew upgrade pdf-tools' PRIOR to upgrading pdf-tools emacs package. If 14 | ;; things are messed up, uninstall brew pdf-tools, remove elpa pdf-tools and 15 | ;; start over. 16 | ;;------------------------------------------------------------------------------ 17 | (use-package pdf-tools 18 | :if (display-graphic-p) 19 | :mode (("\\.pdf\\'" . pdf-view-mode)) 20 | :bind 21 | (:map pdf-view-mode-map 22 | ("C-c h" . api@pdftools/body) 23 | ("C-s" . isearch-forward)) ;; swiper doesn't work properly. 24 | :init 25 | (load "pdf-tools-autoloads" nil t) 26 | :config 27 | (defhydra api@pdftools (:color blue :hint nil) 28 | " 29 | ╭───────────┐ 30 | Move History Scale/Fit Annotations Search/Link Do │ PDF Tools │ 31 | ╭──────────────────────────────────────────────────────────────────┴───────────╯ 32 | ^^_g_^^ _B_ ^↧^ _+_ ^ ^ [_al_] list [_s_] search [_u_] revert buffer 33 | ^^^↑^^^ ^↑^ _H_ ^↑^ ↦ _W_ ↤ [_am_] markup [_o_] outline [_i_] info 34 | ^^_p_^^ ^ ^ ^↥^ _0_ ^ ^ [_at_] text [_F_] link [_d_] dark mode 35 | ^^^↑^^^ ^↓^ ╭─^─^─┐ ^↓^ ╭─^ ^─┐ [_ad_] delete [_f_] search link 36 | _h_ ←pag_e_→ _l_ _N_ │ _P_ │ _-_ _b_ [_aa_] dired 37 | ^^^↓^^^ ^ ^ ╰─^─^─╯ ^ ^ ╰─^ ^─╯ [_y_] yank 38 | ^^_n_^^ ^ ^ _r_eset slice box 39 | ^^^↓^^^ 40 | ^^_G_^^ 41 | -------------------------------------------------------------------------------- 42 | " 43 | ("" nil "quit") 44 | ("al" pdf-annot-list-annotations) 45 | ("ad" pdf-annot-delete) 46 | ("aa" pdf-annot-attachment-dired) 47 | ("am" pdf-annot-add-markup-annotation) 48 | ("at" pdf-annot-add-text-annotation) 49 | ("y" pdf-view-kill-ring-save) 50 | ("+" pdf-view-enlarge :color red) 51 | ("-" pdf-view-shrink :color red) 52 | ("0" pdf-view-scale-reset) 53 | ("H" pdf-view-fit-height-to-window) 54 | ("W" pdf-view-fit-width-to-window) 55 | ("P" pdf-view-fit-page-to-window) 56 | ("n" pdf-view-next-page-command :color red) 57 | ("p" pdf-view-previous-page-command :color red) 58 | ("d" pdf-view-dark-minor-mode) 59 | ("b" pdf-view-set-slice-from-bounding-box) 60 | ("r" pdf-view-reset-slice) 61 | ("g" pdf-view-first-page) 62 | ("G" pdf-view-last-page) 63 | ("e" pdf-view-goto-page) 64 | ("o" pdf-outline) 65 | ("s" pdf-occur) 66 | ("i" pdf-misc-display-metadata) 67 | ("u" pdf-view-revert-buffer) 68 | ("F" pdf-links-action-perform) 69 | ("f" pdf-links-isearch-link) 70 | ("B" pdf-history-backward :color red) 71 | ("N" pdf-history-forward :color red) 72 | ("l" image-forward-hscroll :color red) 73 | ("h" image-backward-hscroll :color red)) 74 | ;;:config 75 | (custom-set-variables '(pdf-tools-handle-upgrades nil)) 76 | (setq pdf-view-resize-factor 1.1 77 | pdf-info-epdfinfo-program "/usr/local/bin/epdfinfo") 78 | (pdf-tools-install)) 79 | (provide 'setup-pdf) 80 | ;;; setup-pdf.el ends here 81 | -------------------------------------------------------------------------------- /.emacs.d/lisp/init-package.el: -------------------------------------------------------------------------------- 1 | ;;; init-package.el --- Package related things -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;; Declare archives and bootstrap use-package. 6 | 7 | ;;; Code: 8 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 9 | 10 | (setq package-archives '(("melpa" . "https://melpa.org/packages/") 11 | ;("melpa-stable" . "https://stable.melpa.org/packages/") 12 | ("gnu" . "https://elpa.gnu.org/packages/")) 13 | package-enable-at-startup nil 14 | package--init-file-ensured t) 15 | 16 | (eval-and-compile 17 | (setq use-package-verbose (not (bound-and-true-p byte-compile-current-file)))) 18 | 19 | ;; Add the macro generated list of package.el loadpaths to load-path. 20 | (mapc #'(lambda (add) (add-to-list 'load-path add)) 21 | (eval-when-compile 22 | ;; (require 'package) 23 | (package-initialize) 24 | ;; Install use-package if not installed yet. 25 | (unless (package-installed-p 'use-package) 26 | (package-refresh-contents) 27 | (package-install 'use-package)) 28 | ;; (require 'use-package) 29 | (setq use-package-always-ensure t) 30 | (let ((package-user-dir-real (file-truename package-user-dir))) 31 | ;; The reverse is necessary, because outside we mapc 32 | ;; add-to-list element-by-element, which reverses. 33 | (nreverse (apply #'nconc 34 | ;; Only keep package.el provided loadpaths. 35 | (mapcar #'(lambda (path) 36 | (if (string-prefix-p package-user-dir-real path) 37 | (list path) 38 | nil)) 39 | load-path)))))) 40 | 41 | (setq use-package-always-defer t) 42 | 43 | ;; (if api-debug-enabled 44 | ;; (setq use-package-expand-minimally nil 45 | ;; use-package-compute-statistics t 46 | ;; use-package-minimum-reported-time 0.01 47 | ;; use-package-verbose (not (bound-and-true-p byte-compile-current-file))) 48 | ;; (setq use-package-verbose nil 49 | ;; use-package-expand-minimally t)) 50 | 51 | (eval-when-compile (require 'use-package)) 52 | ;;(require 'diminish) 53 | (require 'bind-key) 54 | ;;(use-package diminish) 55 | ;;(use-package bind-key) 56 | ;; so we can (require 'use-package) even in compiled emacs to e.g. read docs 57 | ;;(use-package use-package :commands use-package-autoload-keymap) 58 | 59 | ;;------------------------------------------------------------------------------ 60 | ;; Allow loading packages after some other packages. 61 | ;;------------------------------------------------------------------------------ 62 | ;; (defmacro after! (feature &rest body) 63 | ;; "After FEATURE is loaded, evaluate BODY. Supress warnings during compilation." 64 | ;; (declare (indent defun) (debug t)) 65 | ;; `(,(if (or (not (bound-and-true-p byte-compile-current-file)) 66 | ;; (if (symbolp feature) 67 | ;; (require feature nil :no-error) 68 | ;; (load feature :no-message :no-error))) 69 | ;; #'progn 70 | ;; #'with-no-warnings) 71 | ;; (with-eval-after-load ',feature ,@body))) 72 | 73 | ;;------------------------------------------------------------------------------ 74 | ;; `paradox': Project for modernizing Emacs' Package Menu. 75 | ;;------------------------------------------------------------------------------ 76 | (use-package paradox 77 | :hook ((emacs-startup . paradox-enable))) 78 | 79 | (provide 'init-package) 80 | 81 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 82 | ;;; init-package.el ends here 83 | -------------------------------------------------------------------------------- /.emacs.d/lisp/setup-git.el: -------------------------------------------------------------------------------- 1 | ;;; setup-git.el --- git related packages -*- lexical-binding: t; -*- 2 | ;;; Commentary: 3 | ;;; Code: 4 | 5 | (use-package magit 6 | :after evil 7 | :commands (magit-status magit-blame) 8 | :config 9 | (setq magit-auto-revert-mode nil) 10 | ;; Switch to emacs state only while in `magit-blame-mode', then back when 11 | ;; its done (since it's a minor-mode). 12 | (add-hook 'magit-blame-mode-hook 13 | (evil-local-mode (if magit-blame-mode -1 +1)))) 14 | 15 | ;; (use-package evil-magit 16 | ;; :after magit 17 | ;; :commands (evil-magit-init) 18 | ;; :init 19 | ;; ;; optional: this is the evil state that evil-magit will use 20 | ;; ;; (setq evil-magit-state 'normal) 21 | ;; ;; optional: disable additional bindings for yanking text 22 | ;; ;; (setq evil-magit-use-y-for-yank nil) 23 | ;; (require 'evil-magit)) 24 | 25 | ;; Show git status in the fringe. 26 | (use-package git-gutter-fringe 27 | :disabled 28 | :ensure git-gutter 29 | :commands (git-gutter-mode) 30 | :hook ((prog-mode . api|git-gutter-maybe) 31 | (latex-mode . api|git-gutter-maybe) 32 | (text-mode . api|git-gutter-maybe) 33 | (conf-mode . api|git-gutter-maybe)) 34 | :preface 35 | (defun api|git-gutter-maybe () 36 | "Enable `git-gutter-mode' in non-remote buffers." 37 | (when (and (buffer-file-name) 38 | (not (file-remote-p (buffer-file-name)))) 39 | (progn 40 | (require 'git-gutter-fringe) 41 | (git-gutter-mode +1)))) 42 | ;; (dolist (hook '(prog-mode-hook 43 | ;; latex-mode-hook 44 | ;; text-mode-hook 45 | ;; conf-mode-hook)) 46 | ;; (add-hook hook #'api|git-gutter-maybe)) 47 | 48 | :config 49 | (defhydra api@git-gutter (:body-pre (git-gutter-mode 1) 50 | :hint nil) 51 | " 52 | ╭─────────────────┐ 53 | Movement Hunk Actions Misc. │ gg: +%-4s(car (git-gutter:statistic))/ -%-3s(cdr (git-gutter:statistic)) │ 54 | ╭──────────────────────────────────┴─────────────────╯ 55 | ^_g_^ [_s_] stage [_R_] set start Rev 56 | ^_k_^ [_r_] revert 57 | ^↑ ^ [_m_] mark 58 | ^↓ ^ [_p_] popup ╭────────────────────── 59 | ^_j_^ │[_q_] quit 60 | ^_G_^ │[_Q_] Quit and disable" 61 | ("j" (progn (git-gutter:next-hunk 1) 62 | (recenter))) 63 | ("k" (progn (git-gutter:previous-hunk 1) 64 | (recenter))) 65 | ("g" (progn (goto-char (point-min)) 66 | (git-gutter:next-hunk 1))) 67 | ("G" (progn (goto-char (point-min)) 68 | (git-gutter:previous-hunk 1))) 69 | ("s" git-gutter:stage-hunk) 70 | ("r" git-gutter:revert-hunk) 71 | ("m" git-gutter:mark-hunk) 72 | ("p" git-gutter:popup-hunk) 73 | ("R" git-gutter:set-start-revision) 74 | ("q" nil :color blue) 75 | ("Q" (git-gutter-mode -1) :color blue)) 76 | 77 | (setq-default fringes-outside-margins t) 78 | 79 | (fringe-helper-define 'git-gutter-fr:added '(center repeated) 80 | "XXX.....") 81 | (fringe-helper-define 'git-gutter-fr:modified '(center repeated) 82 | "XXX.....") 83 | (fringe-helper-define 'git-gutter-fr:deleted 'bottom 84 | "X......." 85 | "XX......" 86 | "XXX....." 87 | "XXXX....") 88 | 89 | ;; Update git-gutter on focus (in case I was using git externally) 90 | (add-hook 'focus-in-hook #'git-gutter:update-all-windows) 91 | 92 | (defun api|update-git-gutter () 93 | "Refresh git-gutter on `ESC'. Return nil to prevent shadowing other 94 | `+evil-esc-hook' hooks." 95 | (when git-gutter-mode 96 | (git-gutter) 97 | nil)) 98 | (add-hook '+evil-esc-hook #'api|update-git-gutter t)) 99 | 100 | (provide 'setup-git) 101 | ;;; setup-git.el ends here 102 | -------------------------------------------------------------------------------- /.emacs.d/lisp/init-core.el: -------------------------------------------------------------------------------- 1 | ;;; core.el --- Core Emacs stuff -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;;; Code: 6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7 | 8 | ;;------------------------------------------------------------------------------ 9 | ;; `benchmark-init': Benchmark init files. 10 | ;;------------------------------------------------------------------------------ 11 | (use-package benchmark-init 12 | :if (not (bound-and-true-p byte-compile-current-file)) 13 | :init 14 | (require 'benchmark-init) 15 | ;; To disable collection of benchmark data after init is done. 16 | :hook (after-init . benchmark-init/deactivate)) 17 | 18 | ;;------------------------------------------------------------------------------ 19 | ;; `desktop': Allow saving sessions. 20 | ;;------------------------------------------------------------------------------ 21 | (use-package desktop 22 | :disabled 23 | :ensure nil ;; in-built 24 | :init 25 | (progn 26 | (desktop-save-mode 1) 27 | (setq desktop-auto-save-timeout 60 28 | desktop-globals-to-save 29 | (append '((file-name-history . 100) 30 | (compile-history . 100) 31 | (command-history . 100) 32 | (extended-command-history . 100) 33 | (shell-command-history . 100) 34 | (query-replace-history . 100) 35 | (regexp-history . 100) 36 | (grep-history . 100) 37 | (minibuffer-history . 100)) 38 | desktop-globals-to-save)))) 39 | 40 | ;;------------------------------------------------------------------------------ 41 | ;; `esup': Emacs Startup Profiler 42 | ;;------------------------------------------------------------------------------ 43 | (use-package esup 44 | :commands (esup)) 45 | 46 | ;;------------------------------------------------------------------------------ 47 | ;; `fullscreen': Advice commands to execute fullscreen, restoring original 48 | ;; window setup when exiting. 49 | ;;------------------------------------------------------------------------------ 50 | (use-package fullframe 51 | :init 52 | (defun api|init-fullframe () 53 | (fullframe list-package quit-window)) 54 | (add-hook 'emacs-startup-hook #'api|init-fullframe)) 55 | 56 | ;;------------------------------------------------------------------------------ 57 | ;; `helpful': better contextual help. 58 | ;;------------------------------------------------------------------------------ 59 | (use-package helpful 60 | ;;:disabled 61 | :commands (helpful-callable 62 | helpful-key 63 | helpful-variable 64 | helpful-symbol) 65 | :bind 66 | (("C-h k" . helpful-key) 67 | ("C-h f" . helpful-callable) 68 | ("C-h v" . helpful-variable)) 69 | :init 70 | (defalias #'describe-key #'helpful-key) 71 | (defalias #'describe-function #'helpful-callable) 72 | (defalias #'describe-variable #'helpful-variable) 73 | (defalias #'describe-symbol #'helpful-symbol)) 74 | 75 | ;;------------------------------------------------------------------------------ 76 | ;; `no-littering': do not litter emacs.d. 77 | ;;------------------------------------------------------------------------------ 78 | (use-package no-littering 79 | :init 80 | (setq no-littering-etc-directory 81 | (expand-file-name "config/" user-emacs-directory)) 82 | (setq no-littering-var-directory 83 | (expand-file-name "data/" user-emacs-directory)) 84 | (require 'no-littering) 85 | (setq custom-file (no-littering-expand-etc-file-name "custom.el"))) 86 | 87 | ;;------------------------------------------------------------------------------ 88 | ;; `terminal-here': launch terminals at current file location. 89 | ;;------------------------------------------------------------------------------ 90 | (use-package terminal-here 91 | :commands (terminal-here-launch terminal-here-project-launch)) 92 | 93 | (provide 'init-core) 94 | 95 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 96 | ;;; init-core.el ends here 97 | -------------------------------------------------------------------------------- /.emacs.d/lisp/init-frames.el: -------------------------------------------------------------------------------- 1 | ;; init-frames.el --- Emacs frames -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;;; Code: 6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7 | 8 | (setq-default 9 | ;; do not mess with frame size when altering fonts or settings. 10 | frame-inhibit-implied-resize t) 11 | 12 | ;;; Transparent titlebar 13 | ;; https://github.com/d12frosted/homebrew-emacs-plus/blob/master/Formula/emacs-plus.rb#L98 14 | ;; https://github.com/d12frosted/homebrew-emacs-plus/issues/55 15 | ;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Properties-in-Mode.html#Properties-in-Mode 16 | (when (memq window-system '(mac ns)) 17 | ;;(add-to-list 'default-frame-alist '(ns-appearance . dark)) ; nil for dark text 18 | ;;(add-to-list 'default-frame-alist '(ns-transparent-titlebar . nil))) 19 | (add-to-list 'default-frame-alist '(ns-transparent-titlebar . t)) 20 | (add-to-list 'default-frame-alist '(ns-appearance . light))) 21 | 22 | ;;------------------------------------------------------------------------------ 23 | ;; `frames-only-mode': Use frames only, no windows (use tiling managers). 24 | ;; http://compsoc.man.ac.uk/~shep/tearing-out-the-emacs-window-manager.html 25 | ;;------------------------------------------------------------------------------ 26 | (use-package frames-only-mode 27 | :disabled 28 | :hook (emacs-startup . frames-only-mode)) 29 | ;;:init 30 | ;;(add-hook 'emacs-startup-hook (lambda () (frames-only-mode t)))) 31 | ;;:config (frames-only-mode t)) 32 | 33 | ;;------------------------------------------------------------------------------ 34 | ;; `nameframe': Use named frames. 35 | ;;------------------------------------------------------------------------------ 36 | (use-package nameframe 37 | :commands (nameframe-frame-alist 38 | nameframe-get-frame 39 | nameframe-make-frame) 40 | :config (require 'nameframe)) 41 | 42 | ;;------------------------------------------------------------------------------ 43 | ;; `yequake': Drop-down emacs frames 44 | ;;------------------------------------------------------------------------------ 45 | (use-package yequake 46 | :commands (yequake-toggle 47 | yequake-org-capture 48 | yequake-retoggle) 49 | :config 50 | (setq yequake-frames 51 | '(("Org" . 52 | ((name . "Org") 53 | (width . 0.9) 54 | (height . 0.8) 55 | (alpha . 0.95) 56 | (buffer-fns . ((lambda nil 57 | (or (get-buffer "*Org Agenda*") 58 | (save-excursion 59 | (org-agenda-list) 60 | (current-buffer)))) 61 | split-window-horizontally 62 | "~/iCloud/beorg/org-mode/organizer.org")) 63 | (frame-parameters . ((undecorated . t) 64 | (skip-taskbar . t) 65 | (sticky . t))))) 66 | ("mu4e" . 67 | ((name . "mu4e") 68 | (width . 0.9) 69 | (height . 0.8) 70 | (alpha . 0.95) 71 | (buffer-fns . ((lambda nil 72 | (or (get-buffer "*mu4e-headers*") 73 | (get-buffer "*mu4e-main*") 74 | (save-excursion 75 | (mu4e) 76 | (current-buffer)))))) 77 | (frame-parameters . ((undecorated . t) 78 | (skip-taskbar . t) 79 | (sticky . t))))) 80 | ("Capture" . 81 | ((name . "Capture") 82 | (width . 0.75) 83 | (height . 0.5) 84 | (alpha . 0.95) 85 | (buffer-fns . (yequake-org-capture)) 86 | (frame-parameters . ((undecorated . t) 87 | (skip-taskbar . t) 88 | (sticky . t))))) 89 | ))) 90 | 91 | (provide 'init-frames) 92 | 93 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 94 | ;;; init-frames.el ends here 95 | -------------------------------------------------------------------------------- /.emacs.d/lisp/setup-projectile.el: -------------------------------------------------------------------------------- 1 | ;;; setup-projectile.el --- Projectile -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;;; Code: 6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7 | 8 | ;;------------------------------------------------------------------------------ 9 | ;; `counsel-projectile': 10 | ;;------------------------------------------------------------------------------ 11 | (use-package counsel-projectile 12 | :after (counsel 13 | projectile) 14 | :commands (counsel-projectile 15 | counsel-projectile-find-file 16 | counsel-projectile-find-dir 17 | counsel-projectile-switch-to-buffer 18 | counsel-projectile-grep 19 | counsel-projectile-ag 20 | counsel-projectile-switch-project)) 21 | 22 | ;;------------------------------------------------------------------------------ 23 | ;; `projectile': 24 | ;;------------------------------------------------------------------------------ 25 | (use-package projectile 26 | :hook (emacs-startup . projectile-mode) 27 | :init 28 | (setq projectile-sort-order 'recentf 29 | projectile-enable-caching (not noninteractive) 30 | projectile-indexing-method 'alien 31 | projectile-globally-ignored-files '(".DS_Store" "TAGS") 32 | projectile-globally-ignored-directories '("~/.emacs.d/elpa") 33 | projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o")) 34 | :config 35 | ;; Don't consider my home dir as a project 36 | (add-to-list 'projectile-ignored-projects `,(concat (getenv "HOME") "/")) 37 | 38 | ;; Default rg arguments 39 | ;; https://github.com/BurntSushi/ripgrep 40 | (defconst api--rg-arguments 41 | `("--no-ignore-vcs" ;Ignore files/dirs ONLY from `.ignore' 42 | "--line-number" ;Line numbers 43 | "--smart-case" 44 | "--follow" ;Follow symlinks 45 | "--max-columns" "150" ;Emacs doesn't handle long line lengths very well 46 | "--ignore-file" ,(expand-file-name ".ignore" (getenv "HOME"))) 47 | "Default rg arguments used in the functions in `counsel' and `projectile' packages.") 48 | 49 | (defun api*advice-projectile-use-rg () 50 | "Always use `rg' for getting a list of all files in the project." 51 | (let* ((prj-user-ignore-name (expand-file-name 52 | (concat ".ignore." user-login-name) 53 | (projectile-project-root))) 54 | (prj-user-ignore (when (file-exists-p prj-user-ignore-name) 55 | (concat "--ignore-file " prj-user-ignore-name)))) 56 | (mapconcat #'shell-quote-argument 57 | (if prj-user-ignore 58 | (append '("rg") 59 | api--rg-arguments 60 | `(,prj-user-ignore) 61 | '("--null" ;Output null separated results 62 | ;; Get names of all the to-be-searched files, 63 | ;; same as the "-g ''" argument in ag. 64 | "--files")) 65 | (append '("rg") 66 | api--rg-arguments 67 | '("--null" 68 | "--files"))) 69 | " "))) 70 | 71 | (if (executable-find "rg") 72 | (advice-add 'projectile-get-ext-command :override #'api*advice-projectile-use-rg)) 73 | 74 | (after! ivy 75 | (setq projectile-completion-system 'ivy)) 76 | 77 | ;; (after! helm 78 | ;; (defvar helm-projectile-find-file-map (make-sparse-keymap)) 79 | ;; (require 'helm-projectile) 80 | ;; (set-keymap-parent helm-projectile-find-file-map helm-map)) 81 | 82 | (add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook)) 83 | 84 | ;;------------------------------------------------------------------------------ 85 | ;; `nameframe-projectile': 86 | ;;------------------------------------------------------------------------------ 87 | (use-package nameframe-projectile 88 | :after (nameframe projectile) 89 | :hook (emacs-startup . nameframe-projectile-mode) 90 | :config 91 | (require 'nameframe-projectile)) 92 | 93 | (provide 'setup-projectile) 94 | 95 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 96 | ;;; setup-projectile.el ends here 97 | -------------------------------------------------------------------------------- /.emacs.d/lisp/setup-ivy.el: -------------------------------------------------------------------------------- 1 | ;;; setup-ivy.el --- Ivy setup -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;; Setup ivy and related packages. 6 | 7 | ;;; Code: 8 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 9 | 10 | ;;------------------------------------------------------------------------------ 11 | ;; Allow persisting ivy-views. 12 | ;;------------------------------------------------------------------------------ 13 | (defconst ivy-views-file 14 | (expand-file-name (concat user-emacs-data-directory "ivy/ivy-views.el")) 15 | "File in which ivy-views will be saved.") 16 | 17 | ;;------------------------------------------------------------------------------ 18 | ;; `ivy': 19 | ;;------------------------------------------------------------------------------ 20 | (use-package ivy 21 | :ensure ivy-hydra 22 | :hook (emacs-startup . ivy-mode) 23 | :config 24 | (setq ivy-height 12 25 | ivy-do-completion-in-region nil 26 | ivy-wrap t 27 | ivy-fixed-height-minibuffer t 28 | ivy-use-virtual-buffers t 29 | smex-completion-method 'ivy 30 | ;; highlight til EOL 31 | ivy-format-function #'ivy-format-function-line 32 | ;; disable magic slash on non-match 33 | ivy-magic-slash-non-match-action nil 34 | ;; Do not show ^ 35 | ivy-initial-inputs-alist nil) 36 | 37 | (defun api/save-ivy-views () 38 | "Save ivy-views to file." 39 | (interactive) 40 | (with-temp-file ivy-views-file 41 | (prin1 ivy-views (current-buffer)) 42 | (message "Saved ivy-views to file %s." ivy-views-file))) 43 | 44 | (defun api/load-ivy-views () 45 | "Load ivy-views from file." 46 | (interactive) 47 | (if (file-exists-p ivy-views-file) 48 | (progn (setq ivy-views 49 | (with-temp-buffer (insert-file-contents ivy-views-file) 50 | (read (current-buffer)))) 51 | (message "Loaded ivy-views from file %s." ivy-views-file)) 52 | (message "File %s does not exist!" ivy-views-file))) 53 | 54 | (api/load-ivy-views)) 55 | 56 | ;;------------------------------------------------------------------------------ 57 | ;; `ivy-posframe': 58 | ;;------------------------------------------------------------------------------ 59 | (use-package ivy-posframe 60 | ;;:disabled 61 | :hook (ivy-mode . ivy-posframe-mode) 62 | :config 63 | (defun api/ivy-posframe-get-size () 64 | "Set the ivy-posframe size according to the current frame." 65 | (let ((height (or ivy-posframe-height (or ivy-height 10))) 66 | (width (min (or ivy-posframe-width 200) (round (* 0.99 (frame-width)))))) 67 | (list :height height :width width :min-height height :min-width width))) 68 | 69 | (setq ivy-posframe-display-functions-alist '((t . ivy-posframe-display-at-frame-top-center)) 70 | ivy-fixed-height-minibuffer nil 71 | ivy-posframe-size-function 'api/ivy-posframe-get-size 72 | ;;ivy-posframe-width '(frame-width) 73 | ivy-posframe-border-width 10)) 74 | 75 | ;;------------------------------------------------------------------------------ 76 | ;; `ivy-rich': Show more info in ivy-switch-buffer. 77 | ;;------------------------------------------------------------------------------ 78 | (use-package ivy-rich 79 | :commands (ivy-rich-switch-buffer-transformer) 80 | :hook (ivy-mode . ivy-rich-mode) 81 | :init 82 | (setq ivy-virtual-abbreviate 'full 83 | ivy-rich-switch-buffer-align-virtual-buffer t 84 | ivy-rich-path-style 'abbrev)) 85 | 86 | ;;------------------------------------------------------------------------------ 87 | ;; `swiper': 88 | ;;------------------------------------------------------------------------------ 89 | (use-package swiper 90 | :commands (swiper 91 | swiper-all)) 92 | 93 | ;;------------------------------------------------------------------------------ 94 | ;; `counsel': 95 | ;;------------------------------------------------------------------------------ 96 | (use-package counsel 97 | :commands (counsel-ag counsel-rg counsel-pt counsel-apropos counsel-bookmark 98 | counsel-describe-function counsel-describe-variable 99 | counsel-describe-face counsel-M-x counsel-file-jump 100 | counsel-find-file counsel-find-library counsel-info-lookup-symbol 101 | counsel-imenu counsel-recentf counsel-yank-pop 102 | counsel-descbinds counsel-org-capture counsel-grep-or-swiper) 103 | :config 104 | ;; Counsel resets the ivy-initial-inputs-alist to default, so 105 | ;; set it not to show ^. 106 | (setq ivy-initial-inputs-alist nil)) 107 | 108 | ;;------------------------------------------------------------------------------ 109 | ;; `smex': Used by counsel-M-x 110 | ;;------------------------------------------------------------------------------ 111 | (use-package smex 112 | :commands (smex smex-major-mode-commands) 113 | :config 114 | (smex-initialize)) 115 | 116 | (provide 'setup-ivy) 117 | 118 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 119 | ;;; setup-ivy.el ends here 120 | -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | set nocompatible 2 | 3 | "------------------------------------------------------------------------------ 4 | " Plugins 5 | " ----------------------------------------------------------------------------- 6 | 7 | " Set up Plug if not present. 8 | if empty(glob('~/.vim/autoload/plug.vim')) 9 | silent !curl -fLo ~/.vim/autoload/plug.vim --create-dirs 10 | \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim 11 | autocmd VimEnter * PlugInstall | source ~/.vimrc 12 | endif 13 | 14 | call plug#begin('~/.vim/plugged') 15 | 16 | Plug 'vim-airline/vim-airline' 17 | Plug 'vim-airline/vim-airline-themes' 18 | Plug 'altercation/vim-colors-solarized' 19 | Plug 'junegunn/seoul256.vim' 20 | Plug 'flazz/vim-colorschemes' 21 | Plug 'morhetz/gruvbox' 22 | Plug 'airblade/vim-gitgutter' 23 | Plug 'tpope/vim-vinegar' 24 | Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': '.install --all' } 25 | Plug '/usr/local/opt/fzf' | Plug 'junegunn/fzf.vim' 26 | Plug 'easymotion/vim-easymotion' 27 | Plug 'LaTeX-Box-Team/LaTeX-Box' 28 | Plug 'derekwyatt/vim-scala', { 'for': 'scala' } 29 | "if has('nvim') 30 | " Plug 'Shougo/deoplete.nvim', { 'do': ':UpdateRemotePlugins' } 31 | "else 32 | " Plug 'Shougo/deoplete.nvim' 33 | " Plug 'roxma/nvim-yarp' 34 | " Plug 'roxma/vim-hug-neovim-rpc' 35 | "endif 36 | Plug 'myusuf3/numbers.vim' 37 | Plug 'tpope/vim-obsession' 38 | Plug 'hecal3/vim-leader-guide' 39 | Plug 'mhinz/vim-startify' 40 | Plug 'scrooloose/nerdcommenter' 41 | Plug 'w0rp/ale' 42 | 43 | call plug#end() 44 | 45 | filetype plugin indent on 46 | 47 | "------------------------------------------------------------------------------ 48 | " General 49 | " ----------------------------------------------------------------------------- 50 | 51 | syntax enable " Enable syntax highlighting. 52 | 53 | if &encoding ==# 'latin1' && has('gui_running') 54 | set encoding=utf-8 55 | endif 56 | set autoindent " Indentation level for next line. 57 | set backspace=indent,eol,start " Be more flexible with backspace. 58 | set autoread " reload files when changed. 59 | set showmode " Don't show mode, for airline. 60 | set nowrap " Don't wrap lines. 61 | set incsearch " Incremental search. 62 | set ignorecase " Ignore case while searching. 63 | set number " Show line numbers. 64 | set nocursorline " Highlight current line. 65 | set ruler " Show where we are. 66 | set showmatch " Show matching brackets. 67 | set colorcolumn=80 " Guideline at 80th column. 68 | set shiftwidth=4 " 4 indents for tabs. 69 | set expandtab " Expand tabs to spaces. 70 | set tabstop=4 " 4 column indents. 71 | set softtabstop=4 " Insert mode tab and backspace use 4 spaces. 72 | set clipboard+=unnamed " Yank and paste with system clipboard. 73 | set laststatus=2 " Show status line. 74 | set wildmenu " Wildcard searches. 75 | set complete-=i " Ignore included files in complete. 76 | set smarttab " Use smarttabs. 77 | set nobackup " No need for backups. 78 | set nowb " No autobackup. 79 | set noswapfile " No swap. 80 | 81 | "------------------------------------------------------------------------------ 82 | " Plugin related settings 83 | " ----------------------------------------------------------------------------- 84 | 85 | " airline 86 | let g:airline#extensions#tabline#enabled=1 87 | let g:airline#extensions#tabline#fnamemod=':t' 88 | let g:airline_powerline_fonts=1 89 | let g:airline_theme='zenburn' 90 | 91 | " ALE 92 | let g:ale_sign_warning = '▲' 93 | let g:ale_sign_error = '✗' 94 | highlight link ALEWarningSign String 95 | highlight link ALEErrorSign Title 96 | 97 | " deoplete 98 | let g:deoplete#enable_at_startup=1 99 | 100 | " gruvbox 101 | let g:gruvbox_contrast_light='soft' 102 | let g:gruvbox_contrast_dark='soft' 103 | 104 | " seoul256 105 | let g:seoul256_background = 237 106 | let g:seoul256_light_background = 253 107 | 108 | "------------------------------------------------------------------------------ 109 | " Key remaps 110 | "------------------------------------------------------------------------------ 111 | 112 | let mapleader="\" 113 | 114 | nnoremap w :w 115 | inoremap w :w 116 | nnoremap bb :Buffers 117 | nnoremap bd :bd 118 | nnoremap : 119 | nnoremap e :Files 120 | 121 | ino jk 122 | cno jk 123 | vno v 124 | 125 | nnoremap :bnext 126 | nnoremap :bprevious 127 | nnoremap 128 | nnoremap 129 | nnoremap 130 | nnoremap 131 | 132 | " Reformat selected text (fill region) 133 | nnoremap fr gq 134 | " Reformat paragraph (fill paragraph) 135 | nnoremap fp gq} 136 | 137 | " Configure leader guide. 138 | let g:lmap = {} 139 | call leaderGuide#register_prefix_descriptions("", "g:lmap") 140 | nnoremap :LeaderGuide '' 141 | vnoremap :LeaderGuideVisual '' 142 | 143 | if has('gui_running') 144 | set lines=40 145 | set macligatures 146 | set guifont=PragmataPro:h14 147 | endif 148 | 149 | "set background=light 150 | "colorscheme gruvbox 151 | "colorscheme seoul256 152 | colorscheme zenburn 153 | 154 | let g:fzf_colors = 155 | \ { 'fg': ['fg', 'Normal'], 156 | \ 'bg': ['bg', 'Normal'], 157 | \ 'hl': ['fg', 'Comment'], 158 | \ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'], 159 | \ 'bg+': ['bg', 'CursorLine', 'CursorColumn'], 160 | \ 'hl+': ['fg', 'Statement'], 161 | \ 'info': ['fg', 'PreProc'], 162 | \ 'prompt': ['fg', 'Conditional'], 163 | \ 'pointer': ['fg', 'Exception'], 164 | \ 'marker': ['fg', 'Keyword'], 165 | \ 'spinner': ['fg', 'Label'], 166 | \ 'header': ['fg', 'Comment'] } 167 | 168 | if has('nvim') 169 | set termguicolors " Doesn't work with Terminal.app. 170 | let $NVIM_TUI_ENABLE_TRUE_COLOR=1 171 | endif 172 | -------------------------------------------------------------------------------- /.mbsyncrc: -------------------------------------------------------------------------------- 1 | Create Slave 2 | Expunge Both 3 | SyncState * 4 | 5 | # IMAPAccount anand.iyer@berkeley.edu 6 | # 7 | 8 | IMAPAccount bmail 9 | Host imap.gmail.com 10 | User anand.iyer@berkeley.edu 11 | PassCmd "security find-generic-password -s emacs-email -a anand.iyer@berkeley.edu -w" 12 | SSLType IMAPS 13 | AuthMechs LOGIN 14 | 15 | IMAPStore bmail-remote 16 | Account bmail 17 | 18 | MaildirStore bmail-local 19 | Path ~/Maildir/bmail/ 20 | Inbox ~/Maildir/bmail/Inbox 21 | 22 | Channel bmail-inbox 23 | Master :bmail-remote:"INBOX" 24 | Slave :bmail-local:"Inbox" 25 | #Patterns "INBOX" 26 | 27 | Channel bmail-all 28 | Master :bmail-remote:"[Gmail]/All Mail" 29 | Slave :bmail-local:all 30 | 31 | Channel bmail-drafts 32 | Master :bmail-remote:"[Gmail]/Drafts" 33 | Slave :bmail-local:drafts 34 | 35 | Channel bmail-sent 36 | Master :bmail-remote:"[Gmail]/Sent Mail" 37 | Slave :bmail-local:sent 38 | 39 | Channel bmail-trash 40 | Master :bmail-remote:"[Gmail]/Trash" 41 | Slave :bmail-local:trash 42 | 43 | Group bmail 44 | Channel bmail-all 45 | Channel bmail-inbox 46 | Channel bmail-drafts 47 | Channel bmail-sent 48 | Channel bmail-trash 49 | 50 | # IMAPAccount anand.padmanabha.iyer@gmail.com 51 | # 52 | 53 | IMAPAccount anand.padmanabha.iyer@gmail.com 54 | Host imap.gmail.com 55 | User anand.padmanabha.iyer@gmail.com 56 | PassCmd "security find-generic-password -s emacs-email -a anand.padmanabha.iyer@gmail.com -w" 57 | SSLType IMAPS 58 | AuthMechs LOGIN 59 | 60 | IMAPStore anand.padmanabha.iyer@gmail.com-remote 61 | Account anand.padmanabha.iyer@gmail.com 62 | 63 | MaildirStore anand.padmanabha.iyer@gmail.com-local 64 | Path ~/Maildir/anand.padmanabha.iyer@gmail.com/ 65 | Inbox ~/Maildir/anand.padmanabha.iyer@gmail.com/inbox 66 | 67 | Channel anand.padmanabha.iyer@gmail.com-inbox 68 | Master :anand.padmanabha.iyer@gmail.com-remote: 69 | Slave :anand.padmanabha.iyer@gmail.com-local: 70 | Patterns "INBOX" 71 | 72 | Channel anand.padmanabha.iyer@gmail.com-all 73 | Master :anand.padmanabha.iyer@gmail.com-remote:"[Gmail]/All Mail" 74 | Slave :anand.padmanabha.iyer@gmail.com-local:all 75 | 76 | Channel anand.padmanabha.iyer@gmail.com-drafts 77 | Master :anand.padmanabha.iyer@gmail.com-remote:"[Gmail]/Drafts" 78 | Slave :anand.padmanabha.iyer@gmail.com-local:drafts 79 | 80 | Channel anand.padmanabha.iyer@gmail.com-sent 81 | Master :anand.padmanabha.iyer@gmail.com-remote:"[Gmail]/Sent Mail" 82 | Slave :anand.padmanabha.iyer@gmail.com-local:sent 83 | 84 | Channel anand.padmanabha.iyer@gmail.com-trash 85 | Master :anand.padmanabha.iyer@gmail.com-remote:"[Gmail]/Trash" 86 | Slave :anand.padmanabha.iyer@gmail.com-local:trash 87 | 88 | Group anand.padmanabha.iyer@gmail.com 89 | Channel anand.padmanabha.iyer@gmail.com-inbox 90 | Channel anand.padmanabha.iyer@gmail.com-all 91 | Channel anand.padmanabha.iyer@gmail.com-drafts 92 | Channel anand.padmanabha.iyer@gmail.com-sent 93 | Channel anand.padmanabha.iyer@gmail.com-trash 94 | 95 | # IMAPAccount anand.iyer.p@gmail.com 96 | # 97 | 98 | IMAPAccount anand.iyer.p@gmail.com 99 | Host imap.gmail.com 100 | User anand.iyer.p@gmail.com 101 | PassCmd "security find-generic-password -s emacs-email -a anand.iyer.p@gmail.com -w" 102 | SSLType IMAPS 103 | AuthMechs LOGIN 104 | 105 | IMAPStore anand.iyer.p@gmail.com-remote 106 | Account anand.iyer.p@gmail.com 107 | 108 | MaildirStore anand.iyer.p@gmail.com-local 109 | Path ~/Maildir/anand.iyer.p@gmail.com/ 110 | Inbox ~/Maildir/anand.iyer.p@gmail.com/inbox 111 | 112 | Channel anand.iyer.p@gmail.com-inbox 113 | Master :anand.iyer.p@gmail.com-remote: 114 | Slave :anand.iyer.p@gmail.com-local: 115 | Patterns "INBOX" 116 | 117 | Channel anand.iyer.p@gmail.com-all 118 | Master :anand.iyer.p@gmail.com-remote:"[Gmail]/All Mail" 119 | Slave :anand.iyer.p@gmail.com-local:all 120 | 121 | Channel anand.iyer.p@gmail.com-drafts 122 | Master :anand.iyer.p@gmail.com-remote:"[Gmail]/Drafts" 123 | Slave :anand.iyer.p@gmail.com-local:drafts 124 | 125 | Channel anand.iyer.p@gmail.com-sent 126 | Master :anand.iyer.p@gmail.com-remote:"[Gmail]/Sent Mail" 127 | Slave :anand.iyer.p@gmail.com-local:sent 128 | 129 | Channel anand.iyer.p@gmail.com-trash 130 | Master :anand.iyer.p@gmail.com-remote:"[Gmail]/Trash" 131 | Slave :anand.iyer.p@gmail.com-local:trash 132 | 133 | Group anand.iyer.p@gmail.com 134 | Channel anand.iyer.p@gmail.com-inbox 135 | Channel anand.iyer.p@gmail.com-all 136 | Channel anand.iyer.p@gmail.com-drafts 137 | Channel anand.iyer.p@gmail.com-sent 138 | Channel anand.iyer.p@gmail.com-trash 139 | 140 | # IMAPAccount sand.rain.online@gmail.com 141 | # 142 | 143 | IMAPAccount sand.rain.online@gmail.com 144 | Host imap.gmail.com 145 | User sand.rain.online@gmail.com 146 | PassCmd "security find-generic-password -s emacs-email -a sand.rain.online@gmail.com -w" 147 | SSLType IMAPS 148 | AuthMechs LOGIN 149 | 150 | IMAPStore sand.rain.online@gmail.com-remote 151 | Account sand.rain.online@gmail.com 152 | 153 | MaildirStore sand.rain.online@gmail.com-local 154 | Path ~/Maildir/sand.rain.online@gmail.com/ 155 | Inbox ~/Maildir/sand.rain.online@gmail.com/INBOX 156 | 157 | Channel sand.rain.online@gmail.com-inbox 158 | Master :sand.rain.online@gmail.com-remote: 159 | Slave :sand.rain.online@gmail.com-local: 160 | Patterns "INBOX" 161 | 162 | Channel sand.rain.online@gmail.com-all 163 | Master :sand.rain.online@gmail.com-remote:"[Gmail]/All Mail" 164 | Slave :sand.rain.online@gmail.com-local:all 165 | 166 | Channel sand.rain.online@gmail.com-drafts 167 | Master :sand.rain.online@gmail.com-remote:"[Gmail]/Drafts" 168 | Slave :sand.rain.online@gmail.com-local:drafts 169 | 170 | Channel sand.rain.online@gmail.com-sent 171 | Master :sand.rain.online@gmail.com-remote:"[Gmail]/Sent Mail" 172 | Slave :sand.rain.online@gmail.com-local:sent 173 | 174 | Channel sand.rain.online@gmail.com-trash 175 | Master :sand.rain.online@gmail.com-remote:"[Gmail]/Trash" 176 | Slave :sand.rain.online@gmail.com-local:trash 177 | 178 | Group sand.rain.online@gmail.com 179 | Channel sand.rain.online@gmail.com-inbox 180 | Channel sand.rain.online@gmail.com-all 181 | Channel sand.rain.online@gmail.com-drafts 182 | Channel sand.rain.online@gmail.com-sent 183 | Channel sand.rain.online@gmail.com-trash 184 | 185 | # Gmail mailboxes: 186 | # "All Mail" 187 | # "Drafts" 188 | # "Important" 189 | # "Sent Mail" 190 | # "Spam" 191 | # "Starred" 192 | # "Trash" 193 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #=============================================================================== 2 | # MacOS 3 | #=============================================================================== 4 | # General 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | .com.apple.timemachine.donotpresent 23 | 24 | # Directories potentially created on remote AFP share 25 | .AppleDB 26 | .AppleDesktop 27 | Network Trash Folder 28 | Temporary Items 29 | .apdisk 30 | 31 | #=============================================================================== 32 | # JetBrains 33 | #=============================================================================== 34 | # Idea 35 | .idea 36 | 37 | #=============================================================================== 38 | # Latex 39 | #=============================================================================== 40 | ## Core latex/pdflatex auxiliary files: 41 | *.aux 42 | *.lof 43 | *.log 44 | *.lot 45 | *.fls 46 | *.out 47 | *.toc 48 | *.fmt 49 | *.fot 50 | *.cb 51 | *.cb2 52 | .*.lb 53 | 54 | ## Intermediate documents: 55 | *.dvi 56 | *.xdv 57 | *-converted-to.* 58 | 59 | ## Bibliography auxiliary files (bibtex/biblatex/biber): 60 | *.bbl 61 | *.bcf 62 | *.blg 63 | *-blx.aux 64 | *-blx.bib 65 | *.run.xml 66 | 67 | ## Build tool auxiliary files: 68 | *.fdb_latexmk 69 | *.synctex 70 | *.synctex(busy) 71 | *.synctex.gz 72 | *.synctex.gz(busy) 73 | *.pdfsync 74 | 75 | # minted 76 | _minted* 77 | *.pyg 78 | 79 | # auto folder when using emacs and auctex 80 | ./auto/* 81 | *.el 82 | 83 | #=============================================================================== 84 | # Sublime Text 85 | #=============================================================================== 86 | # Cache files for Sublime Text 87 | *.tmlanguage.cache 88 | *.tmPreferences.cache 89 | *.stTheme.cache 90 | 91 | # Workspace files are user-specific 92 | *.sublime-workspace 93 | 94 | # SFTP configuration file 95 | sftp-config.json 96 | 97 | # Package control specific files 98 | Package Control.last-run 99 | Package Control.ca-list 100 | Package Control.ca-bundle 101 | Package Control.system-ca-bundle 102 | Package Control.cache/ 103 | Package Control.ca-certs/ 104 | Package Control.merged-ca-bundle 105 | Package Control.user-ca-bundle 106 | oscrypto-ca-bundle.crt 107 | bh_unicode_properties.cache 108 | 109 | # Sublime-github package stores a github token in this file 110 | # https://packagecontrol.io/packages/sublime-github 111 | GitHub.sublime-settings 112 | 113 | #=============================================================================== 114 | # Emacs 115 | #=============================================================================== 116 | # -*- mode: gitignore; -*- 117 | *~ 118 | \#*\# 119 | /.emacs.desktop 120 | /.emacs.desktop.lock 121 | *.elc 122 | auto-save-list 123 | tramp 124 | .\#* 125 | 126 | # Org-mode 127 | .org-id-locations 128 | *_archive 129 | 130 | # flymake-mode 131 | *_flymake.* 132 | 133 | # eshell files 134 | /eshell/history 135 | /eshell/lastdir 136 | 137 | # elpa packages 138 | /elpa/ 139 | 140 | # reftex files 141 | *.rel 142 | 143 | # AUCTeX auto folder 144 | /auto/ 145 | 146 | # cask packages 147 | .cask/ 148 | dist/ 149 | 150 | # Flycheck 151 | flycheck_*.el 152 | 153 | # server auth directory 154 | /server/ 155 | 156 | # projectiles files 157 | .projectile 158 | 159 | # directory configuration 160 | .dir-locals.el 161 | 162 | #=============================================================================== 163 | # Python 164 | #=============================================================================== 165 | # Byte-compiled / optimized / DLL files 166 | __pycache__/ 167 | *.py[cod] 168 | *$py.class 169 | 170 | # C extensions 171 | *.so 172 | 173 | # Distribution / packaging 174 | .Python 175 | build/ 176 | develop-eggs/ 177 | dist/ 178 | downloads/ 179 | eggs/ 180 | .eggs/ 181 | lib/ 182 | lib64/ 183 | parts/ 184 | sdist/ 185 | var/ 186 | wheels/ 187 | share/python-wheels/ 188 | *.egg-info/ 189 | .installed.cfg 190 | *.egg 191 | MANIFEST 192 | 193 | # PyInstaller 194 | # Usually these files are written by a python script from a template 195 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 196 | *.manifest 197 | *.spec 198 | 199 | # Installer logs 200 | pip-log.txt 201 | pip-delete-this-directory.txt 202 | 203 | # Unit test / coverage reports 204 | htmlcov/ 205 | .tox/ 206 | .nox/ 207 | .coverage 208 | .coverage.* 209 | .cache 210 | nosetests.xml 211 | coverage.xml 212 | *.cover 213 | *.py,cover 214 | .hypothesis/ 215 | .pytest_cache/ 216 | cover/ 217 | 218 | # Translations 219 | *.mo 220 | *.pot 221 | 222 | # Django stuff: 223 | *.log 224 | local_settings.py 225 | db.sqlite3 226 | db.sqlite3-journal 227 | 228 | # Flask stuff: 229 | instance/ 230 | .webassets-cache 231 | 232 | # Scrapy stuff: 233 | .scrapy 234 | 235 | # Sphinx documentation 236 | docs/_build/ 237 | 238 | # PyBuilder 239 | .pybuilder/ 240 | target/ 241 | 242 | # Jupyter Notebook 243 | .ipynb_checkpoints 244 | 245 | # IPython 246 | profile_default/ 247 | ipython_config.py 248 | 249 | # pyenv 250 | # For a library or package, you might want to ignore these files since the code is 251 | # intended to run in multiple environments; otherwise, check them in: 252 | # .python-version 253 | 254 | # pipenv 255 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 256 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 257 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 258 | # install all needed dependencies. 259 | #Pipfile.lock 260 | 261 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 262 | __pypackages__/ 263 | 264 | # Celery stuff 265 | celerybeat-schedule 266 | celerybeat.pid 267 | 268 | # SageMath parsed files 269 | *.sage.py 270 | 271 | # Environments 272 | .env 273 | .venv 274 | env/ 275 | venv/ 276 | ENV/ 277 | env.bak/ 278 | venv.bak/ 279 | 280 | # Spyder project settings 281 | .spyderproject 282 | .spyproject 283 | 284 | # Rope project settings 285 | .ropeproject 286 | 287 | # mkdocs documentation 288 | /site 289 | 290 | # mypy 291 | .mypy_cache/ 292 | .dmypy.json 293 | dmypy.json 294 | 295 | # Pyre type checker 296 | .pyre/ 297 | 298 | # pytype static type analyzer 299 | .pytype/ 300 | 301 | # Cython debug symbols 302 | cython_debug/ 303 | 304 | -------------------------------------------------------------------------------- /.emacs.d/lisp/setup-tex.el: -------------------------------------------------------------------------------- 1 | ;;; setup-tex.el --- latex configuration -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;;; Code: 6 | 7 | ;;------------------------------------------------------------------------------ 8 | ;; Defaults & Helpers 9 | ;;------------------------------------------------------------------------------ 10 | (put 'TeX-command-extra-options 'safe-local-variable #'string) 11 | 12 | (defun api/current-bib () 13 | "Set the bibliography to the current directory." 14 | (interactive) 15 | (let ((local-bib-file (concat (file-name-directory buffer-file-name) "references.bib"))) 16 | (if (file-exists-p local-bib-file) 17 | (progn 18 | (setq bibtex-completion-bibliography local-bib-file) 19 | (message (concat "Local bib file is " local-bib-file))) 20 | (message "Local bib file references.bib not found!")))) 21 | 22 | ;;------------------------------------------------------------------------------ 23 | ;; `auctex-latexmk': Latex Mk support for AUCTeX 24 | ;;------------------------------------------------------------------------------ 25 | (use-package auctex-latexmk 26 | :commands (auctex-latexmk-setup) 27 | ;;:disabled 28 | :init 29 | (setq auctex-latexmk-inherit-TeX-PDF-mode t) 30 | (add-hook 'emacs-startup-hook #'auctex-latexmk-setup)) 31 | 32 | ;;------------------------------------------------------------------------------ 33 | ;; `bibtex': 34 | ;;------------------------------------------------------------------------------ 35 | (use-package bibtex 36 | :ensure nil ; in-built 37 | :mode ("\\.bib" . bibtex-mode) 38 | :config 39 | (setq bibtex-dialect 'biblatex 40 | bibtex-align-at-equal-sign t 41 | bibtex-autokey-name-year-separator "" 42 | bibtex-autokey-year-title-separator "" 43 | bibtex-autokey-titleword-first-ignore '("the" "a" "if" "and" "an") 44 | bibtex-autokey-titleword-length 0 45 | bibtex-autokey-titlewords 0 46 | bibtex-autokey-year-length 4)) 47 | 48 | ;;------------------------------------------------------------------------------ 49 | ;; `company-auctex': 50 | ;;------------------------------------------------------------------------------ 51 | (use-package company-auctex 52 | :after company 53 | :init 54 | (defun api|add-company-auctex-backend () 55 | "Add company-auctex to company backends." 56 | (make-variable-buffer-local 'company-backends) 57 | (company-auctex-init)) 58 | (add-hook 'latex-mode-hook #'api|add-company-auctex-backend)) 59 | 60 | ;;------------------------------------------------------------------------------ 61 | ;; `helm-bibtex': 62 | ;;------------------------------------------------------------------------------ 63 | ;; (use-package helm-bibtex 64 | ;; :disabled 65 | ;; :requires helm 66 | ;; :commands helm-bibtex 67 | ;; :init 68 | ;; (setq bibtex-completion-bibliography `(,(concat org-root-directory "papers/references.bib")) 69 | ;; bibtex-completion-library-path (concat org-root-directory "papers/pdfs") 70 | ;; bibtex-completion-notes-path (concat org-root-directory "papers/notes.org"))) 71 | 72 | ;;------------------------------------------------------------------------------ 73 | ;; `ivy-bibtex': 74 | ;;------------------------------------------------------------------------------ 75 | (use-package ivy-bibtex 76 | :after ivy 77 | :commands (ivy-bibtex 78 | ivy-bibtex-with-local-bibliography) 79 | :config 80 | (setq bibtex-completion-bibliography `(,(concat org-root-directory "papers/references.bib")) 81 | bibtex-completion-library-path (concat org-root-directory "papers/pdfs") 82 | bibtex-completion-notes-path (concat org-root-directory "papers/notes.org")) 83 | (setq ivy-bibtex-default-action 'ivy-bibtex-insert-key)) 84 | 85 | ;;------------------------------------------------------------------------------ 86 | ;; `reftex': 87 | ;;------------------------------------------------------------------------------ 88 | (use-package reftex 89 | :ensure nil ; in-built 90 | :commands (turn-on-reftex) 91 | :init 92 | (setq reftex-plug-into-AUCTeX t) 93 | (add-hook 'LaTeX-mode-hook #'turn-on-reftex)) 94 | 95 | ;;------------------------------------------------------------------------------ 96 | ;; `tex': 97 | ;;------------------------------------------------------------------------------ 98 | (use-package tex 99 | :ensure auctex 100 | :mode ("\\.tex\\'" . latex-mode) 101 | :init 102 | (setq TeX-auto-save t 103 | TeX-parse-self t 104 | TeX-save-query nil 105 | TeX-PDF-mode t 106 | ;;TeX-show-compilation t 107 | TeX-view-program-selection '((output-pdf "PDF Viewer")) 108 | ;;TeX-view-program-selection '((output-pdf "PDF Tools")) 109 | TeX-source-correlate-start-server t 110 | TeX-source-correlate-method 'synctex 111 | TeX-syntactic-comment t 112 | LaTeX-fill-break-at-separators nil 113 | LaTeX-section-hook 114 | '(LaTeX-section-heading 115 | LaTeX-section-title 116 | LaTeX-section-toc 117 | LaTeX-section-section 118 | LaTeX-section-label)) 119 | 120 | (defadvice TeX-LaTeX-sentinel 121 | (around mg-TeX-LaTeX-sentinel-open-output activate) 122 | "Open output when there are errors." 123 | ;; Run `TeX-LaTeX-sentinel' as usual. 124 | ad-do-it 125 | ;; Check for the presence of errors. 126 | (when 127 | (with-current-buffer TeX-command-buffer 128 | (plist-get TeX-error-report-switches (intern (TeX-master-file)))) 129 | ;; If there are errors, open the output buffer. 130 | (TeX-recenter-output-buffer nil))) 131 | 132 | (setq-default TeX-master nil) 133 | ;;(setq LaTeX-command-style '(("" "%(PDF)%(latex) -synctex=1 %(file-line-error) %(extraopts) %S%(PDFout)"))) 134 | (add-hook 'LaTeX-mode-hook 'TeX-PDF-mode) 135 | (add-hook 'LaTeX-mode-hook 'LaTeX-math-mode) 136 | (add-hook 'LaTeX-mode-hook 'TeX-source-correlate-mode) 137 | (add-hook 'LaTeX-mode-hook 'LaTeX-preview-setup) 138 | (add-hook 'LaTeX-mode-hook #'turn-on-auto-fill) 139 | (add-hook 'LaTeX-mode-hook 140 | (lambda () (local-set-key (kbd "") #'TeX-view)) 141 | ) 142 | :config 143 | (setq TeX-view-program-list 144 | '(("PDF Viewer" "/Applications/Skim.app/Contents/SharedSupport/displayline -b -g %n %o %b"))) 145 | (unless (assoc "PDF Tools" TeX-view-program-list-builtin) 146 | (push '("PDF Tools" TeX-pdf-tools-sync-view) TeX-view-program-list)) 147 | ;;(add-hook 'LaTeX-mode-hook (lambda () (setq compile-command "latexmk -pdf"))) 148 | (add-hook 'TeX-after-compilation-finished-functions #'TeX-revert-document-buffer)) 149 | 150 | ;;------------------------------------------------------------------------------ 151 | ;; `writegood-mode': Improve English writing. 152 | ;; 153 | ;; http://matt.might.net/articles/shell-scripts-for-passive-voice-weasel-words-duplicates/ 154 | ;;------------------------------------------------------------------------------ 155 | (use-package writegood-mode 156 | :hook (LaTeX-mode . writegood-mode)) 157 | 158 | (provide 'setup-tex) 159 | ;;; setup-tex.el ends here 160 | -------------------------------------------------------------------------------- /.emacs.d/lisp/init-evil.el: -------------------------------------------------------------------------------- 1 | ;;; init-evil.el --- Evil settings -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;;; Code: 6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7 | 8 | ;;------------------------------------------------------------------------------ 9 | ;; `evil': Extensible vi layer. 10 | ;;------------------------------------------------------------------------------ 11 | (use-package evil 12 | :hook (after-init . evil-mode) 13 | :init 14 | (setq evil-want-C-u-scroll t 15 | evil-want-visual-char-semi-exclusive t 16 | evil-want-Y-yank-to-eol t 17 | evil-magic t 18 | evil-echo-state t 19 | evil-indent-convert-tabs t 20 | evil-ex-search-vim-style-regexp t 21 | evil-ex-substitute-global t 22 | evil-ex-visual-char-range t ; column range for ex commands 23 | evil-insert-skip-empty-lines t 24 | evil-mode-line-format 'nil 25 | ;; more vim-like behavior 26 | evil-symbol-word-search t 27 | ;; don't activate mark on shift-click 28 | shift-select-mode nil) 29 | 30 | :config 31 | (evil-select-search-module 'evil-search-module 'evil-search) 32 | 33 | ;; Set cursor colors later, once theme is loaded 34 | (defun +evil*init-cursors (&rest _) 35 | (setq evil-default-cursor (face-background 'cursor nil t) 36 | evil-normal-state-cursor 'box 37 | evil-emacs-state-cursor `(,(face-foreground 'warning) box) 38 | evil-insert-state-cursor 'bar 39 | evil-visual-state-cursor 'hollow)) 40 | (advice-add #'load-theme :after #'+evil*init-cursors) 41 | 42 | ;; default modes 43 | (dolist (mode '(tabulated-list-mode view-mode comint-mode 44 | term-mode calendar-mode Man-mode grep-mode)) 45 | (evil-set-initial-state mode 'emacs)) 46 | (dolist (mode '(help-mode debugger-mode)) 47 | (evil-set-initial-state mode 'normal))) 48 | 49 | ;;------------------------------------------------------------------------------ 50 | ;; `evil-collection': Set of keybindings for evil. 51 | ;;------------------------------------------------------------------------------ 52 | (use-package evil-collection 53 | :disabled ;; TODO: Too many bugs, wait for stabilization. 54 | ;; :requires (helm) ; if evil-collection is installed before helm, helm craps out. 55 | :after (evil) 56 | :preface 57 | (setq evil-want-integration nil ; must be set before evil is loaded 58 | evil-collection-company-use-tng nil) 59 | :config 60 | (evil-collection-init)) 61 | 62 | ;;------------------------------------------------------------------------------ 63 | ;; `evil-escape': Key sequence to escape from insert state and everything else. 64 | ;;------------------------------------------------------------------------------ 65 | (use-package evil-escape 66 | :after evil 67 | :hook (after-init . evil-escape-mode) 68 | :config 69 | (setq evil-escape-excluded-states '(normal visual multiedit emacs motion) 70 | evil-escape-excluded-major-modes '(neotree-mode) 71 | evil-escape-key-sequence "fd" 72 | evil-escape-delay 0.25)) 73 | 74 | ;;------------------------------------------------------------------------------ 75 | ;; `evil-goggles': Displays a visual hint when editing with evil. 76 | ;;------------------------------------------------------------------------------ 77 | (use-package evil-goggles 78 | :after evil 79 | :hook (after-init . evil-goggles-mode) 80 | :config 81 | (setq evil-goggles-duration 0.1 82 | evil-goggles-pulse nil 83 | evil-goggles-enable-delete nil)) 84 | 85 | ;;------------------------------------------------------------------------------ 86 | ;; `evil-matchit': Press “%” to jump between matched tags in Emacs. 87 | ;;------------------------------------------------------------------------------ 88 | (use-package evil-matchit 89 | :after evil 90 | :hook (emacs-startup . global-evil-matchit-mode)) 91 | ;;:init 92 | ;;(add-hook 'emacs-startup-hook #'global-evil-matchit-mode)) 93 | 94 | ;;------------------------------------------------------------------------------ 95 | ;; `evil-mc': Multiple cursors implementation for evil-mode. 96 | ;;------------------------------------------------------------------------------ 97 | (use-package evil-mc 98 | :after hydra 99 | :commands (evil-mc-make-all-cursors 100 | evil-mc-undo-all-cursors 101 | evil-mc-pause-cursors 102 | evil-mc-resume-cursors 103 | evil-mc-make-and-goto-first-cursor 104 | evil-mc-make-and-goto-last-cursor 105 | evil-mc-make-cursor-here 106 | evil-mc-make-cursor-move-next-line 107 | evil-mc-make-cursor-move-prev-line 108 | evil-mc-make-and-goto-next-cursor 109 | evil-mc-skip-and-goto-next-cursor 110 | evil-mc-make-and-goto-prev-cursor 111 | evil-mc-skip-and-goto-prev-cursor 112 | evil-mc-make-and-goto-next-match 113 | evil-mc-skip-and-goto-next-match 114 | evil-mc-make-and-goto-prev-match 115 | evil-mc-skip-and-goto-prev-match) 116 | :init 117 | ;(defvar evil-mc-key-map (make-sparse-keymap)) 118 | ;; remove emc prefix when there is not multiple cursors 119 | (setq evil-mc-undo-cursors-on-keyboard-quit t 120 | evil-mc-mode-line 121 | `(:eval (when (> (evil-mc-get-cursor-count) 1) 122 | (format ,(propertize " %s:%d" 'face 'cursor) 123 | evil-mc-mode-line-prefix 124 | (evil-mc-get-cursor-count))))) 125 | (defhydra api@multiple-cursors (:hint nil) 126 | " 127 | ^Up^ ^Down^ ^Miscellaneous^ 128 | ---------------------------------------------- 129 | [_p_] Next [_n_] Next [_a_] Match all 130 | [_P_] Skip [_N_] Skip [_q_] Quit 131 | " 132 | ("a" evil-mc-make-all-cursors) 133 | ("n" evil-mc-make-and-goto-next-match) 134 | ("N" evil-mc-skip-and-goto-next-match) 135 | ("p" evil-mc-make-and-goto-prev-match) 136 | ("P" evil-mc-skip-and-goto-prev-match) 137 | ("q" nil)) 138 | 139 | :config 140 | (global-evil-mc-mode 1) 141 | 142 | (defun api|escape-multiple-cursors () 143 | "Clear evil-mc cursors and restore state." 144 | (when (evil-mc-has-cursors-p) 145 | (evil-mc-undo-all-cursors) 146 | (evil-mc-resume-cursors) 147 | t)) 148 | (advice-add #'evil-force-normal-state :after #'api|escape-multiple-cursors)) 149 | 150 | ;;------------------------------------------------------------------------------ 151 | ;; `evil-multiedit': Multiedit capability in evil. 152 | ;;------------------------------------------------------------------------------ 153 | (use-package evil-multiedit 154 | :commands (evil-multiedit-match-all 155 | evil-multiedit-match-and-next 156 | evil-multiedit-match-and-prev 157 | evil-multiedit-match-symbol-and-next 158 | evil-multiedit-match-symbol-and-prev 159 | evil-multiedit-toggle-marker-here 160 | evil-multiedit-toggle-or-restrict-region 161 | evil-multiedit-next 162 | evil-multiedit-prev 163 | evil-multiedit-restore 164 | evil-multiedit-abort 165 | evil-multiedit-ex-match)) 166 | 167 | ;;------------------------------------------------------------------------------ 168 | ;; `evil-nerd-commenter': Block commenting. 169 | ;;------------------------------------------------------------------------------ 170 | (use-package evil-nerd-commenter 171 | :commands (evilnc-comment-or-uncomment-lines)) 172 | 173 | (provide 'init-evil) 174 | 175 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 176 | ;;; init-evil.el ends here 177 | -------------------------------------------------------------------------------- /.zshrc: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------ 2 | # 1. Tmux 3 | #------------------------------------------------------------------------------ 4 | if [ -z "$TMUX" ] 5 | then 6 | tmux attach -t TMUX || tmux new -s TMUX 7 | fi 8 | 9 | #------------------------------------------------------------------------------ 10 | # 2. Exports 11 | #------------------------------------------------------------------------------ 12 | #export PATH="/usr/local/bin:/usr/local/sbin:$PATH" 13 | #export PATH="$HOME/.cargo/bin:$PATH" 14 | export EDITOR="emacsclient -c -n" 15 | export LC_ALL=en_US.UTF-8 16 | export LANG=en_US.UTF-8 17 | 18 | #------------------------------------------------------------------------------ 19 | # 3. Aliases 20 | #------------------------------------------------------------------------------ 21 | alias ..='cd ..' 22 | alias ...='cd ../..' 23 | alias ....='cd ../../..' 24 | alias dotfiles='/usr/local/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME' 25 | alias ll="exa -lGx" 26 | alias emacsc='emacsclient -c -n' 27 | 28 | #------------------------------------------------------------------------------ 29 | # 4. Colors 30 | #------------------------------------------------------------------------------ 31 | autoload -U colors && colors 32 | export CLICOLOR="yes" 33 | 34 | #------------------------------------------------------------------------------ 35 | # 5. Completion 36 | #------------------------------------------------------------------------------ 37 | autoload -U compinit && compinit 38 | zmodload -i zsh/complist 39 | setopt auto_menu 40 | setopt complete_in_word 41 | 42 | zstyle ':completion:*' list-colors '' 43 | 44 | #------------------------------------------------------------------------------ 45 | # 6. History 46 | #------------------------------------------------------------------------------ 47 | if [ -z $HISTFILE ]; then 48 | HISTFILE=$HOME/.zsh_history 49 | fi 50 | HISTSIZE=10000 51 | SAVEHIST=10000 52 | 53 | setopt append_history 54 | setopt inc_append_history 55 | setopt extended_history 56 | setopt hist_expire_dups_first 57 | setopt hist_ignore_dups 58 | setopt hist_ignore_space 59 | setopt hist_verify 60 | setopt share_history 61 | 62 | #------------------------------------------------------------------------------ 63 | # 7. Prompt 64 | #------------------------------------------------------------------------------ 65 | #autoload -U promptinit && promptinit 66 | #prompt pure 67 | 68 | ## http://zanshin.net/2013/02/02/zsh-configuration-from-the-ground-up/ 69 | ## http://sheerun.net/2014/03/21/how-to-boost-your-vim-productivity/ 70 | ## https://github.com/myfreeweb/dotfiles/blob/master/zsh/zshrc 71 | 72 | #------------------------------------------------------------------------------ 73 | # 8. Functions 74 | #------------------------------------------------------------------------------ 75 | ## Use ctrl-z to return to paused Vim instead of 'fg'. 76 | ## http://sheerun.net/2014/03/21/how-to-boost-your-vim-productivity/ 77 | fancy-ctrl-z () { 78 | if [[ $#BUFFER -eq 0 ]]; then 79 | BUFFER="fg" 80 | zle accept-line 81 | else 82 | zle push-input 83 | zle clear-screen 84 | fi 85 | } 86 | zle -N fancy-ctrl-z 87 | bindkey '^Z' fancy-ctrl-z 88 | 89 | ##------------------------------------------------------------------- 90 | ## myIP address 91 | ## ------------------------------------------------------------------- 92 | function myip() { 93 | ifconfig lo0 | grep 'inet ' | sed -e 's/:/ /' | awk '{print "lo0 : " $2}' 94 | ifconfig en0 | grep 'inet ' | sed -e 's/:/ /' | awk '{print "en0 (IPv4): " $2 " " $3 " " $4 " " $5 " " $6}' 95 | ifconfig en0 | grep 'inet6 ' | sed -e 's/ / /' | awk '{print "en0 (IPv6): " $2 " " $3 " " $4 " " $5 " " $6}' 96 | ifconfig en1 | grep 'inet ' | sed -e 's/:/ /' | awk '{print "en1 (IPv4): " $2 " " $3 " " $4 " " $5 " " $6}' 97 | ifconfig en1 | grep 'inet6 ' | sed -e 's/ / /' | awk '{print "en1 (IPv6): " $2 " " $3 " " $4 " " $5 " " $6}' 98 | } 99 | 100 | # ------------------------------------------------------------------- 101 | # compressed file expander 102 | # (from https://github.com/myfreeweb/zshuery/blob/master/zshuery.sh) 103 | # ------------------------------------------------------------------- 104 | ex() { 105 | if [[ -f $1 ]]; then 106 | case $1 in 107 | *.tar.bz2) tar xvjf $1;; 108 | *.tar.gz) tar xvzf $1;; 109 | *.tar.xz) tar xvJf $1;; 110 | *.tar.lzma) tar --lzma xvf $1;; 111 | *.bz2) bunzip $1;; 112 | *.rar) unrar $1;; 113 | *.gz) gunzip $1;; 114 | *.tar) tar xvf $1;; 115 | *.tbz2) tar xvjf $1;; 116 | *.tgz) tar xvzf $1;; 117 | *.zip) unzip $1;; 118 | *.Z) uncompress $1;; 119 | *.7z) 7z x $1;; 120 | *.dmg) hdiutul mount $1;; # mount OS X disk images 121 | *) echo "'$1' cannot be extracted via >ex<";; 122 | esac 123 | else 124 | echo "'$1' is not a valid file" 125 | fi 126 | } 127 | 128 | #------------------------------------------------------------------------------ 129 | # 9. FASD & FZF 130 | # - https://github.com/clvv/fasd 131 | #------------------------------------------------------------------------------ 132 | eval "$(fasd --init auto)" 133 | [ -f ~/.fzf.zsh ] && source ~/.fzf.zsh 134 | 135 | export FZF_DEFAULT_COMMAND='rg --files --no-ignore --hidden --follow -g "!{.git,node_modules}/*" 2> /dev/null' 136 | export FZF_CTRL_T_OPTS="--select-1 --exit-0" 137 | export FZF_COMPLETION_TRIGGER='' 138 | 139 | #bindkey '^T' fzf-completion 140 | #bindkey '^I' $fzf_default_completion 141 | 142 | # Use fd (https://github.com/sharkdp/fd) instead of the default find 143 | # command for listing path candidates. 144 | # - The first argument to the function ($1) is the base path to start traversal 145 | # - See the source code (completion.{bash,zsh}) for the details. 146 | _fzf_compgen_path() { 147 | fd --hidden --follow --exclude ".git" . "$1" 148 | } 149 | 150 | # Use fd to generate the list for directory completion 151 | _fzf_compgen_dir() { 152 | fd --type d --hidden --follow --exclude ".git" . "$1" 153 | } 154 | 155 | # fasd & fzf - jump using `fasd` if argument is given, filter output of `fasd` 156 | # using `fzf` otherwise. 157 | unalias j 2>/dev/null 158 | j() { 159 | [ $# -gt 0 ] && fasd_cd -d "$*" && return 160 | local dir 161 | dir="$(fasd -Rdl "$1" | fzf -1 -0 --no-sort +m)" && cd "${dir}" || return 1 162 | } 163 | 164 | # fasd & fzf - use $EDITOR to edit file. Pick best matched file using `fasd` 165 | # if argument given, else use `fzf` to filter `fasd` output. 166 | unalias e 2>/dev/null 167 | e() { 168 | [ $# -gt 0 ] && fasd -f -e ${EDITOR} "$*" && return 169 | local file 170 | file="$(fasd -Rfl "$1" | fzf -1 -0 --no-sort +m)" && ${EDITOR} "${file}" || return 1 171 | } 172 | 173 | # fe [FUZZY PATTERN] - Open the selected file with the default editor 174 | # - Bypass fuzzy finder if there's only one match (--select-1) 175 | # - Exit if there's no match (--exit-0) 176 | fe() { 177 | local files 178 | IFS=$'\n' files=($(fzf-tmux --query="$1" --multi --select-1 --exit-0)) 179 | [[ -n "$files" ]] && ${EDITOR:-vim} "${files[@]}" 180 | } 181 | 182 | # fasd & fzf - open finder. If argument given, use `fasd` to pick the best match 183 | # else use `fzf` to select from `fasd` results. 184 | unalias o 2>/dev/null 185 | o() { 186 | [ $# -gt 0 ] && fasd -a -e open "$*" && return 187 | local res 188 | res="$(fasd -Rla "$1" | fzf -1 -0 --no-sort +m)" 189 | if [[ -d "${res}" ]]; then 190 | open "${res}" 191 | else 192 | open "$(dirname "$res")" 193 | fi 194 | } 195 | 196 | #------------------------------------------------------------------------------ 197 | # 10. zinit 198 | #------------------------------------------------------------------------------ 199 | ### Added by zinit's installer 200 | source '/Users/api/.zinit/bin/zinit.zsh' 201 | autoload -Uz _zinit 202 | (( ${+_comps} )) && _comps[zinit]=_zinit 203 | ### End of zinit's installer chunk 204 | 205 | zinit load zdharma/history-search-multi-word 206 | 207 | zinit ice compile"*.lzui" 208 | zinit load zdharma/zui 209 | zinit light zdharma/zinit-crasis 210 | 211 | zinit light zsh-users/zsh-autosuggestions 212 | zinit light zsh-users/zsh-syntax-highlighting 213 | 214 | #zinit ice compile'(pure|async).zsh' pick'async.zsh' src'pure.zsh' 215 | #zinit light sindresorhus/pure 216 | 217 | # Local Variables: 218 | # eval: (outline-minor-mode 1) 219 | # outline-regexp: "^# [0-9]+" 220 | # End: 221 | ### End of Zinit's installer chunk 222 | -------------------------------------------------------------------------------- /.emacs.d/lisp/init-editor.el: -------------------------------------------------------------------------------- 1 | ;;; init-editor.el --- Editor related settings -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;;; Code: 6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7 | 8 | (setq-default fill-column 80 9 | word-wrap t 10 | sentence-end-double-space nil 11 | 12 | ;; use spaces, not tabs 13 | indent-tabs-mode nil 14 | tab-always-indent t 15 | tab-width 4 16 | 17 | ;; 18 | auto-save-default nil 19 | create-lockfiles nil 20 | history-length 500 21 | make-backup-files nil 22 | 23 | ;; Scrolling 24 | hscroll-margin 1 25 | hscroll-step 1 26 | scroll-conservatively 101 27 | scroll-margin 0 28 | scroll-preserve-screen-position t 29 | 30 | size-indication-mode t 31 | ; line-number-mode t 32 | display-line-numbers-width 3 33 | column-number-mode t 34 | delete-selection-mode t) 35 | 36 | ;;------------------------------------------------------------------------------ 37 | ;; Show matching parenthesis. 38 | ;;------------------------------------------------------------------------------ 39 | (setq show-paren-delay 0.1 40 | show-paren-highlight-openparen t 41 | show-paren-when-point-inside-paren t) 42 | (add-hook 'after-init-hook #'show-paren-mode) 43 | 44 | ;;------------------------------------------------------------------------------ 45 | ;; Line numbers. 46 | ;;------------------------------------------------------------------------------ 47 | (defvar api-line-numbers-style 'relative 48 | "Style to use for `display-line-numbers' styles, which are: 49 | t Ordinary line numbers 50 | 'relative Relative line numbers") 51 | 52 | (defun api/enable-line-numbers () 53 | "Show line number display." 54 | (interactive) 55 | (if (boundp 'display-line-numbers) 56 | (setq display-line-numbers api-line-numbers-style))) 57 | 58 | (defun api/disable-line-numbers () 59 | "Disable line number display." 60 | (interactive) 61 | (if (boundp 'display-line-numbers) 62 | (setq display-line-numbers nil))) 63 | 64 | ;; enable line numbers by default in some modes. 65 | (dolist (hook '(prog-mode-hook 66 | text-mode-hook)) 67 | (add-hook hook #'api/enable-line-numbers)) 68 | 69 | ;;------------------------------------------------------------------------------ 70 | ;; `auto-fill-mode': 71 | ;;------------------------------------------------------------------------------ 72 | (use-package auto-fill-mode 73 | :ensure nil ;; in-built 74 | :commands (auto-fill-mode) 75 | :hook ((text-mode . auto-fill-mode) 76 | (latex-mode . auto-fill-mode))) 77 | 78 | ;;------------------------------------------------------------------------------ 79 | ;; `column-enforce-mode': highlight text that extends beyond a certain column. 80 | ;; Main difference from whitespace mode is that this allows skipping comments. 81 | ;;------------------------------------------------------------------------------ 82 | (use-package column-enforce-mode 83 | ;;:disabled ;; whitespace-mode is enough for now. 84 | :hook ((prog-mode . column-enforce-mode) 85 | (latex-mode . column-enforce-mode) 86 | (text-mode . column-enforce-mode)) 87 | :config 88 | (setq column-enforce-comments nil 89 | column-enforce-column 80)) 90 | 91 | ;;(dolist (hook '(prog-mode-hook 92 | ;; latex-mode-hook 93 | ;; text-mode-hook)) 94 | ;; (add-hook hook 'column-enforce-mode))) 95 | 96 | ;;------------------------------------------------------------------------------ 97 | ;; `expand-region': Expand region by semantic units. 98 | ;;------------------------------------------------------------------------------ 99 | (use-package expand-region 100 | :commands (er/expand-region 101 | er/contract-region 102 | er/mark-symbol 103 | er/mark-word)) 104 | 105 | ;;------------------------------------------------------------------------------ 106 | ;; `highlight-indent-guides': highlight indentations. 107 | ;;------------------------------------------------------------------------------ 108 | (use-package highlight-indent-guides 109 | :commands (highlight-indentation-mode 110 | highlight-indentation-current-column-mode) 111 | :init (setq highlight-indent-guides-method 'character)) 112 | 113 | ;;------------------------------------------------------------------------------ 114 | ;; `highlight-symbol': highlight symbol at point throughout the current buffer. 115 | ;;------------------------------------------------------------------------------ 116 | (use-package highlight-symbol 117 | :commands highlight-symbol) 118 | 119 | ;;------------------------------------------------------------------------------ 120 | ;; `hl-line': highlight current line. 121 | ;;------------------------------------------------------------------------------ 122 | (use-package hl-line 123 | :ensure nil ; in-built 124 | :hook ((prog-mode text-mode conf-mode) . hl-line-mode)) 125 | 126 | ;;------------------------------------------------------------------------------ 127 | ;; `rainbow-delimiters': Manage delimiter explosion. 128 | ;;------------------------------------------------------------------------------ 129 | (use-package rainbow-delimiters 130 | :hook ((latex-mode . rainbow-delimiters-mode) 131 | (prog-mode . rainbow-delimiters-mode))) 132 | 133 | ;;------------------------------------------------------------------------------ 134 | ;; `recentf': Manage recent files. 135 | ;;------------------------------------------------------------------------------ 136 | (use-package recentf 137 | :ensure nil ; in-built 138 | :hook (emacs-startup . recentf-mode) 139 | :config 140 | (setq recentf-max-menu-items 0 141 | recentf-max-saved-items 300 142 | recentf-filename-handlers '(file-truename) 143 | recentf-exclude 144 | (list "^/tmp/" "^/ssh:" "\\.?ido\\.last$" "\\.revive$" "/TAGS$" 145 | "^/var/folders/.+$" "COMMIT_EDITMSG\\" 146 | no-littering-var-directory 147 | no-littering-etc-directory))) 148 | 149 | ;;------------------------------------------------------------------------------ 150 | ;; `smartparens': Smarter parenthesis matching. 151 | ;;------------------------------------------------------------------------------ 152 | (use-package smartparens 153 | :commands (smartparens-global-mode) 154 | :config 155 | (smartparens-global-mode +1) 156 | (require 'smartparens-config) 157 | (setq sp-autowrap-region t 158 | sp-highlight-pair-overlay nil 159 | sp-cancel-autoskip-on-backward-movement nil 160 | sp-show-pair-delay 0 161 | sp-max-pair-length 3) 162 | 163 | ;; Make smart paranthesis play nice with evil. 164 | ;; (use-package evil-smartparens 165 | ;; :after smartparens 166 | ;; :config (add-hook 'smartparens-enabled-hook #'evil-smartparens-mode)) 167 | 168 | ;; disable smartparens in evil-mode's replace state (they conflict) 169 | (after! evil 170 | (add-hook 'evil-replace-state-entry-hook #'turn-off-smartparens-mode) 171 | (add-hook 'evil-replace-state-exit-hook #'turn-on-smartparens-mode))) 172 | 173 | ;;------------------------------------------------------------------------------ 174 | ;; `undo-tree': visualize undo operations. 175 | ;;------------------------------------------------------------------------------ 176 | (use-package undo-tree 177 | :hook (emacs-startup . global-undo-tree-mode) 178 | :config 179 | (setq undo-tree-auto-save-history nil 180 | undo-tree-visualizer-timestamps t 181 | undo-tree-visualizer-diff t)) 182 | 183 | ;;------------------------------------------------------------------------------ 184 | ;; `whitespace': show and clean unnecessary whitespace. 185 | ;;------------------------------------------------------------------------------ 186 | (use-package whitespace 187 | :ensure nil ;; in-built 188 | :commands (whitespace-cleanup whitespace-mode) 189 | :init 190 | (dolist (hook '(prog-mode-hook 191 | tex-mode-hook 192 | latex-mode-hook 193 | text-mode-hook)) 194 | (add-hook hook #'whitespace-mode)) 195 | (add-hook 'before-save-hook #'whitespace-cleanup) 196 | :config 197 | (setq whitespace-line-column 80 198 | whitespace-style '(face tabs empty trailing lines-tail))) 199 | 200 | (provide 'init-editor) 201 | 202 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 203 | ;;; init-editor.el ends here 204 | -------------------------------------------------------------------------------- /.emacs.d/lisp/init-theme.el: -------------------------------------------------------------------------------- 1 | ;; init-theme.el --- Theme related settings -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;;; Code: 6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7 | 8 | (setq custom-safe-themes t) 9 | 10 | (defvar api-theme-hooks nil 11 | "((theme-id . function) ...).") 12 | 13 | (defvar before-load-theme-hook nil 14 | "Hooks to run before `load-theme'.") 15 | 16 | (defvar after-load-theme-hook nil 17 | "Hooks to run after `load-theme'.") 18 | 19 | (defun api/disable-all-themes () 20 | "Disable any custom themes." 21 | (interactive) 22 | (mapc #'disable-theme custom-enabled-themes)) 23 | 24 | (defun api|add-theme-hook (theme-id hook-func) 25 | "Associate `THEME-ID' with `HOOK-FUNC'." 26 | (add-to-list 'api-theme-hooks (cons theme-id hook-func))) 27 | 28 | (defun api*load-theme-advice (f theme-id &optional no-confirm no-enable &rest args) 29 | "Enhances `load-theme' in two ways: 30 | 1. Disables enabled themes for a clean slate. 31 | 2. Calls functions registered using `api|add-theme-hook'." 32 | (unless no-enable 33 | (api/disable-all-themes)) 34 | (prog1 35 | (apply f theme-id no-confirm no-enable args) 36 | (unless no-enable 37 | (pcase (assq theme-id api-theme-hooks) 38 | (`(,_ . ,f) (funcall f)))))) 39 | 40 | (advice-add 'load-theme 41 | :around 42 | #'api*load-theme-advice) 43 | 44 | (defadvice load-theme (after run-after-load-theme-hook activate) 45 | "Run `after-load-theme-hook'." 46 | (run-hooks 'after-load-theme-hook)) 47 | 48 | (defadvice load-theme (before run-before-load-theme-hook activate) 49 | "Disable any custom themes, and run `before-load-theme-hook'." 50 | (mapc #'disable-theme custom-enabled-themes) 51 | (run-hooks 'before-load-theme-hook)) 52 | 53 | ;;------------------------------------------------------------------------------ 54 | ;; `apropospriate-theme': 55 | ;;------------------------------------------------------------------------------ 56 | (use-package apropospriate-theme 57 | :init 58 | (load "apropospriate-theme-autoloads" nil t) 59 | (add-hook 'after-init-hook (lambda () (load-theme 'apropospriate-dark t)))) 60 | 61 | ;;------------------------------------------------------------------------------ 62 | ;; `circadian': Automatically change theme on sunrise and sunset. 63 | ;;------------------------------------------------------------------------------ 64 | (use-package circadian 65 | :disabled 66 | :commands (circadian-setup) 67 | :init 68 | (add-hook 'emacs-startup-hook #'circadian-setup) 69 | :config 70 | (add-hook 'circadian-after-load-theme-hook (lambda () 71 | (when (fboundp 'powerline-reset) 72 | (powerline-reset)))) 73 | (setq calendar-latitude 37.87 74 | calendar-longitude -122.27 75 | calendar-location-name "Berkeley, CA") 76 | (setq circadian-themes '((:sunrise . solarized-light) 77 | ;;(:sunset . zenburn) 78 | (:sunset . sanityinc-tomorrow-eighties)))) 79 | 80 | ;;------------------------------------------------------------------------------ 81 | ;; `doom-themes': 82 | ;;------------------------------------------------------------------------------ 83 | (use-package doom-themes 84 | :disabled 85 | :init 86 | (add-hook 'after-init-hook (lambda() 87 | (load-theme 'doom-one t))) 88 | :config 89 | (setq doom-themes-enable-bold t 90 | doom-themes-enable-italic t) 91 | (doom-themes-org-config)) 92 | 93 | ;;------------------------------------------------------------------------------ 94 | ;; `seoul256': 95 | ;;------------------------------------------------------------------------------ 96 | (use-package seoul256-theme 97 | :disabled 98 | :ensure nil 99 | :init 100 | (add-to-list 'custom-theme-load-path "~/Code/seoul256-emacs") 101 | (setq seoul256-background 236 102 | seoul256-alternate-background 253 103 | seoul256-override-colors-alist 104 | '((65 . "#a6a6a6"))) 105 | 106 | (load-theme 'seoul256 t) 107 | ) 108 | 109 | ;;(add-hook 'emacs-startup-hook (lambda () 110 | ;; (load-theme 'seoul256 t)))) 111 | 112 | ;;------------------------------------------------------------------------------ 113 | ;; `solarized-theme': https://github.com/bbatsov/solarized-emacs 114 | ;;------------------------------------------------------------------------------ 115 | (use-package solarized-theme 116 | :disabled 117 | :init 118 | (setq solarized-use-less-bold t 119 | solarized-use-more-italic t 120 | 121 | ;; make the fringe stand out from the background 122 | ;; solarized-distinct-fringe-background t 123 | 124 | ;; Don't change the font for some headings and titles 125 | solarized-use-variable-pitch nil 126 | 127 | ;; make the modeline high contrast 128 | ;; solarized-high-contrast-mode-line t 129 | x-underline-at-descent-line t 130 | 131 | ;; Use less colors for indicators such as git:gutter, flycheck and similar 132 | ;; solarized-emphasize-indicators nil 133 | 134 | ;; Don't change size of org-mode headlines (but keep other size-changes) 135 | ;; solarized-scale-org-headlines nil 136 | 137 | ;; Avoid all font-size changes 138 | solarized-distinct-doc-face t 139 | solarized-height-minus-1 1.0 140 | solarized-height-plus-1 1.0 141 | solarized-height-plus-2 1.0 142 | solarized-height-plus-3 1.0 143 | solarized-height-plus-4 1.0)) 144 | 145 | ;;------------------------------------------------------------------------------ 146 | ;; `tomorrow-theme': https://github.com/purcell/color-theme-sanityinc-tomorrow/ 147 | ;;------------------------------------------------------------------------------ 148 | (use-package color-theme-sanityinc-tomorrow 149 | :disabled 150 | :init (load-theme 'sanityinc-tomorrow-eighties t)) 151 | 152 | ;;------------------------------------------------------------------------------ 153 | ;; zenburn-theme: 154 | ;;------------------------------------------------------------------------------ 155 | (use-package zenburn-theme 156 | :disabled 157 | :init 158 | 159 | (defun api|customize-zenburn () 160 | "Customize `zenburn'." 161 | (custom-theme-set-faces 162 | 'zenburn 163 | 164 | ;;'(region ((t (:background "#007475")))) 165 | '(font-lock-comment-delimiter-face ((t (:foreground "gray55")))) 166 | '(font-lock-comment-face ((t (:foreground "gray55")))) 167 | '(font-lock-doc-face ((t (:foreground "gray70")))) 168 | '(shm-current-face ((t (:background "gray27")))) 169 | '(linum ((t (:foreground "gray37")))) 170 | '(fringe ((t (:background "#3f3f3f")))) 171 | 172 | `(isearch ((t (:background "#385f38" :foreground "#f8f893")))) 173 | `(lazy-highlight ((t (:foreground "#ffffe0" :background "#284f28")))) 174 | 175 | ;; column-enforce-mode 176 | '(column-enforce-face ((t (:foreground "#DC8CC3")))) 177 | 178 | ;; eyebrowse 179 | `(eyebrowse-mode-line-active ((t (:foreground "#F0DFAF")))) 180 | `(eyebrowse-mode-line-inactive ((t (:foreground "gray37")))) 181 | 182 | `(ivy-current-match ((t (:background "#4F4F4F")))) 183 | ;;`(ivy-current-match ((t (:inherit lazy-highlight)))) 184 | `(ivy-minibuffer-match-face-1 ((t (:inherit match)))) 185 | `(ivy-minibuffer-match-face-2 ((t (:inherit match)))) 186 | `(ivy-minibuffer-match-face-3 ((t (:inherit match)))) 187 | `(ivy-minibuffer-match-face-4 ((t (:inherit match)))) 188 | 189 | `(mu4e-conversation-header ((t (:inherit header-line)))) 190 | 191 | ;; ace-window 192 | `(aw-leading-char-face ((t (:foreground "#F0DFAF" 193 | :weight bold 194 | :height 1.0)))) 195 | 196 | `(winum-face ((t (:foreground "#F0DFAF" :height 1.3)))) 197 | 198 | ;; solaire-mode 199 | `(solaire-default-face ((t (:background "#383838")))) 200 | `(solaire-hl-line-face ((t (:background "#2B2B2B")))) 201 | 202 | ;; strike through unmatched parenthesis 203 | '(rainbow-delimiters-unmatched-face ((t (:foreground "red" 204 | :inherit unspecified 205 | :strike-through t)))))) 206 | 207 | (api|add-theme-hook 'zenburn #'api|customize-zenburn) 208 | ;;(add-hook 'after-load-theme-hook #'api|customize-zenburn) 209 | ;;(load-theme 'zenburn t) 210 | (add-hook 'after-init-hook (lambda () (load-theme 'zenburn t))) 211 | ) 212 | 213 | (provide 'init-theme) 214 | 215 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 216 | ;;; init-theme.el ends here 217 | -------------------------------------------------------------------------------- /.emacs.d/lisp/init-ui.el: -------------------------------------------------------------------------------- 1 | ;;; init-ui.el --- UI settings -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;;; Code: 6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7 | 8 | (setq-default inhibit-startup-message t 9 | inhibit-startup-echo-area-message user-login-name 10 | inhibit-default-init t 11 | initial-major-mode 'fundamental-mode 12 | initial-scratch-message nil 13 | 14 | ;; don't use visual bells or dialog boxes. 15 | use-dialog-box nil 16 | ring-bell-function #'ignore 17 | visible-bell nil 18 | 19 | ;; update ui less often. 20 | idle-update-delay 2 21 | 22 | ;; don't show advice warnings. 23 | ad-redefinition-action 'accept 24 | 25 | ;; make 'apropos' useful. 26 | apropos-do-all t 27 | 28 | ;; confirm before quitting Emacs (avoids accidental quits). 29 | confirm-kill-emacs 'y-or-n-p 30 | 31 | ;; confirm before visiting non-existing file/buffer. 32 | confirm-nonexistent-file-or-buffer t 33 | 34 | ;; don't allow minibuffer commands while in minbuffer. 35 | enable-recursive-minibuffers nil 36 | 37 | ;; disable bidirectional text for tiny performance boost 38 | bidi-display-reordering nil 39 | 40 | ;; remove continuation arrow on right fringe 41 | fringe-indicator-alist (delq 42 | (assq 'continuation fringe-indicator-alist) 43 | fringe-indicator-alist) 44 | 45 | ;; keep the point out of the minibuffer 46 | minibuffer-prompt-properties '(read-only t point-entered minibuffer-avoid-prompt face minibuffer-prompt) 47 | 48 | ;; don't show buffer boundaries visually. 49 | indicate-buffer-boundaries nil 50 | 51 | ;; don't show empty lines. 52 | indicate-empty-lines nil 53 | 54 | ;; no need to make cursor overly visible. 55 | visible-cursor nil 56 | 57 | ;; don't stretch block cursor. 58 | x-stretch-cursor nil 59 | 60 | ;; don't ask for save confirmation before compilation, just do it. 61 | compilation-ask-about-save nil 62 | 63 | ;; scroll compilation output. 64 | compilation-scroll-output t 65 | 66 | ;; kill existing compilation before starting new, don't ask. 67 | compilation-always-kills t) 68 | 69 | ;;------------------------------------------------------------------------------ 70 | ;; Avoid showing ugly stuff. 71 | ;;------------------------------------------------------------------------------ 72 | ;;(if (fboundp 'tool-bar-mode) (tool-bar-mode -1)) 73 | (if (fboundp 'scroll-bar-mode) (scroll-bar-mode -1)) 74 | (if (fboundp 'tooltip-mode) (tooltip-mode -1)) 75 | (if (display-graphic-p) (menu-bar-mode 1) (menu-bar-mode -1)) 76 | ;;(unless (display-graphic-p) (menu-bar-mode -1)) 77 | 78 | ;; standardize default fringe width 79 | (if (fboundp 'fringe-mode) (fringe-mode 4)) 80 | 81 | ;; Make mouse less jumpy 82 | (setq mouse-wheel-scroll-amount '(1 ((shift) . 1))) 83 | 84 | ;; Enable y/n answers 85 | (defalias 'yes-or-no-p 'y-or-n-p) 86 | 87 | ;; be quiet at startup; don't load or display anything unnecessary 88 | (advice-add #'display-startup-echo-area-message :override #'ignore) 89 | 90 | ;;------------------------------------------------------------------------------ 91 | ;; `all-the-icons': icons for many ui related packages. 92 | ;;------------------------------------------------------------------------------ 93 | (use-package all-the-icons 94 | :commands (all-the-icons-octicon all-the-icons-faicon all-the-icons-fileicon 95 | all-the-icons-wicon all-the-icons-material all-the-icons-alltheicon 96 | all-the-icons-install-fonts all-the-icons-icon-for-buffer)) 97 | 98 | ;;------------------------------------------------------------------------------ 99 | ;; `beacon': show where the cursor is when the window moves. 100 | ;;------------------------------------------------------------------------------ 101 | (use-package beacon 102 | :hook (emacs-startup . beacon-mode)) 103 | 104 | ;;------------------------------------------------------------------------------ 105 | ;; `dashboard': show a dashboard at start. 106 | ;;------------------------------------------------------------------------------ 107 | (use-package dashboard 108 | :disabled 109 | :commands (dashboard-setup-startup-hook 110 | dashboard-refresh-buffer) 111 | ;; :preface 112 | ;; (defun api/dashboard-banner () 113 | ;; "Set a dashboard banner including information on package initialization 114 | ;; time and garbage collections.""" 115 | ;; (setq dashboard-banner-logo-title 116 | ;; (format "Emacs ready in %.2f seconds with %d garbage collections." 117 | ;; (float-time (time-subtract after-init-time before-init-time)) gcs-done))) 118 | :init 119 | (setq dashboard-init-info 120 | (format "Ready in %.2f seconds with %d garbage collections." 121 | (float-time (time-subtract after-init-time before-init-time)) gcs-done)) 122 | :config 123 | ;; (setq dashboard-banner-logo-title 124 | ;; (format "Emacs ready in %.2f seconds with %d garbage collections." 125 | ;; (float-time (time-subtract after-init-time before-init-time)) gcs-done)) 126 | ;; (setq dashboard-init-info 127 | ;; (format "Ready in %.2f seconds with %d garbage collections." 128 | ;; (float-time (time-subtract after-init-time before-init-time)) gcs-done)) 129 | (setq dashboard-items '((recents . 5) 130 | (bookmarks . 5) 131 | (projects . 5))) 132 | :hook (after-init . dashboard-setup-startup-hook)) 133 | 134 | ;;------------------------------------------------------------------------------ 135 | ;; `dimmer': Interactively highlight which buffer is active by dimming others. 136 | ;;------------------------------------------------------------------------------ 137 | ;; (use-package dimmer 138 | ;; :disabled 139 | ;; :init 140 | ;; (setq-default dimmer-fraction 0.2) 141 | ;; (add-hook 'after-init-hook 'dimmer-mode)) 142 | 143 | ;;------------------------------------------------------------------------------ 144 | ;; `fringe-helper': helper functions for fringe bitmaps. 145 | ;;------------------------------------------------------------------------------ 146 | (use-package fringe-helper 147 | :commands (fringe-helper-define 148 | fringe-helper-convert) 149 | :init 150 | (unless (fboundp 'define-fringe-bitmap) 151 | ;; doesn't exist in terminal Emacs; define it to prevent errors 152 | (defun define-fringe-bitmap (&rest _)))) 153 | 154 | ;;------------------------------------------------------------------------------ 155 | ;; `solaire-mode': distinguish file-visiting buffers from other types of buffers. 156 | ;;------------------------------------------------------------------------------ 157 | (use-package solaire-mode 158 | :disabled ;; not very useful. 159 | :init 160 | ;; brighten buffers (that represent real files) 161 | (add-hook 'after-change-major-mode-hook #'turn-on-solaire-mode) 162 | ;; To enable solaire-mode unconditionally for certain modes: 163 | (add-hook 'ediff-prepare-buffer-hook #'solaire-mode) 164 | 165 | ;; ...if you use auto-revert-mode, this prevents solaire-mode from turning 166 | ;; itself off every time Emacs reverts the file 167 | (add-hook 'after-revert-hook #'turn-on-solaire-mode) 168 | 169 | ;; highlight the minibuffer when it is activated: 170 | (add-hook 'minibuffer-setup-hook #'solaire-mode-in-minibuffer) 171 | 172 | ;; if the bright and dark background colors are the wrong way around, use this 173 | ;; to switch the backgrounds of the `default` and `solaire-default-face` faces. 174 | ;; This should be used *after* you load the active theme! 175 | ;; 176 | ;; NOTE: This is necessary for themes in the doom-themes package! 177 | (solaire-mode-swap-bg)) 178 | 179 | ;;------------------------------------------------------------------------------ 180 | ;; `which-key': interactively show available commands. 181 | ;;------------------------------------------------------------------------------ 182 | (use-package which-key 183 | :hook (emacs-startup . which-key-mode) 184 | :config 185 | (setq which-key-sort-order #'which-key-prefix-then-key-order 186 | which-key-min-display-lines 5 187 | which-key-sort-uppercase-first nil 188 | which-key-add-column-padding 1 189 | which-key-max-display-columns nil) 190 | (set-face-attribute 'which-key-local-map-description-face nil :weight 'bold) 191 | (which-key-setup-side-window-bottom)) 192 | 193 | (provide 'init-ui) 194 | 195 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 196 | ;;; init-ui.el ends here 197 | -------------------------------------------------------------------------------- /.emacs.d/lisp/init-keybindings.el: -------------------------------------------------------------------------------- 1 | ;;; init-keybindings.el --- Key bindings -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;; Initialize key bindings 6 | 7 | ;;; Code: 8 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 9 | 10 | (defvar my-leader-key "SPC" 11 | "Anand's leader prefix key.") 12 | 13 | ;;; Super (cmd) key bindings 14 | (after! winum 15 | (global-set-key (kbd "s-0") 'winum-select-window-0-or-10) 16 | (global-set-key (kbd "s-1") 'winum-select-window-1) 17 | (global-set-key (kbd "s-2") 'winum-select-window-2) 18 | (global-set-key (kbd "s-3") 'winum-select-window-3) 19 | (global-set-key (kbd "s-4") 'winum-select-window-4)) 20 | 21 | ;;; Hyper (alt) key bindings 22 | (global-set-key (kbd "H-h") help-map) 23 | (global-set-key (kbd "H-m") 'emms-smart-browse) 24 | (global-set-key (kbd "H-p") 'emms-pause) 25 | 26 | ;;------------------------------------------------------------------------------ 27 | ;; `hydra': 28 | ;;------------------------------------------------------------------------------ 29 | (use-package hydra 30 | :after evil 31 | :init 32 | (setq lv-use-seperator t) 33 | 34 | (defhydra api@text-zoom (:hint t :color red) 35 | " 36 | Text zoom: _j_:zoom in, _k_:zoom out, _0_:reset 37 | " 38 | ("j" text-scale-increase "in") 39 | ("k" text-scale-decrease "out") 40 | ("0" (text-scale-set 0) "reset")) 41 | 42 | (defhydra api@window-nav (:hint nil) 43 | " 44 | Move : _h_: far left _j_: very bottom _k_:very top _l_:far right _s_: swap with other 45 | Resize : _+_: increase height _-_: decrease height _<_:decrease width _>_:increase width _=_: balance 46 | " 47 | ("h" evil-window-move-far-left) 48 | ("j" evil-window-move-very-bottom) 49 | ("k" evil-window-move-very-top) 50 | ("l" evil-window-move-far-right) 51 | ("s" ace-swap-window) 52 | 53 | ("+" evil-window-increase-height) 54 | ("-" evil-window-decrease-height) 55 | ("<" evil-window-decrease-width) 56 | (">" evil-window-increase-width) 57 | ("=" balance-windows) 58 | 59 | ("q" nil))) 60 | 61 | ;;------------------------------------------------------------------------------ 62 | ;; `general': Convenient key definitions. 63 | ;;------------------------------------------------------------------------------ 64 | (use-package general 65 | :commands (general-evil-setup) 66 | :after evil 67 | :init 68 | (general-evil-setup t) 69 | 70 | (setq general-override-states '(insert 71 | emacs 72 | hybrid 73 | normal 74 | visual 75 | motion 76 | operator 77 | replace)) 78 | (general-override-mode) 79 | 80 | (general-define-key :states '(insert visual operator replace) 81 | :keymaps 'global 82 | "C-g" 'evil-escape) 83 | 84 | (general-define-key :states '(normal visual emacs) 85 | :keymaps 'global 86 | :prefix my-leader-key 87 | 88 | "SPC" 'counsel-M-x 89 | 90 | "b" '(:ignore t :which-key "buffer") 91 | "bb" 'ivy-switch-buffer 92 | "bd" 'kill-this-buffer 93 | "bk" 'kill-this-buffer 94 | "bn" 'evil-buffer-new 95 | "bh" 'previous-buffer 96 | "bl" 'next-buffer 97 | 98 | "f" '(:ignore t :which-key "file") 99 | "ff" 'counsel-find-file 100 | "fs" 'save-buffer 101 | 102 | "g" '(:ignore t :which-key "git") 103 | "gs" 'magit-status 104 | "gd" 'magit-diff 105 | "gc" 'magit-commit 106 | "gp" 'magit-push 107 | 108 | "h" '(:ignore t :which-key "hydras") 109 | "hj" '(api@dumb-jump/body :which-key "Dumb Jump") 110 | "ht" '(api@text-zoom/body :which-key "Text zoom") 111 | "hw" '(api@window-nav/body :which-key "Window navigation") 112 | "hc" '(api@multiple-cursors/body :which-key "Multiple cursors") 113 | "hg" '(api@git-gutter/body :which-key "Git gutter") 114 | 115 | "l" '(:ignore t :which-key "window layout") 116 | "lc" '(eyebrowse-create-window-config :which-key "create new layout") 117 | "lp" '(eyebrowse-prev-window-config :which-key "previous layout") 118 | "ln" '(eyebrowse-next-window-config :which-key "next layout") 119 | "ls" '(eyebrowse-switch-to-window-config :which-key "switch layout") 120 | "ld" '(eyebrowse-close-window-config :which-key "delete this layout") 121 | "lr" '(eyebrowse-rename-window-config :which-key "rename layout") 122 | "ll" '(eyebrowse-last-window-config :which-key "last layout") 123 | "l0" '(eyebrowse-switch-to-window-config-0 :which-key "layout 0") 124 | "l1" '(eyebrowse-switch-to-window-config-1 :which-key "layout 1") 125 | "l2" '(eyebrowse-switch-to-window-config-2 :which-key "layout 2") 126 | "l3" '(eyebrowse-switch-to-window-config-3 :which-key "layout 3") 127 | "l4" '(eyebrowse-switch-to-window-config-4 :which-key "layout 4") 128 | "l5" '(eyebrowse-switch-to-window-config-5 :which-key "layout 5") 129 | "l6" '(eyebrowse-switch-to-window-config-6 :which-key "layout 6") 130 | "l7" '(eyebrowse-switch-to-window-config-7 :which-key "layout 7") 131 | "l8" '(eyebrowse-switch-to-window-config-8 :which-key "layout 8") 132 | "l9" '(eyebrowse-switch-to-window-config-9 :which-key "layout 9") 133 | 134 | "n" '((lambda () 135 | (interactive) 136 | (notmuch-tree "folder:/inbox/ OR tag:inbox")) 137 | :which-key "notmuch") 138 | 139 | "m" 'mu4e 140 | 141 | "o" '(:ignore t :which-key "org-mode") 142 | "oa" 'api/show-org-agenda-frame 143 | "oc" 'api/open-org-capture-frame 144 | "od" 'org-deadline 145 | "or" 'org-refile 146 | "os" 'org-schedule 147 | 148 | "p" '(:ignore t :which-key "project") 149 | "pb" 'counsel-projectile-switch-to-buffer 150 | "pp" 'counsel-projectile 151 | "pf" 'counsel-projectile-find-file 152 | "ps" 'projectile-switch-project 153 | "pr" 'counsel-projectile-recentf 154 | "pv" 'counsel-projectile-vc 155 | "px" 'projectile-invalidate-cache 156 | 157 | "q" 'evil-quit 158 | 159 | "/" '(:ignore t :which-key "search") 160 | "//" 'swiper 161 | "/B" 'swiper-all 162 | "/f" 'helm-do-grep-ag 163 | 164 | "s" '(:ignore t :which-key "sessions") 165 | "sa" '(ivy-push-view :which-key "save session") 166 | "sd" '(ivy-pop-view :which-key "delete session") 167 | "sl" '(api/load-ivy-views :which-key "load saved sessions") 168 | "ss" '(ivy-switch-view :which-key "switch session") 169 | "sw" '(api/save-ivy-views :which-key "write sessions to file") 170 | 171 | "t" '(:ignore t :which-key "toggle") 172 | "tc" '(evilnc-comment-or-uncomment-lines :which-key "comments") 173 | "ti" 'highlight-indent-guides-mode 174 | "tt" 'flyspell-mode 175 | "ts" 'flycheck-mode 176 | "th" 'highlight-symbol 177 | "tg" '((lambda () 178 | (interactive) 179 | (if (bound-and-true-p golden-ratio-mode) 180 | (progn 181 | (golden-ratio-mode -1) 182 | (balance-windows)) 183 | (progn 184 | (golden-ratio-mode +1) 185 | (golden-ratio)))) 186 | :which-key "golden ratio mode") 187 | "tw" 'writegood-mode 188 | 189 | "v" #'er/expand-region 190 | "V" #'er/contract-region 191 | 192 | "w" '(evil-window-map :which-key "window") 193 | ;;"w" '(:ignore t :which-key "window") 194 | 195 | "y" '(:ignore t :which-key "snippets") 196 | "yn" 'yas-new-snippet 197 | "yi" 'yas-insert-snippet 198 | "yv" 'yas-visit-snippet-file 199 | 200 | "TAB" 'ace-window)) 201 | 202 | (provide 'init-keybindings) 203 | 204 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 205 | ;;; init-keybindings.el ends here 206 | -------------------------------------------------------------------------------- /.emacs.d/lisp/init-windows.el: -------------------------------------------------------------------------------- 1 | ;;; init-windows.el --- Emacs windows -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;; These are settings related to Emacs windows (not Windows as in OS) 6 | 7 | ;;; Code: 8 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 9 | 10 | (setq-default highlight-nonselected-windows nil 11 | 12 | ;; hide cursors in other windows 13 | cursor-in-non-selected-windows nil 14 | 15 | ;; let minibuffer windows resize automatically. 16 | resize-mini-windows 'grow-only 17 | 18 | ;; maximum size for mini-windows. 19 | max-mini-window-height 0.4 20 | 21 | ;; lean towards horizontal splits. 22 | ;;split-width-threshold 999) 23 | ) 24 | ;;------------------------------------------------------------------------------ 25 | ;; set inter-window bordto be minimal, 26 | ;;------------------------------------------------------------------------------ 27 | (setq-default window-divider-default-places t 28 | window-divider-default-bottom-width 0 29 | window-divider-default-right-width 1) 30 | (add-hook 'after-init-hook #'window-divider-mode) 31 | 32 | ;;------------------------------------------------------------------------------ 33 | ;; Winner mode for quick window configurations. 34 | ;;------------------------------------------------------------------------------ 35 | (use-package winner-mode 36 | :ensure nil ; in-built 37 | :if (fboundp 'winner-mode) 38 | :hook (after-init . winner-mode)) 39 | 40 | ;;------------------------------------------------------------------------------ 41 | ;; Allow switching between active windows using Shift + arrow keys. 42 | ;;------------------------------------------------------------------------------ 43 | ;(when (fboundp 'windmove-default-keybindings) (windmove-default-keybindings)) 44 | (use-package windmove 45 | :ensure nil ; in-built 46 | :when (fboundp 'windmove-default-keybindings) 47 | :hook (emacs-startup . windmove-default-keybindings)) 48 | 49 | ;;------------------------------------------------------------------------------ 50 | ;; `ace-window': Visually select windows. 51 | ;;------------------------------------------------------------------------------ 52 | (use-package ace-window 53 | :commands (ace-window) 54 | :config 55 | (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l) 56 | aw-scope 'global 57 | aw-background t)) 58 | 59 | ;;------------------------------------------------------------------------------ 60 | ;; `eyebrowse': Save and retrieve window layouts. 61 | ;;------------------------------------------------------------------------------ 62 | (use-package eyebrowse 63 | ;;:disabled 64 | :commands (eyebrowse-mode) 65 | :config 66 | (add-to-list 'window-persistent-parameters '(window-side . writable)) 67 | (add-to-list 'window-persistent-parameters '(window-slot . writable)) 68 | (setq eyebrowse-mode-line-separator " " 69 | eyebrowse-mode-line-left-delimiter " " 70 | eyebrowse-mode-line-right-delimiter " " 71 | eyebrowse-wrap-around t 72 | eyebrowse-new-workspace t) 73 | (eyebrowse-mode)) 74 | 75 | ;;------------------------------------------------------------------------------ 76 | ;; `golden-ratio': Automatically resize windows. 77 | ;;------------------------------------------------------------------------------ 78 | (use-package golden-ratio 79 | :config 80 | (progn 81 | ;; golden-ratio-exclude-modes 82 | (dolist (m '("bs-mode" 83 | "calc-mode" 84 | "ediff-mode" 85 | "dired-mode" 86 | "gud-mode" 87 | "gdb-locals-mode" 88 | "gdb-registers-mode" 89 | "gdb-breakpoints-mode" 90 | "gdb-threads-mode" 91 | "gdb-frames-mode" 92 | "gdb-inferior-io-mode" 93 | "gdb-disassembly-mode" 94 | "gdb-memory-mode" 95 | "speedbar-mode" 96 | )) 97 | (add-to-list 'golden-ratio-exclude-modes m)) 98 | 99 | (add-to-list 'golden-ratio-exclude-buffer-regexp "^\\*[hH]elm.*") 100 | 101 | ;; golden-ratio-extra-commands 102 | (dolist (f '(ace-window 103 | ace-delete-window 104 | ace-select-window 105 | ace-swap-window 106 | ace-maximize-window 107 | avy-pop-mark 108 | buf-move-left 109 | buf-move-right 110 | buf-move-up 111 | buf-move-down 112 | evil-avy-goto-word-or-subword-1 113 | evil-avy-goto-line 114 | evil-window-delete 115 | evil-window-split 116 | evil-window-vsplit 117 | evil-window-left 118 | evil-window-right 119 | evil-window-up 120 | evil-window-down 121 | evil-window-bottom-right 122 | evil-window-top-left 123 | evil-window-mru 124 | evil-window-next 125 | evil-window-prev 126 | evil-window-new 127 | evil-window-vnew 128 | evil-window-rotate-upwards 129 | evil-window-rotate-downwards 130 | evil-window-move-very-top 131 | evil-window-move-far-left 132 | evil-window-move-far-right 133 | evil-window-move-very-bottom 134 | quit-window 135 | winum-select-window-0-or-10 136 | winum-select-window-1 137 | winum-select-window-2 138 | winum-select-window-3 139 | winum-select-window-4 140 | winum-select-window-5 141 | winum-select-window-6 142 | winum-select-window-7 143 | winum-select-window-8 144 | winum-select-window-9 145 | windmove-left 146 | windmove-right 147 | windmove-up 148 | windmove-down)) 149 | (add-to-list 'golden-ratio-extra-commands f)) 150 | 151 | ;; golden-ratio-exclude-buffer-names 152 | (dolist (n '(" *NeoTree*" 153 | "*LV*" 154 | " *which-key*")) 155 | (add-to-list 'golden-ratio-exclude-buffer-names n)))) 156 | 157 | ;;------------------------------------------------------------------------------ 158 | ;; `shackle': Tame pop-up windows. 159 | ;;------------------------------------------------------------------------------ 160 | (use-package shackle 161 | :hook (emacs-startup . shackle-mode) 162 | :config 163 | (setq shackle-default-alignment 'below 164 | shackle-default-size 8 165 | helm-display-function 'pop-to-buffer 166 | shackle-rules 167 | '(("^\\*eww" :regexp t :size 0.5 :select t :autokill t :noesc t) 168 | ("^\\*ftp " :noselect t :autokill t :noesc t) 169 | ("^\\*pdf" :noselect t :align right) 170 | ;;(pdf-view-mode :noselect t :align right) 171 | ("\\`\\*helm.*?\\*\\'" :regexp t :align t :size 0.3) 172 | ;; built-in (emacs) 173 | ("*compilation*" :size 0.25 :noselect t :autokill t :autoclose t) 174 | ("*ert*" :same t :modeline t) 175 | ("*info*" :size 0.5 :select t :autokill t) 176 | ("*undo-tree*" :size 0.25 :align right) 177 | ("*Backtrace*" :size 20 :noselect t) 178 | ("*Warnings*" :size 12 :noselect t :autofit t) 179 | ("*Messages*" :size 12 :noselect t) 180 | ("*Help*" :size 0.3 :autokill t) 181 | ("^\\*.*Shell Command.*\\*$" :regexp t :size 20 :noselect t :autokill t) 182 | (apropos-mode :size 0.3 :autokill t :autoclose t) 183 | (Buffer-menu-mode :size 20 :autokill t) 184 | (comint-mode :noesc t) 185 | (grep-mode :size 25 :noselect t :autokill t) 186 | (profiler-report-mode :size 0.3 :regexp t :autokill t :modeline minimal) 187 | (tabulated-list-mode :noesc t) 188 | ("^ ?\\*" :regexp t :size 15 :noselect t :autokill t :autoclose t))) 189 | ;;(shackle-mode)) 190 | ) 191 | 192 | ;;------------------------------------------------------------------------------ 193 | ;; `winum': Allow window selection by number. 194 | ;;------------------------------------------------------------------------------ 195 | (use-package winum 196 | :hook (emacs-startup . winum-mode) 197 | ;;(add-hook 'emacs-startup-hook 'winum-mode) 198 | :config 199 | (setq winum-scope 'global 200 | winum-auto-setup-mode-line nil)) 201 | 202 | ;;------------------------------------------------------------------------------ 203 | ;; `zoom': Automatically zoom active window. 204 | ;;------------------------------------------------------------------------------ 205 | (use-package zoom 206 | :disabled ;; doesn't play well with which-key 207 | :config 208 | ;(setq which-key-popup-type 'minibuffer) 209 | (setq zoom-ignored-major-modes '(calc-mode 210 | dired-mode 211 | ediff-mode 212 | markdown-mode 213 | speedbar-mode 214 | which-key-mode) 215 | zoom-ignored-buffer-name-regexps '("^*calc" 216 | "^\\*[hH]elm.*") 217 | zoom-ignored-buffer-names '(" *NeoTree*" 218 | " *which-key*"))) 219 | 220 | (provide 'init-windows) 221 | 222 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 223 | ;;; init-windows.el ends here 224 | -------------------------------------------------------------------------------- /.emacs.d/lisp/setup-org.el: -------------------------------------------------------------------------------- 1 | ;;; setup-org.el --- Org setup -*- lexical-binding: t; -*- 2 | 3 | ;;; Commentary: 4 | 5 | ;; Some settings related to org mode. Majorly based on: 6 | ;; https://m.reddit.com/r/emacs/comments/4gudyw/help_me_with_my_orgmode_workflow_for_notetaking/ 7 | ;; https://github.com/sriramkswamy/dotemacs/ 8 | 9 | ;;; Code: 10 | 11 | ;;------------------------------------------------------------------------------ 12 | ;; Defaults & helpers: 13 | ;;------------------------------------------------------------------------------ 14 | ;; http://stackoverflow.com/questions/21073859/is-there-a-way-with-org-capture-templates-to-not-insert-a-line-if-initial-conten 15 | (defun v-i-or-nothing () 16 | "Use initial content only if available." 17 | (let ((v-i (plist-get org-store-link-plist :initial))) 18 | (if (equal v-i "") 19 | "" 20 | (concat v-i "\n")))) 21 | 22 | ;;------------------------------------------------------------------------------ 23 | ;; `evil-org': 24 | ;;------------------------------------------------------------------------------ 25 | (use-package evil-org 26 | :commands (evil-org-mode evil-org-recompute-clocks) 27 | :hook (org-mode . evil-org-mode) 28 | :config 29 | (setf evil-org-key-theme '(navigation insert textobjects additional)) 30 | (require 'evil-org-agenda) 31 | (evil-org-agenda-set-keys)) 32 | 33 | ;;------------------------------------------------------------------------------ 34 | ;; `org': 35 | ;;------------------------------------------------------------------------------ 36 | (use-package org-plus-contrib 37 | :mode (("\\.org\\'" . org-mode)) 38 | ;;:bind ("C-c c" . org-capture) 39 | :init 40 | (setq org-directory org-root-directory 41 | org-default-notes-file (concat org-directory "organizer.org") 42 | org-startup-with-inline-images t 43 | org-src-fontify-natively t 44 | org-imenu-depth 8 45 | org-log-done t 46 | org-log-into-drawer t 47 | org-refile-targets '((org-agenda-files . (:maxlevel . 6)))) 48 | 49 | (setq org-agenda-files 50 | (list (concat org-directory "organizer.org") 51 | (concat org-directory "beorg.org") 52 | (concat org-directory "papers/notes.org")) 53 | org-deadline-warning-days 7 54 | org-agenda-start-on-weekday nil 55 | org-agenda-show-all-dates t 56 | org-agenda-skip-deadline-if-done t 57 | org-agenda-skip-scheduled-if-done t 58 | org-agenda-span 7 59 | org-agenda-skip-scheduled-if-deadline-is-shown t 60 | org-reverse-note-order t) 61 | 62 | (setq org-capture-templates 63 | (quote (("t" "Todo" entry 64 | (file+headline org-default-notes-file "Inbox") 65 | "* TODO %^{Todo}\n:PROPERTIES:\n:CREATED: %T\n:END:\n%(v-i-or-nothing)" 66 | :empty-lines 1 67 | :prepend t 68 | :immediate-finish t 69 | :kill-buffer t) 70 | ("e" "Email-process-soon" entry (file+headline org-default-notes-file "Tasks") 71 | "* TODO [Email] %a %?\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))" 72 | :empty-lines 1) 73 | ("n" "Note" entry (file+headline org-default-notes-file "Notes") 74 | "* %U %?" 75 | :prepend t 76 | :empty-lines 1 77 | :kill-buffer t) 78 | ("p" "Paper" entry 79 | (file+headline org-default-notes-file "Papers") 80 | "* %^{Title} %(org-set-tags)\n:PROPERTIES:\n:CREATED: %U\n:Linked: %a\n:END:\n%i\nBrief description:\n%?" 81 | :prepend t 82 | :empty-lines 1 83 | :created t)))) 84 | 85 | ;;;###autoload 86 | (defun api/show-org-agenda-frame () 87 | "Show org-agenda in new frame or select the frame if already open." 88 | (interactive) 89 | (let* ((name "Org Agenda") 90 | (curr-frame (selected-frame)) 91 | (frame-alist (nameframe-frame-alist)) 92 | (frame (nameframe-get-frame name frame-alist))) 93 | (cond 94 | ;; org-agenda frame already exists 95 | ((and frame (not (equal frame curr-frame))) 96 | (select-frame-set-input-focus frame)) 97 | ((not frame) 98 | (progn (nameframe-make-frame name) 99 | (funcall #'org-agenda-list) 100 | (delete-other-windows)))))) 101 | 102 | ;; -- Make org-capture popup in its own frame. 103 | ;;;###autoload 104 | (defun api/open-org-capture-frame () 105 | "Create a new frame and run `org-capture'." 106 | (interactive) 107 | (select-frame (make-frame '((api|org-capture . t)))) 108 | (delete-other-windows) 109 | (cl-letf (((symbol-function 'switch-to-buffer-other-window) #'switch-to-buffer)) 110 | (condition-case err 111 | (org-capture) 112 | ;; `org-capture' signals (error "Abort") when "q" is typed, so 113 | ;; delete the newly-created frame in this scenario. 114 | (error 115 | (message "org-capture: %s" (error-message-string err)) 116 | (delete-frame))))) 117 | 118 | (defadvice org-capture-finalize (after delete-capture-frame activate) 119 | "Delete the frame after `capture-finalize'." 120 | (when (frame-parameter nil 'api|org-capture) 121 | (delete-frame))) 122 | 123 | (defadvice org-capture-destroy (after delete-capture-frame activate) 124 | "Delete the frame after `capture-destroy'." 125 | (when (frame-parameter nil 'api|org-capture) 126 | (delete-frame))) 127 | 128 | ;;Add creation date as a property in all captures. 129 | (require 'org-expiry) 130 | (add-hook 'org-capture-before-finalize-hook 131 | #'(lambda() 132 | (save-excursion 133 | (org-back-to-heading) 134 | (org-expiry-insert-created)))) 135 | 136 | ;; Once inside the capture, change to insert state. 137 | (add-hook 'org-capture-mode-hook #'evil-insert-state) 138 | 139 | ;; No need to show line numbers in org mode. 140 | (add-hook 'org-mode-hook #'api/disable-line-numbers) 141 | 142 | (setq org-publish-project-alist 143 | '( 144 | 145 | ("org-api" 146 | ;; Path to your org files. 147 | :base-directory "~/Code/anand-iyer.com/_org/" 148 | :base-extension "org" 149 | 150 | ;; Path to your Jekyll project. 151 | :publishing-directory "~/Code/anand-iyer.com/" 152 | :recursive t 153 | :publishing-function org-html-publish-to-html 154 | :headline-levels 4 155 | :html-extension "html" 156 | :body-only t ;; Only export section between 157 | 158 | :section-numbers nil 159 | :with-toc nil 160 | :auto-index nil 161 | :auto-preamble nil 162 | :auto-postamble nil 163 | )))) 164 | 165 | ;;------------------------------------------------------------------------------ 166 | ;; `org-babel': 167 | ;;------------------------------------------------------------------------------ 168 | (use-package org-babel 169 | :ensure nil ; org 170 | :after org 171 | :init 172 | (org-babel-do-load-languages 173 | 'org-babel-load-languages 174 | '((awk . t) 175 | (C . t) 176 | (emacs-lisp . t) 177 | (gnuplot . t) 178 | (latex . t) 179 | (js . t) 180 | (perl . t) 181 | (python . t) 182 | (R . t) 183 | (sql . t)))) 184 | 185 | ;;------------------------------------------------------------------------------ 186 | ;; `org-bullets': 187 | ;;------------------------------------------------------------------------------ 188 | (use-package org-bullets 189 | :hook (org-mode . org-bullets-mode)) 190 | 191 | ;;------------------------------------------------------------------------------ 192 | ;; `org-mime': 193 | ;;------------------------------------------------------------------------------ 194 | (use-package org-mime 195 | :disabled 196 | :after (org mu4e) 197 | :config 198 | (setq 199 | org-mime-library 'mml 200 | org-mime-export-options '(:section-numbers nil :with-author nil :with-toc nil))) 201 | 202 | ;;------------------------------------------------------------------------------ 203 | ;; `org-ref': 204 | ;;------------------------------------------------------------------------------ 205 | (use-package org-ref 206 | :config 207 | (setq org-ref-completion-library 'org-ref-ivy-cite 208 | org-ref-notes-directory (concat org-directory "papers/notes") 209 | org-ref-bibliography-notes (concat org-directory "papers/notes.org") 210 | org-ref-default-bibliography `(,(concat org-directory "papers/references.bib")) 211 | org-ref-pdf-directory (concat org-directory "papers/pdfs/")) 212 | :init 213 | (add-hook 'org-mode-hook (lambda () 214 | (require 'org-ref) 215 | (require 'org-ref-latex) 216 | (require 'org-ref-pdf) 217 | (require 'org-ref-url-utils)))) 218 | 219 | ;; interleave PDFs with notes. This needs to be after pdf-tools. Also, interleave 220 | ;; needs to be removed and reinstalled everytime pdf-tools is updated. 221 | ;; See: https://github.com/rudolfochrist/interleave/issues/31#issuecomment-252351991 222 | ;; (use-package interleave 223 | ;; :init 224 | ;; (setq interleave-org-notes-dir-list `(,(concat org-directory "papers"))) 225 | ;; (with-eval-after-load 'doc-view 226 | ;; (bind-key "i" #'interleave--open-notes-file-for-pdf doc-view-mode-map)) 227 | ;; (with-eval-after-load 'pdf-view 228 | ;; (bind-key "i" #'interleave--open-notes-file-for-pdf pdf-view-mode-map))) 229 | 230 | ;;------------------------------------------------------------------------------ 231 | ;; `org-noter': 232 | ;;------------------------------------------------------------------------------ 233 | (use-package org-noter 234 | :init 235 | (setq org-noter-notes-search-path `(,(concat org-directory "papers"))) 236 | :config 237 | (setq org-noter-auto-save-last-location t 238 | org-noter-separate-notes-from-heading t)) 239 | 240 | ;;------------------------------------------------------------------------------ 241 | ;; `org-ref': notational velocity and nvALT replacement. 242 | ;;------------------------------------------------------------------------------ 243 | (use-package deft 244 | :commands (deft) 245 | :init 246 | (defun api/deft () 247 | "Helper for deft" 248 | (interactive) 249 | (deft) 250 | (evil-insert-state nil)) 251 | (setq deft-directory "~/Notes" 252 | deft-extensions '("org" "md" "txt" "markdown") 253 | deft-text-mode 'org-mode 254 | deft-use-filename-as-title t 255 | deft-use-filter-string-for-filename t)) 256 | 257 | (use-package markdown-mode 258 | :commands (markdown-mode gfm-mode) 259 | :mode (("README\\.md\\'" . gfm-mode) 260 | ("\\.md\\'" . markdown-mode) 261 | ("\\.markdown\\'" . markdown-mode)) 262 | :init (setq markdown-command "multimarkdown")) 263 | 264 | (provide 'setup-org) 265 | ;;; setup-org.el ends here 266 | -------------------------------------------------------------------------------- /.hammerspoon/init.lua: -------------------------------------------------------------------------------- 1 | require("utils") 2 | 3 | local hotkey = require "hs.hotkey" 4 | local alert = require "hs.alert" 5 | hs.window.animationDuration = 0 6 | 7 | hyper = {"cmd", "alt", "ctrl"} 8 | hyper_shift = {"cmd", "alt", "ctrl", "shift"} 9 | shift_hyper = {"shift", "cmd", "alt", "ctrl"} 10 | 11 | -- ----------------------------------------------------------------------------- 12 | -- Setup SpoonInstall so that we can install other spoons. 13 | -- ----------------------------------------------------------------------------- 14 | hs.loadSpoon("SpoonInstall") 15 | spoonInstall = spoon.SpoonInstall 16 | spoonInstall.use_syncinstall = true 17 | spoonInstall:updateAllRepos() 18 | 19 | -- ----------------------------------------------------------------------------- 20 | -- System Management 21 | -- ----------------------------------------------------------------------------- 22 | -- local caffeinate = require "hs.caffeinate" 23 | 24 | -- Lockscreen 25 | -- hotkey.bind(hyper, "q", "Lock", function() 26 | -- caffeinate.lockScreen() 27 | -- end) 28 | 29 | -- caffeine functionality. icon images from keepingyouawake. 30 | -- local caffeine = hs.menubar.new() 31 | -- local activeMessage = "Sleeping prohitited" 32 | -- local inactiveMessage = "Sleeping allowed" 33 | -- function setCaffeineDisplay(state) 34 | -- if state then 35 | -- caffeine:setIcon("caffeine-active.png") 36 | -- caffeine:setTooltip(activeMessage) 37 | -- alert.show(activeMessage) 38 | -- else 39 | -- caffeine:setIcon("caffeine-inactive.png") 40 | -- caffeine:setTooltip(inactiveMessage) 41 | -- alert.show(inactiveMessage) 42 | -- end 43 | -- end 44 | 45 | -- function caffeineClicked() 46 | -- setCaffeineDisplay(caffeinate.toggle("displayIdle")) 47 | -- end 48 | 49 | -- if caffeine then 50 | -- caffeine:setClickCallback(caffeineClicked) 51 | -- setCaffeineDisplay(caffeinate.get("displayIdle")) 52 | -- end 53 | 54 | -- hotkey.bind({"cmd","shift"},"c", function() 55 | -- setCaffeineDisplay(caffeinate.toggle("displayIdle")) 56 | -- end) 57 | 58 | -- Make org-capture available system-wide. 59 | hotkey.bind(hyper, 'c', function() 60 | hs.execute("emacsclient -n -F '(quote (name . api|org-capture))' -e '(api/open-org-capture-frame)'", true) 61 | end) 62 | 63 | -- chunkwm doesn't correctly recognize hotplugging monitors. Current solution 64 | -- is to restart: https://github.com/koekeishiya/chunkwm/issues/313 65 | hotkey.bind(hyper, 'w', function() 66 | hs.notify.show("Yabai", "Restarting yabai", "") 67 | hs.execute("brew services restart yabai", true) 68 | hs.notify.show("Yabai", "Yabai restarted", "") 69 | end) 70 | 71 | -- ----------------------------------------------------------------------------- 72 | -- Window Management with ChunkWM - emulate i3 but use hyper as modifier. 73 | -- ----------------------------------------------------------------------------- 74 | mod1 = hyper -- {"alt"} 75 | mod2 = shift_hyper -- {"alt", "shift"} 76 | 77 | bindings = { 78 | -- Focus window 79 | { mod = mod1, key = 'h', command = "chunkc tiling::window --focus west" }, 80 | { mod = mod1, key = 'j', command = "chunkc tiling::window --focus south" }, 81 | { mod = mod1, key = 'k', command = "chunkc tiling::window --focus north" }, 82 | { mod = mod1, key = 'l', command = "chunkc tiling::window --focus east" }, 83 | { mod = mod1, key = 'p', command = "chunkc tiling::window --focus prev" }, 84 | { mod = mod1, key = 'n', command = "chunkc tiling::window --focus next" }, 85 | -- Fullscreen 86 | { mod = mod1, key = 'f', command = "chunkc tiling::window --toggle fullscreen" }, 87 | -- Moving windows (swapping, actually) 88 | { mod = mod2, key = 'h', command = "chunkc tiling::window --swap west" }, 89 | { mod = mod2, key = 'j', command = "chunkc tiling::window --swap south" }, 90 | { mod = mod2, key = 'k', command = "chunkc tiling::window --swap north" }, 91 | { mod = mod2, key = 'l', command = "chunkc tiling::window --swap east" }, 92 | -- Reset and force windows to their original size 93 | { mod = mod1, key = '=', command = "chunkc tiling::desktop --equalize"}, 94 | -- Close window 95 | { mod = mod2, key = 'q', command = "chunkc tiling::window --close" }, 96 | } 97 | 98 | for _, binding in ipairs(bindings) do 99 | hotkey.bind(binding.mod, binding.key, function() 100 | hs.execute(binding.command, true) 101 | end) 102 | end 103 | 104 | -- 105 | -- Resize mode 106 | -- 107 | resize_mode = hs.hotkey.modal.new(hyper, "r") 108 | 109 | alert_uuid = nil 110 | 111 | function resize_mode:entered() 112 | alert_uuid = hs.alert.show("Window Resize Mode", true) 113 | end 114 | 115 | function resize_mode:exited() 116 | hs.alert.closeSpecific(alert_uuid) 117 | end 118 | 119 | resize_mode:bind({}, 'escape', function() resize_mode:exit() end) 120 | resize_mode:bind({}, 'return', function() resize_mode:exit() end) 121 | resize_mode:bind(hyper, 'r', function() resize_mode:exit() end) 122 | -- left will shrink the window’s width. 123 | resize_mode:bind({}, 'left', function() 124 | hs.execute("chunkc tiling::window --use-temporary-ratio -0.1 --adjust-window-edge east", true) 125 | end) 126 | -- right will grow the window’s width. 127 | resize_mode:bind({}, 'right', function() 128 | hs.execute("chunkc tiling::window --use-temporary-ratio 0.1 --adjust-window-edge east", true) 129 | end) 130 | -- up will shrink the window’s height. 131 | resize_mode:bind({}, 'up', function() 132 | hs.execute("chunkc tiling::window --use-temporary-ratio -0.1 --adjust-window-edge south", true) 133 | end) 134 | -- down will grow the window’s height. 135 | resize_mode:bind({}, 'down', function() 136 | hs.execute("chunkc tiling::window --use-temporary-ratio 0.1 --adjust-window-edge south", true) 137 | end) 138 | 139 | -- ----------------------------------------------------------------------------- 140 | -- Window Management - not useful since I'm using a tiling WM. 141 | -- ----------------------------------------------------------------------------- 142 | -- spoonInstall:installSpoonFromRepo("MiroWindowsManager") 143 | -- hs.loadSpoon("MiroWindowsManager") 144 | -- spoon.MiroWindowsManager:bindHotkeys({ 145 | -- up = {hyper, "up"}, 146 | -- right = {hyper, "right"}, 147 | -- down = {hyper, "down"}, 148 | -- left = {hyper, "left"}, 149 | -- fullscreen = {hyper, "f"} 150 | -- }) 151 | 152 | -- ----------------------------------------------------------------------------- 153 | -- Window switching. 154 | -- ----------------------------------------------------------------------------- 155 | -- 156 | -- cmd-tab replacement using alt-tab. Not useful in most cases. 157 | -- 158 | -- switcher = hs.window.switcher.new(hs.window.filter.new():setDefaultFilter{}) 159 | -- switcher.ui.highlightColor = {0.4,0.4,0.5,0.8} 160 | -- switcher.ui.thumbnailSize = 128 161 | -- switcher.ui.selectedThumbnailSize = 284 162 | -- switcher.ui.backgroundColor = {0.3, 0.3, 0.3, 0.5} 163 | -- switcher.ui.fontName = 'System' 164 | -- switcher.ui.showSelectedTitle = false 165 | 166 | -- hs.hotkey.bind(hyper, "tab", function()switcher:next()end) 167 | -- hs.hotkey.bind(hyper_shift, "tab", function()switcher:previous()end) 168 | 169 | -- 170 | -- ace-window style focused-window switcher in a given desktop with hyper-tab. 171 | -- 172 | -- hs.hints.hintChars = {'a','s','d','f','g','h','j','k','l'} 173 | -- hotkey.bind(hyper, 'tab', function() 174 | -- hs.hints.windowHints() 175 | -- end) 176 | 177 | -- ----------------------------------------------------------------------------- 178 | -- Application Management 179 | -- ----------------------------------------------------------------------------- 180 | local application = require "hs.application" 181 | 182 | -- Quick launcher for most used apps bound to hyper + number. 183 | 184 | keysQuickApps = { 185 | {key = '1', name = 'Firefox'}, 186 | {key = '2', name = 'nvALT'}, 187 | {key = '3', name = 'Emacs'}, 188 | {key = '4', name = 'Alacritty'}, 189 | {key = '5', name = 'iTerm'}, 190 | {key = '6', name = 'Finder'}, 191 | } 192 | 193 | for _, app in ipairs(keysQuickApps) do 194 | hotkey.bind(hyper, app.key, app.name, function() 195 | hs.application.launchOrFocus(app.name) 196 | end) 197 | end 198 | 199 | -- 200 | -- Modal bindings for other frequently used apps bound to [hyper + a] + key. 201 | -- 202 | myModal = hotkey.modal.new({}, "F16") 203 | 204 | keysApps = { 205 | {key = 'a', name = 'Airmail 3'}, 206 | {key = 'b', name = 'Firefox'}, 207 | {key = 'e', name = 'Emacs'}, 208 | {key = 'f', name = 'Finder'}, 209 | {key = 'i', name = 'iTerm'}, 210 | {key = 'p', name = 'Skim'}, 211 | {key = 's', name = 'Safari'}, 212 | {key = 't', name = 'Terminal'}, 213 | } 214 | 215 | for _, app in ipairs(keysApps) do 216 | if app.id then 217 | local located_name = hs.application.nameForBundleID(app.id) 218 | if located_name then 219 | myModal:bind('', app.key, located_name, function() 220 | hs.application.launchOrFocusByBundleID(app.id) 221 | myModal:exit() 222 | end) 223 | end 224 | elseif app.name then 225 | myModal:bind('', app.key, app.name, function() 226 | hs.application.launchOrFocus(app.name) 227 | myModal:exit() 228 | end) 229 | end 230 | end 231 | 232 | pressedModal = function() myModal:enter() end 233 | releasedModal = function() end 234 | hotkey.bind(hyper, 'a', nil, pressedModal, releasedModal) 235 | 236 | -- ----------------------------------------------------------------------------- 237 | -- Monitor battery power source and rebind keys if necessary. 238 | -- ----------------------------------------------------------------------------- 239 | -- local battery = require "hs.battery" 240 | -- local currentPowerSource = "" 241 | -- local browser = "" 242 | -- --local appsOnACPowerOnly = {"Backup and Sync from Google", "Dropbox"} 243 | 244 | -- function watchBatteryPowerSource() 245 | -- local powerSource = battery.powerSource() 246 | -- if currentPowerSource ~= powerSource then 247 | -- currentPowerSource = powerSource 248 | -- local isOnBattery = powerSource == 'Battery Power' 249 | 250 | -- -- for _, appName in ipairs(appsOnACPowerOnly) do 251 | -- -- local app = {hs.application.find(appName)} 252 | -- -- if isOnBattery then 253 | -- -- if next(app) ~= nil then 254 | -- -- for _, id in ipairs(app) do 255 | -- -- id:kill(9) 256 | -- -- end 257 | -- -- end 258 | -- -- else 259 | -- -- if next(app) == nil then 260 | -- -- hs.application.launchOrFocus(appName) 261 | -- -- end 262 | -- -- end 263 | -- -- end 264 | 265 | -- browser = "Firefox" 266 | -- if isOnBattery then 267 | -- browser = "Safari" 268 | -- end 269 | 270 | -- hotkey.bind(hyper, '1', nil, function() 271 | -- hs.application.launchOrFocus(browser) 272 | -- end) 273 | 274 | -- end 275 | -- end 276 | 277 | -- battery.watcher.new(watchBatteryPowerSource):start() 278 | -- watchBatteryPowerSource() 279 | 280 | -- ----------------------------------------------------------------------------- 281 | -- Watch for monitor configuration changes, and restart chunkwm everytime 282 | -- the monitor changes. 283 | -- ----------------------------------------------------------------------------- 284 | local laptop_screen = "Color LCD" 285 | local home_screen = "FHD2303L" 286 | local work_screen = "" 287 | 288 | local timer = null 289 | local DELAY = 5 290 | 291 | common_window_layout = { 292 | {'Safari', nil, laptop_screen, hs.layout.maximized, nil, nil}, 293 | {'Firefox', nil, laptop_screen, hs.layout.maximized, nil, nil}, 294 | {'Mail', nil, laptop_screen, hs.layout.maximized, nil, nil}, 295 | } 296 | 297 | function enforce_layout () 298 | local all_screens = hs.screen.allScreens() 299 | local screen_count = table_length(all_screens) 300 | 301 | if (screen_count == 2) then 302 | local second_screen = all_screens[2] 303 | local window_layout = { 304 | {"Emacs", nil, second_screen, hs.layout.maximized, nil, nil}, 305 | {"iTerm", nil, second_screen, hs.layout.maximized, nil, nil}, 306 | {"Alacritty", nil, second_screen, hs.layout.maximized, nil, nil}, 307 | } 308 | 309 | local final_layout = {} 310 | table_merge(final_layout, common_window_layout) 311 | table_merge(final_layout, window_layout) 312 | hs.layout.apply(final_layout) 313 | end 314 | end 315 | 316 | function screen_watcher_handler () 317 | if (timer) then timer:stop() end 318 | timer = hs.timer.doAfter(DELAY, function() 319 | enforce_layout() 320 | end) 321 | end 322 | 323 | -- local screen_watcher = hs.screen.watcher.new(screen_watcher_handler) 324 | -- screen_watcher:start() 325 | 326 | -- ----------------------------------------------------------------------------- 327 | -- Show the mouse when its hiding somewhere. 328 | -- ----------------------------------------------------------------------------- 329 | spoonInstall:installSpoonFromRepo("MouseCircle") 330 | hs.loadSpoon("MouseCircle") 331 | spoon.MouseCircle:bindHotkeys({ 332 | show = { hyper, "m" } 333 | }) 334 | 335 | -- ----------------------------------------------------------------------------- 336 | -- Reload config automatically upon change. 337 | -- ----------------------------------------------------------------------------- 338 | spoonInstall:installSpoonFromRepo("ReloadConfiguration") 339 | hs.loadSpoon("ReloadConfiguration") 340 | --spoon.ReloadConfiguration:start() 341 | -- function reloadConfig(files) 342 | -- doReload = false 343 | -- for _,file in pairs(files) do 344 | -- if file:sub(-4) == ".lua" then 345 | -- doReload = true 346 | -- end 347 | -- end 348 | -- if doReload then 349 | -- hs.reload() 350 | -- end 351 | -- end 352 | -- local myWatcher = hs.pathwatcher.new("/Users/api/.hammerspoon/", 353 | -- reloadConfig):start() 354 | alert.show("Hammerspoon config loaded") 355 | -------------------------------------------------------------------------------- /.hammerspoon/Spoons/SpoonInstall.spoon/init.lua: -------------------------------------------------------------------------------- 1 | --- === SpoonInstall === 2 | --- 3 | --- Install and manage Spoons and Spoon repositories 4 | --- 5 | --- Download: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/SpoonInstall.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/SpoonInstall.spoon.zip) 6 | 7 | local obj={} 8 | obj.__index = obj 9 | 10 | -- Metadata 11 | obj.name = "SpoonInstall" 12 | obj.version = "0.1" 13 | obj.author = "Diego Zamboni " 14 | obj.homepage = "https://github.com/Hammerspoon/Spoons" 15 | obj.license = "MIT - https://opensource.org/licenses/MIT" 16 | 17 | --- SpoonInstall.logger 18 | --- Variable 19 | --- Logger object used within the Spoon. Can be accessed to set the default log level for the messages coming from the Spoon. 20 | obj.logger = hs.logger.new('SpoonInstall') 21 | 22 | --- SpoonInstall.repos 23 | --- Variable 24 | --- Table containing the list of available Spoon repositories. The key 25 | --- of each entry is an identifier for the repository, and its value 26 | --- is a table with the following entries: 27 | --- * desc - Human-readable description for the repository 28 | --- * url - Base URL for the repository. For now the repository is assumed to be hosted in GitHub, and the URL should be the main base URL of the repository. Repository metadata needs to be stored under `docs/docs.json`, and the Spoon zip files need to be stored under `Spoons/`. 29 | --- 30 | --- Default value: 31 | --- ``` 32 | --- { 33 | --- default = { 34 | --- url = "https://github.com/Hammerspoon/Spoons", 35 | --- desc = "Main Hammerspoon Spoon repository", 36 | --- } 37 | --- } 38 | --- ``` 39 | obj.repos = { 40 | default = { 41 | url = "https://github.com/Hammerspoon/Spoons", 42 | desc = "Main Hammerspoon Spoon repository", 43 | } 44 | } 45 | 46 | --- SpoonInstall.use_syncinstall 47 | --- Variable 48 | --- If `true`, `andUse()` will update repos and install packages synchronously. Defaults to `false`. 49 | --- 50 | --- Keep in mind that if you set this to `true`, Hammerspoon will 51 | --- block until all missing Spoons are installed, but the notifications 52 | --- will happen at a more "human readable" rate. 53 | obj.use_syncinstall = false 54 | 55 | -- Execute a command and return its output with trailing EOLs trimmed. If the command fails, an error message is logged. 56 | local function _x(cmd, errfmt, ...) 57 | local output, status = hs.execute(cmd) 58 | if status then 59 | local trimstr = string.gsub(output, "\n*$", "") 60 | return trimstr 61 | else 62 | obj.logger.ef(errfmt, ...) 63 | return nil 64 | end 65 | end 66 | 67 | -- -------------------------------------------------------------------- 68 | -- Spoon repository management 69 | 70 | -- Internal callback to process and store the data from docs.json about a repository 71 | -- callback is called with repo as arguments, only if the call is successful 72 | function obj:_storeRepoJSON(repo, callback, status, body, hdrs) 73 | local success=nil 74 | if (status < 100) or (status >= 400) then 75 | self.logger.ef("Error fetching JSON data for repository '%s'. Error code %d: %s", repo, status, body or "") 76 | else 77 | local json = hs.json.decode(body) 78 | if json then 79 | self.repos[repo].data = {} 80 | for i,v in ipairs(json) do 81 | v.download_url = self.repos[repo].download_base_url .. v.name .. ".spoon.zip" 82 | self.repos[repo].data[v.name] = v 83 | end 84 | self.logger.df("Updated JSON data for repository '%s'", repo) 85 | success=true 86 | else 87 | self.logger.ef("Invalid JSON received for repository '%s': %s", repo, body) 88 | end 89 | end 90 | if callback then 91 | callback(repo, success) 92 | end 93 | return success 94 | end 95 | 96 | -- Internal function to return the URL of the docs.json file based on the URL of a GitHub repo 97 | function obj:_build_repo_json_url(repo) 98 | if self.repos[repo] and self.repos[repo].url then 99 | self.repos[repo].json_url = string.gsub(self.repos[repo].url, "/$", "") .. "/raw/master/docs/docs.json" 100 | self.repos[repo].download_base_url = string.gsub(self.repos[repo].url, "/$", "") .. "/raw/master/Spoons/" 101 | return true 102 | else 103 | self.logger.ef("Invalid or unknown repository '%s'", repo) 104 | return nil 105 | end 106 | end 107 | 108 | --- SpoonInstall:asyncUpdateRepo(repo, callback) 109 | --- Method 110 | --- Asynchronously fetch the information about the contents of a Spoon repository 111 | --- 112 | --- Parameters: 113 | --- * repo - name of the repository to update. Defaults to `"default"`. 114 | --- * callback - if given, a function to be called after the update finishes (also if it fails). The function will receive the following arguments: 115 | --- * repo - name of the repository 116 | --- * success - boolean indicating whether the update succeeded 117 | --- 118 | --- Returns: 119 | --- * `true` if the update was correctly initiated (i.e. the repo name is valid), `nil` otherwise 120 | --- 121 | --- Notes: 122 | --- * For now, the repository data is not persisted, so you need to update it after every restart if you want to use any of the install functions. 123 | function obj:asyncUpdateRepo(repo, callback) 124 | if not repo then repo = 'default' end 125 | if self:_build_repo_json_url(repo) then 126 | hs.http.asyncGet(self.repos[repo].json_url, nil, hs.fnutils.partial(self._storeRepoJSON, self, repo, callback)) 127 | return true 128 | else 129 | return nil 130 | end 131 | end 132 | 133 | --- SpoonInstall:updateRepo(repo) 134 | --- Method 135 | --- Synchronously fetch the information about the contents of a Spoon repository 136 | --- 137 | --- Parameters: 138 | --- * repo - name of the repository to update. Defaults to `"default"`. 139 | --- 140 | --- Returns: 141 | --- * `true` if the update was successful, `nil` otherwise 142 | --- 143 | --- Notes: 144 | --- * This is a synchronous call, which means Hammerspoon will be blocked until it finishes. For use in your configuration files, it's advisable to use `SpoonInstall.asyncUpdateRepo()` instead. 145 | --- * For now, the repository data is not persisted, so you need to update it after every restart if you want to use any of the install functions. 146 | function obj:updateRepo(repo) 147 | if not repo then repo = 'default' end 148 | if self:_build_repo_json_url(repo) then 149 | local a,b,c = hs.http.get(self.repos[repo].json_url) 150 | return self:_storeRepoJSON(repo, nil, a, b, c) 151 | else 152 | return nil 153 | end 154 | end 155 | 156 | --- SpoonInstall:updateAllRepos() 157 | --- Method 158 | --- Synchronously fetch the information about the contents of all Spoon repositories registered in `SpoonInstall.repos` 159 | --- 160 | --- Parameters: 161 | --- * None 162 | --- 163 | --- Returns: 164 | --- * None 165 | --- 166 | --- Notes: 167 | --- * This is a synchronous call, which means Hammerspoon will be blocked until it finishes. 168 | --- * For now, the repository data is not persisted, so you need to update it after every restart if you want to use any of the install functions. 169 | function obj:updateAllRepos() 170 | for k,v in pairs(self.repos) do 171 | self:updateRepo(k) 172 | end 173 | end 174 | 175 | --- SpoonInstall:repolist() 176 | --- Method 177 | --- Return a sorted list of registered Spoon repositories 178 | --- 179 | --- Parameters: 180 | --- * None 181 | --- 182 | --- Returns: 183 | --- * Table containing a list of strings with the repository identifiers 184 | function obj:repolist() 185 | local keys={} 186 | -- Create sorted list of keys 187 | for k,v in pairs(self.repos) do table.insert(keys, k) end 188 | table.sort(keys) 189 | return keys 190 | end 191 | 192 | --- SpoonInstall:search(pat) 193 | --- Method 194 | --- Search repositories for a pattern 195 | --- 196 | --- Parameters: 197 | --- * pat - Lua pattern that will be matched against the name and description of each spoon in the registered repositories. All text is converted to lowercase before searching it, so you can use all-lowercase in your pattern. 198 | --- 199 | --- Returns: 200 | --- * Table containing a list of matching entries. Each entry is a table with the following keys: 201 | --- * name - Spoon name 202 | --- * desc - description of the spoon 203 | --- * repo - identifier in the repository where the match was found 204 | function obj:search(pat) 205 | local res={} 206 | for repo,v in pairs(self.repos) do 207 | if v.data then 208 | for spoon,rec in pairs(v.data) do 209 | if string.find(string.lower(rec.name .. "\n" .. rec.desc), pat) then 210 | table.insert(res, { name = rec.name, desc = rec.desc, repo = repo }) 211 | end 212 | end 213 | else 214 | self.logger.ef("Repository data for '%s' not available - call spoon.SpoonInstall:updateRepo('%s'), then try again.", repo, repo) 215 | end 216 | end 217 | return res 218 | end 219 | 220 | -- -------------------------------------------------------------------- 221 | -- Spoon installation 222 | 223 | -- Internal callback function to finalize the installation of a spoon after the zip file has been downloaded. 224 | -- callback, if given, is called with (urlparts, success) as arguments 225 | function obj:_installSpoonFromZipURLgetCallback(urlparts, callback, status, body, headers) 226 | local success=nil 227 | if (status < 100) or (status >= 400) then 228 | self.logger.ef("Error downloading %s. Error code %d: %s", urlparts.absoluteString, status, body or "") 229 | else 230 | -- Write the zip file to disk in a temporary directory 231 | local tmpdir=_x("/usr/bin/mktemp -d", "Error creating temporary directory to download new spoon.") 232 | if tmpdir then 233 | local outfile = string.format("%s/%s", tmpdir, urlparts.lastPathComponent) 234 | local f=assert(io.open(outfile, "w")) 235 | f:write(body) 236 | f:close() 237 | 238 | -- Check its contents - only one *.spoon directory should be in there 239 | output = _x(string.format("/usr/bin/unzip -l %s '*.spoon/' | /usr/bin/awk '$NF ~ /\\.spoon\\/$/ { print $NF }' | /usr/bin/wc -l", outfile), 240 | "Error examining downloaded zip file %s, leaving it in place for your examination.", outfile) 241 | if output then 242 | if (tonumber(output) or 0) == 1 then 243 | -- Uncompress the zip file 244 | local outdir = string.format("%s/Spoons", hs.configdir) 245 | if _x(string.format("/usr/bin/unzip -o %s -d %s 2>&1", outfile, outdir), 246 | "Error uncompressing file %s, leaving it in place for your examination.", outfile) then 247 | -- And finally, install it using Hammerspoon itself 248 | self.logger.f("Downloaded and installed %s", urlparts.absoluteString) 249 | _x(string.format("/bin/rm -rf '%s'", tmpdir), "Error removing directory %s", tmpdir) 250 | success=true 251 | end 252 | else 253 | self.logger.ef("The downloaded zip file %s is invalid - it should contain exactly one spoon. Leaving it in place for your examination.", outfile) 254 | end 255 | end 256 | end 257 | end 258 | if callback then 259 | callback(urlparts, success) 260 | end 261 | return success 262 | end 263 | 264 | --- SpoonInstall:asyncInstallSpoonFromZipURL(url, callback) 265 | --- Method 266 | --- Asynchronously download a Spoon zip file and install it. 267 | --- 268 | --- Parameters: 269 | --- * url - URL of the zip file to install. 270 | --- * callback - if given, a function to call after the installation finishes (also if it fails). The function receives the following arguments: 271 | --- * urlparts - Result of calling `hs.http.urlParts` on the URL of the Spoon zip file 272 | --- * success - boolean indicating whether the installation was successful 273 | --- 274 | --- Returns: 275 | --- * `true` if the installation was correctly initiated (i.e. the URL is valid), `false` otherwise 276 | function obj:asyncInstallSpoonFromZipURL(url, callback) 277 | local urlparts = hs.http.urlParts(url) 278 | local dlfile = urlparts.lastPathComponent 279 | if dlfile and dlfile ~= "" and urlparts.pathExtension == "zip" then 280 | hs.http.asyncGet(url, nil, hs.fnutils.partial(self._installSpoonFromZipURLgetCallback, self, urlparts, callback)) 281 | return true 282 | else 283 | self.logger.ef("Invalid URL %s, must point to a zip file", url) 284 | return nil 285 | end 286 | end 287 | 288 | --- SpoonInstall:installSpoonFromZipURL(url) 289 | --- Method 290 | --- Synchronously download a Spoon zip file and install it. 291 | --- 292 | --- Parameters: 293 | --- * url - URL of the zip file to install. 294 | --- 295 | --- Returns: 296 | --- * `true` if the installation was successful, `nil` otherwise 297 | function obj:installSpoonFromZipURL(url) 298 | local urlparts = hs.http.urlParts(url) 299 | local dlfile = urlparts.lastPathComponent 300 | if dlfile and dlfile ~= "" and urlparts.pathExtension == "zip" then 301 | a,b,c=hs.http.get(url) 302 | return self:_installSpoonFromZipURLgetCallback(urlparts, nil, a, b, c) 303 | else 304 | self.logger.ef("Invalid URL %s, must point to a zip file", url) 305 | return nil 306 | end 307 | end 308 | 309 | -- Internal function to check if a Spoon/Repo combination is valid 310 | function obj:_is_valid_spoon(name, repo) 311 | if self.repos[repo] then 312 | if self.repos[repo].data then 313 | if self.repos[repo].data[name] then 314 | return true 315 | else 316 | self.logger.ef("Spoon '%s' does not exist in repository '%s'. Please check and try again.", name, repo) 317 | end 318 | else 319 | self.logger.ef("Repository data for '%s' not available - call spoon.SpoonInstall:updateRepo('%s'), then try again.", repo, repo) 320 | end 321 | else 322 | self.logger.ef("Invalid or unknown repository '%s'", repo) 323 | end 324 | return nil 325 | end 326 | 327 | --- SpoonInstall:asyncInstallSpoonFromRepo(name, repo, callback) 328 | --- Method 329 | --- Asynchronously install a Spoon from a registered repository 330 | --- 331 | --- Parameters: 332 | --- * name - Name of the Spoon to install. 333 | --- * repo - Name of the repository to use. Defaults to `"default"` 334 | --- * callback - if given, a function to call after the installation finishes (also if it fails). The function receives the following arguments: 335 | --- * urlparts - Result of calling `hs.http.urlParts` on the URL of the Spoon zip file 336 | --- * success - boolean indicating whether the installation was successful 337 | --- 338 | --- Returns: 339 | --- * `true` if the installation was correctly initiated (i.e. the repo and spoon name were correct), `false` otherwise. 340 | function obj:asyncInstallSpoonFromRepo(name, repo, callback) 341 | if not repo then repo = 'default' end 342 | if self:_is_valid_spoon(name, repo) then 343 | self:asyncInstallSpoonFromZipURL(self.repos[repo].data[name].download_url, callback) 344 | end 345 | return nil 346 | end 347 | 348 | --- SpoonInstall:installSpoonFromRepo(name, repo) 349 | --- Method 350 | --- Synchronously install a Spoon from a registered repository 351 | --- 352 | --- Parameters: 353 | --- * name = Name of the Spoon to install. 354 | --- * repo - Name of the repository to use. Defaults to `"default"` 355 | --- 356 | --- Returns: 357 | --- * `true` if the installation was successful, `nil` otherwise. 358 | function obj:installSpoonFromRepo(name, repo, callback) 359 | if not repo then repo = 'default' end 360 | if self:_is_valid_spoon(name, repo) then 361 | return self:installSpoonFromZipURL(self.repos[repo].data[name].download_url) 362 | end 363 | return nil 364 | end 365 | 366 | --- SpoonInstall:andUse(name, arg) 367 | --- Method 368 | --- Declaratively install, load and configure a Spoon 369 | --- 370 | --- Parameters: 371 | --- * name - the name of the Spoon to install (without the `.spoon` extension). If the Spoon is already installed, it will be loaded using `hs.loadSpoon()`. If it is not installed, it will be installed using `SpoonInstall:asyncInstallSpoonFromRepo()` and then loaded. 372 | --- * arg - if provided, can be used to specify the configuration of the Spoon. The following keys are recognized (all are optional): 373 | --- * repo - repository from where the Spoon should be installed if not present in the system, as defined in `SpoonInstall.repos`. Defaults to `"default"`. 374 | --- * config - a table containing variables to be stored in the Spoon object to configure it. For example, `config = { answer = 42 }` will result in `spoon..answer` being set to 42. 375 | --- * hotkeys - a table containing hotkey bindings. If provided, will be passed as-is to the Spoon's `bindHotkeys()` method. The special string `"default"` can be given to use the Spoons `defaultHotkeys` variable, if it exists. 376 | --- * fn - a function which will be called with the freshly-loaded Spoon object as its first argument. 377 | --- * loglevel - if the Spoon has a variable called `logger`, its `setLogLevel()` method will be called with this value. 378 | --- * start - if `true`, call the Spoon's `start()` method after configuring everything else. 379 | --- * disable - if `true`, do nothing. Easier than commenting it out when you want to temporarily disable a spoon. 380 | --- 381 | --- Returns: 382 | --- * None 383 | function obj:andUse(name, arg) 384 | if not arg then arg = {} end 385 | if arg.disable then return true end 386 | if hs.spoons.use(name, arg, true) then 387 | return true 388 | else 389 | local repo = arg.repo or "default" 390 | if self.repos[repo] then 391 | if self.repos[repo].data then 392 | local load_and_config = function(_, success) 393 | if success then 394 | hs.notify.show("Spoon installed by SpoonInstall", name .. ".spoon is now available", "") 395 | hs.spoons.use(name, arg) 396 | else 397 | obj.logger.ef("Error installing Spoon '%s' from repo '%s'", name, repo) 398 | end 399 | end 400 | if self.use_syncinstall then 401 | return load_and_config(nil, self:installSpoonFromRepo(name, repo)) 402 | else 403 | self:asyncInstallSpoonFromRepo(name, repo, load_and_config) 404 | end 405 | else 406 | local update_repo_and_continue = function(_, success) 407 | if success then 408 | obj:andUse(name, arg) 409 | else 410 | obj.logger.ef("Error updating repository '%s'", repo) 411 | end 412 | end 413 | if self.use_syncinstall then 414 | return update_repo_and_continue(nil, self:updateRepo(repo)) 415 | else 416 | self:asyncUpdateRepo(repo, update_repo_and_continue) 417 | end 418 | end 419 | else 420 | obj.logger.ef("Unknown repository '%s' for Spoon", repo, name) 421 | end 422 | end 423 | end 424 | 425 | return obj 426 | --------------------------------------------------------------------------------