Repository: asciidoctor/asciidoctor (Ruby)

Issue:
multiple menu marcos in a paragraph interpreted strangely
When there are multiple single-level menu inline macros in a paragraph, they are wrongly conflated together.

### To reproduce

Place two or more single-level menu entries in the same paragraph.

E.g.
```asciidoc
:experimental:

Click menu:foo[] and then menu:foo[] again.
```

or equivalently on several source lines (but still one target paragraph)

```asciidoc
:experimental:

Click menu:foo[] and
then menu:foo[] again.
```

#### Expected

These are interpreted as separate macros, resulting in e.g. (for the `docbook` backend)
```xml
Click
<guimenu>foo</guimenu>
and then
<guimenu>foo</guimenu>
again.
```

#### Observed

They are interpreted as one macro, with the stuff between them as part of a menu item, e.g (`docbook` again):
```xml
Click
<menuchoice>
  <guimenu>foo</guimenu>
  <guimenuitem>] and then menu:foo[</guimenuitem>
</menuchoice>
again.
```
(linebreaks & indentation added manually, to better show the structure)

<details><summary>click here for the actual result file content</summary>

```xml
<?xml version="1.0" encoding="UTF-8"?>
<?asciidoc-toc?>
<?asciidoc-numbered?>
<article xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" version="5.0" xml:lang="en">
<info>
<title>Untitled</title>
<date>2019-04-25</date>
</info>
<simpara>Click <menuchoice><guimenu>foo</guimenu> <guimenuitem>] and then menu:foo[</guimenuitem></menuchoice> again.</simpara>
</article>
```

</details>

---

### unaffected

Multi-level menus in either style seem to work alright:

```asciidoc
:experimental:

Click menu:foo[bar] and then menu:foo[bar] again.

Click menu:foo[bar > baz] and then menu:foo[bar > baz] again.

Click "foo > bar" and then "foo > bar" again.

Click "foo > bar > baz" and then "foo > bar > baz" again.
```

As does the similarly structured inline macros `link`:
```asciidoc
Click link:foo[] and then link:foo[] again.

Click link:foo[bar] and then link:foo[bar] again.

Click link:foo[bar,window=baz] and then link:foo[bar,window=baz] again.
```
---
Output of `asciidoctor --version`:
```
Asciidoctor 2.0.8 [https://asciidoctor.org]
Runtime Environment (ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux-musl]) (lc:UTF-8 fs:UTF-8 in:UTF-8 ex:UTF-8)
```
I've tested this with the `asciidoctor/docker-asciidoctor` docker image, sha256 `b72e4a384dbed3a9f24690554d54eeb77039b838b7ed5a2b11b58ed34c248305`.


Discussion:
Yep, this is a bug in the regular expression that matches the menu macro.



Patch:
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index 962961db5c..3e17731d6e 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -13,6 +13,12 @@ endif::[]
 This document provides a high-level view of the changes introduced in Asciidoctor by release.
 For a detailed view of what has changed, refer to the {uri-repo}/commits/master[commit history] on GitHub.
 
+== Unreleased
+
+Bug Fixes::
+
+  * process multiple single-item menu macros in same line (#3279)
+
 // tag::compact[]
 == 2.0.8 (2019-04-22) - @mojavelinux
 
diff --git a/lib/asciidoctor/rx.rb b/lib/asciidoctor/rx.rb
index ef5a091d25..5dc194677d 100644
--- a/lib/asciidoctor/rx.rb
+++ b/lib/asciidoctor/rx.rb
@@ -547,10 +547,11 @@ module Rx; end
   # Examples
   #
   #   menu:File[Save As...]
+  #   menu:Edit[]
   #   menu:View[Page Style > No Style]
   #   menu:View[Page Style, No Style]
   #
-  InlineMenuMacroRx = /\\?menu:(#{CG_WORD}|[#{CC_WORD}&][^\n\[]*[^\s\[])\[ *(#{CC_ALL}*?[^\\])?\]/m
+  InlineMenuMacroRx = /\\?menu:(#{CG_WORD}|[#{CC_WORD}&][^\n\[]*[^\s\[])\[ *(?:|(#{CC_ALL}*?[^\\]))?\]/m
 
   # Matches an implicit menu inline macro.
   #


Test patch:
diff --git a/test/substitutions_test.rb b/test/substitutions_test.rb
index 9be251344d..c2a749465f 100644
--- a/test/substitutions_test.rb
+++ b/test/substitutions_test.rb
@@ -1550,6 +1550,11 @@
         assert_equal %q{<guimenu>File</guimenu>}, para.sub_macros(para.source)
       end
 
+      test 'should process multiple menu macros in same line' do
+        para = block_from_string('menu:File[] and menu:Edit[]', attributes: { 'experimental' => '' })
+        assert_equal '<b class="menuref">File</b> and <b class="menuref">Edit</b>', para.sub_macros(para.source)
+      end
+
       test 'should process menu with menu item using macro syntax' do
         para = block_from_string('menu:File[Save As&#8230;]', attributes: { 'experimental' => '' })
         assert_equal %q{<span class="menuseq"><b class="menu">File</b>&#160;<b class="caret">&#8250;</b> <b class="menuitem">Save As&#8230;</b></span>}, para.sub_macros(para.source)