Skip to content
This repository was archived by the owner on Apr 2, 2026. It is now read-only.

Commit ad8510c

Browse files
committed
Add a way to escape double quotes to quoted strings.
1 parent 3fa3ed2 commit ad8510c

2 files changed

Lines changed: 35 additions & 10 deletions

File tree

src/TextReader/TextCommandReader.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,9 @@ it("It can read unbalanced quoteds strings", function () {
119119
expect(readItems.at(0)?.object).toBe('"unbalanced');
120120
expect(readItems.at(1)?.object).toBe("vronut");
121121
});
122+
123+
it("It can read escaped quotes meow", function () {
124+
const commoand = '"\\"hello \\"';
125+
const readItems = readCommand(commoand);
126+
expect(readItems.at(0)?.object).toBe('"hello "');
127+
});

src/TextReader/TextCommandReader.ts

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -292,29 +292,48 @@ function readKeyword(stream: StringStream): Presentation<Keyword> {
292292
defineReadItem("-", readKeywordOrNegativeInteger);
293293
defineReadItem(":", readKeywordOrNegativeInteger);
294294

295-
function maybeReadQuotedString(stream: StringStream): string | undefined {
295+
function maybeReadQuotedString(
296+
stream: StringStream
297+
): Presentation<string> | undefined {
296298
if (stream.peekChar() !== '"') {
297299
return undefined;
298300
}
299301
stream.readChar();
300302
const word: string[] = [];
301-
readUntil(/"/, stream, word);
302-
if (stream.peekChar() === '"') {
303-
stream.readChar();
304-
return word.join("");
305-
} else {
306-
return undefined;
307-
}
303+
do {
304+
readUntil(/"/, stream, word);
305+
if (stream.peekChar() === '"' && word.at(-1) === "\\") {
306+
word.pop();
307+
word.push('"');
308+
stream.readChar();
309+
if (stream.peekChar() === undefined) {
310+
return StringPresentationType.wrap(word.join(""));
311+
} else {
312+
continue;
313+
}
314+
} else if (stream.peekChar() === '"') {
315+
stream.readChar();
316+
// wrap to stop post processing of the string
317+
// which is the reason they are quoting in the first place.
318+
return StringPresentationType.wrap(word.join(""));
319+
} else if (stream.peekChar() === undefined) {
320+
// the only reason we don't error here is because we don't have the infrastructure
321+
// for how reader errors will work and not look confusing as shit.
322+
return undefined;
323+
}
324+
// eslint-disable-next-line no-constant-condition
325+
} while (true);
308326
}
309327

310-
function readString(stream: StringStream): string {
328+
function readString(stream: StringStream): string | Presentation<string> {
311329
const quotedString = stream.savingPositionIf({
312330
predicate: (t) => t === undefined,
313331
body: (stream) => maybeReadQuotedString(stream as StringStream),
314332
});
315333
if (quotedString !== undefined) {
316-
return quotedString as string;
334+
return quotedString as Presentation<string>;
317335
} else {
336+
// we want these to be transformable read items.
318337
return readWord(stream);
319338
}
320339
}

0 commit comments

Comments
 (0)