Skip to content

Commit 7cd648a

Browse files
committed
Fixed all argument readings
1 parent 1bc6bec commit 7cd648a

File tree

1 file changed

+80
-50
lines changed

1 file changed

+80
-50
lines changed

CSharpMath.Rendering/Text/TextBuilder.cs

Lines changed: 80 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public static Result<TextAtom> Build(string latex) {
4444
StringBuilder mathLaTeX = null;
4545
bool backslashEscape = false;
4646
bool afterCommand = false; //ignore spaces after command
47+
bool afterNewline = false;
4748
int dollarCount = 0;
4849
var globalAtoms = new TextAtomListBuilder();
4950
var breaker = new CustomBreaker { BreakNumberAfterText = true, ThrowIfCharOutOfRange = false };
@@ -93,27 +94,34 @@ Result CheckDollarCount(TextAtomListBuilder atoms) {
9394
}
9495
return Ok();
9596
}
96-
Result<int> BuildBreakList(TextAtomListBuilder atoms, int i, bool oneCharOnly) {
97+
Result<int> BuildBreakList(TextAtomListBuilder atoms, int i, bool oneCharOnly, char stopChar) {
98+
void ParagraphBreak() {
99+
atoms.Break(3);
100+
#warning Should the newline and space occupy the same range?
101+
atoms.TextLength -= 3;
102+
atoms.Add(Space.ParagraphIndent, 3);
103+
}
97104
for (; i < breakList.Count; i++) {
98-
(int startAt, int endAt, char endingChar, WordKind wordKind) ObtainRange(int index) =>
99-
(index == 0 ? 0 : breakList[index - 1].breakAt, breakList[index].breakAt, latex[breakList[index].breakAt - 1], breakList[index].wordKind);
100-
var (startAt, endAt, endingChar, wordKind) = ObtainRange(i);
105+
(int startAt, int endAt, string textSection, WordKind wordKind) ObtainRange(int index) {
106+
var (start, end) = (index == 0 ? 0 : breakList[index - 1].breakAt, breakList[index].breakAt);
107+
return (start, end, latex.Substring(start, end - start), breakList[index].wordKind);
108+
}
109+
var (startAt, endAt, textSection, wordKind) = ObtainRange(i);
101110
bool SetNextRange() {
102111
bool success = ++i < breakList.Count;
103-
if (success) (startAt, endAt, endingChar, wordKind) = ObtainRange(i);
112+
if (success) (startAt, endAt, textSection, wordKind) = ObtainRange(i);
104113
return success;
105114
}
106115
Result<TextAtom> ReadArgumentAtom() {
107116
backslashEscape = false;
108117
var argAtoms = new TextAtomListBuilder();
109-
i++;
110-
BuildBreakList(argAtoms, i, true).Bind(index => i = index);
118+
if(BuildBreakList(argAtoms, ++i, true, '\0').Bind(index => i = index).Error is string error) return error;
111119
return argAtoms.Build();
112120
}
113121
Result<string> ReadArgumentString() {
114122
afterCommand = false;
115123
if (!SetNextRange()) return Err("Missing argument");
116-
if (endingChar != '{') return Err("Missing {");
124+
if (textSection != "{") return Err("Missing {");
117125
int endingIndex = -1;
118126
//startAt + 1 to not start at the { we started at
119127
bool isEscape = false;
@@ -131,9 +139,10 @@ Result<string> ReadArgumentString() {
131139
_ = SetNextRange(); //this never fails because the above check
132140
return Ok(resultText);
133141
}
134-
#warning
135-
//atoms.TextLength = startAt;
136-
if (endingChar == '$') {
142+
143+
atoms.TextLength = startAt;
144+
if (stopChar > 0 && textSection[0] == stopChar) return Ok(i);
145+
if (textSection == "$") {
137146
if (backslashEscape)
138147
if (displayMath != null) mathLaTeX.Append(@"\$");
139148
else atoms.Add("$");
@@ -145,48 +154,71 @@ Result<string> ReadArgumentString() {
145154
} else {
146155
{ if (CheckDollarCount(atoms).Error is string error) return error; }
147156

148-
//Normal unescaped text section, could be in display/inline math mode
149157
if (!backslashEscape) {
150-
var textSection = latex.Substring(startAt, endAt - startAt);
151-
switch (endingChar) {
152-
case '$':
153-
throw new InvalidCodePathException("The $ case should have been accounted for.");
154-
case '\\':
155-
backslashEscape = true;
156-
continue;
157-
case var sp when wordKind == WordKind.Whitespace || wordKind == WordKind.NewLine:
158-
//Collpase spaces
159-
//Consume newlines after commands
160-
if (displayMath == null)
158+
//Unescaped text section, inside display/inline math mode
159+
if(displayMath != null)
160+
switch (textSection) {
161+
case "$":
162+
throw new InvalidCodePathException("The $ case should have been accounted for.");
163+
case "\\":
164+
backslashEscape = true;
165+
continue;
166+
default:
167+
mathLaTeX.Append(textSection);
168+
break;
169+
}
170+
//Unescaped text section, not inside display/inline math mode
171+
else switch (textSection) {
172+
case "$":
173+
throw new InvalidCodePathException("The $ case should have been accounted for.");
174+
case "\\":
175+
backslashEscape = true;
176+
continue;
177+
case "{":
178+
if(BuildBreakList(atoms, ++i, false, '}').Bind(index => i = index).Error is string error) return error;
179+
break;
180+
case "}":
181+
return "Unexpected }, unbalanced braces";
182+
case var _ when wordKind == WordKind.NewLine:
183+
//Consume newlines after commands
184+
//Double newline == paragraph break
185+
if (afterNewline) {
186+
ParagraphBreak();
187+
afterNewline = false;
188+
break;
189+
} else {
190+
atoms.Add();
191+
afterNewline = true;
192+
continue;
193+
}
194+
case var _ when wordKind == WordKind.Whitespace:
195+
//Collpase spaces
161196
if (afterCommand) continue;
162197
else atoms.Add();
163-
else mathLaTeX.Append(textSection);
164-
break;
165-
case var punc when displayMath == null && wordKind == WordKind.Punc && atoms.Last is TextAtom.Text t:
166-
//Append punctuation to text
167-
t.Append(textSection);
168-
break;
169-
default: //Just ordinary text
170-
if (displayMath == null)
198+
break;
199+
case var punc when displayMath == null && wordKind == WordKind.Punc && atoms.Last is TextAtom.Text t:
200+
//Append punctuation to text
201+
t.Append(textSection);
202+
break;
203+
default: //Just ordinary text
171204
if (oneCharOnly) {
172-
if (breakList[i].breakAt < latex.Length) { //don't re-read if we reached the end
173-
breakList[i] = new BreakAtInfo(breakList[i].breakAt + 1, breakList[i].wordKind);
205+
if (startAt + 1 < endAt) { //Only re-read if current break span is more than 1 long
174206
i--;
207+
breakList[i] = new BreakAtInfo(breakList[i].breakAt + 1, breakList[i].wordKind);
175208
}
176209
atoms.Add(textSection[0].ToString());
177210
} else atoms.Add(textSection);
178-
else mathLaTeX.Append(textSection);
179-
break;
180-
}
211+
break;
212+
}
181213
afterCommand = false;
182214
}
183215

184216
//Escaped text section but in inline/display math mode
185217
else if (displayMath != null) {
186-
switch (endingChar) {
187-
case '$':
218+
switch (textSection) {
219+
case "$":
188220
throw new InvalidCodePathException("The $ case should have been accounted for.");
189-
case '(':
221+
case "(":
190222
switch (displayMath) {
191223
case true:
192224
return "Cannot open inline math mode in display math mode";
@@ -195,7 +227,7 @@ Result<string> ReadArgumentString() {
195227
default:
196228
throw new InvalidCodePathException("displayMath is null. This switch should not be hit.");
197229
}
198-
case ')':
230+
case ")":
199231
switch (displayMath) {
200232
case true:
201233
return "Cannot close inline math mode in display math mode";
@@ -209,7 +241,7 @@ Result<string> ReadArgumentString() {
209241
throw new InvalidCodePathException("displayMath is null. This switch should not be hit.");
210242
}
211243
break;
212-
case '[':
244+
case "[":
213245
switch (displayMath) {
214246
case true:
215247
return "Cannot open display math mode in display math mode";
@@ -218,7 +250,7 @@ Result<string> ReadArgumentString() {
218250
default:
219251
throw new InvalidCodePathException("displayMath is null. This switch should not be hit.");
220252
}
221-
case ']':
253+
case "]":
222254
switch (displayMath) {
223255
case true:
224256
if (atoms.Add(mathLaTeX.ToString(), true).Error is string mathError)
@@ -233,15 +265,14 @@ Result<string> ReadArgumentString() {
233265
}
234266
break;
235267
default:
236-
mathLaTeX.Append($@"\{latex.Substring(startAt, endAt - startAt)}");
268+
mathLaTeX.Append($@"\{textSection}");
237269
break;
238270
}
239271
backslashEscape = false;
240272
} else {
241-
242273
//Escaped text section and not in inline/display math mode
243274
afterCommand = true;
244-
switch (latex.Substring(startAt, endAt - startAt)) {
275+
switch (textSection) {
245276
case "(":
246277
mathLaTeX = new StringBuilder();
247278
displayMath = false;
@@ -264,10 +295,7 @@ Result<string> ReadArgumentString() {
264295
atoms.Add();
265296
break;
266297
case "par":
267-
atoms.Break(3);
268-
#warning Should the newline and space occupy the same range?
269-
atoms.TextLength -= 3;
270-
atoms.Add(Space.ParagraphIndent, 3);
298+
ParagraphBreak();
271299
break;
272300
case "fontsize": {
273301
if (ReadArgumentString().Bind(fontSize =>
@@ -340,12 +368,14 @@ Result<string> ReadArgumentString() {
340368
backslashEscape = false;
341369
}
342370
}
371+
afterNewline = false;
343372
if (oneCharOnly) return Ok(i);
344373
}
345374
if (backslashEscape) return @"Unknown command \";
375+
if (stopChar > 0) return $@"Expected {stopChar}";
346376
return Ok(i);
347377
}
348-
{ if (BuildBreakList(globalAtoms, 0, false).Error is string error) return error; }
378+
{ if (BuildBreakList(globalAtoms, 0, false, '\0').Error is string error) return error; }
349379
{ if (CheckDollarCount(globalAtoms).Error is string error) return error; }
350380
if (displayMath != null) return "Math mode was not terminated";
351381
return globalAtoms.Build();

0 commit comments

Comments
 (0)