Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1647 lines (1535 sloc) 58.2 KB

Emacs Config

Load better default settings

This is a straight clone of HRS defaults setup

(load-file "~/.emacs.d/sensible-defaults.el")
(sensible-defaults/use-all-settings)
(sensible-defaults/use-all-keybindings)
(sensible-defaults/backup-to-temp-directory)

Configure use-package

Add MELPA to package-list

(require 'package)
(add-to-list 'package-archives
             '("melpa" . "http://melpa.org/packages/") t)
(add-to-list 'package-archives
             '("org" . "https://orgmode.org/elpa") t)

Make sure use-package is installed

(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

Compile packages and ensure latest version in available - not required anymore

;; (use-package auto-compile
;;   :config (auto-compile-on-load-mode))
;; (setq load-prefer-newer t)

Use quelpa

(use-package quelpa
  :ensure t)

(use-package quelpa-use-package
  :ensure t)

Tweaking UX

Utility Functions

Some handy functionality, mostly drawn from other configs (HRS, Nicolas Petton, JWiegley)

(defvar saved-window-configuration nil)
(defun push-window-configuration ()
  (interactive)
  (push (current-window-configuration) saved-window-configuration))

(defun generate-scratch-buffer ()
  "Create and switch to a temporary scratch buffer with a random
       name."
  (interactive)
  (switch-to-buffer (make-temp-name "scratch-")))

(defun add-auto-mode (mode &rest patterns)
  "Add entries to `auto-mode-alist' to use `MODE' for all given file `PATTERNS'."
  (dolist (pattern patterns)
    (add-to-list 'auto-mode-alist (cons pattern mode))))

(defun kill-current-buffer ()
  "Kill the current buffer without prompting."
  (interactive)
  (kill-buffer (current-buffer)))

(defun iterm-goto-filedir-or-home ()
  "Go to present working dir and focus iterm"
  (interactive)
  (do-applescript
   (concat
    " tell application \"iTerm2\"\n"
    "   tell the current session of current window\n"
    (format "     write text \"cd %s\" \n"
            ;; string escaping madness for applescript
            (replace-regexp-in-string "\\\\" "\\\\\\\\"
                                      (shell-quote-argument (or default-directory "~"))))
    "   end tell\n"
    " end tell\n"
    " do shell script \"open -a iTerm\"\n"
    ))
  )
;; Opens iterm
(defun iterm-focus ()
  (interactive)
  (do-applescript
   " do shell script \"open -a iTerm\"\n"
   ))


(defun split-window-below-and-switch ()
  "Split the window horizontally, then switch to the new pane."
  (interactive)
  (split-window-below)
  (balance-windows)
  (other-window 1))

(defun split-window-right-and-switch ()
  "Split the window vertically, then switch to the new pane."
  (interactive)
  (split-window-right)
  (balance-windows)
  (other-window 1))

(defun package-upgrade-all ()
  "Upgrade all packages automatically without showing *Packages* buffer."
  (interactive)
  (package-refresh-contents)
  (let (upgrades)
    (cl-flet ((get-version (name where)
                           (let ((pkg (cadr (assq name where))))
                             (when pkg
                               (package-desc-version pkg)))))
      (dolist (package (mapcar #'car package-alist))
        (let ((in-archive (get-version package package-archive-contents)))
          (when (and in-archive
                     (version-list-< (get-version package package-alist)
                                     in-archive))
            (push (cadr (assq package package-archive-contents))
                  upgrades)))))
    (if upgrades
        (when (yes-or-no-p
               (message "Upgrade %d package%s (%s)? "
                        (length upgrades)
                        (if (= (length upgrades) 1) "" "s")
                        (mapconcat #'package-desc-full-name upgrades ", ")))
          (save-window-excursion
            (dolist (package-desc upgrades)
              (let ((old-package (cadr (assq (package-desc-name package-desc)
                                             package-alist))))
                (package-install package-desc)
                (package-delete  old-package)))))
      (message "All packages are up to date"))))

UI/UX things

Remove scroll bars

(tool-bar-mode 0)
(menu-bar-mode 0)
(scroll-bar-mode -1)

Inhibit startup message

(setq inhibit-startup-message t)

Turnoff scroll-bell sound

(setq ring-bell-function 'ignore)

Conservative scrolling

(setq scroll-conservatively 100)

Highlight current line

  (when window-system
    (global-hl-line-mode))
;;  (set-face-background 'hl-line "#778184")

Load icons package

(use-package all-the-icons
 :ensure t)

Load theme

(defun my/load-theme (frame)
  (select-frame frame)
  (load-theme 'zerodark t))
(if (daemonp)
    (add-hook 'after-make-frame-functions #'my/load-theme)
  (load-theme 'zerodark t))
;;        (use-package zerodark-theme
  ;;        :ensure t
    ;;      :config
      ;;    (load-theme 'zerodark 'no-confirm))
;;          :hook 'zerodark-setup-modeline-format)
 (use-package zerodark-theme
    :ensure t
    :config
    :hook (my/load-theme)
    :init
    (add-hook 'after-init-hook 'zerodark-setup-modeline-format))

Load rainbow-mode

(use-package rainbow-mode
  :ensure t
  :commands rainbow-mode)

Fonts and resizing

  • Sets default font and font size
  • Text scaling now affects all buffers, not only current
(setq default-font "Menlo")
(setq default-font-size 14)
(setq current-font-size default-font-size)

(setq font-change-increment 1.1)

(defun font-code ()
  (concat default-font "-" (number-to-string current-font-size)))

(defun set-font-size ()
  "Set the font to `default-font' at `current-font-size'.
Set that for the current frame, and also make it the default for
other, future frames."
  (let ((font-code (font-code)))
    (add-to-list 'default-frame-alist (cons 'font font-code))
    (set-frame-font font-code)))

(defun reset-font-size ()
  "Change font size back to `default-font-size'."
  (interactive)
  (setq current-font-size default-font-size)
  (set-font-size))

(defun increase-font-size ()
  "Increase current font size by a factor of `font-change-increment'."
  (interactive)
  (setq current-font-size
        (ceiling (* current-font-size font-change-increment)))
  (set-font-size))

(defun decrease-font-size ()
  "Decrease current font size by a factor of `font-change-increment', down to a minimum size of 1."
  (interactive)
  (setq current-font-size
        (max 1
             (floor (/ current-font-size font-change-increment))))
  (set-font-size))

(define-key global-map (kbd "C-)") 'reset-font-size)
(define-key global-map (kbd "C-+") 'increase-font-size)
(define-key global-map (kbd "C-=") 'increase-font-size)
(define-key global-map (kbd "C-_") 'decrease-font-size)
(define-key global-map (kbd "C--") 'decrease-font-size)

(reset-font-size)

Enable function folding

      (use-package origami
        :ensure t
        :bind (:map origami-mode-map
                    ("C-c C-o" . 'origami-toggle-node)
                    ("C-c C-f" . 'origami-toggle-all-nodes)))
      (add-hook 'global-origami-mode #'origami-mode)
;;        :hook global-origami-mode)

Expand regions

(use-package expand-region
  :ensure t
  :commands (er/expand-region er/contract-region)
  :bind (
         ("M-=" . er/expand-region)
         ("M--" . er/contract-region)))

Flycheck

(use-package flycheck
  :ensure t)

(defun adjust-syntax-spellcheck-timer ()
  "Adjust how often we check for errors based on if there are any.
  This lets us fix any errors as quickly as possible, but in a
  clean buffer we're an order of magnitude laxer about checking."
  (setq flycheck-idle-change-delay
        (if flycheck-current-errors 0.5 30.0)))

;; Each buffer gets its own idle-change-delay because of the
;; buffer-sensitive adjustment above.
(make-variable-buffer-local 'flycheck-idle-change-delay)

(add-hook 'flycheck-after-syntax-check-hook
          'adjust-syntax-spellcheck-timer)

;; Remove newline checks, since they would trigger an immediate check
;; when we want the idle-change-delay to be in effect while editing.
(setq flycheck-check-syntax-automatically '(save
                                            idle-change
                                            mode-enabled))

(eval-after-load 'flycheck
  '(custom-set-variables
    '(flycheck-display-errors-function #'flycheck-pos-tip-error-messages)))

(provide 'setup-flycheck)

Load up which-key

Sometimes my brain takes a fart and then its useful to know which key to press

(use-package which-key
  :defer 5
  :ensure t)

Navigation & Interface

ivy

(use-package ivy
  :ensure t
  :diminish
  :bind (("C-x b" . ivy-switch-buffer)
         ("C-x B" . ivy-switch-buffer-other-window)
         ("M-H"   . ivy-resume))

  :bind (:map ivy-minibuffer-map
              ("<tab>" . ivy-alt-done)
              ("SPC"   . ivy-alt-done-or-space)
              ("C-d"   . ivy-done-or-delete-char)
              ("C-i"   . ivy-partial-or-done)
              ("C-r"   . ivy-previous-line-or-history)
              ("M-r"   . ivy-reverse-i-search))

  :bind (:map ivy-switch-buffer-map
              ("C-k" . ivy-switch-buffer-kill))

  :custom
  (ivy-dynamic-exhibit-delay-ms 200)
  (ivy-height 10)
  (ivy-initial-inputs-alist nil t)
  (ivy-magic-tilde nil)
  (ivy-re-builders-alist '((t . ivy--regex-ignore-order)))
  (ivy-use-virtual-buffers t)
  (ivy-wrap t)

  :preface
  (defun ivy-done-or-delete-char ()
    (interactive)
    (call-interactively
     (if (eolp)
         #'ivy-immediate-done
       #'ivy-delete-char)))

  (defun ivy-alt-done-or-space ()
    (interactive)
    (call-interactively
     (if (= ivy--length 1)
         #'ivy-alt-done
       #'self-insert-command)))

  (defun ivy-switch-buffer-kill ()
    (interactive)
    (debug)
    (let ((bn (ivy-state-current ivy-last)))
      (when (get-buffer bn)
        (kill-buffer bn))
      (unless (buffer-live-p (ivy-state-buffer ivy-last))
        (setf (ivy-state-buffer ivy-last)
              (with-ivy-window (current-buffer))))
      (setq ivy--all-candidates (delete bn ivy--all-candidates))
      (ivy--exhibit)))

  ;; This is the value of `magit-completing-read-function', so that we see
  ;; Magit's own sorting choices.
  (defun my-ivy-completing-read (&rest args)
    (let ((ivy-sort-functions-alist '((t . nil))))
      (apply 'ivy-completing-read args)))

  :config
  (ivy-mode 1)
  (ivy-set-occur 'ivy-switch-buffer 'ivy-switch-buffer-occur))

ace-window

(use-package ace-window
  :ensure t
  :init
  (progn
    (global-set-key [remap other-window] 'ace-window)
    (custom-set-faces
     '(aw-leading-char-face
       ((t (:inherit ace-jump-face-foreground :height 3.0)))))
    ))

counsel

(use-package counsel
  :ensure t)

swiper

(use-package swiper
  :ensure try
  :bind (("C-s" . swiper)
   ("C-r" . swiper)
   ("C-c C-r" . ivy-resume)
   ("M-x" . counsel-M-x)
   ("C-x C-f" . counsel-find-file))
  :config
  (progn
    (ivy-mode 1)
    (setq ivy-use-virtual-buffers t)
    (setq ivy-display-style 'fancy)
    (define-key read-expression-map (kbd "C-r") 'counsel-expression-history)
    ))

dired

Kill files/buffers that are deleted in dired

(setq dired-clean-up-buffers-too t)

Copy directories recursively without confirmation

(setq dired-recursive-copies 'always)

Ask before recursively deleting a directory

(setq dired-recursive-deletes 'top)

Enable dired+

(use-package dired+
  :quelpa (dired+ :fetcher github :repo "emacsmirror/dired-plus"))

Enable dired-toggle

(use-package dired-toggle
  :ensure nil
  :bind ("C-c ~" . dired-toggle)
  :preface
  (defun my-dired-toggle-mode-hook ()
    (interactive)
    (visual-line-mode 1)
    (setq-local visual-line-fringe-indicators '(nil right-curly-arrow))
    (setq-local word-wrap nil))
  :hook (dired-toggle-mode . my-dired-toggle-mode-hook))

company

(use-package company
  :ensure t
  :init (progn
          (add-hook 'prog-mode-hook 'company-mode))
  :config (progn
            (setq company-idle-delay 0.5)
            (setq company-tooltip-limit 10)
            (setq company-minimum-prefix-length 2)
            (setq company-tooltip-flip-when-above t)))

(use-package company-dabbrev
  :ensure nil
  :config (progn
            (setq company-dabbrev-ignore-case t)
            (setq company-dabbrev-downcase nil)))
(add-hook 'after-init-hook 'global-company-mode)

google-this

(use-package google-this
  :ensure t
  :bind-keymap ("C-c /" . google-this-mode-submap)
  :bind* ("M-SPC" . google-this-search)
  :bind (:map google-this-mode-map
              ("/" . google-this-search)))

indent-shift

(use-package indent-shift
  :ensure nil
  :bind (("C-c <" . indent-shift-left)
         ("C-c >" . indent-shift-right)))

drag-stuff

(use-package drag-stuff
 :ensure t)
(drag-stuff-global-mode 1)
(drag-stuff-define-keys)

multiple-cursors

(use-package multiple-cursors
  :ensure t)
;; Edit all selected lines
(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
(global-set-key (kbd "C-M-g") 'mc/mark-all-like-this)
(global-set-key (kbd "C-.") 'mc/skip-to-next-like-this)
(global-set-key (kbd "C-,") 'mc/skip-to-previous-like-this)

Version Control & Project Management

Emacs Backups

The below settings will alter how Emacs handles backups, more info can be found here

Basic settings

(setq version-control t     ;; Use version numbers for backups.
      kept-new-versions 10  ;; Number of newest versions to keep.
      kept-old-versions 0   ;; Number of oldest versions to keep.
      delete-old-versions t ;; Don't ask to delete excess backup versions.
      backup-by-copying t)  ;; Copy all files, don't rename them.

Create backups for version-controlled files too

(setq vc-make-backup-files t)

Finally, we want to create a backup every time we save using C-x C-s. We will create two different backups for this:

  1. Per-session backups
    1. Per-save backups
;; Default and per-save backups go here:
(setq backup-directory-alist '(("" . "~/.emacs.d/backup/per-save")))

(defun force-backup-of-buffer ()
  ;; Make a special "per session" backup at the first save of each
  ;; emacs session.
  (when (not buffer-backed-up)
    ;; Override the default parameters for per-session backups.
    (let ((backup-directory-alist '(("" . "~/.emacs.d/backup/per-session")))
          (kept-new-versions 3))
      (backup-buffer)))
  ;; Make a "per save" backup on each save.  The first save results in
  ;; both a per-session and a per-save backup, to keep the numbering
  ;; of per-save backups consistent.
  (let ((buffer-backed-up nil))
    (backup-buffer)))

(add-hook 'before-save-hook  'force-backup-of-buffer)

Magit

(use-package magit
  :ensure t
  :bind (("C-x g" . magit-status)
         ("C-x G" . magit-status-with-prefix))
  :bind (:map magit-mode-map
              ("U" . magit-unstage-all)
              ("M-h") ("M-s") ("M-m") ("M-w"))
  :bind (:map magit-file-section-map ("<C-return>"))
  :bind (:map magit-hunk-section-map ("<C-return>"))
  :preface
  (defun magit-monitor (&optional no-display)
    "Start git-monitor in the current directory."
    (interactive)
    (let* ((path (file-truename
                  (directory-file-name
                   (expand-file-name default-directory))))
           (name (format "*git-monitor: %s*"
                         (file-name-nondirectory path))))
      (unless (and (get-buffer name)
                   (with-current-buffer (get-buffer name)
                     (string= path (directory-file-name default-directory))))
        (with-current-buffer (get-buffer-create name)
          (cd path)
          (ignore-errors
            (start-process "*git-monitor*" (current-buffer)
                           "git-monitor" "-d" path))))))

  (defun magit-status-with-prefix ()
    (interactive)
    (let ((current-prefix-arg '(4)))
      (call-interactively 'magit-status)))

  :hook (magit-mode . hl-line-mode)
  :config
  (use-package magit-commit
    :config
    (use-package git-commit))

  (use-package magit-files
    :config
    (global-magit-file-mode))

  (add-hook 'magit-status-mode-hook #'(lambda () (magit-monitor t)))

  (eval-after-load 'magit-remote
    '(progn
       (magit-define-popup-action 'magit-fetch-popup
         ?f 'magit-get-remote #'magit-fetch-from-upstream ?u t)
       (magit-define-popup-action 'magit-pull-popup
         ?F 'magit-get-upstream-branch #'magit-pull-from-upstream ?u t)
       (magit-define-popup-action 'magit-push-popup
         ?P 'magit--push-current-to-upstream-desc
         #'magit-push-current-to-upstream ?u t))))

(use-package magit-popup
  :defer t)

(use-package magit-imerge
  ;; jww (2017-12-10): Need to configure.
  :disabled t
  :after magit)

(use-package magithub
  :disabled t
  :after magit
  :config
  (magithub-feature-autoinject t)

  (require 'auth-source-pass)
  (defvar my-ghub-token-cache nil)

  (advice-add
   'ghub--token :around
   #'(lambda (orig-func host username package &optional nocreate forge)
       (or my-ghub-token-cache
           (setq my-ghub-token-cache
                 (funcall orig-func host username package nocreate forge))))))

(use-package magithub-completion
  :commands magithub-completion-enable)

projectile

(use-package projectile
  :ensure t
  :defer 5
  :diminish
  :bind* ("C-c TAB" . projectile-find-other-file)
  :bind-keymap ("C-c p" . projectile-command-map)
  :config
  (projectile-global-mode))

helm

(use-package helm
  :ensure t
  :defer t
  :bind (:map helm-map
              ("<tab>" . helm-execute-persistent-action)
              ("C-i"   . helm-execute-persistent-action)
              ("C-z"   . helm-select-action)
              ("A-v"   . helm-previous-page))
  :config
  (helm-autoresize-mode 1))
(global-set-key (kbd "C-x b") 'helm-buffers-list)

Major Modes

web-mode

  • Enable rainbow mode
  • Set indentation to 2 spaces
(use-package web-mode
  :ensure t
  :config
  (add-hook 'web-mode-hook
            (lambda ()
              (rainbow-mode)
              (setq web-mode-markup-indent-offset 2)))
  (add-auto-mode
   'web-mode
   "\\.blade$"
   "\\.phtml$"
   "\\.erb$"
   "\\.html$"
   "\\.php$"
   "\\.rhtml$"))

js2-mode

  (use-package js2-mode
    :ensure t
    :config
    (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode)))
(add-hook 'j2-mode-hook (lambda () (setq js2-basic-offset 2)))

json-mode

(use-package json-mode
  :ensure t)

js2-refactor

(use-package js2-refactor
  :ensure t)
(use-package xref-js2
  :ensure t)
(setq js2-highlight-level 3)
(add-hook 'js2-mode-hook #'js2-refactor-mode)
(js2r-add-keybindings-with-prefix "C-c C-r")
(define-key js2-mode-map (kbd "C-k") #'js2r-kill)
(add-hook 'js2-mode-hook
  (lambda ()
    (linum-mode 1)))

;; js-mode (which js2 is based on) binds "M-." which conflicts with xref, so
;; unbind it.
(define-key js-mode-map (kbd "M-.") nil)

(add-hook 'js2-mode-hook (lambda ()
  (add-hook 'xref-backend-functions #'xref-js2-xref-backend nil t)))

=markdown

-mode=

(use-package markdown-mode
  :ensure t
  :mode (("\\`README\\.md\\'" . gfm-mode)
         ("\\.md\\'"          . markdown-mode)
         ("\\.markdown\\'"    . markdown-mode))
  :init (setq markdown-command "multimarkdown"))

(use-package markdown-preview-mode
  :after markdown-mode
  :config
  (setq markdown-preview-stylesheets
        (list (concat "https://github.com/dmarcotte/github-markdown-preview/"
                      "blob/master/data/css/github.css"))))
(custom-set-variables '(markdown-command "/usr/local/bin/markdown"))

rest-client

Load company-enabled restclient

(use-package company-restclient
  :ensure t
  :after (company restclient))

Load regular rest client

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

css-mode

 (use-package css-mode
   :commands css-mode
   :init
   (setq css-indent-offset 2)
   :config
   (use-package rainbow-mode
     :init
     (dolist (hook '(css-mode-hook sass-mode-hook))
	(add-hook hook 'rainbow-mode))))

scss-mode

(use-package scss-mode
  :ensure t
  :config
  (setq scss-compile-at-save nil))

c/c++

(add-auto-mode
 'c++-mode
 "\\.cpp"
 "\\.h"
 "\\.hpp")

Enable flycheck for C

(add-hook 'c-mode-common-hook #'flycheck-mode)

Always indent with 4 spaces, in the Linux kernel style.

(setq-default c-default-style "linux"
              c-basic-offset 4)

Enable hungry delete in C

(setq-default c-hungry-delete-key t)

Auto-insert include guards in .h files

(defun gb-insert-h-guard ()
  (interactive)
  (cons "\\.\\([Hh]\\|hh\\|hpp\\)\\'" "My C/C++ header")
  '(nil
    (let* ((noext (substring buffer-file-name 0 (match-beginning 0)))
           (nopath (file-name-nondirectory noext))
           (ident (concat (upcase nopath) "_H_")))
      (concat "#ifndef " ident "\n"
              "#define " ident "\n\n\n"
              "\n\n#endif // " ident "\n"))
    ))

Switch between .h and .c/.cpp files

(defun gb-cpp-switch-h-cpp (arg)
  "Switch between .h and .cpp buffer or file. Look first into the
 open buffers, and look into the current directory if no matching
 buffer was found.
 With argument, switch to the second choice. For example, from a
 .h or a .cpp open the .t.cpp, or from a .t.cpp open the .cpp."
  (interactive "P")
  (let ((ext (bde-file-name-extension (buffer-file-name))))
    (let ((base-name    (string-truncate (buffer-name) (length ext)))
    (base-path    (string-truncate (buffer-file-name) (length ext)))
    (matching-ext (cdr (find-if (lambda (i)
          (string= (car i) ext))
        exordium-cpp-header-switches))))
(when (and arg matching-ext)
  (setq matching-ext (cdr matching-ext)))
(cond (matching-ext
       (unless
     (catch 'found
       (flet ((when-exists-find-and-throw
         (file)
         (when (file-exists-p file)
           (find-file file)
           (throw 'found t))))
         (dolist (candidate-ext matching-ext)
     ;; Look for a buffer matching candidate-ext
     (let ((buff (concat base-name candidate-ext)))
       (when (bufferp (get-buffer buff))
         (switch-to-buffer buff)
         (throw 'found t)))
     ;; No buffer => look for a file
     (when-exists-find-and-throw
      (concat base-path candidate-ext))
     ;; No file in current dir => look in test subdirectory
     (cond (arg
      (let ((base-dir (file-name-directory (buffer-file-name)))
            (test-dirs '("test" "tst")))
        (dolist (test-dir test-dirs)
          (let ((test-path
           (concat (file-name-as-directory test-dir)
             base-name candidate-ext)))
            (when-exists-find-and-throw
             (concat base-dir test-path))
            (when-exists-find-and-throw
             (concat (file-name-directory
          (directory-file-name base-dir))
               test-path))))))
           ;; If test file => look in parent and group directories
           ((string-match ".*/t\\(e\\)?st/.*\.[gt]\.cpp$"
              (buffer-file-name))
      (let ((base-dir
             (file-name-directory
        (directory-file-name (file-name-directory
                  (buffer-file-name))))))
        (when-exists-find-and-throw
         (concat base-dir base-name candidate-ext))
        (when (string-match "^\\([a-z]+\\)_" base-name)
          (when-exists-find-and-throw
           (concat base-dir
             (file-name-as-directory
              (match-string 1 base-name))
             base-name candidate-ext))))))))
       ;; No buffer or file for any matching-ext
       nil)
   (message "No matching buffer or file")))
      (t (message "This is not a C/C++ file"))))))

(define-key c-mode-base-map [(control tab)] 'gb-cpp-switch-h-cpp)

lisp

(use-package slime
  ;; :load-path (expand-site-lisp "slime")
  :commands slime
  :config

  (progn
    (add-hook
     'slime-load-hook
     #'(lambda ()
   (slime-setup
    '(slime-fancy
      slime-repl
      slime-fuzzy
      slime-company))))
    (setq slime-net-coding-system 'utf-8-unix)
    (setq inferior-lisp-program "/usr/local/bin/clisp")))

Enable lisp eval in org-mode

(org-babel-do-load-languages
 'org-babel-load-languages
 '((lisp . t)))

Org Mode and Task Management

org-bullets

(use-package org-bullets
  :ensure t
  :config
  (add-hook 'org-mode-hook (lambda() (org-bullets-mode 1))))

pdf-tools

(use-package pdf-tools
  :ensure t)

org-ref

I like to be able to store notes when I read papers / studies

(use-package org-ref
  :ensure t
  :config
  (setq org-ref-notes-directory "~/Dropbox/org/reading"
        org-ref-bibliography-notes "~/Dropbox/org/reading/index.org"
        org-ref-default-bibliography '("~/Dropbox/org/reading/index.bib")
        org-ref-pdf-directory "~/Dropbox/org/reading/lib/")) ;; where documents are stored

helm-bibtex

Library for creating and storing references and citations

(use-package helm-bibtex
  :ensure t
  :config
  (setq helm-bibtex-bibliography "~/Dropbox/org/reading/index.bib" ;; where your references are stored
      helm-bibtex-library-path "~/Dropbox/org/reading/lib/" ;; where your pdfs etc are stored
      helm-bibtex-notes-path "~/Dropbox/org/reading/index.org" ;; where your notes are stored
      bibtex-completion-bibliography "~/Dropbox/org/reading/index.bib" ;; writing completion
      bibtex-completion-notes-path "~/Dropbox/org/reading/index.org"))

Cosmetics

(setq org-ellipsis "")
(setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)
(setq org-src-window-setup 'current-window)

Keybindings

(global-set-key (kbd "C-x 2") 'split-window-below-and-switch)
(global-set-key (kbd "C-x 3") 'split-window-right-and-switch)
(global-set-key (kbd "C-x C-t") 'iterm-goto-filedir-or-home)
(global-set-key (kbd "C-x k") 'kill-current-buffer)
(global-set-key (kbd "C-x C-b") 'ibuffer)

Other defaults

Always indent with spaces

(setq-default indent-tabs-mode nil)

Follow symlinks

(setq vc-follow-symlinks t)

Set default tab width

(setq-default tab-width 2)

I like to keep the current line highlighted

(setq global-hl-line-mode +1)

Setup paths for emacs shell

(add-to-list 'exec-path "/usr/local/bin")
(use-package exec-path-from-shell
  :ensure t
  :config (when (memq window-system '(mac ns))
            (exec-path-from-shell-initialize)))

Testing new shell command

;; I want an easy command for opening new shells:
(defun new-shell (name)
  "Opens a new shell buffer with the given name in
asterisks (*name*) in the current directory and changes the
prompt to 'name>'."
  (interactive "sName: ")
  (pop-to-buffer (concat "*" name "*"))
  (unless (eq major-mode 'shell-mode)
    (shell (current-buffer))
    (sleep-for 0 200)
    (delete-region (point-min) (point-max))
    (comint-simple-send (get-buffer-process (current-buffer))
                        (concat "export PS1=\"\033[33m" name "\033[0m:\033[35m\\W\033[0m>\""))))
(global-set-key (kbd "C-c s") 'new-shell)

;; Remove case sensitivity for auto-completion
(setq pcomplete-ignore-case t)

;; Load ansi colors
(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)
(setq ansi-color-names-vector ["white" "orange red" "green" "yellow" "pale blue" "magenta" "cyan" "tan"])

Email

Add mu and mu4e to load path

(let ((default-directory "/usr/local/share/emacs/site-lisp/"))
  (normal-top-level-add-subdirs-to-load-path))

Enabel mu4e and link to email account

(use-package mu4e
  :bind ("<f9>" . mu4e)
  :config
  ;; Don't prompt for context on startup
  (setq mu4e-context-policy 'pick-first)
  ;; Don't ask to quit...
  (setq mu4e-confirm-quit nil)
  (setq mu4e-maildir-shortcuts
        '(("/gmail-personal/INBOX"             . ?i)
          ("/gmail-personal/[Gmail].Sent Mail" . ?s)
          ("/gmail-personal/[Gmail].Drafts" . ?d)
          ("/gmail-personal/[Gmail].Trash"     . ?t)))
  (setq mu4e-contexts
        `( ,(make-mu4e-context
             :name "Gmail"
             :match-func (lambda (msg)
                           (when msg
                             (mu4e-message-contact-field-matches msg
                                                                 :to "gustaf.brostedt@gmail.com")))
             :vars '(
                     (user-mail-address . "gustaf.brostedt@gmail.com")
                     (user-full-name . "Gustaf Brostedt")
                     (mu4e-trash-folder . "/gmail-personal/[Gmail].Trash")
                     (mu4e-drafts-folder . "/gmail-personal/[Gmail].Drafts")
                     (mu4e-sent-folder . "/gmail-personal/[Gmail].Sent Mail")
                     ))
           )))

Enable desktop alerts

;; (use-package mu4e-alert
;;   :ensure t
;;   :after mu4e
;;   :init
;;   (setq mu4e-alert-interesting-mail-query
;;         "flag:unread maildir:/Gmail/INBOX"
;;         )
;;   (mu4e-alert-enable-mode-line-display)
;;   (defun refresh-mu4e-alert-mode-line ()
;;     (interactive)
;;     (mu4e~proc-kill)
;;     (mu4e-alert-enable-mode-line-display)
;;     )
;;   (run-with-timer 0 60 'refresh-mu4e-alert-mode-line))
(use-package mu4e-alert
  :after mu4e
  :init
  (mu4e-alert-set-default-style 'notifications)
  :hook ((after-init . mu4e-alert-enable-mode-line-display)
         (after-init . mu4e-alert-enable-notifications)))

Since offline-imap can’t send emails by default so enable this groundbreaking feature

;; I have my "default" parameters from Gmail
(setq mu4e-sent-folder "/Users/gustafbrostedt/Maildir/gmail-personal/[Mu4e].Sent"
      ;; mu4e-sent-messages-behavior 'delete ;; Unsure how this should be configured
      mu4e-drafts-folder "/Users/gustafbrostedt/Maildir/gmail-personal/[Mu4e].Drafts"
      user-mail-address "gustaf.brostedt@gmail.com"
      smtpmail-default-smtp-server "smtp.gmail.com"
      smtpmail-smtp-server "smtp.gmail.com"
      smtpmail-smtp-service 587)

;; Now I set a list of
(defvar my-mu4e-account-alist
  '(("gmail-personal"
     (mu4e-sent-folder "/gmail-personal/[Mu4e].Sent")
     (user-mail-address "gustaf.brostedt@gmail.com")
     (smtpmail-smtp-user "gustaf.brostedt")
     (smtpmail-local-domain "gmail.com")
     (smtpmail-default-smtp-server "smtp.gmail.com")
     (smtpmail-smtp-server "smtp.gmail.com")
     (smtpmail-smtp-service 587)
     )
    ;; Include any other accounts here ...
    ))

(defun my-mu4e-set-account ()
  "Set the account for composing a message.
   This function is taken from:
     https://www.djcbsoftware.nl/code/mu/mu4e/Multiple-accounts.html"
  (let* ((account
          (if mu4e-compose-parent-message
              (let ((maildir (mu4e-message-field mu4e-compose-parent-message :maildir)))
                (string-match "/\\(.*?\\)/" maildir)
                (match-string 1 maildir))
            (completing-read (format "Compose with account: (%s) "
                                     (mapconcat #'(lambda (var) (car var))
                                                my-mu4e-account-alist "/"))
                             (mapcar #'(lambda (var) (car var)) my-mu4e-account-alist)
                             nil t nil nil (caar my-mu4e-account-alist))))
         (account-vars (cdr (assoc account my-mu4e-account-alist))))
    (if account-vars
        (mapc #'(lambda (var)
                  (set (car var) (cadr var)))
              account-vars)
      (error "No email account found 1"))))

(add-hook 'mu4e-compose-pre-hook 'my-mu4e-set-account)

Life Management

Any setup related to managing my agenda and life in general

Todo list and archive

(setq org-directory "~/Dropbox/org/agenda")

(defun org-file-path (filename)
  "Return the absolute address of an org file, given its relative name."
  (concat (file-name-as-directory org-directory) filename))

;;(setq org-inbox-file "~/Dropbox/inbox.org")
(setq org-index-file (org-file-path "index.org"))
(setq org-archive-location
      (concat (org-file-path "../archive.org") "::* From %s"))

(setq org-agenda-files (list org-index-file))

(defun open-index-file ()
  "Open the master org TODO list."
  (interactive)
  (find-file org-index-file)
  (flycheck-mode -1)
  (end-of-buffer))

(global-set-key (kbd "C-c i") 'open-index-file)

(defun mark-done-and-archive ()
  "Mark the state of an org-mode item as DONE and archive it."
  (interactive)
  (org-todo 'done)
  (org-archive-subtree))

(define-key org-mode-map (kbd "C-c C-x C-s") 'mark-done-and-archive)

(setq org-log-done 'time)

org-journal

;; Set default path
(setq org-journal-dir (concat "~/Dropbox/org/agenda/journal/" (format-time-string "%Y/%m/")))
;; Define naming convention
(setq org-journal-file-format "%Y-%m-%d.org")
;; Carry-over incomplete todos
(setq org-journal-carryover-items "TODO=\"TODO\"|TODO=\"STARTED\"")

(use-package org-journal
  :ensure t)

org-habit

(use-package org-habit
  :ensure nil)

Setting up the agenda

Most of the below is taken from My Life In Plain Text by Bernt Hanson.

org-agenda

Tell the agenda where to search for files

(setq org-agenda-files (quote( "~/Dropbox/org/agenda")))

Add some additional todo keywords and edit highlighting

(setq org-todo-keywords
      (quote ((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d)")
              (sequence "WAITING(w@/!)" "HOLD(h@/!)" "|" "CANCELLED(c@/!)" "PHONE" "MEETING"))))

(setq org-todo-keyword-faces
      (quote (("TODO" :foreground "red" :weight bold)
              ("NEXT" :foreground "blue" :weight bold)
              ("DONE" :foreground "forest green" :weight bold)
              ("WAITING" :foreground "orange" :weight bold)
              ("HOLD" :foreground "magenta" :weight bold)
              ("CANCELLED" :foreground "forest green" :weight bold)
              ("MEETING" :foreground "forest green" :weight bold)
              ("PHONE" :foreground "forest green" :weight bold))))

Allow to key toggling between todo states hotkey for changing state: C-c C-t KEY

(setq org-use-fast-todo-selection t)

Allow cycling through todo states with arrow keys, S-left & S-right

(setq org-treat-S-cursor-todo-selection-as-state-change nil)

The below triggers will update the tags on todos as they change state They follow the below structure

  • Moving a task to CANCELLED adds a CANCELLED tag
  • Moving a task to WAITING adds a WAITING tag
  • Moving a task to HOLD adds WAITING and HOLD tags
  • Moving a task to a done state removes WAITING and HOLD tags
  • Moving a task to TODO removes WAITING, CANCELLED, and HOLD tags
  • Moving a task to NEXT removes WAITING, CANCELLED, and HOLD tags
  • Moving a task to DONE removes WAITING, CANCELLED, and HOLD tags
(setq org-todo-state-tags-triggers
      (quote (("CANCELLED" ("CANCELLED" . t))
              ("WAITING" ("WAITING" . t))
              ("HOLD" ("WAITING") ("HOLD" . t))
              (done ("WAITING") ("HOLD"))
              ("TODO" ("WAITING") ("CANCELLED") ("HOLD"))
              ("NEXT" ("WAITING") ("CANCELLED") ("HOLD"))
              ("DONE" ("WAITING") ("CANCELLED") ("HOLD")))))

org-capture

Configure org-capture and load templates

(use-package org-capture
  :commands org-capture
  :bind ("C-c c" . org-capture)
  :ensure nil
  :config
  (setq org-directory "~/Dropbox/org/agenda")
  (setq org-default-notes-file "~/Dropbox/org/agenda/refile.org")
  (setq org-capture-templates
      (quote (("t" "todo" entry (file "~/Dropbox/org/agenda/refile.org")
               "* TODO %?\n%U\n%a\n")
              ("r" "respond" entry (file "~/Dropbox/org/agenda/refile.org")
               "* NEXT Respond to %:from on %:subject\nSCHEDULED: %t\n%U\n%a\n")
              ("n" "note" entry (file "~/Dropbox/org/agenda/refile.org")
               "* %? :NOTE:\n%U\n%a\n")
              ("w" "org-protocol" entry (file "~/Dropbox/org/agenda/refile.org")
               "* TODO Review %c\n%U\n")
              ("m" "Meeting" entry (file "~/Dropbox/org/agenda/refile.org")
               "* MEETING with %? :MEETING:\n%U")
              ("p" "Phone call" entry (file "~/Dropbox/org/agenda/refile.org")
               "* PHONE %? :PHONE:\n%U")
              ("h" "Habit" entry (file "~/Dropbox/org/agenda/refile.org")
               "* NEXT %?\n%U\n%a\nSCHEDULED: %(format-time-string \"%<<%Y-%m-%d %a .+1d/3d>>\")\n:PROPERTIES:\n:STYLE: habit\n:REPEAT_TO_STATE: NEXT\n:END:\n")))))

org-refile

Tell emacs where to look for refiling targets and some customizations to get ido to work its wonders

; Targets include this file and any file contributing to the agenda - up to 9 levels deep
(setq org-refile-targets (quote ((nil :maxlevel . 9)
                                 (org-agenda-files :maxlevel . 9))))

; Use full outline paths for refile targets - we file directly with IDO
(setq org-refile-use-outline-path t)

; Targets complete directly with IDO
(setq org-outline-path-complete-in-steps nil)

; Allow refile to create parent tasks with confirmation
(setq org-refile-allow-creating-parent-nodes (quote confirm))

; Use IDO for both buffer and file completion and ido-everywhere to t
(setq org-completion-use-ido t)
(setq ido-everywhere t)
(setq ido-max-directory-size 100000)
(ido-mode (quote both))
; Use the current window when visiting files and buffers with ido
(setq ido-default-file-method 'selected-window)
(setq ido-default-buffer-method 'selected-window)
; Use the current window for indirect buffer display
(setq org-indirect-buffer-display 'current-window)

;;;; Refile settings
; Exclude DONE state tasks from refile targets
(defun verify-refile-target ()
  "Exclude todo keywords with a done state from refile targets"
  (not (member (nth 2 (org-heading-components)) org-done-keywords)))

(setq org-refile-target-verify-function 'verify-refile-target)

Creating custom agenda views

Custom functions to make this work

(defun bh/find-project-task ()
  "Move point to the parent (project) task if any"
  (save-restriction
    (widen)
    (let ((parent-task (save-excursion (org-back-to-heading 'invisible-ok) (point))))
      (while (org-up-heading-safe)
        (when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
          (setq parent-task (point))))
      (goto-char parent-task)
      parent-task)))

(defun bh/is-project-p ()
  "Any task with a todo keyword subtask"
  (save-restriction
    (widen)
    (let ((has-subtask)
          (subtree-end (save-excursion (org-end-of-subtree t)))
          (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
      (save-excursion
        (forward-line 1)
        (while (and (not has-subtask)
                    (< (point) subtree-end)
                    (re-search-forward "^\*+ " subtree-end t))
          (when (member (org-get-todo-state) org-todo-keywords-1)
            (setq has-subtask t))))
      (and is-a-task has-subtask))))

(defun bh/is-project-subtree-p ()
  "Any task with a todo keyword that is in a project subtree.
Callers of this function already widen the buffer view."
  (let ((task (save-excursion (org-back-to-heading 'invisible-ok)
                              (point))))
    (save-excursion
      (bh/find-project-task)
      (if (equal (point) task)
          nil
        t))))

(defun bh/is-task-p ()
  "Any task with a todo keyword and no subtask"
  (save-restriction
    (widen)
    (let ((has-subtask)
          (subtree-end (save-excursion (org-end-of-subtree t)))
          (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
      (save-excursion
        (forward-line 1)
        (while (and (not has-subtask)
                    (< (point) subtree-end)
                    (re-search-forward "^\*+ " subtree-end t))
          (when (member (org-get-todo-state) org-todo-keywords-1)
            (setq has-subtask t))))
      (and is-a-task (not has-subtask)))))

(defun bh/is-subproject-p ()
  "Any task which is a subtask of another project"
  (let ((is-subproject)
        (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
    (save-excursion
      (while (and (not is-subproject) (org-up-heading-safe))
        (when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
          (setq is-subproject t))))
    (and is-a-task is-subproject)))

(defun bh/list-sublevels-for-projects-indented ()
  "Set org-tags-match-list-sublevels so when restricted to a subtree we list all subtasks.
  This is normally used by skipping functions where this variable is already local to the agenda."
  (if (marker-buffer org-agenda-restrict-begin)
      (setq org-tags-match-list-sublevels 'indented)
    (setq org-tags-match-list-sublevels nil))
  nil)

(defun bh/list-sublevels-for-projects ()
  "Set org-tags-match-list-sublevels so when restricted to a subtree we list all subtasks.
  This is normally used by skipping functions where this variable is already local to the agenda."
  (if (marker-buffer org-agenda-restrict-begin)
      (setq org-tags-match-list-sublevels t)
    (setq org-tags-match-list-sublevels nil))
  nil)

(defvar bh/hide-scheduled-and-waiting-next-tasks t)

(defun bh/toggle-next-task-display ()
  (interactive)
  (setq bh/hide-scheduled-and-waiting-next-tasks (not bh/hide-scheduled-and-waiting-next-tasks))
  (when  (equal major-mode 'org-agenda-mode)
    (org-agenda-redo))
  (message "%s WAITING and SCHEDULED NEXT Tasks" (if bh/hide-scheduled-and-waiting-next-tasks "Hide" "Show")))

(defun bh/skip-stuck-projects ()
  "Skip trees that are not stuck projects"
  (save-restriction
    (widen)
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (if (bh/is-project-p)
          (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
                 (has-next ))
            (save-excursion
              (forward-line 1)
              (while (and (not has-next) (< (point) subtree-end) (re-search-forward "^\\*+ NEXT " subtree-end t))
                (unless (member "WAITING" (org-get-tags-at))
                  (setq has-next t))))
            (if has-next
                nil
              next-headline)) ; a stuck project, has subtasks but no next task
        nil))))

(defun bh/skip-non-stuck-projects ()
  "Skip trees that are not stuck projects"
  ;; (bh/list-sublevels-for-projects-indented)
  (save-restriction
    (widen)
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (if (bh/is-project-p)
          (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
                 (has-next ))
            (save-excursion
              (forward-line 1)
              (while (and (not has-next) (< (point) subtree-end) (re-search-forward "^\\*+ NEXT " subtree-end t))
                (unless (member "WAITING" (org-get-tags-at))
                  (setq has-next t))))
            (if has-next
                next-headline
              nil)) ; a stuck project, has subtasks but no next task
        next-headline))))

(defun bh/skip-non-projects ()
  "Skip trees that are not projects"
  ;; (bh/list-sublevels-for-projects-indented)
  (if (save-excursion (bh/skip-non-stuck-projects))
      (save-restriction
        (widen)
        (let ((subtree-end (save-excursion (org-end-of-subtree t))))
          (cond
           ((bh/is-project-p)
            nil)
           ((and (bh/is-project-subtree-p) (not (bh/is-task-p)))
            nil)
           (t
            subtree-end))))
    (save-excursion (org-end-of-subtree t))))

(defun bh/skip-non-tasks ()
  "Show non-project tasks.
Skip project and sub-project tasks, habits, and project related tasks."
  (save-restriction
    (widen)
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (cond
       ((bh/is-task-p)
        nil)
       (t
        next-headline)))))

(defun bh/skip-project-trees-and-habits ()
  "Skip trees that are projects"
  (save-restriction
    (widen)
    (let ((subtree-end (save-excursion (org-end-of-subtree t))))
      (cond
       ((bh/is-project-p)
        subtree-end)
       ((org-is-habit-p)
        subtree-end)
       (t
        nil)))))

(defun bh/skip-projects-and-habits-and-single-tasks ()
  "Skip trees that are projects, tasks that are habits, single non-project tasks"
  (save-restriction
    (widen)
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (cond
       ((org-is-habit-p)
        next-headline)
       ((and bh/hide-scheduled-and-waiting-next-tasks
             (member "WAITING" (org-get-tags-at)))
        next-headline)
       ((bh/is-project-p)
        next-headline)
       ((and (bh/is-task-p) (not (bh/is-project-subtree-p)))
        next-headline)
       (t
        nil)))))

(defun bh/skip-project-tasks-maybe ()
  "Show tasks related to the current restriction.
When restricted to a project, skip project and sub project tasks, habits, NEXT tasks, and loose tasks.
When not restricted, skip project and sub-project tasks, habits, and project related tasks."
  (save-restriction
    (widen)
    (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
           (next-headline (save-excursion (or (outline-next-heading) (point-max))))
           (limit-to-project (marker-buffer org-agenda-restrict-begin)))
      (cond
       ((bh/is-project-p)
        next-headline)
       ((org-is-habit-p)
        subtree-end)
       ((and (not limit-to-project)
             (bh/is-project-subtree-p))
        subtree-end)
       ((and limit-to-project
             (bh/is-project-subtree-p)
             (member (org-get-todo-state) (list "NEXT")))
        subtree-end)
       (t
        nil)))))

(defun bh/skip-project-tasks ()
  "Show non-project tasks.
Skip project and sub-project tasks, habits, and project related tasks."
  (save-restriction
    (widen)
    (let* ((subtree-end (save-excursion (org-end-of-subtree t))))
      (cond
       ((bh/is-project-p)
        subtree-end)
       ((org-is-habit-p)
        subtree-end)
       ((bh/is-project-subtree-p)
        subtree-end)
       (t
        nil)))))

(defun bh/skip-non-project-tasks ()
  "Show project tasks.
Skip project and sub-project tasks, habits, and loose non-project tasks."
  (save-restriction
    (widen)
    (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
           (next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (cond
       ((bh/is-project-p)
        next-headline)
       ((org-is-habit-p)
        subtree-end)
       ((and (bh/is-project-subtree-p)
             (member (org-get-todo-state) (list "NEXT")))
        subtree-end)
       ((not (bh/is-project-subtree-p))
        subtree-end)
       (t
        nil)))))

(defun bh/skip-projects-and-habits ()
  "Skip trees that are projects and tasks that are habits"
  (save-restriction
    (widen)
    (let ((subtree-end (save-excursion (org-end-of-subtree t))))
      (cond
       ((bh/is-project-p)
        subtree-end)
       ((org-is-habit-p)
        subtree-end)
       (t
        nil)))))

(defun bh/skip-non-subprojects ()
  "Skip trees that are not projects"
  (let ((next-headline (save-excursion (outline-next-heading))))
    (if (bh/is-subproject-p)
        nil
      next-headline)))

The view itself

;; Do not dim blocked tasks
(setq org-agenda-dim-blocked-tasks nil)

;; Compact the block agenda view
(setq org-agenda-compact-blocks t)

;; Custom agenda command definitions
(setq org-agenda-custom-commands
      (quote (("N" "Notes" tags "NOTE"
               ((org-agenda-overriding-header "Notes")
                (org-tags-match-list-sublevels t)))
              ("h" "Habits" tags-todo "STYLE=\"habit\""
               ((org-agenda-overriding-header "Habits")
                (org-agenda-sorting-strategy
                 '(todo-state-down effort-up category-keep))))
              (" " "Agenda"
               ((agenda "" nil)
                (tags "REFILE"
                      ((org-agenda-overriding-header "Tasks to Refile")
                       (org-tags-match-list-sublevels nil)))
                (tags-todo "-CANCELLED/!"
                           ((org-agenda-overriding-header "Stuck Projects")
                            (org-agenda-skip-function 'bh/skip-non-stuck-projects)
                            (org-agenda-sorting-strategy
                             '(category-keep))))
                (tags-todo "-HOLD-CANCELLED/!"
                           ((org-agenda-overriding-header "Projects")
                            (org-agenda-skip-function 'bh/skip-non-projects)
                            (org-tags-match-list-sublevels 'indented)
                            (org-agenda-sorting-strategy
                             '(category-keep))))
                (tags-todo "-CANCELLED/!NEXT"
                           ((org-agenda-overriding-header (concat "Project Next Tasks"
                                                                  (if bh/hide-scheduled-and-waiting-next-tasks
                                                                      ""
                                                                    " (including WAITING and SCHEDULED tasks)")))
                            (org-agenda-skip-function 'bh/skip-projects-and-habits-and-single-tasks)
                            (org-tags-match-list-sublevels t)
                            (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-sorting-strategy
                             '(todo-state-down effort-up category-keep))))
                (tags-todo "-REFILE-CANCELLED-WAITING-HOLD/!"
                           ((org-agenda-overriding-header (concat "Project Subtasks"
                                                                  (if bh/hide-scheduled-and-waiting-next-tasks
                                                                      ""
                                                                    " (including WAITING and SCHEDULED tasks)")))
                            (org-agenda-skip-function 'bh/skip-non-project-tasks)
                            (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-sorting-strategy
                             '(category-keep))))
                (tags-todo "-REFILE-CANCELLED-WAITING-HOLD/!"
                           ((org-agenda-overriding-header (concat "Standalone Tasks"
                                                                  (if bh/hide-scheduled-and-waiting-next-tasks
                                                                      ""
                                                                    " (including WAITING and SCHEDULED tasks)")))
                            (org-agenda-skip-function 'bh/skip-project-tasks)
                            (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-sorting-strategy
                             '(category-keep))))
                (tags-todo "-CANCELLED+WAITING|HOLD/!"
                           ((org-agenda-overriding-header (concat "Waiting and Postponed Tasks"
                                                                  (if bh/hide-scheduled-and-waiting-next-tasks
                                                                      ""
                                                                    " (including WAITING and SCHEDULED tasks)")))
                            (org-agenda-skip-function 'bh/skip-non-tasks)
                            (org-tags-match-list-sublevels nil)
                            (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)))
                (tags "-REFILE/"
                      ((org-agenda-overriding-header "Tasks to Archive")
                       (org-agenda-skip-function 'bh/skip-non-archivable-tasks)
                       (org-tags-match-list-sublevels nil))))
               nil))))

Some key-bindings

(global-set-key (kbd "<f12>") 'org-agenda)

rtags

;; ensure that we use only rtags checking
;; https://github.com/Andersbakken/rtags#optional-1
(defun setup-flycheck-rtags ()
  (interactive)
  (flycheck-select-checker 'rtags)
  ;; RTags creates more accurate overlays.
  (setq-local flycheck-highlighting-mode nil)
  (setq-local flycheck-check-syntax-automatically nil))

(use-package rtags
  :commands (rtags-start-process-unless-running setup-flycheck-rtags)
  :config (progn
            (message "Rtags loaded")
            (use-package company-rtags)
            (use-package helm-rtags))
  ;; only run this if rtags is installed
  (when (require 'rtags nil :noerror)
    ;; make sure you have company-mode installed
    (require 'company)
    (define-key c-mode-base-map (kbd "M-.")
      (function rtags-find-symbol-at-point))
    (define-key c-mode-base-map (kbd "M-,")
      (function rtags-location-stack-back))
    ;; install standard rtags keybindings. Do M-. on the symbol below to
    ;; jump to definition and see the keybindings.
    (rtags-enable-standard-keybindings)
    ;; company completion setup
    (setq rtags-autostart-diagnostics t)
    (rtags-diagnostics)
    (setq rtags-completions-enabled t)
    (push 'company-rtags company-backends)
    (global-company-mode)
    (define-key c-mode-base-map (kbd "<C-tab>") (function company-complete))
    ;; use rtags flycheck mode -- clang warnings shown inline
    (require 'flycheck-rtags)
    ;; c-mode-common-hook is also called by c++-mode
    (add-hook 'c-mode-common-hook #'setup-flycheck-rtags)))