Skip to content

Latest commit

 

History

History
1153 lines (1067 loc) · 43.2 KB

dotEmacs.org

File metadata and controls

1153 lines (1067 loc) · 43.2 KB

Package things!

This is a bit of fumbling to try and get this all to work on a new computer from zero with minimal manual intervention.

(package-initialize)

(when (not package-archive-contents)
  (package-refresh-contents))
(require 'package)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t)
(unless (package-installed-p 'use-package)
  (package-install 'use-package))
(eval-when-compile
  (require 'use-package))

Make use package always install if package is not installed.

(setq use-package-always-ensure t)

Ubuntu specific (hopefully this doesn’t break mac!) - this forces org to update to a later version.

(use-package org :ensure org-contrib :pin org)

This brings back the old “<s” shortcut for source blocks. Unfortunately it has different casing than before, but that’s not worth the time to fix (probably easy though).

(require 'org-tempo)

Extra Plugins

Evil

Because I am a vim user at heart.

Fix tab cycling

Remove evil C-i binding so tab works.

(setq evil-want-C-i-jump nil)

See Evil jumplist remapping for where the rebind happens.

Use package wih org bindings

Set up org bindings first. Honestly not sure if this needs to come before use evil, but not worth figuring out.

(use-package evil-org
  :ensure t
  :after org
  :hook (org-mode . (lambda () evil-org-mode))
  :config
  (require 'evil-org-agenda)
  (evil-org-agenda-set-keys))
(use-package evil)
(evil-mode 1)

Bar cursor

Change cursor to a bar in insert mode.

(use-package evil-terminal-cursor-changer)
(unless (display-graphic-p)
  (require 'evil-terminal-cursor-changer)
  (evil-terminal-cursor-changer-activate) ; or (etcc-on)
  )
(setq evil-default-cursor (quote (t "#750000"))
      evil-visual-state-cursor '("#880000" box)
      evil-normal-state-cursor '("#750000" box)
      evil-insert-state-cursor '("#e2e222" bar)
      )

Evil surround

(use-package evil-surround
  :ensure t
  :config
  (global-evil-surround-mode 1))

Easymotion

(use-package evil-easymotion)
(evilem-default-keybindings "SPC")

Find lisp

(use-package find-lisp)

Smartparens

Doesn’t quite work yet - Maybe I’ll get it going some day.

;;   (use-package smartparens)
;; (use-package evil-smartparens)
;; (add-hook 'smartparens-enabled-hook #'evil-smartparens-mode)

Magit

Definitely pronounced “muh git”, much like “muh queen”. Certainly not “mahjit”, despite what the top hat and wand would make you think.

(use-package magit)

Evil magit

Get keybindings for evil in magit mode. Not sure what else evil-collection has, but some day I want to move this elsewhere if it’s spanning across other modes.

(use-package evil-collection)
(evil-collection-init 'magit)

Forge

To work with github

;;(use-package forge
  ;;:after magit)

Undo Tree

I could have sworn I had this installed at one point, but oh well!

(use-package undo-tree)
(global-undo-tree-mode)
(global-set-key (kbd "C-x C-u") 'undo-tree-visualize)
(define-key evil-ex-map "xu" 'undo-tree-visualize)

Force undo tree files into local emacs d.

(setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo")))

Rifle

All the other deps with the funked up deps

(use-package f)
(use-package s)
(use-package dash)
(use-package helm-org-rifle)

Nice autocompletion things

Much of this I just followed this guide while trying to configure Roam Smart parents

(use-package smartparens)
(smartparens-global-mode t)

Company

(use-package company)
(add-hook 'after-init-hook 'global-company-mode)
(setq company-minimum-prefix-length 2)
(setq company-idle-delay 0.25)
(add-to-list 'company-backends 'company-capf)

Completion config

(setq completion-ignore-case t)

Helm

 (use-package helm
   :ensure t)
 (setq helm-split-window-in-side-p t
	helm-move-to-line-cycle-in-source t)
 (helm-mode 1)

Helm fuzzier matching

Doesn’t quite work yet - I’m trying to get it so that I can fuzzy match in helm-apropos, but despite what the internet says it is not working.

;; (use-package helm-fuzzier)
;; (helm-fuzzier-mode 1)

K8s

Not using k8s a ton day to day, but a magit-like k8s buffer seems great. Going to mess around with it.

(use-package kubernetes)
(use-package kubernetes-evil
:ensure t
:after kubernetes)
(fset 'k8s 'kubernetes-overview)

Custom variables (I don’t really remember what this is)

Variables - org agenda files, which will some day pull dates, but are also used for how things refile. I exclude archive.org from this list because it’s huge.

(defun es/fourteen-days-ago-month ()
  "Lookback fourteen days ago, and format that month as YYYY-MM."
  (format-time-string "%Y-%m" (time-add (current-time) (seconds-to-time -1209600)))
  ;; debug - make this look back more to see if anything is straggling
  ;; (format-time-string "%Y-%m" (time-add (current-time) (seconds-to-time -2409600)))
  )
(defun es/current-month ()
  "Get current month as YYYY-MM."
  (format-time-string "%Y-%m" (current-time))
  )
(defun es/set-org-agenda-files () (interactive)
       (if es/no-work-agenda
           (es/set-no-work-org-agenda-files)
         (es/set-work-org-agenda-files)
         )
       )
(defun es/set-work-org-agenda-files () (interactive)
       "Define my org agenda files"
       (custom-set-variables
        '(org-agenda-files
          (append
           (cl-remove-if (lambda (k) (string-match-p "archive.org" k))
                         (find-lisp-find-files "~/Dropbox/org/projects/" "\.org$"))
           (cl-remove-if (lambda (k) (string-match-p "_done.org" k))
                         (find-lisp-find-files "~/org/projects/" "\.org$"))
           (cl-remove-if (lambda (k) (not (or
                                           (string-match-p (es/current-month) k)
                                           (string-match-p (es/fourteen-days-ago-month) k))))
                         (find-lisp-find-files "~/org/roam/daily" "\.org$"))
           (cl-remove-if (lambda (k) (not (string-match-p "inbox.org" k)))
                         (find-lisp-find-files "~/Dropbox/org" "\.org$"))
           (cl-remove-if (lambda (k) (not (or
                                           (string-match-p (es/current-month) k)
                                           (string-match-p (es/fourteen-days-ago-month) k))))
                         (find-lisp-find-files "~/Dropbox/org/roam/daily/" "\.org$"))
           )
          )))
(defun es/set-nw-agenda () (interactive)
       (setq es/no-work-agenda t)
       )
(defun es/set-yw-agenda () (interactive)
       (setq es/no-work-agenda nil)
       )
(defun es/set-no-work-org-agenda-files () (interactive)
       "Define just personal agenda files"
       (custom-set-variables
        '(org-agenda-files
          (append
           (cl-remove-if (lambda (k) (string-match-p "archive.org" k))
                         (find-lisp-find-files "~/Dropbox/org/projects/" "\.org$"))
           (cl-remove-if (lambda (k) (not (string-match-p "inbox.org" k)))
                         (find-lisp-find-files "~/Dropbox/org" "\.org$"))
           (cl-remove-if (lambda (k) (not (or
                                           (string-match-p (es/current-month) k)
                                           (string-match-p (es/fourteen-days-ago-month) k))))
                         (find-lisp-find-files "~/Dropbox/org/roam/daily/" "\.org$"))
           )
          )))
(es/set-yw-agenda)

Start with bullets folded and indented by default.

(setq org-startup-indented t)
(setq org-startup-folded t)

No clue what custom-set-faces is to be honest.

(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.
 )
;; Package-Requires: ((dash "2.13.0"))
;; (add-to-list 'load-path "~/.emacs.d/vendor/emacs-powerline")
;; (require 'powerline)
;; (require 'cl)

Refile config. I found this on reddit, but I think this says “take the stuff from org-agenda-files and go one N levels deep in the trees to find targets”. It works.

(setq org-refile-targets '((nil :maxlevel . 1)
                           (org-agenda-files :maxlevel . 3)
                           ("~/Dropbox/org/projects/stuff.org" :maxlevel . 1)
                           ("~/Dropbox/org/projects/financeMath.org" :maxlevel . 2)
                           ("~/Dropbox/org/projects/tList.org" :maxlevel . 1)
                           ("~/code/dotfiles/fish/fishProfile.org" :maxlevel . 3)
                           ("~/code/dotfiles/bashProfile.org" :maxlevel . 3)))
(setq org-refile-use-outline-path 'file)
(setq org-refile-allow-creating-parent-nodes 'confirm)

Adding sh (bash) to babel languages so I can tangle my bash profile.

(org-babel-do-load-languages 'org-babel-load-languages
                             '(
                               (shell . t)
                               )
                             )
(setq org-babel-default-header-args:bash '((:tangle . "yes")))

Todo/agenda customization - states and donetime/note

Ongoing thing to figure out what states I want. log-done enables timestamp and prompts for a note. Archive location is what you’d expect.

More details Here

(setq org-todo-keywords
      '((sequence "TODO(t)" "SOMEDAY(s)" "WAITING(w)" "IN-PROGRESS(i)" "BLOCKED(l)" "|" "DONE(d)" "EXPORTED(e)" "OBSOLOTE(b)" "DELEGATED(g)")))

(setq org-log-done 'time)
;;(setq org-log-done 'note)

(setq org-archive-location "~/Dropbox/org/projects/archive.org::")

Custom priorities

(setq org-lowest-priority 74)

Make checkbox/todo tracking recursive so I see everything under the subtree

(setq org-hierarchical-todo-statistics t)

Column view in org-agenda

(setq org-columns-default-format-for-agenda "%80ITEM(Task) %4PRIORITY(Priority)  %10TODO(Todo Status) %17Effort(Estimated Effort){:} %CLOCKSUM(Time Spent)")

Agenda Sorting

Define a custom tiebreaker for priority - I basically want A on par with within 1 day, B on par with within 2 days, etc.

(setq org-agenda-cmp-user-defined (lambda (a b) (message (org-get-priority a))))

Only one change from the default strategy, which is to use effort-up. The ordering on agenda is now “high priority first, low effort first, respect order of org-agenda-files”. I think the fact that all my things in “recurring.org” are habits sort of circuvents “habit-down”. But I don’t mind for now.

(setq org-agenda-sorting-strategy
      '((agenda user-defined-up todo-state-down habit-down time-up priority-down effort-up category-keep)
        (todo priority-down category-keep)
        (tags priority-down category-keep)
        (search category-keep)))

Curating todos

Org agenda todo - filter out things with dates so I schedule any dangling todos. Apparently I need all of these set - I tend to just slap dates on stuff so it’ll show on the agenda, which is good enough for me.

(setq org-agenda-todo-ignore-scheduled "all")
(setq org-agenda-todo-ignore-deadlines "all")
(setq org-agenda-todo-ignore-timestamp "all")
(setq org-agenda-todo-ignore-with-date "all")
(setq org-agenda-tags-todo-honor-ignore-options t)

Agenda shortcuts

Just a command to bring up agenda view

(define-key global-map "\C-ca" 'org-agenda)

Super Agenda

(use-package org-super-agenda)
(setq org-super-agenda-keep-order t)
(org-super-agenda-mode 1)
(setq org-super-agenda-groups
      '(;; Each group has an implicit boolean OR operator between its selectors.
        (:name "Inbox"
               :tag "inbox"
               )
        (:name "Habits Overdue"
               :and(:file-path "recurring.org" :deadline  past :not(:tag "eodroutine"))
               :and(:file-path "recurring.org" :scheduled past :not(:tag "eodroutine"))
               )
        (:name "Habits Today"
               :and(:file-path "recurring.org" :deadline today :not(:tag "eodroutine"))
               :and(:file-path "recurring.org" :scheduled today :not(:tag "eodroutine"))
               )
        (:name "Personal - IN-PROGRESS"
               ;; Single arguments given alone
               :and (:todo ("IN-PROGRESS") :file-path "Dropbox"))
        (:name "Important - Personal"
               ;; Single arguments given alone
               :and (:priority "A" :todo ("TODO" "IN-PROGRESS" "SOMEDAY") :file-path "Dropbox"))
        (:name "Work - IN-PROGRESS"
               ;; Single arguments given alone
               :and (:todo ("IN-PROGRESS") :file-path "Drive")
               :and (:todo ("IN-PROGRESS") :file-path "work.org"))
        (:name "Work Stuck"
               ;; Single arguments given alone
               :and (:priority "A"
                               :todo ("WAITING" "BLOCKED") :file-path "Drive")
               :and (:priority "A"
                               :todo ("WAITING" "BLOCKED") :file-path "work.org"))
        (:name "Important - Work"
               ;; Single arguments given alone
               :and (:priority "A"
                               :todo ("TODO" "SOMEDAY") :file-path "Drive")
               :and (:priority "A"
                               :todo ("TODO") :file-path "work.org"))
        (:name "Other personal"
               :and (:todo ("TODO" "SOMEDAY") :file-path "Dropbox" :not(:tag "eodroutine")))
        (:name "Other work"
               :and(:file-path "work.org" :todo ("TODO"))
               :and(:file-path "Drive" :todo ("TODO")))
        ;; Set order of multiple groups at once
        (:and(:priority<= "B"
                          ;; Show this section after "Today" and "Important", because
                          ;; their order is unspecified, defaulting to 0. Sections
                          ;; are displayed lowest-number-first.
                          :order 0
                          :todo ("TODO" "IN-PROGRESS" "SOMEDAY")))
        ;; After the last group, the agenda will display items that didn't
        ;; match any of these groups, with the default order position of 99
        (:name "Blocked"
               :todo ("BLOCKED"))
        (:name "Future Habits"
               :and(:file-path "recurring.org" :deadline future))
        (:name "Waiting"
               :todo ("WAITING"))
        (:name "EOD Routine"
               :and(:todo "TODO" :file-path "recurring.org" :scheduled today :tag "eodroutine")
               :and(:todo "TODO" :file-path "recurring.org" :scheduled past :tag "eodroutine")
               )
        (:name "Done"
               :and(
                    :todo ("DONE" "OBSOLETE" "DELEGATED" "EXPORTED")
                    )
               )))
(setq org-super-agenda-header-map (make-sparse-keymap))

Agenda evil shortcut

(defun org-agenda-list-day () (interactive)
       "Wrapper for org-agenda-list that just lists a single day"
       (es/set-org-agenda-files)
       (org-agenda-list 1)
       )
(define-key evil-ex-map "a" 'org-agenda-list-day)
(define-key evil-ex-map "nw" 'es/set-nw-agenda)
(define-key evil-ex-map "yw" 'es/set-yw-agenda)

Auto insert subtask tracker

Binds :st to “insert at end of line, append [/], C-cC-c it” for quick subtask adding.

(fset 'es/append-subtask-tracker
      (kmacro-lambda-form [?A ?  ?\[ ?/ ?\] escape ?\C-c ?\C-c] 0 "%d"))

(define-key evil-ex-map "st" 'es/append-subtask-tracker)

Agenda defaults

Enable log mode on start up to see what was completed when

(setq org-agenda-start-with-log-mode "state")

Colors!!!! And other nice displays - change the … to a return thingy, make nice bullet icons.

(load-theme 'manoj-dark)
(setq org-ellipsis "")
(use-package org-bullets
  :ensure t
  :init
  (add-hook 'org-mode-hook (lambda ()
                             (org-bullets-mode 1))))

Line numbering - absolute and relative.

(global-display-line-numbers-mode)
(setq display-line-numbers-type 'relative)

This makes emacs figure out the max line numbers beforehand - for longer files with thousands of lines, there is a little bump that happens when line numbers are displayed - this fixes that.

(setq display-line-numbers-width-start t)

Emphasis markers

WIP - Hide emphasis markers to make things a bit prettier.

bold italic underline literal code strikethrough

Custom Key Bindings

Org refile

This first one is to get a different one for org-refile. I want it as C-r C-f (rf -> refile)

First thing to do is to set “C-r” as a possible prefix.

(define-prefix-command 'ring-map)
(global-set-key (kbd "C-r") 'ring-map)

Next thing to do is to remove “C-r” from the evil map (apparently it’s redo, which I never use).

Then we do the actual “C-r C-f” bind.

(define-key evil-normal-state-map (kbd "C-r") nil)
(global-set-key (kbd "C-r C-f") 'org-refile)
(define-key evil-ex-map "rf" 'org-refile)

Another one - archive. I’m gonna do “C-r C-a” for “refile - archive”, and because I have “C-r” as a prefix now.

(global-set-key (kbd "C-r C-a") 'org-archive-subtree)
(define-key evil-ex-map "ra" 'org-archive-subtree)

Make refile work in evil insert

“C-r” is bound to something else, which I don’t use, and I’d rather be able to refile in insert mode as well.

(define-key evil-insert-state-map (kbd "C-r") nil)
;; (define-key evil-insert-state-map (kbd "C-r C-f"))

Window switching

A lot of the below is from when I relied on C-[key] commands a la emacs style. Recently I’m moving to :[key][key] a la vim style since it’s easier for typing. As such, a lot of the below might be obsolete, but hey, I’m too lazy to go reconcile it. Plus, some of the spots where vim command mode doesn’t work (magit, agenda buffers) will still need C-w C-w.

(define-key evil-ex-map "ww" 'evil-window-next)
(define-key evil-ex-map "WW" 'evil-window-prev)

I use C-w C-w to switch windows a lot, but it messes me up when it deletes a word in insert mode.

(define-key evil-insert-state-map (kbd "C-w") nil)
(define-key evil-insert-state-map (kbd "C-w C-w") 'evil-window-next)
(define-key evil-insert-state-map (kbd "C-w w") 'evil-window-next)

I never really use the most recently used functionality, and would rather have C-w C-p and C-w p just do previous window, since that makes sense to me.

(define-key evil-motion-state-map (kbd "C-w C-p") 'evil-window-prev)
(define-key evil-insert-state-map (kbd "C-w C-p") 'evil-window-prev)
(define-key evil-insert-state-map (kbd "C-w p") 'evil-window-prev)
(define-key evil-motion-state-map (kbd "C-w p") 'evil-window-prev)

In magit, and also globally

;; (define-key magit-status-mode-map (kbd "C-w") nil)
;; (define-key magit-status-mode-map (kbd "C-w C-w") 'evil-window-next)
;; (define-key magit-status-mode-map (kbd "C-w w") 'evil-window-next)
;; (define-key magit-status-mode-map (kbd "C-w C-p") 'evil-window-prev)
;; (define-key magit-status-mode-map (kbd "C-w C-p") 'evil-window-prev)
;; (define-key magit-status-mode-map (kbd "C-w p") 'evil-window-prev)
;; (define-key magit-status-mode-map (kbd "C-w p") 'evil-window-prev)
(setq w-keymap (make-sparse-keymap))
(define-prefix-command 'w-keymap)
(global-set-key (kbd "C-w") 'w-keymap)
(define-key magit-status-mode-map (kbd "C-w") nil)
(define-key magit-diff-mode-map (kbd "C-w") nil)
(global-set-key (kbd "C-w C-w") 'evil-window-next)

Quick reload

Make it so I can quickly reload emacs config.

(defun quick-refresh-dot-emacs ()
  "Quickly reload emacs config"
  (interactive)
  (load-file user-init-file)
  )
(global-set-key (kbd "C-r C-e") 'quick-refresh-dot-emacs)
(define-key evil-ex-map "re" 'quick-refresh-dot-emacs)

Nice little shortcut for evil mode for rifle.

(define-key evil-ex-map "rir" 'helm-org-rifle-agenda-files)
(define-key evil-ex-map "ria" 'helm-org-rifle-occur-org-directory)

More agenda customization

I’ll admit, there’s a header further up for this, but for some reason defining this that far up breaks, and I don’t really want to figure out why org-agenda-mode-map isn’t initiatlized up here

(define-key org-agenda-mode-map (kbd "C-w C-w") 'evil-window-next)

I am evil, so : is special. It sets tags in agenda, which I basically never want to do.

(define-key org-agenda-mode-map (kbd ":") nil)

Evil shortcuts - helm menus, org capture. Basically replace any common C-[something] C-[something] I use with :[something][something]

A bunch of this is effectively recreating helm-config - the file generated from a shell script bundled with helm. It’s easier to roll these in my config so I don’t have to boot from a clean slate, run some random sh, then boot again.

(define-key evil-ex-map "b" 'helm-buffers-list)
(define-key evil-ex-map "mx" 'helm-M-x)
(define-key evil-ex-map "dd" 'helm-apropos)
(define-key evil-ex-map "e" 'helm-find-files)
(define-key evil-ex-map "t" 'org-todo)
(define-key evil-ex-map "co" 'org-open-at-point)
(define-key evil-ex-map "dk" 'describe-key)
(define-key evil-ex-map "dp" 'describe-package)
(define-key evil-ex-map "oc" 'org-capture)
(define-key evil-ex-map "mg" 'magit)
(define-key evil-ex-map "k8s" 'k8s)
(define-key evil-ex-map "cs" 'org-schedule)
(define-key evil-ex-map "c!" 'org-time-stamp-inactive)
(define-key evil-ex-map "ce" 'org-export-dispatch)
(define-key evil-ex-map "kb" 'kill-buffer)
(define-key evil-ex-map "cl" 'org-insert-link)
(define-key evil-ex-map "osl" 'org-store-link)
(define-key evil-ex-map "cni" 'org-roam-node-insert)
(define-key evil-ex-map "xe" 'eval-last-sexp)
(defun es/save-all ()
  "Thin wrapper around saving all buffers"
  (interactive)
  (save-some-buffers t))
(define-key evil-ex-map "sa" 'es/save-all)

Normal map for opening links - remap “go” to do it. Inspired by vim’s gf and gx but go is easier to type.

(define-key evil-normal-state-map "go" 'org-open-at-point)
(evil-define-key 'motion org-agenda-mode-map (kbd "go") 'org-open-at-point)

Do the Thing ex-map

Quick binding for C-cC-c using evil command mode.

(fset 'do-the-thing
      (kmacro-lambda-form [?\C-c ?\C-c] 0 "%d"))

(define-key evil-ex-map "dtt" 'do-the-thing)
(define-key evil-ex-map "cc" 'do-the-thing)

Do today ex-map

Unset shift+right for evil insert, because sometimes it overrides org. I never use it anyway.

(define-key evil-insert-state-map (kbd "S-<right>") nil)

Sticks a priority A todo for today afte the current org node. https://emacs.stackexchange.com/questions/19210/how-to-insert-a-new-same-level-headline-after-current-one

(defalias 'dotoday
 (kmacro "C-<return> S-<right> C-c C-s <return> S-<up> S-<up> A"))
(define-key evil-ex-map "dtd" 'dotoday)

Do today, but with priority b

(defalias 'dotodayb
 (kmacro "C-<return> S-<right> C-c C-s <return> S-<up> A"))
(define-key evil-ex-map "dtb" 'dotodayb)

Do tomorrow

(defalias 'dotmrw
 (kmacro "C-<return> S-<right> C-c C-s S-<right> <return> S-<up> S-<up> A"))

(define-key evil-ex-map "dtm" 'dotmrw)

Insert a do today header, but indented one level from the current header.

(defalias 'doindenttoday
 (kmacro "o M-<return> M-<right> S-<right> S-<up> S-<up> C-c C-s <return>"))
(define-key evil-ex-map "dit" 'doindenttoday)

Do to inbox - experimenting with an inbox view in org-agenda.

(fset 'do-inbox
   (kmacro-lambda-form [?\C-u ?\C-u ?\C-c ?\C-x ?M ?\C-c ?\C-c ?i ?n ?b ?o ?x ?\C-m ?\C-c ?\C-s ?\C-m ?a ?\C-\[ ?x ?e ?n ?d ?- ?k ?b ?\C-i] 0 "%d"))

  (define-key evil-ex-map "dti" 'do-inbox)

Split src block

Let’s me break up an org source block so I can document in between more easily

(fset 'split-src-block
      (kmacro-lambda-form [?i ?# ?+ ?b ?e ?g ?i ?n ?_ ?s ?e ?r ?c ?\C-? ?\C-? ?\C-? ?r ?c ?  ?e ?m ?a ?c ?s ?- ?l ?i ?s ?t ?p ?\C-? ?\C-? ?p escape ?O ?# ?+ ?e ?n ?d ?_ ?s ?r ?c escape ?j ?I ?\C-\[ ?O ?C ?\C-? escape] 0 "%d"))

(define-key evil-ex-map "srcsplit" 'split-src-block)

Link Thread, PR, etc ex-map

Shortcut to make a link called “thread”. Useful for when I want to stamp a link from a slack thread thread

(fset 'thread
 (kmacro-lambda-form [?: ?c ?l ?\C-m ?t ?h ?r ?e ?a ?d ?\C-m] 0 "%d"))

(define-key evil-ex-map "ctl" 'thread)
(fset 'pr-link
 (kmacro-lambda-form [?: ?c ?l ?\C-m ?p ?r ?\C-m] 0 "%d"))

(define-key evil-ex-map "cpl" 'pr-link)
(fset 'link-link
 (kmacro-lambda-form [?: ?c ?l ?\C-m ?l ?i ?n ?k ?\C-m] 0 "%d"))

(define-key evil-ex-map "ckl" 'link-link)

Recover this file

ex map shortcut to recover a file

(define-key evil-ex-map "rtf" 'recover-this-file)

Evil jumplist remapping

Rebind normal C-i to C-j

(define-key evil-normal-state-map (kbd "C-j") 'evil-jump-forward)

Rebind normal C-o to C-k

(define-key evil-normal-state-map (kbd "C-k") 'evil-jump-backward)

Evil motion remapping

A bunch of “do this motion, then center the screen” type changes. There’s probably some better way to curry these but I’m not good enough at elisp.

(defun es/evil-then-center (lambda)
  "Wrapper for any motion to motion, then center the screen"
  (funcall lambda)
  (evil-scroll-line-to-center nil)
  )

(defun es/search-center ()
  "wrapper to center after search"
  (interactive)
  (es/evil-then-center 'evil-search-next)
  )

(define-key evil-motion-state-map (kbd "n") 'es/search-center)

(defun es/search-rev-center ()
  "wrapper to center after reverse search"
  (interactive)
  (es/evil-then-center 'evil-search-previous)
  )
(define-key evil-motion-state-map (kbd "N") 'es/search-rev-center)

(defun es/search-word-center ()
  "wrapper to center after word search"
  (interactive)
  (es/evil-then-center 'evil-search-word-forward)
  )
(define-key evil-motion-state-map (kbd "*") 'es/search-word-center)

(defun es/search-word-rev-center ()
  "wrapper to center after reverse word search"
  (interactive)
  (es/evil-then-center 'evil-search-word-backward)
  )
(define-key evil-motion-state-map (kbd "#") 'es/search-word-rev-center)

Mac copy to clipboard

Yank doesn’t quite do the trick with things, so make a custom one. https://emacs.stackexchange.com/questions/10900/copy-text-from-emacs-to-os-x-clipboard

Also add pp to do visual paste, since pc overrides it.

(fset 'pbcopy
      (kmacro-lambda-form [?\C-\[ ?| ?p ?b ?c ?o ?p ?y ?\C-m] 0 "%d"))

(define-key evil-visual-state-map "pc" 'pbcopy)
(define-key evil-visual-state-map "pp" 'evil-paste-after)

Insert link on highlighted text

(define-key evil-visual-state-map "cl" 'org-insert-link)
(define-key evil-visual-state-map "cc" 'evil-change)

Debugging

Trying to see what this does on startup so I can optimize my init/dotfiles.

;;(setq message-log-max t)

Layout

(defadvice org-agenda (around split-vertically activate)
  (let ((split-width-threshold 300))  ; or whatever width makes sense for you
    ad-do-it))

Wrap text by default

(add-hook 'text-mode-hook 'visual-line-mode)

Org capture setup

Inbox directory

(setq org-default-notes-file "~/Dropbox/org/inbox.org")

Stick backup files elsewhere. They screw up IFTTT’s dropbox integration for some reason.

(setq backup-directory-alist `(("." . "./.emacsSaves")))

Start server

(load "server")
(unless (server-running-p) (server-start))

Capture templates

(setq org-capture-templates
      '(("p" "Personal" entry (file "~/Dropbox/org/inbox.org")
         "* TODO %?\n")
        ("w" "Work" entry (file "~/Dropbox/org/projects/workInbox.org")
         "* TODO %?\n")
        ("t" "Things on my mind" entry (file "~/Dropbox/org/projects/tList.org")
         "* TODO %?\n" )
        ("s" "Stuff" entry (file "~/Dropbox/org/projects/stuff.org")
         "* TODO %?\n")))

Powerline

(use-package powerline-evil
  :config
  (powerline-evil-center-color-theme))

Ubuntu

This is a hack because I probably have a bad config on my ubuntu machine. For some reason, string-empty-p isn’t defined at runtime, but when I describe-function it, it shows up. This breaks org-agenda. Requring subr-x at startup fixes this.

(require 'subr-x)

Ubuntu specific (hopefully this doesn’t break mac!) - this forces org to update to a later version.

(use-package org :ensure org-contrib :pin org)

More hacks to force dependencies into place, hopefully.

(require 'org-macs)

ODT Styles

The default styles are gross. I use google docs all day erry day. This is an ODT file that has the headers for google docs.

This seems to barf on multiline source blocks, but I don’t use that for notes much, so that’s ok (typically the last line of a source block is unstyled).

(setq org-odt-styles-file (concat (getenv "PATH_TO_DOTFILES_REPO") "/gdocStyles.odt"))

Table of contents is ugly, and google doc styles do it for you anyway (in google docs)

(setq org-export-with-toc nil)

So this is an attempt to make people in a meeting todos, and then use todos to quickly flag who is speaking as I’m taking notes. You can only do todo states on headers by default, so I’m using inlinetask to try and use todo states elsewhere.

Update: Doesn’t quite work the way I want, it renders kinda ugly in a huge block. If I’m indented far enough (5?) the todo states seem to work. Keeping because this is needed for the meeting minutes stuff below.

Update: four *s seems to work to not use a header, which will work for me.

(require 'org-inlinetask)

Meeting minutes

This seems interesting. Try it out. Update - as of [2021-08-28 Sat]ish, I basically use roam for notes now, and having roam nodes for people makes it easy to add attendees. This was an interesting experiment, but I’m mostly not using it at this point.

(require 'org)
(require 'dash)

(defun org-actionitems-extract-entry ()
  (-let* ((entries (org-entry-properties))
          ((&alist "ITEM" "TODO" "DEADLINE") entries))
    (list ITEM TODO DEADLINE)))

(defun org-dblock-write:actionitems (params)
  (let ((match (or (plist-get params :match) "/+TODO")))
    (insert-before-markers "| What | Who | When |\n")
    (insert-before-markers "|-\n")
    (let* ((tasks (org-map-entries 'org-actionitems-extract-entry match))
           (rows (-map (lambda (task)
                         (->> task
                           (-map (lambda (item) (or item "")))
                           (apply 'format "| %s | %s | %s |")))
                       tasks))
           (table (string-join rows "\n")))
      (insert-before-markers table))
    (org-table-align)))

Mermaid in org

https://github.com/arnm/ob-mermaid Install this in “~/” or else!

(use-package ob-mermaid)
(setq ob-mermaid-cli-path "~/node_modules/.bin/mmdc")

This is what this ends up looking like. Keeping it here as an example - this is just the thing that the mermaid live editor ships with.

graph TD
    A[Christmas] -->|Get money| B(Go shopping)
    B --> C{Let me think}
    C -->|One| D[Laptop]
    C -->|Two| E[iPhone]
    C -->|Three| F[fa:fa-car Car]
Loading

mermaidTest.png

Sensible Defaults

Use sensible defaults from the git submodule.

(load-file (concat (getenv "PATH_TO_DOTFILES_REPO") "/sensible-defaults.el/sensible-defaults.el"))
(sensible-defaults/use-all-settings)
(sensible-defaults/use-all-keybindings)

Exit hooks/config

Trim whitespace

(add-hook 'write-file-hooks 'delete-trailing-whitespace)

Don’t prompt for exit - this must be after sensible defaults, as it overwrites it.

(setq confirm-kill-emacs nil)

Helm

Configure helm search - basically make everything as fuzzy as possible.

(setq org-outline-path-complete-in-steps nil)
(setq helm-completion-style 'helm-flex)
(add-to-list 'completion-styles 'helm-flex)
(setq helm-apropos-fuzzy-match t)
(setq helm-locate-fuzzy-match t)
(setq helm-mode-fuzzy-match t)

Override M-x

(global-set-key (kbd "M-x") 'helm-M-x)

Roam

General setup and config

make symlinks work

(setq find-file-visit-truename t)

Probably need to change the viewer per OS.

(setq org-roam-graph-executable "neato")
(setq org-roam-db-location "~/org/roam/org-roam.db")
(setq org-roam-graph-viewer "/usr/bin/open")
(use-package org-roam
  :ensure t
  :init
  (setq org-roam-v2-ack t)
  :custom
  (org-roam-directory (file-truename "~/org/roam"))
  (org-roam-completion-everywhere t)
  :bind (("C-c n l" . org-roam-buffer-toggle)
         ("C-c n f" . org-roam-node-find)
         ("C-c n g" . org-roam-graph)
         ("C-c n i" . org-roam-node-insert)
         ("C-c n c" . org-roam-capture)
         ("C-c n d" . org-roam-dailies-capture-today)
         :map org-mode-map
         ("C-M-i" . completion-at-point))
  :config
  (org-roam-setup)
  ;; If using org-roam-protocol
  (require 'org-roam-protocol))

Roam ex map bindings

(define-key evil-ex-map "ni" 'org-roam-node-insert)
(define-key evil-ex-map "nf" 'org-roam-node-find)
(define-key evil-ex-map "nb" 'org-roam-buffer-toggle)

Capture templates for roam

(setq org-roam-capture-templates
      '(
        ("n" "normal" plain "%?"
         :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org"
                            "#+title: ${title}")
         :unnarrowed t)
        ("f" "fun" plain "%?"
         :if-new (file+head "fun/%<%Y%m%d%H%M%S>-${slug}.org"
                            "#+title: ${title}\n#+filetags: fun\n")
         :unnarrowed t)
        ("w" "work" plain "%?"
         :if-new (file+head "work/%<%Y%m%d%H%M%S>-${slug}.org"
                            "#+title: ${title}")
         :unnarrowed t)
        ))
(setq org-roam-node-display-template "${title:30}")

Synchronize cache on startup

(org-roam-db-sync)

Daily workflow

Dailies go here

(setq org-roam-dailies-directory "daily/")

Daily linking

Workflow to link things from agenda to daily note to more intentionally curate todo list. Taken from this post.

Get daily agenda

This doesn’t quite seem to work yet - I suspect it doesn’t play nice with super agenda

(setq org-agenda-custom-commands
      '(("d" "Daily schedule"
         ((agenda ""
                  ((org-agenda-span 'day)
                   (org-agenda-use-time-grid nil)
                   (org-agenda-skip-function '(org-agenda-skip-entry-if 'scheduled 'deadline))))))))
(defun as/get-daily-agenda (&optional date)
  "Return the agenda for the day as a string."
  (interactive)
  (let ((file (make-temp-file "daily-agenda" nil ".txt")))
    (org-agenda nil "d" nil)
    (when date (org-agenda-goto-date date))
    (org-agenda-write file nil nil "*Org Agenda*")
    (kill-buffer)
    (with-temp-buffer
      (insert-file-contents file)
      (goto-char (point-min))
      (kill-line 2)
      (while (re-search-forward "^  " nil t)
        (replace-match "- " nil nil))
      (buffer-string))))

Daily capture templates

This is the bit referenced above that inserts the target header as a link into the org roam note. Pretty handy!

 (defun es/org-roam-header (title)
   "Formats a roam title with the suffix"
   (concat "#+title: %<%Y-%m-%d (%A)> - " title "\n#+startup: showall\n"
           "* Do Today\n* Journal\n")
   )
; (setq org-roam-head
;       (concat "#+title: %<%Y-%m-%d (%A)>\n#+startup: showall\n"
;               "* Do Today\n* Journal\n"))
 (setq personal-header (es/org-roam-header "Personal"))
 (setq work-header (es/org-roam-header "Work"))
 (setq personal-dir "~/Dropbox/org/roam/daily/")
 (setq work-dir "~/org/roam/daily/")
 (setq org-daily-filename "%<%Y-%m-%d>.org")
 (setq personal-file (concat personal-dir org-daily-filename))
 (setq work-file (concat work-dir org-daily-filename))
 (setq org-roam-dailies-capture-templates

         `(("j" "journal" entry
            "* %<%H:%M> %?"
            :if-new (file+head+olp ,personal-file ,personal-header ("Journal")))
           ("t" "do today - work" entry
            "** TODO [#A] %a\nSCHEDULED: <%<%Y-%m-%d>>"
            :if-new (file+head+olp ,work-file ,work-header ("Do Today"))
            :immediate-finish t)
           ("p" "do today - personal" entry
            "** TODO [#A] %a\nSCHEDULED: <%<%Y-%m-%d>>"
            :if-new (file+head+olp ,personal-file ,personal-header ("Do Today"))
            :immediate-finish t)
           ))

Make a shortcut in org agenda to cap something.

(evil-define-key 'motion org-agenda-mode-map (kbd "c") 'org-roam-dailies-capture-today)

Open daily buffer for current day

Quick jump to work or personal daily node.

(defun es/open-roam-daily-today (target)
  "Thin wrapper around org-roam-dailies-goto-today that also saves the file."
  (org-roam-dailies-goto-today target)
  (save-buffer)
  )
(defun es/open-daily-work-buffer ()
  ""
  (interactive)
  (es/open-roam-daily-today "t")
  (es/set-org-agenda-files)
  )
(defun es/open-daily-personal-buffer ()
  ""
  (interactive)
  (es/open-roam-daily-today "p")
  (es/set-org-agenda-files)
  )

(define-key evil-ex-map "rd" 'es/open-daily-work-buffer)
(define-key evil-ex-map "rp" 'es/open-daily-personal-buffer)

Org roam UI

(use-package websocket)
(use-package simple-httpd)
(use-package org-roam-ui)

(define-key evil-ex-map "oru" 'org-roam-ui-open)

Languages

Fish

(use-package fish-mode)

Graphql

(use-package graphql-mode)

Go

(use-package go-mode)

Protobuf

(use-package protobuf-mode)

Ts, react, all the frontend stuff

Probably do something like this

Treesitter

Starting to play with this and see how it works.

(use-package tree-sitter)
(use-package tree-sitter-langs)

IN-PROGRESS Notion

This is an attempt to hit the notion api in order to dump tasks out of org into notion.

My anticipated workflow is, while grooming my inbox, instead of refiling an item, I export it to Notion via POST.

Then I mark the item EXPORTED (custom TODO state) and archive it.

This is also the first elisp I’m writing on my own, so it’s a learning experience.

Thus far I’ve managed to extract the todo state and map it to the todo status I use in notion.

Next, I need to format a payload with local secrets (api key) and hit the api. It looks like the preferred way to do this in emacs is request.el.

(require 'org-element)
;; make a function that gets the org heading components as an alist mapped to the things in notion
;; make a function that json encodes that
;; make a function to call the api
(defun org-todo-to-notion-todo (org-todo)
  "map org todo status to notion status - you should change this to fit whatever todo statuses you have"
  (plist-get '(TODO "To Do" IN-PROGRESSS "Doing" DONE "Done") (intern org-todo)))

(defun org-heading-to-notion-json ()
  "Encode current heading as json"
  (let* ((ohc (org-heading-components))
         (todo-state (nth 2 ohc))
         (notion-todo-state (org-todo-to-notion-todo todo-state)))
    (message notion-todo-state)))

GUI emacs stuff

Font size default

(set-face-attribute 'default nil :height 140)