From mboxrd@z Thu Jan 1 00:00:00 1970 From: Nicolas Goaziou Subject: Re: [RFC] The "c" Org macro Date: Mon, 08 May 2017 18:52:55 +0200 Message-ID: <87bmr35lzs.fsf@nicolasgoaziou.fr> References: <2ee94a64a94b46259b0da6e7d34675c9@HE1PR01MB1898.eurprd01.prod.exchangelabs.com> <87y3u7o3dj.fsf@t3610> <87pofjtk4b.fsf@t3610> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:43211) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1d7luB-0000ur-4n for emacs-orgmode@gnu.org; Mon, 08 May 2017 12:53:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1d7lu6-0007wO-Ie for emacs-orgmode@gnu.org; Mon, 08 May 2017 12:53:03 -0400 Received: from relay7-d.mail.gandi.net ([2001:4b98:c:538::200]:55344) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1d7lu6-0007vg-8b for emacs-orgmode@gnu.org; Mon, 08 May 2017 12:52:58 -0400 Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by relay7-d.mail.gandi.net (Postfix) with ESMTPS id 8E17FB7D for ; Mon, 8 May 2017 18:52:56 +0200 (CEST) Received: from saiph.selenimh (00004301000000000000074b.ipv6.commingeshautdebit.fr [IPv6:2a03:a0a0:0:4301::74b]) (Authenticated sender: mail@nicolasgoaziou.fr) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 46ABEA80C0 for ; Mon, 8 May 2017 18:52:56 +0200 (CEST) Received: from ngz by saiph.selenimh with local (Exim 4.89) (envelope-from ) id 1d7lu3-0007c8-Mj for emacs-orgmode@gnu.org; Mon, 08 May 2017 18:52:55 +0200 In-Reply-To: <87pofjtk4b.fsf@t3610> (Eric S. Fraga's message of "Mon, 08 May 2017 16:59:32 +0100") 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: emacs-orgmode@gnu.org --=-=-= Content-Type: text/plain Hello, Eric S Fraga writes: > On Monday, 8 May 2017 at 15:32, Dushyant Juneja wrote: >> A very useful macro indeed! >> >> One suggestion: can this also be made to support nested headings. For instance: >> * Part {{{c}}} >> ** Part {{{c}}}.{{{c}}} >> * Part {{{c}}} > > I think this is what separate counters will enable but also motivates > need to be able to reset a counter (e.g. the sub-heading one in above > example if it were to be used in the second part). Good idea. Here is an updated patch, in which one can write {{{c(sub,reset)}}} {{{c(sub, 5)}}} or even, for the default macro {{{c(,reset)}}} {{{c(, 99)}}} I find the manual entry a bit awkward. Suggestions welcome. Regards, -- Nicolas Goaziou --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=0001-org-macro-Implement-the-c-macro.patch >From 31397ffa1b0bf9795e2bc11568598af13db6c609 Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Mon, 8 May 2017 12:38:38 +0200 Subject: [PATCH] org-macro: Implement the "c" macro * lisp/org-macro.el (org-macro--counter-table): New variable. (org-macro--counter-initialize): (org-macro--counter-increment): New functions. (org-macro-initialize-templates): Use new functions. * doc/org.texi (Macro replacement): Document new macro. --- doc/org.texi | 10 ++++++++++ lisp/org-macro.el | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/doc/org.texi b/doc/org.texi index 312870f91..6072fcb78 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -10852,6 +10852,16 @@ This macro refers to the filename of the exported file, if any. This macro returns the value of property @var{PROPERTY-NAME} in current entry. If @var{SEARCH-OPTION} (@pxref{Search options}) refers to a remote entry, it will be used instead. + +@item @{@{@{c@}@}@} +@itemx @{@{@{c(@var{NAME})@}@}@} +@itemx @{@{@{c(@var{NAME},@var{RESET})@}@}@} +@cindex c, macro +@cindex counter, macro +This macro returns the number of occurrences of this macro expanded so far. +You can use more than one counter using different @var{NAME} values. If +@var{RESET} is non-empty, the specified counter is reset to the value +specified if it is a number, or 1 otherwise. @end table The surrounding brackets can be made invisible by setting diff --git a/lisp/org-macro.el b/lisp/org-macro.el index 71e917b71..afd302932 100644 --- a/lisp/org-macro.el +++ b/lisp/org-macro.el @@ -36,8 +36,11 @@ ;; Along with macros defined through #+MACRO: keyword, default ;; templates include the following hard-coded macros: -;; {{{time(format-string)}}}, {{{property(node-property)}}}, -;; {{{input-file}}} and {{{modification-time(format-string)}}}. +;; {{{time(format-string)}}}, +;; {{{property(node-property)}}}, +;; {{{input-file}}}, +;; {{{modification-time(format-string)}}}, +;; {{{c(counter,reset}}}. ;; Upon exporting, "ox.el" will also provide {{{author}}}, {{{date}}}, ;; {{{email}}} and {{{title}}} macros. @@ -129,7 +132,7 @@ function installs the following ones: \"property\", (let ((old-template (assoc (car cell) templates))) (if old-template (setcdr old-template (cdr cell)) (push cell templates)))))) - ;; Install hard-coded macros. + ;; Install "property", "time" macros. (mapc update-templates (list (cons "property" "(eval (save-excursion @@ -143,6 +146,7 @@ function installs the following ones: \"property\", l))))) (org-entry-get nil \"$1\" 'selective)))") (cons "time" "(eval (format-time-string \"$1\"))"))) + ;; Install "input-file", "modification-time" macros. (let ((visited-file (buffer-file-name (buffer-base-buffer)))) (when (and visited-file (file-exists-p visited-file)) (mapc update-templates @@ -152,6 +156,10 @@ function installs the following ones: \"property\", (prin1-to-string visited-file) (prin1-to-string (nth 5 (file-attributes visited-file))))))))) + ;; Initialize and install "c" macro. + (org-macro--counter-initialize) + (funcall update-templates + (cons "c" "(eval (org-macro--counter-increment \"$1\" \"$2\"))")) (setq org-macro-templates templates))) (defun org-macro-expand (macro templates) @@ -280,6 +288,9 @@ Return a list of arguments, as strings. This is the opposite of s nil t) "\000")) + +;;; Helper functions and variables for internal macros + (defun org-macro--vc-modified-time (file) (save-window-excursion (when (vc-backend file) @@ -304,6 +315,27 @@ Return a list of arguments, as strings. This is the opposite of (kill-buffer buf)) date)))) +(defvar org-macro--counter-table nil + "Hash table containing counter value per name.") + +(defun org-macro--counter-initialize () + "Initialize `org-macro--counter-table'." + (setq org-macro--counter-table (make-hash-table :test #'equal))) + +(defun org-macro--counter-increment (name &optional reset) + "Increment counter NAME. +NAME is a string identifying the counter. If optional argument +RESET is a non-empty string, reset the counter instead." + (if (org-string-nw-p reset) + (let ((new-value (if (string-match-p "\\`[ \t]*[0-9]+[ \t]*\\'" reset) + (string-to-number reset) + 1))) + (puthash name new-value org-macro--counter-table)) + (let ((value (gethash name org-macro--counter-table))) + (puthash name + (if (null value) 1 (1+ value)) + org-macro--counter-table)))) + (provide 'org-macro) ;;; org-macro.el ends here -- 2.12.2 --=-=-=--