about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--+bindings.el151
-rw-r--r--+commands.el28
-rw-r--r--clocked-in-elt.el18
-rw-r--r--company-sql.el47
-rw-r--r--config.el732
-rw-r--r--init.el185
-rw-r--r--nix-yapf-mode.el21
-rw-r--r--org-alerts.el188
-rw-r--r--org-config.el91
-rw-r--r--org-query.el96
-rw-r--r--packages.el73
-rw-r--r--show-matching-paren.el61
-rw-r--r--slack-snippets.el35
-rw-r--r--snippets/haskell-mode/hlint8
-rw-r--r--snippets/nix-mode/fetchFromGitHub12
-rw-r--r--snippets/nix-mode/pythonPackage16
-rw-r--r--snippets/nix-mode/sha2567
-rw-r--r--snippets/org-mode/combat13
-rw-r--r--snippets/org-mode/reveal6
-rw-r--r--snippets/python-mode/decorate15
-rw-r--r--snippets/python-mode/name7
-rw-r--r--snippets/python-mode/pdb7
-rw-r--r--sql-strings.el75
-rw-r--r--themes/grfn-solarized-light-theme.el72
24 files changed, 1535 insertions, 429 deletions
diff --git a/+bindings.el b/+bindings.el
index af54d84086..875d298d42 100644
--- a/+bindings.el
+++ b/+bindings.el
@@ -304,7 +304,11 @@ private/hlissner/snippets."
      :desc "Git grep"              :n  "g" #'counsel-git-grep
      :desc "Checkout Branch"       :n  "c" #'counsel-git-checkout
      :desc "Next hunk"             :nv "]" #'git-gutter:next-hunk
-     :desc "Previous hunk"         :nv "[" #'git-gutter:previous-hunk)
+     :desc "Previous hunk"         :nv "[" #'git-gutter:previous-hunk
+
+     (:desc "smerge" :prefix "m"
+       :desc "Keep Current" :n "SPC" #'smerge-keep-current
+       :desc "Keep All"     :n "a" #'smerge-keep-all))
 
    (:desc "help" :prefix "h"
      :n "h" help-map
@@ -344,6 +348,7 @@ private/hlissner/snippets."
      :desc "Goto clocked-in note"   :n  "g" #'org-clock-goto
      :desc "Clock Out"              :n  "o" #'org-clock-out)
 
+
    (:desc "open" :prefix "o"
      :desc "Default browser"       :n  "b" #'browse-url-of-file
      :desc "Debugger"              :n  "d" #'+debug/open
@@ -356,9 +361,10 @@ private/hlissner/snippets."
      :desc "Slack Group"           :n  "g" #'slack-group-select
      :desc "Slack Unreads"         :n  "u" #'slack-select-unread-rooms
 
+     :desc "Email"                 :n "m" #'mu4e
+
      ;; applications
      :desc "APP: elfeed"           :n "E" #'=rss
-     :desc "APP: email"            :n "M" #'=email
      :desc "APP: twitter"          :n "T" #'=twitter
      :desc "APP: regex"            :n "X" #'=regex
 
@@ -376,6 +382,12 @@ private/hlissner/snippets."
        :desc "Send to Launchbar"         :n "l" #'+macos/send-to-launchbar
        :desc "Send project to Launchbar" :n "L" #'+macos/send-project-to-launchbar))
 
+   (:desc "Email" :prefix "M"
+     :desc "Compose" :n "m" #'mu4e-compose-new
+     :desc "Update"  :n "u" #'mu4e-update-mail-and-index
+     :desc "Sync"    :n "s" #'mu4e-update-mail-and-index
+     :desc "Open"    :n "o" #'mu4e)
+
    (:desc "project" :prefix "p"
      :desc "Browse project"          :n  "." (find-file-in! (doom-project-root))
      :desc "Find file in project"    :n  "/" #'projectile-find-file
@@ -422,6 +434,9 @@ private/hlissner/snippets."
          (:map dired-mode-map
         "-" #'grfn/dired-minus))
 
+ (:map smartparens-mode-map
+   :n "g o" #'sp-raise-sexp)
+
  ;; --- vim-sexp-mappings-for-regular-people
  (:after paxedit
    (:map paxedit-mode-map
@@ -535,14 +550,13 @@ private/hlissner/snippets."
      [escape]     #'company-search-abort))
 
  ;; counsel
- (:after counsel
-   (:map counsel-ag-map
-     [backtab]  #'+ivy/wgrep-occur      ; search/replace on results
-     "C-SPC"    #'ivy-call-and-recenter ; preview
-     "M-RET"    (+ivy-do-action! #'+ivy-git-grep-other-window-action)))
+;  (:after counsel
+;    (:map counsel-ag-map
+;      [backtab]  #'+ivy/wgrep-occur      ; search/replace on results
+;      "C-SPC"    #'ivy-call-and-recenter ; preview))
 
  ;; evil-commentary
- :n  "gc"  #'evil-commentary
+ ;; :n  "gc"  #'evil-commentary
 
  ;; evil-exchange
  :n  "gx"  #'evil-exchange
@@ -795,10 +809,13 @@ private/hlissner/snippets."
  ;; Haskell
  (:after haskell-mode
    (:map haskell-mode-map
-     :n "K"     #'intero-info
+     ;; :n "K"     #'intero-info
+     :n "K"     #'lsp-describe-thing-at-point
+     ;; :n "g d"   #'lsp-ui-peek-find-definitions
      :n "g d"   #'lsp-ui-peek-find-definitions
-     :n "g SPC" #'intero-repl-load
-     :n "g y"   #'intero-type-at))
+     ;; :n "g SPC" #'intero-repl-load
+     ;; :n "g y"   #'lsp-ui-
+     ))
 
  ;; Javascript
  ;; (:after rjsx-mode
@@ -813,7 +830,8 @@ private/hlissner/snippets."
 
  ;; Elisp
  (:map emacs-lisp-mode-map
-   :n "g SPC" #'eval-buffer)
+   :n "g SPC" #'eval-buffer
+   :n "g RET" (λ! () (ert t)))
 
 
  ;; --- Custom evil text-objects ---------------------
@@ -991,21 +1009,41 @@ private/hlissner/snippets."
 (require 'general)
 (general-evil-setup t)
 
-(nmap :keymaps 'paxedit-mode-map
-      ">" (general-key-dispatch 'evil-shift-right
-            "e" 'paxedit-transpose-forward
-            ")" 'sp-forward-slurp-sexp
-            "(" 'sp-backward-barf-sexp
-            "I" 'grfn/insert-at-sexp-end
-            "a" 'grfn/insert-at-form-end))
-
-(nmap :keymaps 'paxedit-mode-map
-      "<" (general-key-dispatch 'evil-shift-left
-            "e" 'paxedit-transpose-backward
-            ")" 'sp-forward-barf-sexp
-            "(" 'sp-backward-slurp-sexp
-            "I" 'grfn/insert-at-sexp-start
-            "a" 'grfn/insert-at-form-start))
+(nmap
+  ">" (general-key-dispatch 'evil-shift-right
+        "e" 'paxedit-transpose-forward
+        ")" 'sp-forward-slurp-sexp
+        "(" 'sp-backward-barf-sexp
+        "I" 'grfn/insert-at-sexp-end
+        ;; "a" 'grfn/insert-at-form-end
+        ))
+
+(nmap
+  "<" (general-key-dispatch 'evil-shift-left
+        "e" 'paxedit-transpose-backward
+        ")" 'sp-forward-barf-sexp
+        "(" 'sp-backward-slurp-sexp
+        "I" 'grfn/insert-at-sexp-start
+        ;; "a" 'grfn/insert-at-form-start
+        ))
+
+
+(defmacro saving-excursion (&rest body)
+  `(λ! () (save-excursion ,@body)))
+
+(nmap "c" (general-key-dispatch 'evil-change
+            "r c" (saving-excursion (string-inflection-lower-camelcase))
+            "r C" (saving-excursion (string-inflection-camelcase))
+            "r m" (saving-excursion (string-inflection-camelcase))
+            "r s" (saving-excursion (string-inflection-underscore))
+            "r u" (saving-excursion (string-inflection-upcase))
+            "r -" (saving-excursion (string-inflection-kebab-case))
+            "r k" (saving-excursion (string-inflection-kebab-case))
+            ;; "r ." (saving-excursion (string-inflection-dot-case))
+            ;; "r ." (saving-excursion (string-inflection-space-case))
+            ;; "r ." (saving-excursion (string-inflection-title-case))
+            ))
+
 
 (predd-defmulti eval-sexp (lambda (form) major-mode))
 
@@ -1137,7 +1175,7 @@ If invoked with a prefix ARG eval the expression after inserting it"
         "p" (general-key-dispatch 'fireplace-eval
               "p" 'eval-sexp-at-point
               "c" 'eval-last-sexp
-              "d" 'cider-eval-defun-at-point
+              "d" 'eval-defun
               "r" 'cider-test-run-test)
         "x" (general-key-dispatch 'fireplace-eval-context
               "x" 'cider-eval-sexp-at-point-in-context
@@ -1214,10 +1252,21 @@ If invoked with a prefix ARG eval the expression after inserting it"
   (interactive)
   (if (and (org-in-src-block-p)
            (equal direction 'below))
-      (grfn/insert-new-src-block)
+    (grfn/insert-new-src-block)
     (funcall orig direction)))
 
-(advice-add #'+org/insert-item :around #'grfn/+org-insert-item)
+(advice-add #'+org--insert-item :around #'grfn/+org-insert-item)
+;; (advice-add #'+org/insert-item-below :around
+;;             (lambda (orig) (grfn/+org-insert-item orig 'below)))
+
+(defun set-pdb-trace ()
+  (interactive)
+  (end-of-line)
+  (insert (format "\n%simport pdb;pdb.set_trace()"
+                  (make-string (python-indent-calculate-indentation)
+                               ?\s)))
+  (evil-indent (line-beginning-position)
+               (line-end-position)))
 
 (map!
 
@@ -1225,21 +1274,28 @@ If invoked with a prefix ARG eval the expression after inserting it"
    :n "#" 'forge-dispatch)
 
  (:map haskell-mode-map
-   ;; :n "K"     'lsp-info-under-point
-   ;; :n "g d"   'lsp-ui-peek-find-definitions
-   ;; :n "g r"   'lsp-ui-peek-find-references
-   ;; :n "g \\"  '+haskell/repl
-   :n "K"     'intero-info
-   :n "g d"   'intero-goto-definition
-   :n "g SPC" 'intero-repl-load
-   :n "g \\"  'intero-repl
-   :n "g y"   'intero-type-at
+   :n "K"     'lsp-info-under-point
+   :n "g d"   'lsp-ui-peek-find-definitions
+   :n "g r"   'lsp-ui-peek-find-references
+   :n "g \\"  '+haskell/repl
+   ;; :n "K"     'intero-info
+   ;; :n "g d"   'intero-goto-definition
+   ;; :n "g SPC" 'intero-repl-load
+   ;; :n "g \\"  'intero-repl
+   ;; :n "g y"   'intero-type-at
    ;; :n "g RET" 'grfn/run-sputnik-test-for-file
 
    (:localleader
      :desc "Apply action"  :n "e" 'intero-repl-eval-region
      :desc "Rename symbol" :n "r" 'intero-apply-suggestions))
 
+ (:map python-mode-map
+   :n "K" #'anaconda-mode-show-doc
+   :n "g SPC" #'+eval/buffer
+   :n "g RET" #'python-pytest-file
+   :n "g \\" #'+python/open-ipython-repl
+   [remap evil-commentary-yank] #'set-pdb-trace)
+
  (:after agda2-mode
    (:map agda2-mode-map
      :n "g SPC" 'agda2-load
@@ -1249,8 +1305,10 @@ If invoked with a prefix ARG eval the expression after inserting it"
 
      (:localleader
        :desc "Give"                               :n "SPC" 'agda2-give
+       :desc "Case Split"                         :n "c"   'agda2-make-case
+       :desc "Make Helper"                        :n "h"   'agda2-helper-function-type
        :desc "Refine"                             :n "r"   'agda2-refine
-       :desc "Auto"                               :n "a"   'agda2-auto
+       :desc "Auto"                               :n "a"   'agda2-auto-maybe-all
        :desc "Goal type and context"              :n "t"   'agda2-goal-and-context
        :desc "Goal type and context and inferred" :n ";"   'agda2-goal-and-context-and-inferred)))
 
@@ -1296,4 +1354,15 @@ If invoked with a prefix ARG eval the expression after inserting it"
      "M-k" #'org-move-subtree-up
      "M-j" #'org-move-subtree-down
      (:localleader
-       :n "g" #'counsel-org-goto))))
+       :n "g" #'counsel-org-goto))
+
+   (:map org-capture-mode-map
+     :n "g RET" #'org-capture-finalize
+     :n "g \\"  #'org-captue-refile))
+
+ (:after lsp
+   (:map lsp-mode-map
+     :n "K"   #'lsp-describe-thing-at-point
+     :n "g r" #'lsp-rename
+     (:localleader
+       :n "a" #'lsp-execute-code-action))))
diff --git a/+commands.el b/+commands.el
index 4025a9504a..a5753c8e99 100644
--- a/+commands.el
+++ b/+commands.el
@@ -1,4 +1,4 @@
-;;; private/grfn/+commands.el -*- lexical-binding: t; -*-
+
 
 (defalias 'ex! 'evil-ex-define-cmd)
 
@@ -29,6 +29,8 @@
 (ex! "na[rrow]"     #'+evil:narrow-buffer)
 (ex! "retab"        #'+evil:retab)
 
+(ex! "glog" #'magit-log-buffer-file)
+
 ;; External resources
 ;; TODO (ex! "db"          #'doom:db)
 ;; TODO (ex! "dbu[se]"     #'doom:db-select)
@@ -115,13 +117,31 @@
 ;; Org-mode
 (ex! "cap"         #'+org-capture/dwim)
 
-(ex! "arev" #'generate-alembic-migration)
+(evil-define-command evil-alembic-revision (args)
+  (interactive "<a>")
+  (apply
+   #'generate-alembic-migration
+   (read-string "Message: ")
+   (s-split "\\s+" (or args ""))))
+(ex! "arev[ision]" #'evil-alembic-revision)
 
 (evil-define-command evil-alembic-upgrade (&optional revision)
   (interactive "<a>")
-  (alembic-upgrade revision))
+  (alembic-upgrade (or revision "head")))
+
+(ex! "aup[grade]" #'evil-alembic-upgrade)
+
+(evil-define-command evil-alembic-downgrade (&optional revision)
+  (interactive "<a>")
+  (alembic-downgrade revision))
+
+(ex! "adown[grade]" #'evil-alembic-downgrade)
+
+(evil-define-command evil-alembic (args)
+  (interactive "<a>")
+  (run-alembic args))
 
-(ex! "aup" #'evil-alembic-upgrade)
+(ex! "alemb[ic]" #'evil-alembic)
 
 ;; Elixir
 (add-hook! elixir-mode
diff --git a/clocked-in-elt.el b/clocked-in-elt.el
new file mode 100644
index 0000000000..00fda047e4
--- /dev/null
+++ b/clocked-in-elt.el
@@ -0,0 +1,18 @@
+;;; ~/.doom.d/clocked-in-elt.el -*- lexical-binding: t; -*-
+;;;
+(load (expand-file-name "init" (or (getenv "EMACSDIR")
+               (expand-file-name
+                "../.emacs.d"
+                (file-name-directory (file-truename load-file-name))))))
+
+(require 'org-clock)
+(require 'org-element)
+
+(let ((item (or org-clock-marker
+                (car org-clock-history))))
+  (when item
+    (with-current-buffer (marker-buffer item)
+      (goto-char (marker-position item))
+      (let ((element (org-element-at-point)))
+        (when (eq 'headline (car element))
+          (message "%s" (plist-get (cadr element) :raw-value)))))))
diff --git a/company-sql.el b/company-sql.el
index 58c57dde80..2408347cef 100644
--- a/company-sql.el
+++ b/company-sql.el
@@ -56,24 +56,26 @@
 ;;; Listing relations
 
 (cl-defun company-sql/list-tables (conn)
-  (-map (-compose 'symbol-name 'car)
-        (emacsql conn
-         [:select [tablename]
-          :from pg_catalog:pg_tables
-          :where (and (!= schemaname '"information_schema")
-                      (!= schemaname '"pg_catalog"))])))
+  (with-timeout (3)
+    (-map (-compose 'symbol-name 'car)
+          (emacsql conn
+                   [:select [tablename]
+                            :from pg_catalog:pg_tables
+                            :where (and (!= schemaname '"information_schema")
+                                        (!= schemaname '"pg_catalog"))]))))
 
 (cl-defun company-sql/list-columns (conn)
-  (-map
-   (lambda (row)
-     (propertize (symbol-name (nth 0 row))
-                 'table-name (nth 1 row)
-                 'data-type  (nth 2 row)))
-   (emacsql conn
-    [:select [column_name
-              table_name
-              data_type]
-     :from information_schema:columns])))
+  (with-timeout (3)
+    (-map
+     (lambda (row)
+       (propertize (symbol-name (nth 0 row))
+                   'table-name (nth 1 row)
+                   'data-type  (nth 2 row)))
+     (emacsql conn
+              [:select [column_name
+                        table_name
+                        data_type]
+                       :from information_schema:columns]))))
 
 ;;; Keywords
 
@@ -195,7 +197,7 @@
    (apply-partially #'s-starts-with? prefix)
    (append (-map (lambda (s)
                    (propertize s 'company-postgresql-annotation "table"))
-                 (company-sql/list-tables conn))
+
            (-map (lambda (s)
                    (propertize s 'company-postgresql-annotation
                                (format "%s.%s %s"
@@ -208,7 +210,7 @@
                  (company-sql/list-columns conn))
            (-map (lambda (s)
                    (propertize s 'company-postgresql-annotation "keyword"))
-                 company-postgresql/keywords))))
+                 company-postgresql/keywords)))))
 
 (defun company-postgresql (command &optional arg &rest _)
   (interactive (list 'interactive))
@@ -230,11 +232,10 @@
   ())
 
 (defun org-company-sql/connect (conn-params)
-  (car                                  ; ???
-   (or (alist-get-equal conn-params org-company-sql/connections)
-       (let ((conn (apply 'emacsql-psql conn-params)))
-         (add-to-list 'org-company-sql/connections (cons conn-params conn))
-         conn))))
+  (or (alist-get-equal conn-params org-company-sql/connections)
+      (let ((conn (apply 'emacsql-psql conn-params)))
+        (add-to-list 'org-company-sql/connections (cons conn-params conn))
+        conn)))
 
 (defun org-company-sql/in-sql-source-block-p ()
   (let ((org-elt (org-element-at-point)))
diff --git a/config.el b/config.el
index b928937623..287d097893 100644
--- a/config.el
+++ b/config.el
@@ -4,17 +4,26 @@
 (setq x-super-keysym 'alt
       x-alt-keysym   'meta)
 
-(setq user-mail-address "root@gws.fyi"
+(setq user-mail-address "griffin@urbint.com"
       user-full-name    "Griffin Smith")
 
-; (def-package-hook! doom-themes :disable)
+(setq doom-font (font-spec :family "Meslo LGSDZ Nerd Font" :size 14)
+      doom-big-font (font-spec :family "Meslo LGSDZ Nerd Font" :size 19)
+      doom-big-font-increment 5
+      doom-variable-pitch-font (font-spec :family "DejaVu Sans")
+      doom-unicode-font (font-spec :family "Meslo LG S DZ"))
 
 (after! rust
-  (setq rust-format-on-save t))
+  ;; (require 'ein)
+  (setq rust-format-on-save t)
+  (add-hook! :after rust-mode-hook #'lsp)
+  (add-hook! :after rust-mode-hook #'rust-enable-format-on-save))
 
 (load! "utils")
-
 (load! "company-sql")
+(load! "org-query")
+(load! "nix-yapf-mode")
+(load! "show-matching-paren")
 
 ; (defconst rust-src-path
 ;   (-> "/Users/griffin/.cargo/bin/rustc --print sysroot"
@@ -30,8 +39,11 @@
 (add-hook! rust-mode
   (flycheck-rust-setup)
   (flycheck-mode)
-  (racer-mode)
-  (cargo-minor-mode))
+  (cargo-minor-mode)
+  (lsp)
+  (rust-enable-format-on-save)
+  (map! :map rust-mode-map
+        "C-c C-f" #'rust-format-buffer))
 
 (add-hook! elixir-mode
   (require 'flycheck-credo)
@@ -97,8 +109,9 @@
     (let ((theme (car theme-settings))
           (faces (cadr theme-settings)))
       (if (member theme custom-enabled-themes)
-          (dolist (face faces)
-            (custom-theme-set-faces theme face))))))
+          (progn
+            (dolist (face faces)
+              (custom-theme-set-faces theme face)))))))
 
 (defcustom theme-overrides nil
   "Association list of override faces to set for different custom themes.")
@@ -107,12 +120,23 @@
   "Set VALUE of a KEY in ALIST-SYMBOL."
   (set alist-symbol (cons (list key value) (assq-delete-all key (eval alist-symbol)))))
 
+(comment
+ (custom-theme-set-faces 'grfn-solarized-light
+                         `(font-lock-doc-face
+                           ((t (:foreground ,+solarized-s-base1)))))
+
++solarized-s-base1
+(custom-theme-)
+ (custom-face-get-current-spec 'font-lock-doc-face)
+
+ )
+
 (alist-set 'theme-overrides 'grfn-solarized-light
            `((font-lock-doc-face ((t (:foreground ,+solarized-s-base1))))
              (font-lock-preprocessor-face ((t (:foreground ,+solarized-red))))
              (font-lock-keyword-face ((t (:foreground ,+solarized-green :bold nil))))
              (font-lock-builtin-face ((t (:foreground ,+solarized-s-base01
-                                          :bold t))))
+                                                      :bold t))))
 
              (elixir-attribute-face ((t (:foreground ,+solarized-blue))))
              (elixir-atom-face ((t (:foreground ,+solarized-cyan))))
@@ -120,7 +144,10 @@
              (line-number ((t (:background ,+solarized-s-base2 :foreground ,+solarized-s-base1))))
 
              (haskell-operator-face ((t (:foreground ,+solarized-green))))
-             (haskell-keyword-face ((t (:foreground ,+solarized-cyan))))))
+             (haskell-keyword-face ((t (:foreground ,+solarized-cyan))))
+
+             (org-drawer ((t (:foreground ,+solarized-s-base1
+                              :bold t))))))
 
 (setq solarized-use-variable-pitch nil
       solarized-scale-org-headlines nil
@@ -203,15 +230,14 @@
 (defvar +grfn-snippets-dir (expand-file-name "snippets/" +grfn-dir))
 
 ;;
-(when (featurep! :feature evil)
-  (load! "+bindings")
-  (load! "+commands"))
+(load! "+bindings")
+(load! "+commands")
 
 (load! "+private")
 
 (require 'dash)
 
-(def-package! predd)
+(use-package! predd)
 
 
 ;;
@@ -238,14 +264,6 @@
   (sp-pair "[" nil :post-handlers '(("| " " "))
            :unless '(sp-point-before-word-p sp-point-before-same-p)))
 
-;; feature/evil
-(after! evil-mc
-  ;; Make evil-mc resume its cursors when I switch to insert mode
-  (add-hook! 'evil-mc-before-cursors-created
-    (add-hook 'evil-insert-state-entry-hook #'evil-mc-resume-cursors nil t))
-  (add-hook! 'evil-mc-after-cursors-deleted
-    (remove-hook 'evil-insert-state-entry-hook #'evil-mc-resume-cursors t)))
-
 ;; feature/snippets
 (after! yasnippet
   ;; Don't use default snippets, use mine.
@@ -257,44 +275,36 @@
   (setq company-idle-delay 0.2
         company-minimum-prefix-length 1))
 
-(setq +doom-modeline-height 10)
-
-;; lang/org
-;; (after! org-bullets
-;;   ;; The standard unicode characters are usually misaligned depending on the
-;;   ;; font. This bugs me. Personally, markdown #-marks for headlines are more
-;;   ;; elegant, so we use those.
-;;   (setq org-bullets-bullet-list '("#")))
-
-;; (defmacro faces! (mode &rest forms)
-;;   (let ((hook-name (-> mode symbol-name (concat "-hook"))))
-;;     (if-let ((hook-sym (intern-soft hook-name)))
-;;         `(add-hook! ,hook-sym
-;;            (message "HELLO I AM MACRO TIME")
-;;            ,@(->
-;;               forms
-;;               (seq-partition 2)
-;;               (->> (seq-map
-;;                     (lambda (pair)
-;;                       (let ((face  (car pair))
-;;                             (color (cadr pair)))
-;;                         `(set-face-foreground ,face ,color)))))))
-;;       (warn "Hook name %s (for mode %s) does not exist as symbol!"
-;;             (hook-name)
-;;             (symbol-name mode)))))
-
-(def-package! org-clubhouse
+(setq doom-modeline-height 12)
+
+(load "/home/griffin/code/org-clubhouse/org-clubhouse.el")
+(use-package! org-clubhouse
   :config
   (setq org-clubhouse-state-alist
         '(("PROPOSED" . "Proposed")
           ("BACKLOG"  . "Backlog")
           ("TODO"     . "Scheduled")
           ("ACTIVE"   . "In Progress")
-          ("PR"       . "In Review")
-          ("TESTING"  . "In Testing")
-          ("DONE"     . "Completed"))))
+          ("PR"       . "Peer Review")
+          ("TESTING"  . "Stakeholder Review")
+          ("DONE"     . "Completed"))
+        org-clubhouse-username "griffin"
+        org-clubhouse-claim-story-on-status-update
+        '("ACTIVE" "PR" "TESTING" "DONE")
+        org-clubhouse-create-stories-with-labels 'existing
+        org-clubhouse-workflow-name "Urbint")
+
+  (defun grfn/sprint-tasks ()
+    (interactive)
+    (find-file "/home/griffin/notes/work.org")
+    (goto-char 1)
+    (search-forward "* Sprint Tasks")
+    (goto-eol) (insert-char ?\n)
+    (org-clubhouse-headlines-from-query
+     2
+     "owner:griffin state:Scheduled")))
+
 
-; (require 'doom-themes)
 
 ;; Should really figure out which of these is correct, eventually
 
@@ -369,96 +379,31 @@
   (setq evil-shift-width 2))
 
 (after! org
-  (setq
-   org-directory (expand-file-name "~/notes")
-   +org-dir (expand-file-name "~/notes")
-   org-default-notes-file (concat org-directory "/inbox.org")
-   +org-default-todo-file (concat org-directory "/inbox.org")
-   org-agenda-files (list (expand-file-name "~/notes"))
-   org-refile-targets '((org-agenda-files :maxlevel . 3))
-   org-outline-path-complete-in-steps nil
-   org-refile-use-outline-path t
-   org-file-apps `((auto-mode . emacs)
-                   (,(rx (or (and "." (optional "x") (optional "htm") (optional "l") buffer-end)
-                             (and buffer-start "http" (optional "s") "://")))
-                    . "firefox %s")
-                   (,(rx ".pdf" buffer-end) . "apvlv %s")
-                   (,(rx "." (or "png"
-                                 "jpg"
-                                 "jpeg"
-                                 "gif"
-                                 "tif"
-                                 "tiff")
-                         buffer-end)
-                    . "feh %s"))
-   org-log-done 'time
-   org-archive-location "~/notes/trash::* From %s"
-   org-cycle-separator-lines 2
-   org-hidden-keywords '(title)
-   org-tags-column -130
-   org-ellipsis "⤵"
-   org-imenu-depth 9
-   org-capture-templates
-   `(("t" "Todo" entry
-      (file+headline +org-default-todo-file "Inbox")
-      "* TODO %?\n%i"
-      :prepend t
-      :kill-buffer t)
-
-     ("n" "Notes" entry
-      (file+headline +org-default-notes-file "Inbox")
-      "* %U %?\n%i"
-      :prepend t
-      :kill-buffer t)
-
-     ("c" "Task note" entry
-      (clock)
-      "* %U %?\n%i[[%l][Context]]\n"
-      :kill-buffer t
-      :unnarrowed t)
-
-     ("d" "Tech debt" entry
-      (file+headline ,(concat org-directory "/work.org")
-                     "Inbox")
-      "* TODO %? :debt:\nContext: %a\nIn task: %K"
-      :prepend t
-      :kill-buffer t))
-   org-deadline-warning-days 1
-   org-agenda-skip-scheduled-if-deadline-is-shown 'todo
-   org-agenda-custom-commands
-   '(("p" "Sprint Tasks" tags-todo "sprint")
-     ("i" "Inbox" tags "inbox")
-     ("r" "Running jobs" todo "RUNNING")
-     ("w" "@Work" tags-todo "@work")))
+  (load! "org-config")
 
   (set-face-foreground 'org-block +solarized-s-base00)
   (add-hook! org-mode
     (add-hook! evil-normal-state-entry-hook
       #'org-align-all-tags))
+  (add-hook 'org-mode-hook (lambda () (display-line-numbers-mode -1)))
+  (setq whitespace-global-modes '(not org-mode magit-mode))
   (setf (alist-get 'file org-link-frame-setup) 'find-file-other-window)
   (set-face-foreground 'org-block +solarized-s-base00)
-  )
+
+  (add-hook! org-mode
+    (set-company-backend! 'org-mode
+      '(:separate company-ob-postgresql
+                  company-dabbrev
+                  company-yasnippet
+                  company-ispell))))
 
 (after! magit
   (setq git-commit-summary-max-length 50))
 
-;; (def-package! forge
-;;   :after magit)
-
-(comment
-
- (string-match-p "(?!foo).*" "bar")
- )
-
 (after! ivy
   (setq ivy-re-builders-alist
         '((t . ivy--regex-fuzzy))))
 
-(setq doom-font (font-spec :family "Meslo LGSDZ Nerd Font" :size 14)
-      doom-big-font (font-spec :family "Meslo LGSDZ Nerd Font" :size 19)
-      doom-variable-pitch-font (font-spec :family "DejaVu Sans")
-      doom-unicode-font (font-spec :family "Meslo LG S DZ"))
-
 (add-hook 'before-save-hook 'delete-trailing-whitespace)
 
 (after! paxedit
@@ -478,11 +423,11 @@
 
 
 (add-hook! haskell-mode
-  (intero-mode)
-  ;; (lsp-mode)
-  (flycheck-add-next-checker
-   'intero
-   'haskell-hlint)
+  ;; (intero-mode)
+  (lsp-mode)
+  ;; (flycheck-add-next-checker
+  ;;  'intero
+  ;;  'haskell-hlint)
   (set-fill-column 80)
   (setq evil-shift-width 2))
 
@@ -491,13 +436,6 @@
 
 (load! "slack-snippets")
 
-(after! magit
-  ;; (require 'evil-magit)
-  ;; (require 'magithub)
-  )
-
-; (require 'auth-password-store)
-; (auth-pass-enable)
 (auth-source-pass-enable)
 
 (require 'fill-column-indicator)
@@ -522,37 +460,6 @@
     (turn-on-fci-mode)))
 
 
-;; https://github.com/alpaker/Fill-Column-Indicator/issues/67#issuecomment-195611974
-;; (add-hook 'prog-mode-hook #'fci-mode)
-;; (after! fill-column-indicator
-;;   (add-hook 'prog-mode-hook #'fci-mode)
-;;   (defvar eos/fci-disabled nil)
-;;   (make-variable-buffer-local 'eos/fci-disabled)
-
-;;   ;; Add a hook that disables fci if enabled when the window changes and it
-;;   ;; isn't wide enough to display it.
-;;   (defun eos/maybe-disable-fci ()
-;;     (interactive)
-;;     ;; Disable FCI if necessary
-;;     (when (and fci-mode
-;;                (< (window-width) (or fci-rule-column fill-column)))
-;;       (fci-mode -1)
-;;       (setq-local eos/fci-disabled t))
-;;     ;; Enable FCI if necessary
-;;     (when (and eos/fci-disabled
-;;                (eq fci-mode nil)
-;;                (> (window-width) (or fci-rule-column fill-column)))
-;;       (fci-mode 1)
-;;       (setq-local eos/fci-disabled nil)))
-
-;;   (defun eos/add-fci-disabling-hook ()
-;;     (interactive)
-;;     (add-hook 'window-configuration-change-hook
-;;               #'eos/maybe-disable-fci))
-
-;;   (add-hook 'prog-mode-hook #'eos/add-fci-disabling-hook))
-
-
 ;;; Javascript
 
 (require 'smartparens)
@@ -657,6 +564,11 @@
 (setq projectile-create-missing-test-files 't)
 
 (after! magit
+  (map! :map magit-mode-map
+        ;; :n "] ]" #'magit-section-forward
+        ;; :n "[ [" #'magit-section-backward
+        )
+
   (define-suffix-command magit-commit-wip ()
     (interactive)
     (magit-commit-create '("-m" "wip")))
@@ -664,7 +576,50 @@
   (transient-append-suffix
     #'magit-commit
     ["c"]
-    (list "W" "Commit WIP" #'magit-commit-wip)))
+    (list "W" "Commit WIP" #'magit-commit-wip))
+
+  (define-suffix-command magit-reset-head-back ()
+    (interactive)
+    (magit-reset-mixed "HEAD~"))
+
+  (define-suffix-command magit-reset-head-previous ()
+    (interactive)
+    (magit-reset-mixed "HEAD@{1}"))
+
+  (transient-append-suffix
+    #'magit-reset
+    ["f"]
+    (list "b" "Reset HEAD~"    #'magit-reset-head-back))
+  (transient-append-suffix
+    #'magit-reset
+    ["f"]
+    (list "o" "Reset HEAD@{1}" #'magit-reset-head-previous))
+
+  (defun magit-read-org-clubhouse-branch-args ()
+    (if-let ((story-id (org-clubhouse-clocked-in-story-id)))
+        (let ((start-point (magit-read-starting-point
+                            "Create and checkout branch for Clubhouse story"
+                            nil
+                            "origin/master")))
+          (if (magit-rev-verify start-point)
+              (let ((desc (magit-read-string-ns
+                           (format "Story description (to go after gs/ch%d/)"
+                                   story-id))))
+                (list
+                 (format "gs/ch%d/%s" story-id desc)
+                 start-point))
+            (user-error "Not a valid starting point: %s" choice)))
+      (user-error "No currently clocked-in clubhouse story")))
+
+  (define-suffix-command magit-checkout-org-clubhouse-branch (branch start-point)
+    (interactive (magit-read-org-clubhouse-branch-args))
+    (magit-branch-and-checkout branch start-point))
+
+  (transient-append-suffix
+    #'magit-branch
+    ["c"]
+    (list "C" "Checkout Clubhouse branch" #'magit-checkout-org-clubhouse-branch))
+  )
 
 ;; (defun grfn/split-window-more-sensibly (&optional window)
 ;;   (let ((window (or window (selected-window))))
@@ -686,54 +641,104 @@
 ;;                  (with-selected-window window
 ;;                    (split-window-below))))))))
 
-;; (def-package! lsp-mode
-;;   :after (:any haskell-mode)
-;;   :config
-;;   (lsp-mode)
-;;   (setq lsp-project-whitelist '("^/home/griffin/code/urb/grid/$")
-;;         lsp-response-timeout 60)
-;;   :hook
-;;   (haskell-mode . lsp-mode))
-
-;; (def-package! lsp-ui
-;;   :after lsp-mode
-;;   :config
-;;   (setq lsp-ui-flycheck-enable t)
-;;   (setq imenu-auto-rescan t)
-;;   (set-face-background 'lsp-ui-doc-background +solarized-s-base2)
-;;   (set-face-background 'lsp-face-highlight-read +solarized-s-base2)
-;;   (set-face-background 'lsp-face-highlight-write +solarized-s-base2)
-;;   :hook
-;;   (lsp-mode . lsp-ui-mode)
-;;   (lsp-ui-mode . flycheck-mode))
-
-;; (def-package! company-lsp
-;;   :after (lsp-mode lsp-ui)
-;;   :config
-;;   (setq company-backends '(company-lsp))
-;;   (setq company-lsp-async t))
+(use-package! lsp-mode
+  :after (:any haskell-mode)
+  :config
+  (lsp-mode)
+  (setq lsp-response-timeout 60)
+  :hook
+  (haskell-mode . lsp-mode))
 
-;; (def-package! lsp-haskell
-;;   :after (lsp-mode lsp-ui haskell-mode)
-;;   :hook
-;;   (haskell-mode . lsp-haskell-enable)
-;;   :config
-;;   (setq lsp-haskell-process-path-hie "/home/griffin/.local/bin/hie-wrapper"
-;;         lsp-haskell-process-args-hie
-;;           '("-d" "-l" "/tmp/hie.log" "+RTS" "-M4G" "-H1G" "-K4G" "-A16M" "-RTS"
-;;             "--lsp")))
+(use-package! lsp-ui
+  :after lsp-mode
+  :config
+  (defun +grfn/lsp-ui-doc-frame-hook (frame window)
+    (set-frame-font (if doom-big-font-mode doom-big-font doom-font)
+                    nil (list frame)))
+  (setq lsp-ui-flycheck-enable t
+        lsp-ui-doc-header nil
+        lsp-ui-doc-position 'top
+        lsp-ui-doc-alignment 'window
+        lsp-ui-doc-frame-hook '+grfn/lsp-ui-doc-frame-hook)
+  (setq imenu-auto-rescan t)
+  (set-face-background 'lsp-ui-doc-background +solarized-s-base2)
+  (set-face-background 'lsp-face-highlight-read +solarized-s-base2)
+  (set-face-background 'lsp-face-highlight-write +solarized-s-base2)
+  :hook
+  (lsp-mode . lsp-ui-mode)
+  (lsp-ui-mode . flycheck-mode))
+
+(use-package! company-lsp
+  :after (lsp-mode lsp-ui)
+  :config
+  ;; (setq company-backends '(company-lsp))
+  (setq company-lsp-async t))
+
+(use-package! lsp-treemacs
+  :config
+  (map! :map lsp-mode-map
+        (:leader
+          "c X" #'lsp-treemacs-errors-list)))
+
+(use-package! dap-mode)
+
+(defun +grfn/haskell-mode-setup ()
+  (interactive)
+  (flymake-mode -1)
+  ;; If there’s a 'hie.sh' defined locally by a project
+  ;; (e.g. to run HIE in a nix-shell), use it…
+  (let ((hie-directory (locate-dominating-file default-directory "hie.sh")))
+    (when hie-directory
+      (setq-local lsp-haskell-process-path-hie (expand-file-name "hie.sh" hie-directory))
+      (setq-local
+       haskell-hoogle-command
+       (s-trim
+        (shell-command-to-string
+         (concat
+          "nix-shell " (expand-file-name "shell.nix" hie-directory)
+          " --run \"which hoogle\" 2>/dev/null"))))))
+  ;; … and only then setup the LSP.
+  (lsp))
+
+(defun never-flymake-mode (orig &rest args)
+  (when (and (bound-and-true-p flymake-mode))
+    (funcall orig 0)
+    (message "disabled flymake-mode")))
+(advice-add #'flymake-mode :around #'never-flymake-mode)
+
+(use-package! lsp-haskell
+  :after (lsp-mode lsp-ui haskell-mode)
+  ;; :hook
+  ;; (haskell-mode . lsp-haskell-enable)
+  :config
+  (add-hook 'haskell-mode-hook #'+grfn/haskell-mode-setup 't)
+  (setq lsp-haskell-process-path-hie "/home/griffin/.nix-profile/bin/hie-8.6.5"
+        lsp-haskell-process-args-hie
+        '("-d" "-l" "/tmp/hie.log" "+RTS" "-M4G" "-H1G" "-K4G" "-A16M" "-RTS")))
 
-;; (def-package! lsp-imenu
-;;   :after (lsp-mode lsp-ui)
-;;   :hook
-;;   (lsp-after-open . lsp-enable-imenu))
+(use-package! lsp-imenu
+  :after (lsp-mode lsp-ui)
+  :hook
+  (lsp-after-open . lsp-enable-imenu))
+
+;; (use-package! counsel-etags
+;;   :ensure t
+;;   :init
+;;   (add-hook 'haskell-mode-hook
+;;             (lambda ()
+;;               (add-hook 'after-save-hook
+;;                         'counsel-etags-virtual-update-tags 'append 'local)))
+;;   :config
+;;   (setq counsel-etags-update-interval 60)
+;;   ;; (push "build" counsel-etags-ignore-directories)
+;;   )
 
-(def-package! evil-magit
+(use-package! evil-magit
   :after (magit))
 
-(def-package! writeroom-mode)
+(use-package! writeroom-mode)
 
-(def-package! graphql-mode)
+(use-package! graphql-mode)
 
 (require 'whitespace)
 (setq whitespace-style '(face lines-tail))
@@ -867,7 +872,7 @@
     (before 1)
     (it 2)))
 
-(def-package! flycheck-clojure
+(use-package! flycheck-clojure
   ;; :disabled t
   :after (flycheck cider)
   :config
@@ -883,54 +888,67 @@
    'cljr-magic-require-namespaces
    '("s" . "clojure.spec.alpha")))
 
-(def-package! sqlup-mode
+(use-package! sqlup-mode
   :hook
   (sql-mode-hook . sqlup-mode)
   (sql-interactive-mode-hook . sqlup-mode))
 
-(def-package! emacsql)
-(def-package! emacsql-psql
+(use-package! emacsql)
+(use-package! emacsql-psql
   :after (emacsql))
 
-(def-package! yapfify
-  :hook
-  (python-mode-hook . yapf-mode))
+(use-package! pyimport
+  :after (python))
 
-(def-package! w3m
-  :hook
-  (setq browse-url-browser-function 'w3m-browse-url))
+(use-package! yapfify
+  :after (python)
+  :init
+  (add-hook! python-mode #'yapf-mode))
 
-(def-package! ob-http
+(use-package! w3m
+  :config
+  (setq browse-url-browser-function
+        `(("^https://app.clubhouse.io.*" . browse-url-firefox)
+          ("^https://github.com.*" . browse-url-firefox)
+          (".*" . browse-url-firefox))))
+
+(use-package! ob-http
   :config
   (add-to-list 'org-babel-load-languages '(http . t)))
 
-(def-package! ob-ipython
+(use-package! ob-ipython
+  :after (pyimport)
   :config
   (add-to-list 'org-babel-load-languages '(ipython . t))
   (setq ob-ipython-command
         "/home/griffin/code/urb/ciml-video-classifier/bin/jupyter"))
 
-(def-package! counsel-spotify)
+(use-package! counsel-spotify)
+
+(after! counsel
+  (map! [remap counsel-org-capture] #'org-capture
+        [remap org-capture] #'org-capture))
 
-(def-package! evil-snipe :disabled t)
+(use-package! evil-snipe :disabled t)
 (evil-snipe-mode -1)
 
-(def-package! rainbow-mode)
+(use-package! rainbow-mode)
 
-(def-package! org-alert
+(use-package! org-alert
+  :disabled t
   :config
   (org-alert-enable)
   (setq alert-default-style 'libnotify
         org-alert-headline-title "org"))
 
-(def-package! ob-async)
+(use-package! ob-async)
 
-(def-package! org-recent-headings
+(use-package! org-recent-headings
   :after (org)
   :config
   (map! :n "SPC n r" #'org-recent-headings-ivy))
 
-(def-package! org-sticky-header
+(use-package! org-sticky-header
   :after (org)
   :hook (org-mode-hook . org-sticky-header-mode)
   :config
@@ -955,11 +973,13 @@
   "Reference to a function whose return value will be used as the directory to
   run Alembic in")
 
-(comment
- (+grfn/extract-alembic-migration-name
-   "Generating
-/home/griffin/code/urb/grid/backend/src/grid/migrations/versions/15fb1b518507_test.py
-... done"))
+(put 'alembic-command 'safe-local-variable (lambda (_) t))
+(put 'alembic-dir-fun 'safe-local-variable (lambda (_) t))
+
+(defun make-alembic-command (args)
+  (if (functionp alembic-command)
+      (funcall alembic-command args)
+    (concat alembic-command " " args)))
 
 (defun +grfn/extract-alembic-migration-name (output)
   (string-match (rx (0+ anything) "Generating "
@@ -969,19 +989,227 @@
                 output)
   (match-string-no-properties 1 output))
 
-(defun generate-alembic-migration (msg)
-  (interactive "sMessage: ")
+(defun -run-alembic (args)
   (let* ((default-directory (funcall alembic-dir-fun))
-         (out (shell-command-to-string
-               (format "%s revision -m \"%s\""
-                       alembic-command
-                       msg)))
-         (migration-name (+grfn/extract-alembic-migration-name out)))
-    (find-file-other-window migration-name)))
-
-(defun alembic-upgrade (&optional revision)
+         (command (make-alembic-command args))
+         ;; (format "nix-shell --run 'alembic %s'" args)
+         ;; (format "%s %s" alembic-command args)
+         (res
+          (with-temp-buffer
+            (cons
+             (shell-command command t)
+             (s-replace-regexp
+              "^.*Nix search path entry.*$" ""
+              (buffer-string)))))
+         (exit-code (car res))
+         (out (cdr res)))
+    ;; (if (= 0 exit-code)
+    ;;     out
+    ;;   (error "Error running %s: %s" command out))
+    out
+    ))
+
+(comment
+ --exit-code
+ --bs
+ )
+
+(defun run-alembic (args)
+  (interactive "sAlembic command: ")
+  (message "%s" (-run-alembic args)))
+
+(defun generate-alembic-migration (msg &rest args)
+  (interactive "sMessage: ")
+  (->
+   (format "revision %s -m \"%s\""
+           (s-join " " args)
+           msg)
+   (-run-alembic)
+   (+grfn/extract-alembic-migration-name)
+   (find-file-other-window)))
+
+(cl-defun alembic-upgrade (&optional revision &key namespace)
+  (interactive "sRevision: ")
   (let ((default-directory (funcall alembic-dir-fun)))
-    (message
-     (shell-command-to-string (format "%s upgrade %s"
-                                      alembic-command
-                                      (or revision "head"))))))
+    (run-alembic (format "%s upgrade %s"
+                         (if namespace (concat "-n " namespace) "")
+                         (or revision "head")))))
+
+(defun alembic-downgrade (revision)
+  (interactive "sRevision: ")
+  (let ((default-directory (funcall alembic-dir-fun)))
+    (run-alembic (format "downgrade %s" (or revision "head")))))
+
+(use-package! gnuplot)
+(use-package! gnuplot-mode :after gnuplot)
+(use-package! string-inflection)
+
+(after! anaconda-mode
+  (set-company-backend! 'anaconda-mode #'company-yasnippet))
+
+;; (add-hook! python-mode
+;;   (capf))
+
+(cl-defstruct pull-request url number title author repository)
+
+(defun grfn/alist->plist (alist)
+  (->> alist
+       (-mapcat (lambda (pair)
+                  (list (intern (concat ":" (symbol-name (car pair))))
+                        (cdr pair))))))
+
+(defun grfn/review-requests ()
+  (let ((resp (ghub-graphql "query reviewRequests {
+    reviewRequests: search(
+      type:ISSUE,
+      query: \"is:open is:pr review-requested:glittershark archived:false\",
+      first: 100
+    ) {
+      issueCount
+      nodes {
+        ... on PullRequest {
+          url
+          number
+          title
+          author {
+            login
+            ... on User { name }
+          }
+          repository {
+            name
+            owner { login }
+          }
+        }
+      }
+    }
+  }")))
+    (->> resp
+         (alist-get 'data)
+         (alist-get 'reviewRequests)
+         (alist-get 'nodes)
+         (-map
+          (lambda (pr)
+            (apply
+             #'make-pull-request
+             (grfn/alist->plist pr)))))))
+
+(defun grfn/pr->org-headline (level pr)
+  (check-type level integer)
+  (check-type pr pull-request)
+  (format "%s TODO Review %s's PR on %s/%s: %s :pr:
+SCHEDULED: <%s>"
+          (make-string level ?*)
+          (->> pr (pull-request-author) (alist-get 'name))
+          (->> pr (pull-request-repository)
+               (alist-get 'owner)
+               (alist-get 'login))
+          (->> pr (pull-request-repository) (alist-get 'name))
+          (org-make-link-string
+           (pull-request-url pr)
+           (pull-request-title pr))
+          (format-time-string "%Y-%m-%d %a")))
+
+(require 'ghub)
+(defun grfn/org-headlines-from-review-requests (level)
+  "Create org-mode headlines at LEVEL from all review-requested PRs on Github"
+  (interactive "*nLevel: ")
+  (let* ((prs (grfn/review-requests))
+         (text (mapconcat (apply-partially #'grfn/pr->org-headline level) prs "\n")))
+    (save-mark-and-excursion
+      (insert text))
+    (org-align-tags 't)))
+
+(comment
+ (require 'ghub)
+
+ (intern (substring (symbol-name :foo) 1))
+
+ ((data (reviewRequests
+         (issueCount . 2)
+         (nodes ((url . "https://github.com/urbint/grid/pull/819")
+                 (number . 819)
+                 (title . "Hector.blanco/ch11498/take storagebucket out of crossbores schema")
+                 (repository (name . "grid")
+                             (owner (login . "urbint"))))
+                ((url . "https://github.com/urbint/ml/pull/32")
+                 (number . 32)
+                 (title . "Quality scoring")
+                 (repository (name . "ml")
+                             (owner (login . "urbint"))))))))
+ )
+
+(defun grfn/num-inbox-items ()
+  (length (org-elements-agenda-match "inbox" t)))
+
+(use-package! dhall-mode
+  :mode "\\.dhall\\'")
+
+(use-package! github-review
+  :after forge)
+
+(after! mu4e
+  (setq sendmail-program "/usr/bin/msmtp"
+        send-mail-function #'smtpmail-send-it
+        message-sendmail-f-is-evil t
+        message-sendmail-extra-arguments '("--read-envelope-from")
+        message-send-mail-function #'message-send-mail-with-sendmail))
+
+(defun grfn/org-add-db-connection-params ()
+  (interactive)
+  (ivy-read
+   "DB to connect to: "
+   (-map (lambda (opts)
+           (propertize (symbol-name (car opts))
+                       'header-args (cdr opts)))
+         db-connection-param-options)
+   :require-match t
+   :action
+   (lambda (opt)
+     (let ((header-args (get-text-property 0 'header-args opt)))
+       (org-set-property "header-args" header-args)))))
+
+(use-package! kubernetes
+  :commands (kubernetes-overview))
+
+(use-package! k8s-mode
+  :hook (k8s-mode . yas-minor-mode))
+
+(use-package! sx)
+
+;; (use-package! nix-update
+;;   :config
+;;   (map! (:map nix-mode-map
+;;           (:leader
+;;             :desc "Update fetcher" :nv #'nix-update-fetch))))
+
+
+(after! lsp-haskell
+  (lsp-register-client
+   (make-lsp--client
+    :new-connection (lsp-stdio-connection (lambda () (lsp-haskell--hie-command)))
+    :major-modes '(haskell-mode)
+    :server-id 'hie
+    ;; :multi-root t
+    ;; :initialization-options 'lsp-haskell--make-init-options
+    )
+   )
+  )
+
+(after! mu4e
+  (setq mu4e-contexts
+        `(,(make-mu4e-context
+            :name "work"
+            :vars
+            '())
+          ,(make-mu4e-context
+            :name "personal"
+            :vars
+            '()))))
+
+(solaire-global-mode -1)
+
+(use-package! wsd-mode)
+
+(use-package! metal-mercury-mode)
+(use-package! flycheck-mercury
+  :after (metal-mercury-mode flycheck-mercury))
diff --git a/init.el b/init.el
index ca4a89069e..1dd0180f87 100644
--- a/init.el
+++ b/init.el
@@ -1,54 +1,45 @@
 ;;; private/grfn/init.el -*- lexical-binding: t; -*-
 
-(doom! :feature
-      ;debugger          ; FIXME stepping through code, to help you add bugs
-       eval              ; run code, run (also, repls)
-       (evil +everywhere); come to the dark side, we have cookies
-       file-templates    ; auto-snippets for empty files
-       (lookup           ; helps you navigate your code and documentation
-        +docsets)        ; ...or in Dash docsets locally
-       snippets          ; my elves. They type so I don't have to
-       spellcheck        ; tasing you for misspelling mispelling
-       syntax-checker    ; tasing you for every semicolon you forget
-       workspaces        ; tab emulation, persistence & separate workspaces
-
-       :completion
-       (company          ; the ultimate code completion backend
-        +auto)           ; as-you-type code completion
-      ;(helm             ; the *other* search engine for love and life
-      ; +fuzzy)          ; enable fuzzy search backend for helm
-      ;ido               ; the other *other* search engine...
-       (ivy              ; a search engine for love and life
-        +fuzzy)          ; enable fuzzy search backend for ivy
+(doom! :completion
+       company           ; the ultimate code completion backend
+       ;;helm              ; the *other* search engine for love and life
+       ;;ido               ; the other *other* search engine...
+       ivy               ; a search engine for love and life
 
        :ui
+       ;;deft              ; notational velocity for Emacs
        doom              ; what makes DOOM look the way it does
-       doom-dashboard    ; a nifty splash screen for Emacs
+       ;doom-dashboard    ; a nifty splash screen for Emacs
        doom-quit         ; DOOM quit-message prompts when you quit Emacs
-       evil-goggles      ; display visual hints when editing in evil
-       fci               ; a `fill-column' indicator
+       ;fill-column       ; a `fill-column' indicator
        hl-todo           ; highlight TODO/FIXME/NOTE tags
+       ;;indent-guides     ; highlighted indent columns
        modeline          ; snazzy, Atom-inspired modeline, plus API
        nav-flash         ; blink the current line after jumping
-      ;neotree           ; a project drawer, like NERDTree for vim
-      ;treemacs          ; a project drawer, like neotree but cooler
+       ;;neotree           ; a project drawer, like NERDTree for vim
+       ophints           ; highlight the region an operation acts on
        (popup            ; tame sudden yet inevitable temporary windows
         +all             ; catch all popups that start with an asterix
         +defaults)       ; default popup rules
        pretty-code       ; replace bits of code with pretty symbols
-      ;tabbar            ; FIXME an (incomplete) tab bar for Emacs
+       ;;tabbar            ; FIXME an (incomplete) tab bar for Emacs
+       ;;treemacs          ; a project drawer, like neotree but cooler
        unicode           ; extended unicode support for various languages
        vc-gutter         ; vcs diff in the fringe
        vi-tilde-fringe   ; fringe tildes to mark beyond EOB
        window-select     ; visually switch windows
+       workspaces        ; tab emulation, persistence & separate workspaces
 
        :editor
-       fold
-       ;; (format +onsave)  ; automated prettiness
+       (evil +everywhere); come to the dark side, we have cookies
+       file-templates    ; auto-snippets for empty files
+       fold              ; (nigh) universal code folding
+       ;;(format +onsave)  ; automated prettiness
        ;;lispy             ; vim for lisp, for people who dont like vim
-       ;;multiple-cursors  ; editing in many places at once
+       multiple-cursors  ; editing in many places at once
        ;;parinfer          ; turn lisp into python, sort of
        rotate-text       ; cycle region at point between text candidates
+       snippets          ; my elves. They type so I don't have to
 
        :emacs
        (dired            ; making dired pretty [functional]
@@ -57,33 +48,40 @@
         )
        electric          ; smarter, keyword-based electric-indent
        ;;eshell            ; a consistent, cross-platform shell (WIP)
-       imenu             ; an imenu sidebar and searchable code index
        ;;term              ; terminals in Emacs
        vc                ; version-control and Emacs, sitting in a tree
 
        :tools
+       ;;ansible
+       ;;debugger          ; FIXME stepping through code, to help you add bugs
+       ;;direnv
        docker
-       editorconfig      ; let someone else argue about tabs vs spaces
-       ein               ; tame Jupyter notebooks with emacs
+       ;;editorconfig      ; let someone else argue about tabs vs spaces
+       ;; ein               ; tame Jupyter notebooks with emacs
+       eval              ; run code, run (also, repls)
        flycheck          ; tasing you for every semicolon you forget
        flyspell          ; tasing you for misspelling mispelling
        gist              ; interacting with github gists
-       lsp
-      ;macos             ; MacOS-specific commands
+       (lookup           ; helps you navigate your code and documentation
+        +docsets)        ; ...or in Dash docsets locally
+       ;;lsp
+       ;;macos             ; MacOS-specific commands
+       magit             ; a git porcelain for Emacs
        make              ; run make tasks from Emacs
-       magit             ;
-       password-store    ; password manager for nerds
+       pass              ; password manager for nerds
        pdf               ; pdf enhancements
-      ;prodigy           ; FIXME managing external services & code builders
-      ;rgb               ; creating color strings
+       ;;prodigy           ; FIXME managing external services & code builders
+       ;;rgb               ; creating color strings
        ;;terraform         ; infrastructure as code
        ;;tmux              ; an API for interacting with tmux
        ;;upload            ; map local to remote projects via ssh/ftp
        ;;wakatime
+       ;;vterm             ; another terminals in Emacs
 
        :lang
+       agda              ; types of types of types of types...
        ;;assembly          ; assembly for fun or debugging
-       ;;(cc +irony +rtags); C/C++/Obj-C madness
+       cc                ; C/C++/Obj-C madness
        clojure           ; java with a lisp
        ;;common-lisp       ; if you've seen one lisp, you've seen them all
        coq               ; proofs-as-programs
@@ -96,25 +94,29 @@
        emacs-lisp        ; drown in parentheses
        ;;ess               ; emacs speaks statistics
        ;;go                ; the hipster dialect
-       (haskell +intero) ; a language that's lazier than I am
+       ;; (haskell +intero) ; a language that's lazier than I am
+       haskell ; a language that's lazier than I am
        ;;hy                ; readability of scheme w/ speed of python
        idris             ;
-       (java +meghanada) ; the poster child for carpal tunnel syndrome
+       ;;(java +meghanada) ; the poster child for carpal tunnel syndrome
        javascript        ; all(hope(abandon(ye(who(enter(here))))))
        julia             ; a better, faster MATLAB
-       ;;latex             ; writing papers in Emacs has never been so fun
+       ;;kotlin            ; a better, slicker Java(Script)
+       latex             ; writing papers in Emacs has never been so fun
        ;;ledger            ; an accounting system in Emacs
        ;;lua               ; one-based indices? one-based indices
        markdown          ; writing docs for people to ignore
        ;;nim               ; python + lisp at the speed of c
-       ;;nix               ; I hereby declare "nix geht mehr!"
-       ocaml             ; an objective camel
+       nix               ; I hereby declare "nix geht mehr!"
+       ;;ocaml             ; an objective camel
        (org              ; organize your plain life in plain text
         +attach          ; custom attachment system
         +babel           ; running code in org
         +capture         ; org-capture in and outside of Emacs
         +export          ; Exporting org to whatever you want
-        +present)        ; Emacs for presentations
+        +habit           ; Keep track of your habits
+        +present         ; Emacs for presentations
+        +protocol)       ; Support for org-protocol:// links
        ;;perl              ; write code no one else can comprehend
        ;;php               ; perl's insecure younger brother
        ;;plantuml          ; diagrams for confusing people more
@@ -129,6 +131,7 @@
        (sh +fish)        ; she sells (ba|z|fi)sh shells on the C xor
        ;;solidity          ; do you need a blockchain? No.
        ;;swift             ; who asked for emoji variables?
+       ;;terra             ; Earth and Moon in alignment for performance.
        ;;web               ; the tubes
        ;;vala              ; GObjective-C
 
@@ -136,25 +139,89 @@
        ;; toward a specific purpose. They may have additional dependencies and
        ;; should be loaded late.
        :app
-      ;(email +gmail)    ; emacs as an email client
+       ;;(email +gmail)    ; emacs as an email client
        irc               ; how neckbeards socialize
-      ;(rss +org)        ; emacs as an RSS reader
-      ;twitter           ; twitter client https://twitter.com/vnought
-      ;(write            ; emacs as a word processor (latex + org + markdown)
-      ; +wordnut         ; wordnet (wn) search
-      ; +langtool)       ; a proofreader (grammar/style check) for Emacs
+       ;;(rss +org)        ; emacs as an RSS reader
+       twitter           ; twitter client https://twitter.com/vnought
+       ;;(write            ; emacs as a word processor (latex + org + markdown)
+       ;; +wordnut         ; wordnet (wn) search
+       ;; +langtool)       ; a proofreader (grammar/style check) for Emacs
+
+       :email
+       (mu4e +gmail)
+       notmuch
 
        :collab
-      ;floobits          ; peer programming for a price
-      ;impatient-mode    ; show off code over HTTP
+       ;;floobits          ; peer programming for a price
+       ;;impatient-mode    ; show off code over HTTP
 
        :config
        ;; For literate config users. This will tangle+compile a config.org
        ;; literate config in your `doom-private-dir' whenever it changes.
-      ;literate
+       ;;literate
 
-       ;; The default module set reasonable defaults for Emacs. It also provides
-       ;; a Spacemacs-inspired keybinding scheme, a custom yasnippet library,
-       ;; and additional ex commands for evil-mode. Use it as a reference for
-       ;; your own modules.
-       (default +bindings +snippets +evil-commands))
+       ;; The default module sets reasonable defaults for Emacs. It also
+       ;; provides a Spacemacs-inspired keybinding scheme and a smartparens
+       ;; config. Use it as a reference for your own modules.
+       (default +bindings +smartparens))
+(custom-set-variables
+ ;; custom-set-variables was added by Custom.
+ ;; If you edit it by hand, you could mess it up, so be careful.
+ ;; Your init file should contain only one such instance.
+ ;; If there is more than one, they won't work right.
+ '(doom-big-font-mode nil)
+ '(flycheck-javascript-flow-args nil)
+ '(org-agenda-files
+   '("/home/griffin/notes/personal.org" "/home/griffin/notes/2020-01-27-data-pipeline-deploy-mismatch.org" "/home/griffin/notes/architecture.org" "/home/griffin/notes/cooking.org" "/home/griffin/notes/culture-survey.org" "/home/griffin/notes/dir-structure.org" "/home/griffin/notes/dnd.org" "/home/griffin/notes/inbox.org" "/home/griffin/notes/misc-todo.org" "/home/griffin/notes/nix-talk.org" "/home/griffin/notes/notes.org" "/home/griffin/notes/one-on-one.org" "/home/griffin/notes/work.org" "/home/griffin/notes/xanthous.org" "/home/griffin/notes/xgboost.org"))
+ '(safe-local-variable-values
+   '((intero-stack-yaml . "/home/griffin/code/mlem/stack.yaml")
+     (elisp-lint-indent-specs
+      (if-let* . 2)
+      (when-let* . 1)
+      (let* . defun)
+      (nrepl-dbind-response . 2)
+      (cider-save-marker . 1)
+      (cider-propertize-region . 1)
+      (cider-map-repls . 1)
+      (cider--jack-in . 1)
+      (cider--make-result-overlay . 1)
+      (insert-label . defun)
+      (insert-align-label . defun)
+      (insert-rect . defun)
+      (cl-defun . 2)
+      (with-parsed-tramp-file-name . 2)
+      (thread-first . 1)
+      (thread-last . 1))
+     (checkdoc-package-keywords-flag)
+     (cider-jack-in-default . "shadow-cljs")
+     (projectile-project-root . "/home/griffin/code/urb/grid/backend/src")
+     (python-pytest-executable . "/home/griffin/code/urb/grid/backend/src/.venv/bin/pytest"))))
+(custom-set-faces
+ ;; custom-set-faces was added by Custom.
+ ;; If you edit it by hand, you could mess it up, so be careful.
+ ;; Your init file should contain only one such instance.
+ ;; If there is more than one, they won't work right.
+ '(default ((((class color) (min-colors 89)) (:foreground "#657b83" :background "#fdf6e3"))))
+ '(agda2-highlight-bound-variable-face ((t nil)))
+ '(agda2-highlight-coinductive-constructor-face ((t (:foreground "#b58900"))))
+ '(agda2-highlight-datatype-face ((t (:foreground "#268bd2"))))
+ '(agda2-highlight-dotted-face ((t nil)))
+ '(agda2-highlight-error-face ((t (:foreground "#dc322f" :underline t))))
+ '(agda2-highlight-field-face ((t (:foreground "#dc322f"))))
+ '(agda2-highlight-function-face ((t (:foreground "#268bd2"))))
+ '(agda2-highlight-incomplete-pattern-face ((t (:background "#cb4b16" :foreground "#002b36"))))
+ '(agda2-highlight-inductive-constructor-face ((t (:foreground "#859900"))))
+ '(agda2-highlight-keyword-face ((t (:foreground "#859900"))))
+ '(agda2-highlight-module-face ((t (:foreground "#b58900"))))
+ '(agda2-highlight-number-face ((t (:foreground "#6c71c4"))))
+ '(agda2-highlight-operator-face ((t nil)))
+ '(agda2-highlight-postulate-face ((t (:foreground "#268bd2"))))
+ '(agda2-highlight-primitive-face ((t (:foreground "#268bd2"))))
+ '(agda2-highlight-primitive-type-face ((t (:foreground "#268bd2"))))
+ '(agda2-highlight-record-face ((t (:foreground "#268bd2"))))
+ '(agda2-highlight-string-face ((t (:foreground "#2aa198"))))
+ '(agda2-highlight-symbol-face ((((background "#fdf6e3")) (:foreground "#586e75"))))
+ '(agda2-highlight-termination-problem-face ((t (:background "#cb4b16" :foreground "#002b36"))))
+ '(agda2-highlight-typechecks-face ((t (:background "#2aa198" :foreground "#002b36"))))
+ '(agda2-highlight-unsolved-constraint-face ((t (:background "#eee8d5"))))
+ '(agda2-highlight-unsolved-meta-face ((t (:background "#eee8d5")))))
diff --git a/nix-yapf-mode.el b/nix-yapf-mode.el
new file mode 100644
index 0000000000..9dba47bd36
--- /dev/null
+++ b/nix-yapf-mode.el
@@ -0,0 +1,21 @@
+;;; ~/.doom.d/nix-yapf-mode.el -*- lexical-binding: t; -*-
+
+
+(defun +grfn/yapfify-call-bin (input-buffer output-buffer start-line end-line)
+  (with-current-buffer input-buffer
+    (call-process-region
+     (point-min)
+     (point-max)
+     "nix-shell"
+     nil
+     (list output-buffer nil)
+     nil
+     "/home/griffin/code/urb/grid/yapf.nix"
+     "--run"
+     (concat
+      "yapf -l "
+      (number-to-string start-line)
+      "-"
+      (number-to-string end-line)))))
+
+(advice-add #'yapfify-call-bin :override #'+grfn/yapfify-call-bin)
diff --git a/org-alerts.el b/org-alerts.el
new file mode 100644
index 0000000000..993791f367
--- /dev/null
+++ b/org-alerts.el
@@ -0,0 +1,188 @@
+;;; ~/.doom.d/org-alerts.el -*- lexical-binding: t; -*-
+
+;;; Commentary:
+
+;;; Code:
+
+(require 's)
+(require 'dash)
+(require 'alert)
+(require 'org-agenda)
+
+
+(defvar grfn/org-alert-interval 300
+  "Interval in seconds to recheck and display deadlines.")
+
+
+(defvar grfn/org-alert-notification-title "*org*"
+  "Title to be sent with notify-send.")
+
+(defvar grfn/org-alert-headline-regexp "\\(Sched.+:.+\\|Deadline:.+\\)"
+  "Regexp for headlines to search in agenda buffer.")
+
+(defun grfn/org-alert--strip-prefix (headline)
+  "Remove the scheduled/deadline prefix from HEADLINE."
+  (replace-regexp-in-string ".*:\s+" "" headline))
+
+
+(defun grfn/org-alert--unique-headlines (regexp agenda)
+  "Return unique headlines from the results of REGEXP in AGENDA."
+  (let ((matches (-distinct (-flatten (s-match-strings-all regexp agenda)))))
+    (--map (grfn/org-alert--strip-prefix it) matches)))
+
+
+(defun grfn/org-alert--get-headlines ()
+  "Return the current org agenda as text only."
+  (with-temp-buffer
+    (let ((org-agenda-sticky nil)
+          (org-agenda-buffer-tmp-name (buffer-name)))
+      (ignore-errors (org-agenda-list nil "TODAY" 1))
+      (grfn/org-alert--unique-headlines
+       grfn/org-alert-headline-regexp
+       (buffer-substring-no-properties (point-min) (point-max))))))
+
+(defun grfn/parse-range-string (str)
+  (when
+      (string-match (rx (group (repeat 2 (any digit))
+                               ":"
+                               (repeat 2 (any digit)))
+                        (optional
+                         (and
+                          "-"
+                          (group (repeat 2 (any digit))
+                                 ":"
+                                 (repeat 2 (any digit))))))
+                    str)
+    (list
+     (org-read-date nil t
+                    (match-string 1 str))
+     (when-let ((et (match-string 2 str))) (org-read-date nil t et)))))
+
+(defun grfn/start-time-from-range-string (str)
+  (pcase-let ((`(,start-time . _) (grfn/parse-range-string str)))
+    start-time))
+
+(comment
+ (org-agenda-list nil "TODAY" 1)
+
+ (grfn/org-alert--get-headlines)
+ (setq --src
+       (with-temp-buffer
+         (let ((org-agenda-sticky nil)
+               (org-agenda-buffer-tmp-name (buffer-name)))
+           (ignore-errors (org-agenda-list nil "TODAY" 1))
+           (buffer-substring-no-properties (point-min) (point-max)))))
+
+ (setq --entries
+       (with-temp-buffer
+         (let ((inhibit-redisplay t)
+               (org-agenda-sticky nil)
+               (org-agenda-buffer-tmp-name (buffer-name))
+               (org-agenda-buffer-name (buffer-name))
+               (org-agenda-buffer (current-buffer)))
+           (org-agenda-get-day-entries
+            (cadr (org-agenda-files nil 'ifmode))
+            (calendar-gregorian-from-absolute
+             (time-to-days (org-read-date nil t "TODAY")))))))
+
+ (loop for k in (text-properties-at 0 (car --entries))
+       by #'cddr
+       collect k)
+
+ (--map (substring-no-properties (get-text-property 0 'txt it)) --entries)
+ (--map (get-text-property 0 'time it) --entries)
+ (current-time)
+
+ (format-time-string "%R" (org-read-date nil t "10:00-11:00"))
+
+ (grfn/start-time-from-range-string "10:00")
+
+ (current-time-string (org-read-date nil t "10:00-11:00"))
+
+ (todo-state
+  org-habit-p
+  priority
+  warntime
+  ts-date
+  date
+  type
+  org-hd-marker
+  org-marker
+  face
+  undone-face
+  help-echo
+  mouse-face
+  done-face
+  org-complex-heading-regexp
+  org-todo-regexp
+  org-not-done-regexp
+  dotime
+  format
+  extra
+  time
+  level
+  txt
+  breadcrumbs
+  duration
+  time-of-day
+  org-lowest-priority
+  org-highest-priority
+  tags
+  org-category)
+
+ (propertize)
+
+ --src
+ )
+
+
+(defun grfn/org-alert--headline-complete? (headline)
+  "Return whether HEADLINE has been completed."
+  (--any? (s-starts-with? it headline) org-done-keywords-for-agenda))
+
+
+(defun grfn/org-alert--filter-active (deadlines)
+  "Remove any completed headings from the provided DEADLINES."
+  (-remove 'grfn/org-alert--headline-complete? deadlines))
+
+
+(defun grfn/org-alert--strip-states (deadlines)
+  "Remove the todo states from DEADLINES."
+  (--map (s-trim (s-chop-prefixes org-todo-keywords-for-agenda it)) deadlines))
+
+
+(defun grfn/org-alert-check ()
+  "Check for active, due deadlines and initiate notifications."
+  (interactive)
+  ;; avoid interrupting current command.
+  (unless (minibufferp)
+    (save-window-excursion
+      (save-excursion
+        (save-restriction
+          (let ((active (grfn/org-alert--filter-active (grfn/org-alert--get-headlines))))
+            (dolist (dl (grfn/org-alert--strip-states active))
+              (alert dl :title grfn/org-alert-notification-title))))))
+    (when (get-buffer org-agenda-buffer-name)
+      (ignore-errors
+        (with-current-buffer org-agenda-buffer-name
+          (org-agenda-redo t))))))
+
+
+(defun grfn/org-alert-enable ()
+  "Enable the notification timer.  Cancels existing timer if running."
+  (interactive)
+  (grfn/org-alert-disable)
+  (run-at-time 0 grfn/org-alert-interval 'grfn/org-alert-check))
+
+
+(defun grfn/org-alert-disable ()
+  "Cancel the running notification timer."
+  (interactive)
+  (dolist (timer timer-list)
+    (if (eq (elt timer 5) 'grfn/org-alert-check)
+        (cancel-timer timer))))
+
+
+
+(provide 'grfn/org-alert)
+;;; grfn/org-alert.el ends here
diff --git a/org-config.el b/org-config.el
new file mode 100644
index 0000000000..faf2a1bf42
--- /dev/null
+++ b/org-config.el
@@ -0,0 +1,91 @@
+;;; ~/.doom.d/org-config.el -*- lexical-binding: t; -*-
+;;;
+
+(defun notes-file (f)
+  (concat org-directory (if (string-prefix-p "/" f) "" "/") f))
+
+(require 'org-mu4e)
+
+(setq
+ org-directory (expand-file-name "~/notes")
+ +org-dir (expand-file-name "~/notes")
+ org-default-notes-file (concat org-directory "/inbox.org")
+ +org-default-todo-file (concat org-directory "/inbox.org")
+ org-agenda-files (list org-directory)
+ org-refile-targets '((org-agenda-files :maxlevel . 3))
+ org-outline-path-complete-in-steps nil
+ org-refile-use-outline-path t
+ org-file-apps `((auto-mode . emacs)
+                 (,(rx (or (and "." (optional "x") (optional "htm") (optional "l") buffer-end)
+                           (and buffer-start "http" (optional "s") "://")))
+                  . "firefox %s")
+                 (,(rx ".pdf" buffer-end) . "apvlv %s")
+                 (,(rx "." (or "png"
+                               "jpg"
+                               "jpeg"
+                               "gif"
+                               "tif"
+                               "tiff")
+                       buffer-end)
+                  . "feh %s"))
+ org-log-done 'time
+ org-archive-location "~/notes/trash::* From %s"
+ org-cycle-separator-lines 2
+ org-hidden-keywords '(title)
+ org-tags-column -130
+ org-ellipsis "⤵"
+ org-imenu-depth 9
+ org-capture-templates
+ `(("t" "Todo" entry
+    (file +org-default-todo-file)
+    "* TODO %?\n%i"
+    :kill-buffer t)
+
+   ("n" "Notes" entry
+    (file +org-default-todo-file)
+    "* %U %?\n%i"
+    :prepend t
+    :kill-buffer t)
+
+   ("c" "Task note" entry
+    (clock)
+    "* %U %?\n%i[[%l][Context]]\n"
+    :kill-buffer t
+    :unnarrowed t)
+
+   ;; ("d" "Tech debt" entry
+   ;;  (file+headline ,(concat org-directory "/work.org")
+   ;;                 "Inbox")
+   ;;  "* TODO %? :debt:\nContext: %a\nIn task: %K"
+   ;;  :prepend t
+   ;;  :kill-buffer t)
+
+   ("p" "Projects")
+   ("px" "Xanthous" entry
+    (file+headline ,(notes-file "xanthous.org") "Backlog")
+    "* TODO %?\nContext %a\nIn task: %K")
+
+   ("d" "Data recording")
+   ;; ("dr" "Reflux data" table-line
+   ;;  (file+olp ,(notes-file "personal.org")
+   ;;            "Data" "Reflux")
+   ;;  "| %U | %^{reflux|0|1|2|3|4|5} | %^{ate 1hr before bed?|Y|N} | %^{ate spicy food yesterday?|Y|N} |"
+   ;;  :unnarrowed t
+   ;;  :immediate-finish t
+   ;;  )
+   )
+
+ org-capture-templates-contexts
+ `(("px" ((in-file . "/home/griffin/code/xanthous/.*"))))
+
+ org-deadline-warning-days 1
+ org-agenda-skip-scheduled-if-deadline-is-shown 'todo
+ org-todo-keywords '((sequence "TODO(t)" "ACTIVE(a)" "|" "DONE(d)" "RUNNING(r)")
+                     (sequence "NEXT(n)" "WAITING(w)" "LATER(l)" "|" "CANCELLED(c)"))
+ org-agenda-custom-commands
+ '(("p" "Sprint Tasks" tags-todo "sprint")
+   ("i" "Inbox" tags "inbox")
+   ("r" "Running jobs" todo "RUNNING")
+   ("w" "@Work" tags-todo "@work")
+   ("n" . "Next...")
+   ("np" "Next Sprint" tags-todo "next_sprint|sprint_planning")))
diff --git a/org-query.el b/org-query.el
new file mode 100644
index 0000000000..3ed4b086af
--- /dev/null
+++ b/org-query.el
@@ -0,0 +1,96 @@
+;;; ~/.doom.d/org-query.el -*- lexical-binding: t; -*-
+
+(require 'org)
+(require 'org-agenda)
+(require 'inflections)
+
+(defun grfn/org-agenda-entry->element (agenda-entry)
+  ;; ???
+  ())
+
+(defun org-elements-agenda-match (match &optional todo-only)
+  (setq match
+        (propertize match 'inherited t))
+  (with-temp-buffer
+    (let ((inhibit-redisplay (not debug-on-error))
+          (org-agenda-sticky nil)
+          (org-agenda-buffer-tmp-name (buffer-name))
+          (org-agenda-buffer-name (buffer-name))
+          (org-agenda-buffer (current-buffer))
+          (matcher (org-make-tags-matcher match))
+          result)
+      (org-agenda-prepare (concat "TAGS " match))
+      (setq match (car matcher)
+            matcher (cdr matcher))
+      (dolist (file (org-agenda-files nil 'ifmode)
+                    result)
+        (catch 'nextfile
+          (org-check-agenda-file file)
+          (when-let ((buffer (if (file-exists-p file)
+                                 (org-get-agenda-file-buffer file)
+                               (error "No such file %s" file))))
+            (with-current-buffer buffer
+              (unless (derived-mode-p 'org-mode)
+                (error "Agenda file %s is not in Org mode" file))
+              (save-excursion
+                (save-restriction
+                  (if (eq buffer org-agenda-restrict)
+                      (narrow-to-region org-agenda-restrict-begin
+                                        org-agenda-restrict-end)
+                    (widen))
+                  (setq result
+                        (append result (org-scan-tags
+                                        'agenda
+                                        matcher
+                                        todo-only))))))))))))
+
+(defun grfn/num-inbox-items ()
+  (length (org-elements-agenda-match "inbox" t)))
+
+(defun grfn/num-inbox-items-message ()
+  (let ((n (grfn/num-inbox-items)))
+    (unless (zerop n)
+      (format "%d %s"
+              n
+              (if (= 1 n) "item" "items")))))
+
+(defmacro grfn/at-org-clocked-in-item (&rest body)
+  `(when (org-clocking-p)
+     (let ((m org-clock-marker))
+       (with-current-buffer (marker-buffer m)
+         (save-mark-and-excursion
+           (goto-char m)
+           (org-back-to-heading t)
+           ,@body)))))
+
+(defun grfn/org-element-clocked-in-task ()
+  (grfn/at-org-clocked-in-item
+   (org-element-at-point)))
+
+(comment
+ (grfn/org-element-clocked-in-task)
+ (org-element-property :title (grfn/org-element-clocked-in-task))
+ )
+
+(defun grfn/minutes->hours:minutes (minutes)
+  (format "%d:%02d"
+          (floor (/ minutes 60))
+          (mod minutes 60)))
+
+(comment
+ (grfn/minutes->hours:minutes 1)        ; => "0:01"
+ (grfn/minutes->hours:minutes 15)       ; => "0:15"
+ (grfn/minutes->hours:minutes 130)      ; => "2:10"
+ )
+
+(defun grfn/org-current-clocked-in-task-message ()
+  (if (org-clocking-p)
+      (format "(%s) [%s]"
+              (org-element-property :title (grfn/org-element-clocked-in-task))
+              (grfn/minutes->hours:minutes
+               (org-clock-get-clocked-time)))
+    ""))
+
+(comment
+ (grfn/org-current-clocked-in-task-message)
+ )
diff --git a/packages.el b/packages.el
index 799bcbe92a..41e8e14904 100644
--- a/packages.el
+++ b/packages.el
@@ -1,8 +1,6 @@
 ;; -*- no-byte-compile: t; -*-
 ;;; private/grfn/packages.el
 
-;; (package! 'tide :disable t)
-
 (package! moody)
 
 ;; Editor
@@ -10,24 +8,26 @@
 (package! fill-column-indicator)
 (package! flx)
 (package! general
-  :recipe (general
-           :fetcher github
-           :repo "noctuid/general.el"))
+  :recipe (:host github :repo "noctuid/general.el"))
 (package! fill-column-indicator)
 (package! writeroom-mode)
 (package! dash)
 (package! w3m)
 (package! rainbow-mode)
+(package! string-inflection)
 
 ;;; Org
 (package! org-clubhouse
-  :recipe (org-clubhouse
-           :fetcher file
-           :path "~/code/urb/org-clubhouse"))
+  :recipe (:host file
+           :local-repo "~/code/org-clubhouse"))
 (package! org-alert)
 (package! ob-http)
 (package! ob-ipython)
 (package! ob-async)
+(package! org-recent-headings)
+(package! org-sticky-header)
+(package! gnuplot)
+(package! gnuplot-mode)
 
 ;; Presentation
 (package! epresent)
@@ -42,6 +42,12 @@
 (package! evil-magit)
 (package! marshal)
 (package! forge)
+(package!
+  github-review
+  :recipe
+  (:host github
+         :repo "charignon/github-review"
+         :files ("github-review.el")))
 
 ;; Elisp
 (package! dash)
@@ -49,17 +55,22 @@
 (package! s)
 (package! request)
 (package! predd
-  :recipe (predd
-           :fetcher github
-           :repo "skeeto/predd"))
+  :recipe (:host github :repo "skeeto/predd"))
 
 ;; Haskell
-(package! lsp-mode)
-(package! lsp-ui :recipe (:fetcher github :repo "emacs-lsp/lsp-ui"))
 (package! lsp-haskell)
+(package! counsel-etags)
+
+;;; LSP
+(package! lsp-mode)
+(package! lsp-ui :recipe (:host github :repo "emacs-lsp/lsp-ui"))
 (package! company-lsp)
+(package! lsp-treemacs)
+(package! dap-mode)
 
 ;; Rust
+(package! rustic :disable t)
+(package! racer :disable t)
 (package! cargo)
 
 ;; Elixir
@@ -80,10 +91,10 @@
 (package! graphql-mode)
 
 ;; Haskell
-;; (package! lsp-mode)
-;; (package! lsp-ui)
-;; (package! lsp-haskell)
-;; (package! company-lsp)
+(package! lsp-mode)
+(package! lsp-ui)
+(package! lsp-haskell)
+(package! company-lsp)
 ;; (package! lsp-imenu)
 
 ;; Clojure
@@ -95,7 +106,35 @@
 (package! emacsql-psql)
 
 ;;; Python
+(package! pyimport)
 (package! yapfify)
 
 ;;; Desktop interaction
 (package! counsel-spotify)
+
+;;; Dhall
+(package! dhall-mode)
+
+;;; Kubernetes
+(package! kubernetes)
+(package! kubernetes-evil)
+(package! k8s-mode)
+
+;;; Stack Exchange
+(package! sx)
+
+;;; Nix
+(package! nix-update
+  :recipe (:host github
+           :repo "glittershark/nix-update-el"))
+
+;;; Sequence diagrams
+(package! wsd-mode
+  :recipe (:host github
+           :repo "josteink/wsd-mode"))
+
+;;; logic?
+(package! metal-mercury-mode
+  :recipe (:host github
+                 :repo "ahungry/metal-mercury-mode"))
+(package! flycheck-mercury)
diff --git a/show-matching-paren.el b/show-matching-paren.el
new file mode 100644
index 0000000000..d10751a63f
--- /dev/null
+++ b/show-matching-paren.el
@@ -0,0 +1,61 @@
+;;; ~/.doom.d/show-matching-paren.el -*- lexical-binding: t; -*-
+
+;;; https://with-emacs.com/posts/ui-hacks/show-matching-lines-when-parentheses-go-off-screen/
+
+;; we will call `blink-matching-open` ourselves...
+(remove-hook 'post-self-insert-hook
+             #'blink-paren-post-self-insert-function)
+;; this still needs to be set for `blink-matching-open` to work
+(setq blink-matching-paren 'show)
+
+(let ((ov nil)) ; keep track of the overlay
+  (advice-add
+   #'show-paren-function
+   :after
+    (defun show-paren--off-screen+ (&rest _args)
+      "Display matching line for off-screen paren."
+      (when (overlayp ov)
+        (delete-overlay ov))
+      ;; check if it's appropriate to show match info,
+      ;; see `blink-paren-post-self-insert-function'
+      (when (and (overlay-buffer show-paren--overlay)
+                 (not (or cursor-in-echo-area
+                          executing-kbd-macro
+                          noninteractive
+                          (minibufferp)
+                          this-command))
+                 (and (not (bobp))
+                      (memq (char-syntax (char-before)) '(?\) ?\$)))
+                 (= 1 (logand 1 (- (point)
+                                   (save-excursion
+                                     (forward-char -1)
+                                     (skip-syntax-backward "/\\")
+                                     (point))))))
+        ;; rebind `minibuffer-message' called by
+        ;; `blink-matching-open' to handle the overlay display
+        (cl-letf (((symbol-function #'minibuffer-message)
+                   (lambda (msg &rest args)
+                     (let ((msg (apply #'format-message msg args)))
+                       (setq ov (display-line-overlay+
+                                 (window-start) msg ))))))
+          (blink-matching-open))))))
+
+(defun display-line-overlay+ (pos str &optional face)
+  "Display line at POS as STR with FACE.
+
+FACE defaults to inheriting from default and highlight."
+  (let ((ol (save-excursion
+              (goto-char pos)
+              (make-overlay (line-beginning-position)
+                            (line-end-position)))))
+    (overlay-put ol 'display str)
+    (overlay-put ol 'face
+                 (or face '(:inherit default :inherit highlight)))
+    ol))
+
+(setq show-paren-style 'paren
+      show-paren-delay 0.03
+      show-paren-highlight-openparen t
+      show-paren-when-point-inside-paren nil
+      show-paren-when-point-in-periphery t)
+(show-paren-mode 1)
diff --git a/slack-snippets.el b/slack-snippets.el
index 0c51751921..9e05382ee6 100644
--- a/slack-snippets.el
+++ b/slack-snippets.el
@@ -192,10 +192,11 @@
      (ivy-read
       "Select channel: "
       ;; TODO want to potentially use purpose / topic stuff here
-      (-map (lambda (chan) (let ((label (assoc-default 'label (cdr chan)))
-                            (id (car chan)))
-                        (propertize label 'channel-id id)))
-            conversations)
+      (->> conversations
+           (-filter (lambda (c) (assoc-default 'label (cdr c))))
+           (-map (lambda (chan) (let ((label (assoc-default 'label (cdr chan)))
+                                 (id (car chan)))
+                             (propertize label 'channel-id id)))))
       :history 'slack/channel-history
       :action (lambda (selected)
                 (let ((channel-id (get-text-property 0 'channel-id selected)))
@@ -203,14 +204,24 @@
                   (message "Sent message to %s" selected))))))
   nil)
 
+(comment
+ (prompt-for-channel #'message)
+ (->> --convos
+      (-filter (lambda (c) (assoc-default 'label (cdr c))))
+      (-map (lambda (chan) (let ((label (assoc-default 'label (cdr chan)))
+                       (id (car chan)))
+                   (propertize label 'channel-id id)))))
+
+ (->> --convos (car) (cdr) (assoc-default 'label))
+ )
+
 (defun slack-send-code-snippet (&optional snippet-text)
-  (interactive)
-  (when-let ((snippet-text (or snippet-text
-                               (buffer-substring-no-properties (mark) (point)))))
-    (prompt-for-channel
-     (lambda (channel-id)
-       (slack/post-message
-        :text       (format "```\n%s```" snippet-text)
-        :channel-id channel-id)))))
+  (interactive
+   (list (buffer-substring-no-properties (mark) (point))))
+  (prompt-for-channel
+   (lambda (channel-id)
+     (slack/post-message
+      :text       (format "```\n%s```" snippet-text)
+      :channel-id channel-id))))
 
 (provide 'slack-snippets)
diff --git a/snippets/haskell-mode/hlint b/snippets/haskell-mode/hlint
new file mode 100644
index 0000000000..74b63dc672
--- /dev/null
+++ b/snippets/haskell-mode/hlint
@@ -0,0 +1,8 @@
+# -*- mode: snippet -*-
+# name: hlint
+# uuid:
+# expand-env: ((yas-indent-line 'fixed))
+# key: hlint
+# condition: t
+# --
+{-# ANN module ("Hlint: ignore $1" :: String) #- }
\ No newline at end of file
diff --git a/snippets/nix-mode/fetchFromGitHub b/snippets/nix-mode/fetchFromGitHub
new file mode 100644
index 0000000000..9b93735730
--- /dev/null
+++ b/snippets/nix-mode/fetchFromGitHub
@@ -0,0 +1,12 @@
+# -*- mode: snippet -*-
+# name: fetchFromGitHub
+# uuid:
+# key: fetchFromGitHub
+# condition: t
+# --
+fetchFromGitHub {
+                owner = "$1";
+                repo = "$2";
+                rev = "$3";
+                sha256 = "0000000000000000000000000000000000000000000000000000";
+}
\ No newline at end of file
diff --git a/snippets/nix-mode/pythonPackage b/snippets/nix-mode/pythonPackage
new file mode 100644
index 0000000000..0a74c21e18
--- /dev/null
+++ b/snippets/nix-mode/pythonPackage
@@ -0,0 +1,16 @@
+# key: pypkg
+# name: pythonPackage
+# condition: t
+# --
+${1:pname} = buildPythonPackage rec {
+           name = "\${pname}-\${version}";
+           pname = "$1";
+           version = "${2:1.0.0}";
+           src = fetchPypi {
+               inherit pname version;
+               sha256 = "0000000000000000000000000000000000000000000000000000";
+           };
+           propagatedBuildInputs = with pythonSelf; [
+               $3
+           ];
+};
\ No newline at end of file
diff --git a/snippets/nix-mode/sha256 b/snippets/nix-mode/sha256
new file mode 100644
index 0000000000..e3d52e1c02
--- /dev/null
+++ b/snippets/nix-mode/sha256
@@ -0,0 +1,7 @@
+# -*- mode: snippet -*-
+# name: sha256
+# uuid:
+# key: sha256
+# condition: t
+# --
+sha256 = "0000000000000000000000000000000000000000000000000000";
\ No newline at end of file
diff --git a/snippets/org-mode/combat b/snippets/org-mode/combat
new file mode 100644
index 0000000000..ef46062d09
--- /dev/null
+++ b/snippets/org-mode/combat
@@ -0,0 +1,13 @@
+# -*- mode: snippet -*-
+# name: combat
+# uuid:
+# key: combat
+# condition: t
+# --
+|             | initiative | max hp | current hp | status |      |
+|-------------+------------+--------+------------+--------+------|
+| Barty Barty |            |        |            |        | <--- |
+| Hectoroth   |            |        |            |        |      |
+| Xanadu      |            |        |            |        |      |
+| Aurora      |            |        |            |        |      |
+| EFB         |            |        |            |        |      |
\ No newline at end of file
diff --git a/snippets/org-mode/reveal b/snippets/org-mode/reveal
new file mode 100644
index 0000000000..1bdbdfa5dc
--- /dev/null
+++ b/snippets/org-mode/reveal
@@ -0,0 +1,6 @@
+# key: reveal
+# name: reveal
+# condition: t
+# --
+#+ATTR_REVEAL: :frag ${1:roll-in}
+$0
\ No newline at end of file
diff --git a/snippets/python-mode/decorate b/snippets/python-mode/decorate
new file mode 100644
index 0000000000..9448b45c96
--- /dev/null
+++ b/snippets/python-mode/decorate
@@ -0,0 +1,15 @@
+# -*- mode: snippet -*-
+# name: decorate
+# uuid:
+# key: decorate
+# condition: t
+# --
+def wrap(inner):
+    @wraps(inner)
+    def wrapped(*args, **kwargs):
+        ret = inner(*args, **kwargs)
+        return ret
+
+    return wrapped
+
+return wrap
\ No newline at end of file
diff --git a/snippets/python-mode/name b/snippets/python-mode/name
new file mode 100644
index 0000000000..eca6d60b48
--- /dev/null
+++ b/snippets/python-mode/name
@@ -0,0 +1,7 @@
+# -*- mode: snippet -*-
+# name: name
+# uuid:
+# key: name
+# condition: t
+# --
+__name__
\ No newline at end of file
diff --git a/snippets/python-mode/pdb b/snippets/python-mode/pdb
new file mode 100644
index 0000000000..6b5c0bbc0a
--- /dev/null
+++ b/snippets/python-mode/pdb
@@ -0,0 +1,7 @@
+# -*- mode: snippet -*-
+# name: pdb
+# uuid:
+# key: pdb
+# condition: t
+# --
+import pdb; pdb.set_trace()
\ No newline at end of file
diff --git a/sql-strings.el b/sql-strings.el
new file mode 100644
index 0000000000..37e22af421
--- /dev/null
+++ b/sql-strings.el
@@ -0,0 +1,75 @@
+;;; ~/.doom.d/sql-strings.el -*- lexical-binding: t; -*-
+
+;;; https://www.emacswiki.org/emacs/StringAtPoint
+(defun ourcomments-string-or-comment-bounds-1 (what)
+  (save-restriction
+    (widen)
+    (let* ((here (point))
+           ;; Fix-me: when on end-point, how to handle that and which should be last hit point?
+           (state (parse-partial-sexp (point-min) (1+ here)))
+           (type (if (nth 3 state)
+                     'string
+                   (if (nth 4 state)
+                       'comment)))
+           (start (when type (nth 8 state)))
+           end)
+      (unless start
+        (setq state (parse-partial-sexp (point-min) here))
+        (setq type (if (nth 3 state)
+                       'string
+                     (if (nth 4 state)
+                         'comment)))
+        (setq start (when type (nth 8 state))))
+      (unless (or (not what)
+                  (eq what type))
+        (setq start nil))
+      (if (not start)
+          (progn
+            (goto-char here)
+            nil)
+        (setq state (parse-partial-sexp (1+ start) (point-max)
+                                        nil nil state 'syntax-table))
+        (setq end (point))
+        (goto-char here)
+        (cons start end)))))
+
+(defun ourcomments-bounds-of-string-at-point ()
+  "Return bounds of string at point if any."
+  (ourcomments-string-or-comment-bounds-1 'string))
+
+(put 'string 'bounds-of-thing-at-point 'ourcomments-bounds-of-string-at-point)
+
+(defun -sanitize-sql-string (str)
+  (->> str
+       (downcase)
+       (s-trim)
+       (replace-regexp-in-string
+        (rx (or (and string-start (or "\"\"\""
+                                      "\""))
+                (and (or "\"\"\""
+                         "\"")
+                     string-end)))
+        "")
+       (s-trim)))
+
+(defun sql-string-p (str)
+  "Returns 't if STR looks like a string literal for a SQL statement"
+  (setq str (-sanitize-sql-string str))
+  (or (s-starts-with? "select" str)))
+
+;;; tests
+
+(require 'ert)
+
+(ert-deftest sanitize-sql-string-test ()
+  (should (string-equal "select * from foo;"
+                        (-sanitize-sql-string
+                         "\"\"\"SELECT * FROM foo;\n\n\"\"\""))))
+
+(ert-deftest test-sql-string-p ()
+  (dolist (str '("SELECT * FROM foo;"
+                 "select * from foo;"))
+    (should (sql-string-p str)))
+
+  (dolist (str '("not a QUERY"))
+    (should-not (sql-string-p str))))
diff --git a/themes/grfn-solarized-light-theme.el b/themes/grfn-solarized-light-theme.el
index 338cfabfcc..ae00b6b5fc 100644
--- a/themes/grfn-solarized-light-theme.el
+++ b/themes/grfn-solarized-light-theme.el
@@ -1,4 +1,6 @@
 (require 'solarized)
+(eval-when-compile
+  (require 'solarized-palettes))
 
 ;; (defun grfn-solarized-theme ()
 ;;   (custom-theme-set-faces
@@ -56,30 +58,58 @@
 
 (deftheme grfn-solarized-light "The light variant of Griffin's solarized theme")
 
-(create-solarized-theme
- 'light 'grfn-solarized-light
- (lambda ()
-   (custom-theme-set-faces
-    'grfn-solarized-light
-    `(font-lock-doc-face ((t (:foreground ,+solarized-s-base1))))
-    `(font-lock-preprocessor-face ((t (:foreground ,+solarized-red))))
-    `(font-lock-keyword-face ((t (:foreground ,+solarized-green))))
+(setq grfn-solarized-faces
+      '("Griffin's solarized theme customization"
+        (custom-theme-set-faces
+         theme-name
+         `(font-lock-doc-face ((t (:foreground ,+solarized-s-base1))))
+         `(font-lock-preprocessor-face ((t (:foreground ,+solarized-red))))
+         `(font-lock-keyword-face ((t (:foreground ,+solarized-green))))
 
-    `(elixir-attribute-face ((t (:foreground ,+solarized-blue))))
-    `(elixir-atom-face ((t (:foreground ,+solarized-cyan))))
-    )
+         `(elixir-attribute-face ((t (:foreground ,+solarized-blue))))
+         `(elixir-atom-face ((t (:foreground ,+solarized-cyan))))
+         `(agda2-highlight-keyword-face ((t (:foreground ,green))))
+         `(agda2-highlight-string-face ((t (:foreground ,cyan))))
+         `(agda2-highlight-number-face ((t (:foreground ,violet))))
+         `(agda2-highlight-symbol-face ((((background ,base3)) (:foreground ,base01))))
+         `(agda2-highlight-primitive-type-face ((t (:foreground ,blue))))
+         `(agda2-highlight-bound-variable-face ((t nil)))
+         `(agda2-highlight-inductive-constructor-face ((t (:foreground ,green))))
+         `(agda2-highlight-coinductive-constructor-face ((t (:foreground ,yellow))))
+         `(agda2-highlight-datatype-face ((t (:foreground ,blue))))
+         `(agda2-highlight-field-face ((t (:foreground ,red))))
+         `(agda2-highlight-function-face ((t (:foreground ,blue))))
+         `(agda2-highlight-module-face ((t (:foreground ,yellow))))
+         `(agda2-highlight-postulate-face ((t (:foreground ,blue))))
+         `(agda2-highlight-primitive-face ((t (:foreground ,blue))))
+         `(agda2-highlight-record-face ((t (:foreground ,blue))))
+         `(agda2-highlight-dotted-face ((t nil)))
+         `(agda2-highlight-operator-face ((t nil)))
+         `(agda2-highlight-error-face ((t (:foreground ,red :underline t))))
+         `(agda2-highlight-unsolved-meta-face ((t (:background ,base2))))
+         `(agda2-highlight-unsolved-constraint-face ((t (:background ,base2))))
+         `(agda2-highlight-termination-problem-face ((t (:background ,orange :foreground ,base03))))
+         `(agda2-highlight-incomplete-pattern-face ((t (:background ,orange :foreground ,base03))))
+         `(agda2-highlight-typechecks-face ((t (:background ,cyan :foreground ,base03))))
 
-   ))
+         `(font-lock-doc-face ((t (:foreground ,+solarized-s-base1))))
+         `(font-lock-preprocessor-face ((t (:foreground ,+solarized-red))))
+         `(font-lock-keyword-face ((t (:foreground ,+solarized-green :bold nil))))
+         `(font-lock-builtin-face ((t (:foreground ,+solarized-s-base01
+                                                  :bold t))))
 
-(custom-theme-set-faces
- 'grfn-solarized-light
- `(font-lock-doc-face ((t (:foreground ,+solarized-s-base1))))
- `(font-lock-preprocessor-face ((t (:foreground ,+solarized-red))))
- `(font-lock-keyword-face ((t (:foreground ,+solarized-green))))
+         `(elixir-attribute-face ((t (:foreground ,+solarized-blue))))
+         `(elixir-atom-face ((t (:foreground ,+solarized-cyan))))
+         `(linum ((t (:background ,+solarized-s-base2 :foreground ,+solarized-s-base1))))
+         `(line-number ((t (:background ,+solarized-s-base2 :foreground ,+solarized-s-base1))))
 
- `(elixir-attribute-face ((t (:foreground ,+solarized-blue))))
- `(elixir-atom-face ((t (:foreground ,+solarized-cyan))))
- )
+         `(haskell-operator-face ((t (:foreground ,+solarized-green))))
+         `(haskell-keyword-face ((t (:foreground ,+solarized-cyan))))
 
-(provide-theme 'grfn-solarized-light)
+         `(org-drawer ((t (:foreground ,+solarized-s-base1
+                                      :bold t)))))))
+
+(solarized-with-color-variables
+  'light 'grfn-solarized-light solarized-light-color-palette-alist)
 
+(provide-theme 'grfn-solarized-light)