emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Merging ox-texinfo+ into ox-texinfo
@ 2021-11-09 18:01 Jonas Bernoulli
  2021-11-19 12:46 ` Nicolas Goaziou
  0 siblings, 1 reply; 21+ messages in thread
From: Jonas Bernoulli @ 2021-11-09 18:01 UTC (permalink / raw)
  To: emacs-orgmode

Hello,

In the olden days before Org's own manual was written using an org-mode
file, I started doing just that for Magit.  Because ox-texinfo.el wasn't
quite there yet I wrote an extension, ox-texinfo+.el, to fill in the
gaps.  Since then I have written seven more manuals that use my
extension.

I recently talked to Bastien about this and he encouraged to bring up
the possibility of merging ox-texinfo+.el into ox-texinfo.el.

ox-texinfo+ (https://github.com/tarsius/ox-texinfo-plus) has several
features but the one I would like to talk about now is the following.

[If you want to look at the other features now, then please use the
 "next" branch as I am in the process of trimming some of them down
 or even removing them completely.  The main feature is the same in
 the "master" and "next" branches.]

   Create `@deffn` and similar definition items by writing list
   items in Org that look similar to what they will look like in
   Info.  To enable this, add:

   #+TEXINFO_DEFFN: t

   to your Org file.  After doing that, you can create definition
   items like so:

   - Command: magit-section-show

     Show the body of the current section.

   - Function: magit-git-exit-code &rest args
   - Macro: magit-insert-section &rest args
   - Variable: magit-display-buffer-noselect
   - User Option: magit-display-buffer-function
   - Key: q, magit-mode-bury-buffer

I propose that we add this as an optional feature to ox-texinfo.el
itself.

IMO the biggest advantage of this style is that it leads to a prettier
org file, which is suitable for direct consumption by end-users.  It is
also easier to write in this style by package authors who might not want
to fully familiarize themselves with all the peculiarities of writing an
org file intended for export to texinfo.

It is possible to mix the two styles; you can use the ox-texinfo+.el
style for most or all definitions but use the additional flexibility of
ox-texinfo.el, when that is needed.

What do you think?  Might this be something that could be merged?

The reason I am bringing this up now after years of maintaining this as
an extension is that I would like to finally stop checking in both the
*.org and *.texi files into git.  [Non]GNU Elpa already supports this
and I plan to implement it for Melpa as well.  It would be much nicer if
the only additional requirement for an *elpa was to have a recent enough
Org version installed, instead of that and also ox-texinfo+.el.

     Cheers,
     Jonas


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Merging ox-texinfo+ into ox-texinfo
  2021-11-09 18:01 Merging ox-texinfo+ into ox-texinfo Jonas Bernoulli
@ 2021-11-19 12:46 ` Nicolas Goaziou
  2021-11-20 21:06   ` Jonas Bernoulli
  0 siblings, 1 reply; 21+ messages in thread
From: Nicolas Goaziou @ 2021-11-19 12:46 UTC (permalink / raw)
  To: Jonas Bernoulli; +Cc: emacs-orgmode

Hello,

Jonas Bernoulli <jonas@bernoul.li> writes:

> I recently talked to Bastien about this and he encouraged to bring up
> the possibility of merging ox-texinfo+.el into ox-texinfo.el.
>
> ox-texinfo+ (https://github.com/tarsius/ox-texinfo-plus) has several
> features but the one I would like to talk about now is the following.

[...]
>
>    Create `@deffn` and similar definition items by writing list
>    items in Org that look similar to what they will look like in
>    Info.  To enable this, add:
>
>    #+TEXINFO_DEFFN: t
>
>    to your Org file.  After doing that, you can create definition
>    items like so:
>
>    - Command: magit-section-show
>
>      Show the body of the current section.
>
>    - Function: magit-git-exit-code &rest args
>    - Macro: magit-insert-section &rest args
>    - Variable: magit-display-buffer-noselect
>    - User Option: magit-display-buffer-function
>    - Key: q, magit-mode-bury-buffer
>
> I propose that we add this as an optional feature to ox-texinfo.el
> itself.

I like the idea, thank you for suggesting it.

The chosen UI is rather odd however. I cannot think of another use of
controlling export thhough "#+keyword: boolean" syntax. Usually, we
extend the "options" keyword. It could become, for example:

  #+options: texinfo+:t

Could it be possible to use that syntax instead?

> It is possible to mix the two styles; you can use the ox-texinfo+.el
> style for most or all definitions but use the additional flexibility of
> ox-texinfo.el, when that is needed.

How is it possible? Keywords are global. How do you change value
locally?

Regards,
-- 
Nicolas Goaziou


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Merging ox-texinfo+ into ox-texinfo
  2021-11-19 12:46 ` Nicolas Goaziou
@ 2021-11-20 21:06   ` Jonas Bernoulli
  2021-11-21 12:41     ` Nicolas Goaziou
  0 siblings, 1 reply; 21+ messages in thread
From: Jonas Bernoulli @ 2021-11-20 21:06 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

Nicolas Goaziou <mail@nicolasgoaziou.fr> writes:
> I like the idea, thank you for suggesting it.

Great :D

>>    #+TEXINFO_DEFFN: t
>
> The chosen UI is rather odd however. I cannot think of another use of
> controlling export thhough "#+keyword: boolean" syntax. Usually, we
> extend the "options" keyword. It could become, for example:
>
>   #+options: texinfo+:t
>
> Could it be possible to use that syntax instead?

Of course.  I probably used the separate keyword because all the entries
for ox-texinfo's :options-alist did that too, but if that's not how this
is usually done for booleans, then I see no reason not to change it.

>> It is possible to mix the two styles; you can use the ox-texinfo+.el
>> style for most or all definitions but use the additional flexibility of
>> ox-texinfo.el, when that is needed.
>
> How is it possible? Keywords are global. How do you change value
> locally?

Well... it turned out not to be true, but I should be able to get it to
work.  The idea is that the new shorthand handling is only used if such
a shorthand is actually used by the item that is being processed.  All
other list items should effectively be treated as before, but that isn't
the case yet.  For now all non-shorthand list items are simply treated
as @item, but `org-texinfo+-item' could be changed to instead fall back
to the `org-texinfo-item's default behavior in those cases.  (It would
still have to check whether it needs to begin and/or end the "item
container" (itemize/table/...), so it is not completely trivial, but
should be doable.)

For testing purposes I have moved the relevant `ox-texinfo+.el' code
into `ox-texinfo.el', changing only how the feature has to be enabled,
and everything that worked before continues to work.  If the feature is
enabled, then my manuals are exported the same as before and with the
feature disabled org-manual.org also results in the same texi file as
before.

So I have to address the above issue and then we also have to think
about naming.  I was thinking about using the term "shorthands"; instead
of "texinfo-deffn:t" we could use "texinfo-shorthands:t".  The functions
need to be renamed too of course, but IMO simply replacing "ox-texinfo+"
with "ox-texinfo-shorthand" is quite ugly.  Do you have a suggestion for
that?  All the new functions could be placed in the "Item" section.

     Jonas


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Merging ox-texinfo+ into ox-texinfo
  2021-11-20 21:06   ` Jonas Bernoulli
@ 2021-11-21 12:41     ` Nicolas Goaziou
  2021-11-30 16:58       ` Jonas Bernoulli
  0 siblings, 1 reply; 21+ messages in thread
From: Nicolas Goaziou @ 2021-11-21 12:41 UTC (permalink / raw)
  To: Jonas Bernoulli; +Cc: emacs-orgmode

Hello,

Jonas Bernoulli <jonas@bernoul.li> writes:

> Of course.  I probably used the separate keyword because all the entries
> for ox-texinfo's :options-alist did that too, but if that's not how this
> is usually done for booleans, then I see no reason not to change it.

More precisely, there's an historical distinction between string values
and other values (symbols, numbers...). The former is set by keywords,
the latter is obtained with "options". Consequently, all the entries in
ox-texinfo's :options-alist are used to set strings.

> Well... it turned out not to be true, but I should be able to get it to
> work.  The idea is that the new shorthand handling is only used if such
> a shorthand is actually used by the item that is being processed.  All
> other list items should effectively be treated as before, but that isn't
> the case yet.  For now all non-shorthand list items are simply treated
> as @item, but `org-texinfo+-item' could be changed to instead fall back
> to the `org-texinfo-item's default behavior in those cases.  (It would
> still have to check whether it needs to begin and/or end the "item
> container" (itemize/table/...), so it is not completely trivial, but
> should be doable.)

Then I suggest to use "attr_texinfo" keyword, for example:

   #+attr_texinfo: :shorthand t
   - item...

This way, we ensure the change is local. `org-texinfo-item' already
checks :sep attribute.

In this case, there's no need to add a new keyword or extend "options".
   
> So I have to address the above issue and then we also have to think
> about naming.  I was thinking about using the term "shorthands"; instead
> of "texinfo-deffn:t" we could use "texinfo-shorthands:t".  The functions
> need to be renamed too of course, but IMO simply replacing "ox-texinfo+"
> with "ox-texinfo-shorthand" is quite ugly.  Do you have a suggestion for
> that?  All the new functions could be placed in the "Item" section.

I see no reason to change the prefix, since these functions are part of
ox-texinfo. I didn't look closely at your code, tho, so I may be wide of
the mark.

WDYT?

Regards,
-- 
Nicolas Goaziou


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Merging ox-texinfo+ into ox-texinfo
  2021-11-21 12:41     ` Nicolas Goaziou
@ 2021-11-30 16:58       ` Jonas Bernoulli
  2021-12-18 21:40         ` [PATCH 0/2] ox-texinfo: Define definition commands using description lists Jonas Bernoulli
  0 siblings, 1 reply; 21+ messages in thread
From: Jonas Bernoulli @ 2021-11-30 16:58 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: emacs-orgmode

Sorry for the delay, I got side-tracked with many other things.

Nicolas Goaziou <mail@nicolasgoaziou.fr> writes:

>>> It is possible to mix the two styles;
>>
>> Well... it turned out not to be true, but I should be able to get it
>> to work.
>
> Then I suggest to use "attr_texinfo" keyword, for example:
>
>    #+attr_texinfo: :shorthand t
>    - item...
>
> This way, we ensure the change is local. `org-texinfo-item' already
> checks :sep attribute.

I am sure I can get it to work just fine without a need for that.
It just turns out that I haven't done so yet, because I only used the
ox-texinfo+ style in manuals that use that style exclusively.  Now
that you have signaled that there is a good change that this would be
included in Org, putting in the work to use both styles in parallel is
actually justified.

But it likely will be a few weeks until I get to work because I looked
at the current implementation again and decided that it would be better
to start over and do the work using org-element instead of at the latest
possible moment when strings are being concatenated as ox-texinfo+
currently does.

> I see no reason to change the prefix, since these functions are part of
> ox-texinfo. I didn't look closely at your code, tho, so I may be wide of
> the mark.

I haven't started working on the org-element based implementation yet,
but I expect that won't actually need any new function definitions so,
the question is moot anyway.  (But just in case: I agree.)

     Cheers,
     Jonas


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 0/2] ox-texinfo: Define definition commands using description lists
  2021-11-30 16:58       ` Jonas Bernoulli
@ 2021-12-18 21:40         ` Jonas Bernoulli
  2021-12-18 21:40           ` [PATCH 1/2] ox-texinfo: Turn a description list item with "+" bullet into @itemx Jonas Bernoulli
                             ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Jonas Bernoulli @ 2021-12-18 21:40 UTC (permalink / raw)
  To: emacs-orgmode; +Cc: kyle, mail

Hello again,

  The new implementation of the proposed feature is now ready.
Unlike the old implementation it works by filtering the parse tree
(instead of doing it later by advising `org-texinfo-plain-list' and
`org-texinfo-item'), and it expects the use of description lists to
define description commands (instead of regular unordered lists).

  I have already updated the manuals of borg, epkg, forge, ghub,
magit, magit-section, transient and with-editor to this new style and
it worked very well.

  Executive summary: This adds a second, alternative style to write
(in Org files) Texinfo definition commands that closely resembles the
final Info/HMTL/PDF output instead of the intermediate Texinfo file.

  Likewise this adds a second, alternative style to group/"combine"
an @item with one or more $itemx. (See the first commit.)

  These additions are described in more detail in the manual, which I
have updated.  The other styles that are used in Org's own manual are
not affected and both styles can be used in the same manual.

     Cheers,
     Jonas


Jonas Bernoulli (2):
  ox-texinfo: Turn a description list item with "+" bullet into @itemx
  ox-texinfo: Define definition commands using description lists

 doc/org-manual.org | 133 ++++++++++++++++++++++++++++++++---
 lisp/ox-texinfo.el | 169 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 286 insertions(+), 16 deletions(-)

-- 
2.34.1



^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 1/2] ox-texinfo: Turn a description list item with "+" bullet into @itemx
  2021-12-18 21:40         ` [PATCH 0/2] ox-texinfo: Define definition commands using description lists Jonas Bernoulli
@ 2021-12-18 21:40           ` Jonas Bernoulli
  2021-12-26 21:37             ` Nicolas Goaziou
  2021-12-18 21:40           ` [PATCH 2/2] ox-texinfo: Define definition commands using description lists Jonas Bernoulli
  2022-01-05 13:30           ` [PATCH v2 0/3] " Jonas Bernoulli
  2 siblings, 1 reply; 21+ messages in thread
From: Jonas Bernoulli @ 2021-12-18 21:40 UTC (permalink / raw)
  To: emacs-orgmode; +Cc: kyle, mail

* doc/org-manual.org (Plain lists in Texinfo export): Reorder and
document new functionality.
* lisp/ox-texinfo.el (org-texinfo--filter-parse-tree)
(org-texinfo--normalize-items): New functions.
* lisp/ox-texinfo.el (org-texinfo-item): Use @itemx or @item
depending on the used bullet.
---
 doc/org-manual.org | 37 ++++++++++++++++++++++++++-----------
 lisp/ox-texinfo.el | 39 +++++++++++++++++++++++++++++++++++----
 2 files changed, 61 insertions(+), 15 deletions(-)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index b65e2f173..b8bb391c2 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -15236,6 +15236,23 @@ This paragraph is preceded by...
 :DESCRIPTION: List attributes.
 :END:
 
+#+cindex: lettered lists, in Texinfo export
+#+cindex: enum, Texinfo attribute
+The Texinfo export back-end converts unordered and ordered lists in
+the Org file using the default command =@itemize=.
+
+Ordered lists are numbered when exported to Texinfo format.  Such
+numbering obeys any counter (see [[*Plain Lists]]) in the first item of
+the list.  The =:enum= attribute also let you start the list at a
+specific number, or switch to a lettered list, as illustrated here:
+
+#+begin_example
+#+ATTR_TEXINFO: :enum A
+1. Alpha
+2. Bravo
+3. Charlie
+#+end_example
+
 #+cindex: @samp{ATTR_TEXINFO}, keyword
 #+cindex: two-column tables, in Texinfo export
 #+cindex: table-type, Texinfo attribute
@@ -15262,7 +15279,7 @@ entry in the first column of the table.
 The following example illustrates all the attributes above:
 
 #+begin_example
-,#+ATTR_TEXINFO: :table-type vtable :sep , :indic asis
+,#+attr_texinfo: :table-type vtable :sep , :indic asis
 - foo, bar :: This is the common text for variables foo and bar.
 #+end_example
 
@@ -15277,18 +15294,16 @@ This is the common text for variables foo and bar.
 @end table
 #+end_example
 
-#+cindex: lettered lists, in Texinfo export
-#+cindex: enum, Texinfo attribute
-Ordered lists are numbered when exported to Texinfo format.  Such
-numbering obeys any counter (see [[*Plain Lists]]) in the first item of
-the list.  The =:enum= attribute also let you start the list at
-a specific number, or switch to a lettered list, as illustrated here
+In description lists the used bullet is significant when exporting to
+Texinfo; when in doubt, then use =-=.  An item that uses =+= instead
+becomes a new entry in the first column of the table.  The above
+output can also be produced with:
 
 #+begin_example
-#+ATTR_TEXINFO: :enum A
-1. Alpha
-2. Bravo
-3. Charlie
+,#+attr_texinfo: :table-type vtable :indic asis
+- foo ::
++ bar ::
+  This is the common text for foo and bar.
 #+end_example
 
 *** Tables in Texinfo export
diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el
index b0125894a..35862357d 100644
--- a/lisp/ox-texinfo.el
+++ b/lisp/ox-texinfo.el
@@ -418,6 +418,11 @@ (defun org-texinfo--filter-section-blank-lines (headline _backend _info)
   "Filter controlling number of blank lines after a section."
   (replace-regexp-in-string "\n\\(?:\n[ \t]*\\)*\\'" "\n\n" headline))
 
+(defun org-texinfo--filter-parse-tree (tree backend info)
+  "Normalize headlines and items."
+  (org-texinfo--normalize-headlines tree backend info)
+  (org-texinfo--normalize-items tree info))
+
 (defun org-texinfo--normalize-headlines (tree _backend info)
   "Normalize headlines in TREE.
 
@@ -443,6 +448,29 @@ (defun org-texinfo--normalize-headlines (tree _backend info)
     info)
   tree)
 
+(defun org-texinfo--normalize-items (tree info)
+  "Normalize items in TREE.
+
+INFO is a plist used as a communication channel.
+
+Items in description lists that use the \"+\" bullet are
+converted to `@itemx'.  If another item is followed by such an
+item, then the first item should not be followed by a space,
+which this function takes care of.
+
+Return new tree."
+  (org-element-map tree 'plain-list
+    (lambda (plain-list)
+      (when (eq (org-element-property :type plain-list) 'descriptive)
+        (let ((contents (org-element-contents plain-list)))
+          (while (setq item (pop contents))
+            (let ((next-item (car contents)))
+              (when (and next-item
+                         (equal (org-element-property :bullet next-item) "+ "))
+                (org-element-put-property item :post-blank 0)))))))
+    info)
+  tree)
+
 (defun org-texinfo--find-verb-separator (s)
   "Return a character not used in string S.
 This is used to choose a separator for constructs like \\verb."
@@ -998,13 +1026,16 @@ (defun org-texinfo-item (item contents info)
 		     (let ((tag (org-export-data tag info)))
 		       (if split
 			   (split-string tag (regexp-quote split) t "[ \t\n]+")
-			 (list tag))))))
+			 (list tag)))))
+         (command (if (equal (org-element-property :bullet item) "+ ")
+                      "@itemx"
+                    "@item")))
     (format "%s\n%s"
 	    (pcase items
-	      (`nil "@item")
-	      (`(,item) (concat "@item " item))
+	      (`nil command)
+	      (`(,item) (concat command " " item))
 	      (`(,item . ,items)
-	       (concat "@item " item "\n"
+	       (concat command " " item "\n"
 		       (mapconcat (lambda (i) (concat "@itemx " i))
 				  items
 				  "\n"))))
-- 
2.34.1



^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 2/2] ox-texinfo: Define definition commands using description lists
  2021-12-18 21:40         ` [PATCH 0/2] ox-texinfo: Define definition commands using description lists Jonas Bernoulli
  2021-12-18 21:40           ` [PATCH 1/2] ox-texinfo: Turn a description list item with "+" bullet into @itemx Jonas Bernoulli
@ 2021-12-18 21:40           ` Jonas Bernoulli
  2021-12-26 21:46             ` Nicolas Goaziou
  2022-01-05 13:30           ` [PATCH v2 0/3] " Jonas Bernoulli
  2 siblings, 1 reply; 21+ messages in thread
From: Jonas Bernoulli @ 2021-12-18 21:40 UTC (permalink / raw)
  To: emacs-orgmode; +Cc: kyle, mail

* doc/org-manual.org (Plain lists in Texinfo export): Document use
of definition command prefixes in description lists.

* lisp/ox-texinfo.el (org-texinfo--definition-command-alist)
(org-texinfo--definition-command-regexp): New variables.
* lisp/ox-texinfo.el (org-texinfo--filter-parse-tree): Call
org-texinfo--separate-definitions.
* lisp/ox-texinfo.el (org-texinfo--separate-definitions)
(org-texinfo--match-definition, org-texinfo--split-definition)
(org-texinfo--split-plain-list, org-texinfo--massage-key-item):
New functions.
---
 doc/org-manual.org |  98 ++++++++++++++++++++++++++++++++-
 lisp/ox-texinfo.el | 132 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 227 insertions(+), 3 deletions(-)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index b8bb391c2..e8d777875 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -15303,7 +15303,99 @@ output can also be produced with:
 ,#+attr_texinfo: :table-type vtable :indic asis
 - foo ::
 + bar ::
-  This is the common text for foo and bar.
+  This is the common text for variables foo and bar.
+#+end_example
+
+Likewise, the Texinfo export back-end supports two approaches to
+writing Texinfo definition commands (see [[info:texinfo::Definition
+Commands]]).  One of them uses description lists and is describe below,
+the other is described in [[*Special blocks in Texinfo export]].
+
+Items in a description list in a Org file that begin with =Function:=
+or certain other prefixes are converted using Texinfo definition
+commands.  This works even if other items in the same list do not have
+such a prefix; if necessary a single description list is converted
+using multiple tables (such as =@vtable=) and definition commands
+(such as =@defun=).
+
+#+begin_example
+- Function: org-texinfo-drawer drawer contents info ::
+  Transcode a DRAWER element from Org to Texinfo.
+#+end_example
+
+#+texinfo: @noindent
+becomes
+
+#+begin_example
+@defun org-texinfo-drawer drawer contents info ::
+  Transcode a DRAWER element from Org to Texinfo.
+@end defun
+#+end_example
+
+The recognized prefixes are =Command:=, =Function:=, =Macro:=,
+=Special Form:=, =Variable:= and =User Option:=.  These are the same
+prefixes that appear in the Info file for the respective definition
+commands.  For example a =Function:= item in the Org file is converted
+to a =@defun= command in the Texinfo file, which in turn is converted
+to a definition prefixed with =-- Function:= in the Info file.
+
+As a special case the prefix =Key:= is also recognized.  No Texinfo
+definition command exists for key bindings and the output in Info
+files also lacks the =Key:= prefix.  Even so this special case is
+supported because it provides a convenient shorthand, as illustrated
+here:
+
+#+begin_example
+- Key: C-n (do-something) ::
+  This command does something.
+
+- User Option: do-something-somehow ::
+  This option controls how exactly ~do-something~ does its thing.
+#+end_example
+
+#+texinfo: @noindent
+becomes
+
+#+begin_example
+@table @asis
+@item @kbd{C-c C-c} (@code{do-something})
+@kindex C-c C-c
+@findex do-something
+This command does something.
+@end table
+
+@defopt do-something-somehow
+This option controls how exactly @code{do-something} does its thing.
+@end defopt
+#+end_example
+
+Key items don't have to specify the respective command in parenthesis
+as done above; that part is optional.
+
+You can get the same result using the alternative approach (see
+[[*Special blocks in Texinfo export]]), which is more verbose and less
+similar to the final Info/HTML/PDF output (but more similar to the
+intermediate Texinfo file):
+
+#+begin_example
+- {{{kbd(C-c C-c)}}} (~do-something~) ::
+
+  #+kindex: C-c C-c
+  #+findex: do-something
+  This command does something.
+
+,#+attr_texinfo: :options do-something-somehow
+,#+begin_defopt
+  This option controls how exactly ~do-something~ does its thing.
+,#+end_defopt
+#+end_example
+
+Regardless of which approach you use, you must define the =kbd= macro
+(see [[*Macro Replacement]]), which you can then use anywhere in the Org
+file:
+
+#+begin_example
+,#+macro: kbd (eval (let ((case-fold-search nil) (regexp (regexp-opt '("SPC" "RET" "LFD" "TAB" "BS" "ESC" "DELETE" "SHIFT" "Ctrl" "Meta" "Alt" "Cmd" "Super" "UP" "LEFT" "RIGHT" "DOWN") 'words))) (format "@@texinfo:@kbd{@@%s@@texinfo:}@@" (replace-regexp-in-string regexp "@@texinfo:@key{@@\\&@@texinfo:}@@" $1 t))))
 #+end_example
 
 *** Tables in Texinfo export
@@ -15373,6 +15465,10 @@ your king.
 :DESCRIPTION: Special block attributes.
 :END:
 
+The Texinfo export back-end supports two approaches to writing Texinfo
+definition commands.  One of them is describe here, the other in
+[[*Plain lists in Texinfo export]].
+
 #+cindex: @samp{ATTR_TEXINFO}, keyword
 
 The Texinfo export back-end converts special blocks to commands with
diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el
index 35862357d..cc9fca918 100644
--- a/lisp/ox-texinfo.el
+++ b/lisp/ox-texinfo.el
@@ -83,7 +83,7 @@ (org-export-define-backend 'texinfo
     (verse-block . org-texinfo-verse-block))
   :filters-alist
   '((:filter-headline . org-texinfo--filter-section-blank-lines)
-    (:filter-parse-tree . org-texinfo--normalize-headlines)
+    (:filter-parse-tree . org-texinfo--filter-parse-tree)
     (:filter-section . org-texinfo--filter-section-blank-lines)
     (:filter-final-output . org-texinfo--untabify))
   :menu-entry
@@ -407,6 +407,23 @@ (defconst org-texinfo-inline-image-rules
 	      (regexp-opt '("eps" "pdf" "png" "jpg" "jpeg" "gif" "svg"))))
   "Rules characterizing image files that can be inlined.")
 
+(defconst org-texinfo--definition-command-alist
+  '(("deffn Command" . "Command")
+    ("defun" . "Function")
+    ("defmac" . "Macro")
+    ("defspec" . "Special Form")
+    ("defvar" . "Variable")
+    ("defopt" . "User Option")
+    (nil . "Key"))
+  "Alist mapping Texinfo definition commands to output in Info files.")
+
+(defconst org-texinfo--definition-command-regexp
+  (format "\\`%s: \\(.+\\)"
+          (regexp-opt
+           (delq nil (mapcar #'cdr org-texinfo--definition-command-alist))
+           1))
+  "Regexp used to match definition commands in descriptive lists.")
+
 \f
 ;;; Internal Functions
 
@@ -421,7 +438,8 @@ (defun org-texinfo--filter-section-blank-lines (headline _backend _info)
 (defun org-texinfo--filter-parse-tree (tree backend info)
   "Normalize headlines and items."
   (org-texinfo--normalize-headlines tree backend info)
-  (org-texinfo--normalize-items tree info))
+  (org-texinfo--normalize-items tree info)
+  (org-texinfo--separate-definitions tree backend info))
 
 (defun org-texinfo--normalize-headlines (tree _backend info)
   "Normalize headlines in TREE.
@@ -598,6 +616,116 @@ (defun org-texinfo--sectioning-structure (info)
       (`(,_ ,_ . ,sections) sections)
       (_ (user-error "Unknown Texinfo class: %S" class)))))
 
+(defun org-texinfo--separate-definitions (tree _backend info)
+  "Split up descriptive lists that contain Texinfo definition commands."
+  (org-element-map tree 'plain-list
+    (lambda (plain-list)
+      (when (eq (org-element-property :type plain-list) 'descriptive)
+        (let ((contents (org-element-contents plain-list))
+              item items)
+          (while (setq item (pop contents))
+            (pcase-let ((`(,cmd . ,args) (org-texinfo--match-definition item)))
+              (cond
+               (cmd
+                (when items
+                  (org-texinfo--split-plain-list plain-list (nreverse items))
+                  (setq items nil))
+                (org-texinfo--split-definition plain-list item cmd args))
+               (t
+                (when args
+                  (org-texinfo--massage-key-item plain-list item args))
+                (push item items)))))
+          (unless (org-element-contents plain-list)
+            (org-element-extract-element plain-list)))))
+    info)
+  tree)
+
+(defun org-texinfo--match-definition (item)
+  "Return a cons-cell if ITEM specifies a Texinfo definition command.
+The car is the command and the cdr is its arguments."
+  (let ((tag (car-safe (org-element-property :tag item))))
+    (and tag
+         (stringp tag)
+         (string-match org-texinfo--definition-command-regexp tag)
+         (pcase-let*
+             ((cmd (car (rassoc (match-string-no-properties 1 tag)
+                                 org-texinfo--definition-command-alist)))
+              (`(,cmd ,category)
+               (and cmd (save-match-data (split-string cmd " "))))
+              (args (match-string-no-properties 2 tag)))
+           (cons cmd (if category (concat category " " args) args))))))
+
+(defun org-texinfo--split-definition (plain-list item cmd args)
+  "Insert a definition command before list PLAIN-LIST.
+Replace list item ITEM with a special-block that inherits the
+contents of ITEM and whose type and Texinfo attributes are
+specified by CMD and ARGS."
+  (let ((contents (org-element-contents item)))
+    (org-element-insert-before
+     (apply #'org-element-create 'special-block
+            (list :type cmd
+                  :attr_texinfo (list (format ":options %s" args))
+                  :post-blank (if contents 1 0))
+            (mapc #'org-element-extract-element contents))
+     plain-list))
+  (org-element-extract-element item))
+
+(defun org-texinfo--split-plain-list (plain-list items)
+  "Insert a new plain list before the plain list PLAIN-LIST.
+Remove ITEMS from PLAIN-LIST and use them as the contents of the
+new plain list."
+  (org-element-insert-before
+   (apply #'org-element-create 'plain-list
+          (list :type 'descriptive :post-blank 1)
+          (mapc #'org-element-extract-element items))
+   plain-list))
+
+(defun org-texinfo--massage-key-item (plain-list item args)
+  "In PLAIN-LIST modify ITEM based on ARGS.
+Reformat ITEM's tag property and add findex and kindex entries to
+its content.  If the bullet is \"+\" then use \"@itemx\" and deal with
+data from preceeding siblings that use such a bullet."
+  (let (key cmd)
+    (if (string-match " +(\\([^()]+\\)) *\\'" args)
+        (setq key (substring args 0 (match-beginning 0))
+              cmd (match-string 1 args))
+      (setq key args))
+    (org-element-put-property
+     item :tag
+     (nconc (if (assoc "kbd" org-macro-templates)
+                (let ((templates org-macro-templates))
+                  (with-temp-buffer
+                    (insert (format "{{{kbd(%s)}}}" key))
+                    (org-macro-replace-all templates)
+                    (let ((tags (car (org-element-map (org-element-parse-buffer)
+		                         'paragraph #'org-element-contents t))))
+	              (dolist (tag tags)
+	                (org-element-put-property tag :parent tags))
+	              tags)))
+              `((code (:value ,key :post-blank 0))))
+            (and cmd `(" (" (code (:value ,cmd :post-blank 0)) ")"))))
+    (let ((findex (org-element-property :findex item))
+          (kindex (org-element-property :kindex item))
+          (next-item (cadr (memq item (org-element-contents plain-list))))
+          (mx (string-prefix-p "M-x " key)))
+      (when (and (not cmd) mx)
+        (setq cmd (substring key 4)))
+      (when (and cmd (not (member cmd findex)))
+        (setq findex (nconc findex (list cmd))))
+      (unless mx
+        (setq kindex (nconc kindex (list key))))
+      (if (and next-item
+               (equal (org-element-property :bullet next-item) "+ "))
+          (progn (org-element-put-property next-item :findex findex)
+                 (org-element-put-property next-item :kindex kindex)
+                 (org-element-put-property item :findex nil)
+                 (org-element-put-property item :kindex nil))
+        (org-element-set-contents
+         item (nconc
+               (mapcar (lambda (key) `(keyword (:key "KINDEX" :value ,key))) kindex)
+               (mapcar (lambda (cmd) `(keyword (:key "FINDEX" :value ,cmd))) findex)
+               (org-element-contents item)))))))
+
 ;;; Template
 
 (defun org-texinfo-template (contents info)
-- 
2.34.1



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] ox-texinfo: Turn a description list item with "+" bullet into @itemx
  2021-12-18 21:40           ` [PATCH 1/2] ox-texinfo: Turn a description list item with "+" bullet into @itemx Jonas Bernoulli
@ 2021-12-26 21:37             ` Nicolas Goaziou
  2021-12-27 18:05               ` Jonas Bernoulli
  0 siblings, 1 reply; 21+ messages in thread
From: Nicolas Goaziou @ 2021-12-26 21:37 UTC (permalink / raw)
  To: Jonas Bernoulli; +Cc: kyle, emacs-orgmode

Hello,

Thanks. Some comments follow.

Jonas Bernoulli <jonas@bernoul.li> writes:

> +In description lists the used bullet is significant when exporting to
> +Texinfo; when in doubt, then use =-=.  An item that uses =+= instead
> +becomes a new entry in the first column of the table.  The above
> +output can also be produced with:
>  
>  #+begin_example
> -#+ATTR_TEXINFO: :enum A
> -1. Alpha
> -2. Bravo
> -3. Charlie
> +,#+attr_texinfo: :table-type vtable :indic asis
> +- foo ::
> ++ bar ::
> +  This is the common text for foo and bar.
>  #+end_example

The above is fragile, because pressing <C-c C-c> on an item will
"repair" the bullets. Therefore, you cannot support mixed bullets in the
same list.

>  *** Tables in Texinfo export
> diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el
> index b0125894a..35862357d 100644
> --- a/lisp/ox-texinfo.el
> +++ b/lisp/ox-texinfo.el
> @@ -418,6 +418,11 @@ (defun org-texinfo--filter-section-blank-lines (headline _backend _info)
>    "Filter controlling number of blank lines after a section."
>    (replace-regexp-in-string "\n\\(?:\n[ \t]*\\)*\\'" "\n\n" headline))
>  
> +(defun org-texinfo--filter-parse-tree (tree backend info)
> +  "Normalize headlines and items."
> +  (org-texinfo--normalize-headlines tree backend info)
> +  (org-texinfo--normalize-items tree info))

Could you expound the docstring? Arguments are missing, and "normalize"
is vague.

> +  (org-element-map tree 'plain-list
> +    (lambda (plain-list)
> +      (when (eq (org-element-property :type plain-list) 'descriptive)
> +        (let ((contents (org-element-contents plain-list)))
> +          (while (setq item (pop contents))
> +            (let ((next-item (car contents)))
> +              (when (and next-item
> +                         (equal (org-element-property :bullet next-item) "+ "))

The above will fail if `org-list-two-spaces-after-bullet-regexp' is
non-nil. You should compare the trimmed bullet with "+".

Anyhow, relying on mixed bullets is not great…

Regards,
-- 
Nicolas Goaziou


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/2] ox-texinfo: Define definition commands using description lists
  2021-12-18 21:40           ` [PATCH 2/2] ox-texinfo: Define definition commands using description lists Jonas Bernoulli
@ 2021-12-26 21:46             ` Nicolas Goaziou
  2021-12-27 18:05               ` Jonas Bernoulli
  0 siblings, 1 reply; 21+ messages in thread
From: Nicolas Goaziou @ 2021-12-26 21:46 UTC (permalink / raw)
  To: Jonas Bernoulli; +Cc: kyle, emacs-orgmode

Hello,

Thanks.

Jonas Bernoulli <jonas@bernoul.li> writes:

> +#+begin_example
> +- Key: C-n (do-something) ::
> +  This command does something.
> +
> +- User Option: do-something-somehow ::
> +  This option controls how exactly ~do-something~ does its thing.
> +#+end_example
> +
> +#+texinfo: @noindent
> +becomes
> +
> +#+begin_example
> +@table @asis
> +@item @kbd{C-c C-c} (@code{do-something})
> +@kindex C-c C-c
> +@findex do-something
> +This command does something.
> +@end table

There's a mismatch between the keys.

> +Key items don't have to specify the respective command in parenthesis
> +as done above; that part is optional.

Simply put:

Command in parenthesis, as done above, is optional.

> +Regardless of which approach you use, you must define the =kbd= macro
> +(see [[*Macro Replacement]]), which you can then use anywhere in the Org
> +file:
> +
> +#+begin_example
> +,#+macro: kbd (eval (let ((case-fold-search nil) (regexp (regexp-opt '("SPC" "RET" "LFD" "TAB" "BS" "ESC" "DELETE" "SHIFT" "Ctrl" "Meta" "Alt" "Cmd" "Super" "UP" "LEFT" "RIGHT" "DOWN") 'words))) (format "@@texinfo:@kbd{@@%s@@texinfo:}@@" (replace-regexp-in-string regexp "@@texinfo:@key{@@\\&@@texinfo:}@@" $1 t))))
>  #+end_example

Ouch. I don't think we should expect users to define this in order to
use the feature being implemented. IOW, it should work out of the box.

I think the functions responsible for generating the Texinfo code should
handle this without relying on the macro. Of course, if that part is
factored out, the macro might, in turn, make use of it.

> +(defconst org-texinfo--definition-command-regexp
> +  (format "\\`%s: \\(.+\\)"
> +          (regexp-opt
> +           (delq nil (mapcar #'cdr org-texinfo--definition-command-alist))
> +           1))

What is 1 meaning here? Do you mean t?


> +(defun org-texinfo--separate-definitions (tree _backend info)
> +  "Split up descriptive lists that contain Texinfo definition
> commands."

You need to document the arguments.
> +  (org-element-map tree 'plain-list
> +    (lambda (plain-list)
> +      (when (eq (org-element-property :type plain-list) 'descriptive)
> +        (let ((contents (org-element-contents plain-list))
> +              item items)

Nitpick: (items nil)

> +          (while (setq item (pop contents))

nitpick: Use dolist.

> +            (pcase-let ((`(,cmd . ,args) (org-texinfo--match-definition item)))
> +              (cond
> +               (cmd
> +                (when items
> +                  (org-texinfo--split-plain-list plain-list (nreverse items))
> +                  (setq items nil))
> +                (org-texinfo--split-definition plain-list item cmd args))
> +               (t
> +                (when args
> +                  (org-texinfo--massage-key-item plain-list item args))
> +                (push item items)))))
> +          (unless (org-element-contents plain-list)
> +            (org-element-extract-element plain-list)))))
> +    info)
> +  tree)
> +
> +(defun org-texinfo--match-definition (item)
> +  "Return a cons-cell if ITEM specifies a Texinfo definition command.
> +The car is the command and the cdr is its arguments."
> +  (let ((tag (car-safe (org-element-property :tag item))))
> +    (and tag
> +         (stringp tag)
> +         (string-match org-texinfo--definition-command-regexp tag)
> +         (pcase-let*
> +             ((cmd (car (rassoc (match-string-no-properties 1 tag)
> +                                 org-texinfo--definition-command-alist)))
> +              (`(,cmd ,category)
> +               (and cmd (save-match-data (split-string cmd " "))))
> +              (args (match-string-no-properties 2 tag)))
> +           (cons cmd (if category (concat category " " args) args))))))
> +
> +(defun org-texinfo--split-definition (plain-list item cmd args)
> +  "Insert a definition command before list PLAIN-LIST.
> +Replace list item ITEM with a special-block that inherits the
> +contents of ITEM and whose type and Texinfo attributes are
> +specified by CMD and ARGS."
> +  (let ((contents (org-element-contents item)))
> +    (org-element-insert-before
> +     (apply #'org-element-create 'special-block
> +            (list :type cmd
> +                  :attr_texinfo (list (format ":options %s" args))
> +                  :post-blank (if contents 1 0))
> +            (mapc #'org-element-extract-element contents))
> +     plain-list))
> +  (org-element-extract-element item))
> +
> +(defun org-texinfo--split-plain-list (plain-list items)
> +  "Insert a new plain list before the plain list PLAIN-LIST.
> +Remove ITEMS from PLAIN-LIST and use them as the contents of the
> +new plain list."
> +  (org-element-insert-before
> +   (apply #'org-element-create 'plain-list
> +          (list :type 'descriptive :post-blank 1)
> +          (mapc #'org-element-extract-element items))
> +   plain-list))
> +
> +(defun org-texinfo--massage-key-item (plain-list item args)
> +  "In PLAIN-LIST modify ITEM based on ARGS.
> +Reformat ITEM's tag property and add findex and kindex entries to
> +its content.  If the bullet is \"+\" then use \"@itemx\" and deal with
> +data from preceeding siblings that use such a bullet."
> +  (let (key cmd)
> +    (if (string-match " +(\\([^()]+\\)) *\\'" args)

Could you use `rx' here?

> +        (setq key (substring args 0 (match-beginning 0))
> +              cmd (match-string 1 args))
> +      (setq key args))
> +    (org-element-put-property
> +     item :tag
> +     (nconc (if (assoc "kbd" org-macro-templates)
> +                (let ((templates org-macro-templates))
> +                  (with-temp-buffer
> +                    (insert (format "{{{kbd(%s)}}}" key))

Here, there could be a function building the key chord, and you could
wrap the result into a raw string (see `org-export-raw-string').

Regards,
-- 
Nicolas Goaziou


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] ox-texinfo: Turn a description list item with "+" bullet into @itemx
  2021-12-26 21:37             ` Nicolas Goaziou
@ 2021-12-27 18:05               ` Jonas Bernoulli
  2021-12-30  9:40                 ` Nicolas Goaziou
  0 siblings, 1 reply; 21+ messages in thread
From: Jonas Bernoulli @ 2021-12-27 18:05 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: kyle, emacs-orgmode

Nicolas Goaziou <mail@nicolasgoaziou.fr> writes:

> Hello,
>
> Thanks. Some comments follow.

Thanks for the review!

> Jonas Bernoulli <jonas@bernoul.li> writes:
>
>> +In description lists the used bullet is significant when exporting to
>> +Texinfo; when in doubt, then use =-=.  An item that uses =+= instead
>> +becomes a new entry in the first column of the table.  The above
>> +output can also be produced with:
>>  
>>  #+begin_example
>> -#+ATTR_TEXINFO: :enum A
>> -1. Alpha
>> -2. Bravo
>> -3. Charlie
>> +,#+attr_texinfo: :table-type vtable :indic asis
>> +- foo ::
>> ++ bar ::
>> +  This is the common text for foo and bar.
>>  #+end_example
>
> The above is fragile, because pressing <C-c C-c> on an item will
> "repair" the bullets. Therefore, you cannot support mixed bullets in the
> same list.

The alternative also isn't great (see below).

I vaguely remember having run into this feature before when using Org to
record a pros and cons list.  As a maintainer I don't like this question
but; could this feature be made optional?  (Of course one could use tags
to indicate whether an item is a pro or cons, but for such a simple use-
case that seems more work than necessary and less immediately obvious.)

>>  *** Tables in Texinfo export
>> diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el
>> index b0125894a..35862357d 100644
>> --- a/lisp/ox-texinfo.el
>> +++ b/lisp/ox-texinfo.el
>> @@ -418,6 +418,11 @@ (defun org-texinfo--filter-section-blank-lines (headline _backend _info)
>>    "Filter controlling number of blank lines after a section."
>>    (replace-regexp-in-string "\n\\(?:\n[ \t]*\\)*\\'" "\n\n" headline))
>>  
>> +(defun org-texinfo--filter-parse-tree (tree backend info)
>> +  "Normalize headlines and items."
>> +  (org-texinfo--normalize-headlines tree backend info)
>> +  (org-texinfo--normalize-items tree info))
>
> Could you expound the docstring? Arguments are missing, and "normalize"
> is vague.

This bothered me a bit too when writing it but at the same time
it seemed like overkill to replicate the docstrings of the called
functions.  How do you feel about using a hook instead?

(defvar org-texinfo--filter-parse-tree-functions
  '(org-texinfo--normalize-headlines
    org-texinfo--normalize-items)
  "List of functions the `texinfo' back-end applies to the parsed tree.
Each filter is called with three arguments: the parse tree, as
returned by `org-element-parse-buffer', the back-end, as
a symbol, and the communication channel, as a plist.  It must
return the modified parse tree to transcode.")

Do you prefer to add the hook functions as done above or should each one
be added individually using add-hook?

>> +  (org-element-map tree 'plain-list
>> +    (lambda (plain-list)
>> +      (when (eq (org-element-property :type plain-list) 'descriptive)
>> +        (let ((contents (org-element-contents plain-list)))
>> +          (while (setq item (pop contents))
>> +            (let ((next-item (car contents)))
>> +              (when (and next-item
>> +                         (equal (org-element-property :bullet next-item) "+ "))
>
> The above will fail if `org-list-two-spaces-after-bullet-regexp' is
> non-nil. You should compare the trimmed bullet with "+".

Done.  Is this okay?:

              (when (and next-item
                         (string-prefix-p
                          "+"
                          (org-element-property :bullet next-item)))

Or should the line-breaks go elsewhere?

> Anyhow, relying on mixed bullets is not great…

The alternative isn't great either.

For example:

- Key: C-c C-w (forge-browse-TYPE) ::
+ Key: C-c C-w (forge-browse-dwim) ::
+ Key: N b I (forge-browse-issues) ::
+ Key: N b P (forge-browse-pullreqs) ::
+ Key: N b t (forge-browse-topic) ::
+ Key: N b i (forge-browse-issue) ::
+ Key: N b p (forge-browse-pullreq) ::

  These commands visit the topic, issue(s), pull-request(s), post,
  branch, commit, or remote at point in a browser. ...

vs.

- Key: C-c C-w (forge-browse-TYPE), C-c C-w (forge-browse-dwim), N b I (forge-browse-issues), N b P (forge-browse-pullreqs), N b t (forge-browse-topic), N b i (forge-browse-issue), N b p (forge-browse-pullreq) ::

  These commands visit the topic, issue(s), pull-request(s), post,
  branch, commit, or remote at point in a browser. ...

I am sure I am gonna make mistakes when using the latter approach.

     Cheers,
     Jonas


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/2] ox-texinfo: Define definition commands using description lists
  2021-12-26 21:46             ` Nicolas Goaziou
@ 2021-12-27 18:05               ` Jonas Bernoulli
  2021-12-30  0:57                 ` Nicolas Goaziou
  0 siblings, 1 reply; 21+ messages in thread
From: Jonas Bernoulli @ 2021-12-27 18:05 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: kyle, emacs-orgmode

Nicolas Goaziou <mail@nicolasgoaziou.fr> writes:

> There's a mismatch between the keys.

Fixed.

> Simply put:
>
> Command in parenthesis, as done above, is optional.

Done.

>> +Regardless of which approach you use, you must define the =kbd= macro
>> +(see [[*Macro Replacement]]), which you can then use anywhere in the Org
>> +file:
>> +
>> +#+begin_example
>> +,#+macro: kbd (eval (let ((case-fold-search nil) (regexp (regexp-opt '("SPC" "RET" "LFD" "TAB" "BS" "ESC" "DELETE" "SHIFT" "Ctrl" "Meta" "Alt" "Cmd" "Super" "UP" "LEFT" "RIGHT" "DOWN") 'words))) (format "@@texinfo:@kbd{@@%s@@texinfo:}@@" (replace-regexp-in-string regexp "@@texinfo:@key{@@\\&@@texinfo:}@@" $1 t))))
>>  #+end_example
>
> Ouch. I don't think we should expect users to define this in order to
> use the feature being implemented. IOW, it should work out of the box.

Luckily that's already how it works; I just chose to not document the
fallback (done that now).  If the macro is not available, then @code{}
is used instead.

> I think the functions responsible for generating the Texinfo code should
> handle this without relying on the macro.

I tried but could not get it to work that way.  Whatever I tried
ox-texinfo insisted on breaking it by adding quotes.

I didn't go as far as to try injecting export-snippet elements into the
tree because without using org-macro-replace-all it seemed painful to do
that.  But on second thought...

Would it be okay to represent e.g. "C-c SPC" as:

   (export-snippet
    (:back-end "texinfo" :value "@kbd{C-c @key{SPC}}" :post-blank 0 :parent #2))

instead of the more painful to construct:

   (export-snippet
    (:back-end "texinfo" :value "@kbd{" :begin 317 :end 334 :post-blank 0 :parent #2))
   #("C-c " 0 4
     (:parent #2))
   (export-snippet
    (:back-end "texinfo" :value "@key{" :begin 338 :end 355 :post-blank 0 :parent #2))
   #("SPC" 0 3
     (:parent #2))
   (export-snippet
    (:back-end "texinfo" :value "}" :begin 358 :end 371 :post-blank 0 :parent #2))
   (export-snippet
    (:back-end "texinfo" :value "}" :begin 371 :end 384 :post-blank 0 :parent #2))

> Of course, if that part is
> factored out, the macro might, in turn, make use of it.

>> +(defconst org-texinfo--definition-command-regexp
>> +  (format "\\`%s: \\(.+\\)"
>> +          (regexp-opt
>> +           (delq nil (mapcar #'cdr org-texinfo--definition-command-alist))
>> +           1))
>
> What is 1 meaning here? Do you mean t?

Yes. Done.

>> +(defun org-texinfo--separate-definitions (tree _backend info)
>> +  "Split up descriptive lists that contain Texinfo definition
>> commands."
>
> You need to document the arguments.
>> +  (org-element-map tree 'plain-list
>> +    (lambda (plain-list)
>> +      (when (eq (org-element-property :type plain-list) 'descriptive)
>> +        (let ((contents (org-element-contents plain-list))
>> +              item items)
>
> Nitpick: (items nil)

Done.

>> +          (while (setq item (pop contents))
>
> nitpick: Use dolist.

Err, that's what I would usually do.  Not sure why not here.

Done.

>> +    (if (string-match " +(\\([^()]+\\)) *\\'" args)
>
> Could you use `rx' here?

Done.

(Not a fan personally.  IMO rx is less readable than a plain old
regexp, though that's probably just because I never took the time
to retrain myself.)

>> +        (setq key (substring args 0 (match-beginning 0))
>> +              cmd (match-string 1 args))
>> +      (setq key args))
>> +    (org-element-put-property
>> +     item :tag
>> +     (nconc (if (assoc "kbd" org-macro-templates)
>> +                (let ((templates org-macro-templates))
>> +                  (with-temp-buffer
>> +                    (insert (format "{{{kbd(%s)}}}" key))
>
> Here, there could be a function building the key chord, and you could
> wrap the result into a raw string (see `org-export-raw-string').

I think that is one of the things I tried that ox-texinfo insisted on
quoting anyway.  I might misremember, so I will have another look.
Above I suggested using an `export-snippet' element (instead of `raw');
to me that seems appropriate too.

     Cheers,
     Jonas


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/2] ox-texinfo: Define definition commands using description lists
  2021-12-27 18:05               ` Jonas Bernoulli
@ 2021-12-30  0:57                 ` Nicolas Goaziou
  2022-01-05 13:16                   ` Jonas Bernoulli
  0 siblings, 1 reply; 21+ messages in thread
From: Nicolas Goaziou @ 2021-12-30  0:57 UTC (permalink / raw)
  To: Jonas Bernoulli; +Cc: kyle, emacs-orgmode

Hello,

Jonas Bernoulli <jonas@bernoul.li> writes:

> Would it be okay to represent e.g. "C-c SPC" as:
>
>    (export-snippet
>     (:back-end "texinfo" :value "@kbd{C-c @key{SPC}}" :post-blank 0 :parent #2))

Just use (org-export-raw-string "@kbd{C-c @key{SPC}}") instead.

> I think that is one of the things I tried that ox-texinfo insisted on
> quoting anyway.  I might misremember, so I will have another look.

`org-export-raw-string' is a recent addition in Org.

> Above I suggested using an `export-snippet' element (instead of `raw');
> to me that seems appropriate too.

I think that's abusing export snippets. They are more user-oriented,
e.g. filters can apply to them.

Note you can write (org-export-raw-string (some-public-function "C-c
SPC")) where (some-public-function "C-c SPC") => "@kbd{C-c @key{SPC}}",
as done currently by the "kbd" macro.

Regards,
-- 
Nicolas Goaziou


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] ox-texinfo: Turn a description list item with "+" bullet into @itemx
  2021-12-27 18:05               ` Jonas Bernoulli
@ 2021-12-30  9:40                 ` Nicolas Goaziou
  2022-01-05 13:12                   ` Jonas Bernoulli
  0 siblings, 1 reply; 21+ messages in thread
From: Nicolas Goaziou @ 2021-12-30  9:40 UTC (permalink / raw)
  To: Jonas Bernoulli; +Cc: kyle, emacs-orgmode

Hello,

Jonas Bernoulli <jonas@bernoul.li> writes:

> I vaguely remember having run into this feature before when using Org to
> record a pros and cons list.  As a maintainer I don't like this question
> but; could this feature be made optional?  (Of course one could use tags
> to indicate whether an item is a pro or cons, but for such a simple use-
> case that seems more work than necessary and less immediately
> obvious.)

You can also make two lists. I don't think we should provide "pros ans
cons list", because it has implications outside export.

> This bothered me a bit too when writing it but at the same time
> it seemed like overkill to replicate the docstrings of the called
> functions.  How do you feel about using a hook instead?
>
> (defvar org-texinfo--filter-parse-tree-functions
>   '(org-texinfo--normalize-headlines
>     org-texinfo--normalize-items)
>   "List of functions the `texinfo' back-end applies to the parsed tree.
> Each filter is called with three arguments: the parse tree, as
> returned by `org-element-parse-buffer', the back-end, as
> a symbol, and the communication channel, as a plist.  It must
> return the modified parse tree to transcode.")

Sure.

> Do you prefer to add the hook functions as done above or should each one
> be added individually using add-hook?

`add-hook' is more for users, I think.

> Done.  Is this okay?:
>
>               (when (and next-item
>                          (string-prefix-p
>                           "+"
>                           (org-element-property :bullet next-item)))
>
> Or should the line-breaks go elsewhere?

The line breaks do not matter much but it may fail if
(org-element-property :bullet next-item) returns nil.

>> Anyhow, relying on mixed bullets is not great…
>
> The alternative isn't great either.
>
> For example:
>
> - Key: C-c C-w (forge-browse-TYPE) ::
> + Key: C-c C-w (forge-browse-dwim) ::
> + Key: N b I (forge-browse-issues) ::
> + Key: N b P (forge-browse-pullreqs) ::
> + Key: N b t (forge-browse-topic) ::
> + Key: N b i (forge-browse-issue) ::
> + Key: N b p (forge-browse-pullreq) ::
>
>   These commands visit the topic, issue(s), pull-request(s), post,
>   branch, commit, or remote at point in a browser. ...
>
> vs.
>
> - Key: C-c C-w (forge-browse-TYPE), C-c C-w (forge-browse-dwim), N b I (forge-browse-issues), N b P (forge-browse-pullreqs), N b t (forge-browse-topic), N b i (forge-browse-issue), N b p (forge-browse-pullreq) ::
>
>   These commands visit the topic, issue(s), pull-request(s), post,
>   branch, commit, or remote at point in a browser. ...
>
> I am sure I am gonna make mistakes when using the latter approach.

True, but OTOH, the first option is not really possible. However, there
are still alternatives. For example, you could check blank lines between
items:

  - key: a ::
  - key: b ::

  - key: c ::
  - key: d ::

I suggest to require a special attribute before doing so, e.g.,

  #+attr_texinfo: :compact t
  - key: a ::
  - key: b ::

  - key: c ::
  - key: d ::

Another option would be to merge consecutive lists with such an
attribute, for the same result:

  #+attr_texinfo: :compact t
  - key: a ::
  - key: b ::

  #+attr_texinfo: :compact t
  - key: c ::
  - key: d ::


  - This is a regular list since it does not have :compact attribute.

IIRC, I did an experiment like this one when introducing matrices in
LaTeX export.

Regards,
-- 
Nicolas Goaziou


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/2] ox-texinfo: Turn a description list item with "+" bullet into @itemx
  2021-12-30  9:40                 ` Nicolas Goaziou
@ 2022-01-05 13:12                   ` Jonas Bernoulli
  0 siblings, 0 replies; 21+ messages in thread
From: Jonas Bernoulli @ 2022-01-05 13:12 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: kyle, emacs-orgmode

Nicolas Goaziou <mail@nicolasgoaziou.fr> writes:

>> For example:
>>
>> - Key: C-c C-w (forge-browse-TYPE) ::
>> + Key: C-c C-w (forge-browse-dwim) ::
>> + Key: N b I (forge-browse-issues) ::
>> + Key: N b P (forge-browse-pullreqs) ::
>> + Key: N b t (forge-browse-topic) ::
>> + Key: N b i (forge-browse-issue) ::
>> + Key: N b p (forge-browse-pullreq) ::
>>
>>   These commands visit the topic, issue(s), pull-request(s), post,
>>   branch, commit, or remote at point in a browser. ...
>>
>> vs.
>>
>> - Key: C-c C-w (forge-browse-TYPE), C-c C-w (forge-browse-dwim), N b I (forge-browse-issues), N b P (forge-browse-pullreqs), N b t (forge-browse-topic), N b i (forge-browse-issue), N b p (forge-browse-pullreq) ::
>>
>>   These commands visit the topic, issue(s), pull-request(s), post,
>>   branch, commit, or remote at point in a browser. ...
>>
>> I am sure I am gonna make mistakes when using the latter approach.
>
> True, but OTOH, the first option is not really possible. However, there
> are still alternatives. For example, you could check blank lines between
> items:
>
>   - key: a ::
>   - key: b ::
>
>   - key: c ::
>   - key: d ::
>
> I suggest to require a special attribute before doing so, e.g.,
>
>   #+attr_texinfo: :compact t
>   - key: a ::
>   - key: b ::
>
>   - key: c ::
>   - key: d ::

I went with that approach.

> Another option would be to merge consecutive lists with such an
> attribute, for the same result:
>
>   #+attr_texinfo: :compact t
>   - key: a ::
>   - key: b ::
>
>   #+attr_texinfo: :compact t
>   - key: c ::
>   - key: d ::
>
>
>   - This is a regular list since it does not have :compact attribute.

Ordered lists are transcoded to @itemize, while description lists are
transcoded to @table or some other table command.  So they cannot be
combined into one list-like thing in Texinfo.

The first two lists could be combined, but IMO it is better to only
require the :compact t once and avoid splitting the list and then
recombining the lists back into one.

     Jonas

Ps: Slightly sad about loosing the +.
    It looks very much like the x at the end of @itemx.


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/2] ox-texinfo: Define definition commands using description lists
  2021-12-30  0:57                 ` Nicolas Goaziou
@ 2022-01-05 13:16                   ` Jonas Bernoulli
  0 siblings, 0 replies; 21+ messages in thread
From: Jonas Bernoulli @ 2022-01-05 13:16 UTC (permalink / raw)
  To: Nicolas Goaziou; +Cc: kyle, emacs-orgmode

Nicolas Goaziou <mail@nicolasgoaziou.fr> writes:

> Hello,
>
> Jonas Bernoulli <jonas@bernoul.li> writes:
>
>> Would it be okay to represent e.g. "C-c SPC" as:
>>
>>    (export-snippet
>>     (:back-end "texinfo" :value "@kbd{C-c @key{SPC}}" :post-blank 0 :parent #2))
>
> Just use (org-export-raw-string "@kbd{C-c @key{SPC}}") instead.

That works.  I must of done something wrong when first trying that.

>> I think that is one of the things I tried that ox-texinfo insisted on
>> quoting anyway.  I might misremember, so I will have another look.
>
> `org-export-raw-string' is a recent addition in Org.
>
>> Above I suggested using an `export-snippet' element (instead of `raw');
>> to me that seems appropriate too.
>
> I think that's abusing export snippets. They are more user-oriented,
> e.g. filters can apply to them.
>
> Note you can write (org-export-raw-string (some-public-function "C-c
> SPC")) where (some-public-function "C-c SPC") => "@kbd{C-c @key{SPC}}",
> as done currently by the "kbd" macro.

I named it org-texinfo-kbd-macro and wrote it so that it can be used by
the kbd macro.  I have changed doc/doc-setup.org to use it.

DEL was missing from the list of special keys.

     Cheers,
     Jonas


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 0/3] ox-texinfo: Define definition commands using description lists
  2021-12-18 21:40         ` [PATCH 0/2] ox-texinfo: Define definition commands using description lists Jonas Bernoulli
  2021-12-18 21:40           ` [PATCH 1/2] ox-texinfo: Turn a description list item with "+" bullet into @itemx Jonas Bernoulli
  2021-12-18 21:40           ` [PATCH 2/2] ox-texinfo: Define definition commands using description lists Jonas Bernoulli
@ 2022-01-05 13:30           ` Jonas Bernoulli
  2022-01-05 13:30             ` [PATCH v2 1/3] ox-texinfo: Add function for use by kbd macro Jonas Bernoulli
                               ` (3 more replies)
  2 siblings, 4 replies; 21+ messages in thread
From: Jonas Bernoulli @ 2022-01-05 13:30 UTC (permalink / raw)
  To: emacs-orgmode

I think I have addressed all you feedback.

The only difference when exporting org-manual.org is:

-When typing text into a field, Org treats @kbd{DEL},
+When typing text into a field, Org treats @kbd{@key{DEL}},

Jonas Bernoulli (3):
  ox-texinfo: Add function for use by kbd macro
  ox-texinfo: Optionally use @itemx for certain description list items
  ox-texinfo: Define definition commands using description lists

 doc/doc-setup.org  |   2 +-
 doc/org-manual.org | 135 ++++++++++++++++++++++++++---
 lisp/ox-texinfo.el | 207 +++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 327 insertions(+), 17 deletions(-)

-- 
2.34.1



^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 1/3] ox-texinfo: Add function for use by kbd macro
  2022-01-05 13:30           ` [PATCH v2 0/3] " Jonas Bernoulli
@ 2022-01-05 13:30             ` Jonas Bernoulli
  2022-01-05 13:30             ` [PATCH v2 2/3] ox-texinfo: Optionally use @itemx for certain description list items Jonas Bernoulli
                               ` (2 subsequent siblings)
  3 siblings, 0 replies; 21+ messages in thread
From: Jonas Bernoulli @ 2022-01-05 13:30 UTC (permalink / raw)
  To: emacs-orgmode

* doc/doc-setup.org: Use org-texinfo-kbd-macro for kbd macro.
* doc/org-manual.org: Add new node "Key bindings in Texinfo export".
* lisp/ox-texinfo.el (org-texinfo-kbd-macro): New function.
---
 doc/doc-setup.org  |  2 +-
 doc/org-manual.org | 27 +++++++++++++++++++++++++++
 lisp/ox-texinfo.el | 23 ++++++++++++++++++++++-
 3 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/doc/doc-setup.org b/doc/doc-setup.org
index f59660e8e..59ad0eb60 100644
--- a/doc/doc-setup.org
+++ b/doc/doc-setup.org
@@ -49,5 +49,5 @@
 
 # The "kbd" macro turns KBD into @kbd{KBD}.  Additionally, it
 # encloses case-sensitive special keys (SPC, RET...) within @key{...}.
-#+macro: kbd (eval (let ((case-fold-search nil) (regexp (regexp-opt '("SPC" "RET" "LFD" "TAB" "BS" "ESC" "DELETE" "SHIFT" "Ctrl" "Meta" "Alt" "Cmd" "Super" "UP" "LEFT" "RIGHT" "DOWN") 'words))) (format "@@texinfo:@kbd{@@%s@@texinfo:}@@" (replace-regexp-in-string regexp "@@texinfo:@key{@@\\&@@texinfo:}@@" $1 t))))
+#+macro: kbd (eval (org-texinfo-kbd-macro $1))
 
diff --git a/doc/org-manual.org b/doc/org-manual.org
index b65e2f173..a5aac7d61 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -15353,6 +15353,33 @@ your king.
 ,#+END_QUOTE
 #+end_example
 
+*** Key bindings in Texinfo export
+:PROPERTIES:
+:DESCRIPTION: @@kbd Texinfo command.
+:END:
+
+Org does not provide any markup for key bindings that corresponds to
+Texinfo's ~@kbd~ and ~@key~ commands.  One way to deal with this is to
+fall back to code syntax.  =~C-x SPC~=, for example, is transcoded to
+~@code{C-x SPC}~.
+
+A better approach is to define and use an Org macro named ~kbd~.  To
+make that easier the function ~org-texinfo-kbd-macro~ is provided,
+which is intended to be used like this:
+
+#+begin_example
+#+macro: kbd (eval (org-texinfo-kbd-macro $1))
+
+Type {{{kbd(C-c SPC)}}}.
+#+end_example
+
+#+texinfo: @noindent
+which becomes
+
+#+begin_example
+Type @kbd{C-c @key{SPC}}.
+#+end_example
+
 *** Special blocks in Texinfo export
 :PROPERTIES:
 :DESCRIPTION: Special block attributes.
diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el
index b0125894a..57cbcf6ad 100644
--- a/lisp/ox-texinfo.el
+++ b/lisp/ox-texinfo.el
@@ -1611,7 +1611,28 @@ (defun org-texinfo-verse-block (_verse-block contents _info)
   (format "@display\n%s@end display" contents))
 
 \f
-;;; Interactive functions
+;;; Public Functions
+
+(defun org-texinfo-kbd-macro (key &optional noquote)
+  "Quote KEY using @kbd{...} and if necessary $key{...}.
+
+This is intended to be used as an Org macro like so:
+
+  #+macro: kbd (eval (org-texinfo-kbd-macro $1))
+  Type {{{kbd(C-c SPC)}}}.
+
+Also see info node `(org)Key bindings in Texinfo export'.
+
+If optional NOQOUTE is non-nil, then do not add the quoting
+that is necessary when using this in an Org macro."
+  (format (if noquote "@kbd{%s}" "@@texinfo:@kbd{@@%s@@texinfo:}@@")
+	  (let ((case-fold-search nil))
+	    (replace-regexp-in-string
+	     org-texinfo--quoted-keys-regexp
+	     (if noquote "@key{\\&}" "@@texinfo:@key{@@\\&@@texinfo:}@@")
+	     key t))))
+
+;;; Interactive Functions
 
 ;;;###autoload
 (defun org-texinfo-export-to-texinfo
-- 
2.34.1



^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 2/3] ox-texinfo: Optionally use @itemx for certain description list items
  2022-01-05 13:30           ` [PATCH v2 0/3] " Jonas Bernoulli
  2022-01-05 13:30             ` [PATCH v2 1/3] ox-texinfo: Add function for use by kbd macro Jonas Bernoulli
@ 2022-01-05 13:30             ` Jonas Bernoulli
  2022-01-05 13:30             ` [PATCH v2 3/3] ox-texinfo: Define definition commands using description lists Jonas Bernoulli
  2022-01-14 23:01             ` [PATCH v2 0/3] " Jonas Bernoulli
  3 siblings, 0 replies; 21+ messages in thread
From: Jonas Bernoulli @ 2022-01-05 13:30 UTC (permalink / raw)
  To: emacs-orgmode

* doc/org-manual.org (Plain lists in Texinfo export): Reorder and
document new functionality.
* lisp/ox-texinfo.el: Add org-texinfo--combine-items to the list of
:filter-parse-tree functions of the texinfo backend.
* lisp/ox-texinfo.el (org-texinfo--combine-items) New function.
* lisp/ox-texinfo.el (org-texinfo-item) Transcode combined items to
one @item and one or more @itemx.
---
 doc/org-manual.org | 38 +++++++++++++++++++++++++++-----------
 lisp/ox-texinfo.el | 45 +++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 68 insertions(+), 15 deletions(-)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index a5aac7d61..b3c4a9bef 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -15236,6 +15236,23 @@ This paragraph is preceded by...
 :DESCRIPTION: List attributes.
 :END:
 
+#+cindex: lettered lists, in Texinfo export
+#+cindex: enum, Texinfo attribute
+The Texinfo export back-end converts unordered and ordered lists in
+the Org file using the default command =@itemize=.
+
+Ordered lists are numbered when exported to Texinfo format.  Such
+numbering obeys any counter (see [[*Plain Lists]]) in the first item of
+the list.  The =:enum= attribute also let you start the list at a
+specific number, or switch to a lettered list, as illustrated here:
+
+#+begin_example
+#+ATTR_TEXINFO: :enum A
+1. Alpha
+2. Bravo
+3. Charlie
+#+end_example
+
 #+cindex: @samp{ATTR_TEXINFO}, keyword
 #+cindex: two-column tables, in Texinfo export
 #+cindex: table-type, Texinfo attribute
@@ -15262,7 +15279,7 @@ entry in the first column of the table.
 The following example illustrates all the attributes above:
 
 #+begin_example
-,#+ATTR_TEXINFO: :table-type vtable :sep , :indic asis
+,#+attr_texinfo: :table-type vtable :indic asis :sep ,
 - foo, bar :: This is the common text for variables foo and bar.
 #+end_example
 
@@ -15277,18 +15294,17 @@ This is the common text for variables foo and bar.
 @end table
 #+end_example
 
-#+cindex: lettered lists, in Texinfo export
-#+cindex: enum, Texinfo attribute
-Ordered lists are numbered when exported to Texinfo format.  Such
-numbering obeys any counter (see [[*Plain Lists]]) in the first item of
-the list.  The =:enum= attribute also let you start the list at
-a specific number, or switch to a lettered list, as illustrated here
+The =:combine= attribute is an alternative to the =:sep= attribute,
+which allows writing each entry on its own line.  If this attribute is
+non-nil and an item in a description list has no body but is followed
+by another item, then the second item is transcoded to =@itemx=.  This
+example is transcoded to the same output as above.
 
 #+begin_example
-#+ATTR_TEXINFO: :enum A
-1. Alpha
-2. Bravo
-3. Charlie
+,#+attr_texinfo: :table-type vtable :indic asis :combine t
+- foo ::
+- bar ::
+  This is the common text for variables foo and bar.
 #+end_example
 
 *** Tables in Texinfo export
diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el
index 57cbcf6ad..8f671ea13 100644
--- a/lisp/ox-texinfo.el
+++ b/lisp/ox-texinfo.el
@@ -83,7 +83,8 @@ (org-export-define-backend 'texinfo
     (verse-block . org-texinfo-verse-block))
   :filters-alist
   '((:filter-headline . org-texinfo--filter-section-blank-lines)
-    (:filter-parse-tree . org-texinfo--normalize-headlines)
+    (:filter-parse-tree . (org-texinfo--normalize-headlines
+			   org-texinfo--combine-items))
     (:filter-section . org-texinfo--filter-section-blank-lines)
     (:filter-final-output . org-texinfo--untabify))
   :menu-entry
@@ -421,7 +422,7 @@ (defun org-texinfo--filter-section-blank-lines (headline _backend _info)
 (defun org-texinfo--normalize-headlines (tree _backend info)
   "Normalize headlines in TREE.
 
-BACK-END is the symbol specifying back-end used for export.
+_BACKEND is the symbol `texinfo'; the back-end used for export.
 INFO is a plist used as a communication channel.
 
 Make sure every headline in TREE contains a section, since those
@@ -443,6 +444,37 @@ (defun org-texinfo--normalize-headlines (tree _backend info)
     info)
   tree)
 
+(defun org-texinfo--combine-items (tree _backend info)
+  "Normalize items in TREE.
+
+_BACKEND is the symbol `texinfo'; the back-end used for export.
+INFO is a plist used as a communication channel.
+
+Items in description lists that use the \"+\" bullet are
+converted to `@itemx'.  If another item is followed by such an
+item, then the first item should not be followed by a space,
+which this function takes care of.
+
+Return new tree."
+  (org-element-map tree 'item
+    (lambda (item)
+      (let ((plain-list (org-element-property :parent item)))
+	(when (and (org-not-nil (org-export-read-attribute
+				 :attr_texinfo plain-list :compact))
+		   (eq (org-element-property :type plain-list) 'descriptive))
+	  (let ((next-item
+		 (cadr (memq item (org-element-contents plain-list)))))
+	    (when (and next-item
+		       (not (org-element-contents item))
+		       (= (org-element-property :post-blank item) 1))
+	      (org-element-put-property
+	       next-item :itemx
+	       (nconc (org-element-property :itemx item)
+		      (list (org-element-property :tag item))))
+	      (org-element-extract-element item))))))
+    info)
+  tree)
+
 (defun org-texinfo--find-verb-separator (s)
   "Return a character not used in string S.
 This is used to choose a separator for constructs like \\verb."
@@ -994,8 +1026,13 @@ (defun org-texinfo-item (item contents info)
 		 (org-export-read-attribute :attr_texinfo
 					    (org-element-property :parent item)
 					    :sep)))
-	 (items (and tag
-		     (let ((tag (org-export-data tag info)))
+	 (items (org-element-property :itemx item))
+	 (items (cond (items
+		       (mapcar (lambda (tag) (org-export-data tag info))
+			       (nconc items (list tag))))
+		      ((not tag) nil)
+		      (t
+		       (setq tag (org-export-data tag info))
 		       (if split
 			   (split-string tag (regexp-quote split) t "[ \t\n]+")
 			 (list tag))))))
-- 
2.34.1



^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 3/3] ox-texinfo: Define definition commands using description lists
  2022-01-05 13:30           ` [PATCH v2 0/3] " Jonas Bernoulli
  2022-01-05 13:30             ` [PATCH v2 1/3] ox-texinfo: Add function for use by kbd macro Jonas Bernoulli
  2022-01-05 13:30             ` [PATCH v2 2/3] ox-texinfo: Optionally use @itemx for certain description list items Jonas Bernoulli
@ 2022-01-05 13:30             ` Jonas Bernoulli
  2022-01-14 23:01             ` [PATCH v2 0/3] " Jonas Bernoulli
  3 siblings, 0 replies; 21+ messages in thread
From: Jonas Bernoulli @ 2022-01-05 13:30 UTC (permalink / raw)
  To: emacs-orgmode

* doc/org-manual.org (Plain lists in Texinfo export): Document use
of definition command prefixes in description lists.
* lisp/ox-texinfo.el: Add org-texinfo--separate-definitions to the
list of :filter-parse-tree functions of the texinfo backend.
* lisp/ox-texinfo.el (org-texinfo--quoted-keys-regexp)
(org-texinfo--definition-command-alist)
(org-texinfo--definition-command-regexp): New variables.
* lisp/ox-texinfo.el (org-texinfo--filter-parse-tree): Call
org-texinfo--separate-definitions.
* lisp/ox-texinfo.el (org-texinfo--separate-definitions)
(org-texinfo--match-definition, org-texinfo--split-definition)
(org-texinfo--split-plain-list, org-texinfo--massage-key-item):
New functions.
---
 doc/org-manual.org |  70 +++++++++++++++++++++++
 lisp/ox-texinfo.el | 139 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 209 insertions(+)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index b3c4a9bef..daa207a5d 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -15307,6 +15307,72 @@ example is transcoded to the same output as above.
   This is the common text for variables foo and bar.
 #+end_example
 
+Likewise, the Texinfo export back-end supports two approaches to
+writing Texinfo definition commands (see [[info:texinfo::Definition
+Commands]]).  One of them uses description lists and is describe below,
+the other is described in [[*Special blocks in Texinfo export]].
+
+Items in a description list in a Org file that begin with =Function:=
+or certain other prefixes are converted using Texinfo definition
+commands.  This works even if other items in the same list do not have
+such a prefix; if necessary a single description list is converted
+using multiple tables (such as =@vtable=) and definition commands
+(such as =@defun=).
+
+#+begin_example
+- Function: org-texinfo-drawer drawer contents info ::
+  Transcode a DRAWER element from Org to Texinfo.
+#+end_example
+
+#+texinfo: @noindent
+becomes
+
+#+begin_example
+@defun org-texinfo-drawer drawer contents info ::
+  Transcode a DRAWER element from Org to Texinfo.
+@end defun
+#+end_example
+
+The recognized prefixes are =Command:=, =Function:=, =Macro:=,
+=Special Form:=, =Variable:= and =User Option:=.  These are the same
+prefixes that appear in the Info file for the respective definition
+commands.  For example a =Function:= item in the Org file is converted
+to a =@defun= command in the Texinfo file, which in turn is converted
+to a definition prefixed with =-- Function:= in the Info file.
+
+As a special case the prefix =Key:= is also recognized.  No Texinfo
+definition command exists for key bindings and the output in Info
+files also lacks the =Key:= prefix.  Even so this special case is
+supported because it provides a convenient shorthand, as illustrated
+here:
+
+#+begin_example
+- Key: C-c C-c (do-something) ::
+  This command does something.
+
+- User Option: do-something-somehow ::
+  This option controls how exactly ~do-something~ does its thing.
+#+end_example
+
+#+texinfo: @noindent
+becomes
+
+#+begin_example
+@table @asis
+@item @kbd{C-c C-c} (@code{do-something})
+@kindex C-c C-c
+@findex do-something
+This command does something.
+@end table
+
+@defopt do-something-somehow
+This option controls how exactly @code{do-something} does its thing.
+@end defopt
+#+end_example
+
+#+texinfo: @noindent
+Command in parenthesis, as done above, is optional.
+
 *** Tables in Texinfo export
 :PROPERTIES:
 :DESCRIPTION: Table attributes.
@@ -15401,6 +15467,10 @@ Type @kbd{C-c @key{SPC}}.
 :DESCRIPTION: Special block attributes.
 :END:
 
+The Texinfo export back-end supports two approaches to writing Texinfo
+definition commands.  One of them is describe here, the other in
+[[*Plain lists in Texinfo export]].
+
 #+cindex: @samp{ATTR_TEXINFO}, keyword
 
 The Texinfo export back-end converts special blocks to commands with
diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el
index 8f671ea13..a79f620c6 100644
--- a/lisp/ox-texinfo.el
+++ b/lisp/ox-texinfo.el
@@ -84,6 +84,7 @@ (org-export-define-backend 'texinfo
   :filters-alist
   '((:filter-headline . org-texinfo--filter-section-blank-lines)
     (:filter-parse-tree . (org-texinfo--normalize-headlines
+			   org-texinfo--separate-definitions
 			   org-texinfo--combine-items))
     (:filter-section . org-texinfo--filter-section-blank-lines)
     (:filter-final-output . org-texinfo--untabify))
@@ -408,6 +409,30 @@ (defconst org-texinfo-inline-image-rules
 	      (regexp-opt '("eps" "pdf" "png" "jpg" "jpeg" "gif" "svg"))))
   "Rules characterizing image files that can be inlined.")
 
+(defvar org-texinfo--quoted-keys-regexp
+  (regexp-opt '("BS" "TAB" "RET" "ESC" "SPC" "DEL"
+		"LFD" "DELETE" "SHIFT" "Ctrl" "Meta" "Alt"
+		"Cmd" "Super" "UP" "LEFT" "RIGHT" "DOWN")
+	      'words)
+  "Regexp matching keys that have to be quoted using @key{KEY}.")
+
+(defconst org-texinfo--definition-command-alist
+  '(("deffn Command" . "Command")
+    ("defun" . "Function")
+    ("defmac" . "Macro")
+    ("defspec" . "Special Form")
+    ("defvar" . "Variable")
+    ("defopt" . "User Option")
+    (nil . "Key"))
+  "Alist mapping Texinfo definition commands to output in Info files.")
+
+(defconst org-texinfo--definition-command-regexp
+  (format "\\`%s: \\(.+\\)"
+	  (regexp-opt
+	   (delq nil (mapcar #'cdr org-texinfo--definition-command-alist))
+	   t))
+  "Regexp used to match definition commands in descriptive lists.")
+
 \f
 ;;; Internal Functions
 
@@ -602,6 +627,120 @@ (defun org-texinfo--sectioning-structure (info)
       (`(,_ ,_ . ,sections) sections)
       (_ (user-error "Unknown Texinfo class: %S" class)))))
 
+(defun org-texinfo--separate-definitions (tree _backend info)
+  "Split up descriptive lists in TREE that contain Texinfo definition commands.
+
+_BACKEND is the symbol `texinfo'; the back-end used for export.
+INFO is a plist used as a communication channel.
+
+Return new tree."
+  (org-element-map tree 'plain-list
+    (lambda (plain-list)
+      (when (eq (org-element-property :type plain-list) 'descriptive)
+	(let ((contents (org-element-contents plain-list))
+	      (items nil))
+	  (dolist (item contents)
+	    (pcase-let ((`(,cmd . ,args) (org-texinfo--match-definition item)))
+	      (cond
+	       (cmd
+		(when items
+		  (org-texinfo--split-plain-list plain-list (nreverse items))
+		  (setq items nil))
+		(org-texinfo--split-definition plain-list item cmd args))
+	       (t
+		(when args
+		  (org-texinfo--massage-key-item plain-list item args))
+		(push item items)))))
+	  (unless (org-element-contents plain-list)
+	    (org-element-extract-element plain-list)))))
+    info)
+  tree)
+
+(defun org-texinfo--match-definition (item)
+  "Return a cons-cell if ITEM specifies a Texinfo definition command.
+The car is the command and the cdr is its arguments."
+  (let ((tag (car-safe (org-element-property :tag item))))
+    (and tag
+	 (stringp tag)
+	 (string-match org-texinfo--definition-command-regexp tag)
+	 (pcase-let*
+	     ((cmd (car (rassoc (match-string-no-properties 1 tag)
+				 org-texinfo--definition-command-alist)))
+	      (`(,cmd ,category)
+	       (and cmd (save-match-data (split-string cmd " "))))
+	      (args (match-string-no-properties 2 tag)))
+	   (cons cmd (if category (concat category " " args) args))))))
+
+(defun org-texinfo--split-definition (plain-list item cmd args)
+  "Insert a definition command before list PLAIN-LIST.
+Replace list item ITEM with a special-block that inherits the
+contents of ITEM and whose type and Texinfo attributes are
+specified by CMD and ARGS."
+  (let ((contents (org-element-contents item)))
+    (org-element-insert-before
+     (apply #'org-element-create 'special-block
+	    (list :type cmd
+		  :attr_texinfo (list (format ":options %s" args))
+		  :post-blank (if contents 1 0))
+	    (mapc #'org-element-extract-element contents))
+     plain-list))
+  (org-element-extract-element item))
+
+(defun org-texinfo--split-plain-list (plain-list items)
+  "Insert a new plain list before the plain list PLAIN-LIST.
+Remove ITEMS from PLAIN-LIST and use them as the contents of the
+new plain list."
+  (org-element-insert-before
+   (apply #'org-element-create 'plain-list
+	  (list :type 'descriptive :post-blank 1)
+	  (mapc #'org-element-extract-element items))
+   plain-list))
+
+(defun org-texinfo--massage-key-item (plain-list item args)
+  "In PLAIN-LIST modify ITEM based on ARGS.
+Reformat ITEM's tag property and add findex and kindex entries to
+its content.  If the bullet is \"+\" then use \"@itemx\" and deal with
+data from preceeding siblings that use such a bullet."
+  (let (key cmd)
+    (if (string-match (rx (+ " ")
+			  "(" (group (+ (not (any "()")))) ")"
+			  (* " ")
+			  eos)
+		      args)
+	(setq key (substring args 0 (match-beginning 0))
+	      cmd (match-string 1 args))
+      (setq key args))
+    (org-element-put-property
+     item :tag
+     (cons (org-export-raw-string (org-texinfo-kbd-macro key t))
+	   (and cmd `(" (" (code (:value ,cmd :post-blank 0)) ")"))))
+    (let ((findex (org-element-property :findex item))
+	  (kindex (org-element-property :kindex item))
+	  (next-item (cadr (memq item (org-element-contents plain-list))))
+	  (mx (string-prefix-p "M-x " key)))
+      (when (and (not cmd) mx)
+	(setq cmd (substring key 4)))
+      (when (and cmd (not (member cmd findex)))
+	(setq findex (nconc findex (list cmd))))
+      (unless mx
+	(setq kindex (nconc kindex (list key))))
+      (cond
+       ((and next-item
+	     (org-not-nil
+	      (org-export-read-attribute :attr_texinfo plain-list :compact))
+	     (not (org-element-contents item))
+	     (= (org-element-property :post-blank item) 1))
+	(org-element-put-property next-item :findex findex)
+	(org-element-put-property next-item :kindex kindex)
+	(org-element-put-property item :findex nil)
+	(org-element-put-property item :kindex nil))
+       (t
+	(org-element-set-contents
+	 item (nconc
+	       (mapcar (lambda (key) `(keyword (:key "KINDEX" :value ,key))) kindex)
+	       (mapcar (lambda (cmd) `(keyword (:key "FINDEX" :value ,cmd))) findex)
+	       (org-element-contents item))))))))
+
 ;;; Template
 
 (defun org-texinfo-template (contents info)
-- 
2.34.1



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 0/3] ox-texinfo: Define definition commands using description lists
  2022-01-05 13:30           ` [PATCH v2 0/3] " Jonas Bernoulli
                               ` (2 preceding siblings ...)
  2022-01-05 13:30             ` [PATCH v2 3/3] ox-texinfo: Define definition commands using description lists Jonas Bernoulli
@ 2022-01-14 23:01             ` Jonas Bernoulli
  3 siblings, 0 replies; 21+ messages in thread
From: Jonas Bernoulli @ 2022-01-14 23:01 UTC (permalink / raw)
  To: emacs-orgmode; +Cc: Nicolas Goaziou

Hello Nicolas,

Could you please have another look?

     Cheers,
     Jonas


Jonas Bernoulli <jonas@bernoul.li> writes:

> I think I have addressed all you feedback.
>
> The only difference when exporting org-manual.org is:
>
> -When typing text into a field, Org treats @kbd{DEL},
> +When typing text into a field, Org treats @kbd{@key{DEL}},
>
> Jonas Bernoulli (3):
>   ox-texinfo: Add function for use by kbd macro
>   ox-texinfo: Optionally use @itemx for certain description list items
>   ox-texinfo: Define definition commands using description lists
>
>  doc/doc-setup.org  |   2 +-
>  doc/org-manual.org | 135 ++++++++++++++++++++++++++---
>  lisp/ox-texinfo.el | 207 +++++++++++++++++++++++++++++++++++++++++++--
>  3 files changed, 327 insertions(+), 17 deletions(-)
>
> -- 
> 2.34.1


^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2022-01-14 23:05 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-09 18:01 Merging ox-texinfo+ into ox-texinfo Jonas Bernoulli
2021-11-19 12:46 ` Nicolas Goaziou
2021-11-20 21:06   ` Jonas Bernoulli
2021-11-21 12:41     ` Nicolas Goaziou
2021-11-30 16:58       ` Jonas Bernoulli
2021-12-18 21:40         ` [PATCH 0/2] ox-texinfo: Define definition commands using description lists Jonas Bernoulli
2021-12-18 21:40           ` [PATCH 1/2] ox-texinfo: Turn a description list item with "+" bullet into @itemx Jonas Bernoulli
2021-12-26 21:37             ` Nicolas Goaziou
2021-12-27 18:05               ` Jonas Bernoulli
2021-12-30  9:40                 ` Nicolas Goaziou
2022-01-05 13:12                   ` Jonas Bernoulli
2021-12-18 21:40           ` [PATCH 2/2] ox-texinfo: Define definition commands using description lists Jonas Bernoulli
2021-12-26 21:46             ` Nicolas Goaziou
2021-12-27 18:05               ` Jonas Bernoulli
2021-12-30  0:57                 ` Nicolas Goaziou
2022-01-05 13:16                   ` Jonas Bernoulli
2022-01-05 13:30           ` [PATCH v2 0/3] " Jonas Bernoulli
2022-01-05 13:30             ` [PATCH v2 1/3] ox-texinfo: Add function for use by kbd macro Jonas Bernoulli
2022-01-05 13:30             ` [PATCH v2 2/3] ox-texinfo: Optionally use @itemx for certain description list items Jonas Bernoulli
2022-01-05 13:30             ` [PATCH v2 3/3] ox-texinfo: Define definition commands using description lists Jonas Bernoulli
2022-01-14 23:01             ` [PATCH v2 0/3] " Jonas Bernoulli

Code repositories for project(s) associated with this inbox:

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).