瀏覽代碼

Add a dispatcher command for inserting dynamic blocks

* lisp/org.el (org-dynamic-block-insert-dblock,
  org-dynamic-block-alist, org-dynamic-block-functions,
  org-dynamic-block-types, org-dynamic-block-define,
  org-dynamic-block-function): New variables, New functions.

* lisp/org-keys.el (org-dynamic-block-insert-dblock): Add binding for
  the function.
(org-clock-report, org-columns-insert-dblock): Remove function
keybindings. Mark them as obsolete.

* doc/org-manual.org (Dynamic Blocks): : Add manual for dispatch
command `org-dynamic-block-insert-dblock'.

* testing/lisp/test-org-clock.el: New test.
stardiviner 6 年之前
父節點
當前提交
34b71a0ca9
共有 8 個文件被更改,包括 94 次插入8 次删除
  1. 8 3
      doc/org-manual.org
  2. 13 0
      etc/ORG-NEWS
  3. 3 0
      lisp/org-clock.el
  4. 3 1
      lisp/org-colview.el
  5. 6 0
      lisp/org-compat.el
  6. 2 4
      lisp/org-keys.el
  7. 35 0
      lisp/org.el
  8. 24 0
      testing/lisp/test-org-clock.el

+ 8 - 3
doc/org-manual.org

@@ -19975,9 +19975,14 @@ users mailing list, at mailto:emacs-orgmode@gnu.org.
 
 
 Org supports /dynamic blocks/ in Org documents.  They are inserted
 Org supports /dynamic blocks/ in Org documents.  They are inserted
 with begin and end markers like any other code block, but the contents
 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.
+
+#+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
 Dynamic blocks can have names and function parameters.  The syntax is
 similar to source code block specifications:
 similar to source code block specifications:

+ 13 - 0
etc/ORG-NEWS

@@ -40,6 +40,13 @@ arguments no longer imply a "file" result is expected.
 See [[git:3367ac9457]] for details.
 See [[git:3367ac9457]] for details.
 
 
 ** New features
 ** 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
 *** Babel
 **** Add LaTeX output support in PlantUML
 **** Add LaTeX output support in PlantUML
 *** New minor mode to display headline numbering
 *** New minor mode to display headline numbering
@@ -85,6 +92,12 @@ system than the main Org document.  For example:
 the corresponding direction by swapping with the adjacent cell.
 the corresponding direction by swapping with the adjacent cell.
 
 
 ** New functions
 ** New functions
+*** ~org-dynamic-block-insert-dblock~
+
+Use default keybinding =<C-c C-x x>= 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-up~
 *** ~org-table-cell-down~
 *** ~org-table-cell-down~
 *** ~org-table-cell-left~
 *** ~org-table-cell-left~

+ 3 - 0
lisp/org-clock.el

@@ -36,6 +36,7 @@
 (declare-function org-element-property "org-element" (property element))
 (declare-function org-element-property "org-element" (property element))
 (declare-function org-element-type "org-element" (element))
 (declare-function org-element-type "org-element" (element))
 (declare-function org-table-goto-line "org-table" (n))
 (declare-function org-table-goto-line "org-table" (n))
+(declare-function org-dynamic-block-define "org" (type func))
 
 
 (defvar org-frame-title-format-backup frame-title-format)
 (defvar org-frame-title-format-backup frame-title-format)
 (defvar org-time-stamp-formats)
 (defvar org-time-stamp-formats)
@@ -2052,6 +2053,8 @@ in the buffer and update it."
     (start (goto-char start)))
     (start (goto-char start)))
   (org-update-dblock))
   (org-update-dblock))
 
 
+(org-dynamic-block-define "clocktable" #'org-clock-report)
+
 (defun org-day-of-week (day month year)
 (defun org-day-of-week (day month year)
   "Returns the day of the week as an integer."
   "Returns the day of the week as an integer."
   (nth 6
   (nth 6

+ 3 - 1
lisp/org-colview.el

@@ -41,6 +41,7 @@
 (declare-function org-element-property "org-element" (property element))
 (declare-function org-element-property "org-element" (property element))
 (declare-function org-element-restriction "org-element" (element))
 (declare-function org-element-restriction "org-element" (element))
 (declare-function org-element-type "org-element" (element))
 (declare-function org-element-type "org-element" (element))
+(declare-function org-dynamic-block-define "org" (type func))
 
 
 (defvar org-agenda-columns-add-appointments-to-effort-sum)
 (defvar org-agenda-columns-add-appointments-to-effort-sum)
 (defvar org-agenda-columns-compute-summary-properties)
 (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."
   "Summarize CHECK-BOXES with a check-box cookie."
   (format "[%d/%d]"
   (format "[%d/%d]"
 	  (cl-count-if (lambda (b) (or (equal b "[X]")
 	  (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)
 		       check-boxes)
 	  (length check-boxes)))
 	  (length check-boxes)))
 
 
@@ -1537,6 +1538,7 @@ PARAMS is a property list of parameters:
 		     (id)))))
 		     (id)))))
   (org-update-dblock))
   (org-update-dblock))
 
 
+(org-dynamic-block-define "columnview" #'org-columns-insert-dblock)
 
 
 
 
 ;;; Column view in the agenda
 ;;; Column view in the agenda

+ 6 - 0
lisp/org-compat.el

@@ -464,6 +464,12 @@ use of this function is for the stuck project list."
 (define-obsolete-function-alias 'org-babel-strip-quotes
 (define-obsolete-function-alias 'org-babel-strip-quotes
   'org-strip-quotes "Org 9.2")
   'org-strip-quotes "Org 9.2")
 
 
+(define-obsolete-function-alias 'org-clock-report
+  'org-dynamic-block-insert-dblock "Org 9.3")
+
+(define-obsolete-function-alias 'org-columns-insert-dblock
+  'org-dynamic-block-insert-dblock "Org 9.3")
+
 ;;;; Obsolete link types
 ;;;; Obsolete link types
 
 
 (eval-after-load 'org
 (eval-after-load 'org

+ 2 - 4
lisp/org-keys.el

@@ -49,10 +49,8 @@
 (declare-function org-clock-in "org" (&optional select start-time))
 (declare-function org-clock-in "org" (&optional select start-time))
 (declare-function org-clock-in-last "org" (&optional arg))
 (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-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-clone-subtree-with-time-shift "org" (n &optional shift))
 (declare-function org-columns "org" (&optional global columns-fmt-string))
 (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-comment-dwim "org" (arg))
 (declare-function org-copy "org" ())
 (declare-function org-copy "org" ())
 (declare-function org-copy-special "org" ())
 (declare-function org-copy-special "org" ())
@@ -67,6 +65,7 @@
 (declare-function org-cycle "org" (&optional arg))
 (declare-function org-cycle "org" (&optional arg))
 (declare-function org-cycle-agenda-files "org" ())
 (declare-function org-cycle-agenda-files "org" ())
 (declare-function org-date-from-calendar "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-dblock-update "org" (&optional arg))
 (declare-function org-deadline "org" (arg1 &optional time))
 (declare-function org-deadline "org" (arg1 &optional time))
 (declare-function org-decrease-number-at-point "org" (&optional inc))
 (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-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-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-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-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-l") #'org-toggle-latex-fragment)
 (org-defkey org-mode-map (kbd "C-c C-x C-v") #'org-toggle-inline-images)
 (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-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 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 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-,") #'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)
 (org-defkey org-mode-map (kbd "C-c C-x -") #'org-timer-item)
 (org-defkey org-mode-map (kbd "C-c C-x -") #'org-timer-item)

+ 35 - 0
lisp/org.el

@@ -11518,6 +11518,41 @@ If COMMAND is not given, use `org-update-dblock'."
 	(unless (re-search-forward org-dblock-end-re nil t)
 	(unless (re-search-forward org-dblock-end-re nil t)
 	  (error "Dynamic block not terminated"))))))
 	  (error "Dynamic block not terminated"))))))
 
 
+(defcustom org-dynamic-block-alist nil
+  "Alist defining all the Org dynamic blocks.
+The key is the dynamic block type name, as a string.  The value
+is the function used to insert the dynamic block."
+  :group 'org-block
+  :package-version '(Org . "9.3")
+  :type '(alist :tag "Dynamic block name"
+		:key-type string
+                :value-type function)
+  :safe #'listp)
+
+(defun org-dynamic-block-function (type)
+  "Return function associated to a given dynamic block type.
+TYPE is the dynamic block type, as a string."
+  (cdr (assoc type org-dynamic-block-alist)))
+
+(defun org-dynamic-block-types ()
+  "List 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))))
+  (pcase (org-dynamic-block-function type)
+    (`nil (error "No such dynamic block: %S" type))
+    ((and f (pred functionp)) (funcall f))
+    (_ (error "Invalid function for dynamic block %S" type))))
+
 (defun org-dblock-update (&optional arg)
 (defun org-dblock-update (&optional arg)
   "User command for updating dynamic blocks.
   "User command for updating dynamic blocks.
 Update the dynamic block at point.  With prefix ARG, update all dynamic
 Update the dynamic block at point.  With prefix ARG, update all dynamic

+ 24 - 0
testing/lisp/test-org-clock.el

@@ -273,6 +273,30 @@ the buffer."
 
 
 ;;; Clocktable
 ;;; 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<point>"
+      (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 ()
 (ert-deftest test-org-clock/clocktable/ranges ()
   "Test ranges in Clock table."
   "Test ranges in Clock table."
   ;; Relative time: Previous two days.
   ;; Relative time: Previous two days.