EOS: Development Module

Table of Contents

(provide 'eos-develop)

EOS Development Module Configuration

This contains the configuration for elisp programming

Remove some back-ends from vc-mode, no need to check all these things, I use magit for everything anyway:

(setq vc-handled-backends '(git svn))

I need to hide the lighter for subword mode:

(use-package subword
  :diminish subword-mode)
(use-package log4j-mode
  :ensure t
  :init
  (add-hook #'log4j-mode-hook #'view-mode)
  (add-hook #'log4j-mode-hook #'read-only-mode)
  (add-hook #'log4j-mode-hook 'eos/turn-on-hl-line))

Highlight idle things, but only in certain modes

(use-package idle-highlight-mode
  :ensure t
  :init
  (add-hook 'java-mode-hook #'idle-highlight-mode)
  (add-hook 'emacs-lisp-mode-hook #'idle-highlight-mode)
  (add-hook 'clojure-lisp-mode-hook #'idle-highlight-mode)
  :config
  (setq idle-highlight-idle-time 1.5))

Hide-show is kind of like Vim's folding, but manually done right now.

I'm in the process of trying out Origami as a replacement, since it's a bit easier on the brain and has nicer functions (supposedly), however, Origami is much slower than hideshow for large buffers.

(use-package hideshow
  :bind (("C-c TAB" . hs-toggle-hiding)
         ("C-\\" . hs-toggle-hiding)
         ("M-\\" . eos/hs-fold-show-only-methods)
         ("M-+" . hs-show-all))
  :init
  (add-hook #'prog-mode-hook #'hs-minor-mode)
  (when (fboundp 'define-fringe-bitmap)
    (define-fringe-bitmap 'hs-marker [16 48 112 240 112 48 16] nil nil 'center))
  (defface hs-face '((t (:background "#ff8")))
    "Face to hightlight the ... area of hidden regions"
    :group 'hideshow)
  (defface hs-fringe-face '((t (:foreground "#888")))
    "Face used to highlight the fringe on folded regions"
    :group 'hideshow)
  (setq hs-set-up-overlay
        (lambda (ov)
          (when (eq 'code (overlay-get ov 'hs))
            (let ((marker-string "*")
                  (display-string (format " ... " (count-lines (overlay-start ov)
                                                               (overlay-end ov)))))
              (put-text-property 0 1 'display
                                 (list 'right-fringe 'hs-marker 'hs-fringe-face)
                                 marker-string)
              (put-text-property 0 (length display-string)
                                 'face 'hs-face display-string)
              (overlay-put ov 'before-string marker-string)
              (overlay-put ov 'display display-string))))
        hs-isearch-open t)
  :diminish hs-minor-mode
  :config
  (defvar hs-special-modes-alist
    (mapcar 'purecopy
            '((c-mode "{" "}" "/[*/]" nil nil)
              (c++-mode "{" "}" "/[*/]" nil nil)
              (bibtex-mode ("@\\S(*\\(\\s(\\)" 1))
              (java-mode "{" "}" "/[*/]" nil nil)
              (js-mode "{" "}" "/[*/]" nil)
              (javascript-mode  "{" "}" "/[*/]" nil))))

  (defvar eos/hs-level 2
    "Default level to hide at when calling
    `eos/fold-show-only-methods'. This is buffers may set this to
    be buffer-local.")

  (setq eos/hs-fold-show-only-methods-active-p nil)
  (defun eos/hs-fold-show-only-methods ()
    "Toggle between hiding all methods using `eos/hs-level' or
showing them."
    (interactive)
    (save-excursion
      (if eos/hs-fold-show-only-methods-active-p
          (progn
            (hs-show-all)
            (setq-local eos/hs-fold-show-only-methods-active-p nil))
        (progn
          (goto-char (point-min))
          (hs-hide-level eos/hs-level)
          (setq-local eos/hs-fold-show-only-methods-active-p t))))))

Bring up the compilation buffer with C-x c

(defun eos/last-compilation-buffer ()
  "Display last compilation buffer in current window."
  (interactive)
  (if (buffer-live-p compilation-last-buffer)
      (set-window-buffer (get-buffer-window) compilation-last-buffer)
    (message "Last compilation buffer is killed.")))

(global-set-key (kbd "C-x c") #'eos/last-compilation-buffer)

Also, you don't need to prompt me about saving files for compilation, just do it.

(setq compilation-ask-about-save nil)

Need to be able to have buffers shared between machines with Syncthing

(global-auto-revert-mode t)

Uses M-n and M-p to jump between the same variable in multiple places

(use-package smartscan
  :ensure t
  :init (add-hook #'prog-mode-hook #'smartscan-mode)
  :config
  (bind-key "M-'" #'other-window smartscan-map)
  (setq smartscan-symbol-selector "symbol"))

You'd be surprised how often you need to toggle boolean states in programming. I was surprised by how often I use this.

(use-package bool-flip
  :ensure t
  :bind ("C-c C-b" . bool-flip-do-flip))

Navigating programming modes

I like using C-c C-p and C-c C-n to navigate by headlines in org-mode, so I'd also like to navigate by function declaration in all development modes with the same thing.

(defun eos/previous-function ()
  (interactive)
  (beginning-of-defun))

(defun eos/next-function ()
  (interactive)
  (beginning-of-defun -1))

(bind-key "C-c C-p" 'eos/previous-function prog-mode-map)
(bind-key "C-c C-n" 'eos/next-function prog-mode-map)

;; cc-mode likes to have its own things, so bind them there too
;;(bind-key "C-c C-p" 'eos/previous-function c-mode-base-map)
;;(bind-key "C-c C-n" 'eos/next-function c-mode-base-map)

There's also a mode called navi-mode / outshine that aims to bring some of org-mode into development, so let's try that out.

(defvar outline-minor-mode-prefix "\M-#")

(use-package navi-mode
  :ensure t
  :init
  (require 'outshine)
  (add-hook 'outline-minor-mode-hook 'outshine-hook-function)
  (add-hook 'emacs-lisp-mode-hook 'outline-minor-mode)
  (add-hook 'clojure-mode-hook 'outline-minor-mode))

Indentation

Everyone has a different indentation they like, so let's use dtrt-indent (dtrt = do the right thing) to try and figure out the best indentation. I don't enable it automatically though, I invoke it manually.

(use-package dtrt-indent
  :ensure t
  :diminish t
  :config
  (setq dtrt-indent-active-mode-line-info ""))

Additional highlighting

There is also some additional configuration that we may want to enable, let's do that with additional highlighting modes.

First, highlight numbers in a "special" way, so they stick out:

(use-package highlight-numbers
  :ensure t
  :init
  (add-hook 'prog-mode-hook #'highlight-numbers-mode))

Also highlight quoted symbols in a nice way.

(use-package highlight-quoted
  :ensure t
  :init
  (add-hook 'prog-mode-hook #'highlight-quoted-mode))

Also highlight pre-defined symbols in elisp

(use-package highlight-defined
  :ensure t
  :init
  (add-hook 'emacs-lisp-hook #'highlight-defined-mode))

Highlight operators (like & and ; in C-like modes)

(use-package highlight-operators
  :ensure t
  :init
  (add-hook 'c-mode-common-hook #'highlight-operators-mode))

Finally, let's highlight escape sequences in a better way also

(use-package highlight-escape-sequences
  :ensure t
  :init
  (add-hook 'prog-mode-hook #'hes-mode))

Semantic Editing

First, use a development version of cedet if applicable, I download the latest snapshot from http://www.randomsample.de/cedet-snapshots/ and extract it in ~/src/elisp. Don't forget to run make in it!

And then things to set up semantic mode

;; Use the full Java 1.5 grammar to parse Java files
(autoload 'wisent-java-default-setup "semantic/wisent/java"
  "Hook run to setup Semantic in `java-mode'." nil nil)

(defun eos/setup-semantic-mode ()
  (interactive)
  (use-package semantic
    :init
    (require 'semantic/wisent)
    (require 'semantic/wisent/java)
    (require 'semantic/wisent/java-wy)
    (require 'semantic/ia)
    (setq semantic-default-submodes
          '(;; Perform semantic actions during idle time
            global-semantic-idle-scheduler-mode
            ;; Use a database of parsed tags
            global-semanticdb-minor-mode
            ;; Decorate buffers with additional semantic information
            global-semantic-decoration-mode
            ;; Highlight the name of the function you're currently in
            global-semantic-highlight-func-mode
            ;; Generate a summary of the current tag when idle
            global-semantic-idle-summary-mode
            ;; Switch to recently changed tags with `semantic-mrub-switch-tags',
            ;; or `C-x B'
            global-semantic-mru-bookmark-mode))
    (semantic-mode t)
    ;; Fixing a bug in semantic, see #22287
    (defun semanticdb-save-all-db-idle ()
      "Save all semantic tag databases from idle time.
Exit the save between databases if there is user input."
      (semantic-safe "Auto-DB Save: %S"
        ;; FIXME: Use `while-no-input'?
        (save-mark-and-excursion ;; <-- added line
         (semantic-exit-on-input 'semanticdb-idle-save
           (mapc (lambda (db)
                   (semantic-throw-on-input 'semanticdb-idle-save)
                   (semanticdb-save-db db t))
                 semanticdb-database-list)))))))

(add-hook 'c-mode-hook #'eos/setup-semantic-mode)
(add-hook 'java-mode-hook #'eos/setup-semantic-mode)
(add-hook 'emacs-lisp-mode-hook #'semantic-mode)

Emacs' Built In Electric Modes (pair/indent/layout)

Emacs finally has better support for automatically doing things like indentation and pairing parentheses. So, let's enable (some) of that

How about some auto-indentation:

(electric-indent-mode 1)

;; Ignore electric indentation for python and yaml
(defun electric-indent-ignore-mode (char)
  "Ignore electric indentation for python-mode"
  (if (or (equal major-mode 'python-mode)
          (equal major-mode 'yaml-mode))
      'no-indent
    nil))
(add-hook 'electric-indent-functions 'electric-indent-ignore-mode)

Finally, perhaps we want some automatic layout:

(electric-layout-mode 1)

Programming Mode Hooks

In programming modes, make sure things like FIXME and TODO are highlighted so they stand out:

(defun eos/add-watchwords ()
  "Highlight FIXME, TODO, and NOCOMMIT in code TODO"
  (font-lock-add-keywords
   nil '(("\\<\\(TODO\\(?:(.*)\\)?:?\\)\\>"  1 'warning prepend)
         ("\\<\\(FIXME\\(?:(.*)\\)?:?\\)\\>" 1 'error prepend)
         ("\\<\\(NOCOMMIT\\(?:(.*)\\)?:?\\)\\>"  1 'error prepend))))

(add-hook 'prog-mode-hook #'eos/add-watchwords)

Paren matching with electric-pair-mode and Smartparens

So, I vacillate between using electric-pair-mode and smartparens, ELP because it's built-in to Emacs and much faster, and Smartparens because it supports a lot of the paredit-like things that I love in lisp, but everywhere.

First, stuff for automatically inserting pairs of characters with electric-pair-mode:

(electric-pair-mode -1)
(setq electric-pair-preserve-balance t
      electric-pair-delete-adjacent-pairs t
      electric-pair-open-newline-between-pairs nil)
(show-paren-mode 1)

Now, the smartparens configuration:

(use-package smartparens
  :ensure t
  :diminish smartparens-mode
  :init
  (electric-pair-mode -1)
  (require 'smartparens-config)
  ;; Turn on smartparens in the minibuffer
  (add-hook 'minibuffer-setup-hook 'turn-on-smartparens-strict-mode)
  (define-key smartparens-mode-map (kbd "C-M-f") 'sp-forward-sexp)
  (define-key smartparens-mode-map (kbd "C-M-b") 'sp-backward-sexp)

  (define-key smartparens-mode-map (kbd "C-M-<right>") 'sp-forward-sexp)
  (define-key smartparens-mode-map (kbd "C-M-<left>") 'sp-backward-sexp)
  (define-key smartparens-mode-map (kbd "M-F") 'sp-forward-sexp)
  (define-key smartparens-mode-map (kbd "M-B") 'sp-backward-sexp)

  (define-key smartparens-mode-map (kbd "C-M-d") 'sp-down-sexp)
  (define-key smartparens-mode-map (kbd "C-M-a") 'sp-backward-down-sexp)
  (define-key smartparens-mode-map (kbd "C-S-d") 'sp-beginning-of-sexp)
  (define-key smartparens-mode-map (kbd "C-S-a") 'sp-end-of-sexp)

  (define-key smartparens-mode-map (kbd "C-M-e") 'sp-up-sexp)
  (define-key smartparens-mode-map (kbd "C-M-u") 'sp-backward-up-sexp)
  (define-key smartparens-mode-map (kbd "C-M-t") 'sp-transpose-sexp)

  (define-key smartparens-mode-map (kbd "C-M-n") 'sp-next-sexp)
  (define-key smartparens-mode-map (kbd "C-M-p") 'sp-previous-sexp)

  (define-key smartparens-mode-map (kbd "C-M-k") 'sp-kill-sexp)
  (define-key smartparens-mode-map (kbd "C-M-w") 'sp-copy-sexp)

  (define-key smartparens-mode-map (kbd "M-r") 'sp-unwrap-sexp)

  (define-key smartparens-mode-map (kbd "C-(") 'sp-forward-barf-sexp)
  (define-key smartparens-mode-map (kbd "C-)") 'sp-forward-slurp-sexp)
  (define-key smartparens-mode-map (kbd "M-(") 'sp-forward-barf-sexp)
  (define-key smartparens-mode-map (kbd "M-)") 'sp-forward-slurp-sexp)

  (define-key smartparens-mode-map (kbd "M-D") 'sp-splice-sexp)

  ;; Handle backspace in c-like modes better for smartparens
  (bind-key [remap c-electric-backspace]
            'sp-backward-delete-char smartparens-strict-mode-map)

  ;; ;; Bind ";" to sp-comment in elisp
  (bind-key ";" 'sp-comment emacs-lisp-mode-map)

  (defun sp--org-skip-asterisk (ms mb me)
    (or (and (= (line-beginning-position) mb)
             (eq 32 (char-after (1+ mb))))
        (and (= (1+ (line-beginning-position)) me)
             (eq 32 (char-after me)))))

  ;; Org-mode
  (sp-with-modes
      'org-mode
    (sp-local-pair "*" "*"
                   :actions '(insert wrap)
                   :unless '(sp-point-after-word-p sp-point-at-bol-p)
                   :wrap "C-*" :skip-match 'sp--org-skip-asterisk)
    (sp-local-pair "_" "_" :unless '(sp-point-after-word-p) :wrap "C-_")
    (sp-local-pair "/" "/" :unless '(sp-point-after-word-p)
                   :post-handlers '(("[d1]" "SPC")))
    (sp-local-pair "~" "~" :unless '(sp-point-after-word-p)
                   :post-handlers '(("[d1]" "SPC")))
    (sp-local-pair "=" "=" :unless '(sp-point-after-word-p)
                   :post-handlers '(("[d1]" "SPC")))
    (sp-local-pair "«" "»"))

    ;;; Java
  (sp-with-modes
      '(java-mode c++-mode)
    (sp-local-pair "{" nil :post-handlers '(("||\n[i]" "RET")))
    (sp-local-pair "/*" "*/" :post-handlers '((" | " "SPC")
                                              ("* ||\n[i]" "RET"))))

  (smartparens-global-strict-mode 1))

Paredit everywhere

Paredit is fantastic for lisp-like languages, and it would be great if it were available everywhere (a subset of it, anyway), thankfully there is paredit-everywhere.

Note that I need to unbind M-s because it's the new isearch prefix in 25.1, so I set it to nil in the map.

(eval-after-load 'paredit-everywhere
  '(define-key paredit-everywhere-mode-map (kbd "M-s") nil))
(use-package paredit-everywhere
  :ensure t
  :disabled t
  :init (add-hook 'prog-mode-hook 'paredit-everywhere-mode))

Documentation with helm-dash

Dash is a documentation tool that has nice offline documentation. This is great for plane trips or just when the internet goes out.

Make sure that you do M-x helm-dash-install-docset to install the correct docset(s).

I usually install Java_SE8, Emacs Lisp, and ElasticSearch. Then I use C-c D ('D' for Documentation) to activate it.

(use-package helm-dash
  :ensure t
  :bind (("C-c D" . helm-dash))
  :init
  (setq helm-dash-common-docsets '("ElasticSearch")
        helm-dash-min-length 2)
  :config
  (defun eos/use-java-docset ()
    (setq-local helm-dash-docsets '("Java")))
  (defun eos/use-elisp-docset ()
    (setq-local helm-dash-docsets '("Emacs Lisp")))
  (add-hook 'java-mode-hook #'eos/use-java-docset)
  (add-hook 'emacs-lisp-mode-hook #'eos/use-elisp-docset))

Flycheck - Syntax Checking On The Fly

Pretty minimally configured, but awesome tool for most dynamic languages.

(when (fboundp 'define-fringe-bitmap)
  (define-fringe-bitmap 'flycheck-fringe-bitmap-double-arrow
    [0 0 0 0 0 4 12 28 60 124 252 124 60 28 12 4 0 0 0 0]))

(use-package flycheck
  :ensure t
  :defer 5
  :bind (("M-g M-n" . flycheck-next-error)
         ("M-g M-p" . flycheck-previous-error)
         ("M-g M-=" . flycheck-list-errors))
  :init
  (require 'flycheck)
  (global-flycheck-mode)
  (setq flycheck-indication-mode 'right-fringe
        flycheck-check-syntax-automatically '(save mode-enabled))
  :diminish flycheck-mode
  :config
  (progn
    (setq-default flycheck-disabled-checkers
                  '(emacs-lisp-checkdoc json-jsonlint json-python-json))
    (use-package flycheck-pos-tip
      :ensure t
      :init
      (flycheck-pos-tip-mode)
      (setq flycheck-pos-tip-timeout 10
            flycheck-display-errors-delay 0.5))
    (use-package helm-flycheck
      :ensure t
      :init (define-key flycheck-mode-map (kbd "C-c ! h") 'helm-flycheck))
    (use-package flycheck-haskell
      :ensure t
      :init (add-hook 'flycheck-mode-hook #'flycheck-haskell-setup))))

Development snippets with yasnippet

I have recently be using skeletons, but yasnippet is useful also, so I'll try it again now after a while.

(use-package yasnippet
  :ensure t
  :bind (("M-=" . yas-insert-snippet))
  :diminish yas-minor-mode
  :init
  (yas-global-mode 1)
  :config
  (add-to-list 'yas-snippet-dirs "~/.emacs.d/site-lisp/snippets")
  (yas-reload-all))

Multi-compile for different compilations I run

Running ES is great, but I'm an Elasticsearch developer, so I need to be able to run tests and all that pretty easily.

(use-package multi-compile
  :ensure t
  :commands multi-compile-run
  :bind ("<f6>" . multi-compile-run)
  :init
  (defun eshell/comp ()
    "Run multi-compile from the directory you are currently located in"
    (multi-compile-run))
  :config
  (require 's)
  (setq multi-compile-completion-system 'helm
        multi-compile-alist
        '(;; Elasticsearch-specific compilation commands
          ((s-contains? "es/elasticsearch" default-directory)
           . (("ES core compile"
               "gradle :core:compileJava :core:compileTestJava --console=plain"
               "~/es/elasticsearch")
              ("ES everything compile"
               "gradle compileJava compileTestJava precommit --console=plain"
               "~/es/elasticsearch")
              ("ES core unit test"
               "gradle :core:test --console=plain"
               "~/es/elasticsearch")
              ("ES core integ test"
               "gradle :core:integTest --console=plain"
               "~/es/elasticsearch")
              ("ES core check"
               "gradle :core:check --console=plain"
               "~/es/elasticsearch")
              ("ES documentation tests"
               "gradle :docs:check --console=plain"
               "~/es/elasticsearch")
              ("ES REST tests"
               "gradle :distribution:integ-test-zip:integTest -Dtests.class=\"org.elasticsearch.test.rest.*Yaml*IT\" --console=plain"
               "~/es/elasticsearch")
              ("ES precommit"
               "gradle precommit --console=plain"
               "~/es/elasticsearch")
              ("ES qa check"
               "gradle check --console=plain"
               "~/es/elasticsearch/qa")
              ("ES check all"
               "gradle check --console=plain"
               "~/es/elasticsearch")))
          ;; X-pack specific compilation commands
          ((s-contains? "elasticsearch-extra/x-pack" default-directory)
           . (("x-pack compile" .
               "gradle :x-pack:elasticsearch:x-pack:compileJava :x-pack:elasticsearch:x-pack:compileTestJava --console=plain")
              ("x-pack everything compile" .
               "gradle compileJava compileTestJava precommit --console=plain")
              ("x-pack precommit" .
               "gradle precommit --console=plain")
              ("x-pack check"
               "gradle check --console=plain"
               "~/es/elasticsearch-extra/x-pack-elasticsearch")))
          ;; Java compilation commands
          (java-mode
           . (("ant compile" .
               "ant compile compile-test")
              ("mvn compile" .
               "mvn compile test-compile")
              ("gradle compile" .
               "gradle compileJava compileTestJava --console=plain"))))))

Also, we need compilation-mode to truncate lines immediately

(add-hook 'compilation-mode-hook #'toggle-truncate-lines)

Determining the test at point and copying the syntax for running it

(defun eos/test-at-point ()
  (interactive)
  (if (not (eq major-mode 'java-mode))
      (message "Buffer is not currently in java-mode")
    "foo"))

Emacs Lisp (Elisp)

This contains the configuration for elisp programming

First, turn on paredit and eldoc everywhere it's useful:

(use-package paredit
  :ensure t
  :commands paredit-mode
  :diminish "()"
  :init
  (add-hook 'emacs-lisp-mode-hook #'paredit-mode)
  (add-hook 'ielm-mode-hook #'paredit-mode)
  :config
  (bind-key "M-)" #'paredit-forward-slurp-sexp paredit-mode-map)
  (bind-key "C-(" #'paredit-forward-barf-sexp paredit-mode-map)
  (bind-key "C-)" #'paredit-forward-slurp-sexp paredit-mode-map)
  (bind-key ")" #'paredit-close-parenthesis paredit-mode-map)
  (bind-key "M-\"" #'my/other-window-backwards paredit-mode-map))
(use-package eldoc
  :diminish eldoc-mode
  :init
  (add-hook 'emacs-lisp-mode-hook #'eldoc-mode)
  (add-hook 'ielm-mode-hook #'eldoc-mode)
  (add-hook 'lisp-interaction-mode-hook #'eldoc-mode)
  :config
  (setq eldoc-idle-delay 0.1))

Define some niceties for popping up an ielm buffer:

(defun ielm-other-window ()
  "Run ielm on other window"
  (interactive)
  (switch-to-buffer-other-window
   (get-buffer-create "*ielm*"))
  (call-interactively 'ielm))

(define-key emacs-lisp-mode-map (kbd "C-c C-z") 'ielm-other-window)
(define-key lisp-interaction-mode-map (kbd "C-c C-z") 'ielm-other-window)

Turn on elisp-slime-nav if available, so M-. works to jump to function definitions:

(use-package elisp-slime-nav
  :ensure t
  :diminish elisp-slime-nav-mode
  :init (add-hook 'emacs-lisp-mode-hook #'elisp-slime-nav-mode))

Some minor Elisp things borrowed from Steve Purcell's config.

(bind-key "M-:" #'pp-eval-expression)

(defun eos/eval-last-sexp-or-region (prefix)
 "Eval region from BEG to END if active, otherwise the last sexp."
 (interactive "P")
 (if (and (mark) (use-region-p))
 (eval-region (min (point) (mark)) (max (point) (mark)))
 (pp-eval-last-sexp prefix)))

(bind-key "C-x C-e" 'eos/eval-last-sexp-or-region emacs-lisp-mode-map)

(define-key lisp-mode-shared-map (kbd "RET") 'reindent-then-newline-and-indent)

Here's something that makes minibuffer evaluation a lot better, by pretti-fying the contents, and other such things. It's a package called "eval-expr".

(use-package eval-expr
  :ensure t
  :init
  (add-hook 'after-init-hook #'eval-expr-install))

Set up some things for developing Emacs itself:

(use-package debbugs
  :ensure t)

A couple of helpers for the minibuffer:

(add-hook 'eval-expression-minibuffer-setup-hook #'eldoc-mode)
(add-hook 'eval-expression-minibuffer-setup-hook #'paredit-mode)

Display the ugly ^L lines in Elisp files as actual lines

(use-package page-break-lines
  :ensure t
  :commands (turn-on-page-break-lines-mode)
  :diminish page-break-lines-mode
  :init
  (add-hook 'emacs-lisp-mode-hook #'turn-on-page-break-lines-mode))

Python

Some various python settings, including loading jedi if needed to set up keys, the custom hook only loads jedi when editing python files:

(use-package python
  :defer t
  :config
  (define-key python-mode-map (kbd "<backtab>") 'python-back-indent))

I'm using the virtualenvwrapper package for managing these

(use-package virtualenvwrapper
  :ensure t
  :defer t
  :init
  (progn
    (venv-initialize-interactive-shells)
    (venv-initialize-eshell)
    (setq venv-location (or (getenv "WORKON_HOME")
                            "~/.venvs"))))

Ruby

Using rbenv, set it up correctly when idle

(use-package rbenv
  :ensure t
  :defer 25
  :init
  ;; I don't really care about the active ruby in the modeline
  (setq rbenv-show-active-ruby-in-modeline nil)
  (global-rbenv-mode t))

Haskell

Use GHC for haskell mode, and turn on auto-complete and some doc/indent modes:

(defun eos/turn-off-flyspell ()
  (interactive)
  (flyspell-mode -1))

(use-package haskell-mode
  :ensure t
  :init
  (use-package intero
    :ensure t
    :init
    (add-hook 'haskell-mode-hook 'intero-mode))
  (add-hook 'haskell-mode-hook #'eos/turn-off-flyspell))

I tend to want to align things by regex (ie, =) a lot in Haskell, so bind C-c M-a to do it.

(global-set-key (kbd "C-c M-a") #'align-regexp)

PureScript

It's like Haskell, but for Javascript!

(use-package purescript-mode
  :ensure t
  :init
  (use-package psc-ide
    :ensure t
    :init
    (defun eos/setup-purescript ()
      (interactive)
      (flyspell-mode -1)
      (psc-ide-mode)
      (company-mode 1)
      (flycheck-mode 1)
      (turn-on-purescript-indentation))
    (add-hook 'purescript-mode-hook #'eos/setup-purescript)))

Javascript

I want indentation of 2 for json/js.

(setq-default js-indent-level 2)

Bleh javascript. js2-mode is better than nothing.

(use-package js2-mode
  :ensure t
  :mode "\\.js\\'"
  :config (js2-imenu-extras-setup))

There's tern also, but I leave it turned off by default, just installed

(use-package tern
  :ensure t)

Finally, use json-mode for JSON instead of js-mode

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

Shell scripting

Not really much here, other than telling shell-script-mode that .bats files are shell-scripts

(add-to-list 'auto-mode-alist '("\\.bats$" . shell-script-mode))

Let's make .zsh also be a shell script

(add-to-list 'auto-mode-alist '("\\.zsh$" . shell-script-mode))

Rust

I've been following Rust for a while now, and I'd like to contribute to it. So need to have all the development bits installed and set up.

(use-package rust-mode
  :ensure t
  :init
  (use-package toml-mode
    :ensure t))

And racer, for rust completion

(use-package racer
  :ensure t
  :init
  (use-package company-racer
    :ensure t
    :init
    (push 'company-racer company-backends))
  (add-hook 'rust-mode-hook #'racer-mode)
  (add-hook 'rust-mode-hook #'eldoc-mode)
  :config
  (setq racer-cmd (executable-find "racer")))

And support for flycheck and rust

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

Groovy

I tend to have to edit a lot of build.gradle files these days…

(use-package groovy-mode
  :ensure t)

Author: Lee Hinman

Created: 2017-08-21 Mon 14:28