Import SuperbChemistry version 2.2
[superbchemistry/superbchemistry.git] / extension / SuperbChemistry / Main.xba
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
3 <script:module xmlns:script="http://openoffice.org/2000/script" script:name="Main" script:language="StarBasic">&apos; SuperbChemistry version 2.2
4 &apos; http://mattmccutchen.net/schem/
5 &apos; Written and maintained by Matt McCutchen &lt;matt@mattmccutchen.net&gt;
6 &apos;
7 &apos; Applies superscript and subscript formatting to chemical formulas in
8 &apos; OpenOffice.org Writer documents.
9 &apos;
10 &apos; Rules:
11 &apos; - Quantities [0-9]+ and charges [0-9]*[-+−] are recognized after an element
12 &apos;   symbol [A-Z][a-z]? or a closing delimiter [\])}] .  Hyphens are converted
13 &apos;   into real minus signs.
14 &apos; - A charge sign [-+−] is ignored if it is followed by a letter, digit,
15 &apos;   opening delimiter, or [&lt;&gt;] .  (Charges should appear only at the end of a
16 &apos;   formula, and we want to avoid matching ordinary hyphens in text.)
17 &apos; - When digits followed by a charge sign are recognized, the last digit
18 &apos;   becomes part of the charge and the remaining digits become the quantity.
19 &apos;   (Charges rarely have absolute value more than 9.)
20 &apos; - In cases like X2-, we have to guess whether the digit is an atom/group
21 &apos;   quantity or a charge amount.  We guess atom/group quantity if X is H (NH4+),
22 &apos;   O (NO3-), a halogen (SbF6-, AlCl4-, etc.), or a closing parenthesis
23 &apos;   (Fe(OH)2+; the group likely would not have been parenthesized unless it had
24 &apos;   a quantity).  Otherwise we guess charge amount (Fe3+).  This heuristic
25 &apos;   should be right most of the time.
26 &apos;
27 &apos; Examples:
28 &apos; C12345 ==&gt; C_{12345}
29 &apos; H+ ==&gt; H^+
30 &apos; Cl- ==&gt; Cl^-
31 &apos; Fe3+ ==&gt; Fe^{3+}
32 &apos; SO42- ==&gt; SO_4^{2-}
33 &apos; C1232+ ==&gt; C_{123}^{2+}
34 &apos; N3- ==&gt; N^{3-}
35 &apos; N|_3^- not recognized (| represents &quot;no-width no break&quot;)
36 &apos; NH4+ ==&gt; NH_4^+
37 &apos; NO3- ==&gt; NO_3^-
38 &apos; AlCl4- =&gt; AlCl_4^-
39 &apos; Fe(OH)2+ ==&gt; Fe(OH)_2^+
40 &apos; O12 ==&gt; O_{12}
41 &apos; y4- not recognized
42 &apos; x2 not recognized
43 &apos; Foo2 not recognized
44 &apos; TI-89 not recognized
45 &apos;
46 &apos; To format the current document, run the FormatDocument macro: go to Tools -&gt;
47 &apos; Macros -&gt;  Run Macro... -&gt; My Macros -&gt; SuperbChemistry -&gt; Main -&gt;
48 &apos; FormatDocument -&gt; Run.  I realize that this is ugly.  I tried to make the
49 &apos; package install a menu item to format the document, but the resulting package
50 &apos; caused OpenOffice.org to crash regularly (I didn&apos;t investigate why), so I
51 &apos; abandoned that idea.  Note that you can add a menu item as a user
52 &apos; customization (Tools -&gt; Customize), and I recommend it if you plan to use
53 &apos; SuperbChemistry frequently.
54 &apos;
55 &apos; FormatDocument uses a sequence of regular expression find-and-replace
56 &apos; operations since that was easy to implement and makes the rules easy to
57 &apos; change.  The operations appear in the undo history, so you can undo a
58 &apos; formatting run by undoing the block of &quot;Replace&quot; entries at the top of the
59 &apos; history.
60 &apos;
61 &apos; I would like to support formatting a selection, but the OpenOffice.org API
62 &apos; does not appear to support replace-all within a selection.  I could find
63 &apos; within the selection and implement the replacing myself, but that is more
64 &apos; work than I want to do.
65 &apos;
66 &apos; If SuperbChemistry makes a mistake (e.g., recognizes a &quot;formula&quot; that isn&apos;t
67 &apos; or formats a formula incorrectly), you can correct the formatting yourself
68 &apos; and prevent future runs of the macro from recognizing the offending text by
69 &apos; inserting a &quot;No-width no break&quot; character in the middle of it.  This character
70 &apos; is available in the &quot;Insert -&gt; Formatting Mark&quot; menu when &quot;Tools -&gt; Options -&gt;
71 &apos; Language Settings -&gt; Languages -&gt; Enhanced language support -&gt;
72 &apos; Enabled for complex text layout (CTL)&quot; is enabled.
73
74 &apos; ==============================================================================
75
76 &apos; Regular expression replace in the document,
77 &apos; creating superscripts if superb &gt; 0 or subscripts if superb &lt; 0.
78 &apos; Used by FormatDocument.
79 sub SuperbReplace(doc as object, searchStr as string, replaceStr as string, superb as integer)
80
81 dim rd as object
82 rd = doc.createReplaceDescriptor()
83
84 rd.SearchCaseSensitive = true
85 rd.SearchRegularExpression = true
86 rd.setSearchString(searchStr)
87 rd.setReplaceString(replaceStr)
88
89 if superb &lt;&gt; 0 then
90         dim replaceAttrs(1) as new com.sun.star.beans.PropertyValue
91         replaceAttrs(0).Name = &quot;CharEscapement&quot;
92         if superb &gt; 0 then
93                 replaceAttrs(0).Value = 33
94         else
95                 replaceAttrs(0).Value = -9
96         end if
97         replaceAttrs(1).Name = &quot;CharEscapementHeight&quot;
98         replaceAttrs(1).Value = 58
99         rd.setReplaceAttributes(replaceAttrs)
100 end if
101
102 doc.replaceAll(rd)
103
104 end sub
105
106 &apos; Formats the current document
107 sub FormatDocument
108
109 &apos; Idiom: Match something and tag it on the left or right with @x@
110 &apos; for further processing.  If the replacement text could use
111 &apos; backreferences, this would be easier.  (I think backreferences were added
112 &apos; since I originally wrote this code, but I see no need to rewrite it to take
113 &apos; advantage of them. - Matt 2008-10-26)
114
115 &apos; Tag candidate charges following symbols or ), but not in compound words, etc.
116 &apos; Acceptable next character.  (Has to be before end of line to avoid matching @g@ tag itself.)
117 SuperbReplace(ThisComponent, &quot;([A-Z][a-z]?|[\])}])[0-9]*[-+−][^[({A-Za-z0-9&lt;&gt;]&quot;, &quot;&amp;@G@&quot;, 0)
118 &apos; Retag in front.
119 SuperbReplace(ThisComponent, &quot;.@G@&quot;, &quot;@g@&amp;&quot;, 0)
120 &apos; End of line.
121 SuperbReplace(ThisComponent, &quot;([A-Z][a-z]?|[\])}])[0-9]*[-+−]$&quot;, &quot;&amp;@g@&quot;, 0)
122
123 &apos; Some groups grab a single following digit as a quantity rather than a charge amount.
124 &apos; See detailed rationale above.
125 SuperbReplace(ThisComponent, &quot;(H|O|F|Cl|Br|I|\))[0-9]&quot;, &quot;&amp;@n@&quot;, 0)
126
127 &apos; Real minus signs in charges.
128 SuperbReplace(ThisComponent, &quot;-@g@&quot;, &quot;−@g@&quot;, 0)
129
130 &apos; Make charges: at most one digit.
131 SuperbReplace(ThisComponent, &quot;[0-9]?[−+]@g@&quot;, &quot;@q@&amp;&quot;, 1)
132
133 &apos; Remove the O and ) markers in case of O57.
134 SuperbReplace(ThisComponent, &quot;@n@&quot;, &quot;&quot;, 0)
135
136 &apos; Tag quantities: as many digits as we can still grab.
137 SuperbReplace(ThisComponent, &quot;([A-Z][a-z]?|[\])}])[0-9]+&quot;, &quot;&amp;@n@&quot;, 0)
138
139 &apos; Make quantities.
140 SuperbReplace(ThisComponent, &quot;[0-9]+@n@&quot;, &quot;&amp;&quot;, -1)
141
142 &apos; Clean up all markers.
143 SuperbReplace(ThisComponent, &quot;@[gGnq]@&quot;, &quot;&quot;, 0)
144
145 end sub
146
147 </script:module>