Update org config

This commit is contained in:
Henrik Lissner 2016-02-13 00:46:58 -05:00
parent 3cc18ac674
commit a670dad95f
8 changed files with 474 additions and 332 deletions

2
Cask
View file

@ -219,7 +219,7 @@
(depends-on "org-download") (depends-on "org-download")
(depends-on "ox-opml" :git "https://github.com/edavis/org-opml") (depends-on "ox-opml" :git "https://github.com/edavis/org-opml")
(depends-on "ox-pandoc") (depends-on "ox-pandoc")
; (depends-on "org-plus-contrib") (depends-on "org-plus-contrib")
;; Writing -- modules/lib-writing.el ;; Writing -- modules/lib-writing.el
(depends-on "helm-bibtex") (depends-on "helm-bibtex")

View file

@ -93,8 +93,7 @@ buffers."
(interactive) (interactive)
(in! org-directory (in! org-directory
(let ((helm-ff-skip-boring-files t)) (let ((helm-ff-skip-boring-files t))
(helm-find-files-1 org-directory)))) (helm-find-files-1 (concat org-directory "/")))))
(provide 'defuns-helm) (provide 'defuns-helm)
;;; defuns-helm.el ends here ;;; defuns-helm.el ends here

View file

@ -1,8 +1,8 @@
;;; helm-deft.el --- helm module for grepping note files over directories ;;; helm-deft.el --- helm module for grepping note files over directories
;; Copyright (C) 2014 Derek Feichtinger ;; Copyright (C) 2014 Derek Feichtinger
;; Author: Derek Feichtinger <derek.feichtinger@psi.ch> ;; Author: Derek Feichtinger <dfeich@gmail.com>
;; Keywords: convenience ;; Keywords: convenience
;; Homepage: https://github.com/dfeich/helm-deft ;; Homepage: https://github.com/dfeich/helm-deft
;; Version: TODO ;; Version: TODO
@ -23,6 +23,18 @@
;; You should have received a copy of the GNU General Public License ;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Helm command to find files fast based on contents and filename. Inspired
;; by the great emacs deft package. It allows defining a list of input directories
;; that can be defined and that are searched recursively.
;;
;; helm-deft is composed of three search sources
;; - file names: simple match of pattern vs. file name
;; - file match: shows file names of files where all of the individual patterns
;; match anywhere in the file
;; - file contents: show the lines where the last word in the search patterns
;; matches
;;; Code: ;;; Code:
(require 'helm) (require 'helm)
@ -30,45 +42,64 @@
(require 'helm-files) (require 'helm-files)
(require 'f) (require 'f)
(require 'cl-lib) (require 'cl-lib)
(require 'subr-x)
(defgroup helm-deft nil (defgroup helm-deft nil
"customization group for the helm-deft utility" :group 'helm :version 24.3) "customization group for the helm-deft utility" :group 'helm :version 24.3)
(defcustom helm-deft-dir-list (defcustom helm-deft-dir-list
'("~/Documents") '("~/Documents")
"list of directories in which to search recursively for candidate files" "List of directories in which to search recursively for candidate files."
:group 'helm-deft :group 'helm-deft
) )
(defcustom helm-deft-extension "org" (defcustom helm-deft-extension "org"
"defines file extension for identifying candidate files to be searched for") "Defines file extension for identifying candidate files to be searched for.")
(defvar helm-deft-file-list "" (defvar helm-deft-file-list nil
"variable to store the list of candidate files") "Variable to store the list of candidate files.
This is constant over the invocation of one helm-deft.")
(defvar helm-deft-matching-files '()
"Used for building the list of filenames that the grep matched.")
(defvar helm-source-deft-fn (defvar helm-source-deft-fn
'((name . "File Names") '((name . "File Names")
(header-line . "C-r: rotate pattern C-s/C-d: set/delete (marked) candidates from list")
(init . (lambda () (init . (lambda ()
(progn (setq helm-deft-file-list (helm-deft-fname-search)) (progn (unless helm-deft-file-list
(setq helm-deft-file-list (helm-deft-fname-search)))
(with-current-buffer (helm-candidate-buffer 'local) (with-current-buffer (helm-candidate-buffer 'local)
(insert (mapconcat 'identity (insert (mapconcat 'identity
helm-deft-file-list "\n")))))) helm-deft-file-list "\n"))))))
(candidates-in-buffer) (candidates-in-buffer)
;; matching is done in the buffer when candidates-in-buffer is used ;; matching is done in the buffer when candidates-in-buffer is used
;; We only want against the basename and not the full path ;; We only want against the basename and not the full path
(match-part . (lambda (c) (helm-basename c))) (match-part . (lambda (c) (helm-basename c)))
(type . file) ;;(type . file)
;; Note: We override the transformer that the file type brings. We (action . helm-find-files-actions)
;; want the file list sorted ;; We want the file list sorted. helm-highlight-files also will
;; transform a filename to a (basename . filename) cons
(candidate-transformer . (lambda (c) (sort (helm-highlight-files c) (candidate-transformer . (lambda (c) (sort (helm-highlight-files c)
(lambda (a b) (lambda (a b)
(string< (downcase (car a)) (string< (downcase (car a))
(downcase (car b))))))) (downcase (car b)))))))
;; (action . (("open file" . (lambda (candidate) (cleanup . (lambda () (setq helm-deft-file-list nil)))
;; (find-file candidate)))))
;;(persistent-help . "show name")
) )
"Source definition for matching filenames of the `helm-deft' utility") "Source definition for matching filenames of the `helm-deft' utility.")
(defun helm-deft-fname-search ()
"Search all preconfigured directories for matching files.
Returns the filenames as a list."
(assert helm-deft-extension nil "No file extension defined for helm-deft")
(assert helm-deft-dir-list nil "No directories defined for helm-deft")
(cl-loop for dir in helm-deft-dir-list
do (assert (file-exists-p dir) nil
(format "Directory %s does not exist. Check helm-deft-dir-list" dir))
collect (f--files dir (equal (f-ext it) helm-deft-extension) t)
into reslst
finally (return (apply #'append reslst)))
)
(defvar helm-source-deft-filegrep (defvar helm-source-deft-filegrep
'((name . "File Contents") '((name . "File Contents")
@ -76,16 +107,142 @@
;; We use the action from the helm-grep module ;; We use the action from the helm-grep module
(action . helm-grep-action) (action . helm-grep-action)
(requires-pattern) (requires-pattern)
(filter-one-by-one . helm-grep-filter-one-by-one) (pattern-transformer . (lambda (pattern)
(cl-loop for ptr in (split-string pattern " *" t)
if (string-prefix-p "w:" ptr)
collect (string-remove-prefix "w:" ptr) into cptr
else collect ptr into cptr
finally return (mapconcat 'identity cptr " "))))
(filter-one-by-one . (lambda (candidate)
;; we abuse the filter-one-by-one function
;; for building the candidates list for the
;; matching-files source
(helm-deft-matching-files-search candidate)
;; we borrow the helm-grep filter function
(helm-grep-filter-one-by-one candidate)))
(cleanup . (lambda () (when (get-buffer "*helm-deft-proc*") (cleanup . (lambda () (when (get-buffer "*helm-deft-proc*")
(let ((kill-buffer-query-functions nil)) (let ((kill-buffer-query-functions nil))
(kill-buffer "*helm-deft-proc*"))))) (kill-buffer "*helm-deft-proc*")))))
) )
"Source definition for matching against file contents for the "Source definition for matching against file contents for the `helm-deft' utility.")
`helm-deft' utility")
(defun helm-deft-build-cmd (ptrnstr filelst)
"Builds a grep command based on the patterns and file list.
PTRNSTR may contain multiple search patterns separated by
spaces. The first pattern will be used to retrieve matching
lines. All other patterns will be used to pre-select files with
matching lines. FILELST is a list of file paths"
(let* ((ptrnlst (reverse (split-string ptrnstr " *" t)))
(firstp (pop ptrnlst))
(firstaddflag (if (string-prefix-p "w:" firstp)
(progn
(setq firstp (string-remove-prefix "w:" firstp))
"-w")
""))
(filelst (mapconcat 'identity filelst " "))
(innercmd (if ptrnlst
(cl-labels ((build-inner-cmd
(ptrnlst filelst)
(let* ((pattern (pop ptrnlst))
(addflags
(if (string-prefix-p "w:" pattern)
(progn
(setq pattern
(string-remove-prefix
"w:" pattern))
"-w")
"")))
(if ptrnlst
(format "$(grep %s -Elie '%s' %s)"
addflags pattern
(build-inner-cmd ptrnlst filelst))
(format "$(grep %s -Elie '%s' %s)"
addflags pattern filelst)))))
(build-inner-cmd ptrnlst filelst))
filelst)))
(format "grep %s -EHine '%s' %s" firstaddflag firstp innercmd))
)
(defun helm-deft-fgrep-search ()
"Greps for the helm search pattern in the configuration defined file list."
(setq helm-deft-matching-files '())
;; need to pass helm-input (the real input line) to the build
;; function since helm-pattern is already cleaned by the
;; pattern-transformer function of helm-source-deft-filegrep
(let* ((shcmd (helm-deft-build-cmd helm-input helm-deft-file-list)))
(helm-log "grep command: %s" shcmd)
;; the function must return the process object
(prog1
(start-process-shell-command "helm-deft-proc" "*helm-deft-proc*"
shcmd)
(set-process-sentinel
(get-process "helm-deft-proc")
(lambda (process event)
(cond
((string= event "finished\n")
(with-helm-window
(setq mode-line-format
'(" " mode-line-buffer-identification " "
(:eval (format "L%s" (helm-candidate-number-at-point))) " "
(:eval (propertize
;; TODO: The count is wrong since it counts all sources
(format
"[Grep process finished - (%s results)] "
(max (1- (count-lines
(point-min)
(point-max)))
0))
'face 'helm-grep-finish))))
(force-mode-line-update))
;; must NOT DO a targeted update here. Seems to call also this source
;; and we end in an infinite loop
;; (helm-update nil helm-source-deft-matching-files)
)
;; Catch error output in log.
(t (helm-log
"Error: Grep %s"
(replace-regexp-in-string "\n" "" event))))
))
)
))
(defvar helm-source-deft-matching-files
'((name . "Matching Files")
(candidates . helm-deft-matching-files)
;;(type . file)
;; introducing the delayed value to always have it scheduled after
;; the async grep process that produces the basis for this source
(delayed . 0.5)
(action . helm-find-files-actions)
;; need to override the file type's match settings
(match . (lambda (candidate) t))
(candidate-transformer . (lambda (c) (sort (helm-highlight-files c)
(lambda (a b)
(string< (downcase (car a))
(downcase (car b)))))))
(requires-pattern)
(volatile)
)
"Source definition for showing matching files from the grep buffer of the `helm-deft' utility.")
(defun helm-deft-matching-files-search (candidate)
"Add entry to helm-deft-matching-files list from a grep CANDIDATE."
(when (string-match "\\([^:]+\\):[0-9]+:" candidate)
(pushnew (match-string 1 candidate) helm-deft-matching-files :test #'equal)))
;; (defun helm-deft-matching-files-search ()
;; (when (get-buffer "*helm-deft-proc*")
;; (with-current-buffer "*helm-deft-proc*"
;; (beginning-of-buffer)
;; (while (and
;; (looking-at "^\\([^:]+\\):[0-9]+:")
;; (not (equal (forward-line) 1)))
;; (push (match-string 1) helm-deft-matching-files)))
;; (cl-remove-duplicates helm-deft-matching-files :test #'equal))
;; )
(defun helm-deft-rotate-searchkeys () (defun helm-deft-rotate-searchkeys ()
"rotate the words of the search pattern in the helm minibuffer" "Rotate the words of the search pattern in the helm minibuffer."
(interactive) (interactive)
(helm-log "Executing helm-deft-rotate-searchkeys") (helm-log "Executing helm-deft-rotate-searchkeys")
(let ((patlst (split-string helm-pattern " *"))) (let ((patlst (split-string helm-pattern " *")))
@ -98,64 +255,42 @@
(helm-update))) (helm-update)))
) )
(defun helm-deft-remove-candidate-file ()
"Remove the file under point from the list of candidates."
(interactive)
;; helm-get-selection returns current item under point
;; helm-marked-candidates returns all marked candidates or the item under point
(dolist (selection (helm-marked-candidates))
(when (string-match "\\([^:]+\\):[0-9]+:" selection)
(setq selection (match-string 1 selection)))
(setq helm-deft-file-list (delete selection helm-deft-file-list)))
(helm-unmark-all)
(helm-force-update))
(defun helm-deft-set-to-marked ()
"Set the filelist to the marked files."
(interactive)
(setq helm-deft-file-list (helm-marked-candidates))
(helm-unmark-all)
(helm-force-update))
(defvar helm-deft-map (defvar helm-deft-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map) (set-keymap-parent map helm-map)
(define-key map (kbd "C-r") 'helm-deft-rotate-searchkeys) (define-key map (kbd "C-r") 'helm-deft-rotate-searchkeys)
(define-key map (kbd "C-d") 'helm-deft-remove-candidate-file)
(define-key map (kbd "C-s") 'helm-deft-set-to-marked)
(delq nil map)) (delq nil map))
"helm keymap used for helm deft sources") "Helm keymap used for helm deft sources.")
(defun helm-deft-fname-search ()
"search all preconfigured directories for matching files and return the
filenames as a list"
(cl-assert helm-deft-extension nil "No file extension defined for helm-deft")
(cl-assert helm-deft-dir-list nil "No directories defined for helm-deft")
(cl-loop for dir in helm-deft-dir-list
do (cl-assert (file-exists-p dir) nil
(format "Directory %s does not exist. Check helm-deft-dir-list" dir))
collect (f--files dir (equal (f-ext it) helm-deft-extension) t)
into reslst
finally (return (apply #'append reslst)))
)
(defun helm-deft-build-cmd (ptrnstr filelst)
"Builds a grep command where PTRNSTR may contain multiple search patterns
separated by spaces. The first pattern will be used to retrieve matching lines.
All other patterns will be used to pre-select files with matching lines.
FILELST is a list of file paths"
(let* ((ptrnlst (remove "" (reverse (split-string ptrnstr " *"))))
(firstp (pop ptrnlst))
(filelst (mapconcat 'identity filelst " "))
(innercmd (if ptrnlst
(cl-labels ((build-inner-cmd
(ptrnlst filelst)
(let ((pattern (pop ptrnlst)))
(if ptrnlst
(format "$(grep -Elie \"%s\" %s)" pattern
(build-inner-cmd ptrnlst filelst))
(format "$(grep -Elie \"%s\" %s)"
pattern filelst)))))
(build-inner-cmd ptrnlst filelst))
filelst)))
(format "grep -EHine \"%s\" %s" firstp innercmd))
)
(defun helm-deft-fgrep-search ()
"greps for the helm search pattern in the configuration defined
file list"
(let* ((shcmd (helm-deft-build-cmd helm-pattern helm-deft-file-list)))
(helm-log "grep command: %s" shcmd)
(start-process-shell-command "helm-deft-proc" "*helm-deft-proc*"
shcmd))
)
;;;###autoload ;;;###autoload
(defun helm-deft () (defun helm-deft ()
"Preconfigured `helm' module for locating note files where either the "Preconfigured `helm' module for locating matching files.
filename or the file contents match the query string. Inspired by the Either the filename or the file contents must match the query
emacs `deft' extension" string. Inspired by the Emacs `deft' extension"
(interactive) (interactive)
(helm :sources '(helm-source-deft-fn helm-source-deft-filegrep) (helm :sources '(helm-source-deft-fn helm-source-deft-matching-files
helm-source-deft-filegrep)
:keymap helm-deft-map)) :keymap helm-deft-map))
(provide 'helm-deft) (provide 'helm-deft)

View file

@ -1,5 +1,7 @@
;;; defuns-org-crm.el --- for my custom org-based CRM ;;; defuns-org-crm.el --- for my custom org-based CRM
(require 'helm-deft)
(defun narf--helm-org (&optional directory) (defun narf--helm-org (&optional directory)
(let ((helm-deft-dir-list `(,(or directory default-directory)))) (let ((helm-deft-dir-list `(,(or directory default-directory))))
(helm-deft))) (helm-deft)))
@ -30,33 +32,7 @@
(let ((narf--helm-org-params '())) (let ((narf--helm-org-params '()))
(narf--helm-org (expand-file-name "writing/" org-directory)))) (narf--helm-org (expand-file-name "writing/" org-directory))))
;;;###autoload ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun narf/org-crm-link-contact (id)
(org-open-file (narf--org-crm-id-to-path id 'contact) t))
;;;###autoload
(defun narf/org-crm-link-project (id)
(org-open-file (narf--org-crm-id-to-path id 'project) t))
;;;###autoload
(defun narf/org-crm-link-invoice (id)
(org-open-file (narf--org-crm-id-to-path id 'invoice) t))
(defun narf--org-complete (type)
(let ((default-directory (symbol-value (intern (format "org-directory-%ss" type)))))
(let* ((file (org-iread-file-name ">>> "))
(match (s-match "^\\([0-9]+\\)[-.]" (f-filename file))))
(unless (file-exists-p file)
(message "Created %s" file)
(write-region "" nil file))
(unless match
(user-error "Invalid file ID"))
(format "%s:%s" type (cadr match)))))
;;;###autoload
(defun org-contact-complete-link () (narf--org-complete 'contact))
;;;###autoload
(defun org-project-complete-link () (narf--org-complete 'project))
;;;###autoload
(defun org-invoice-complete-link () (narf--org-complete 'invoice))
(defun narf--org-crm-assert-type (type) (defun narf--org-crm-assert-type (type)
(unless (memq type '(project contact invoice)) (unless (memq type '(project contact invoice))
@ -67,7 +43,7 @@
(let* ((prefix (let* ((prefix
(replace-regexp-in-string (replace-regexp-in-string
"/+$" "" (symbol-value (intern (format "org-directory-%ss" type))))) "/+$" "" (symbol-value (intern (format "org-directory-%ss" type)))))
(last-file (car-safe (sort (f-glob "*.org" prefix) 'string>)))) (last-file (car-safe (sort (f-glob "*.org" prefix) 'org-string>))))
(when last-file (when last-file
(let* ((old-id (narf--org-crm-path-to-id last-file type)) (let* ((old-id (narf--org-crm-path-to-id last-file type))
(new-id (format "%04X" (1+ old-id)))) (new-id (format "%04X" (1+ old-id))))
@ -91,7 +67,12 @@
(replace-regexp-in-string (replace-regexp-in-string
"/+$" "" (symbol-value (intern (format "org-directory-%ss" type)))))) "/+$" "" (symbol-value (intern (format "org-directory-%ss" type))))))
(car-safe (car-safe
(f-glob (format (if (eq type 'invoice) "*-%04X.org" "%04X*.org") (f-glob (format (cond ((eq type 'invoice)
"*-%04X.org")
((eq type 'courses)
"%s*.org")
(t
"%04X*.org"))
(string-to-number id 16)) (string-to-number id 16))
prefix)))) prefix))))

View file

@ -1,5 +1,13 @@
;;; defuns-org.el ;;; defuns-org.el
;;;###autoload
(defun narf/org-get-property (name)
(interactive)
(save-excursion
(goto-char 1)
(re-search-forward (format "^#\\+%s:[ \t]*\\([^\n]+\\)" (upcase name)) nil t)
(buffer-substring-no-properties (match-beginning 1) (match-end 1))))
;;;###autoload ;;;###autoload
(defun narf/org-open-notes () (defun narf/org-open-notes ()
(interactive) (interactive)

View file

@ -0,0 +1,45 @@
;;; macros-org.el
;;;###autoload
(defmacro define-org-link! (type directory &optional id-func)
(setq directory (f-slash directory))
(let* ((type-str (symbol-name type))
(link-sym (intern (format "narf/org-link-%s" type-str)))
(dir-var (intern (format "org-directory-%s" type-str))))
`(progn
(defvar ,dir-var ,(expand-file-name directory org-directory))
(defun ,(intern (format "narf/helm-org-%s" type-str)) ()
(interactive)
(let ((default-directory ,directory))
(helm-deft)))
(defun ,link-sym (id)
(let ((path (f-glob (format "%s*.org" id) ,directory)))
(unless path
(error "ID not found: %s" id))
(org-open-file (car path) t)))
(org-add-link-type ,type-str ',link-sym)
(defun ,(intern (format "narf/org-%s-at-pt" type-str)) ()
(interactive)
(let* ((id (or (narf/org-get-property ,type-str)
(thing-at-point 'word t)))
(path (f-glob (format "%s*.org" id) ,dir-var)))
(unless path
(user-error "Couldn't find anything with %s (%s in %s)" id path ,directory))
(org-open-file (car path) t)))
(defun ,(intern (format "org-%s-complete-link" type-str)) ()
(let* ((default-directory (f-slash ,dir-var))
(file (org-iread-file-name ">>> "))
(relpath (f-relative file ,dir-var)))
(when (and (not (file-exists-p file))
(y-or-n-p (format "Create %s?" relpath)))
(write-region "" nil file)
(message "Created %s" file))
(format "%s:%s" ,type-str ,(if id-func `(funcall ,id-func relpath) 'relpath))
)))))
(provide 'macros-org)
;;; macros-org.el ends here

View file

@ -58,7 +58,7 @@
"add-hook" "associate" "open-with" "define-repl" "add-hook" "associate" "open-with" "define-repl"
"define-builder" "narf-space-setup" "define-env-command" "define-builder" "narf-space-setup" "define-env-command"
"define-text-object" "add-yas-minor-mode" "define-text-object" "add-yas-minor-mode"
"define-company-backend")) "define-org-link!" "define-company-backend"))
"!\\)") "!\\)")
(1 font-lock-keyword-face append)))) (1 font-lock-keyword-face append))))

View file

@ -7,13 +7,13 @@
:keymap (make-sparse-keymap) ; defines evil-org-mode-map :keymap (make-sparse-keymap) ; defines evil-org-mode-map
:group 'evil-org) :group 'evil-org)
(defvar org-directory (expand-file-name "org/" narf-dropbox-dir)) (defvar org-directory (expand-file-name write-mode-dir))
(defvar org-directory-contacts (expand-file-name "work/contacts/" org-directory)) (defvar org-directory-contacts (expand-file-name "Work/Contacts/" org-directory))
(defvar org-directory-projects (expand-file-name "work/projects/" org-directory)) (defvar org-directory-projects (expand-file-name "Work/Projects/" org-directory))
(defvar org-directory-invoices (expand-file-name "work/invoices/" org-directory)) (defvar org-directory-invoices (expand-file-name "Work/Invoices/" org-directory))
(defvar org-directory-courses (expand-file-name "Courses/" org-directory))
(defvar org-default-notes-file (concat org-directory "notes.org")) (defvar org-default-notes-file (concat org-directory "/Notes.org"))
(defvar org-default-todo-file (concat org-directory "todo.org"))
(add-hook! org-load 'narf|org-init) (add-hook! org-load 'narf|org-init)
@ -21,7 +21,7 @@
(defun narf@org-vars () (defun narf@org-vars ()
(setq org-agenda-files (setq org-agenda-files
(f-entries org-directory (lambda (path) (string-suffix-p ".org" path)) t) (f-entries org-directory (lambda (path) (string-suffix-p ".org" path)))
org-archive-location (concat org-directory "/archive/%s::") org-archive-location (concat org-directory "/archive/%s::")
org-attach-directory ".attach/" org-attach-directory ".attach/"
@ -46,7 +46,7 @@
org-log-done t org-log-done t
org-agenda-window-setup 'other-window org-agenda-window-setup 'other-window
org-agenda-skip-unavailable-files t org-agenda-skip-unavailable-files t
org-startup-folded 'content org-startup-folded t
org-todo-keywords '((sequence "TODO(t)" "|" "DONE(d)") org-todo-keywords '((sequence "TODO(t)" "|" "DONE(d)")
(sequence "IDEA(i)" "NEXT(n)" "ACTIVE(a)" "WAITING(w)" "LATER(l)" "|" "CANCELLED(c)") (sequence "IDEA(i)" "NEXT(n)" "ACTIVE(a)" "WAITING(w)" "LATER(l)" "|" "CANCELLED(c)")
(sequence "UNSENT(u)" "UNPAID(U)" "|" "PAID(p)")) (sequence "UNSENT(u)" "UNPAID(U)" "|" "PAID(p)"))
@ -58,33 +58,18 @@
("@projects" . ?r)) ("@projects" . ?r))
org-capture-templates org-capture-templates
'(("t" "TODO" entry '(("c" "Changelog" entry
(file+headline org-default-todo-file "Inbox") (file+headline (concat (narf/project-root) "CHANGELOG.org") "Unreleased")
"*** TODO %? %u") "* %?")
;; TODO Select file from org files
;; ("T" "Specific TODO" entry
;; (function narf/-org-capture-choose)
;; "** TODO %?\n%i" :prepend t)
;; ("c" "Changelog" entry
;; (function narf/-org-capture-changelog)
;; "** %<%H:%M>: %? :unsorted:\n%i" :prepend t)
("j" "Journal" entry ("j" "Journal" entry
(file+datetree (concat org-directory "journal.org")) (file+datetree (concat org-directory "journal.org"))
"** %<%H:%M>: %?\n%i" :prepend t) "** %<%H:%M>: %?\n%i" :prepend t)
;; TODO Select file from notes folder
("n" "Notes" entry ("n" "Notes" entry
(file+headline org-default-notes-file "Inbox") (file+headline org-default-notes-file "Inbox")
"* %u %?\n%i" :prepend t) "* %u %?\n%i" :prepend t)
("s" "Writing Scraps" entry
(file+headline (concat org-directory "writing/scraps.org") "Unsorted")
"* %t %?\n%i" :prepend t)
;; TODO Sort word under correct header
("v" "Vocab" entry ("v" "Vocab" entry
(file+headline (concat org-directory "topics/vocab.org") "Unsorted") (file+headline (concat org-directory "topics/vocab.org") "Unsorted")
"** %i%?\n") "** %i%?\n")
@ -117,7 +102,11 @@
(defun narf@org-export () (defun narf@org-export ()
(defvar narf-org-export-directory (concat org-directory ".export")) (defvar narf-org-export-directory (concat org-directory ".export"))
(require 'ox-pandoc)
(unless (featurep 'ox-opml)
(load-library "org-opml"))
(use-package ox-pandoc)
(setq org-export-backends '(ascii html latex md opml) (setq org-export-backends '(ascii html latex md opml)
org-export-with-toc nil) org-export-with-toc nil)
@ -135,20 +124,21 @@
org-src-preserve-indentation t org-src-preserve-indentation t
org-src-tab-acts-natively t) org-src-tab-acts-natively t)
(defun narf-refresh-babel-lob () ;; (defun narf-refresh-babel-lob ()
(let ((files (f-entries org-directory (lambda (path) (f-ext? path "org")) t))) ;; (let ((files (f-entries org-directory (lambda (path) (f-ext? path "org")) t)))
(async-start ;; (async-start
`(lambda () ;; `(lambda ()
,(async-inject-variables "\\`\\(org-directory\\|load-path$\\)") ;; ,(async-inject-variables "\\`\\(org-directory\\|load-path$\\)")
(require 'org) ;; (require 'org)
(setq org-babel-library-of-babel nil) ;; (setq org-babel-library-of-babel nil)
(mapc (lambda (f) (org-babel-lob-ingest f)) (list ,@files)) ;; (mapc (lambda (f) (org-babel-lob-ingest f)) (list ,@files))
org-babel-library-of-babel) ;; org-babel-library-of-babel)
(lambda (lib) ;; (lambda (lib)
;; (persistent-soft-store 'org-babel-library lib "org") ;; ;; (persistent-soft-store 'org-babel-library lib "org")
(message "Library of babel updated!") ;; (message "Library of babel updated!")
(setq org-babel-library-of-babel lib))))) ;; (setq org-babel-library-of-babel lib)))))
(setq org-babel-library-of-babel (narf-refresh-babel-lob)) ;; (setq org-babel-library-of-babel (narf-refresh-babel-lob))
(add-hook! org-mode (add-hook! org-mode
(add-hook 'after-save-hook (add-hook 'after-save-hook
(lambda () (lambda ()
@ -163,7 +153,9 @@
'((python . t) (ruby . t) (sh . t) (js . t) (css . t) '((python . t) (ruby . t) (sh . t) (js . t) (css . t)
(plantuml . t) (emacs-lisp . t) (matlab . t) (plantuml . t) (emacs-lisp . t) (matlab . t)
(latex . t) (calc . t) (lisp . t) (lilypond . t) (latex . t) (calc . t) (lisp . t) (lilypond . t)
(http . t) (rust . t) (go . t))) (go . t)
(rust . t)))
;; (http . t)
(setq org-babel-lilypond-gen-png t) (setq org-babel-lilypond-gen-png t)
;; Ensure lilypond doesn't print out entire pages for previews ;; Ensure lilypond doesn't print out entire pages for previews
@ -207,117 +199,94 @@ will function properly."
(defun narf@org-latex () (defun narf@org-latex ()
(setq-default (setq-default
org-latex-preview-ltxpng-directory (concat narf-temp-dir "ltxpng/") org-latex-preview-ltxpng-directory (concat narf-temp-dir "ltxpng/")
org-latex-remove-logfiles t org-latex-remove-logfiles nil
org-latex-create-formula-image-program 'dvipng org-latex-create-formula-image-program 'dvipng
org-startup-with-latex-preview nil org-startup-with-latex-preview nil
org-highlight-latex-and-related '(latex) org-highlight-latex-and-related '(latex)
org-format-latex-options (plist-put org-format-latex-options :scale 1.4) org-format-latex-options (plist-put org-format-latex-options :scale 1.2)
org-latex-image-default-width nil org-latex-image-default-width nil
org-latex-packages-alist org-latex-packages-alist
'(("" "gauss" t) '(;; ("" "gauss" t)
;; ("" "physics" t) TODO Install this ;; ("" "physics" t) TODO Install this
))) )))
(defun narf@org-looks () (defun narf@org-looks ()
(setq org-image-actual-width nil (setq-default
org-startup-with-inline-images nil org-image-actual-width nil
org-startup-indented t org-startup-with-inline-images nil
org-pretty-entities t org-startup-indented t
org-pretty-entities-include-sub-superscripts t org-pretty-entities nil
org-use-sub-superscripts '{} org-pretty-entities-include-sub-superscripts t
org-fontify-whole-heading-line nil org-use-sub-superscripts '{}
org-fontify-done-headline t org-fontify-whole-heading-line nil
org-fontify-quote-and-verse-blocks t org-fontify-done-headline t
org-ellipsis 'hs-face org-fontify-quote-and-verse-blocks t
org-indent-indentation-per-level 2 org-ellipsis 'hs-face
org-cycle-separator-lines 2 org-indent-indentation-per-level 2
org-hide-emphasis-markers t org-cycle-separator-lines 2
org-hide-leading-stars t org-hide-emphasis-markers t
org-bullets-bullet-list '("" "" "" "" "" "") org-hide-leading-stars t
org-entities-user org-bullets-bullet-list '("" "" "" "" "" "")
'(("flat" "\\flat" nil "" "" "266D" "") org-entities-user
("sharp" "\\sharp" nil "" "" "266F" "")) '(("flat" "\\flat" nil "" "" "266D" "")
("sharp" "\\sharp" nil "" "" "266F" "")))
org-priority-faces
'((?A . org-todo-vhigh)
(?B . org-todo-high)
(?C . org-todo)))
(add-hook! org-mode (add-hook! org-mode
(highlight-regexp org-any-link-re 'org-link)) (highlight-regexp org-any-link-re 'org-link))
;; Restore org-block-background face (removed in official org) ;; Restore org-block-background face (removed in official org)
(defface org-block-background '((t ())) ;; (defface org-block-background '((t ())) "Face used for the source block background.")
"Face used for the source block background.") ;; (defun narf--adjoin-to-list-or-symbol (element list-or-symbol)
(defun narf--adjoin-to-list-or-symbol (element list-or-symbol) ;; (let ((list (if (not (listp list-or-symbol))
(let ((list (if (not (listp list-or-symbol)) ;; (list list-or-symbol)
(list list-or-symbol) ;; list-or-symbol)))
list-or-symbol))) ;; (require 'cl-lib)
(require 'cl-lib) ;; (cl-adjoin element list)))
(cl-adjoin element list))) ;; (set-face-attribute 'org-block-background nil :inherit
(set-face-attribute 'org-block-background nil :inherit ;; (narf--adjoin-to-list-or-symbol
(narf--adjoin-to-list-or-symbol ;; 'fixed-pitch
'fixed-pitch ;; (face-attribute 'org-block-background :inherit)))
(face-attribute 'org-block-background :inherit)))
;; Prettify symbols, blocks and TODOs ;; Prettify symbols, blocks and TODOs
(defface org-headline-todo '((t ())) "Face for todo headlines") (defface org-headline-todo '((t ())) "Face for todo headlines")
(defface org-headline-done '((t ())) "Face for todo headlines")
(defface org-todo-high '((t ())) "Face for high-priority todo") (defface org-todo-high '((t ())) "Face for high-priority todo")
(defface org-todo-vhigh '((t ())) "Face for very high-priority todo") (defface org-todo-vhigh '((t ())) "Face for very high-priority todo")
;; (defface org-whitespace '((t ())) "Face for spaces") ;; (defface org-whitespace '((t ())) "Face for spaces")
(defface org-list-bullet '((t ())) "Face for list bullets") (defface org-list-bullet '((t ())) "Face for list bullets")
(defface org-todo-checkbox '((t ())) "Face for list bullets") (defface org-todo-checkbox '((t ())) "Face for list bullets")
(font-lock-add-keywords
'org-mode `(("^ *\\(#\\+begin_src\\>\\)"
(1 (narf/show-as ?#)))
("^ *\\(#\\+end_src\\>\\)"
(1 (narf/show-as ?#)))
("^ *\\(#\\+begin_quote\\>\\)"
(1 (narf/show-as ?>)))
("^ *\\(#\\+end_quote\\>\\)"
(1 (narf/show-as ?>)))
;; Hide TODO tags (defvar narf-org-font-lock-keywords
("^\\**\\(\\* DONE\\) \\([^$\n\r]+\\)" '(("^ *\\([-+]\\|[0-9]+[).]\\)[^$\n\r]"
(1 (narf/show-as ?☑)) (1 'org-list-bullet))
(2 'org-headline-done)) ;; Crossed out finished items
("^\\**\\(\\* \\(?:TODO\\|PAID\\)\\) " ("\\* \\(?:DONE\\|PAID\\) \\([^$\n\r]+\\)"
(1 (narf/show-as ?☐))) (1 'org-headline-done))
("^ *\\(?:[-+]\\|[0-9]+[).]\\) \\[X\\] \\([^$\n\r]+\\)"
("[-+*] \\[X\\] \\([^$\n\r]+\\)" (1 'org-headline-done))))
(1 'org-headline-done)) (font-lock-add-keywords 'org-mode narf-org-font-lock-keywords))
;; Show checkbox for other todo states (but don't hide the label)
(,(concat
"\\(\\*\\) "
(regexp-opt '("IDEA" "NEXT" "ACTIVE" "WAITING" "LATER" "CANCELLED" "UNPAID" "UNSENT") t)
" ")
(1 (narf/show-as ?☐)))
("^ *\\([-+]\\|[0-9]+[).]\\)\\( \\)+[^$\n\r]"
(1 'org-list-bullet))
)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun narf|org-hook () (defun narf|org-hook ()
(evil-org-mode +1) (evil-org-mode +1)
(org-bullets-mode +1)
(org-indent-mode +1) (org-indent-mode +1)
;; (text-scale-set 1) (setq line-spacing '1)
(setq header-line-format mode-line-format
mode-line-format '("%e"))
(visual-line-mode +1)
(visual-fill-column-mode +1)
(when write-mode
(org-bullets-mode +1))
;;; OS-Specific ;;; OS-Specific
(cond (IS-MAC (narf-org-init-for-osx)) (cond (IS-MAC (narf-org-init-for-osx))
(IS-LINUX nil) (IS-LINUX nil)
(IS-WINDOWS nil)) (IS-WINDOWS nil))
;; Org-specific font. See `narf-writing-font'
(setq buffer-face-mode-face `(:family ,(symbol-name (font-get narf-writing-font :family))))
(buffer-face-mode +1)
(setq truncate-lines nil)
(setq line-spacing '2)
(defun narf|org-update-statistics-cookies () (defun narf|org-update-statistics-cookies ()
(when (file-exists-p buffer-file-name) (when (file-exists-p buffer-file-name)
(org-update-statistics-cookies t))) (org-update-statistics-cookies t)))
@ -365,9 +334,12 @@ will function properly."
(setq epa-file-encrypt-to user-mail-address) (setq epa-file-encrypt-to user-mail-address)
;; Custom links ;; Custom links
(org-add-link-type "contact" 'narf/org-crm-link-contact) (define-org-link! project "Work/Projects" 'f-no-ext)
(org-add-link-type "project" 'narf/org-crm-link-project) (define-org-link! invoice "Work/Invoices" 'f-no-ext)
(org-add-link-type "invoice" 'narf/org-crm-link-invoice) (define-org-link! contact "Work/Contacts" 'f-no-ext)
(define-org-link! dev "Personal/Dev")
(define-org-link! course "Courses"
(lambda (path) (substring path 0 (s-index-of " " path))))
(after! helm (after! helm
(mapc (lambda (r) (add-to-list 'helm-boring-file-regexp-list r)) (mapc (lambda (r) (add-to-list 'helm-boring-file-regexp-list r))
@ -411,6 +383,8 @@ will function properly."
(f-relative path (f-dirname (buffer-file-name)))) (f-relative path (f-dirname (buffer-file-name))))
(advice-add 'org-download--fullname :filter-return 'narf*org-download--fullname) (advice-add 'org-download--fullname :filter-return 'narf*org-download--fullname)
;; Let org-download also handle PDFs
;;; Auto-completion ;;; Auto-completion
(after! company (after! company
(require 'company-math) (require 'company-math)
@ -472,9 +446,8 @@ will function properly."
:v "M-`" "S+" :v "M-`" "S+"
(:leader (:leader
:n ";" 'helm-org-in-buffer-headings :n ";" 'helm-org-in-buffer-headings
:n "oa" 'narf/org-attachment-reveal :n "oa" 'narf/org-attachment-reveal)
)
(:localleader (:localleader
:n "/" 'org-sparse-tree :n "/" 'org-sparse-tree
@ -486,7 +459,7 @@ will function properly."
:nv "l" 'org-insert-link :nv "l" 'org-insert-link
:n "L" 'org-store-link :n "L" 'org-store-link
:n "x" 'narf/org-remove-link :n "x" 'narf/org-remove-link
:n "w" 'writing-mode ;; :n "w" 'writing-mode
:n "v" 'variable-pitch-mode :n "v" 'variable-pitch-mode
:n "SPC" 'narf/org-toggle-checkbox :n "SPC" 'narf/org-toggle-checkbox
:n "RET" 'org-archive-subtree :n "RET" 'org-archive-subtree
@ -558,111 +531,112 @@ will function properly."
:e "C-n" 'org-agenda-next-item :e "C-n" 'org-agenda-next-item
:e "C-p" 'org-agenda-previous-item))) :e "C-p" 'org-agenda-previous-item)))
(progn ;; Org hacks (progn ;; Org hacks
(defun org-fontify-meta-lines-and-blocks-1 (limit) (defun org-fontify-meta-lines-and-blocks-1 (limit)
"Fontify #+ lines and blocks." "Fontify #+ lines and blocks."
(let ((case-fold-search t)) (let ((case-fold-search t))
(if (re-search-forward (if (re-search-forward
"^\\([ \t]*#\\(\\(\\+[a-zA-Z]+:?\\| \\|$\\)\\(_\\([a-zA-Z]+\\)\\)?\\)[ \t]*\\(\\([^ \t\n]*\\)[ \t]*\\(.*\\)\\)\\)" "^\\([ \t]*#\\(\\(\\+[a-zA-Z]+:?\\| \\|$\\)\\(_\\([a-zA-Z]+\\)\\)?\\)[ \t]*\\(\\([^ \t\n]*\\)[ \t]*\\(.*\\)\\)\\)"
limit t) limit t)
(let ((beg (match-beginning 0)) (let ((beg (match-beginning 0))
(block-start (match-end 0)) (block-start (match-end 0))
(block-end nil) (block-end nil)
(lang (match-string 7)) (lang (match-string 7))
(beg1 (line-beginning-position 2)) (beg1 (line-beginning-position 2))
(dc1 (downcase (match-string 2))) (dc1 (downcase (match-string 2)))
(dc3 (downcase (match-string 3))) (dc3 (downcase (match-string 3)))
end end1 quoting block-type ovl) end end1 quoting block-type ovl)
(cond (cond
((and (match-end 4) (equal dc3 "+begin")) ((and (match-end 4) (equal dc3 "+begin"))
;; Truly a block ;; Truly a block
(setq block-type (downcase (match-string 5)) (setq block-type (downcase (match-string 5))
quoting (member block-type org-protecting-blocks)) quoting (member block-type org-protecting-blocks))
(when (re-search-forward (when (re-search-forward
(concat "^[ \t]*#\\+end" (match-string 4) "\\>.*") (concat "^[ \t]*#\\+end" (match-string 4) "\\>.*")
nil t) ;; on purpose, we look further than LIMIT nil t) ;; on purpose, we look further than LIMIT
(setq end (min (point-max) (match-end 0)) (setq end (min (point-max) (match-end 0))
end1 (min (point-max) (1- (match-beginning 0)))) end1 (min (point-max) (1- (match-beginning 0))))
(setq block-end (match-beginning 0)) (setq block-end (match-beginning 0))
(when quoting (when quoting
(org-remove-flyspell-overlays-in beg1 end1) (org-remove-flyspell-overlays-in beg1 end1)
(remove-text-properties beg end (remove-text-properties beg end
'(display t invisible t intangible t))) '(display t invisible t intangible t)))
(add-text-properties (add-text-properties
beg end '(font-lock-fontified t font-lock-multiline t)) beg end '(font-lock-fontified t font-lock-multiline t))
(add-text-properties beg beg1 '(face org-meta-line)) (add-text-properties beg beg1 '(face org-meta-line))
(org-remove-flyspell-overlays-in beg beg1) (org-remove-flyspell-overlays-in beg beg1)
(add-text-properties ; For end_src (add-text-properties ; For end_src
end1 (min (point-max) (1+ end)) '(face org-meta-line)) end1 (min (point-max) (1+ end)) '(face org-meta-line))
(org-remove-flyspell-overlays-in end1 end) (org-remove-flyspell-overlays-in end1 end)
(cond (cond
((and lang (not (string= lang "")) org-src-fontify-natively) ((and lang (not (string= lang "")) org-src-fontify-natively)
(org-src-font-lock-fontify-block lang block-start block-end) (org-src-font-lock-fontify-block lang block-start block-end)
;;;;;;; EDIT ;;;;;;; EDIT
;; remove old background overlays ;; remove old background overlays
(mapc (lambda (ov) (mapc (lambda (ov)
(if (eq (overlay-get ov 'face) 'org-block-background) (if (eq (overlay-get ov 'face) 'org-block-background)
(delete-overlay ov))) (delete-overlay ov)))
(overlays-at (/ (+ beg1 block-end) 2))) (overlays-at (/ (+ beg1 block-end) 2)))
;; add a background overlay ;; add a background overlay
(setq ovl (make-overlay beg1 block-end)) (setq ovl (make-overlay beg1 block-end))
(overlay-put ovl 'face 'org-block-background) (overlay-put ovl 'face 'org-block-background)
(overlay-put ovl 'evaporate t)) ; make it go away when empty (overlay-put ovl 'evaporate t)) ; make it go away when empty
;; (add-text-properties beg1 block-end '(src-block t))) ;; (add-text-properties beg1 block-end '(src-block t)))
;;;;;;; /EDIT ;;;;;;; /EDIT
(quoting (quoting
(add-text-properties beg1 (min (point-max) (1+ end1)) (add-text-properties beg1 (min (point-max) (1+ end1))
'(face org-block))) ; end of source block '(face org-block))) ; end of source block
((not org-fontify-quote-and-verse-blocks)) ((not org-fontify-quote-and-verse-blocks))
((string= block-type "quote") ((string= block-type "quote")
(add-text-properties beg1 (min (point-max) (1+ end1)) '(face org-quote))) (add-text-properties beg1 (min (point-max) (1+ end1)) '(face org-quote)))
((string= block-type "verse") ((string= block-type "verse")
(add-text-properties beg1 (min (point-max) (1+ end1)) '(face org-verse)))) (add-text-properties beg1 (min (point-max) (1+ end1)) '(face org-verse))))
(add-text-properties beg beg1 '(face org-block-begin-line)) (add-text-properties beg beg1 '(face org-block-begin-line))
(add-text-properties (min (point-max) (1+ end)) (min (point-max) (1+ end1)) (add-text-properties (min (point-max) (1+ end)) (min (point-max) (1+ end1))
'(face org-block-end-line)) '(face org-block-end-line))
t)) t))
((string-match-p ((string-match-p
(format "^\\+%s+:$" (format "^\\+%s+:$"
(regexp-opt '("title" "author" "email" "date" "address" "location" "contact" (regexp-opt '("title" "author" "email" "date" "address" "location" "contact"
"project" "country" "city" "created" "issued" "paid" "currency"))) "project" "country" "city" "created" "issued" "paid" "currency")))
dc1) dc1)
;; (member dc1 '("+title:" "+author:" "+email:" "+date:" "+address:" "+location:" "+contact:" "+project:")) ;; (member dc1 '("+title:" "+author:" "+email:" "+date:" "+address:" "+location:" "+contact:" "+project:"))
(org-remove-flyspell-overlays-in (org-remove-flyspell-overlays-in
(match-beginning 0) (match-beginning 0)
(if (equal "+title:" dc1) (match-end 2) (match-end 0))) (if (equal "+title:" dc1) (match-end 2) (match-end 0)))
(add-text-properties (add-text-properties
beg (match-end 3) beg (match-end 3)
(if (member (intern (substring dc1 1 -1)) org-hidden-keywords) (if (member (intern (substring dc1 1 -1)) org-hidden-keywords)
'(font-lock-fontified t invisible t) '(font-lock-fontified t invisible t)
'(font-lock-fontified t face org-document-info-keyword))) '(font-lock-fontified t face org-document-info-keyword)))
(add-text-properties (add-text-properties
(match-beginning 6) (min (point-max) (1+ (match-end 6))) (match-beginning 6) (min (point-max) (1+ (match-end 6)))
(if (string-equal dc1 "+title:") (if (string-equal dc1 "+title:")
'(font-lock-fontified t face org-document-title) '(font-lock-fontified t face org-document-title)
'(font-lock-fontified t face org-document-info)))) '(font-lock-fontified t face org-document-info))))
((equal dc1 "+caption:") ((equal dc1 "+caption:")
(org-remove-flyspell-overlays-in (match-end 2) (match-end 0)) (org-remove-flyspell-overlays-in (match-end 2) (match-end 0))
(remove-text-properties (match-beginning 0) (match-end 0) (remove-text-properties (match-beginning 0) (match-end 0)
'(display t invisible t intangible t)) '(display t invisible t intangible t))
(add-text-properties (match-beginning 1) (match-end 3) (add-text-properties (match-beginning 1) (match-end 3)
'(font-lock-fontified t face org-meta-line)) '(font-lock-fontified t face org-meta-line))
(add-text-properties (match-beginning 6) (+ (match-end 6) 1) (add-text-properties (match-beginning 6) (+ (match-end 6) 1)
'(font-lock-fontified t face org-block)) '(font-lock-fontified t face org-block))
t) t)
((member dc3 '(" " "")) ((member dc3 '(" " ""))
(org-remove-flyspell-overlays-in beg (match-end 0)) (org-remove-flyspell-overlays-in beg (match-end 0))
(add-text-properties (add-text-properties
beg (match-end 0) beg (match-end 0)
'(font-lock-fontified t face font-lock-comment-face))) '(font-lock-fontified t face font-lock-comment-face)))
(t ;; just any other in-buffer setting, but not indented (t ;; just any other in-buffer setting, but not indented
(org-remove-flyspell-overlays-in (match-beginning 0) (match-end 0)) (org-remove-flyspell-overlays-in (match-beginning 0) (match-end 0))
(remove-text-properties (match-beginning 0) (match-end 0) (remove-text-properties (match-beginning 0) (match-end 0)
'(display t invisible t intangible t)) '(display t invisible t intangible t))
(add-text-properties beg (match-end 0) (add-text-properties beg (match-end 0)
'(font-lock-fontified t face org-meta-line)) '(font-lock-fontified t face org-meta-line))
t)))))) t))))))
)) )
)
(provide 'module-org) (provide 'module-org)
;;; module-org.el ends here ;;; module-org.el ends here