commit e679725be1e300356470463267da026250890eb6 Author: petrucci4prez Date: Wed Mar 21 21:44:31 2018 -0400 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..076a0b5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/* +!.gitignore +!conf.org +!conf.el diff --git a/conf.el b/conf.el new file mode 100644 index 0000000..06b29b9 --- /dev/null +++ b/conf.el @@ -0,0 +1,797 @@ + +(setq inhibit-startup-screen t) + +(tool-bar-mode -1) +(menu-bar-mode -1) +(scroll-bar-mode -1) + +(set-default 'truncate-lines t) + +(setq make-backup-files nil) +(setq auto-save-default nil) + +(setq pop-up-windows nil) ; no popups (eg ediff) + +;; (global-linum-mode t) +(line-number-mode 1) +(column-number-mode 1) + +(setq-default tab-width 4) + +(setq scroll-conservatively 100) + +(when window-system (global-prettify-symbols-mode t)) + +(when window-system (global-hl-line-mode t)) + +(defalias 'yes-or-no-p 'y-or-n-p) ; eliminate yes or no prompt on killing procs + +(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)))) + +(use-package spaceline + :ensure t + :config + (require 'spaceline-config) + (setq powerline-default-separator (quote arrow)) + (spaceline-spacemacs-theme) + (setq spaceline-buffer-size-p nil)) + +(use-package dashboard + :ensure t + :config + (dashboard-setup-startup-hook) + (setq dashboard-items '((recents . 10)))) + +(global-set-key (kbd "C-h a") 'apropos) + +(use-package delight + :ensure t) + +(use-package beacon + :ensure t + :delight + :init + (beacon-mode 1)) + +(use-package which-key + :ensure t + :delight + :init + (which-key-mode)) + +(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")) + +(use-package smex + :ensure t + :init + (smex-initialize) + :bind + ("M-x" . 'smex) + ("M-X" . 'smex-major-mode-commands)) + +(use-package rainbow-delimiters + :ensure t + :delight + :init + (add-hook 'prog-mode-hook #'rainbow-delimiters-mode)) + +(use-package ace-window + :ensure t + :bind ("M-o" . ace-window) + :config (setq aw-background nil)) + +(use-package avy + :ensure t + :bind ("M-s" . avy-goto-char) + :config (setq avy-background t)) + +(use-package sudo-edit + :ensure t + :bind ("C-c s" . sudo-edit)) + +(use-package typit + :init + :ensure t) + +(use-package calfw + :init + :ensure t) + +(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))) + +(use-package undo-tree + :ensure t + :delight + :config + (global-undo-tree-mode) + (setq undo-tree-visualizer-diff t)) + +(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) + +(defun config-visit () +(interactive) +(find-file "~/.emacs.d/conf.org")) +(global-set-key (kbd "C-c e") 'config-visit) + +(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) + +(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)))) + +(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)))) + +(global-set-key (kbd "") '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)))) + +(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)))))) + +(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/")) + +(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") + +;;(add-hook 'org-capture-mode-hook 'evil-append) + +(add-to-list 'org-structure-template-alist + '("el" "#+BEGIN_SRC emacs-lisp\n?\n#+END_SRC")) + +(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 + +(setq org-special-ctrl-a/e t) +(setq org-special-ctrl-k t) +(setq org-yank-adjusted-subtrees t) + +(setq org-todo-keywords + (quote ((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d)") + (sequence "WAITING(w@/!)" "HOLD(h@/!)" "|" "CANCELLED(c@/!)")))) + +(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)))) + +(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"))))) + +(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) + +(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" . ??)))) + +(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")))) + +(setq org-refile-targets (quote ((nil :maxlevel . 9) + ("~/Org/reference/idea.org" :maxlevel . 9) + (org-agenda-files :maxlevel . 9)))) + +(setq org-refile-use-outline-path t) +(setq org-outline-path-complete-in-steps nil) +(setq org-completion-use-ido t) + +(setq org-refile-allow-creating-parent-nodes (quote confirm)) + +(setq org-indirect-buffer-display 'current-window) + +(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) + +(setq org-agenda-files (quote ("~/Org" + "~/Org/large_projects" + "~/Org/reference"))) +(setq org-agenda-dim-blocked-tasks nil) +(setq org-agenda-compact-blocks t) + +(setq org-agenda-span 'day) + +(setq org-agenda-time-grid (quote ((daily today remove-match) + #("----------------" 0 16 (org-heading t)) + (0900 1100 1300 1500 1700)))) + +(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)) + +(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-CANCELLED/!NEXT" + ((org-agenda-overriding-header (concat "Project Next Tasks" + (if nd/hide-scheduled-and-waiting-next-tasks + "" + " (including WAITING and SCHEDULED tasks)"))) + (org-agenda-skip-function 'nd/skip-projects-and-habits-and-single-tasks) + (org-tags-match-list-sublevels t) + (org-agenda-todo-ignore-with-date 'all) + (org-agenda-sorting-strategy + '(todo-state-down effort-up category-keep)))) + (tags-todo "-NA-REFILE-CANCELLED-WAITING-HOLD/!" + ((org-agenda-overriding-header (concat "Atomic Tasks" + (if nd/hide-scheduled-and-waiting-next-tasks + "" + " (including WAITING and SCHEDULED tasks)"))) + (org-agenda-skip-function 'nd/skip-project-tasks) + (org-agenda-todo-ignore-with-date 'all) + (org-agenda-sorting-strategy + '(category-keep)))) + (tags-todo "-NA-REFILE-CANCELLED-WAITING-HOLD/!" + ((org-agenda-overriding-header (concat "Project Subtasks" + (if nd/hide-scheduled-and-waiting-next-tasks + "" + " (including WAITING and SCHEDULED tasks)"))) + (org-agenda-skip-function 'nd/skip-non-project-tasks) + (org-agenda-todo-ignore-with-date 'all) + (org-agenda-sorting-strategy + '(category-keep)))) + (tags-todo "-NA-CANCELLED+WAITING|HOLD/!" + ((org-agenda-overriding-header (concat "Waiting and Postponed Tasks" + (if nd/hide-scheduled-and-waiting-next-tasks + "" + " (including WAITING and SCHEDULED tasks)"))) + (org-agenda-skip-function 'nd/skip-non-tasks) + (org-tags-match-list-sublevels nil) + (org-agenda-todo-ignore-with-date 'all))) + (tags-todo "-NA-CANCELLED/!" + ((org-agenda-overriding-header "Stuck Projects") + (org-agenda-skip-function 'nd/skip-non-stuck-projects) + (org-agenda-skip-function 'nd/skip-non-blocked-projects) + (org-agenda-sorting-strategy + '(category-keep)))) + (tags-todo "-NA-HOLD-CANCELLED/!" + ((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)))) + nil)))) + +(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) + +(defun nd/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)))) + ;; go up to parent heading (no error) + (while (org-up-heading-safe) + ;; in case the parent has no todo keyword, keep going + (when (member (nth 2 (org-heading-components)) org-todo-keywords-1) + (setq parent-task (point)))) + ;; when parent found, go there and return its position + (goto-char parent-task) + parent-task))) + +;; keep +(defun nd/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)))) + +;; old version +;; (defun nd/is-subtask-p () +;; "Any task with a todo keyword that is in a project subtree. +;; Callers of this function already widen the buffer view." +;; ;; go back up to heading +;; (let ((task (save-excursion (org-back-to-heading 'invisible-ok) +;; (point)))) + +;; (save-excursion +;; (nd/find-project-task) +;; ;; go up to parent heading +;; (if (equal (point) task) +;; nil +;; t)))) + + +;; (defun nd/is-subproject-p () +;; "Any task which is a subtask of another project" +;; (let ((is-subproject) +;; ;; is-a-task is true if it has a valid TODO keyword +;; (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1))) +;; (save-excursion +;; ;; loop up through headings until we encounter a task or the top level +;; (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 nd/is-subtask-p () + "Any task with a todo keyword that is in a project subtree. +Callers of this function already widen the buffer view." + ;; go back up to heading + (let ((task (save-excursion (org-back-to-heading 'invisible-ok) + (point)))) + + (save-excursion + (nd/find-project-task) + ;; go up to parent heading + (if (equal (point) task) + nil + t)))) +;; (defun nd/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)))) +;; ;; go up to parent heading (no error) +;; (while (org-up-heading-safe) +;; ;; in case the parent has no todo keyword, keep going +;; (when (member (nth 2 (org-heading-components)) org-todo-keywords-1) +;; (setq parent-task (point)))) +;; ;; when parent found, go there and return its position +;; (goto-char parent-task) +;; parent-task))) + +(defun nd/is-atomic-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 nd/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 nd/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 nd/hide-scheduled-and-waiting-next-tasks t) + +(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"))) + +;; this skip function seems inefficient, it looks like we are skipping one headline at a time +;; but searching for NEXT in the entire subtree +;; can I do better? +(defun nd/skip-stuck-projects () + "Skip trees that are not stuck projects" + ;; save narrow buffer state + (save-restriction + ;; widen to see the entire buffer + (widen) + ;; define next-headline as either the next headline or the end of the buffer + (let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))) + ;; if headline has subtasks + (if (nd/is-project-p) + ;; define subtree-end as the end of the subtree + ;; initialize has-next with nil + (let* ((subtree-end (save-excursion (org-end-of-subtree t))) + (has-next )) + ;; save where we are pointing + (save-excursion + ;; go forward one line + (forward-line 1) + ;; while loop which continues if + ;; - has-next is nil + ;; - we are not at the end of the subtree + ;; - there is no NEXT between here and the subtree end + + ;; this is a loop because there could be multiple NEXT tasks (obviously) + ;; the regex search moves the point to the end of the first found NEXT + ;; relative to the start point position + ;; once it gets to the end of the subtree it returns nil and the loop breaks + (while (and (not has-next) + (< (point) subtree-end) + (re-search-forward "^\\*+ NEXT " subtree-end t)) + ;; if WAITING is not in tag list + ;; i guess this is here because if the loop finds next + ;; and the NEXT task also has WAITING (which it would need to inherit + ;; because WAITING and NEXT are mutully exclusive) then we keep looping + + ;; so the Bernt defined stuck projects as those which have WAITING tasks + ;; that override a NEXT subtask + (unless (member "WAITING" (org-get-tags-at)) + ;; set has-next to true + (setq has-next t)))) + ;; if we have a next task, set to nil (eg don't skip) + (if has-next + nil + ;; if no next task, skip to next headline + next-headline)) ; a stuck project, has subtasks but no next task + ;; don't skip if not a project + nil)))) + +(defun nd/skip-non-stuck-projects () + "Skip trees that are not stuck projects" + ;; (nd/list-sublevels-for-projects-indented) + (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)))) + +(defun nd/skip-non-blocked-projects () + "Skip trees that are not stuck projects" + ;; (nd/list-sublevels-for-projects-indented) + (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 "^\\*+ WAITING " 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 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-task-p))) + nil) + (t + subtree-end)))) + (save-excursion (org-end-of-subtree t)))) + +(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 + ((nd/is-atomic-task-p) + 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) + ((and (nd/is-atomic-task-p) (not (nd/is-subtask-p))) + 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))) + +(use-package org-bullets + :ensure t + :config + (add-hook 'org-mode-hook (lambda () (org-bullets-mode)))) + +(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 ?┓)) + +(defvar nd-term-shell "/bin/bash") +(defadvice ansi-term (before force-bash) + (interactive (list nd-term-shell))) +(ad-activate 'ansi-term) + +(setq ediff-window-setup-function 'ediff-setup-windows-plain) diff --git a/conf.org b/conf.org new file mode 100644 index 0000000..266c315 --- /dev/null +++ b/conf.org @@ -0,0 +1,995 @@ +* 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 "") '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-CANCELLED/!NEXT" + ((org-agenda-overriding-header (concat "Project Next Tasks" + (if nd/hide-scheduled-and-waiting-next-tasks + "" + " (including WAITING and SCHEDULED tasks)"))) + (org-agenda-skip-function 'nd/skip-projects-and-habits-and-single-tasks) + (org-tags-match-list-sublevels t) + (org-agenda-todo-ignore-with-date 'all) + (org-agenda-sorting-strategy + '(todo-state-down effort-up category-keep)))) + (tags-todo "-NA-REFILE-CANCELLED-WAITING-HOLD/!" + ((org-agenda-overriding-header (concat "Atomic Tasks" + (if nd/hide-scheduled-and-waiting-next-tasks + "" + " (including WAITING and SCHEDULED tasks)"))) + (org-agenda-skip-function 'nd/skip-project-tasks) + (org-agenda-todo-ignore-with-date 'all) + (org-agenda-sorting-strategy + '(category-keep)))) + (tags-todo "-NA-REFILE-CANCELLED-WAITING-HOLD/!" + ((org-agenda-overriding-header (concat "Project Subtasks" + (if nd/hide-scheduled-and-waiting-next-tasks + "" + " (including WAITING and SCHEDULED tasks)"))) + (org-agenda-skip-function 'nd/skip-non-project-tasks) + (org-agenda-todo-ignore-with-date 'all) + (org-agenda-sorting-strategy + '(category-keep)))) + (tags-todo "-NA-CANCELLED+WAITING|HOLD/!" + ((org-agenda-overriding-header (concat "Waiting and Postponed Tasks" + (if nd/hide-scheduled-and-waiting-next-tasks + "" + " (including WAITING and SCHEDULED tasks)"))) + (org-agenda-skip-function 'nd/skip-non-tasks) + (org-tags-match-list-sublevels nil) + (org-agenda-todo-ignore-with-date 'all))) + (tags-todo "-NA-CANCELLED/!" + ((org-agenda-overriding-header "Stuck Projects") + (org-agenda-skip-function 'nd/skip-non-stuck-projects) + (org-agenda-skip-function 'nd/skip-non-blocked-projects) + (org-agenda-sorting-strategy + '(category-keep)))) + (tags-todo "-NA-HOLD-CANCELLED/!" + ((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)))) + 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 +#+BEGIN_SRC emacs-lisp + (defun nd/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)))) + ;; go up to parent heading (no error) + (while (org-up-heading-safe) + ;; in case the parent has no todo keyword, keep going + (when (member (nth 2 (org-heading-components)) org-todo-keywords-1) + (setq parent-task (point)))) + ;; when parent found, go there and return its position + (goto-char parent-task) + parent-task))) + + ;; keep + (defun nd/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)))) + + ;; old version + ;; (defun nd/is-subtask-p () + ;; "Any task with a todo keyword that is in a project subtree. + ;; Callers of this function already widen the buffer view." + ;; ;; go back up to heading + ;; (let ((task (save-excursion (org-back-to-heading 'invisible-ok) + ;; (point)))) + + ;; (save-excursion + ;; (nd/find-project-task) + ;; ;; go up to parent heading + ;; (if (equal (point) task) + ;; nil + ;; t)))) + + + ;; (defun nd/is-subproject-p () + ;; "Any task which is a subtask of another project" + ;; (let ((is-subproject) + ;; ;; is-a-task is true if it has a valid TODO keyword + ;; (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1))) + ;; (save-excursion + ;; ;; loop up through headings until we encounter a task or the top level + ;; (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 nd/is-subtask-p () + "Any task with a todo keyword that is in a project subtree. + Callers of this function already widen the buffer view." + ;; go back up to heading + (let ((task (save-excursion (org-back-to-heading 'invisible-ok) + (point)))) + + (save-excursion + (nd/find-project-task) + ;; go up to parent heading + (if (equal (point) task) + nil + t)))) + ;; (defun nd/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)))) + ;; ;; go up to parent heading (no error) + ;; (while (org-up-heading-safe) + ;; ;; in case the parent has no todo keyword, keep going + ;; (when (member (nth 2 (org-heading-components)) org-todo-keywords-1) + ;; (setq parent-task (point)))) + ;; ;; when parent found, go there and return its position + ;; (goto-char parent-task) + ;; parent-task))) + + (defun nd/is-atomic-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 nd/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 nd/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 nd/hide-scheduled-and-waiting-next-tasks t) + + (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"))) + + ;; this skip function seems inefficient, it looks like we are skipping one headline at a time + ;; but searching for NEXT in the entire subtree + ;; can I do better? + (defun nd/skip-stuck-projects () + "Skip trees that are not stuck projects" + ;; save narrow buffer state + (save-restriction + ;; widen to see the entire buffer + (widen) + ;; define next-headline as either the next headline or the end of the buffer + (let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))) + ;; if headline has subtasks + (if (nd/is-project-p) + ;; define subtree-end as the end of the subtree + ;; initialize has-next with nil + (let* ((subtree-end (save-excursion (org-end-of-subtree t))) + (has-next )) + ;; save where we are pointing + (save-excursion + ;; go forward one line + (forward-line 1) + ;; while loop which continues if + ;; - has-next is nil + ;; - we are not at the end of the subtree + ;; - there is no NEXT between here and the subtree end + + ;; this is a loop because there could be multiple NEXT tasks (obviously) + ;; the regex search moves the point to the end of the first found NEXT + ;; relative to the start point position + ;; once it gets to the end of the subtree it returns nil and the loop breaks + (while (and (not has-next) + (< (point) subtree-end) + (re-search-forward "^\\*+ NEXT " subtree-end t)) + ;; if WAITING is not in tag list + ;; i guess this is here because if the loop finds next + ;; and the NEXT task also has WAITING (which it would need to inherit + ;; because WAITING and NEXT are mutully exclusive) then we keep looping + + ;; so the Bernt defined stuck projects as those which have WAITING tasks + ;; that override a NEXT subtask + (unless (member "WAITING" (org-get-tags-at)) + ;; set has-next to true + (setq has-next t)))) + ;; if we have a next task, set to nil (eg don't skip) + (if has-next + nil + ;; if no next task, skip to next headline + next-headline)) ; a stuck project, has subtasks but no next task + ;; don't skip if not a project + nil)))) + + (defun nd/skip-non-stuck-projects () + "Skip trees that are not stuck projects" + ;; (nd/list-sublevels-for-projects-indented) + (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)))) + + (defun nd/skip-non-blocked-projects () + "Skip trees that are not stuck projects" + ;; (nd/list-sublevels-for-projects-indented) + (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 "^\\*+ WAITING " 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 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-task-p))) + nil) + (t + subtree-end)))) + (save-excursion (org-end-of-subtree t)))) + + (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 + ((nd/is-atomic-task-p) + 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) + ((and (nd/is-atomic-task-p) (not (nd/is-subtask-p))) + 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