about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--home/common/legacy-dotfiles.nix8
-rw-r--r--home/common/solarized.nix18
-rw-r--r--home/home.nix70
-rw-r--r--home/modules/alacritty.nix46
-rw-r--r--home/modules/alsi.nix41
-rw-r--r--home/modules/emacs.nix45
-rw-r--r--home/modules/i3.nix233
-rw-r--r--home/modules/lib/cloneRepo.nix67
-rw-r--r--home/modules/nixos-logo.txt26
-rwxr-xr-xhome/modules/pure.zsh-theme151
-rw-r--r--home/modules/shell.nix189
-rw-r--r--home/modules/vim.nix47
-rw-r--r--home/modules/vimrc1121
-rw-r--r--home/modules/zshrc371
-rwxr-xr-xinstall38
-rw-r--r--pkgs/alsi/default.nix22
-rw-r--r--system/configuration.nix11
-rw-r--r--system/machines/bumblebee.nix21
-rw-r--r--system/modules/common.nix106
-rw-r--r--system/modules/emacs.nix23
-rw-r--r--system/modules/reusable/README.org2
-rw-r--r--system/modules/reusable/battery.nix32
-rw-r--r--system/modules/sound.nix14
-rw-r--r--system/modules/xserver.nix19
24 files changed, 2721 insertions, 0 deletions
diff --git a/home/common/legacy-dotfiles.nix b/home/common/legacy-dotfiles.nix
new file mode 100644
index 0000000000..33d9581e6a
--- /dev/null
+++ b/home/common/legacy-dotfiles.nix
@@ -0,0 +1,8 @@
+with import <nixpkgs> {};
+fetchgit {
+  url = "https://github.com/glittershark/dotfiles.git";
+  rev = "e0c7f2592fbc2f9942763d2146d362a1314630e9";
+  # date = "2020-03-25T20:38:51-04:00";
+  sha256 = "126zy4ff6nl2vma2s74waksim7j5h3n6qpaxnnn17vkc1cq0fcd9";
+  fetchSubmodules = false;
+}
diff --git a/home/common/solarized.nix b/home/common/solarized.nix
new file mode 100644
index 0000000000..e94693edc5
--- /dev/null
+++ b/home/common/solarized.nix
@@ -0,0 +1,18 @@
+rec {
+  base03  = "#002B36";
+  base02  = "#073642";
+  base01  = "#586e75";
+  base00  = "#657b83";
+  base0   = "#839496";
+  base1   = "#93a1a1";
+  base2   = "#eee8d5";
+  base3   = "#fdf6e3";
+  yellow  = "#b58900";
+  orange  = "#cb4b16";
+  red     = "#dc322f";
+  magenta = "#d33682";
+  violet  = "#6c71c4";
+  blue    = "#268bd2";
+  cyan    = "#2aa198";
+  green   = "#859900";
+}
diff --git a/home/home.nix b/home/home.nix
new file mode 100644
index 0000000000..e0ecda410b
--- /dev/null
+++ b/home/home.nix
@@ -0,0 +1,70 @@
+{ config, pkgs, ... }:
+
+{
+  imports = [
+    ./modules/alacritty.nix
+    ./modules/emacs.nix
+    ./modules/i3.nix
+    ./modules/shell.nix
+    ./modules/vim.nix
+    ./modules/alsi.nix
+    ./modules/lib/cloneRepo.nix
+
+  ];
+
+  # Let Home Manager install and manage itself.
+  programs.home-manager.enable = true;
+  xsession.enable = true;
+
+  # This value determines the Home Manager release that your
+  # configuration is compatible with. This helps avoid breakage
+  # when a new Home Manager release introduces backwards
+  # incompatible changes.
+  #
+  # You can update Home Manager without changing this value. See
+  # the Home Manager release notes for a list of state version
+  # changes in each release.
+  home.stateVersion = "19.09";
+
+  home.packages = with pkgs; [
+    nix-prefetch-github
+    htop
+    powertop
+    pass
+    gitAndTools.hub
+    shellcheck
+    gnupg
+
+    # Spotify...etc
+    spotify
+    playerctl
+
+    # games
+    crawl
+    dwarf-fortress
+  ];
+
+  nixpkgs.config.allowUnfree = true;
+
+  programs.git = {
+    enable = true;
+    userEmail = "root@gws.fyi";
+    userName  = "Griffin Smith";
+  };
+
+  services.redshift = {
+    enable = true;
+    provider = "geoclue2";
+  };
+
+  services.pasystray.enable = true;
+
+  impure.clonedRepos.passwordStore = {
+    github = "glittershark/pass";
+    path = ".password-store";
+  };
+
+  services.gpg-agent = {
+    enable = true;
+  };
+}
diff --git a/home/modules/alacritty.nix b/home/modules/alacritty.nix
new file mode 100644
index 0000000000..ba26360fe9
--- /dev/null
+++ b/home/modules/alacritty.nix
@@ -0,0 +1,46 @@
+{ config, lib, pkgs, ... }:
+{
+  home.packages = with pkgs; [
+    alacritty 
+  ];
+
+  programs.alacritty = {
+    enable = true;
+    settings = {
+      font.size = 6;
+
+      colors = with import ../common/solarized.nix; rec {
+        # Default colors
+        primary = {
+          background = base3;
+          foreground = base00;
+        };
+
+        cursor = {
+          text = base3;
+          cursor = base00;
+        };
+
+        # Normal colors
+        normal = {
+          inherit red green yellow blue magenta cyan;
+          black = base02;
+          white = base2;
+        };
+
+        # Bright colors
+        bright = normal;
+        # bright = {
+        #   black = base03;
+        #   red = orange;
+        #   green = base01;
+        #   yellow = base00;
+        #   blue = base0;
+        #   magenta = violet;
+        #   cyan = base1;
+        #   white = base3;
+        # };
+      };
+    };
+  };
+}
diff --git a/home/modules/alsi.nix b/home/modules/alsi.nix
new file mode 100644
index 0000000000..cb9802e2ce
--- /dev/null
+++ b/home/modules/alsi.nix
@@ -0,0 +1,41 @@
+{ config, lib, pkgs, ... }:
+let alsi = pkgs.callPackage ../../pkgs/alsi {};
+in
+{
+  home.packages = [ alsi ];
+
+  home.file.".config/alsi/alsi.logo" = {
+    source = ./nixos-logo.txt;
+    force = true;
+  };
+
+  home.file.".config/alsi/alsi.conf" = {
+    text = ''
+    #!${pkgs.perl}/bin/perl
+
+    scalar {
+      ALSI_VERSION         => "0.4.8",
+      COLORS_FILE          => "/home/grfn/.config/alsi/alsi.colors",
+      DE_FILE              => "/home/grfn/.config/alsi/alsi.de",
+      DEFAULT_COLOR_BOLD   => "blue",
+      DEFAULT_COLOR_NORMAL => "blue",
+      DF_COMMAND           => "df -Th -x sys -x tmpfs -x devtmpfs &>/dev/stdout",
+      GTK2_RC_FILE         => "/home/grfn/.gtkrc-2.0",
+      GTK3_RC_FILE         => "/home/grfn/.config/gtk-3.0/settings.ini",
+      LOGO_FILE            => "/home/grfn/.config/alsi/alsi.logo",
+      OUTPUT_FILE          => "/home/grfn/.config/alsi/alsi.output",
+      # PACKAGES_PATH        => "/var/lib/pacman/local/",
+      PS_COMMAND           => "ps -A",
+      USAGE_COLORS         => 0,
+      USAGE_COLORS_BOLD    => 0,
+      USAGE_PRECENT_GREEN  => 50,
+      USAGE_PRECENT_RED    => 100,
+      USAGE_PRECENT_YELLOW => 85,
+      USE_LOGO_FROM_FILE   => 1,
+      USE_VALUES_COLOR     => 0,
+      WM_FILE              => "/home/grfn/.config/alsi/alsi.wm",
+    }
+    '';
+    force = true;
+  };
+}
diff --git a/home/modules/emacs.nix b/home/modules/emacs.nix
new file mode 100644
index 0000000000..05b09ec2c5
--- /dev/null
+++ b/home/modules/emacs.nix
@@ -0,0 +1,45 @@
+{ pkgs, lib, ... }:
+
+let
+ # doom-emacs = pkgs.callPackage (builtins.fetchTarball {
+ #   url = https://github.com/vlaci/nix-doom-emacs/archive/master.tar.gz;
+ # }) {
+ #   doomPrivateDir = ./doom.d;  # Directory containing your config.el init.el
+ #                               # and packages.el files
+ # };
+in {
+  imports = [ ./lib/cloneRepo.nix ];
+
+  # home.packages = [ doom-emacs ];
+  # home.file.".emacs.d/init.el".text = ''
+  #     (load "default.el")
+  # '';
+  #
+
+  home.packages = [
+    # haskellPackages.Agda BROKEN
+  ];
+
+  programs.emacs.enable = true;
+  home.file.".doom.d".source = ./doom.d;
+
+  impure.clonedRepos = {
+    orgClubhouse = {
+      github = "glittershark/org-clubhouse";
+      path = "code/org-clubhouse";
+    };
+
+    doomEmacs = {
+      github = "hlissner/org-clubhouse";
+      path = ".emacs.d";
+      after = ["orgClubhouse"];
+      onClone = "bin/doom install";
+    };
+  };
+
+  # Notes
+  services.syncthing = {
+    enable = true;
+    tray = true;
+  };
+}
diff --git a/home/modules/i3.nix b/home/modules/i3.nix
new file mode 100644
index 0000000000..e4820b5280
--- /dev/null
+++ b/home/modules/i3.nix
@@ -0,0 +1,233 @@
+{ config, lib, pkgs, ... }:
+let
+  mod = "Mod4";
+  solarized = import ../common/solarized.nix;
+  decorationFont = "MesloLGSDZ 6";
+in {
+  home.packages = with pkgs; [
+    maim
+    rofi
+    i3status
+    python38Packages.py3status
+  ];
+
+  xsession.scriptPath = ".hm-xsession";
+  xsession.windowManager.i3 = {
+    enable = true;
+    config = {
+      modifier = mod;
+      keybindings = lib.mkOptionDefault {
+        "${mod}+h" = "focus left";
+        "${mod}+j" = "focus down";
+        "${mod}+k" = "focus up";
+        "${mod}+l" = "focus right";
+        "${mod}+semicolon" = "focus parent";
+
+        "${mod}+Shift+h" = "move left";
+        "${mod}+Shift+j" = "move down";
+        "${mod}+Shift+k" = "move up";
+        "${mod}+Shift+l" = "move right";
+
+        "${mod}+Shift+x" = "kill";
+
+        "${mod}+Return" = "exec alacritty";
+
+        "${mod}+Shift+s" = "split h";
+        "${mod}+Shift+v" = "split v";
+
+        "${mod}+f" = "fullscreen";
+
+        "${mod}+Shift+r" = "exec home-manager switch";
+
+        "${mod}+r" = "mode resize";
+
+        # Marks
+        "${mod}+Shift+m" = ''exec i3-input -F "mark %s" -l 1 -P 'Mark: ' '';
+        "${mod}+m" = ''exec i3-input -F '[con_mark="%s"] focus' -l 1 -P 'Go to: ' '';
+
+        # Screenshots
+        "${mod}+q" = "exec maim";
+        "${mod}+Shift+q" = "exec \"maim -s | xclip -selection clipboard -t image/png\"";
+
+        # Launching applications
+        "${mod}+u" =
+          let rofi = pkgs.writeShellScript "rofi" ''
+            rofi \
+              -modi 'combi' \
+              -combi-modi "window,drun,ssh,run" \
+              -font 'MesloLGSDZ 10' \
+              -show combi
+          '';
+          in "exec ${rofi}";
+
+        # Media
+        "XF86AudioPlay" = "exec playerctl play-pause";
+        "XF86AudioNext" = "exec playerctl next";
+        "XF86AudioPrevious" = "exec playerctl previous";
+        "XF86AudioRaiseVolume" = "exec pulseaudio-ctl up";
+        "XF86AudioLowerVolume" = "exec pulseaudio-ctl down";
+        "XF86AudioMute" = "exec pulseaudio-ctl mute";
+
+        # Screen Layout
+        "${mod}+Shift+t" = "exec xrandr --auto";
+        # TODO
+        # $mod+t exec /home/griffin/.screenlayout/work.sh
+        # $mod+Ctrl+t exec /home/griffin/bin/fix_screen.sh
+      };
+
+      fonts = [ decorationFont ];
+
+      colors = with solarized; rec {
+        focused = {
+          border = base01;
+          background = base01;
+          text = base3;
+          indicator = red;
+          childBorder = base02;
+        };
+        focusedInactive = focused // {
+          border = base03;
+          background = base03;
+          # text = base1;
+        };
+        unfocused = focusedInactive;
+        background = base03;
+      };
+
+      modes.resize = {
+        l = "resize shrink width 5 px or 5 ppt";
+        k = "resize grow height 5 px or 5 ppt";
+        j = "resize shrink height 5 px or 5 ppt";
+        h = "resize grow width 5 px or 5 ppt";
+
+        Return = "mode \"default\"";
+      };
+
+      bars = [{
+        statusCommand =
+          let i3status-conf = pkgs.writeText "i3status.conf" ''
+            general {
+                output_format = i3bar
+                colors = true
+                color_good = "#859900"
+
+                interval = 1
+            }
+
+            order += "mpd"
+            order += "wireless wlp3s0"
+            order += "ethernet enp3s0f0"
+            order += "cpu_usage"
+            order += "battery 0"
+            # order += "volume master"
+            order += "time"
+
+            mpd {
+                format = "%artist - %album - %title"
+            }
+
+            wireless wlp3s0 {
+                format_up = "W: (%quality - %essid - %bitrate) %ip"
+                format_down = "W: -"
+            }
+
+            ethernet enp3s0f0 {
+                format_up = "E: %ip"
+                format_down = "E: -"
+            }
+
+            battery 0 {
+                format = "%status %percentage"
+                path = "/sys/class/power_supply/BAT%d/uevent"
+                low_threshold = 10
+            }
+
+            cpu_usage {
+                format = "CPU: %usage"
+            }
+
+            load {
+                format = "%5min"
+            }
+
+            time {
+                format = "    %a %h %d ⌚   %I:%M     "
+            }
+
+            # volume master {
+            #     format = "☊ %volume"
+            #     format_muted = "☊ X"
+            #     device = "default"
+            #     mixer_idx = 0
+            # }
+          '';
+          in "py3status -c ${i3status-conf}";
+        fonts = [ decorationFont ];
+        position = "top";
+        colors = with solarized; rec {
+          background = base03;
+          statusline = base3;
+          separator = base1;
+          activeWorkspace = {
+            border = base03;
+            background = base1;
+            text = base3;
+          };
+          focusedWorkspace = activeWorkspace;
+          inactiveWorkspace = activeWorkspace // {
+            background = base01;
+          };
+          urgentWorkspace = activeWorkspace // {
+            background = red;
+          };
+        };
+      }];
+    };
+  };
+
+  services.dunst = {
+    enable = true;
+    settings = with solarized; {
+      global = {
+        font = "Meslo 6";
+        allow_markup = true;
+        format = "<b>%s</b>\n%b";
+        sort = true;
+        alignment = "left";
+        geometry = "600x5-30+20";
+        idle_threshold = 120;
+        separator_color = "frame";
+      };
+
+      frame = {
+        width = 0;
+        color = "#aaaaaa";
+      };
+
+      shortcuts = {
+        close = "ctrl+space";
+        close_all = "ctrl+shift+space";
+        history = "ctrl+grave";
+        context = "ctrl+shift+period";
+      };
+
+      urgency_low = {
+        background = base03;
+        foreground = base3;
+        timeout = 5;
+      };
+
+      urgency_normal = {
+        background = base02;
+        foreground = base3;
+        timeout = 7;
+      };
+
+      urgency_critical = {
+        background = red;
+        foreground = base3;
+        timeout = 0;
+      };
+    };
+  };
+}
diff --git a/home/modules/lib/cloneRepo.nix b/home/modules/lib/cloneRepo.nix
new file mode 100644
index 0000000000..50f6ca2d3d
--- /dev/null
+++ b/home/modules/lib/cloneRepo.nix
@@ -0,0 +1,67 @@
+{ lib, config, ... }:
+with lib;
+{
+  options = {
+    impure.clonedRepos = mkOption {
+      description = "Repositories to clone";
+      default = {};
+      type = with types; loaOf (
+        let sm = submodule {
+          options = {
+            url = mkOption {
+              type = nullOr str;
+              description = "URL of repository to clone";
+              default = null;
+            };
+
+            github = mkOption {
+              type = nullOr str;
+              description = "Github owner/repo of repository to clone";
+              default = null;
+            };
+
+            path = mkOption {
+              type = str;
+              description = "Path to clone to";
+            };
+
+            onClone = mkOption {
+              type = str;
+              description = ''
+                Shell command to run after cloning the repo for the first time.
+                Runs inside the repo itself.
+              '';
+              default = "";
+            };
+
+            after = mkOption {
+              type = listOf str;
+              description = "Activation hooks that this repository must be cloned after";
+              default = [];
+            };
+          };
+        };
+        in addCheck sm (cr: (! isNull cr.url || ! isNull cr.github))
+      );
+    };
+  };
+
+  config = {
+    home.activation =
+      mapAttrs
+      (_: {
+        url, path, github, onClone, after
+      }:
+        let repoURL = if isNull url then "git@github.com:${github}" else url;
+        in hm.dag.entryAfter (["writeBoundary"] ++ after) ''
+          $DRY_RUN_CMD mkdir -p $(dirname "${path}")
+          if [[ ! -d ${path} ]]; then
+            $DRY_RUN_CMD git clone "${repoURL}" "${path}"
+            pushd ${path}
+            $DRY_RUN_CMD ${onClone}
+            popd
+          fi
+        '')
+      config.impure.clonedRepos;
+  };
+}
diff --git a/home/modules/nixos-logo.txt b/home/modules/nixos-logo.txt
new file mode 100644
index 0000000000..d4b16b44f0
--- /dev/null
+++ b/home/modules/nixos-logo.txt
@@ -0,0 +1,26 @@
+                 ((((((          ###%######       ##%###/
+               ,(((((((/(          #%#%#%#%#    .#%#%#%#%#
+                 ((((((///          %#######%. #####%###/
+                  (((((/(//,         /##%###%###%######
+                    (((//////          #####%########(
+         .(((((((((((((((///////////////#%%%########          ((
+        (((((((((((((((///////////////////#########         .((((
+       ((((((((((((((((/(//////////////////##########      ((((((((
+                   (#########                #########    (((((((((
+                  #########                   #########/((((((((((
+                *#########                     .#######(((((((((
+ ###%###################                         ####(//((((((((((((((((
+####%##################                           .#////////((((((((((((((
+%%%%%%%%%%%%%%#######((                           ////////////((((((((((((
+ ###%#######%#######////.                        ///////////////////((((
+         ###%###%#///////(                      /////////
+       .####%#### /////////                   /////////,
+      %#%#%#%#%*   /////////(                /////////
+      .#####%#       ////////(######################%#######%#####,
+        %####         (////////#####################%###%###%###%
+         .#          (//////(//((###################%#######%##%
+                    (//(((((((((((          #####%%%%(
+                  //(/((((((((((((((          ######%##
+                 (((((((((  (((((((((          #####%###/
+                (((((((((    /(((((((((         .###%####%
+                 ((((((        (((((((((          %#%#%#/
diff --git a/home/modules/pure.zsh-theme b/home/modules/pure.zsh-theme
new file mode 100755
index 0000000000..b4776e8159
--- /dev/null
+++ b/home/modules/pure.zsh-theme
@@ -0,0 +1,151 @@
+#!/bin/zsh -f
+# vim: ft=zsh:
+# MIT License
+# For my own and others sanity
+# git:
+# %b => current branch
+# %a => current action (rebase/merge)
+# prompt:
+# %F => color dict
+# %f => reset color
+# %~ => current path
+# %* => time
+# %n => username
+# %m => shortname host
+# %(?..) => prompt conditional - %(condition.true.false)
+
+# turns seconds into human readable time
+# 165392 => 1d 21h 56m 32s
+prompt_pure_human_time() {
+	local tmp=$1
+	local days=$(( tmp / 60 / 60 / 24 ))
+	local hours=$(( tmp / 60 / 60 % 24 ))
+	local minutes=$(( tmp / 60 % 60 ))
+	local seconds=$(( tmp % 60 ))
+	(( $days > 0 )) && echo -n "${days}d "
+	(( $hours > 0 )) && echo -n "${hours}h "
+	(( $minutes > 0 )) && echo -n "${minutes}m "
+	echo "${seconds}s"
+}
+
+is_git_repo() {
+	command git rev-parse --is-inside-work-tree &>/dev/null
+	return $?
+}
+
+# fastest possible way to check if repo is dirty
+prompt_pure_git_dirty() {
+	# check if we're in a git repo
+	is_git_repo || return
+	# check if it's dirty
+	[[ "$PURE_GIT_UNTRACKED_DIRTY" == 0 ]] && local umode="-uno" || local umode="-unormal"
+	command test -n "$(git status --porcelain --ignore-submodules ${umode})"
+
+	(($? == 0)) && echo '*'
+}
+
+prompt_pure_git_wip() {
+	is_git_repo || return
+	local subject="$(command git show --pretty=%s --quiet HEAD 2>/dev/null)"
+	[ "$subject" == 'wip' ] && echo '[WIP]'
+}
+
+# displays the exec time of the last command if set threshold was exceeded
+prompt_pure_cmd_exec_time() {
+	local stop=$EPOCHSECONDS
+	local start=${cmd_timestamp:-$stop}
+	integer elapsed=$stop-$start
+	(($elapsed > ${PURE_CMD_MAX_EXEC_TIME:=5})) && prompt_pure_human_time $elapsed
+}
+
+prompt_pure_preexec() {
+	cmd_timestamp=$EPOCHSECONDS
+
+	# shows the current dir and executed command in the title when a process is active
+	print -Pn "\e]0;"
+	echo -nE "$PWD:t: $2"
+	print -Pn "\a"
+}
+
+# string length ignoring ansi escapes
+prompt_pure_string_length() {
+	echo ${#${(S%%)1//(\%([KF1]|)\{*\}|\%[Bbkf])}}
+}
+
+prompt_pure_nix_info() {
+	local packages_info=''
+	if [[ -z $NIX_SHELL_PACKAGES ]]; then
+		packages_info='[nix-shell]'
+	else
+		packages_info="{ $NIX_SHELL_PACKAGES }"
+	fi
+
+	case $IN_NIX_SHELL in
+		'pure')
+			echo "$fg_bold[green][nix-shell] "
+			;;
+		'impure')
+			echo "$fg_bold[magenta][nix-shell] "
+			;;
+		*) ;;
+	esac
+}
+
+prompt_pure_precmd() {
+	# shows the full path in the title
+	print -Pn '\e]0;%~\a'
+
+	# git info
+	vcs_info
+
+	local prompt_pure_preprompt="\n$(prompt_pure_nix_info)$fg_bold[green]$prompt_pure_username%F{blue}%~%F{yellow}$vcs_info_msg_0_`prompt_pure_git_dirty` $fg_no_bold[red]`prompt_pure_git_wip`%f %F{yellow}`prompt_pure_cmd_exec_time`%f "
+	print -P $prompt_pure_preprompt
+
+	# check async if there is anything to pull
+	# (( ${PURE_GIT_PULL:-1} )) && {
+	# 	# check if we're in a git repo
+	# 	command git rev-parse --is-inside-work-tree &>/dev/null &&
+	# 	# make sure working tree is not $HOME
+	# 	[[ "$(command git rev-parse --show-toplevel)" != "$HOME" ]] &&
+	# 	# check check if there is anything to pull
+	# 	command git fetch &>/dev/null &&
+	# 	# check if there is an upstream configured for this branch
+	# 	command git rev-parse --abbrev-ref @'{u}' &>/dev/null && {
+	# 		local arrows=''
+	# 		(( $(command git rev-list --right-only --count HEAD...@'{u}' 2>/dev/null) > 0 )) && arrows='⇣'
+	# 		(( $(command git rev-list --left-only --count HEAD...@'{u}' 2>/dev/null) > 0 )) && arrows+='⇡'
+	# 		print -Pn "\e7\e[A\e[1G\e[`prompt_pure_string_length $prompt_pure_preprompt`C%F{cyan}${arrows}%f\e8"
+	# 	}
+	# } &!
+
+	# reset value since `preexec` isn't always triggered
+	unset cmd_timestamp
+}
+
+
+prompt_pure_setup() {
+	# prevent percentage showing up
+	# if output doesn't end with a newline
+	export PROMPT_EOL_MARK=''
+
+	prompt_opts=(cr subst percent)
+
+	zmodload zsh/datetime
+	autoload -Uz add-zsh-hook
+	autoload -Uz vcs_info
+
+	add-zsh-hook precmd prompt_pure_precmd
+	add-zsh-hook preexec prompt_pure_preexec
+
+	zstyle ':vcs_info:*' enable git
+	zstyle ':vcs_info:git*' formats ' %b'
+	zstyle ':vcs_info:git*' actionformats ' %b|%a'
+
+	# show username@host if logged in through SSH
+	[[ "$SSH_CONNECTION" != '' ]] && prompt_pure_username='%n@%m '
+
+	# prompt turns red if the previous command didn't exit with 0
+	PROMPT='%(?.%F{green}.%F{red})❯%f '
+}
+
+prompt_pure_setup "$@"
diff --git a/home/modules/shell.nix b/home/modules/shell.nix
new file mode 100644
index 0000000000..51dc0e3670
--- /dev/null
+++ b/home/modules/shell.nix
@@ -0,0 +1,189 @@
+{ config, lib, pkgs, ... }:
+{
+  home.packages = with pkgs; [
+    zsh
+    autojump
+  ];
+
+  programs.zsh = {
+    enable = true;
+    enableAutosuggestions = true;
+    autocd = true;
+
+    shellAliases = rec {
+      # NixOS stuff
+      hms = "home-manager switch";
+      nor = "sudo nixos-rebuild switch";
+      nrs = nor;
+      vihome = "vim ~/.config/nixpkgs/home.nix && home-manager switch";
+      virc = "vim ~/.config/nixpkgs/home/shell.nix && home-manager switch && source ~/.zshrc";
+
+      # Nix
+      ns = "nix-shell";
+
+      # Aliases from old config
+      stck = "dirs -v";
+      b= "cd ~1";
+      ".." = "cd ..";
+      "..." = "cd ../..";
+      "...." = "cd ../../..";
+      "....." = "cd ../../../..";
+      "http" = "http --style solarized";
+      "grep" = "grep $GREP_OPTIONS";
+      "bak" = "~/bin/backup.sh";
+      "xmm" = "xmodmap ~/.Xmodmap";
+      "asdflkj" = "asdf";
+      "asdf" = "asdfghjkl";
+      "asdfghjkl" = "echo \"Having some trouble?\"";
+      "ift" = "sudo iftop -i wlp3s0";
+      "rvpn" = "sudo systemctl restart openvpn@bldr-dev openvpn@lsvl-dev";
+      "gne" = "gn edit";
+      "gnf" = "gn find";
+      "gnt" = "gn tag-list";
+      "gnn" = "gn notebook-list";
+      "mytl" = "t tl $TWITTER_WHOAMI";
+      "first" = "awk '{print \$$1}'";
+      "dcu" = "docker-compose up";
+      "dc" = "docker-compose";
+      "dck" = "docker";
+      "dockerclean" = "dockercleancontainers && dockercleanimages";
+      "dockercleanimages" = "docker images -a --no-trunc | grep none | awk '{print \$$3}' | xargs -L 1 -r docker rmi";
+      "dockercleancontainers" = "docker ps -a --no-trunc| grep 'Exit' | awk '{print \$$1}' | xargs -L 1 -r docker rm";
+      "cmt" = "git log --oneline | fzf-tmux | awk '{print \$$1}'";
+      "workmon" = "xrandr --output DP-2 --pos 1440x900 --primary";
+      "vi" = "vim";
+      "awa" = "ssh aw2-admin.nomi.host";
+      "dtf" = "cd ~/.dotfiles";
+      "adbdev" = "adb devices";
+      "adbcon" = "adb connect $GNEX_IP";
+      "gwip" = "git add . && git commit -am wip";
+      "gpr" = "g pull-request";
+      "gcl" = "git clone";
+      "grs" = "gr --soft";
+      "grhh" = "grh HEAD";
+      "grh" = "gr --hard";
+      "gr" = "git reset";
+      "gcb" = "gc -b";
+      "gco" = "gc";
+      "gcd" = "gc development";
+      "gcm" = "gc master";
+      "gc" = "git checkout";
+      "gbg" = "git branch | grep";
+      "gba" = "git branch -a";
+      "gb" = "git branch";
+      "gcv" = "git commit --verbose";
+      "gci" = "git commit";
+      "gm" = "git merge";
+      "gdc" = "gd --cached";
+      "gd" = "git diff";
+      "gsl" = "git stash list";
+      "gss" = "git show stash";
+      "gsad" = "git stash drop";
+      "gsa" = "git stash";
+      "gst" = "gs";
+      "gs" = "git status";
+      "gg" = "gl --decorate --oneline --graph --date-order --all";
+      "gl" = "git log";
+      "gf" = "git fetch";
+      "gur" = "gu --rebase";
+      "gu" = "git pull";
+      "gpf" = "gp -f";
+      "gpa" = "gp --all";
+      "gpu" = "git push -u origin \"$(git symbolic-ref --short HEAD)\"";
+      "gp" = "git push";
+      "ganw" = "git diff -w --no-color | git apply --cached --ignore-whitespace";
+      "ga" = "git add";
+      "gnp" = "git --no-pager";
+      "g" = "git";
+      "git" = "hub";
+      "mpalb" = "mpc search album";
+      "mpart" = "mpc search artist";
+      "mps" = "mpc search";
+      "mpa" = "mpc add";
+      "mpt" = "mpc toggle";
+      "mpl" = "mpc playlist";
+      "dsstore" = "find . -name '*.DS_Store' -type f -ls -delete";
+      "df" = "df -h";
+      "fs" = "stat -f '%z bytes'";
+      "ll" = "ls -al";
+      "la" = "ls -a";
+    };
+
+    oh-my-zsh = {
+      enable = true;
+
+      plugins = [
+        "battery"
+        "colorize"
+        "command-not-found"
+        "github"
+        "gitignore"
+        "postgres"
+        "systemd"
+        "themes"
+        "vi-mode"
+      ];
+
+      custom = "${pkgs.stdenv.mkDerivation {
+        name = "oh-my-zsh-custom";
+        unpackPhase = ":";
+        installPhase = ''
+          mkdir -p $out/themes
+          mkdir -p $out/custom/plugins
+          ln -s ${./pure.zsh-theme} $out/themes/pure.zsh-theme
+        '';
+      }}";
+
+      theme = "pure";
+    };
+
+    plugins = [{
+      name = "pure-theme";
+      src = pkgs.fetchFromGitHub {
+        owner = "sindresorhus";
+        repo = "pure";
+        rev = "0a92b02dd4172f6c64fdc9b81fe6cd4bddb0a23b";
+        sha256 = "0l8jqhmmjn7p32hdjnv121xsjnqd2c0plhzgydv2yzrmqgyvx7cc";
+      };
+    }];
+
+    initExtraBeforeCompInit = ''
+      zstyle ':completion:*' completer _complete _ignored _correct _approximate
+      zstyle ':completion:*' matcher-list \'\' 'm:{[:lower:]}={[:upper:]} m:{[:lower:][:upper:]}={[:upper:][:lower:]} r:|[._- :]=** r:|=**' 'l:|=* r:|=*'
+      zstyle ':completion:*' max-errors 5
+      zstyle ':completion:*' use-cache yes
+      zstyle ':completion::complete:grunt::options:' expire 1
+      zstyle ':completion:*' prompt '%e errors'
+      # zstyle :compinstall filename '~/.zshrc'
+      autoload -Uz compinit
+    '';
+
+    initExtra = ''
+      source ${./zshrc}
+      source ${pkgs.fetchFromGitHub {
+        owner = "zsh-users";
+        repo = "zsh-syntax-highlighting";
+        rev = "7678a8a22780141617f809002eeccf054bf8f448";
+        sha256 = "0xh4fbd54kvwwpqvabk8lpw7m80phxdzrd75q3y874jw0xx1a9q6";
+      }}/zsh-syntax-highlighting.zsh
+      source ${pkgs.autojump}/share/autojump/autojump.zsh
+      source ${pkgs.fetchFromGitHub {
+        owner = "chisui";
+        repo = "zsh-nix-shell";
+        rev = "a65382a353eaee5a98f068c330947c032a1263bb";
+        sha256 = "0l41ac5b7p8yyjvpfp438kw7zl9dblrpd7icjg1v3ig3xy87zv0n";
+      }}/nix-shell.plugin.zsh
+
+      autoload -U promptinit; promptinit
+      prompt pure
+
+      [[ ! $IN_NIX_SHELL ]] && alsi -l
+    '';
+  };
+
+  programs.fzf = {
+    enable = true;
+    enableBashIntegration = true;
+    enableZshIntegration = true;
+  };
+}
diff --git a/home/modules/vim.nix b/home/modules/vim.nix
new file mode 100644
index 0000000000..87d4309333
--- /dev/null
+++ b/home/modules/vim.nix
@@ -0,0 +1,47 @@
+{ config, pkgs, ... }:
+{
+  programs.neovim = {
+    enable = true;
+    viAlias = true;
+    vimAlias = true;
+    plugins = with pkgs.vimPlugins; [
+      ctrlp
+      deoplete-nvim
+      syntastic
+      vim-abolish
+      vim-airline
+      vim-airline-themes
+      vim-bufferline
+      vim-closetag
+      # vim-colors-solarized
+      # solarized
+      (pkgs.vimUtils.buildVimPlugin {
+        name = "vim-colors-solarized";
+        src = pkgs.fetchFromGitHub {
+          owner = "glittershark";
+          repo = "vim-colors-solarized";
+          rev = "4857c3221ec3f2693a45855154cb61a2cefb514d";
+          sha256 = "0kqp5w14g7adaiinmixm7z3x4w74lv1lcgbqjbirx760f0wivf9y";
+        };
+      })
+      vim-commentary
+      vim-dispatch
+      vim-endwise
+      vim-repeat
+      vim-fugitive
+      vim-markdown
+      vim-nix
+      vim-rhubarb
+      vim-sexp
+      vim-sexp-mappings-for-regular-people
+      vim-sleuth
+      vim-startify
+      vim-surround
+      vim-unimpaired
+      vinegar
+    ];
+    extraConfig = ''
+      source ${./vimrc}
+    '';
+  };
+}
diff --git a/home/modules/vimrc b/home/modules/vimrc
new file mode 100644
index 0000000000..16bc8d9184
--- /dev/null
+++ b/home/modules/vimrc
@@ -0,0 +1,1121 @@
+" vim:set fdm=marker fmr={{{,}}} ts=2 sts=2 sw=2 expandtab:
+
+
+" Basic Options {{{
+set nocompatible
+set modeline
+set modelines=10
+syntax enable
+filetype plugin indent on
+set ruler
+set showcmd
+set number
+set incsearch
+set smartcase
+set ignorecase
+set scrolloff=10
+set tabstop=4
+set shiftwidth=4
+set softtabstop=4
+set nosmartindent
+set expandtab
+set noerrorbells visualbell t_vb=
+set laststatus=2
+set hidden
+let mapleader = ','
+let maplocalleader = '\'
+set undofile
+" set undodir=~/.vim/undo
+set wildignore=*.pyc,*.o,.git
+set clipboard=unnamed
+" set backupdir=$HOME/.vim/backup   
+" set directory=$HOME/.vim/tmp     
+set foldmarker={{{,}}}
+set colorcolumn=+1
+set concealcursor=
+set formatoptions+=j
+set wildmenu
+set wildmode=longest,list:full
+set noincsearch
+" }}}
+
+" GUI options {{{
+set go-=m
+set go-=T
+set go-=r
+set go-=L
+set go-=e
+set guifont=Meslo\ LG\ S\ DZ\ 9
+" }}}
+
+" Colors {{{
+" set t_Co=256
+
+fu! ReverseBackground()
+  if &bg=="light"
+    se bg=dark
+  else
+    se bg=light
+  endif
+endf
+com! BgToggle call ReverseBackground()
+nm <F12> :BgToggle<CR>
+
+set background=light
+colorscheme solarized
+" }}}
+
+" ---------------------------------------------------------------------------
+
+" CtrlP {{{
+let g:ctrlp_custom_ignore = {
+      \ 'dir': '(node_modules|target)'
+      \ }
+let g:ctrlp_max_files = 0
+let g:ctrlp_max_depth = 100
+" }}}
+
+" YouCompleteMe {{{
+let g:ycm_semantic_triggers =  {
+      \   'c' : ['->', '.'],
+      \   'objc' : ['->', '.'],
+      \   'ocaml' : ['.', '#'],
+      \   'cpp,objcpp' : ['->', '.', '::'],
+      \   'perl' : ['->'],
+      \   'php' : ['->', '::'],
+      \   'cs,java,javascript,d,python,perl6,scala,vb,elixir,go' : ['.'],
+      \   'vim' : ['re![_a-zA-Z]+[_\w]*\.'],
+      \   'lua' : ['.', ':'],
+      \   'erlang' : [':'],
+      \   'clojure' : [],
+      \   'haskell' : ['re!.*', '.', ' ', '(']
+      \ }
+      " \   'haskell' : ['.', '(', ' ']
+      " \   'ruby' : ['.', '::'],
+      " \   'clojure' : ['(', '.', '/', '[']
+" }}}
+
+" Neocomplete {{{
+if !has('nvim')
+  " Use neocomplete.
+  let g:neocomplete#enable_at_startup = 1
+  " Use smartcase.
+  let g:neocomplete#enable_smart_case = 1
+  " Set minimum syntax keyword length.
+  let g:neocomplete#sources#syntax#min_keyword_length = 3
+  let g:neocomplete#lock_buffer_name_pattern = '\*ku\*'
+
+  " Define dictionary.
+  " let g:neocomplete#sources#dictionary#dictionaries = {
+  "     \ 'default' : '',
+  "     \ 'vimshell' : $HOME.'/.vimshell_hist',
+  "     \ 'scheme' : $HOME.'/.gosh_completions'
+  "     \ }
+
+  " Define keyword.
+  if !exists('g:neocomplete#keyword_patterns')
+      let g:neocomplete#keyword_patterns = {}
+  endif
+  let g:neocomplete#keyword_patterns['default'] = '\h\w*'
+
+  " Plugin key-mappings.
+  inoremap <expr><C-g>     neocomplete#undo_completion()
+  inoremap <expr><C-l>     neocomplete#complete_common_string()
+
+  " Recommended key-mappings.
+  " <CR>: close popup and save indent.
+  inoremap <silent> <CR> <C-r>=<SID>my_cr_function()<CR>
+  function! s:my_cr_function()
+    return (pumvisible() ? "\<C-y>" : "" ) . "\<CR>"
+    " For no inserting <CR> key.
+    "return pumvisible() ? "\<C-y>" : "\<CR>"
+  endfunction
+  " <TAB>: completion.
+  inoremap <expr><TAB>  pumvisible() ? "\<C-n>" : "\<TAB>"
+  " <C-h>, <BS>: close popup and delete backword char.
+  inoremap <expr><C-h> neocomplete#smart_close_popup()."\<C-h>"
+  inoremap <expr><BS> neocomplete#smart_close_popup()."\<C-h>"
+  " Close popup by <Space>.
+  "inoremap <expr><Space> pumvisible() ? "\<C-y>" : "\<Space>"
+
+  " AutoComplPop like behavior.
+  "let g:neocomplete#enable_auto_select = 1
+
+  " Shell like behavior(not recommended).
+  "set completeopt+=longest
+  "let g:neocomplete#enable_auto_select = 1
+  "let g:neocomplete#disable_auto_complete = 1
+  "inoremap <expr><TAB>  pumvisible() ? "\<Down>" : "\<C-x>\<C-u>"
+
+  " Enable omni completion.
+  " autocmd FileType css setlocal omnifunc=csscomplete#CompleteCSS
+  " autocmd FileType html,markdown setlocal omnifunc=htmlcomplete#CompleteTags
+  " autocmd FileType javascript setlocal omnifunc=javascriptcomplete#CompleteJS
+  " autocmd FileType python setlocal omnifunc=pythoncomplete#Complete
+  " autocmd FileType xml setlocal omnifunc=xmlcomplete#CompleteTags
+
+  " Enable heavy omni completion.
+  if !exists('g:neocomplete#sources#omni#input_patterns')
+    let g:neocomplete#sources#omni#input_patterns = {}
+  endif
+endif
+" }}}
+
+" Deoplete {{{
+if has('nvim')
+  let g:deoplete#enable_at_startup = 1
+
+  inoremap <silent> <CR> <C-r>=<SID>my_cr_function()<CR>
+  function! s:my_cr_function()
+    return (pumvisible() ? "\<C-y>" : "" ) . "\<CR>"
+    " For no inserting <CR> key.
+    "return pumvisible() ? "\<C-y>" : "\<CR>"
+  endfunction
+  " <TAB>: completion.
+  inoremap <expr><TAB> pumvisible() ? "\<C-n>" : "\<TAB>"
+  inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<TAB>"
+endif
+" }}}
+
+" Neovim Terminal mode {{{
+if has('nvim')
+  tnoremap <Esc> <C-\><C-n>
+  nnoremap \\ :tabedit term://zsh<CR>
+  nnoremap q\ :call <SID>OpenRepl()<CR>
+
+  if !exists('g:repl_size')
+    let g:repl_size=9
+  endif
+
+  function! s:OpenRepl() " {{{
+    " Check if buffer exists and is open
+    if exists('s:repl_bufname') && bufexists(s:repl_bufname) && bufwinnr(s:repl_bufname) >=? 0
+      " If so, just switch to it
+      execute bufwinnr(s:repl_bufname) . 'wincmd' 'w'
+      norm i
+      return
+    endif
+
+    if !exists('b:console')
+      let b:console=$SHELL
+    endif
+
+    let l:console_cmd = b:console
+
+    execute 'bot' g:repl_size . 'new'
+    set winfixheight nobuflisted
+    call termopen(l:console_cmd)
+    let s:repl_bufname = bufname('%')
+    norm i
+  endfunction " }}}
+endif
+" }}}
+
+" Tagbar options {{{
+let g:tagbar_autoclose = 1
+let g:tagbar_autofocus = 1
+let g:tagbar_compact = 1
+" }}}
+
+" delimitMate options {{{
+let g:delimitMate_expand_cr = 1
+" }}}
+
+" UltiSnips options {{{
+let g:UltiSnipsExpandTrigger = '<c-j>'
+   "g:UltiSnipsJumpForwardTrigger          <c-j>
+   "g:UltiSnipsJumpBackwardTrigger         <c-k>
+" }}}
+
+" VDebug Options {{{
+let g:vdebug_options = {'server': '192.168.56.1'}
+" }}}
+
+" Statusline {{{
+let g:airline_powerline_fonts=1
+
+if !exists('g:airline_symbols')
+  let g:airline_symbols = {}
+endif
+let g:airline_symbols.space = "\ua0"
+
+let g:airline#extensions#tagbar#flags = 'f'
+let g:airline#extensions#tabline#enabled = 1
+let g:airline#extensions#tabline#show_buffers = 0
+let g:airline#extensions#tabline#show_tabs = 1
+let g:airline#extensions#tabline#tab_min_count = 2
+let g:airline#extensions#tmuxline#enabled = 0
+
+let g:tmuxline_theme = 'airline'
+let g:tmuxline_preset = 'full'
+
+"set statusline=
+"set statusline+=%2*[%n%H%M%R%W]%*\              " flags and buf no
+"set statusline+=%-40f%<\                        " path
+"set statusline+=%=%40{fugitive#statusline()}\   " Vim status
+"set statusline+=%1*%y%*%*\                      " file type
+"set statusline+=%10((%l,%c)%)\                  " line and column
+"set statusline+=%P                              " percentage of file
+" }}}
+
+" Code review mode {{{
+fun! GetFontName()
+  return substitute(&guifont, '^\(.\{-}\)[0-9]*$', '\1', '')
+endfun
+
+fun! <SID>CodeReviewMode()
+  let &guifont = GetFontName() . ' 15'
+endfun
+com! CodeReviewMode call <SID>CodeReviewMode()
+" }}}
+
+" Syntastic {{{
+let g:syntastic_enable_signs = 0
+
+" Python {{{
+let g:syntastic_python_checkers = ['flake8']
+let g:syntastic_python_flake8_post_args = "--ignore=E101,E223,E224,E301,E302,E303,E501,E701,W,F401,E111,E261"
+
+" }}} 
+" Javascript {{{
+let g:syntastic_javascript_checkers = ['eslint']
+let g:flow#autoclose = 1
+let g:flow#enable = 1
+
+" augroup syntastic_javascript_jsx
+"   autocmd!
+"   autocmd BufReadPre,BufNewFile *.js 
+"   autocmd BufReadPre,BufNewFile *.jsx
+"         \ let g:syntastic_javascript_checkers = ['jsxhint']
+" augroup END
+
+" }}}
+" Haml {{{
+let g:syntastic_haml_checkers = ['haml_lint']
+
+" }}}
+" Html {{{
+let g:syntastic_html_checkers = []
+
+" }}}
+" Ruby {{{
+let g:syntastic_ruby_checkers = ['rubocop']
+" }}}
+" SASS/SCSS {{{
+let g:syntastic_scss_checkers = ['scss_lint']
+" }}}
+" Haskell {{{
+" let g:syntastic_haskell_checkers = ['ghc-mod']
+" }}}
+" Elixir {{{
+let g:syntastic_elixir_checkers = ['elixir']
+let g:syntastic_enable_elixir_checker = 1
+" }}}
+" }}}
+
+" Bufferline {{{
+let g:bufferline_echo=0
+" }}}
+
+" Eclim {{{
+let g:EclimCompletionMethod = 'omnifunc'
+augroup eclim
+  au!
+  au FileType java call <SID>JavaSetup()
+  au FileType java set textwidth=120
+augroup END
+
+function! s:JavaSetup() abort
+  noremap <C-I> :JavaImport<CR>
+  nnoremap K :JavaDocPreview<CR>
+  nnoremap ]d :JavaSearchContext<CR>
+  nnoremap [d :JavaSearchContext<CR>
+  nnoremap g<CR> :JUnit<CR>
+  nnoremap g\ :Mvn test<CR>
+endfunction
+" }}}
+
+" Signify options {{{
+let g:signify_mapping_next_hunk = ']h'
+let g:signify_mapping_prev_hunk = '[h'
+let g:signify_vcs_list          = ['git']
+let g:signify_sign_change       = '~'
+let g:signify_sign_delete       = '-'
+" }}}
+
+" Simplenote {{{
+let g:SimplenoteFiletype = 'markdown'
+let g:SimplenoteSortOrder = 'pinned,modifydate,tagged,createdate'
+let g:SimplenoteVertical = 1
+
+nnoremap <Leader>nn :Simplenote -n<CR>
+nnoremap <Leader>nl :Simplenote -l<CR>
+nnoremap <Leader>nw :Simplenote -l work<CR>
+nnoremap <Leader>nt :Simplenote -t<CR>
+" }}}
+
+" Emmet {{{
+" Expand abbreviation
+let g:user_emmet_leader_key = '<C-y>'
+" }}}
+
+" Startify {{{
+let g:startify_bookmarks=[ '~/.vimrc',  '~/.zshrc' ]
+" }}}
+
+" Abolish {{{
+let g:abolish_save_file = expand('~/.vim/after/plugin/abolish.vim')
+" }}}
+
+" Rails projections {{{
+
+if !exists('g:rails_projections')
+  let g:rails_projections = {}
+endif
+
+call extend(g:rails_projections, {
+      \ "config/routes.rb": { "command": "routes" },
+      \ "config/structure.sql": { "command": "structure" }
+      \ }, 'keep')
+
+if !exists('g:rails_gem_projections')
+  let g:rails_gem_projections = {}
+endif
+
+call extend(g:rails_gem_projections, {
+      \ "active_model_serializers": {
+      \   "app/serializers/*_serializer.rb": {
+      \     "command": "serializer",
+      \     "template": "class %SSerializer < ActiveModel::Serializer\nend",
+      \     "affinity": "model"}},
+      \ "react-rails": {
+      \   "app/assets/javascripts/components/*.jsx": {
+      \     "command": "component",
+      \     "template": "var %S = window.%S = React.createClass({\n  render: function() {\n  }\n});",
+      \     "alternate": "spec/javascripts/components/%s_spec.jsx" },
+      \   "spec/javascripts/components/*_spec.jsx": {
+      \     "alternate": "app/assets/javascripts/components/{}.jsx" }},
+      \ "rspec": {
+      \    "spec/**/support/*.rb": {
+      \      "command": "support"}},
+      \ "cucumber": {
+      \   "features/*.feature": {
+      \     "command": "feature",
+      \     "template": "Feature: %h"},
+      \   "features/support/*.rb": {
+      \     "command": "support"},
+      \   "features/support/env.rb": {
+      \     "command": "support"},
+      \   "features/step_definitions/*_steps.rb": {
+      \     "command": "steps"}},
+      \ "carrierwave": {
+      \   "app/uploaders/*_uploader.rb": {
+      \     "command": "uploader",
+      \     "template": "class %SUploader < CarrierWave::Uploader::Base\nend"}},
+      \ "draper": {
+      \   "app/decorators/*_decorator.rb": {
+      \     "command": "decorator",
+      \     "affinity": "model",
+      \     "template": "class %SDecorator < Draper::Decorator\nend"}},
+      \ "fabrication": {
+      \   "spec/fabricators/*_fabricator.rb": {
+      \     "command": ["fabricator", "factory"],
+      \     "alternate": "app/models/%s.rb",
+      \     "related": "db/schema.rb#%p",
+      \     "test": "spec/models/%s_spec.rb",
+      \     "template": "Fabricator :%s do\nend",
+      \     "affinity": "model"}},
+      \ "factory_girl": {
+      \   "spec/factories/*.rb": {
+      \     "command": "factory",
+      \     "alternate": "app/models/%i.rb",
+      \     "related": "db/structure.sql#%s",
+      \     "test": "spec/models/%s_spec.rb",
+      \     "template": "FactoryGirl.define do\n  factory :%i do\n  end\nend",
+      \     "affinity": "model"},
+      \   "spec/factories.rb": {
+      \      "command": "factory"},
+      \   "test/factories.rb": {
+      \      "command": "factory"}}
+      \ }, 'keep')
+" }}}
+
+" Other projections {{{
+let g:projectionist_heuristics = {
+      \ "config.ru&docker-compose.yml&app/&config/&OWNERS": {
+      \   "app/jobs/*.rb": {
+      \     "type": "job",
+      \     "alternate": "spec/jobs/{}_spec.rb"
+      \   },
+      \   "app/models/*.rb": {
+      \     "type": "model",
+      \     "alternate": "spec/models/{}_spec.rb"
+      \   },
+      \   "app/resources/*_resource.rb": {
+      \     "type": "resource",
+      \     "alternate": "spec/resources/{}_resource_spec.rb"
+      \   },
+      \   "config/*.yml": {
+      \     "type": "config"
+      \   },
+      \   "spec/*_spec.rb": {
+      \     "type": "spec",
+      \     "alternate": "app/{}.rb"
+      \   },
+      \   "spec/factories/*.rb": {
+      \     "type": "factory",
+      \   }
+      \ },
+      \ "svc-gateway.cabal": {
+      \   "src/*.hs": {
+      \     "type": "src",
+      \     "alternate": "test/{}Spec.hs"
+      \  },
+      \   "test/*Spec.hs": {
+      \     "type": "spec",
+      \     "alternate": "src/{}.hs",
+      \     "template": [
+      \       "module Gateway.Resource.HierarchySpec (main, spec) where",
+      \       "",
+      \       "import Prelude",
+      \       "import Test.Hspec",
+      \       "import Data.Aeson",
+      \       "",
+      \       "import Gateway.Resource.Hierarchy",
+      \       "",
+      \       "main :: IO ()",
+      \       "main = hspec spec",
+      \       "",
+      \       "spec :: Spec",
+      \       "spec = do",
+      \       "    describe \"something\" $ undefined"
+      \    ]
+      \  },
+      \  "svc-gateway.cabal": {
+      \    "type": "cabal"
+      \  }
+      \ },
+      \ "package.json&.flowconfig": {
+      \   "src/*.*": {
+      \     "type": "src",
+      \     "alternate": "test/{}_spec.js"
+      \   }
+      \ },
+      \ "pom.xml&src/main/clj/|src/main/cljs": {
+      \   "*": { 
+      \     "start": "USE_NREPL=1 bin/run -m elephant.dev-system" ,
+      \     "connect": "nrepl://localhost:5554",
+      \     "piggieback": "(figwheel-sidecar.repl-api/repl-env)"
+      \   },
+      \   "pom.xml": { "type": "pom" },
+      \   "src/main/clj/*.clj": {
+      \     "alternate": "src/test/clj/{}_test.clj",
+      \     "template": ["(ns {dot|hyphenate})"]
+      \   },
+      \   "src/test/clj/*_test.clj": {
+      \     "alternate": "src/main/clj/{}.clj",
+      \     "dispatch": ":RunTests {dot|hyphenate}-test",
+      \     "template": ["(ns {dot|hyphenate}-test",
+      \                  "  (:require [clojure.test :refer :all]))"]
+      \   },
+      \   "src/main/cljs/*.cljs": {
+      \     "alternate": "src/test/cljs/{}_test.cljs"
+      \   },
+      \   "src/main/cljs/*_test.cljs": {
+      \     "alternate": "src/main/cljs/{}.cljs",
+      \     "dispatch": ":RunTests {dot|hyphenate}-test"
+      \   },
+      \   "src/main/clj/*.cljc": {
+      \     "alternate": "src/test/clj/{}_test.cljc"
+      \   },
+      \   "src/main/clj/*_test.cljc": {
+      \     "alternate": "src/test/clj/{}.cljc",
+      \     "dispatch": ":RunTests {dot|hyphenate}-test"
+      \   }
+      \ }}
+" }}}
+
+" AutoPairs {{{
+let g:AutoPairsCenterLine = 0
+" }}}
+
+" Filetypes {{{
+
+" Python {{{
+aug Python 
+  au!
+  au FileType python set tabstop=4 shiftwidth=4 softtabstop=4 expandtab
+aug END
+let g:python_highlight_all=1
+" }}}
+
+" PHP {{{
+aug PHP
+  au!
+  "au FileType php setlocal fdm=marker fmr={{{,}}}
+aug END " }}}
+
+" Mail {{{
+aug Mail 
+  au FileType mail setlocal spell
+aug END " }}}
+
+" Haskell {{{
+let g:haskell_conceal_wide = 1
+let g:haskellmode_completion_ghc = 0
+let g:necoghc_enable_detailed_browse = 1
+
+augroup Haskell
+  autocmd!
+  autocmd FileType haskell setlocal textwidth=110 shiftwidth=2
+  autocmd FileType haskell setlocal omnifunc=necoghc#omnifunc
+  autocmd FileType haskell call <SID>HaskellSetup()
+  autocmd FileType haskell setlocal keywordprg=hoogle\ -cie
+augroup END
+
+function! s:HaskellSetup()
+  set sw=4
+  " compiler cabal
+  " let b:start='cabal run'
+  " let b:console='cabal repl'
+  " let b:dispatch='cabal test'
+  compiler stack
+  let b:start='stack run'
+  let b:console='stack ghci'
+  let b:dispatch='stack test'
+  nnoremap <buffer> gy :HdevtoolsType<CR>
+  nnoremap <buffer> yu :HdevtoolsClear<CR>
+endfunction
+" }}}
+
+" Ruby {{{
+
+function! s:RSpecSyntax()
+  syn keyword rspecMethod describe context it its specify shared_context 
+        \ shared_examples shared_examples_for shared_context include_examples 
+        \ include_context it_should_behave_like it_behaves_like before after 
+        \ around fixtures controller_name helper_name scenario feature 
+        \ background given described_class
+  syn match rspecMethod '\<let\>!\='
+  syn match rspecMethod '\<subject\>!\='
+  syn keyword rspecMethod violated pending expect expect_any_instance_of allow 
+        \ allow_any_instance_of double instance_double mock mock_model 
+        \ stub_model xit
+  syn match rspecMethod '\.\@<!\<stub\>!\@!'
+
+  call s:RSpecHiDefaults()
+endfunction
+
+function! s:RSpecHiDefaults()
+  hi def link rspecMethod rubyFunction
+endfunction
+
+augroup Ruby 
+  au!
+  " au FileType ruby let b:surround_114 = "\\(module|class,def,if,unless,case,while,until,begin,do) \r end"
+  " au FileType ruby set fdm=syntax
+  au FileType ruby set tw=110
+  au FileType ruby set omnifunc=
+  au FileType ruby nnoremap <buffer> gy orequire 'pry'; binding.pry<ESC>^
+  au FileType ruby nnoremap <buffer> gY Orequire 'pry'; binding.pry<ESC>^
+  au FileType ruby nnoremap <buffer> yu :g/require 'pry'; binding.pry/d<CR> 
+  au BufNewFile,BufRead *_spec.rb call <SID>RSpecSyntax()
+augroup END
+
+let ruby_operators = 1
+let ruby_space_errors = 1
+
+let g:rubycomplete_rails = 1
+command! -range ConvertHashSyntax <line1>,<line2>s/:(\S{-})(\s{-})=> /\1:\2/
+" }}}
+
+" Clojure {{{
+
+aug Clojure
+  au!
+  autocmd FileType clojure nnoremap <C-S> :Slamhound<CR>
+  autocmd FileType clojure nnoremap <silent> gr :w <bar> Require <bar> e<CR>
+  let g:clojure_align_multiline_strings = 1
+  let g:clojure_fuzzy_indent_patterns =
+        \ ['^with', '^def', '^let', '^fact']
+  let g:clojure_special_indent_words =
+        \ 'deftype,defrecord,reify,proxy,extend-type,extend-protocol,letfn,html'
+
+  autocmd FileType clojure setlocal textwidth=80
+  autocmd FileType clojure setlocal lispwords+=GET,POST,PATCH,PUT,DELETE |
+        \ setlocal lispwords+=context,select
+  autocmd BufNewFile,BufReadPost *.cljx setfiletype clojure
+  autocmd BufNewFile,BufReadPost *.cljx setlocal omnifunc=
+  autocmd BufNewFile,BufReadPost *.cljs setlocal omnifunc=
+  autocmd FileType clojure call <SID>TangentInit()
+  autocmd FileType clojure call <SID>sexp_mappings()
+  autocmd BufRead *.cljc ClojureHighlightReferences
+  autocmd FileType clojure let b:AutoPairs = {
+        \ '"': '"',
+        \ '{': '}',
+        \ '(': ')',
+        \ '[': ']'}
+        " Don't auto-pair quote reader macros
+        " \'`': '`',
+        " \ '''': '''', 
+
+  autocmd User ProjectionistActivate call s:projectionist_connect()
+
+  function! s:projectionist_connect() abort
+    let connected = !empty(fireplace#path())
+    if !connected
+      for [root, value] in projectionist#query('connect')
+        try
+          silent execute "FireplaceConnect" value root
+          let connected = 1
+          break
+        catch /.*Connection refused.*/
+        endtry
+      endfor
+    endif
+
+    " if connected && exists(':Piggieback') 
+    "   for [root, value] in projectionist#query('piggieback')
+    "     silent execute "Piggieback" value
+    "     break
+    "   endfor
+    " endif
+  endfunction
+
+  " autocmd BufNewFile,BufReadPost *.cljx setlocal omnifunc=
+  " autocmd BufNewFile,BufReadPost *.cljs setlocal omnifunc=
+
+  autocmd FileType clojure let b:console='lein repl'
+  autocmd FileType clojure call <SID>ClojureMaps()
+
+  function! s:ClojureMaps() abort
+    nnoremap <silent> <buffer> [m :call search('^(def', 'Wzb')<CR>
+    nnoremap <silent> <buffer> ]m :call search('^(def', 'Wz')<CR>
+  endfunction
+
+  command! Scratch call <SID>OpenScratch()
+  autocmd FileType clojure nnoremap <buffer> \s :Scratch<CR>
+
+  let g:scratch_buffer_name = 'SCRATCH'
+
+  function! s:OpenScratch()
+    if bufwinnr(g:scratch_buffer_name) > 0
+      execute bufwinnr(g:scratch_buffer_name) . 'wincmd' 'w'
+      return
+    endif
+
+    vsplit SCRATCH
+    set buftype=nofile
+    set filetype=clojure
+    let b:scratch = 1
+  endfunction
+aug END
+
+function! s:sexp_mappings() abort
+  if !exists('g:sexp_loaded')
+    return
+  endif
+
+  nmap <buffer> cfo <Plug>(sexp_raise_list)
+  nmap <buffer> cfO <Plug>(sexp_raise_element)
+  nmap <buffer> cfe <Plug>(sexp_raise_element)
+endfunction
+
+function! s:TangentInit() abort
+  set textwidth=80
+  command! TReset    call fireplace#session_eval('(user/reset)')
+  command! TGo       call fireplace#session_eval('(user/go)')
+  command! TMigrate  call fireplace#session_eval('(user/migrate)')
+  command! TRollback call fireplace#session_eval('(user/rollback)')
+  nnoremap g\ :TReset<CR>
+endfunction
+
+" }}}
+
+" Go {{{
+
+let g:go_highlight_functions = 1
+let g:go_highlight_methods = 1
+let g:go_highlight_structs = 1
+let g:go_highlight_operators = 1
+let g:go_highlight_build_constraints = 1
+
+augroup Go
+  autocmd!
+  autocmd FileType go setlocal omnifunc=go#complete#Complete
+  autocmd FileType go setlocal foldmethod=syntax
+  autocmd FileType go setlocal foldlevel=100
+  autocmd FileType go nnoremap <buffer> <F9> :GoTest<CR>
+  autocmd FileType go inoremap <buffer> <F9> <ESC>:GoTest<CR>i
+augroup END
+
+" }}}
+
+" RAML {{{
+
+function! s:buffer_syntax() " {{{
+  syn keyword ramlRAML          RAML             contained
+  syn match   ramlVersionString '^#%RAML \d\.\d' contains=ramlRAML
+endfunction " }}}
+
+augroup RAML
+  autocmd!
+  autocmd BufRead,BufNewFile *.raml set filetype=yaml
+  autocmd BufRead,BufNewFile *.raml call s:buffer_syntax()
+augroup END
+
+hi def link ramlVersionString Special
+hi def link ramlRAML Error
+" }}}
+
+" Mustache/Handlebars {{{
+let g:mustache_abbreviations = 1
+" }}}
+
+" Netrw {{{
+augroup netrw
+  autocmd!
+  autocmd FileType netrw nnoremap <buffer> Q :Rexplore<CR>
+
+  " Hee hee, oil and vinegar
+  function! s:setup_oil() abort
+    nnoremap <buffer> q <C-6>
+    xnoremap <buffer> q <C-6>
+  endfunction
+augroup END
+" }}}
+" }}}
+
+" Remove trailing whitespace {{{
+fun! <SID>StripTrailingWhitespaces()
+  let l = line(".")
+  let c = col(".")
+  %s/\s\+$//e
+  call cursor(l, c)
+endfun
+
+augroup striptrailingwhitespaces " {{{
+autocmd FileType c,cpp,java,php,ruby,python,sql,javascript,sh,jst,less,haskell,haml,coffee,scss,clojure,objc,elixir,yaml,json,eruby
+  \ autocmd BufWritePre <buffer> :call <SID>StripTrailingWhitespaces()
+augroup END " }}}
+
+" }}}
+
+" Goyo {{{
+let g:limelight_conceal_ctermfg = "10"
+let g:limelight_conceal_guifg = "#586e75"
+autocmd! User GoyoEnter Limelight
+autocmd! User GoyoLeave Limelight!
+" }}}
+
+"-----------------------------------------------------------------------------
+
+" Commands {{{
+
+" Edit temporary SQL files {{{
+let s:curr_sql = 0
+fun! <SID>EditSqlTempFile()
+  let l:fname = '/tmp/q' . s:curr_sql . '.sql'
+  execute 'edit' l:fname
+  let s:curr_sql = s:curr_sql + 1
+endfun
+com! EditSqlTempFile call <SID>EditSqlTempFile()
+" }}}
+
+" Double Indentation
+command! -range DoubleIndentation <line1>,<line2>s/^\(\s.\{-}\)\(\S\)/\1\1\2/
+
+" Quick-and-dirty fix capitalization of sql files
+command! -range FixSqlCapitalization <line1>,<line2>v/\v(^\s*--.*$)|(TG_)/norm guu
+
+" VimPipe Commands {{{
+" let g:sql_type_default = 'pgsql'
+command! SqlLive let b:vimpipe_command="vagrant ssh -c '~/mysql'"
+command! SqlRails let b:vimpipe_command="bin/rails dbconsole"
+command! SqlHeroku let b:vimpipe_command="heroku pg:psql"
+command! SqlEntities let b:vimpipe_command="psql -h 127.1 entities nomi"
+command! SqlUsers let b:vimpipe_command="psql -h 127.1 users nomi"
+command! SqlTangent let b:vimpipe_command="psql -h local.docker tangent super"
+" }}}
+
+" Git commands {{{
+command! -nargs=* Gpf Gpush -f <args>
+command! -nargs=* Gcv Gcommit --verbose <args>
+" }}}
+
+" Focus dispatch to only the last failures
+command! -nargs=* FocusFailures FocusDispatch rspec --only-failures <args>
+
+" }}}
+
+" Autocommands {{{
+
+augroup fugitive " {{{
+  au!
+  autocmd BufNewFile,BufRead fugitive://* set bufhidden=delete
+augroup END " }}}
+
+augroup omni " {{{
+  au!
+  " autocmd FileType javascript setlocal omnifunc=tern#Complete
+  "autocmd FileType python setlocal omnifunc=pythoncomplete#Complete
+  autocmd FileType php setlocal omnifunc=
+augroup END " }}}
+
+augroup sql " {{{
+  au!
+  autocmd FileType sql                 let b:vimpipe_command="psql -h 127.0.0.1 landlordsny_development landlordsny"
+  autocmd FileType sql                 let b:vimpipe_filetype="postgresql"
+  autocmd FileType sql                 set syntax=postgresql
+  autocmd FileType postgresql          set nowrap
+  autocmd BufNewFile,BufReadPost *.sql set syntax=pgsql
+augroup END " }}}
+
+augroup markdown " {{{
+  au!
+  autocmd FileType markdown let b:vimpipe_command='markdown'
+  autocmd FileType markdown let b:vimpipe_filetype='html'
+  autocmd FileType markdown set tw=80
+augroup END " }}}
+
+augroup typescript " {{{
+  au!
+  autocmd FileType typescript let b:vimpipe_command='tsc'
+  autocmd FileType typescript let b:vimpipe_filetype='javascript'
+  autocmd FileType typescript TSSstarthere
+  autocmd FileType typescript nnoremap <buffer> gd :TSSdef<CR>
+augroup END " }}}
+
+augroup jsx " {{{
+  au!
+  " autocmd FileType jsx set syntax=javascript
+  autocmd FileType javascript set filetype=javascript.jsx
+augroup END " }}}
+
+augroup nicefoldmethod " {{{
+  au!
+  " Don't screw up folds when inserting text that might affect them, until
+  " leaving insert mode. Foldmethod is local to the window. Protect against
+  " screwing up folding when switching between windows.
+  autocmd InsertEnter *
+    \ if !exists('w:last_fdm') |
+    \   let w:last_fdm=&foldmethod |
+    \   setlocal foldmethod=manual |
+    \ endif
+  autocmd InsertLeave,WinLeave *
+    \ if exists('w:last_fdm') |
+    \    let &l:foldmethod=w:last_fdm |
+    \    unlet w:last_fdm |
+    \ endif
+augroup END " }}}
+
+augroup visualbell " {{{
+  au!
+  autocmd GUIEnter * set visualbell t_vb=
+augroup END
+" }}}
+
+augroup quickfix " {{{
+  au!
+  autocmd QuickFixCmdPost grep cwindow
+augroup END " }}}
+
+augroup php " {{{
+  au!
+augroup END  "}}}
+
+augroup rubylang " {{{
+  au!
+  autocmd FileType ruby compiler rake
+augroup END " }}}
+
+augroup javascript "{{{
+  au!
+  autocmd FileType javascript let &errorformat =
+        \ '%E%.%#%n) %s:,' .
+        \ '%C%.%#Error: %m,' .
+        \ '%C%.%#at %s (%f:%l:%c),' .
+        \ '%Z%.%#at %s (%f:%l:%c),' .
+        \ '%-G%.%#,'
+augroup END " }}}
+
+augroup git " {{{
+  autocmd!
+  autocmd FileType gitcommit set textwidth=72
+augroup END
+" }}}
+" }}}
+
+" Leader commands {{{
+
+" Edit specific files {{{
+nnoremap <silent> <leader>ev :split $MYVIMRC<CR>
+nnoremap <silent> <leader>eb :split ~/.vim_bundles<CR>
+nnoremap <silent> <leader>es :UltiSnipsEdit<CR>
+nnoremap <silent> <leader>ea :split ~/.vim/after/plugin/abolish.vim<CR>
+
+nnoremap <silent> <leader>sv :so $MYVIMRC<CR>
+nnoremap <silent> <leader>sb :so ~/.vim_bundles<CR>
+nnoremap <silent> <leader>sa :so ~/.vim/after/plugin/abolish.vim<CR>
+
+nnoremap <Leader>el :EditSqlTempFile<CR>
+" }}}
+
+" Toggle navigation panels {{{
+nnoremap <Leader>l :TagbarToggle<CR>
+nnoremap <Leader>mb :MBEToggle<CR>
+nnoremap <Leader>u :GundoToggle<CR>
+
+nnoremap <Leader>t :CtrlP<CR>
+nnoremap <Leader>z :FZF<CR>
+nnoremap <Leader>b :CtrlPBuffer<CR>
+nnoremap <Leader>a :CtrlPTag<CR>
+nnoremap <Leader>r :CtrlPGitBranch<CR>
+" }}}
+
+" CtrlP {{{
+let g:ctrlp_custom_ignore = {
+      \ 'dir': 'node_modules',
+      \ }
+" }}}
+
+" Git leader commands {{{
+noremap <Leader>g :Git<SPACE>
+noremap <Leader>gu :Gpull<CR>
+noremap <Leader>gp :Gpush<CR>
+noremap <Leader>s :Gstatus<CR>
+noremap <Leader>cv :Gcommit --verbose<CR>
+noremap <Leader>ca :Gcommit --verbose --amend<CR>
+
+nnoremap <Leader>dl :diffg LOCAL<CR>
+nnoremap <Leader>dr :diffg REMOTE<CR>
+nnoremap <Leader>db :diffg BASE<CR>
+nnoremap <Leader>du :diffu<CR>
+nnoremap <Leader>dg :diffg<CR>
+
+nnoremap <Leader>d2 :diffg //2<CR>:diffu<CR>
+nnoremap <Leader>d3 :diffg //3<CR>:diffu<CR>
+
+nnoremap <Leader>yt :SignifyToggle<CR>
+" }}}
+
+" Breakpoint Leader Commands {{{
+nnoremap <Leader>x :Breakpoint<CR>
+nnoremap <Leader>dx :BreakpointRemove *<CR>
+" }}}
+
+" Tabularize {{{
+  " Leader Commands {{{
+  nnoremap <localleader>t= :Tabularize /=<CR>
+  vmap <localleader>t= :Tabularize /=<CR>
+
+  nnoremap <localleader>t> :Tabularize /=><CR>
+  vmap <localleader>t> :Tabularize /=><CR>
+  " }}}
+
+  " => Aligning {{{
+  function! s:rocketalign()
+    let l:p = '^.*=>\s.*$'
+    echo l:p
+    if exists(':Tabularize') && getline('.') =~# '^.*=' &&
+                \ (getline(line('.')-1) =~# l:p || getline(line('.')+1) =~# l:p)
+      let column = strlen(substitute(getline('.')[0:col('.')],'[^=>]','','g'))
+      let position = strlen(matchstr(getline('.')[0:col('.')],'.*=>\s*\zs.*'))
+      Tabularize/=>/l1
+      normal! $
+      call search(repeat('[^=>]*=>',column).'\s\{-\}'.repeat('.',position),'ce',line('.'))
+    endif
+  endfunction
+  "inoremap <buffer> <space>=><space> =><Esc>:call <SID>rocketalign()<CR>a
+  " }}}
+
+  " = Aligning {{{
+  function! s:eqalign()
+    let l:p = '^.*=\s.*$'
+    if exists(':Tabularize') && getline('.') =~# '^.*=' &&
+                \ (getline(line('.')-1) =~# l:p || getline(line('.')+1) =~# l:p)
+      let column = strlen(substitute(getline('.')[0:col('.')],'[^=]','','g'))
+      let position = strlen(matchstr(getline('.')[0:col('.')],'.*=\s*\zs.*'))
+      Tabularize/=/l1
+      normal! $
+      call search(repeat('[^=]*=',column).'\s\{-\}'.repeat('.',position),'ce',line('.'))
+    endif
+  endfunction
+  "inoremap <buffer><silent> <space>=<space> =<Esc>:call <SID>eqalign()<CR>a
+  " }}}
+
+  " : Aligning {{{
+  function! s:colonalign()
+    let l:p : '^.*:\s.*$'
+    if exists(':Tabularize') && getline('.') :~# '^.*:' &&
+                \ (getline(line('.')-1) :~# l:p || getline(line('.')+1) :~# l:p)
+      let column : strlen(substitute(getline('.')[0:col('.')],'[^:]','','g'))
+      let position : strlen(matchstr(getline('.')[0:col('.')],'.*:\s*\zs.*'))
+      Tabularize/:/l1
+      normal! $
+      call search(repeat('[^:]*:',column).'\s\{-\}'.repeat('.',position),'ce',line('.'))
+    endif
+  endfunction
+  "inoremap <buffer><silent> <space>:<space> :<Esc>:call <SID>colonalign()<CR>a
+  " }}}
+" }}}
+
+" }}}
+
+" Mappings {{{
+" 'delete current'
+nnoremap dc 0d$
+nnoremap com :silent !tmux set status<CR>
+nnoremap <F9>  :Make<CR>
+nnoremap g<CR> :Dispatch<CR>
+nnoremap g\ :Start<CR>
+inoremap <F9> <ESC>:Make<CR>i
+
+" Navigate buffers {{{
+nnoremap gb :bn<CR>
+nnoremap gB :bp<CR>
+" }}}
+
+" Window Navigation {{{
+nnoremap <space>w <C-w>
+nnoremap <space>h <C-w>h
+nnoremap <space>j <C-w>j
+nnoremap <space>k <C-w>k
+nnoremap <space>l <C-w>l
+nnoremap <space>z <C-w>z
+" }}}
+
+
+" Sort with motion {{{
+if !exists("g:sort_motion_flags")
+  let g:sort_motion_flags = ""
+endif
+function! s:sort_motion(mode) abort
+  if a:mode == 'line'
+    execute "'[,']sort " . g:sort_motion_flags
+  elseif a:mode == 'char'
+    execute "normal! `[v`]y"
+    let sorted = join(sort(split(@@, ', ')), ', ')
+    execute "normal! v`]c" . sorted
+  elseif a:mode == 'V' || a:mode == ''
+    execute "'<,'>sort " . g:sort_motion_flags
+  endif
+endfunction
+
+function! s:sort_lines() 
+  let beginning = line('.')
+  let end = v:count + beginning - 1
+  execute beginning . ',' . end . 'sort' 
+endfunction
+
+xnoremap <silent> <Plug>SortMotionVisual :<C-U>call <SID>sort_motion(visualmode())<CR>
+nnoremap <silent> <Plug>SortMotion :<C-U>set opfunc=<SID>sort_motion<CR>g@
+nnoremap <silent> <Plug>SortLines :<C-U>call <SID>sort_lines()<CR>
+
+map go <Plug>SortMotion
+vmap go <Plug>SortMotionVisual
+map goo <Plug>SortLines
+" }}}
+" }}}
+
+let g:hare_executable = 'cabal exec -- ghc-hare'
diff --git a/home/modules/zshrc b/home/modules/zshrc
new file mode 100644
index 0000000000..95c1733e13
--- /dev/null
+++ b/home/modules/zshrc
@@ -0,0 +1,371 @@
+#!/usr/bin/zsh
+# vim: set fdm=marker fmr={{{,}}}:
+
+stty -ixon
+
+# Compinstall {{{
+zstyle ':completion:*' completer _complete _ignored _correct _approximate
+zstyle ':completion:*' matcher-list '' 'm:{[:lower:]}={[:upper:]} m:{[:lower:][:upper:]}={[:upper:][:lower:]} r:|[._- :]=** r:|=**' 'l:|=* r:|=*'
+zstyle ':completion:*' max-errors 5
+zstyle ':completion:*' use-cache yes
+zstyle ':completion::complete:grunt::options:' expire 1
+zstyle ':completion:*' prompt '%e errors'
+zstyle :compinstall filename '~/.zshrc'
+autoload -Uz compinit
+compinit
+# }}}
+
+# Zsh-newuser-install {{{
+HISTFILE=~/.histfile
+HISTSIZE=1000
+SAVEHIST=1000
+setopt appendhistory autocd extendedglob notify autopushd
+unsetopt beep nomatch
+bindkey -v
+# }}}
+
+# Basic options {{{
+set -o vi
+umask 022
+export VIRTUAL_ENV_DISABLE_PROMPT=1
+# export PATH=~/.local/bin:~/.cabal/bin:$PATH:~/code/go/bin:~/bin:~/npm/bin:~/.gem/ruby/2.1.0/bin:~/.gem/ruby/2.0.0/bin:/home/smith/bin
+# }}}
+
+# Zsh highlight highlighters {{{
+ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets pattern root)
+# }}}
+
+# More basic options {{{
+setopt no_hist_verify
+setopt histignorespace
+# }}}
+
+# Utility Functions {{{
+
+# Set the terminal's title bar.
+function titlebar() {
+echo -ne "\033]0;$*\007"
+}
+
+function quiet() {
+"$@" >/dev/null
+}
+
+function quieter() {
+"$@" >/dev/null 2>&1
+}
+
+# From http://stackoverflow.com/questions/370047/#370255
+function path_remove() {
+IFS=:
+# convert it to an array
+t=($PATH)
+unset IFS
+# perform any array operations to remove elements from the array
+t=(${t[@]%%$1})
+IFS=:
+# output the new array
+echo "${t[*]}"
+}
+
+# }}}
+
+# Force screen to use zsh {{{
+# }}}
+
+# Environment {{{
+export EDITOR="/usr/bin/vim"
+# }}}
+
+# Directory Stuff {{{
+
+# Always use color output for `ls`
+if [[ "$OSTYPE" =~ ^darwin ]]; then
+else
+  export LS_COLORS='no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.ogg=01;35:*.mp3=01;35:*.wav=01;35:'
+fi
+
+# Directory listing
+
+# Easier navigation: .., ..., -
+
+# File size
+
+# Recursively delete `.DS_Store` files
+
+# Create a new directory and enter it
+function md() {
+  mkdir -p "$@" && cd "$@"
+}
+
+# }}}
+
+# MPD/MPC stuff {{{
+function mp() {
+# Test if drive is already mounted
+if ! lsblk | grep /media/external >/dev/null; then
+  if ! sudo mount /media/external; then
+    echo "External drive not plugged in, or could not mount"
+    return 1
+  fi
+fi
+if (mpc >/dev/null 2>&1); then
+  ncmpcpp
+else
+  mpd &&
+    (pgrep mpdscribble || mpdscribble) &&
+    ncmpcpp
+fi
+}
+
+# kill mp
+function kmp() {
+killall ncmpcpp
+mpd --kill
+
+local files
+
+if (files=$(lsof 2>&1 | grep -v docker | grep external)); then
+  echo
+  echo "==> Still processes using external drive:"
+  echo
+  echo $files
+else
+  sudo umount /media/external
+fi
+}
+
+
+function mppal() {
+mpc search album "$1" | mpc add &&
+  mpc play;
+}
+# }}}
+
+# Git stuff {{{
+# function ga() { git add "${@:-.}"; } # Add all files by default
+# Add non-whitespace changes
+# function gc() { git checkout "${@:-master}"; } # Checkout master by default
+
+# open all changed files (that still actually exist) in the editor
+function ged() {
+local files=()
+for f in $(git diff --name-only "$@"); do
+  [[ -e "$f" ]] && files=("${files[@]}" "$f")
+done
+local n=${#files[@]}
+echo "Opening $n $([[ "$@" ]] || echo "modified ")file$([[ $n != 1 ]] && \
+  echo s)${@:+ modified in }$@"
+q "${files[@]}"
+}
+
+# git find-replace
+function gfr() {
+if [[ "$#" == "0" ]]; then
+  echo 'Usage:'
+  echo ' gg_replace term replacement file_mask'
+  echo
+  echo 'Example:'
+  echo ' gg_replace cappuchino cappuccino *.html'
+  echo
+else
+  find=$1; shift
+  replace=$1; shift
+
+  ORIG_GLOBIGNORE=$GLOBIGNORE
+  GLOBIGNORE=*.*
+  if [[ "$#" = "0" ]]; then
+    set -- ' ' $@
+  fi
+
+  while [[ "$#" -gt "0" ]]; do
+    for file in `git grep -l $find -- $1`; do
+      sed -e "s/$find/$replace/g" -i'' $file
+    done
+    shift
+  done
+
+  GLOBIGNORE=$ORIG_GLOBIGNORE
+fi
+}
+
+function vconflicts() {
+$EDITOR $(git status --porcelain | awk '/^UU/ { print $2 }')
+}
+
+function fetchall() {
+for repo in ~/code/nomi/gems/* ~/code/nomi/services/svc-users ~/code/nomi/services/svc-entities ~/code/go/src/github.com/getnomi/svc-gateway; do
+  echo -e "\x1b[34;1m=======> \x1b[37;1m$repo\x1b[0m"
+  git -C $repo fetch
+done
+}
+# }}}
+
+# Wifi {{{
+# }}}
+
+# adb {{{
+export GNEX_IP='192.168.3.30'
+# }}}
+
+# Golang {{{
+export GOPATH="/home/griffin/code/go"
+# }}}
+
+# Tail logs {{{
+# }}}
+
+# Running stuff {{{
+# }}}
+
+# Directories {{{
+
+
+
+export NODE_ENV='development'
+# }}}
+
+# SSH shortcuts {{{
+# }}}
+
+# Editing config files {{{
+# }}}
+
+# XRandR {{{
+# }}}
+
+# fzf {{{
+v() {
+  local file
+  file=$(fzf-tmux --query="$1" --select-1 --exit-0)
+  [ -n "$file" ] && ${EDITOR:-vim} "$file"
+}
+
+c() {
+  local dir
+  dir=$(find ${1:-*} -path '*/\.*' -prune -o -type d -print 2> /dev/null | fzf +m) && cd "$dir"
+}
+
+co() {
+  local branch
+  branch=$(git branch -a | sed -s "s/\s*\**//g" | fzf --query="$1" --select-1 --exit-0) && git checkout "$branch"
+}
+
+
+# fh - repeat history
+# h() {
+#   eval $(([ -n "$ZSH_NAME" ] && fc -l 1 || history) | fzf +s | sed 's/ *[0-9]* *//')
+# }
+
+# fkill - kill process
+fkill() {
+  ps -ef | sed 1d | fzf-tmux -m | awk '{print $2}' | xargs kill -${1:-9}
+}
+# }}}
+
+# Tmux utils {{{
+kill_detached() {
+  for sess in $(tmux ls | grep -v attached | sed -s "s/:.*$//"); do
+    tmux kill-session -t $sess;
+  done
+}
+# }}}
+
+# Docker {{{
+
+
+# dbp foo/bar .
+function dbp () {
+  docker build -t $1 ${@:2} && docker push $1
+}
+
+# }}}
+
+# Vagrant {{{
+# }}}
+
+# Twitter! {{{
+export TWITTER_WHOAMI='glittershark1'
+
+
+# favelast <username>
+function favelast() {
+  t fave $(t tl -l $1 | head -n1 | first)
+}
+
+function rtlast() {
+  t rt $(t tl -l $1 | head -n1 | first)
+}
+
+function tthread() {
+  t reply $(t tl -l $TWITTER_WHOAMI | head -n1 | first) $@
+}
+# }}}
+
+# Geeknote {{{
+gnc() {
+  gn create --title $1 --content '' &&
+    gn find --count=1 "$1"
+    gn edit 1
+}
+# }}}
+
+# Systemd aliases {{{
+# }}}
+
+# Misc aliases {{{
+
+function fw() { # fix white
+  local substitution
+  local substitution='s/\x1b\[90m/\x1b[92m/g'
+  $@ > >(perl -pe "$substitution") 2> >(perl -pe "$substitution" 1>&2)
+}
+# }}}
+
+# Grep options {{{
+unset GREP_OPTIONS
+export GREP_OPTIONS=
+# }}}
+
+# Keyboard backlight {{{
+
+KEYBOARD_BRIGHTNESS_FILE='/sys/devices/platform/applesmc.768/leds/smc::kbd_backlight/brightness'
+
+setkbd() {
+  echo $1 | sudo tee $KEYBOARD_BRIGHTNESS_FILE
+}
+
+kbdup() {
+  curr=$(< $KEYBOARD_BRIGHTNESS_FILE)
+  echo $(( $curr + 15 )) | sudo tee $KEYBOARD_BRIGHTNESS_FILE
+}
+
+kbdup() {
+  curr=$(< $KEYBOARD_BRIGHTNESS_FILE)
+  echo $(( $curr - 15 )) | sudo tee $KEYBOARD_BRIGHTNESS_FILE
+}
+
+# }}}
+
+# Run docker containers {{{
+    # -d \
+    # -v $HOME/.pentadactyl:/home/firefox/.pentadactyl:rw \
+    # -v $HOME/.pentadactylrc:/home/firefox/.pentadactylrc:rw \
+    # -v $HOME/.mozilla:/home/firefox/.mozilla:rw \
+    # -v $HOME/.config:/home/firefox/.config \
+    # -v $HOME/Downloads:/home/firefox/Downloads:rw \
+    # -v /etc/fonts:/etc/fonts \
+    # -v /tmp/.X11-unix:/tmp/.X11-unix \
+    # -v /dev/snd:/dev/snd \
+    # --net=host \
+    # -v $XDG_RUNTIME_DIR:$XDG_RUNTIME_DIR \
+    # -e uid=$(id -u) \
+    # -e gid=$(id -g) \
+    # -e DISPLAY=$DISPLAY \
+    # -e XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR \
+    # --name firefox \
+    # --rm -it \
+    # glittershark/firefox
+# }}}
+
+[ -f ./.localrc ] && source ./.localrc
diff --git a/install b/install
new file mode 100755
index 0000000000..bad60db020
--- /dev/null
+++ b/install
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+set -eo pipefail
+
+if [[ -f /etc/nixos/.system-installed ]]; then
+    echo "=== System config already installed, skipping"
+else
+    echo "==> Installing system config"
+
+    [[ -d /etc/nixos ]] && sudo mv /etc/nixos{,.bak}
+    sudo mkdir -p /etc/nixos
+    sudo cp /etc/nixos.bak/hardware-configuration.nix /etc/nixos
+
+    sudo cp ./configuration.nix /etc/nixos/
+    sudo ln -s $(pwd)/{machines,modules,pkgs} /etc/nixos
+    sudo touch /etc/nixos/.system-installed
+
+    nixos-rebuild switch
+    echo "==> System config installed, your old configuration is at /etc/nixos.bak"
+fi
+echo
+
+if [[ -f ~/.config/nixpkgs/system-installed ]]; then
+    echo "=== home-anager config already installed, skipping"
+else
+    echo "==> Installing home-manager config"
+    nix-channel --add https://github.com/rycee/home-manager/archive/master.tar.gz home-manager
+    nix-channel --update
+    nix-shell '<home-manager>' -A install
+
+    [[ -d ~/.config/nixpkgs ]] && mv ~/.config/{nixpkgs,nixpkgs.bak}
+    mkdir -p ~/.config/nixpkgs
+    ln -s home/* ~/.config/nixpkgs
+
+    home-manager switch
+
+    echo "==> home-manager config installed"
+fi
diff --git a/pkgs/alsi/default.nix b/pkgs/alsi/default.nix
new file mode 100644
index 0000000000..d4da8ff38e
--- /dev/null
+++ b/pkgs/alsi/default.nix
@@ -0,0 +1,22 @@
+{ perl, stdenv, fetchFromGitHub }:
+stdenv.mkDerivation {
+  name = "alsi";
+  pname = "alsi";
+  version = "0.4.8";
+
+  src = fetchFromGitHub {
+    owner = "trizen";
+    repo = "alsi";
+    rev = "fe2a925caad38d4cc7afe10d74ba60c5db09ee66";
+    sha256 = "060xlalfclrda5f1h3svj4v2gr19mdrsc62vrg7hgii0f3lib7j5";
+  };
+
+  buildInputs = [
+    (perl.withPackages (ps: with ps; [ DataDump ]))
+  ];
+
+  installPhase = ''
+    mkdir -p $out/bin
+    cp alsi $out/bin/alsi
+  '';
+}
diff --git a/system/configuration.nix b/system/configuration.nix
new file mode 100644
index 0000000000..eae567015b
--- /dev/null
+++ b/system/configuration.nix
@@ -0,0 +1,11 @@
+{ config, pkgs, ... }:
+
+let machine = throw "Pick a machine from ./machines"; in
+{
+  imports =
+    [
+      /etc/nixos/hardware-configuration.nix
+      ./modules/common.nix
+      machine
+    ];
+}
diff --git a/system/machines/bumblebee.nix b/system/machines/bumblebee.nix
new file mode 100644
index 0000000000..a1cd3ffa14
--- /dev/null
+++ b/system/machines/bumblebee.nix
@@ -0,0 +1,21 @@
+{ config, lib, pkgs, ... }:
+{
+  imports = [
+    ../modules/reusable/battery.nix
+  ];
+
+  networking.hostName = "bumblebee";
+
+  powerManagement = {
+    enable = true;
+    cpuFreqGovernor = "powersave";
+    powertop.enable = true;
+  };
+
+  # Hibernate on low battery
+  laptop.onLowBattery = {
+    enable = true;
+    action = "hibernate";
+    thresholdPercentage = 5;
+  };
+}
diff --git a/system/modules/common.nix b/system/modules/common.nix
new file mode 100644
index 0000000000..27f4a73f09
--- /dev/null
+++ b/system/modules/common.nix
@@ -0,0 +1,106 @@
+{ config, lib, pkgs, ... }:
+
+{
+  imports =
+    [
+      ./xserver.nix
+      ./emacs.nix
+      ./sound.nix
+    ];
+
+  boot.loader.systemd-boot.enable = true;
+  boot.loader.efi.canTouchEfiVariables = true;
+
+  networking.hostName = "bumblebee";
+  networking.useDHCP = false;
+  networking.networkmanager.enable = true;
+
+  # Select internationalisation properties.
+  # i18n = {
+  #   consoleFont = "Lat2-Terminus16";
+  #   consoleKeyMap = "us";
+  #   defaultLocale = "en_US.UTF-8";
+  # };
+
+  # Set your time zone.
+  time.timeZone = "America/New_York";
+
+  environment.systemPackages = with pkgs; [
+    wget
+    vim
+    zsh
+    git
+    w3m
+    libnotify
+    file
+  ];
+
+  # Some programs need SUID wrappers, can be configured further or are
+  # started in user sessions.
+  # programs.mtr.enable = true;
+  # programs.gnupg.agent = {
+  #   enable = true;
+  #   enableSSHSupport = true;
+  #   pinentryFlavor = "gnome3";
+  # };
+
+  programs.nm-applet.enable = true;
+
+
+  services.openssh.enable = true;
+
+  # Open ports in the firewall.
+  # networking.firewall.allowedTCPPorts = [ ... ];
+  # networking.firewall.allowedUDPPorts = [ ... ];
+  # Or disable the firewall altogether.
+  networking.firewall.enable = false;
+
+  # Enable CUPS to print documents.
+  # services.printing.enable = true;
+
+  users.mutableUsers = true;
+  programs.zsh.enable = true;
+  environment.pathsToLink = [ "/share/zsh" ];
+  users.users.grfn = {
+    isNormalUser = true;
+    initialPassword = "password";
+    extraGroups = [
+      "wheel"  # Enable ‘sudo’ for the user.
+      "networkmanager"
+      "audio"
+    ];
+    shell = pkgs.zsh;
+  };
+
+  # This value determines the NixOS release from which the default
+  # settings for stateful data, like file locations and database versions
+  # on your system were taken. It‘s perfectly fine and recommended to leave
+  # this value at the release version of the first install of this system.
+  # Before changing this value read the documentation for this option
+  # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
+  system.stateVersion = "20.03"; # Did you read the comment?
+
+  nixpkgs.config.allowUnfree = true;
+
+  fonts.fonts = with pkgs; [
+    nerdfonts
+  ];
+
+  services.geoclue2.enable = true;
+
+  powerManagement = {
+    enable = true;
+    cpuFreqGovernor = "powersave";
+    powertop.enable = true;
+  };
+  # Hibernate on low battery
+  laptop.onLowBattery = {
+    enable = true;
+    action = "hibernate";
+    thresholdPercentage = 5;
+  };
+
+  nix = {
+    autoOptimiseStore = true;
+  };
+}
diff --git a/system/modules/emacs.nix b/system/modules/emacs.nix
new file mode 100644
index 0000000000..1cfa2b0745
--- /dev/null
+++ b/system/modules/emacs.nix
@@ -0,0 +1,23 @@
+{ config, pkgs, lib, ... }:
+with lib;
+{
+  options.programs.emacs.useGit = mkOption {
+    description = "Use emacs from git";
+    type = types.bool;
+    default = false;
+  };
+
+  config = {
+    nixpkgs.overlays = if config.programs.emacs.useGit then [] else [
+      (import (builtins.fetchTarball https://github.com/nix-community/emacs-overlay/archive/master.tar.gz))
+    ];
+
+    environment.systemPackages = with pkgs; [
+      (if config.programs.emacs.useGit then emacsGit else emacs)
+      ripgrep
+      coreutils
+      fd
+      clang
+    ];
+  };
+}
diff --git a/system/modules/reusable/README.org b/system/modules/reusable/README.org
new file mode 100644
index 0000000000..34d9bfdcb7
--- /dev/null
+++ b/system/modules/reusable/README.org
@@ -0,0 +1,2 @@
+This directory contains things I'm eventually planning on contributing upstream
+to nixpkgs
diff --git a/system/modules/reusable/battery.nix b/system/modules/reusable/battery.nix
new file mode 100644
index 0000000000..d7043bf549
--- /dev/null
+++ b/system/modules/reusable/battery.nix
@@ -0,0 +1,32 @@
+{ config, lib, pkgs, ... }:
+with lib;
+{
+  options = {
+    laptop.onLowBattery = {
+      enable = mkEnableOption "Perform action on low battery";
+
+      thresholdPercentage = mkOption {
+        description = "Threshold battery percentage on which to perform the action";
+        default = 5;
+        type = types.int;
+      };
+
+      action = mkOption {
+        description = "Action to perform on low battery";
+        default = "hibernate";
+        type = types.enum [ "hibernate" "suspend" "suspend-then-hibernate" ];
+      };
+    };
+  };
+
+  config =
+    let cfg = config.laptop.onLowBattery;
+    in mkIf cfg.enable {
+    services.udev.extraRules = concatStrings [
+      ''SUBSYSTEM=="power_supply", ''
+      ''ATTR{status}=="Discharging", ''
+      ''ATTR{capacity}=="[0-${toString cfg.thresholdPercentage}]", ''
+      ''RUN+="/${pkgs.systemd}/bin/systemctl ${cfg.action}"''
+    ];
+  };
+}
diff --git a/system/modules/sound.nix b/system/modules/sound.nix
new file mode 100644
index 0000000000..0d5ce3e318
--- /dev/null
+++ b/system/modules/sound.nix
@@ -0,0 +1,14 @@
+{ config, lib, pkgs, ... }:
+{
+  # Enable sound.
+  sound.enable = true;
+  hardware.pulseaudio.enable = true;
+  nixpkgs.config.pulseaudio = true;
+
+  environment.systemPackages = with pkgs; [
+    pulseaudio-ctl
+    paprefs
+    pasystray
+    pavucontrol
+  ];
+}
diff --git a/system/modules/xserver.nix b/system/modules/xserver.nix
new file mode 100644
index 0000000000..52f04e2e6a
--- /dev/null
+++ b/system/modules/xserver.nix
@@ -0,0 +1,19 @@
+{ config, pkgs, ... }:
+{
+  # Enable the X11 windowing system.
+  services.xserver = {
+    enable = true;
+    layout = "us";
+    xkbOptions = "caps:swapescape";
+
+    libinput.enable = true;
+
+    windowManager.i3 = {
+      enable = true;
+      extraPackages = with pkgs; [
+        i3status
+        i3lock
+      ];
+    };
+  };
+}