Complete Computing Environment: Programming in Emacs

Table of Contents

Code is my creative outlet. I use it as a way to express myself, as a way to unwind my thoughts in to reality and as a way to build myself a future worth living. My code comes in many forms and serves many purpose. The act of programming, of writing code, is liberating, is freeing, despite the limitations and struggles of using a computer.

I spend a lot of time exploring and dabbling in my free time. I have a wealth of exploratory projects, things built on new ideas and new languages, play toys and future business ideas. These are singular acts of creation, my own children and creations, shared with the people around me as explanations and instructions to understanding my way of grokking the world. My tools should enable the creation of pet projects, the curation of their code, and the insurance of their completion, regardless of the language.

More than on personal projects, though, I spend time transforming the code others have written. This is the bulk of the code I write as my day job, transformations of existing code that is not my own and that I may not yet have the full understanding of. My editor should enable and embrace refactoring and extending existing code. It should make introspecting and exploring code bases easy and intuitive.

My projects are all version controlled using Git. Exploring the history of a project, gaining points of reference within codebases, these are core parts of my learning model in a new code base; who owns what, and how do they think? My tools should make it easy to answer these questions, and should allow me to manipulate the repository myself, be that rewriting history, or simply committing new code.

(provide 'cce-code-core)

Core Programming Environment Setup

There is some base-level tooling required for me to get my job done as a programmer, let's install those tools here:

  • git
rpm-install git

I only use line numbering when I'm programming, let's turn it on! I turn off eager loading and delay the rendering of this because for big files, because it can get really damn slow.

(setq linum-delay t
      linum-eager nil)
(add-hook 'prog-mode-hook 'linum-mode)

Semantic Mode is a neat built-in code parser with autocomplete, refactor and other cool bits.

(add-hook 'prog-mode-hook 'semantic-mode)

Install some one-off modes that auto-enable when we need them and need no configuration.

(install-pkgs '(jinja2-mode
                lua-mode
                json-mode
                puppet-mode
                scad-mode
                web-mode
                yaml-mode
                graphviz-dot-mode))

Aggressive Indent makes sure your code is always properly indented. Paired with DTRT, we end up with the ability to never actually have to care about our code indentation, as it should be.

(install-pkgs '(aggressive-indent))
(eval-after-load 'aggressive-indent-mode (lambda ()
                                           (diminish 'aggressive-indent-mode "⮕")))

(defun rrix/re-indent ()
  (unless (eq major-mode
              'python-mode)
    (aggressive-indent-mode)
    (local-set-key (kbd "RET") 'reindent-then-newline-and-indent)))
(add-hook 'prog-mode-hook 'rrix/re-indent)

Code exploration

Projectile

Projectile1 is one of those tools like Helm that some people will say is too heavy or big or bloated, but is incredibly well designed and full featured.

(require 'projectile)
(add-hook 'prog-mode-hook 'projectile-mode)
(diminish 'projectile-mode)

Projectile has some pretty nice functionality, which we expose via this Hydra, prefixed on C-x p, as a override to projectile's default C-x p prefix.

From here we can dive in to a live grep with a, find files with h, switch project using P, and other random crap.

(defhydra hydra-projectile-other-window (:color teal)
  "projectile-other-window"
  ("f"  projectile-find-file-other-window        "file")
  ("g"  projectile-find-file-dwim-other-window   "file dwim")
  ("d"  projectile-find-dir-other-window         "dir")
  ("b"  projectile-switch-to-buffer-other-window "buffer")
  ("q"  nil                                      "cancel" :color blue))

(defhydra hydra-projectile (global-map "C-x p" :color teal)
  "
     PROJECTILE: %(projectile-project-root)

     Find File            Search/Tags          Buffers                Cache
------------------------------------------------------------------------------------------
                      _a_: grep              _i_: Ibuffer           _c_: cache clear
                                           _b_: switch to buffer  _x_: remove known project
                      _o_: multi-occur       _K_: Kill all buffers  _X_: cleanup non-existing
  _r_: recent file                                               ^^^^_z_: cache current
  _d_: dir

"
  ("a"   projectile-grep)
  ("b"   projectile-switch-to-buffer)
  ("c"   projectile-invalidate-cache)
  ("d"   projecti
le-find-dir)
  ("f"   projectile-find-file)
  ("i"   projectile-ibuffer)
  ("j"   counsel-imenu)
  ("K"   projectile-kill-buffers)
  ("m"   projectile-multi-occur)
  ("o"   multi-occur)
  ("P"   projectile-switch-project "switch project")
  ("p"   projectile-switch-project)
  ("s"   projectile-switch-project)
  ("r"   projectile-recentf)
  ("x"   projectile-remove-known-project)
  ("X"   projectile-cleanup-known-projects)
  ("z"   projectile-cache-current-file)
  ("`"   hydra-projectile-other-window/body "other window")
  ("q"   nil "cancel" :color blue))

Ubiquitous Version Control

Magit and VC are both a part of my toolchain, through this hydra that I use. They're both incredibly powerful tools, serving slightly different use cases.

I have a hydra that acts as an entry point for my Version Control workflow.

(install-pkgs '(magit))
(require 'magit)
(defhydra hydra-magit (global-map "C-c g" :color teal :hint nil)
  "
     PROJECTILE: %(projectile-project-root)

     Immuting            Mutating
-----------------------------------------
  _w_: blame line      _b_: checkout
  _a_: annotate file   _B_: branch mgr
  _d_: diff            _c_: commit
  _s_: status          _e_: rebase
  _l_: log
  _t_: time machine

"
  ("w" git-messenger:popup-message)
  ("a" vc-annotate)
  ("b" magit-checkout)
  ("B" magit-branch-manager)
  ("c" vc-next-action)
  ("d" magit-diff-working-tree)
  ("e" magit-interactive-rebase)
  ("s" magit-status)
  ("l" magit-log)
  ("t" git-timemachine))

Git Blame

I have Git blame on C-x g ! using git-messenger 2, a neat little piece of kit which gives you a popup notification with the commit details of the current line of code.

(install-pkgs '(git-messenger))
(require 'git-messenger)

NEXT Branching

Phabricator/Arcanist basically requires you to always be working in a branch. If you want to open a diff, you open a diff between two branches, your work branch and master, so you have to be working on a branch. I need an easy way to keep me from commit on master in certain repositories, maybe as a pre-commit hook as a starter, but it should probably end up being a part of my editor workflow.

In the mean time, I can switch branches using a combination of Magit and Hydra, on C-x g b and C-x g B to open the branch manager.

Committing

I have two ways of doing this, in general; larger commits and single-file changes.

The latter I can use vc-next-action to do in a single blast, but for larger blobs of code, or to stage single hunks in a file, I'll need to use magit-status, add the files and then commit them all.

I have vc-next-action bound to C-x g c and I have magit-status bound to C-x g s.

History rewriting

The workflow that I use at work encourages clean git history, by doing rebases during landing; this lets me rewrite history as I please while I am working and bundle each piece of work in to a single commit or set of commits. This is bound to C-x g e.

History viewing

Magit has good repository logging, and git-timemachine3 can walk an individual file's history really well. I have magit-log bound to C-x g l and I have git-timemachine bound to C-x g t.

(install-pkgs '(git-timemachine))
(require 'git-timemachine)

Stashing

I don't do this enough to put it on a dedicated global key, it is available inside of magit-status under z, let's leave it there.

Autocomplete with Company

(install-pkgs '(company))

I use company for more than just programming completions (see 💕=company-emoji=💕, f.e.), so let's just enable it everywhere.

(global-company-mode)
(global-set-key (kbd "C-TAB") 'company-complete)

NEXT Refactoring Tools

NEXT Phabricator/Arcanist integration

NEXT Create some nice Phabricator reports to make Triage easier

[2015-01-05 Mon 12:15] UberEverything work

NEXT Phabricator org-mode integration

  • pull tdown in to an org-mode document
  • updates as necessary

Footnotes:

Author: Ryan Rix

Created: 2017-07-02 Sun 11:27

Validate XHTML 1.0