;;; init.el --- Initialization file for emacs ;;; Commentary: Emacs startup file --- initialization file for emacs (setq custom-file (concat user-emacs-directory ".emacs-customize.el") require-final-newline t) ;; Track emacs load time (defconst emacs-start-time (current-time)) ;; Other configs (setq make-backup-files nil) (setq auto-save-default nil) (global-auto-revert-mode t) ;; Splash Screen (setq inhibit-startup-screen t) (setq initial-scratch-message ";; Happy Hacking") ;; Show matching parens (setq show-paren-delay 0) (show-paren-mode 1) (electric-pair-mode 1) ;; UI configurations (if (display-graphic-p) (progn (tool-bar-mode -1) (scroll-bar-mode -1))) (tooltip-mode -1) (menu-bar-mode -1) (global-linum-mode 1) ;; Font configurations (add-to-list 'default-frame-alist '(font . "Iosevka-14")) (add-to-list 'default-frame-alist '(height . 24)) (add-to-list 'default-frame-alist '(width . 80)) (add-to-list 'default-frame-alist '(fullscreen . maximized)) ;;; Package Management (require 'package) (setq package-enable-at-startup nil) (setq package-archives '(("org" . "http://orgmode.org/elpa/") ("gnu" . "http://elpa.gnu.org/packages/") ("melpa" . "https://melpa.org/packages/"))) (package-initialize) ;; Bootstrap `use-package` (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (eval-when-compile (require 'use-package)) ;; always download all packages if not already downloaded (setq use-package-always-ensure t) ;; keep stats about packages (setq use-package-compute-statistics t) ; no longer included with use-package by default (use-package diminish) (use-package auto-package-update :ensure t :config (setq auto-package-update-delete-old-versions t auto-package-update-interval 4) (auto-package-update-maybe)) ;; Restart emacs from within emacs (use-package restart-emacs :ensure t) ;; Theme (use-package doom-themes :ensure t :config (load-theme 'doom-molokai t)) ;; Auto enforced consistence (use-package editorconfig :diminish "↹" :init (setq auto-mode-alist (cl-union auto-mode-alist '(("\\.editorconfig\\'" . editorconfig-conf-mode) ("editorconfig\\'" . editorconfig-conf-mode)))) :config (editorconfig-mode 1)) (use-package smartparens :hook ((prog-mode-hook) . smartparens-mode) :config (require 'smartparens-config)) (use-package aggressive-indent :diminish "⇉" :config (global-aggressive-indent-mode t)) (use-package fzf :ensure t) ;; Anzu for search matching (use-package anzu :ensure t :config (global-anzu-mode 1) (global-set-key [remap query-replace-regexp] 'anzu-query-replace-regexp) (global-set-key [remap query-replace] 'anzu-query-replace)) (use-package avy :defer t :init (progn (setq avy-all-windows 'all-frames) (setq avy-background t))) (use-package dumb-jump :ensure t) ;; Vim mode (use-package evil :ensure t :config (evil-mode 1)) (use-package evil-escape :ensure t :init (setq-default evil-escape-key-sequence "jk") :config (evil-escape-mode 1)) (use-package evil-nerd-commenter :ensure t) (use-package evil-surround :ensure t :config (global-evil-surround-mode 1)) (use-package disable-mouse :ensure t :config (global-disable-mouse-mode)) ;; Helm (use-package helm :ensure t :init (setq helm-M-x-fuzzy-match t helm-mode-fuzzy-match t helm-buffers-fuzzy-matching t helm-recentf-fuzzy-match t helm-locate-fuzzy-match t helm-semantic-fuzzy-match t helm-imenu-fuzzy-match t helm-completion-in-region-fuzzy-match t helm-candidate-number-list 80 helm-split-window-inside-p t helm-move-to-line-cycle-in-source t helm-echo-input-in-header-line t helm-autoresize-max-height 0 helm-autoresize-min-height 20) :config (helm-mode 1)) ;; RipGrep (use-package helm-rg :ensure t) ;; Projectile (use-package projectile :ensure t :init (setq projectile-require-project-root nil) :config (projectile-mode 1)) ;; Helm Projectile (use-package helm-projectile :ensure t :init (setq helm-projectile-fuzzy-match t) :config (helm-projectile-on)) ;; All The Icons (use-package all-the-icons :ensure t) ;; Which Key (use-package which-key :ensure t :init (setq which-key-separator " ") (setq which-key-prefix-prefix "+") :config (which-key-mode)) ;; Git Support (use-package magit :defer t) (use-package evil-magit :defer t) (use-package magit-gitflow :defer t) (use-package helm-git-grep :defer t) (use-package helm-gitignore :defer t) (use-package git-commit :defer t) (use-package git-messenger :defer t :config (define-key git-messenger-map [escape] 'git-messenger:popup-close)) (use-package gitattributes-mode :defer t) (use-package gitconfig-mode :defer t) (use-package gitignore-mode :defer t) (use-package git-link :defer t :config (setq git-link-open-in-browser t)) (use-package git-gutter :defer t :config (global-git-gutter-mode +1)) (use-package gitignore-templates :defer t) ;; See below 3 links for why config has been set like this ;; https://stackoverflow.com/questions/25517190/missing-complete-candidate-for-verilog-mode-with-company-mode ;; https://github.com/flycheck/flycheck/issues/740 ;; https://github.com/flycheck/flycheck/issues/1250 (use-package verilog-mode :defer t :config (add-to-list 'company-keywords-alist (cons 'verilog-mode verilog-keywords)) (setq flycheck-verilog-verilator-executable "verilator_bin")) ;; Custom keybinding (use-package general :ensure t :init (setq general-override-states '(insert emacs hybrid normal visual motion operator replace)) :config (general-define-key :states '(normal visual insert emacs) :prefix "SPC" :non-normal-prefix "M-SPC" "TAB" '(switch-to-prev-buffer :which-key "previous buffer") "SPC" '(helm-M-x :which-key "M-x") ;; fuzzy search "ff" '(fzf :which-key "fuzzy file search") ;; Projectile "/" '(helm-projectile-rg :which-key "ripgrep") "pf" '(helm-projectile-find-file :which-key "find files") "pF" '(helm-projectile-find-file-dwim :which-key "find files dwim") "pp" '(helm-projectile-switch-project :which-key "switch project") "pb" '(helm-projectile-switch-to-buffer :which-key "switch buffer") "pr" '(helm-projectile-recent :which-key "show recent") "pd" '(helm-projectile-find-dir :which-key "find dir") "ph" '(helm-projectile :which-key "helm projectile") ;; Buffers "bb" '(helm-mini :which-key "buffers list") ;; Window "wl" '(windmove-right :which-key "move right") "wh" '(windmove-left :which-key "move left") "wk" '(windmove-up :which-key "move up") "wj" '(windmove-down :which-key "move bottom") "w/" '(split-window-right :which-key "split right") "w-" '(split-window-below :which-key "split bottom") "wx" '(delete-window :which-key "delete window") "qz" '(delete-frame :which-key "delete frame") "qq" '(kill-emacs :which-key "quit") "qr" '(restart-emacs :which-key "restart emacs") ;; Others "at" '(eshell :which-key "open terminal") ;; Magit key bindings "gc" '(magit-clone :which-key "magit clone") "gff" '(magit-find-file :which-key "magit find file") "gfl" '(magit-log-buffer-file :which-key "magit log buffer file") "gfd" '(magit-diff-dwim :which-key "magit diff buffer file popup") "gi" '(magit-init :which-key "magit initialize") "gL" '(magit-list-repositories :which-key "magit list repositories") "gm" '(magit-dispatch-popup :which-key "magit dispatch popup") "gs" '(magit-status :which-key "open Magit status buffer") "gS" '(magit-stage-file :which-key "magit stage file") "gU" '(magit-unstage-file :which-key "magit unstage file") "g/" '(helm-git-grep :which-key "open helm git grep") "g*" '(helm-git-grep-at-point :which-key "open helm git grep at point") "gI" '(helm-gitignore :which-key "helm gitignore") "%" 'magit-gitflow-popup "gti" 'gitignore-templates-insert "gtn" 'gitignore-templates-new-file "gM" 'git-messenger:popup-message "gll" 'spacemacs/git-link "glL" 'spacemacs/git-link-copy-url-only "glc" 'spacemacs/git-link-commit "glC" 'spacemacs/git-link-commit-copy-url-only ;; evil nerd commenter "ci" 'evilnc-comment-or-uncomment-lines "cl" 'evilnc-quick-comment-or-uncomment-to-the-line "ll" 'evilnc-quick-comment-or-uncomment-to-the-line "cc" 'evilnc-copy-and-comment-lines "cp" 'evilnc-comment-or-uncomment-paragraphs "cr" 'comment-or-uncomment-region "cv" 'evilnc-toggle-invert-comment-line-by-line "." 'evilnc-copy-and-comment-operator "\\" 'evilnc-comment-operator "jb" 'avy-pop-mark "jj" 'evil-avy-goto-char-timer "jl" 'evil-avy-goto-line "jw" 'evil-avy-goto-word-or-subword-1 ;; dumb jump "dg" 'dumb-jump-go "dp" 'dump-jump-back "dq" 'dump-jump-quick-look "dw" 'dumb-jump-go-other-window "de" 'dumb-jump-go-prefer-external "do" 'dumb-jump-go-prefer-external-other-window "dp" 'dumb-jump-go-prompt ;; xref "xv" 'visit-tags-table "xd" 'xref-find-definitions "xr" 'xref-find-references "xa" 'xref-find-apropos "xf" 'xref-find-definitions-other-frame "xp" 'xref-pop-marker-stack "xq" 'xref-query-replace-in-results "xs" 'tags-search)) (general-define-key :states '(normal visual emacs) :prefix "SPC m" :keymaps 'haskell-mode-map ;; Haskell bindings "f" '(hindent-reformat-decl :which-key "format declaration using hindent") "F" '(haskell-mode-stylish-buffer :which-key "format buffer using haskell stylish") "rb" '(hlint-refactor-refactor-buffer :which-key "apply all hlint suggestions") "rr" '(hlint-refactor-refactor-at-point :which-key "apply hlint suggestion under cursor")) (general-define-key :states '(normal visual emacs) :prefix "SPC m" :keymaps 'rust-mode-map "c." '(cargo-process-repeat :which-key "repeat the last cargo command") "cC" '(cargo-process-clean :which-key "remove build artifacts with cargo") "cX" '(cargo-process-run-example :which-key "execute project example with cargo") "cc" '(cargo-process-build :which-key "compile project with cargo") "cd" '(cargo-process-doc :which-key "generate documentation with cargo") "cD" '(cargo-process-doc-open :which-key "open cargo docs") "ce" '(cargo-process-bench :which-key "run benchmarks with cargo") "cf" '(cargo-process-fmt :which-key "format all project files with rustfmt") "ci" '(cargo-process-init :which-key "create a new project with cargo") "cl" '(cargo-process-clippy :which-key "run linter with cargo") "cn" '(cargo-process-new :which-key "create new project with cargo") "co" '(cargo-process-current-file-tests :which-key "run all tests in current file with cargo") "cs" '(cargo-process-search :which-key "search for packages on crates.io") "ct" '(cargo-process-current-test :which-key "run the current test with cargo") "cu" '(cargo-process-update :which-key "update dependencies with cargo") "cx" '(cargo-process-run :which-key "execute a process with cargo") "cv" '(cargo-process-check :which-key "verify a project with cargo") "t" '(cargo-process-test :which-key "run test with cargo") "==" '(rust-format-buffer :which-key "rust reformat the buffer")) (general-define-key :states '(normal visual emacs) :prefix "SPC m" :keymaps 'lisp-mode-map "cc" '(slime-compile-file :which-key "compile file") "cC" '(slime-compile-and-load-file :which-key "compile file and load") "cl" '(slime-load-file :which-key "load file") "cf" '(slime-compile-defun :which-key "compile function") "cr" '(slime-compile-region :which-key "compile region") "cn" '(slime-remove-notes :which-key "remove compilation notes") "eb" '(slime-eval-buffer :which-key "evaluate buffer") "ef" '(slime-eval-defun :which-key "evaluate top level sexpr") "eF" '(slime-undefine-function :which-key "undefine the fn at point") "ee" '(slime-eval-last-expression :which-key "evaluate last sexpr") "er" '(slime-eval-region :which-key "evaluate region") "gb" '(slime-pop-find-definition-stack :which-key "go back") "gn" '(slime-next-note :which-key "next note") "gN" '(slime-previous-note :which-key "previous note") "ha" '(slime-apropos :which-key "SLIME appropos") "hA" '(slime-apropos-all :which-key "SLIME appropos all") "hd" '(slime-disassemble-symbol :which-key "disassemble symbol at point") "hh" '(slime-describe-symbol :which-key "describe symbol at point") "hH" '(slime-hyperspec-lookup :which-key "hyperspec lookup symbol at point") "hi" '(slime-inspect-definition :which-key "inspect defintion") "hp" '(slime-apropos-package :which-key "browse appropos results for package's exported symbols") "ht" '(slime-toggle-trace-definition :which-key "toggle tracing of function at point") "hT" '(slime-untrace-all :which-key "untrace all functions") "h<" '(slime-who-calls :which-key "show all known callers") "h>" '(slime-calls-who :which-key "show all known callees") "hr" '(slime-who-references :which-key "show references to global variable") "hm" '(slime-who-macroexpands :which-key "show all usages of a macro") "hs" '(slime-who-specializes :which-key "show all methods specialized on a class") "ma" '(slime-macroexpand-all :which-key "macroexpand the expr at point completely") "mo" '(slime-macroexpand-1 :which-key "macroexpand the expr at point once") "se" '(slime-eval-last-expression-in-repl :which-key "evaluate last sexpr in repl") "si" '(slime :which-key "start an inferior process") "sq" '(slime-quit-lisp :which-key "quit") "tf" '(slime-toggle-fancy-trace)) (general-define-key :states '(normal visual emacs) :prefix "SPC m" :keymaps 'scheme-mode-map "'" '(geiser-mode-switch-to-repl) "," '(lisp-state-toggle-lisp-state) "cc" '(geiser-compile-current-buffer :which-key "compile current buffer") "cp" '(geiser-add-to-load-path :which-key "add directory to load path") "eb" '(geiser-eval-buffer :which-key "evaluate the whole buffer") "ee" '(geiser-eval-last-sexp :which-key "evaluate last sexp") "ef" '(geiser-eval-definition :which-key "evaluate current function") "el" '(lisp-state-eval-sexp-end-of-line :which-key "evaluate line") "er" '(geiser-eval-region :which-key "evaluate region") "gb" '(geiser-pop-symbol-stack :which-key "go back") "gm" '(geiser-edit-module :which-key "goto module") "gn" '(next-error :which-key "next error") "gN" '(previous-error :which-key "previous error") "hh" '(geiser-doc-symbol-at-point :which-key "docs for symbol at point") "hd" '(geiser-doc-look-up-manual :which-key "look up manual entry for symbol at point") "hm" '(geiser-doc-module :which-key "display exports for module") "h<" '(geiser-xref-callers :which-key "display callers") "h>" '(geiser-xref-callees :which-key "display callees") "il" '(geiser-insert-lambda :which-key "insert lambda") "me" '(geiser-expand-last-sexp :which-key "macroexpand last sexp") "mf" '(geiser-expand-definition :which-key "macroexpand surrounding sexp") "mx" '(geiser-expand-region :which-key "macroexpand region") "si" '(geiser-mode-switch-to-repl :which-key "start or switch to repl") "sb" '(geiser-eval-buffer :which-key "send buffer to repl") "sB" '(geiser-eval-buffer-and-go :which-key "send buffer to repl and focus it") "sf" '(geiser-eval-definition :which-key "send definition to repl") "sF" '(geiser-eval-definition-and-go :which-key "send definition to repl and focus it") "se" '(geiser-eval-last-sexp :which-key "send last sexp to repl") "sr" '(geiser-eval-region :which-key "send region to repl") "sR" '(geiser-eval-region-and-go :which-key "send region to repl and focus it") "ss" '(geiser-set-scheme :which-key "select scheme implementation")) ;(general-define-key ;:states '(normal visual emacs) ;:prefix "SPC m" ;:keymaps 'go-mode-map ;"hh" '(godoc-at-point ;:which-key "godoc at point") ;"ig" '(go-goto-imports ;:which-key "goto imports") ;"ia" '(go-import-add ;:which-key "add imports") ;"ir" '(go-remove-unused-imports ;:which-key "remove unused imports") ;"eb" '(go-play-buffer ;:which-key "go-play buffer") ;"er" '(go-play-region ;:which-key "go-play region") ;"ed" '(go-download-play ;:which-key "download go-play snippet") ;"xx" '(go-run-main ;:which-key "run go run for current main package") ;"ga" '(ff-find-other-file ;:which-key "jump to matching test file or back") ;"gc" '(go-coverage ;:which-key "open a clone of buffer with coverage info") ;"rn" '(go-rename ;:which-key "go rename") ;"fd" '(go-guru-describe ;:which-key "go-guru describe symbol at point") ;"ff" '(go-guru-freevars ;:which-key "go-guru show free variables") ;"fi" '(go-guru-implements ;:which-key "go-guru show implements relation") ;"fc" '(go-guru-peers ;:which-key "go-guru show channel sends/receives") ;"fr" '(go-guru-referrers ;:which-key "go-guru show referrers") ;"fj" '(go-guru-definition ;:which-key "go-guru jump to symbol definition") ;"fp" '(go-guru-pointsto ;:which-key "go-guru show what select expr points to") ;"fs" '(go-guru-callstack ;:which-key "go-guru show call stack") ;"fe" '(go-guru-whicherrs ;:which-key "go-guru show possible constants/types for error value") ;"f<" '(go-guru-callers ;:which-key "go-guru show possible callers") ;"f>" '(go-guru-callees ;:which-key "go-guru show call targets") ;"fo" '(go-guru-set-scope ;:which-key "go-guru set analysis scope")) ;; custom functions (defun spacemacs/git-link-copy-url-only () "Only copy the generated link to the kill ring." (interactive) (let (git-link-open-in-browser) (call-interactively 'spacemacs/git-link))) (defun spacemacs/git-link-commit-copy-url-only () "Only copy the generated link to the kill ring." (interactive) (let (git-link-open-in-browser) (call-interactively 'spacemacs/git-link-commit))) (defun spacemacs/git-link () "Allow the user to run git-link in a git-timemachine buffer." (interactive) (require 'git-link) (if (and (boundp 'git-timemachine-revision) git-timemachine-revision) (cl-letf (((symbol-function 'git-link--branch) (lambda () (car git-timemachine-revision)))) (call-interactively 'git-link)) (call-interactively 'git-link))) (defun spacemacs/git-link-commit () "Allow the user to run git-link-commit in a git-timemachine buffer." (interactive) (require 'git-link) (if (and (boundp 'git-timemachine-revision) git-timemachine-revision) (cl-letf (((symbol-function 'word-at-point) (lambda () (car git-timemachine-revision)))) (call-interactively 'git-link-commit)) (call-interactively 'git-link-commit))) (defun go-run-main () (interactive) (shell-command (format "go run %s" (shell-quote-argument (buffer-file-name))))) ;; Fancy titlebar for MacOS (add-to-list 'default-frame-alist '(ns-transparent-titlebar . t)) (add-to-list 'default-frame-alist '(ns-appearance . dark)) (setq ns-use-proxy-icon nil) (setq frame-title-format nil) ;; Flycheck (use-package flycheck :ensure t :init (global-flycheck-mode)) ;; To disable flycheck while working with this file (setq-default flycheck-disabled-checkers '(emacs-lisp-checkdoc)) ;; Company mode (use-package company :ensure t :diminish "⇥" :init (add-hook 'after-init-hook 'global-company-mode) (setq company-minimum-prefix-length 3) (setq company-auto-complete nil) (setq company-idle-delay 0) (setq company-require-match 'never) (setq company-frontends '(company-pseudo-tooltip-unless-just-one-frontend company-preview-frontend company-echo-metadata-frontend)) (setq tab-always-indent 'complete) (defvar completion-at-point-functions-saved nil) :config (global-company-mode 1) (define-key company-active-map (kbd "TAB") 'company-complete-common-or-cycle) (define-key company-active-map (kbd "") 'company-complete-common-or-cycle) (define-key company-active-map (kbd "S-TAB") 'company-select-previous) (define-key company-active-map (kbd "") 'company-select-previous) (define-key company-mode-map [remap indent-for-tab-command] 'company-indent-for-tab-command) (defun company-indent-for-tab-command (&optional arg) (interactive "P") (let ((completion-at-point-functions-saved completion-at-point-functions) (completion-at-point-functions '(company-complete-common-wrapper))) (indent-for-tab-command arg))) (defun company-complete-common-wrapper () (let ((completion-at-point-functions completion-at-point-functions-saved)) (company-complete-common)))) (use-package company-quickhelp :init (company-quickhelp-mode 1)) ;; Powerline (use-package spaceline :ensure t :init (setq powerline-default-separator 'slant) :config (spaceline-emacs-theme) (spaceline-toggle-minor-modes-off) (spaceline-toggle-buffer-size-off) (spaceline-toggle-evil-state-on)) ;;; Language Support ;; Haskell support (use-package haskell-mode :defer t :init (electric-indent-mode 0) :custom ((haskell-process-type 'stack-ghci) (haskell-process-suggest-remove-import-lines t) (haskell-process-auto-import-loaded-modules t) (haskell-process-log t) (haskell-stylish-on-save t) (haskell-indentation-layout-offset 4) (haskell-indentation-starter-offset 4) (haskell-indentation-left-offset 4) (haskell-indentation-where-pre-offset 4) (haskell-indentation-where-post-offset 4))) (use-package flycheck-haskell :defer t :config (setq-default flycheck-disabled-checkers '(haskell-stack-ghc)) :hook (haskell-mode . #'flycheck-haskell-setup)) (use-package company-ghci :defer t :config (push 'company-ghci company-backends) :hook (haskell-interactive-mode . company-mode)) (use-package hindent :defer t :config (setq-default hindent-reformat-buffer-on-save t) :hook (haskell-mode . #'hindent-mode)) (use-package hlint-refactor :defer t) (use-package rainbow-delimiters :ensure t :hook (prog-mode-hook . rainbow-delimiters-mode)) ;; Rust support (use-package rust-mode :defer t :ensure t :config (setq rust-format-on-save t)) (use-package racer :defer t :hook ((rust-mode . racer-mode) (racer-mode . eldoc-mode) (racer-mode . company-mode))) (use-package cargo :defer t) ;; LISP support (use-package evil-cleverparens :ensure t) (use-package parinfer :ensure t :init (progn (setq parinfer-extensions '(defaults pretty-parens evil paredit smart-tab smart-yank))) :hook ((emacs-lisp-mode . parinfer-mode) (common-lisp-mode . parinfer-mode) (lisp-mode . parinfer-mode) (scheme-mode . parinfer-mode))) (use-package slime :commands slime-mode :init (progn (setq slime-contribs '(slime-asdf slime-fancy slime-indentation slime-sbcl-exts slime-scratch) inferior-lisp-program "sbcl") (setq slime-complete-symbol*-fancy t) (setq slime-complete-symbol-function 'slime-fuzzy-complete-symbol) (defun slime/disable-smartparens () (smartparens-strict-mode -1) (turn-off-smartparens-mode)) (add-hook 'slime-repl-mode-hook #'slime/disable-smartparens)) :config (slime-setup)) ;; scheme support (use-package geiser :defer t :commands run-geiser :hook (scheme-mode . company-mode)) ;; go support ;(use-package company-go ;:defer t ;:init ;(progn ;(setq company-go-show-annotation t) ;(push 'company-go company-backends))) ;(use-package go-impl ;:defer t) ;(use-package go-guru ;:defer t) ;(use-package go-mode ;:defer t ;:init ;(setq-local tab-width 8) ;:config ;(add-hook 'before-save-hook 'gofmt-before-save) ;:hook ;(go-mode . company-mode)) ;;; init.el ends