Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions src/core/domain/grammar/implementations/SpacingRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,6 @@ export class SpacingRule extends SpacingRuleShared implements GrammarRule {
return this.createTechnicalCompactionEdit(":", lastChar, "time or ratio notation");
}

if (
punctChar === "." &&
this.isIdentifierStartChar(lastChar) &&
this.shouldCompactAccessor(inputStr, length - 3)
) {
return this.createTechnicalCompactionEdit(".", lastChar, "code accessor");
}

return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,6 @@ export class TechnicalTokenCompactionRule extends SpacingRuleShared implements G
return this.createEdit(`:${lastChar}`, 3, "Compacted technical time or ratio notation");
}

if (
punctChar === "." &&
this.isIdentifierStartChar(lastChar) &&
this.shouldCompactAccessor(inputStr, length - 3)
) {
return this.createEdit(`.${lastChar}`, 3, "Compacted technical accessor spacing");
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -174,35 +174,6 @@ export abstract class SpacingRuleShared {
return leftSingleIdentifier && rightSingleIdentifier;
}

protected shouldCompactAccessor(inputStr: string, punctIndex: number): boolean {
const tokenEnd = punctIndex - 1;
let tokenStart = tokenEnd;

while (tokenStart >= 0 && this.isIdentifierChar(inputStr[tokenStart])) {
tokenStart -= 1;
}

tokenStart += 1;
if (tokenStart > tokenEnd) {
return false;
}

const previousSignificantIndex = this.findPreviousSignificantIndex(inputStr, tokenStart - 1);
if (previousSignificantIndex === null) {
const token = inputStr.slice(tokenStart, tokenEnd + 1);
return /\d/.test(token) || token.startsWith("$");
}

// Treat cue chars as code context only when tightly attached to the token
// before the dot (e.g. "obj.user. x"), not across sentence whitespace.
if (previousSignificantIndex !== tokenStart - 1) {
return false;
}

const previousSignificant = inputStr[previousSignificantIndex];
return previousSignificant === "." || SpacingRuleShared.CODE_CUE_CHARS.has(previousSignificant);
}

protected isTightlyAttached(inputStr: string, index: number): boolean {
if (index <= 0) {
return false;
Expand Down
18 changes: 9 additions & 9 deletions src/ui/options/fluenttyperI18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1724,15 +1724,15 @@ i18n.extend({
pr: "Compactação de tokens técnicos",
},
grammar_rule_technical_compaction_desc: {
en: "Compacts spaces inside technical tokens such as decimals, times, and code accessors.",
fr: "Supprime les espaces à l'intérieur des éléments techniques tels que décimaux, heures et accesseurs de code.",
hr: "Uklanja razmake unutar tehničkih tokena poput decimala, vremena i pristupnika u kodu.",
es: "Compacta espacios dentro de tokens técnicos como decimales, horas y accesores de código.",
el: "Συμπτύσσει κενά μέσα σε τεχνικά σύμβολα όπως δεκαδικοί αριθμοί, ώρες και προσπελάσεις κώδικα.",
sv: "Tar bort mellanslag i tekniska token som decimaler, tider och kodaccessorer.",
de: "Entfernt Leerzeichen innerhalb technischer Tokens wie Dezimalzahlen, Zeiten und Code-Zugriffen.",
pl: "Usuwa spacje wewnątrz tokenów technicznych, takich jak liczby dziesiętne, godziny i akcesory kodu.",
pr: "Remove espaços dentro de tokens técnicos como decimais, horários e acessores de código.",
en: "Compacts spaces inside numeric tokens such as decimals, times, and ratios.",
fr: "Supprime les espaces à l'intérieur des éléments numériques tels que décimaux, heures et rapports.",
hr: "Uklanja razmake unutar numeričkih tokena poput decimala, vremena i omjera.",
es: "Compacta espacios dentro de tokens numéricos como decimales, horas y proporciones.",
el: "Συμπτύσσει κενά μέσα σε αριθμητικά σύμβολα όπως δεκαδικοί αριθμοί, ώρες και αναλογίες.",
sv: "Tar bort mellanslag i numeriska token som decimaler, tider och förhållanden.",
de: "Entfernt Leerzeichen innerhalb numerischer Tokens wie Dezimalzahlen, Zeiten und Verhältnissen.",
pl: "Usuwa spacje wewnątrz tokenów liczbowych, takich jak liczby dziesiętne, godziny i proporcje.",
pr: "Remove espaços dentro de tokens numéricos como decimais, horários e proporções.",
},
grammar_rule_technical_compaction_example: {
en: 'Example: "3. 14" -> "3.14"',
Expand Down
6 changes: 3 additions & 3 deletions tests/e2e/coverage-matrix.json
Original file line number Diff line number Diff line change
Expand Up @@ -804,17 +804,17 @@
},
{
"id": "grammar_punctuation_spacing",
"description": "Grammar spacing compacts technical punctuation while preserving prose continuation.",
"description": "Grammar spacing compacts numeric punctuation while preserving dotted-word continuation.",
"coverage": [
{
"layer": "e2e-full",
"file": "tests/e2e/full.e2e.test.ts",
"test": "Grammar Rule Engine compacts technical punctuation spacing and preserves prose continuation"
"test": "Grammar Rule Engine compacts numeric punctuation spacing and preserves prose continuation"
},
{
"layer": "unit",
"file": "tests/grammar/V1GrammarRules.test.ts",
"test": "compacts decimal, time/ratio, and accessor spacing conservatively"
"test": "compacts decimal and time/ratio spacing"
}
]
},
Expand Down
19 changes: 14 additions & 5 deletions tests/e2e/full.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5028,7 +5028,7 @@ describeE2E(`Extension E2E Test [${BROWSER_TYPE}]`, () => {
);

test(
"Grammar Rule Engine compacts technical punctuation spacing and preserves prose continuation",
"Grammar Rule Engine compacts numeric punctuation spacing and preserves prose continuation",
async () => {
const selector = "#test-input";

Expand Down Expand Up @@ -5073,16 +5073,25 @@ describeE2E(`Extension E2E Test [${BROWSER_TYPE}]`, () => {
await typeInInput(page, selector, "12:30");
await waitForNormalizedValue("12:30");

await clearInputContent(page, selector);
await typeInInput(page, selector, "cfg_1.x");
await waitForNormalizedValue("cfg_1.x");

await clearInputContent(page, selector);
await typeInInput(page, selector, "Hello.");
await waitForNormalizedValue("Hello. ");
await typeInInput(page, selector, "w");
await waitForNormalizedValue("Hello. w");

await clearInputContent(page, selector);
// Prime an already-authored abbreviation so this isolates typing after its trailing space.
await page.$eval(selector, (element) => {
if (!(element instanceof HTMLInputElement)) {
throw new Error("Expected test input");
}
element.value = "9 a.m. ";
element.focus();
element.setSelectionRange(element.value.length, element.value.length);
});
await typeInInput(page, selector, "and");
await waitForNormalizedValue("9 a.m. and");

await setSettingAndWaitStable(
worker!,
KEY_ENABLED_GRAMMAR_RULES,
Expand Down
35 changes: 8 additions & 27 deletions tests/grammar/SpacingRule.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,35 +289,16 @@ describe("SpacingRule", () => {
});
});

test("compacts conservative accessor contexts with code cues", () => {
expect(ruleA.apply(getContext("obj.cfg_1.\xA0x"))).toEqual({
replacement: ".x",
deleteBackwards: 3,
deleteForwards: 0,
confidence: "high",
description: "Compacted technical punctuation spacing for code accessor",
});

expect(ruleA.apply(getContext("obj.user.\xA0n"))).toEqual({
replacement: ".n",
deleteBackwards: 3,
deleteForwards: 0,
confidence: "high",
description: "Compacted technical punctuation spacing for code accessor",
});

expect(ruleA.apply(getContext("cfg_1.\xA0x"))).toEqual({
replacement: ".x",
deleteBackwards: 3,
deleteForwards: 0,
confidence: "high",
description: "Compacted technical punctuation spacing for code accessor",
});
});

test("does not compact prose continuation without code cues", () => {
test("preserves spacing after dotted words without language-specific detection", () => {
expect(ruleA.apply(getContext("Hello.\xA0w"))).toBeNull();
expect(ruleA.apply(getContext("old_word.\xA0X"))).toBeNull();
expect(ruleA.apply(getContext("Read on.\xA0Duplicate.\xA0W"))).toBeNull();
expect(ruleA.apply(getContext("obj.cfg_1.\xA0x"))).toBeNull();
expect(ruleA.apply(getContext("a.b.\xA0c"))).toBeNull();
expect(ruleA.apply(getContext("return a.b.\xA0c"))).toBeNull();
expect(ruleA.apply(getContext("9 a.m.\xA0a"))).toBeNull();
expect(ruleA.apply(getContext("Use e.g.\xA0examples"))).toBeNull();
expect(ruleA.apply(getContext("Siehe z.B.\xA0examples"))).toBeNull();
expect(ruleA.apply(getContext("Użyj m.in.\xA0examples"))).toBeNull();
});
});
19 changes: 9 additions & 10 deletions tests/grammar/V1GrammarRules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ describe("V1 grammar rules", () => {
});

describe("TechnicalTokenCompactionRule", () => {
test("compacts decimal, time/ratio, and accessor spacing conservatively", () => {
test("compacts decimal and time/ratio spacing", () => {
const rule = new TechnicalTokenCompactionRule(true);

expect(rule.apply(context("3. 1"))).toEqual({
Expand All @@ -298,21 +298,20 @@ describe("V1 grammar rules", () => {
confidence: "high",
description: "Compacted technical time or ratio notation",
});

expect(rule.apply(context("obj.cfg_1. x"))).toEqual({
replacement: ".x",
deleteBackwards: 3,
deleteForwards: 0,
confidence: "high",
description: "Compacted technical accessor spacing",
});
});

test("does not compact prose continuation", () => {
test("preserves spacing after dotted words without language-specific detection", () => {
const rule = new TechnicalTokenCompactionRule(true);
expect(rule.apply(context("Hello. w"))).toBeNull();
expect(rule.apply(context("old_word. X"))).toBeNull();
expect(rule.apply(context("Read on. Duplicate. W"))).toBeNull();
expect(rule.apply(context("obj.cfg_1. x"))).toBeNull();
expect(rule.apply(context("a.b. c"))).toBeNull();
expect(rule.apply(context("return a.b. c"))).toBeNull();
expect(rule.apply(context("9 a.m. a"))).toBeNull();
expect(rule.apply(context("Use e.g. examples"))).toBeNull();
expect(rule.apply(context("Siehe z.B. examples"))).toBeNull();
expect(rule.apply(context("Użyj m.in. examples"))).toBeNull();
});
});

Expand Down
Loading