Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
534 lines (507 sloc) 15.9 KB

Init

This is our initialisation script. This basically sets MELPA packages and ensures that user-package is installed on first install. On first install it’s worth setting:

(setq use-package-always-ensure t)
(require 'package)
(package-initialize)
(setq package-enable-at-startup nil)
(add-to-list 'package-archives
	     '("melpa" . "https://melpa.org/packages/"))
;; Bootstrap `use-package'
(unless (package-installed-p 'use-package)
	(package-refresh-contents)
	(package-install 'use-package))
(setq custom-file "~/.emacs.d/custom-settings.el")
(load custom-file t)
(setq ad-redefinition-action 'accept)

Personal Information

(setq user-full-name "Clint Ryan"
      user-mail-address "")

Interface

Just some nice user interfaces tweaks. Bread and butter stuff!

(global-linum-mode 1)
(scroll-bar-mode -1)
(setq inhibit-startup-message t)
(setq-default indent-tabs-mode nil)
(setq ring-bell-function 'ignore)
(tool-bar-mode -1)
(fset 'yes-or-no-p 'y-or-n-p)

Company

(use-package company
  :ensure t
  :config 
  (add-hook 'prog-mode-hook 'global-company-mode)
  (setq company-tooltip-align-annotations t))

Color Theme

Solarize everything!

(use-package zenburn-theme
  :ensure t
  :config)

Evil

Evil complements the emacs ecosystem perfectly. The first thing I do is get this set up! It’s super important to have the leader keymap as well, so that I can perform all my combinations super fast. A lot of these keybindings have been heavily influenced from spacemacs. I like to throw in magit support and surround support too.

(use-package evil
  :ensure t
  :diminish evil-mode
  :init 
  (setq evil-want-C-u-scroll t)
  :config
  (evil-mode 1))
(use-package evil-leader
  :ensure t
  :config
  (evil-leader/set-leader "SPC")
  (evil-leader/set-key
   "SPC" 'counsel-M-x
   "[" 'previous-error
   "]" 'next-error
   "bb" 'ivy-switch-buffer
   "bl" 'dired
   "bd" 'kill-buffer
   "bk" 'kill-this-buffer
   "bD" 'kill-other-buffers
   "bn" 'next-buffer
   "bp" 'previous-buffer
   "eb" 'eval-buffer
   "er" 'eval-region
   "fs" 'save-buffer
   "fo" 'open-org-file
   "fc" 'open-calendar-file
   "ff" 'counsel-find-file
   "fr" 'counsel-recentf
   "fed" 'open-config-file
   "feR" 'reload-config-file
   "sg" 'counsel-git-grep
   "tl" 'toggle-truncate-lines
   "wc" 'evil-window-delete
   "ww" 'ace-window
   "wo" 'delete-other-windows
   "wj" 'evil-window-down
   "wk" 'evil-window-up
   "wh" 'evil-window-left
   "wl" 'evil-window-right
   "wv" 'evil-window-vsplit
   "ws" 'evil-window-split)
  (global-evil-leader-mode))
(use-package evil-surround
  :ensure t
  :config
  (global-evil-surround-mode))

Expand Region

(use-package expand-region
  :ensure t
  :bind ("C-=" . er/expand-region))

FlyCheck

(use-package flycheck
  :ensure t
  :diminish flycheck-mode
  :config
  (add-hook 'prog-mode-hook 'flycheck-mode)
  (setq-default flycheck-disabled-checker 'javascript-jshint)
  (setq-default flycheck-disabled-checker 'json-jsonlist)
  (setq-default flycheck-disabled-checker 'javascript-eslint)
  (setq-default flycheck-javascript-eslint-executable "eslint-project-relative")
  (flycheck-add-mode 'javascript-eslint 'web-mode)

  (defun my/use-eslint-from-node-modules ()
    (let* ((root (locate-dominating-file
    (or (buffer-file-name) default-directory)
      "node_modules"))
      (eslint (and root
      (expand-file-name "node_modules/eslint/bin/eslint.js"
        root))))
      (when (and eslint (file-executable-p eslint))
    (setq-local flycheck-javascript-eslint-executable eslint))))

  (add-hook 'flycheck-mode-hook #'my/use-eslint-from-node-modules)
  ;;; (with-eval-after-load 'flycheck
  ;;;  (advice-add 'flycheck-eslint-config-exists-p :override (lambda() t))) 

)

General

(setq-default indent-tabs-mode nil)
(global-set-key (kbd "<f5>") 'revert-buffer)
(global-set-key (kbd "<f12>") 'ansi-term)
(setq backup-directory-alist '(("." . "~/.emacs.d/backups")))
(global-set-key (kbd "s-p") 'counsel-M-x)
(add-hook 'dired-mode-hook
 (lambda ()
  (define-key dired-mode-map (kbd "^")
    (lambda () (interactive) (find-alternate-file "..")))
  ; was dired-up-directory
 ))

Helper Functions

;; OSX fix for eslint lookup
(use-package exec-path-from-shell
  :ensure t
  :config
  (when (memq window-system '(mac ns))
    (exec-path-from-shell-initialize)))

(defun init-install()
  (setq use-package-always-ensure t)
  reload-config-file())

(defun neotree-find-project-root()
  (interactive)
  (if (neo-global--window-exists-p)
      (neotree-hide)
    (let ((origin-buffer-file-name (buffer-file-name)))
      (neotree-find (projectile-project-root))
      (neotree-find origin-buffer-file-name))))

(defun reload-config-file()
  (interactive)
  (org-babel-load-file "~/.emacs.d/org-init.org"))

(defun open-config-file()
  (interactive)
  (find-file "~/.emacs.d/org-init.org"))

(defun open-org-file()
  (interactive)
  (find-file "~/Dropbox/notes/gtd.org"))

(defun open-calendar-file()
  (interactive)
  (find-file "~/Dropbox/notes/calendar.org"))

(defun kill-other-buffers (&optional arg)
  "Kill all other buffers.
If the universal prefix argument is used then will the windows too."
  (interactive "P")
  (when (yes-or-no-p (format "Killing all buffers except \"%s\"? "
                             (buffer-name)))
    (mapc 'kill-buffer (delq (current-buffer) (buffer-list)))
    (when (equal '(4) arg) (delete-other-windows))
    (message "Buffers deleted!")))

Ivy/Swiper

(use-package counsel
  :ensure t
  :diminish ivy-mode
  :config
  (ivy-mode 1)
  (setq ivy-use-virtual-buffers t)
  (setq ivy-re-builders-alist
   '((t . ivy--regex-ignore-order)))
  :bind
  ("s-f" . swiper))

Code

Our favourite languages!

C#

(use-package omnisharp
  :ensure t
  :config
  (add-hook 'csharp-mode-hook 'omnisharp-mode))

Javascript

Everybody uses JSON now, this make things look very pretty

(use-package json-mode
  :ensure t)

NPM mode lets us run our npm scripts directly from emacs

(use-package npm-mode
  :ensure t)
;; (use-package js2-mode
;;  :ensure t
;;  :diminish js2-mode
;;  :config
;;  (setq js2-basic-offset 2)
;;  (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
;;  (evil-leader/set-key-for-mode 'js2-mode
;;    "mf" 'tide-jump-to-definition
;;    "mb" 'tide-jump-back)
;;)

RJSX mode inherits js2-mode and supports jsx well. In my experience it’s better than js2-jsx-mode, so I use it instead. We set basic offsets and also unmap vim C-d in insert mode, so that we can use the nice tag completion We also integrate with Tide here, so that we can jump back and forth across definitions

(use-package rjsx-mode
  :ensure t
  :config
  (evil-leader/set-key-for-mode 'rjsx-mode
    "mf" 'tide-jump-to-definition
    "mb" 'tide-jump-back)
  (setq js2-basic-offset 2)
  (define-key evil-insert-state-map (kbd "C-d") nil)
  (add-to-list 'auto-mode-alist '("\\.js\\'" . rjsx-mode))
)

Bread and butter web-mode. Highlighting for all things html/css

(use-package web-mode
  :ensure t
  :config
  (defun my-web-mode-hook ()
    "Hooks for Web mode. Adjust indents"
    (setq web-mode-markup-indent-offset 2)
    (setq web-mode-attr-indent-offset 2)
    (setq web-mode-css-indent-offset 2)
    (setq web-mode-code-indent-offset 2)
    (setq css-indent-offset 2))
  (add-hook 'web-mode-hook  'my-web-mode-hook))

Tide mode utilises Microsoft’s excellent typescript tooling. Tide mode provides excellent code completion, formatting and syntax checking.

(use-package tide
  :ensure t
  :config
  (defun setup-tide-mode ()
    (interactive)
    (tide-setup)
    (flycheck-mode +1)
    (setq flycheck-check-syntax-automatically '(save mode-enabled))
    (eldoc-mode +1)
    (tide-hl-identifier-mode +1)
    (tide-setup)
    (tide-hl-identifier-mode +1)
   )
  (add-hook 'js2-mode-hook  #'setup-tide-mode)
)

Rust

(use-package rust-mode
  :ensure t
  :mode ("\\.rs\\'" . rust-mode))

Let flycheck hook into rust tooling

(use-package flycheck-rust
  :ensure t
  :config
  (add-hook 'flycheck-mode-hook #'flycheck-rust-setup))

Autocompletion for rust. I love how new languages provide tooling like this that are editor agnostic.

(use-package racer
  :ensure t
  :config
  (evil-define-key 'insert rust-mode-map
    (kbd "TAB") 'company-indent-or-complete-common)
  (add-hook 'rust-mode-hook #'racer-mode)
  (add-hook 'racer-mode-hook #'eldoc-mode))

Cargo lets us build, test and run our rust applications from within emacs. Super useful when developing

(use-package cargo
  :ensure t
  :config
  (add-hook 'rust-mode-hook 'cargo-minor-mode)
  (evil-leader/set-key-for-mode 'rust-mode
    "mb" 'cargo-process-build
    "mr" 'cargo-process-run
    "mt" 'cargo-process-test))

CSS

(setq css-indent-offset 2)

Yaml

Let’s get all our yamls in order

(use-package yaml-mode
  :ensure t
  :mode ("\\.yml\\'" . yaml-mode)
)

Magit

Magit is quite magical. I’m a huge fan of shelling out to command line when possible, but magit is a lot more intuitive, helpful and efficient. Combined with evil-magit and this is my favourite way of doing version control.

(use-package magit
  :ensure t
  :commands magit-status
  :init
  (use-package evil-magit
    :ensure t)
  (evil-leader/set-key
   "gs" 'magit-status))

Markdown

I try to use org files where possible, but markdown is super useful sometimes for projects. You can install live export tools as well, but I tend not to.

(use-package markdown-mode
  :ensure t
  :commands (markdown-mode))

NeoTree

We need an evil tree! Coupled with some major mode evil bindings and we’re in action

(use-package neotree
  :ensure t
  :config
  (evil-define-key 'normal neotree-mode-map 
    (kbd "TAB") 'neotree-enter
    "H" 'neotree-hidden-file-toggle
    "q" 'neotree-hide
    (kbd "RET") 'neotree-enter)

  (evil-leader/set-key-for-mode 'neotree-mode 
    "mo" 'neotree-open-file-in-system-application
    "md" 'neotree-delete-node
    "mr" 'neotree-rename-node
    "mc" 'neotree-create-node)

  (setq neo-theme 'nerd)
  (setq neo-window-fixed-size nil)
  (setq neo-smart-open t))
  (setq neo-window-width 40)
  (setq neo-default-system-application "open")

Org

Org mode is an extremely productive way of organising your text files. I have org mode setup in basically a few files:

  • GTD.org
  • Calendar.org

We use org-capture to easily capture events, ideas and todo items without context switching from what I’m doing. I also use gcal.el to organise and synchronise with my google calendar. I generally will create an event in google calendar, or from within emacs (and sync). Then I’ll create a link from my calendar.org file to my gtd.org file with a TODO item against it and the schedule.

A better way might be to just use org-agenda and use the calendar file as well, but I’ll probably experiment with it a little before doing that.

(require 'org-agenda)
(define-key org-agenda-mode-map "c" 'org-agenda-columns)
(setq org-directory "~/Dropbox/notes")
(setq org-default-notes-file (concat org-directory "/gtd.org"))
(define-key global-map "\C-cc" 'org-capture)
(setq org-global-properties '(("Effort_ALL". "0 0:10 0:20 0:30 1:00 2:00 3:00 4:00 6:00 8:00")))
(setq org-columns-default-format '"%25ITEM %10Effort(Est){+} %TODO %TAGS")
(org-agenda-files '"~/Dropbox/notes/gtd.org")
(setq org-tag-alist '((:startgroup . nil)
                      (:endgroup . nil)
                      ("WORK" . ?w) ("HOME" . ?h) ("COMPUTER" . ?l) ("GOALS" . ?g) ("READING" . ?r) ("PROJECT" . ?p)))
(setq org-agenda-custom-commands
      '(("g" . "GTD contexts")
        ("gw" "Work" tags-todo "WORK")
        ("gc" "Computer" tags-todo "COMPUTER")
        ("gg" "Goals" tags-todo "GOALS")
        ("gh" "Home" tags-todo "HOME")
        ("gt" "Tasks" tags-todo "TASKS")
        ("G" "GTD Block Agenda"
         ((tags-todo "WORK")
          (tags-todo "COMPUTER")
          (tags-todo "GOALS")
          (tags-todo "TASKS"))
         nil                      ;; i.e., no local settings
         )))
(evil-leader/set-key
    "oc" 'org-capture
    "oa" 'org-agenda
    "os" 'org-schedule)

(evil-leader/set-key-for-mode 'org-mode
    "mt" 'org-set-tags-command
    "md" 'org-deadline
    "me" 'org-set-effort
    "mn" 'org-narrow-to-subtree
    "mr" 'org-refile
    "mss" 'org-store-link
    "msp" 'org-insert-last-stored-link
    "mw" 'widen)

(evil-define-key 'normal org-mode-map
  ">" 'org-shiftmetaright
  "<" 'org-shiftmetaleft
  "c" 'org-toggle-checkbox
  "t" 'org-todo
  "gs" 'org-goto)

(evil-leader/set-key-for-mode 'org-capture-mode 
  "c" 'org-capture-finalize
  "k" 'org-capture-kill)

(setq org-capture-templates
      '(("t" "Todo" entry (file+headline "~/Dropbox/notes/gtd.org" "Inbox")
             "* TODO %?\n%T" :prepend T)
        ("e" "Event" entry (file "~/Dropbox/notes/calendar.org")
             "* %?\n%T" :prepend T)
        ("i" "Ideas" entry (file+headline "~/Dropbox/notes/gtd.org" "Ideas")
             "* %?\n%T" :prepend T)
        ("g" "Goals" entry (file+headline "~/Dropbox/notes/gtd.org" "Goals")
             "* %?\n%T" :prepend T)
        ("j" "Journal" entry (file+datetree "~/Dropbox/notes/journal.org")
             "* %?\nEntered on %U\n  %i\n  %a")))

Just give me nice bullet points!

(use-package org-bullets
  :ensure t
  :config
  (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))

Create speed commands for editing org files

(setq org-use-speed-commands t)

Setup google calendar sync. I keep a secrets file in my Dropbox that I load here as well. Secrets file contains a few variables for secrets and client tokens

(use-package org-gcal
  :ensure t
  :config 
  (load-file "~/Dropbox/Keys/gcal.el")
  (setq org-gcal-client-id my/google-secrets-client
      org-gcal-client-secret my/google-secrets-secret
      org-gcal-file-alist '(("clint.ryan3@gmail.com" .  "~/Dropbox/notes/calendar.org")))
)

Projectile

Projectile is awesome for searching and handling projects. I ignore node_modules naturally and also have some evil bindings for easily accessing projects using leader keys

(use-package projectile
  :ensure t
  :diminish projectile-mode
  :commands (projectile-find-file projectile-switch-project)
  :init
  (evil-leader/set-key
    "pf" 'projectile-find-file
    "pp" 'projectile-switch-project
    "pb" 'projectile-switch-buffer
    "ft" 'neotree-toggle
    "pt" 'neotree-find-project-root)
  :config
  (setq projectile-completion-system 'ivy)
  (add-to-list 'projectile-globally-ignored-directories "node_modules")
  (projectile-global-mode))

Smart Parenthesis

Hightlight parens smartly :P

(use-package smartparens
  :ensure t)

Snippets

YaSnippet allows us to insert snippets easily. We disable the <TAB> completion because we use that for other things, but we can insert snippets still using leader bindings.

(use-package yasnippet
  :ensure t
  :diminish yas-minor-mode
  :config
  (define-key yas-minor-mode-map (kbd "<tab>") nil)
  (define-key yas-minor-mode-map (kbd "TAB") nil)
  (evil-leader/set-key
   "is" 'yas-insert-snippet
   "in" 'yas-new-snippet)
  (yas-global-mode 1))

Which Key

Awesome package for key discovery!

(use-package which-key
  :ensure t
  :config
  (which-key-mode))