SuperbChemistry 3.0 master
authorMatt McCutchen <matt@mattmccutchen.net>
Thu, 10 Sep 2020 17:39:47 +0000 (13:39 -0400)
committerMatt McCutchen <matt@mattmccutchen.net>
Thu, 10 Sep 2020 17:39:47 +0000 (13:39 -0400)
- Update for compatibility with modern versions of OpenOffice and
  LibreOffice.  One of the regular expressions contained an unescaped [
  in a character class, which no longer works because it now denotes a
  named character class.  Also, work around a bug in LibreOffice undo.

- Put all actions taken during a formatting pass in an undo context so
  they can be undone and redone as a unit.

- Change the file extension to oxt and add full extension metadata and a
  menu item.

- Add support for formatting a selection rather than the entire
  document, with a minor limitation.

- Make the rules for recognizing sequences slightly more conservative.

.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
README.md [new file with mode: 0644]
SuperbChemistry-test.odt
extension/Addons.xcu [new file with mode: 0644]
extension/META-INF/manifest.xml
extension/SuperbChemistry/Main.xba
extension/SuperbChemistry/dialog.xlb
extension/SuperbChemistry/script.xlb
extension/description.xml [new file with mode: 0644]
extension/extension-description.txt [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..7cc7f81
--- /dev/null
@@ -0,0 +1 @@
+/SuperbChemistry.oxt
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..59b2de9
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
+OXT:=SuperbChemistry.oxt
+
+all: $(OXT)
+
+# No dependencies declared.  Clean in order to make it again.
+$(OXT):
+       rm -f $@
+       cd extension && zip -r ../$(OXT) *
+
+clean:
+       rm -f $(OXT)
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..38e420c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,61 @@
+# SuperbChemistry
+
+This is an extension for [OpenOffice](https://www.openoffice.org/) and
+[LibreOffice](https://www.libreoffice.org/) that applies superscript and
+subscript formatting to chemical formulas in bulk in Writer documents.  See [the
+web page](https://mattmccutchen.net/superbchemistry/) for user documentation.
+
+The rest of this document refers to LibreOffice, but the same remarks apply to
+OpenOffice.
+
+## Development
+
+Run `make clean all` to generate `SuperbChemistry.oxt`, which you can install in
+LibreOffice via "Tools" -> "Extension Manager".
+
+By default, the library is installed read-only to prevent users from making
+changes that would be lost without warning if they uninstall the extension.  For
+development, you can change `library:readonly="true"` to
+`library:readonly="false"` in `extension/SuperbChemistry/*.xlb` so you can edit
+the library in LibreOffice.  Then you can copy the edited `Main.xba` from your
+profile (a typical location is
+`~/.config/libreoffice/4/user/uno_packages/cache/uno_packages/*.tmp_/SuperbChemistry.oxt/SuperbChemistry/Main.xba`,
+but this will depend on your operating system and application version) back to
+this working tree.
+
+`SuperbChemistry-test.odt` is a test suite that exercises most cases of the
+formatting rules.
+
+## Formatting rules
+
+- An _item_ is an element symbol (`[A-Z][a-z]?`) or text that starts or ends
+  with a group symbol `()[]{}` (depending on which side of the item we're
+  looking at).
+- A _charge symbol_ is `+`, `-` (U+002D hyphen-minus), or `−` (U+2212 minus
+  sign).
+- We recognize the following sequences:
+  - An item followed by one or more digits and one of the following: another
+    item, space or tab, closing group symbol `)]}`, sentence punctuation
+    `.,:;?!'"`, or end of line.
+  - An item followed by zero or more digits, a charge symbol, and any of the
+    things allowed in the previous case except for another item (to avoid
+    matching compound words like `A-B`).  This means we won't match something
+    like `Na+Cl-` , but formulas are rarely written that way.
+- A recognized charge symbol of `-` is replaced with `−`.
+- In a recognized sequence with no charge symbol, all of the digits are treated
+  as a quantity.
+- In a recognized sequence with a charge symbol, the last digit is treated as a
+  charge amount and the rest are treated as a quantity.  For example, in `Fe3+`,
+  the digit should be a charge amount.  Exception: if there is only one digit,
+  it is treated as a quantity in two cases:
+  - If the item is `H`, `O`, `F`, `Cl`, `Br`, or `I`, because these elements
+    often occur in quantities greater than 1 and rarely have a charge greater
+    than 1.
+  - If the item ends in a closing group symbol, because it probably wouldn't
+    have been enclosed in group symbols if its quantity were 1.
+
+## License
+
+I, Matt McCutchen, the sole author of SuperbChemistry, waive my copyright to it,
+placing it in the public domain.  SuperbChemistry comes with absolutely no
+warranty.
index 9740bbc..33f2e1c 100644 (file)
Binary files a/SuperbChemistry-test.odt and b/SuperbChemistry-test.odt differ
diff --git a/extension/Addons.xcu b/extension/Addons.xcu
new file mode 100644 (file)
index 0000000..91cd233
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<oor:component-data xmlns:oor="http://openoffice.org/2001/registry"
+ oor:name="Addons" oor:package="org.openoffice.Office">
+  <node oor:name="AddonUI">
+    <node oor:name="AddonMenu">
+      <!-- MenuItem -->
+      <node oor:name="net.mattmccutchen.superbchemistry.FormatSelectionOrDocument" oor:op="replace">
+        <prop oor:name="URL">
+          <value>vnd.sun.star.script:SuperbChemistry.Main.FormatSelectionOrDocument?language=Basic&amp;location=application</value>
+        </prop>
+        <prop oor:name="Title">
+          <value>SuperbChemistry: Format selection or document</value>
+        </prop>
+        <prop oor:name="Context">
+          <value>com.sun.star.text.TextDocument</value>
+        </prop>
+      </node>
+    </node>
+  </node>
+</oor:component-data>
index 184035e..e414e74 100644 (file)
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <manifest:manifest>
  <manifest:file-entry manifest:full-path="SuperbChemistry/" manifest:media-type="application/vnd.sun.star.basic-library"/>
-</manifest:manifest>
\ No newline at end of file
+ <manifest:file-entry manifest:full-path="Addons.xcu" manifest:media-type="application/vnd.sun.star.configuration-data"/>
+</manifest:manifest>
index 530cf8d..960dc6c 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
-<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Main" script:language="StarBasic">&apos; SuperbChemistry version 2.2
-&apos; http://mattmccutchen.net/schem/
-&apos; Written and maintained by Matt McCutchen &lt;matt@mattmccutchen.net&gt;
-&apos;
-&apos; Applies superscript and subscript formatting to chemical formulas in
-&apos; OpenOffice.org Writer documents.
-&apos;
-&apos; Rules:
-&apos; - Quantities [0-9]+ and charges [0-9]*[-+−] are recognized after an element
-&apos;   symbol [A-Z][a-z]? or a closing delimiter [\])}] .  Hyphens are converted
-&apos;   into real minus signs.
-&apos; - A charge sign [-+−] is ignored if it is followed by a letter, digit,
-&apos;   opening delimiter, or [&lt;&gt;] .  (Charges should appear only at the end of a
-&apos;   formula, and we want to avoid matching ordinary hyphens in text.)
-&apos; - When digits followed by a charge sign are recognized, the last digit
-&apos;   becomes part of the charge and the remaining digits become the quantity.
-&apos;   (Charges rarely have absolute value more than 9.)
-&apos; - In cases like X2-, we have to guess whether the digit is an atom/group
-&apos;   quantity or a charge amount.  We guess atom/group quantity if X is H (NH4+),
-&apos;   O (NO3-), a halogen (SbF6-, AlCl4-, etc.), or a closing parenthesis
-&apos;   (Fe(OH)2+; the group likely would not have been parenthesized unless it had
-&apos;   a quantity).  Otherwise we guess charge amount (Fe3+).  This heuristic
-&apos;   should be right most of the time.
-&apos;
-&apos; Examples:
-&apos; C12345 ==&gt; C_{12345}
-&apos; H+ ==&gt; H^+
-&apos; Cl- ==&gt; Cl^-
-&apos; Fe3+ ==&gt; Fe^{3+}
-&apos; SO42- ==&gt; SO_4^{2-}
-&apos; C1232+ ==&gt; C_{123}^{2+}
-&apos; N3- ==&gt; N^{3-}
-&apos; N|_3^- not recognized (| represents &quot;no-width no break&quot;)
-&apos; NH4+ ==&gt; NH_4^+
-&apos; NO3- ==&gt; NO_3^-
-&apos; AlCl4- =&gt; AlCl_4^-
-&apos; Fe(OH)2+ ==&gt; Fe(OH)_2^+
-&apos; O12 ==&gt; O_{12}
-&apos; y4- not recognized
-&apos; x2 not recognized
-&apos; Foo2 not recognized
-&apos; TI-89 not recognized
-&apos;
-&apos; To format the current document, run the FormatDocument macro: go to Tools -&gt;
-&apos; Macros -&gt;  Run Macro... -&gt; My Macros -&gt; SuperbChemistry -&gt; Main -&gt;
-&apos; FormatDocument -&gt; Run.  I realize that this is ugly.  I tried to make the
-&apos; package install a menu item to format the document, but the resulting package
-&apos; caused OpenOffice.org to crash regularly (I didn&apos;t investigate why), so I
-&apos; abandoned that idea.  Note that you can add a menu item as a user
-&apos; customization (Tools -&gt; Customize), and I recommend it if you plan to use
-&apos; SuperbChemistry frequently.
-&apos;
-&apos; FormatDocument uses a sequence of regular expression find-and-replace
-&apos; operations since that was easy to implement and makes the rules easy to
-&apos; change.  The operations appear in the undo history, so you can undo a
-&apos; formatting run by undoing the block of &quot;Replace&quot; entries at the top of the
-&apos; history.
-&apos;
-&apos; I would like to support formatting a selection, but the OpenOffice.org API
-&apos; does not appear to support replace-all within a selection.  I could find
-&apos; within the selection and implement the replacing myself, but that is more
-&apos; work than I want to do.
-&apos;
-&apos; If SuperbChemistry makes a mistake (e.g., recognizes a &quot;formula&quot; that isn&apos;t
-&apos; or formats a formula incorrectly), you can correct the formatting yourself
-&apos; and prevent future runs of the macro from recognizing the offending text by
-&apos; inserting a &quot;No-width no break&quot; character in the middle of it.  This character
-&apos; is available in the &quot;Insert -&gt; Formatting Mark&quot; menu when &quot;Tools -&gt; Options -&gt;
-&apos; Language Settings -&gt; Languages -&gt; Enhanced language support -&gt;
-&apos; Enabled for complex text layout (CTL)&quot; is enabled.
-
-&apos; ==============================================================================
-
-&apos; Regular expression replace in the document,
-&apos; creating superscripts if superb &gt; 0 or subscripts if superb &lt; 0.
-&apos; Used by FormatDocument.
-sub SuperbReplace(doc as object, searchStr as string, replaceStr as string, superb as integer)
-
-dim rd as object
-rd = doc.createReplaceDescriptor()
-
-rd.SearchCaseSensitive = true
-rd.SearchRegularExpression = true
-rd.setSearchString(searchStr)
-rd.setReplaceString(replaceStr)
-
-if superb &lt;&gt; 0 then
-       dim replaceAttrs(1) as new com.sun.star.beans.PropertyValue
-       replaceAttrs(0).Name = &quot;CharEscapement&quot;
-       if superb &gt; 0 then
-               replaceAttrs(0).Value = 33
-       else
-               replaceAttrs(0).Value = -9
-       end if
-       replaceAttrs(1).Name = &quot;CharEscapementHeight&quot;
-       replaceAttrs(1).Value = 58
-       rd.setReplaceAttributes(replaceAttrs)
-end if
-
-doc.replaceAll(rd)
-
-end sub
-
-&apos; Formats the current document
-sub FormatDocument
-
-&apos; Idiom: Match something and tag it on the left or right with @x@
-&apos; for further processing.  If the replacement text could use
-&apos; backreferences, this would be easier.  (I think backreferences were added
-&apos; since I originally wrote this code, but I see no need to rewrite it to take
-&apos; advantage of them. - Matt 2008-10-26)
-
-&apos; Tag candidate charges following symbols or ), but not in compound words, etc.
-&apos; Acceptable next character.  (Has to be before end of line to avoid matching @g@ tag itself.)
-SuperbReplace(ThisComponent, &quot;([A-Z][a-z]?|[\])}])[0-9]*[-+−][^[({A-Za-z0-9&lt;&gt;]&quot;, &quot;&amp;@G@&quot;, 0)
-&apos; Retag in front.
-SuperbReplace(ThisComponent, &quot;.@G@&quot;, &quot;@g@&amp;&quot;, 0)
-&apos; End of line.
-SuperbReplace(ThisComponent, &quot;([A-Z][a-z]?|[\])}])[0-9]*[-+−]$&quot;, &quot;&amp;@g@&quot;, 0)
-
-&apos; Some groups grab a single following digit as a quantity rather than a charge amount.
-&apos; See detailed rationale above.
-SuperbReplace(ThisComponent, &quot;(H|O|F|Cl|Br|I|\))[0-9]&quot;, &quot;&amp;@n@&quot;, 0)
-
-&apos; Real minus signs in charges.
-SuperbReplace(ThisComponent, &quot;-@g@&quot;, &quot;−@g@&quot;, 0)
-
-&apos; Make charges: at most one digit.
-SuperbReplace(ThisComponent, &quot;[0-9]?[−+]@g@&quot;, &quot;@q@&amp;&quot;, 1)
-
-&apos; Remove the O and ) markers in case of O57.
-SuperbReplace(ThisComponent, &quot;@n@&quot;, &quot;&quot;, 0)
-
-&apos; Tag quantities: as many digits as we can still grab.
-SuperbReplace(ThisComponent, &quot;([A-Z][a-z]?|[\])}])[0-9]+&quot;, &quot;&amp;@n@&quot;, 0)
-
-&apos; Make quantities.
-SuperbReplace(ThisComponent, &quot;[0-9]+@n@&quot;, &quot;&amp;&quot;, -1)
-
-&apos; Clean up all markers.
-SuperbReplace(ThisComponent, &quot;@[gGnq]@&quot;, &quot;&quot;, 0)
-
-end sub
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Main" script:language="StarBasic">Option Explicit
+
+Function HaveSelection(doc As Object)
+       Dim sel as Object
+       sel = doc.CurrentController.Selection
+       If sel.Count &gt; 1 Then
+               HaveSelection = True
+               Exit Function
+       End If
+       Dim s0
+       s0 = sel.getByIndex(0)
+       If s0.Text.compareRegionStarts(s0.Start, s0.End) = 0 Then
+               HaveSelection = False
+       Else
+               HaveSelection = True
+       End If
+End Function
+
+&apos; Regular expression replace in the document, creating superscripts if
+&apos; superb &gt; 0 or subscripts if superb &lt; 0.
+Sub SuperbReplace(doc As Object, searchRegex As String, replacePattern As String, superb As Integer)
+
+       Dim rd As Object
+       rd = doc.createReplaceDescriptor()
+
+       rd.SearchCaseSensitive = true
+       rd.SearchRegularExpression = true
+       rd.setSearchString(searchRegex)
+       rd.setReplaceString(replacePattern)
+
+       If superb &lt;&gt; 0 Then
+               Dim replaceAttrs(1) As New com.sun.star.beans.PropertyValue
+               replaceAttrs(0).Name = &quot;CharEscapement&quot;
+               If superb &gt; 0 Then
+                       replaceAttrs(0).Value = 33
+               Else
+                       &apos; The default escapement for subscripts is -33, which looked bad to me in
+                       &apos; chemical formulas.  This looks better.  Modify to your taste.
+                       replaceAttrs(0).Value = -9
+               End If
+               replaceAttrs(1).Name = &quot;CharEscapementHeight&quot;
+               replaceAttrs(1).Value = 58
+               rd.setReplaceAttributes(replaceAttrs)
+       End If
+
+       doc.replaceAll(rd)
+
+End Sub
+
+Sub ReplaceInSelection(doc As Object, searchRegex As String, replacePattern As String)
+
+       Dim frame As Object, dispatcher As Object
+       frame = doc.CurrentController.Frame
+       dispatcher = createUnoService(&quot;com.sun.star.frame.DispatchHelper&quot;)
+
+       Dim args(6) As New com.sun.star.beans.PropertyValue
+       args(0).Name = &quot;SearchItem.AlgorithmType&quot;
+       args(0).Value = 1
+       args(1).Name = &quot;SearchItem.SearchFlags&quot;
+       args(1).Value = &amp;H1800  &apos; Search in selection
+       args(2).Name = &quot;SearchItem.SearchString&quot;
+       args(2).Value = searchRegex
+       args(3).Name = &quot;SearchItem.ReplaceString&quot;
+       args(3).Value = replacePattern
+       args(4).Name = &quot;SearchItem.Command&quot;
+       args(4).Value = 3
+       args(5).Name = &quot;SearchItem.AlgorithmType2&quot;
+       args(5).Value = 2
+       args(6).Name = &quot;Quiet&quot;
+       args(6).Value = true
+
+       dispatcher.executeDispatch(frame, &quot;.uno:ExecuteSearch&quot;, &quot;&quot;, 0, args())
+
+End Sub
+
+Global formatSelectionWarningShown As Boolean
+&apos; I haven&apos;t found a way to initialize the variable, but it looks like its
+&apos; default value is treated as false in an if statement.
+&apos;formatSelectionWarningShown = False
+
+Sub FormatSelectionOrDocumentDebug()
+       &apos; Replacing with an empty replacement string triggers a bug in LibreOffice
+       &apos; (https://bugs.documentfoundation.org/show_bug.cgi?id=136577), so we must
+       &apos; avoid it.  Fortunately, avoiding it is pretty straightforward.
+
+       &apos; Insert @m@ between an item and a number or charge.
+       If HaveSelection(ThisComponent) Then
+               &apos; doc.replaceAll is not capable of searching a selection, while the
+               &apos; dispatch-based replace API uses the current format options in the
+               &apos; &quot;Find &amp; Replace&quot; dialog and does not let us change them, which means that
+               &apos; (1) existing settings can break things and (2) we cannot make superscripts
+               &apos; and subscripts.  We do the best we can by using one dispatch-based replace
+               &apos; to tag all the sequences we want to operate on (which loses the selection in
+               &apos; OpenOffice anyway) and then proceed with replaceAll calls on the whole
+               &apos; document, which will only operate on the already tagged sequences.
+               If Not formatSelectionWarningShown Then
+                       MsgBox &quot;Due to limitations in the OpenOffice/LibreOffice API, the &quot; &amp; _
+                               &quot;&quot;&quot;Format selection&quot;&quot; command may not process some chemical formulas &quot; &amp; _
+                               &quot;in the selection or may apply incorrect formatting if any format &quot; &amp; _
+                               &quot;options are active in the &quot;&quot;Find &amp; Replace&quot;&quot; dialog box.  If this &quot; &amp; _
+                               &quot;happens, just undo the command (if any changes were made), clear the &quot; &amp; _
+                               &quot;format options in the &quot;&quot;Find &amp; Replace&quot;&quot; dialog box (focus the &quot; &amp; _
+                               &quot;&quot;&quot;Find&quot;&quot; field, click &quot;&quot;No Format&quot;&quot;, and repeat for the &quot;&quot;Replace&quot;&quot; &quot; &amp; _
+                               &quot;field), and run &quot;&quot;Format selection&quot;&quot; again.&quot; &amp; Chr$(13) &amp; Chr$(13) &amp; _
+                               &quot;This message is always shown on the first &quot;&quot;Format selection&quot;&quot; &quot; &amp; _
+                               &quot;command in each OpenOffice/LibreOffice session because &quot; &amp; _
+                               &quot;SuperbChemistry has no way to detect whether format options are &quot; &amp; _
+                               &quot;active in &quot;&quot;Find &amp; Replace&quot;&quot;.&quot;, _
+                               0, &quot;SuperbChemistry &quot;&quot;Format selection&quot;&quot; notice&quot;
+                       formatSelectionWarningShown = True
+               End If
+               ReplaceInSelection(ThisComponent, &quot;(?&lt;=[A-Z][a-z]?|[\])}])[-+−0-9]+&quot;, &quot;@m@&amp;&quot;)
+       Else
+               SuperbReplace(ThisComponent, &quot;(?&lt;=[A-Z][a-z]?|[\])}])[-+−0-9]+&quot;, &quot;@m@&amp;&quot;, 0)
+       End If
+
+       &apos; Insert @c@ after a charge.
+       SuperbReplace(ThisComponent, &quot;(?&lt;=@m@)([0-9]*[-+−])(?=[ \t\])}.,:;?!&apos;&quot;&quot;]|$)&quot;, &quot;&amp;@c@&quot;, 0)
+
+       &apos; Real minus signs in charges.
+       SuperbReplace(ThisComponent, &quot;-@c@&quot;, &quot;−@c@&quot;, 0)
+
+       &apos; Some groups grab a single following digit as a quantity rather than a charge amount.
+       &apos; Insert @sq@ marker to prevent the charge from grabbing the digit.
+       SuperbReplace(ThisComponent, &quot;(?&lt;=(H|O|F|Cl|Br|I|[\])}])@m@)[0-9]&quot;, &quot;&amp;@sq@&quot;, 0)
+
+       &apos; Each charge grabs at most one digit and moves the @c@ in front to prevent the
+       &apos; quantity from grabbing the digit.
+       SuperbReplace(ThisComponent, &quot;([0-9]?[−+])@c@&quot;, &quot;@c@$1&quot;, 1)
+
+       &apos; Remove any @sq@ markers so items can grab all the digits that follow for the quantity.
+       SuperbReplace(ThisComponent, &quot;(.)@sq@&quot;, &quot;$1&quot;, 0)
+
+       &apos; At this point, we have only @m@ and @c@ markers left.
+
+       &apos; Format quantities: as many digits as we can still grab.
+       &apos; We have to allow @ as a following character for our own @c@ tag.
+       SuperbReplace(ThisComponent, &quot;(?&lt;=@m@)[0-9]+(?=[@A-Z \t\])}.,:;?!&apos;&quot;&quot;]|$)&quot;, &quot;&amp;&quot;, -1)
+
+       &apos; Clean up @c@ markers.  We know there is a charge sign after each.
+       SuperbReplace(ThisComponent, &quot;@c@(.)&quot;, &quot;$1&quot;, 0)
+
+       &apos; Clean up @m@ markers.  We know there is some character before each.
+       SuperbReplace(ThisComponent, &quot;(.)@m@&quot;, &quot;$1&quot;, 0)
+
+End Sub
+
+Dim madeChanges As Boolean
+
+Sub UndoListener_undoActionAdded()
+End Sub
+Sub UndoListener_actionUndone()
+End Sub
+Sub UndoListener_actionRedone()
+End Sub
+Sub UndoListener_allActionsCleared()
+End Sub
+Sub UndoListener_redoActionsCleared()
+End Sub
+Sub UndoListener_resetAll()
+End Sub
+Sub UndoListener_enteredContext()
+End Sub
+Sub UndoListener_enteredHiddenContext()
+End Sub
+Sub UndoListener_leftContext()
+       madeChanges = True
+End Sub
+Sub UndoListener_leftHiddenContext()
+End Sub
+Sub UndoListener_cancelledContext()
+End Sub
+
+Sub FormatSelectionOrDocument()
+
+       Dim undoActionName As String
+       If HaveSelection(ThisComponent) Then
+               undoActionName = &quot;SuperbChemistry: Format selection&quot;
+       Else
+               undoActionName = &quot;SuperbChemistry: Format document&quot;
+       End If
+       ThisComponent.UndoManager.enterUndoContext(undoActionName)
+
+       On Error Goto ErrorHandler
+       FormatSelectionOrDocumentDebug
+       On Error Goto 0
+
+       ThisComponent.UndoManager.leaveUndoContext()
+       Exit Sub
+
+ErrorHandler:
+
+       &apos; If our undo context is nonempty, we want to undo the generated action.
+       &apos; If not, we do not want to undo as that would undo the user&apos;s previous
+       &apos; action.  If we just check whether the title of the last undoable action
+       &apos; is &quot;SuperbChemistry: Format (selection|document)&quot;, that might be wrong if
+       &apos; the user ran FormatDocument twice in a row: probably unlikely, but the
+       &apos; completely correct check is not that hard.
+       Dim listener As Object
+       listener = CreateUnoListener(&quot;UndoListener_&quot;, &quot;com.sun.star.document.XUndoManagerListener&quot;)
+       madeChanges = False
+       ThisComponent.UndoManager.addUndoManagerListener(listener)
+       ThisComponent.UndoManager.leaveUndoContext()
+       ThisComponent.UndoManager.removeUndoManagerListener(listener)
+       If madeChanges Then
+               ThisComponent.UndoManager.undo()
+               ThisComponent.UndoManager.clearRedo()
+       End If
+
+       MsgBox &quot;SuperbChemistry encountered an unexpected error:&quot; &amp; Chr$(13) &amp; Chr$(13) &amp; _
+               &quot;Code &quot; &amp; Err &amp; &quot;: &quot; &amp; Error$ &amp; Chr$(13) &amp; Chr$(13) &amp; _
+               &quot;Any changes made so far have been undone.&quot; &amp; Chr$(13) &amp; Chr$(13) &amp; _
+               &quot;SuperbChemistry needed to catch the error in order to leave your undo &quot; &amp; _
+               &quot;history in a consistent state.  If the problem is reproducible and you &quot; &amp; _
+               &quot;want to see the precise error location, run the FormatDocumentOrSelectionDebug &quot; &amp; _
+               &quot;macro, but be advised that it may generate multiple entries in the undo &quot; &amp; _
+               &quot;history and will not undo them on error.&quot;, _
+               0, &quot;SuperbChemistry internal error&quot;
+       On Error Goto 0
+End Sub
 
 </script:module>
\ No newline at end of file
index 8d924f4..7609d23 100644 (file)
@@ -1,3 +1,3 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd">
-<library:library xmlns:library="http://openoffice.org/2000/library" library:name="SuperbChemistry" library:readonly="false" library:passwordprotected="false"/>
\ No newline at end of file
+<library:library xmlns:library="http://openoffice.org/2000/library" library:name="SuperbChemistry" library:readonly="true" library:passwordprotected="false"/>
\ No newline at end of file
index 815dca2..c3d89f3 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd">
-<library:library xmlns:library="http://openoffice.org/2000/library" library:name="SuperbChemistry" library:readonly="false" library:passwordprotected="false">
+<library:library xmlns:library="http://openoffice.org/2000/library" library:name="SuperbChemistry" library:readonly="true" library:passwordprotected="false">
  <library:element library:name="Main"/>
 </library:library>
\ No newline at end of file
diff --git a/extension/description.xml b/extension/description.xml
new file mode 100644 (file)
index 0000000..7ca5367
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<description
+ xmlns="http://openoffice.org/extensions/description/2006"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+  <identifier value="net.mattmccutchen.superbchemistry"/>
+  <version value="3.0"/>
+  <publisher>
+    <name xlink:href="https://mattmccutchen.net/superbchemistry/">Matt McCutchen</name>
+  </publisher>
+  <display-name>
+    <name>SuperbChemistry</name>
+  </display-name>
+  <extension-description>
+    <src xlink:href="extension-description.txt"/>
+  </extension-description>
+</description>
diff --git a/extension/extension-description.txt b/extension/extension-description.txt
new file mode 100644 (file)
index 0000000..c9b4c2e
--- /dev/null
@@ -0,0 +1 @@
+Applies superscript and subscript formatting to chemical formulas in bulk in Writer documents.
\ No newline at end of file