Álvaro Ramírez
Emacs org block company completion
UPDATE: This is now available on melpa.
Back in 2015, I bound the "<" key to a hydra for quickly inserting org blocks. The idea came from Oleg's post on org-mode block templates in Hydra. The suggested binding settled in my muscle memory without much effort.
Fast forward to Febrary 2019. I replaced the hydra with org-insert-structure-template when org-try-structure-completion was removed from org mode. No biggie, as I kept the same binding to "<" and hardly noticed the change.
Since my primary use-case for easy templates is inserting source blocks, I was keen to expedite choosing the source language as well as inserting the source block itself.
Writing a small company mode completion backend fits my primary use-case pretty well.
The company backend looks as follow (Warning: Snippet needs Org v9.2).
Note: This code is not up to date. Install via melpa or see its repository.
(require 'map) (require 'org) (require 'seq) (defvar company-org-block-bol-p t "If t, detect completion when at begining of line, otherwise detect completion anywhere.") (defvar company-org--regexp "<\\([^ ]*\\)") (defun company-org-block (command &optional arg &rest ignored) "Complete org babel languages into source blocks." (interactive (list 'interactive)) (cl-case command (interactive (company-begin-backend 'company-org-block)) (prefix (when (derived-mode-p 'org-mode) (company-org-block--grab-symbol-cons))) (candidates (company-org-block--candidates arg)) (post-completion (company-org-block--expand arg)))) (defun company-org-block--candidates (prefix) "Return a list of org babel languages matching PREFIX." (seq-filter (lambda (language) (string-prefix-p prefix language)) ;; Flatten `org-babel-load-languages' and ;; `org-structure-template-alist', join, and sort. (seq-sort #'string-lessp (append (mapcar #'prin1-to-string (map-keys org-babel-load-languages)) (map-values org-structure-template-alist))))) (defun company-org-block--template-p (template) (seq-contains (map-values org-structure-template-alist) template)) (defun company-org-block--expand (insertion) "Replace INSERTION with actual source block." (delete-region (point) (- (point) (1+ ;; Include "<" in length. (length insertion)))) (if (company-org-block--template-p insertion) (company-org-block--wrap-point insertion ;; May be multiple words. ;; Take the first one. (nth 0 (split-string insertion))) (company-org-block--wrap-point (format "src %s" insertion) "src"))) (defun company-org-block--wrap-point (begin end) "Wrap point with block using BEGIN and END. For example: #+begin_BEGIN | #+end_END" (insert (format "#+begin_%s\n" begin)) (insert (make-string org-edit-src-content-indentation ?\s)) ;; Saving excursion restores point to location inside code block. (save-excursion (insert (format "\n#+end_%s" end)))) (defun company-org-block--grab-symbol-cons () "Return cons with symbol and t whenever prefix of < is found. For example: \"<e\" -> (\"e\" . t)" (when (looking-back (if company-org-block-bol-p (concat "^" company-org--regexp) company-org--regexp) (line-beginning-position)) (cons (match-string-no-properties 1) t)))
To use, add the backend enable company-mode in org-mode:
(add-to-list 'company-backends 'company-org-block) (company-mode +1)
Updates
- Removed language-specific header logic (use org-babel-default-header-args instead).
- Also completes non-source block templates from org-structure-template-alist.
- Source in my dot files.
- Removed unnecessary binding. Just add company backend as usual.
- Thanks to Takaaki Ishikawa for suggesting `org-edit-src-content-indentation'.
- Thanks to Thomas Kobber for highlighting incompatibility with older org versions.