From mboxrd@z Thu Jan 1 00:00:00 1970 From: stardiviner Subject: Re: [Feature Request] Add an dispatcher command (keybinding) for inserting dynamic blocks Date: Wed, 02 Jan 2019 08:12:15 +0800 Message-ID: <87h8erdijk.fsf@gmail.com> References: <871s7lvn4n.fsf@gmail.com> <3332dc93-afb1-0854-6298-06e0939aff3a@free.fr> <87wop1zcwo.fsf@nicolasgoaziou.fr> <87k1k57xt7.fsf@gmail.com> <877eg1yxy6.fsf@nicolasgoaziou.fr> <874lb4sqnk.fsf@gmail.com> <87ftuoznas.fsf@gmail.com> <874lazb5gb.fsf@nicolasgoaziou.fr> <877efvkn4d.fsf@gmail.com> <87a7kn1i1a.fsf@nicolasgoaziou.fr> Reply-To: numbchild@gmail.com Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Return-path: Received: from eggs.gnu.org ([208.118.235.92]:35206) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1geU7h-0000bu-SM for emacs-orgmode@gnu.org; Tue, 01 Jan 2019 19:11:03 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1geU7e-0006iw-Ja for emacs-orgmode@gnu.org; Tue, 01 Jan 2019 19:11:01 -0500 Received: from [61.175.244.13] (port=12939 helo=dark.localdomain) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1geU7d-0006hp-Bx for emacs-orgmode@gnu.org; Tue, 01 Jan 2019 19:10:58 -0500 In-reply-to: <87a7kn1i1a.fsf@nicolasgoaziou.fr> List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: "Emacs-orgmode" To: Nicolas Goaziou Cc: Thierry Banel , emacs-orgmode@gnu.org --=-=-= Content-Type: text/plain Nicolas Goaziou writes: > Hello, > > stardiviner writes: > >> Indeed, I mimicked `org-link-set-parameters' almost all. About this, I >> originally just lazy, now I have a thought about this alist of plist >> design, I think adding snippet-like text template string. This idea is >> still coarse. I will update this idea in my org agenda todo list. > > We are not sure this would end up as a good idea anyway. Meanwhile, > I think the alist of plists idea is a bit complicated. Ok, I changed data structure into alist now. > >> And I have another reason, I think use same structure can make user feel >> comfortable, because it is same as `org-link-set-parameters`. It's a >> good reason. > > Org uses a lot of data types in its defcustoms. I don't think there is > more comfort in sticking to a particular one. OTOH, a simpler structure > means simpler code. Ditto > > So if we have no other property than :function, I'd rather have a simple > alist (KEY . FUNCTION). If we ever need more properties, we can change > the structure, as long as it is in master, it is not set in stone. > >> About test, would you allow me to write it later? > > No problem. They do not need to be complex, tho. I added a test by insert clocktable. It's passed. > >> At last, present my updated patch. Merry Christmas. > > Thank you. > >> -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 i)}}} by default. >> + >> +#+kindex: C-c C-x i >> +#+findex: org-dynamic-block-insert-dblock >> +Select one type of dynamic block to insert. >> + >> +For example, {{{kbd(C-c C-x i c l o c k t a b l e RET)}}} inserts a >> +dynamic table that updates the work time (see [[*Clocking Work >> Time]]). > > 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 i)}}} by default. For example, > {{{kbd(C-c C-x i c l o c k t a b l e RET)}}} inserts a table that > updates the work time (see [[*Clocking Work Time]]). Copied. > >> +(org-dynamic-block-set-parameters >> + "clocktable" >> + :function 'org-clock-report) > > The function could be, e.g., > > (org-dynamic-block-define "clocktable" #'org-clock-report) Updated. > >> +(defun org-dynamic-block-get-parameter (type key) >> + "Get TYPE dynamic block property for KEY. >> +TYPE is a string and KEY is a plist keyword." >> + (plist-get >> + (cdr (assoc type org-dynamic-block-parameters)) >> + key)) > > Simply > > (cdr (assoc type org-dynamic-block-parameters)) > > if you simplify the structure. Updated. > >> +(defun org-dynamic-block-set-parameters (type &rest parameters) >> + "Set dynamic block TYPE properties to PARAMETERS. >> +PARAMETERS should be :key val pairs. >> +The key is usually is `:function', and the value is a function name symbol." >> + (let ((data (assoc type org-dynamic-block-parameters))) >> + (if data (setcdr data (org-combine-plists (cdr data) parameters)) >> + (push (cons type parameters) org-dynamic-block-parameters)))) > > Ditto. It could be > > (defun org-dynamic-block-define (type fun) > (push (cons type fun) org-dynamic-block-parameters)) Updated. > >> +(defun org-dynamic-block-types () >> + "Return a list of known dynamic block types." >> + (mapcar #'car org-dynamic-block-parameters)) >> + >> +(defun org-dynamic-block-functions () >> + "Return a list of functions that are called to insert dynamic block." >> + (cl-loop for dblock in org-dynamic-block-parameters >> + with insert-func >> + do (setq insert-func (org-dynamic-block-get-parameter (car dblock) :function)) >> + if insert-func >> + collect insert-func)) > > Is this function necessary? Updated. > >> +(defun org-dynamic-block-insert-dblock (dblock-type) >> + "Insert a dynamic block of type DBLOCK-TYPE. >> +When used interactively, select the dynamic block types among >> +defined types, per `org-dynamic-block-set-parameters'." >> + (interactive (list (completing-read "dynamic block: " >> + (mapcar #'car org-dynamic-block-parameters)))) > > (mapcar #'car ...) -> (org-dynamic-block-types) Updated. > >> + (let ((func (org-dynamic-block-get-parameter dblock-type :function))) > > See above. Updated. Regards. As always, add patch as attachment. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-lisp-org.el-org-dynamic-block-insert-dblock-New-func.patch >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 --=-=-= Content-Type: text/plain -- [ stardiviner ] I try to make every word tell the meaning what I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3 --=-=-=--