emacs-config/conf.org

1019 lines
35 KiB
Org Mode
Raw Normal View History

2018-03-21 21:59:12 -04:00
work in progress
2018-03-21 21:44:31 -04:00
* ui
** remove garbage
*** startup screen
#+BEGIN_SRC emacs-lisp
(setq inhibit-startup-screen t)
#+END_SRC
*** useless mouse widgets
#+BEGIN_SRC emacs-lisp
(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)
#+END_SRC
*** line wrap
#+BEGIN_SRC emacs-lisp
(set-default 'truncate-lines t)
#+END_SRC
*** autosave/backup files
#+BEGIN_SRC emacs-lisp
(setq make-backup-files nil)
(setq auto-save-default nil)
#+END_SRC
*** popup windows
#+BEGIN_SRC emacs-lisp
(setq pop-up-windows nil) ; no popups (eg ediff)
#+END_SRC
** pretty stuff
*** enable line/column numbering
#+BEGIN_SRC emacs-lisp
;; (global-linum-mode t)
(line-number-mode 1)
(column-number-mode 1)
#+END_SRC
*** tab width
#+BEGIN_SRC emacs-lisp
(setq-default tab-width 4)
#+END_SRC
*** smooth scrolling
#+BEGIN_SRC emacs-lisp
(setq scroll-conservatively 100)
#+END_SRC
*** pretty symbols
#+BEGIN_SRC emacs-lisp
(when window-system (global-prettify-symbols-mode t))
#+END_SRC
*** highlight current line
#+BEGIN_SRC emacs-lisp
(when window-system (global-hl-line-mode t))
#+END_SRC
** yes-no prompt enhancement
#+BEGIN_SRC emacs-lisp
(defalias 'yes-or-no-p 'y-or-n-p) ; eliminate yes or no prompt on killing procs
#+END_SRC
** theme color selection
need this to:
a) apply the gui theme if gui is loaded as client and
b) ensure that the reloaded theme is only applied to the current frame
NOTE: this only works if we start term after gui, and term has light bg. not big deal for now since I hardly ever use term as client
#+BEGIN_SRC emacs-lisp
(defvar my:theme 'spacemacs-dark)
(defvar my:theme-window-loaded nil)
(defvar my:theme-terminal-loaded nil)
(if (daemonp)
(add-hook 'after-make-frame-functions(lambda (frame)
(select-frame frame)
(if (window-system frame)
(unless my:theme-window-loaded
(if my:theme-terminal-loaded
(enable-theme my:theme)
(load-theme my:theme t))
(setq my:theme-window-loaded t))
(unless my:theme-terminal-loaded
(if my:theme-window-loaded
(enable-theme my:theme)
(load-theme my:theme t))
(setq my:theme-terminal-loaded t)))))
(progn
(load-theme my:theme t)
(if (display-graphic-p)
(setq my:theme-window-loaded t)
(setq my:theme-terminal-loaded t))))
#+END_SRC
* modeline
#+BEGIN_SRC emacs-lisp
(use-package spaceline
:ensure t
:config
(require 'spaceline-config)
(setq powerline-default-separator (quote arrow))
(spaceline-spacemacs-theme)
(setq spaceline-buffer-size-p nil))
#+END_SRC
** dashboard
#+BEGIN_SRC emacs-lisp
(use-package dashboard
:ensure t
:config
(dashboard-setup-startup-hook)
(setq dashboard-items '((recents . 10))))
#+END_SRC
* keybindings
** apropros
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "C-h a") 'apropos)
#+END_SRC
* printing
**
* packages
** delight
#+BEGIN_SRC emacs-lisp
(use-package delight
:ensure t)
#+END_SRC
** beacon
#+BEGIN_SRC emacs-lisp
(use-package beacon
:ensure t
:delight
:init
(beacon-mode 1))
#+END_SRC
** whichkey
#+BEGIN_SRC emacs-lisp
(use-package which-key
:ensure t
:delight
:init
(which-key-mode))
#+END_SRC
** ido
#+BEGIN_SRC emacs-lisp
(use-package ido
:ensure t
:bind
("C-x C-b" . 'ido-switch-buffer)
("C-x b" . 'ibuffer)
:config
(ido-mode 1)
(setq ido-everywhere t)
(setq ido-enable-flex-matching t)
(setq ido-max-directory-size 100000)
(setq ido-default-file-method 'selected-window)
(setq ido-default-buffer-method 'selected-window)
(use-package ido-vertical-mode
:ensure t
:init
(ido-vertical-mode 1)
(setq ido-vertical-define-keys 'C-n-and-C-p-only)))
;; (setq ido-file-extensions-order '(".org" ".txt" ".py" ".emacs" ".xml" ".el" ".ini" ".cfg" ".cnf"))
#+END_SRC
** smex
#+BEGIN_SRC emacs-lisp
(use-package smex
:ensure t
:init
(smex-initialize)
:bind
("M-x" . 'smex)
("M-X" . 'smex-major-mode-commands))
#+END_SRC
** rainbow-delimiters
#+BEGIN_SRC emacs-lisp
(use-package rainbow-delimiters
:ensure t
:delight
:init
(add-hook 'prog-mode-hook #'rainbow-delimiters-mode))
#+END_SRC
** ace-window
#+BEGIN_SRC emacs-lisp
(use-package ace-window
:ensure t
:bind ("M-o" . ace-window)
:config (setq aw-background nil))
#+END_SRC
** avy
#+BEGIN_SRC emacs-lisp
(use-package avy
:ensure t
:bind ("M-s" . avy-goto-char)
:config (setq avy-background t))
#+END_SRC
** sudo edit
#+BEGIN_SRC emacs-lisp
(use-package sudo-edit
:ensure t
:bind ("C-c s" . sudo-edit))
#+END_SRC
** typit
#+BEGIN_SRC emacs-lisp
(use-package typit
:init
:ensure t)
#+END_SRC
** calfw
#+BEGIN_SRC emacs-lisp
(use-package calfw
:init
:ensure t)
#+END_SRC
** evil
*** packages
#+BEGIN_SRC emacs-lisp
(use-package evil
:ensure t
:config
(evil-mode 1)
(use-package evil-org
:ensure t
:after org
:delight
:config
(add-hook 'org-mode-hook 'evil-org-mode)
(add-hook 'evil-org-mode-hook
(lambda ()
(evil-org-set-key-theme)))
(require 'evil-org-agenda)
(evil-org-agenda-set-keys)))
#+END_SRC
*** keybindings
vim is all about escape, not...ctrl+g???
+BEGIN_SRC emacs-lisp
(define-key evil-normal-state-map [escape] 'keyboard-quit)
(define-key evil-visual-state-map [escape] 'keyboard-quit)
;; since ctrl+g and evil make no sense
(defun nd/minibuffer-keyboard-quit ()
"Abort recursive edit.
In Delete Selection mode, if the mark is active, just deactivate it;
then it takes a second \\[keyboard-quit] to abort the minibuffer."
(interactive)
(if (and delete-selection-mode transient-mark-mode mark-active)
(setq deactivate-mark t)
(when (get-buffer "*Completions*") (delete-windows-on "*Completions*"))
(abort-recursive-edit)))
(define-key minibuffer-local-ns-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-completion-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-must-match-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-isearch-map [escape] 'minibuffer-keyboard-quit)
#+END_SRC
** undo tree
#+BEGIN_SRC emacs-lisp
(use-package undo-tree
:ensure t
:delight
:config
(global-undo-tree-mode)
(setq undo-tree-visualizer-diff t))
#+END_SRC
* custom functions
** follow window splitting
#+BEGIN_SRC emacs-lisp
(defun split-and-follow-horizontally ()
(interactive)
(split-window-below)
(balance-windows)
(other-window 1))
(global-set-key (kbd "C-x 2") 'split-and-follow-horizontally)
(defun split-and-follow-vertically ()
(interactive)
(split-window-right)
(balance-windows)
(other-window 1))
(global-set-key (kbd "C-x 3") 'split-and-follow-vertically)
#+END_SRC
** config edit and reload
*** edit
#+BEGIN_SRC emacs-lisp
(defun config-visit ()
(interactive)
(find-file "~/.emacs.d/conf.org"))
(global-set-key (kbd "C-c e") 'config-visit)
#+END_SRC
*** reload
#+BEGIN_SRC emacs-lisp
(defun config-reload ()
"Reloads ~/.emacs.d/conf.org at runtime"
(interactive)
(org-babel-load-file (expand-file-name "~/.emacs.d/conf.org")))
(global-set-key (kbd "C-c r") 'config-reload)
#+END_SRC
** custom keybindings
*** delete whole line
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "C-S-w") 'fc/delete-whole-line)
(defun fc/delete-whole-line ()
"Delete the whole line without flooding the kill ring"
(interactive)
(delete-region (progn (forward-line 0) (point))
(progn (forward-line 1) (point))))
#+END_SRC
*** delete word forward
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "M-d") 'fc/delete-word-forward)
(defun fc/delete-word-forward (arg)
"Delete word forward without flooding the kill ring"
(interactive "p")
(delete-region (point) (progn (forward-word arg) (point))))
#+END_SRC
*** delete word backward
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "<M-backspace>") 'fc/delete-word-backward)
(defun fc/delete-word-backward (arg)
"Delete word backward without flooding the kill ring"
(interactive "p")
(delete-region (point) (progn (backward-word arg) (point))))
#+END_SRC
*** duplicate line
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "C-c C-d") 'fc/duplicate-current-line-or-region)
(defun fc/duplicate-current-line-or-region (arg)
"Duplicates the current line or region ARG times."
(interactive "p")
(let (beg end (origin (point)))
(if (and mark-active (> (point) (mark)))
(exchange-point-and-mark))
(setq beg (line-beginning-position))
(if mark-active
(exchange-point-and-mark))
(setq end (line-end-position))
(let ((region (buffer-substring-no-properties beg end)))
(dotimes (i arg)
(goto-char end)
(newline)
(insert region)
(setq end (point))))))
#+END_SRC
(goto-char (+ origin (* (length region) arg) arg)))))
* ess
#+begin_src emacs-lisp
(setq inferior-R-args "--quiet --no-save")
(load "ess-site")
(setq ess-history-file "session.Rhistory")
(setq ess-history-directory
(substitute-in-file-name "${XDG_CONFIG_HOME}/r/"))
#+END_SRC
* languages
** python
#+BEGIN_SRC
(elpy-enable)
;; make python tabs 4 chars
(add-hook 'python-mode-hook
(lambda ()
(setq indent-tabs-mode t)
(setq tab-width 4)
(setq python-indent 4)))
#+END_SRC
* org-mode
** basic
#+BEGIN_SRC emacs-lisp
(setq org-log-done t)
(setq org-src-window-setup 'current-window)
(setq org-startup-indented t)
(delight 'org-indent-mode)
(setq org-directory "~/Org")
#+END_SRC
** evil modes
#+BEGIN_SRC emacs-lisp
;;(add-hook 'org-capture-mode-hook 'evil-append)
#+END_SRC
** source snippets
*** emacs-lisp
#+BEGIN_SRC emacs-lisp
(add-to-list 'org-structure-template-alist
'("el" "#+BEGIN_SRC emacs-lisp\n?\n#+END_SRC"))
#+END_SRC
** keyboard shortcuts
*** global
#+BEGIN_SRC emacs-lisp
(global-set-key "\C-cl" 'org-store-link)
(global-set-key "\C-ca" 'org-agenda)
(global-set-key "\C-cb" 'org-iswitchb)
(global-set-key (kbd "C-c c") 'org-capture)
;; consider adding f1-12 shortcuts for org things that must be a) fast and b) work in any mode
#+END_SRC
*** navigation
#+BEGIN_SRC emacs-lisp
(setq org-special-ctrl-a/e t)
(setq org-special-ctrl-k t)
(setq org-yank-adjusted-subtrees t)
#+END_SRC
** todo states
*** sequences
#+BEGIN_SRC emacs-lisp
(setq org-todo-keywords
(quote ((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d)")
(sequence "WAITING(w@/!)" "HOLD(h@/!)" "|" "CANCELLED(c@/!)"))))
#+END_SRC
*** colors
#+BEGIN_SRC emacs-lisp
(setq org-todo-keyword-faces
(quote (("TODO" :foreground "light coral" :weight bold)
("NEXT" :foreground "khaki" :weight bold)
("DONE" :foreground "light green" :weight bold)
("WAITING" :foreground "orange" :weight bold)
("HOLD" :foreground "violet" :weight bold)
("CANCELLED" :foreground "deep sky blue" :weight bold))))
#+END_SRC
*** triggers
#+BEGIN_SRC emacs-lisp
(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")))))
#+END_SRC
*** subtask autocomplete
#+BEGIN_SRC emacs-lisp
(defun org-summary-todo (n-done n-not-done)
"Switch entry to DONE when all subentries are done, to TODO otherwise."
(let (org-log-done org-log-states) ; turn off logging
(org-todo (if (= n-not-done 0) "DONE" "TODO"))))
(add-hook 'org-after-todo-statistics-hook 'org-summary-todo)
#+END_SRC
** tag selection keys
#+BEGIN_SRC emacs-lisp
(setq org-tag-alist (quote ((:startgroup)
("@errand" . ?e)
("@work" . ?o)
("@home" . ?h)
("@travel" . ?f)
(:endgroup)
("LAPTOP" . ?L)
("WAITING" . ?W)
("HOLD" . ?H)
("PERSONAL" . ?P)
("WORK" . ?O)
("NOTE" . ?N)
("CANCELLED" . ?C)
("FLAGGED" . ??))))
#+END_SRC
** capture templates
TODO, use %a to link to calling buffer
TODO: add fast way to immediately schedule an event or appointment
TODO: add meeting template as scheduled+action item thing
#+BEGIN_SRC emacs-lisp
(setq org-capture-templates
(quote (("t" "todo" entry (file "~/Org/capture.org") "* TODO %?\n%U\n")
("n" "note" entry (file "~/Org/capture.org") "* %? :NOTE:\n%U\n" )
("a" "appointment" entry (file "~/Org/capture.org") "* TODO %?\n%U\n%^t\n" )
("m" "multi-day" entry (file "~/Org/capture.org") "* TODO %?\n%U\n%^t--%^t\n" )
("d" "deadline" entry (file "~/Org/capture.org") "* TODO %?\nDEADLINE: %^t\n%U\n" )
("j" "journal" entry (file+datetree "~/Org/diary.org") "* %?\n%U\n")
("p" "org-protocol" entry (file+headline ,(concat org-directory "~/Org/capture.org") "Inbox")
"* %^{Title}\nSource: %u, %c\n #+BEGIN_QUOTE\n%i\n#+END_QUOTE\n\n\n%?")
("L" "org-protocol" entry (file+headline ,(concat org-directory "~/Org/capture.org") "Inbox")
"* %? [[%:link][%:description]] \nCaptured On: %U")
("h" "habit" entry (file "~/Org/capture.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"))))
#+END_SRC
** refile
*** targets
#+BEGIN_SRC emacs-lisp
(setq org-refile-targets (quote ((nil :maxlevel . 9)
("~/Org/reference/idea.org" :maxlevel . 9)
(org-agenda-files :maxlevel . 9))))
#+END_SRC
*** completion
#+BEGIN_SRC emacs-lisp
(setq org-refile-use-outline-path t)
(setq org-outline-path-complete-in-steps nil)
(setq org-completion-use-ido t)
#+END_SRC
*** node creation
#+BEGIN_SRC emacs-lisp
(setq org-refile-allow-creating-parent-nodes (quote confirm))
#+END_SRC
*** use current window
#+BEGIN_SRC emacs-lisp
(setq org-indirect-buffer-display 'current-window)
#+END_SRC
*** exclude done states
#+BEGIN_SRC emacs-lisp
(defun nd/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 'nd/verify-refile-target)
#+END_SRC
** agenda
*** basic config
#+BEGIN_SRC emacs-lisp
(setq org-agenda-files (quote ("~/Org"
"~/Org/large_projects"
"~/Org/reference")))
(setq org-agenda-dim-blocked-tasks nil)
(setq org-agenda-compact-blocks t)
#+END_SRC
*** views
**** show only today
#+BEGIN_SRC emacs-lisp
(setq org-agenda-span 'day)
#+End_src
**** display time grid
#+BEGIN_SRC emacs-lisp
(setq org-agenda-time-grid (quote ((daily today remove-match)
#("----------------" 0 16 (org-heading t))
(0900 1100 1300 1500 1700))))
#+END_SRC
**** right align tags
#+BEGIN_SRC emacs-lisp
(add-hook 'org-finalize-agenda-hook 'place-agenda-tags)
(defun place-agenda-tags ()
"Put the agenda tags by the right border of the agenda window."
(setq org-agenda-tags-column (- 4 (window-width)))
(org-agenda-align-tags))
#+END_SRC
*** custom commands
#+BEGIN_SRC emacs-lisp
(setq org-agenda-tags-todo-honor-ignore-options t)
(setq org-agenda-custom-commands
(quote ((" " "Agenda"
((agenda "" nil)
(tags "REFILE"
((org-agenda-overriding-header "Tasks to Refile")
(org-tags-match-list-sublevels nil)))
(tags-todo "-NA-REFILE/!"
((org-agenda-overriding-header (concat "Project Next Tasks"))
(org-agenda-skip-function 'nd/skip-non-next-project-tasks)
(org-agenda-todo-ignore-with-date 'all)
(org-agenda-sorting-strategy
'(category-keep))))
(tags-todo "-NA-REFILE/!"
((org-agenda-overriding-header (concat "Project Waiting Tasks"))
(org-agenda-skip-function 'nd/skip-non-waiting-project-tasks)
(org-agenda-todo-ignore-with-date 'all)
(org-agenda-sorting-strategy
'(category-keep))))
(tags-todo "-NA-REFILE/!"
((org-agenda-overriding-header (concat "Project Held Tasks"))
(org-agenda-skip-function 'nd/skip-non-held-project-tasks)
(org-agenda-todo-ignore-with-date 'all)
(org-agenda-sorting-strategy
'(category-keep))))
(tags-todo "-NA-REFILE/!"
((org-agenda-overriding-header (concat "Atomic Tasks"))
(org-agenda-skip-function 'nd/skip-non-atomic-tasks)
(org-agenda-todo-ignore-with-date 'all)
(org-agenda-sorting-strategy
'(category-keep))))
2018-03-31 01:43:17 -04:00
(tags-todo "-NA-REFILE/!"
2018-03-21 21:44:31 -04:00
((org-agenda-overriding-header "Stuck Projects")
(org-agenda-skip-function 'nd/skip-non-stuck-projects)
(org-agenda-sorting-strategy
'(category-keep))))
(tags-todo "-NA-REFILE/!"
((org-agenda-overriding-header "Held Projects")
(org-agenda-skip-function 'nd/skip-non-held-projects)
(org-agenda-sorting-strategy
'(category-keep))))
(tags-todo "-NA-REFILE/!"
((org-agenda-overriding-header "Waiting Projects")
(org-agenda-skip-function 'nd/skip-non-waiting-projects)
(org-agenda-sorting-strategy
'(category-keep))))
(tags-todo "-NA-REFILE/!"
((org-agenda-overriding-header "Active Projects")
(org-agenda-skip-function 'nd/skip-non-active-projects)
2018-03-21 21:44:31 -04:00
(org-agenda-sorting-strategy
2018-03-31 01:43:17 -04:00
'(category-keep)))))
;; (tags-todo "-NA-REFILE/!"
;; ((org-agenda-overriding-header "Projects")
;; (org-agenda-skip-function 'nd/skip-non-projects)
;; (org-tags-match-list-sublevels 'indented)
;; (org-agenda-sorting-strategy
;; '(category-keep))))
;; (tags "-NA-REFILE/"
;; ((org-agenda-overriding-header "Tasks to Archive")
;; (org-agenda-skip-function 'nd/skip-non-archivable-tasks)
;; (org-tags-match-list-sublevels nil))))
2018-03-21 21:44:31 -04:00
nil))))
#+END_SRC
*** auto exclusion
#+BEGIN_SRC emacs-lisp
(defun nd/org-auto-exclude-function (tag)
"Automatic task exclusion in the agenda with / RET"
(and (cond
((string= tag "hold")
t))
(concat "-" tag)))
(setq org-agenda-auto-exclude-function 'nd/org-auto-exclude-function)
#+END_SRC
*** filtering functions
2018-03-22 23:32:11 -04:00
some definitions:
2018-03-24 00:50:01 -04:00
- todoitem: heading with todo state
2018-03-22 23:32:11 -04:00
- task: todo heading with no todo headings beneath it
- project: todo heading with tasks or other project in subtree
- subtask: task that is part of a project
- subproject: project that is part of another project
- atomic task: task that is not part of a project
- project order: quantifies the degree of project nesting.
- First order projects have only subtasks
- Second order projects have subtasks or first order subprojects
- etc
2018-03-21 21:44:31 -04:00
#+BEGIN_SRC emacs-lisp
2018-03-24 00:50:01 -04:00
(defun nd/is-todoitem-p ()
"return todo keyword if present in headline
(which defines the heading as a todoitem)
this is used to both test if a heading is a todoitem
and retrieve the keyword"
(let ((keyword (nth 2 (org-heading-components))))
(if (member keyword org-todo-keywords-1)
keyword)))
2018-03-21 21:44:31 -04:00
(defun nd/heading-has-children ()
2018-03-31 01:43:17 -04:00
"returns t if heading has todoitems in its immediate subtree"
;; TODO make this more efficient (and accurate) by only testing
;; the level immediately below (if it exists)
(let ((has-children)
(subtree-end (save-excursion (org-end-of-subtree t))))
(save-excursion
(outline-next-heading)
(while (and (not has-children)
(< (point) subtree-end))
(when (nd/is-todoitem-p)
2018-03-31 01:43:17 -04:00
(setq has-children t))
;; (org-forward-heading-same-level 1 t)))
(outline-next-heading)))
has-children))
2018-03-22 00:32:17 -04:00
(defun nd/heading-has-parent ()
2018-03-31 01:43:17 -04:00
"returns parent keyword if heading is in the immediate subtree of a todoitem"
(save-excursion (and (org-up-heading-safe) (nd/is-todoitem-p))))
2018-03-24 00:50:01 -04:00
(defun nd/is-project-p ()
"return todo keyword if heading is todoitem and has children"
2018-03-31 01:43:17 -04:00
(and (nd/heading-has-children) (nd/is-todoitem-p)))
2018-03-21 21:44:31 -04:00
2018-03-24 00:50:01 -04:00
(defun nd/is-task-p ()
"return todo keyword if heading is todoitem with no children"
2018-03-31 01:43:17 -04:00
(and (not (nd/heading-has-children)) (nd/is-todoitem-p)))
2018-03-24 00:50:01 -04:00
(defun nd/is-atomic-task-p ()
"return todo keyword if heading is task with no parents"
2018-03-31 01:43:17 -04:00
(and (not (nd/heading-has-parent)) (nd/is-task-p)))
2018-03-24 00:50:01 -04:00
(defun nd/is-project-task-p ()
"return todo keyword if heading is task with no parents"
(and (nd/heading-has-parent) (nd/is-task-p)))
(defun nd/is-scheduled-heading-p ()
"return timestamp if headline is scheduled"
(org-entry-get nil "SCHEDULED"))
(defun nd/is-active-task-p ()
"return keyword if task is either NEXT or scheduled"
(let ((keyword (nd/is-task-p)))
(if (or (equal keyword "NEXT") (nd/is-scheduled-heading-p))
keyword)))
(defun nd/is-blocked-task-p ()
"return keyword if task is WAITING"
(equal (nd/is-task-p) "WAITING"))
2018-03-22 00:32:17 -04:00
2018-03-22 23:32:11 -04:00
;; org-forward-heading-same-level
;; project level testing
(defun nd/test-first-order-project ()
"tests the state of a project assuming first order.
if not first order, this function will iterate to the next project
and descend into it by calling itelf recursively.
function is not meant to be called independently."
(let ((found-active)
(previous-point))
(save-excursion
(setq previous-point (point))
(outline-next-heading)
(while (and (not found-active)
(> (point) previous-point))
(when (or (and (nd/is-project-p)
(nd/test-first-order-project))
(nd/is-active-task-p))
(setq found-active t))
(setq previous-point (point))
(org-forward-heading-same-level 1 t)))
found-active))
(defconst nd/project-invalid-todostates
'("WAITING" "NEXT")
"projects cannot have these todostates")
2018-03-31 01:43:17 -04:00
;; project level testing
(defun nd/descend-into-project ()
"returns numeric value according to state of project:
0: stuck
1: held
2: waiting
3: active
Larger values have precedence over smaller (eg a NEXT
keyword will override any other WAITING or HELD task present"
(let ((project-state 0)
(previous-point))
(save-excursion
(setq previous-point (point))
(outline-next-heading)
(while (and (< project-state 3)
(> (point) previous-point))
(let ((keyword (nd/is-todoitem-p))
(has-children (nd/heading-has-children)))
(if keyword
(let ((cur-state
(if has-children
(cond ((equal keyword "HOLD") 1)
((equal keyword "TODO") (nd/descend-into-project))
(t 0))
(cond ((equal keyword "HOLD") 1)
((equal keyword "WAITING") 2)
((equal keyword "NEXT") 3)
((nd/is-scheduled-heading-p) 3)
(t 0)))))
(if (> cur-state project-state)
2018-03-30 20:54:25 -04:00
(setq project-state cur-state)))))
(setq previous-point (point))
(org-forward-heading-same-level 1 t)))
project-state))
2018-03-31 01:43:17 -04:00
(defun nd/is-project-status-p (statuscode)
(let ((keyword (nd/is-project-p)))
(if keyword
(cond ((member keyword nd/project-invalid-todostates) nil)
((and (equal keyword "HOLD") (= statuscode 1)) keyword)
((and (equal keyword "HOLD") (/= statuscode 1)) nil)
((= statuscode (nd/descend-into-project)) keyword)))))
2018-03-22 00:32:17 -04:00
;; task skip functions
2018-03-31 01:43:17 -04:00
;; NOTE: use save-restriction and widen if we ever actually use narrowing
2018-03-22 00:32:17 -04:00
(defun nd/skip-non-atomic-tasks ()
2018-03-31 01:43:17 -04:00
(if (not (nd/is-atomic-task-p))
(save-excursion (or (outline-next-heading) (point-max)))))
2018-03-21 21:44:31 -04:00
(defun nd/skip-non-next-project-tasks ()
(if (not (equal (nd/is-project-task-p) "NEXT"))
(save-excursion (or (outline-next-heading) (point-max)))))
(defun nd/skip-non-waiting-project-tasks ()
(if (not (equal (nd/is-project-task-p) "WAITING"))
(save-excursion (or (outline-next-heading) (point-max)))))
(defun nd/skip-non-held-project-tasks ()
(if (not (equal (nd/is-project-task-p) "HOLD"))
2018-03-31 01:43:17 -04:00
(save-excursion (or (outline-next-heading) (point-max)))))
(defun nd/skip-non-stuck-projects ()
(if (not (nd/is-project-status-p 0))
(save-excursion (or (outline-next-heading) (point-max)))))
2018-03-21 21:44:31 -04:00
(defun nd/skip-non-held-projects ()
(if (not (nd/is-project-status-p 1))
(save-excursion (or (outline-next-heading) (point-max)))))
(defun nd/skip-non-waiting-projects ()
(if (not (nd/is-project-status-p 2))
(save-excursion (or (outline-next-heading) (point-max)))))
(defun nd/skip-non-active-projects ()
(if (not (nd/is-project-status-p 3))
(save-excursion (or (outline-next-heading) (point-max)))))
2018-03-31 01:43:17 -04:00
;; (defvar nd/hide-scheduled-and-waiting-next-tasks t)
2018-03-21 21:44:31 -04:00
2018-03-31 01:43:17 -04:00
;; (defun nd/toggle-next-task-display ()
;; (interactive)
;; (setq nd/hide-scheduled-and-waiting-next-tasks (not nd/hide-scheduled-and-waiting-next-tasks))
;; (when (equal major-mode 'org-agenda-mode)
;; (org-agenda-redo))
;; (message "%s WAITING and SCHEDULED NEXT Tasks" (if nd/hide-scheduled-and-waiting-next-tasks "Hide" "Show")))
;; (defun nd/skip-non-stuck-projects ()
;; "Skip trees that are not stuck projects"
;; (save-restriction
;; (widen)
;; (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
;; (if (nd/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))))
2018-03-21 21:44:31 -04:00
2018-03-22 23:32:11 -04:00
;; project test functions
;; is state
;; if project
;; if order = 1
;; return (state is true)
;; else order > 1
;; call is state (recursive)
;; else if task
;; return (state is true)
;; note: this needs to iterate through lines
;; (defun nd/is-active-project-p ()
;; "return true if project has at least one
;; NEXT/scheduled task or active subproject"
;; ;; if not a project then don't bother
;; (if (nd/is-project-p)
;; (let (((subtree-end (save-excursion (org-end-of-subtree t))))
;; (is-active))
;; (save-excursion
;; (while (and (not is-active)
;; (< (point) subtree-end))
;; (outline-heading-next)
;; (cond ((nd/is-active-task-p) (setq is-active t))
;; ((nd/is-active-project-p) (setq is-active))))))))
2018-03-21 21:44:31 -04:00
2018-03-22 23:32:11 -04:00
;; (defun nd/skip-non-stuck-projects ()
;; goto next headline
;; if project
;; if project order 1
;; if it has NEXT, WAITING, HOLD, or a scheduled task
;; then skip (return end of subtree)
;; else stuck project, return nil
;; else (order > 1)
;; descend into project (recursion)
;; skip (either an atomic task or non-todo, return next heading)
;; )
2018-03-21 21:44:31 -04:00
2018-03-31 01:43:17 -04:00
;; (defun nd/skip-non-projects ()
;; "Skip trees that are not projects"
;; ;; (nd/list-sublevels-for-projects-indented)
;; (if (save-excursion (nd/skip-non-stuck-projects))
;; (save-restriction
;; (widen)
;; (let ((subtree-end (save-excursion (org-end-of-subtree t))))
;; (cond
;; ((nd/is-project-p)
;; nil)
;; ((and (nd/is-subtask-p) (not (nd/is-atomic-p)))
;; nil)
;; (t
;; subtree-end))))
;; (save-excursion (org-end-of-subtree t))))
2018-03-21 21:44:31 -04:00
(defun nd/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
2018-03-22 00:32:17 -04:00
((nd/is-atomic-p)
2018-03-21 21:44:31 -04:00
nil)
(t
next-headline)))))
(defun nd/skip-project-trees-and-habits ()
"Skip trees that are projects"
(save-restriction
(widen)
(let ((subtree-end (save-excursion (org-end-of-subtree t))))
(cond
((nd/is-project-p)
subtree-end)
;; ((org-is-habit-p)
;; subtree-end)
(t
nil)))))
(defun nd/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 nd/hide-scheduled-and-waiting-next-tasks
(member "WAITING" (org-get-tags-at)))
next-headline)
((nd/is-project-p)
next-headline)
2018-03-22 00:32:17 -04:00
((and (nd/is-atomic-p) (not (nd/is-subtask-p)))
2018-03-21 21:44:31 -04:00
next-headline)
(t
nil)))))
(defun nd/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
((nd/is-project-p)
next-headline)
;; ((org-is-habit-p)
;; subtree-end)
((and (not limit-to-project)
(nd/is-subtask-p))
subtree-end)
((and limit-to-project
(nd/is-subtask-p)
(member (org-get-todo-state) (list "NEXT")))
subtree-end)
(t
nil)))))
(defun nd/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
((nd/is-project-p)
subtree-end)
;; ((org-is-habit-p)
;; subtree-end)
((nd/is-subtask-p)
subtree-end)
(t
nil)))))
(defun nd/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
((nd/is-project-p)
next-headline)
;; ((org-is-habit-p)
;; subtree-end)
((and (nd/is-subtask-p)
(member (org-get-todo-state) (list "NEXT")))
subtree-end)
((not (nd/is-subtask-p))
subtree-end)
(t
nil)))))
(defun nd/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
((nd/is-project-p)
subtree-end)
;; ((org-is-habit-p)
;; subtree-end)
(t
nil)))))
;; (defun nd/skip-non-subprojects ()
;; "Skip trees that are not projects"
;; (let ((next-headline (save-excursion (outline-next-heading))))
;; (if (nd/is-subproject-p)
;; nil
;; next-headline)))
#+END_SRC
** ui
*** bullets
#+BEGIN_SRC emacs-lisp
(use-package org-bullets
:ensure t
:config
(add-hook 'org-mode-hook (lambda () (org-bullets-mode))))
#+END_SRC
** caldav
+BEGIN_SRC emacs-lisp
(use-package org-caldav
:ensure t
:config (org-caldav-url "https://portnoy4prez.yavin4.ch/nextcloud/remote.php/dav/calendars/petrucci4prez/concerts/"
org-cladav-calendar-id "testorg"
org-caldav-inbox "~/Org/reference/testcal.org"))
#+END_SRC
** calfw
#+BEGIN_SRC emacs-lisp
(use-package calfw-org
:init
:ensure t
:config (setq cfw:fchar-junction ?╋
cfw:fchar-vertical-line ?┃
cfw:fchar-horizontal-line ?━
cfw:fchar-left-junction ?┣
cfw:fchar-right-junction ?┫
cfw:fchar-top-junction ?┯
cfw:fchar-top-left-corner ?┏
cfw:fchar-top-right-corner ?┓))
#+END_SRC
* shell
#+begin_src emacs-lisp
(defvar nd-term-shell "/bin/bash")
(defadvice ansi-term (before force-bash)
(interactive (list nd-term-shell)))
(ad-activate 'ansi-term)
#+END_SRC
* ediff
#+BEGIN_SRC emacs-lisp
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
#+END_SRC