From ac812470f074e40727a0ee5487f4608418ec18ea Mon Sep 17 00:00:00 2001 From: stardiviner Date: Sun, 23 Dec 2018 13:35:38 +0800 Subject: [PATCH] * lisp/org.el (org-dynamic-block-insert-dblock): New function. (org-dynamic-block-alist, org-dynamic-block-functions, org-dynamic-block-types, org-dynamic-block-define, org-dynamic-block-get-func): New variables, New functions. * lisp/org-keys.el: (org-dynamic-block-insert-dblock) New functions. (org-clock-report, org-columns-insert-dblock) Remove function keybindings. * doc/org-manual.org: Add manual for dispatch command ~org-dynamic-block-insert-dblock~. * testing/lisp/test-org-clock.el: Add test for inserting clocktable with `org-dynamic-block-insert-dblock'. --- doc/org-manual.org | 13 ++++++++++--- etc/ORG-NEWS | 13 +++++++++++++ lisp/org-clock.el | 3 +++ lisp/org-colview.el | 4 +++- lisp/org-keys.el | 6 ++---- lisp/org.el | 34 ++++++++++++++++++++++++++++++++++ testing/lisp/test-org-clock.el | 24 ++++++++++++++++++++++++ 7 files changed, 89 insertions(+), 8 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index aad190b3b..5b4a0b241 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -19926,9 +19926,16 @@ users mailing list, at mailto:emacs-orgmode@gnu.org. Org supports /dynamic blocks/ in Org documents. They are inserted with begin and end markers like any other code block, but the contents -are updated automatically by a user function. For example, {{{kbd(C-c -C-x C-r)}}} inserts a dynamic table that updates the work time (see -[[*Clocking Work Time]]). +are updated automatically by a user function. You can use dispatch +command ~org-dynamic-block-insert-dblock~, which is bound to +keybinding {{{kbd(C-c C-x x)}}} by default. + +#+kindex: C-c C-x x +#+findex: org-dynamic-block-insert-dblock +You can insert a dynamic block with ~org-dynamic-block-insert-dblock~, +which is bound to {{{kbd(C-c C-x x)}}} by default. For example, +{{{kbd(C-c C-x x c l o c k t a b l e RET)}}} inserts a table that +updates the work time (see [[*Clocking Work Time]]). Dynamic blocks can have names and function parameters. The syntax is similar to source code block specifications: diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index f9bea4b56..aab006d8e 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -40,6 +40,13 @@ arguments no longer imply a "file" result is expected. See [[git:3367ac9457]] for details. ** New features +*** Add a dispatcher command to insert dynamic blocks + +You can add dynamic block into ~org-dynamic-block-alist~ with function +~org-dynamic-block-define~. All dynamic blocks in +~org-dynamic-block-define~ can be used by +~org-dynamic-block-insert-dblock~ command. + *** Babel **** Add LaTeX output support in PlantUML *** New property =HTML_HEADLINE_CLASS= in HTML export @@ -79,6 +86,12 @@ system than the main Org document. For example: the corresponding direction by swapping with the adjacent cell. ** New functions +*** ~org-dynamic-block-insert-dblock~ + +Use default keybinding == to run command +~org-dynamic-block-insert-dblock~. It will prompt user to select +dynamic block in ~org-dynamic-block-alist~. + *** ~org-table-cell-up~ *** ~org-table-cell-down~ *** ~org-table-cell-left~ diff --git a/lisp/org-clock.el b/lisp/org-clock.el index 1ebfa0201..3beef39eb 100644 --- a/lisp/org-clock.el +++ b/lisp/org-clock.el @@ -36,6 +36,7 @@ (declare-function org-element-property "org-element" (property element)) (declare-function org-element-type "org-element" (element)) (declare-function org-table-goto-line "org-table" (n)) +(declare-function org-dynamic-block-define "org" (type &rest rest)) (defvar org-frame-title-format-backup frame-title-format) (defvar org-time-stamp-formats) @@ -2052,6 +2053,8 @@ in the buffer and update it." (start (goto-char start))) (org-update-dblock)) +(org-dynamic-block-define "clocktable" #'org-clock-report) + (defun org-day-of-week (day month year) "Returns the day of the week as an integer." (nth 6 diff --git a/lisp/org-colview.el b/lisp/org-colview.el index 507c58a6a..eb0975ed5 100644 --- a/lisp/org-colview.el +++ b/lisp/org-colview.el @@ -41,6 +41,7 @@ (declare-function org-element-property "org-element" (property element)) (declare-function org-element-restriction "org-element" (element)) (declare-function org-element-type "org-element" (element)) +(declare-function org-dynamic-block-define "org" (type &rest rest)) (defvar org-agenda-columns-add-appointments-to-effort-sum) (defvar org-agenda-columns-compute-summary-properties) @@ -1237,7 +1238,7 @@ When PRINTF is non-nil, use it to format the result." "Summarize CHECK-BOXES with a check-box cookie." (format "[%d/%d]" (cl-count-if (lambda (b) (or (equal b "[X]") - (string-match-p "\\[\\([1-9]\\)/\\1\\]" b))) + (string-match-p "\\[\\([1-9]\\)/\\1\\]" b))) check-boxes) (length check-boxes))) @@ -1537,6 +1538,7 @@ PARAMS is a property list of parameters: (id))))) (org-update-dblock)) +(org-dynamic-block-define "columnview" #'org-columns-insert-dblock) ;;; Column view in the agenda diff --git a/lisp/org-keys.el b/lisp/org-keys.el index bed2f2ad4..cd9ba1d8a 100644 --- a/lisp/org-keys.el +++ b/lisp/org-keys.el @@ -49,10 +49,8 @@ (declare-function org-clock-in "org" (&optional select start-time)) (declare-function org-clock-in-last "org" (&optional arg)) (declare-function org-clock-out "org" (&optional switch-to-state fail-quietly at-time)) -(declare-function org-clock-report "org" (&optional arg)) (declare-function org-clone-subtree-with-time-shift "org" (n &optional shift)) (declare-function org-columns "org" (&optional global columns-fmt-string)) -(declare-function org-columns-insert-dblock "org" ()) (declare-function org-comment-dwim "org" (arg)) (declare-function org-copy "org" ()) (declare-function org-copy-special "org" ()) @@ -67,6 +65,7 @@ (declare-function org-cycle "org" (&optional arg)) (declare-function org-cycle-agenda-files "org" ()) (declare-function org-date-from-calendar "org" ()) +(declare-function org-dynamic-block-insert-dblock "org" (&optional arg)) (declare-function org-dblock-update "org" (&optional arg)) (declare-function org-deadline "org" (arg1 &optional time)) (declare-function org-decrease-number-at-point "org" (&optional inc)) @@ -638,7 +637,7 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command names." (org-defkey org-mode-map (kbd "C-c C-x C-j") #'org-clock-goto) (org-defkey org-mode-map (kbd "C-c C-x C-q") #'org-clock-cancel) (org-defkey org-mode-map (kbd "C-c C-x C-d") #'org-clock-display) -(org-defkey org-mode-map (kbd "C-c C-x C-r") #'org-clock-report) +(org-defkey org-mode-map (kbd "C-c C-x x") #'org-dynamic-block-insert-dblock) (org-defkey org-mode-map (kbd "C-c C-x C-u") #'org-dblock-update) (org-defkey org-mode-map (kbd "C-c C-x C-l") #'org-toggle-latex-fragment) (org-defkey org-mode-map (kbd "C-c C-x C-v") #'org-toggle-inline-images) @@ -650,7 +649,6 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command names." (org-defkey org-mode-map (kbd "C-c C-x e") #'org-set-effort) (org-defkey org-mode-map (kbd "C-c C-x E") #'org-inc-effort) (org-defkey org-mode-map (kbd "C-c C-x o") #'org-toggle-ordered-property) -(org-defkey org-mode-map (kbd "C-c C-x i") #'org-columns-insert-dblock) (org-defkey org-mode-map (kbd "C-c C-,") #'org-insert-structure-template) (org-defkey org-mode-map (kbd "C-c C-x .") #'org-timer) (org-defkey org-mode-map (kbd "C-c C-x -") #'org-timer-item) diff --git a/lisp/org.el b/lisp/org.el index 1ee341f43..19f164426 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -11521,6 +11521,40 @@ If COMMAND is not given, use `org-update-dblock'." (unless (re-search-forward org-dblock-end-re nil t) (error "Dynamic block not terminated")))))) +(defcustom org-dynamic-block-alist nil + "An alist that defines all the Org dynamic blocks. +The key of alist is a string of the dynamic block type name. +The value of alist is a definition function to insert dynamic block." + :type '(alist :tag "dynamic block name" + :key-type string + :value-type function) + :safe #'listp + :group 'org-block + :package-version '(Org . "9.3")) + +(defun org-dynamic-block-get-func (type) + "Get TYPE dynamic block property which TYPE is a string." + (cdr (assoc type org-dynamic-block-alist))) + +(defun org-dynamic-block-types () + "Return all defined dynamic block types." + (mapcar #'car org-dynamic-block-alist)) + +(defun org-dynamic-block-define (type func) + "Define dynamic block TYPE with FUNC." + (push (cons type func) org-dynamic-block-alist)) + +(defun org-dynamic-block-insert-dblock (type) + "Insert a dynamic block of type TYPE. +When used interactively, select the dynamic block types among +defined types, per `org-dynamic-block-define'." + (interactive (list (completing-read "dynamic block: " + (org-dynamic-block-types)))) + (let ((func (org-dynamic-block-get-func type))) + (if (functionp func) + (funcall func) + (message "No such dynamic block: %s" func)))) + (defun org-dblock-update (&optional arg) "User command for updating dynamic blocks. Update the dynamic block at point. With prefix ARG, update all dynamic diff --git a/testing/lisp/test-org-clock.el b/testing/lisp/test-org-clock.el index 0d5cb5569..04ff9c06b 100644 --- a/testing/lisp/test-org-clock.el +++ b/testing/lisp/test-org-clock.el @@ -273,6 +273,30 @@ the buffer." ;;; Clocktable +(ert-deftest test-org-clock/clocktable/insert () + "Test insert clocktable dynamic block with `org-dynamic-block-insert-dblock'." + (should + (equal + "| Headline | Time | | +|--------------+--------+------| +| *Total time* | *1:00* | | +|--------------+--------+------| +| \\_ H2 | | 1:00 |" + (org-test-with-temp-text "** H1\n\n** H2\n" + (insert (org-test-clock-create-clock ". 1:00" ". 2:00")) + + (goto-line 2) + (require 'org-clock) + (org-dynamic-block-insert-dblock "clocktable") + + (goto-line 1) + (unwind-protect + (save-excursion + (when (search-forward "#+CAPTION:") (forward-line)) + (buffer-substring-no-properties + (point) (progn (search-forward "#+END:") (line-end-position 0)))) + (delete-region (point) (search-forward "#+END:\n"))))))) + (ert-deftest test-org-clock/clocktable/ranges () "Test ranges in Clock table." ;; Relative time: Previous two days. -- 2.20.1