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
54 changes: 30 additions & 24 deletions generate_espanso.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,17 +177,19 @@ def generate_pack(words, title, desc, include_accents=True):
for word in sorted(set(words)):
if len(word) < 3:
continue
for typo in sorted(generate_all_typos(word, include_accents)):
if typo in seen:
continue
seen.add(typo)
lines.append(f" - trigger: {esc(typo)}")
lines.append(f" replace: {esc(word)}")
if not any(c in word for c in 'àèéìòù'):
lines.append(" propagate_case: true")
lines.append(" word: true")
lines.append("")
total += 1
typos = sorted(t for t in generate_all_typos(word, include_accents) if t not in seen)
if not typos:
continue
seen.update(typos)
lines.append(" - triggers:")
for typo in typos:
lines.append(f' - {esc(typo)}')
lines.append(f" replace: {esc(word)}")
if not any(c in word for c in 'àèéìòù'):
lines.append(" propagate_case: true")
lines.append(" word: true")
lines.append("")
total += len(typos)
return '\n'.join(lines), total


Expand All @@ -196,20 +198,23 @@ def generate_accenti_pack():
ACCENTI_WORDS, "Accenti",
"Missing accents, future tense verbs, -ità nouns"
)
short_groups = [
(["e'", "e1"], "è"),
(["si'", "si1"], "sì"),
(["la'", "la1"], "là"),
(["li'", "li1"], "lì"),
]
short_lines = [
" # Short accented words (too short for the auto-generator)",
]
for trigger, replace in [
("e'", "è"), ("e1", "è"),
("si'", "sì"), ("si1", "sì"),
("la'", "là"), ("la1", "là"),
("li'", "lì"), ("li1", "lì"),
]:
short_lines.append(f" - trigger: {esc(trigger)}")
for triggers, replace in short_groups:
short_lines.append(" - triggers:")
for t in triggers:
short_lines.append(f' - {esc(t)}')
short_lines.append(f" replace: {esc(replace)}")
short_lines.append(" word: true")
short_lines.append("")
total += 1
total += len(triggers)
return content + '\n' + '\n'.join(short_lines), total


Expand Down Expand Up @@ -350,7 +355,7 @@ def get_version() -> str:
"refuos-italiano": {
"title": "Refuos Italiano",
"description": "Real-time autocorrection for everyday Italian words. Fixes typos like acnhe→anche, comunqeu→comunque.",
"tags": ["italian", "autocorrect", "typo", "italiano"],
"tags": ["italian", "autocorrect", "typo", "italiano", "languages", "spell-correction", "typofixer"],
"readme": textwrap.dedent("""\
# Refuos Italiano

Expand All @@ -364,7 +369,7 @@ def get_version() -> str:
|------------|--------------|
| `acnhe` | `anche` |
| `comunqeu` | `comunque` |
| `perche` | `perché` |
| `probelma` | `problema` |

~2,500 rules in total.

Expand All @@ -376,7 +381,7 @@ def get_version() -> str:
"refuos-accenti": {
"title": "Refuos Accenti",
"description": "Autocorrection for Italian accents, future-tense verbs and -ità nouns. Fixes perche→perché, aggiungero→aggiungerò.",
"tags": ["italian", "autocorrect", "accents", "accenti", "italiano"],
"tags": ["italian", "autocorrect", "accents", "accenti", "italiano", "languages", "spell-correction", "typofixer"],
"readme": textwrap.dedent("""\
# Refuos Accenti

Expand All @@ -402,7 +407,7 @@ def get_version() -> str:
"refuos-dev": {
"title": "Refuos Dev",
"description": "Autocorrection for tech and code terms: HTML, CSS, patterns, paradigms, Git, DevOps, Python and more. Fixes cosnt→const, reutrn→return.",
"tags": ["dev", "autocorrect", "code", "html", "css", "git", "devops", "python", "patterns", "architecture"],
"tags": ["dev", "autocorrect", "code", "html", "css", "git", "devops", "python", "patterns", "architecture", "spell-correction", "typofixer"],
"readme": textwrap.dedent("""\
# Refuos Dev

Expand All @@ -425,7 +430,8 @@ def get_version() -> str:
Framework-agnostic: works for JavaScript, TypeScript, Python, Go, Java,
and any other stack. For framework-specific terms (React hooks, Vue
Composition API, NestJS decorators, Django ORM, etc.) use a local
dictionary — see `dictionaries/local/README.md`.
dictionary — see the [project repository](https://github.com/heavybeard/refuos)
for documentation on local dictionaries.

## Source

Expand Down
35 changes: 18 additions & 17 deletions tests/test_yaml_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ def test_matches_is_non_empty_list(self):
assert len(doc["matches"]) > 0
assert total > 0

def test_every_match_has_trigger_replace_word(self):
def test_every_match_has_triggers_replace_word(self):
content, _ = ge.generate_pack(["anche", "bello"], "Test", "Test pack")
doc = _parse(content)
for match in doc["matches"]:
# every match must have a trigger
assert "trigger" in match, f"Match missing trigger: {match}"
assert "triggers" in match, f"Match missing triggers: {match}"
assert isinstance(match["triggers"], list), f"triggers should be a list: {match}"
assert "replace" in match, f"Match missing replace: {match}"
assert match.get("word") is True, f"Match missing word:true: {match}"

Expand Down Expand Up @@ -77,11 +77,12 @@ def test_short_words_below_3_chars_are_skipped(self):
content, total = ge.generate_pack(["ab"], "Test", "Short words")
assert total == 0

def test_total_matches_actual_rules_count(self):
def test_total_matches_actual_trigger_count(self):
words = ["anche", "bello", "comunque"]
content, total = ge.generate_pack(words, "Test", "Count check")
doc = _parse(content)
assert len(doc["matches"]) == total
trigger_count = sum(len(m["triggers"]) for m in doc["matches"])
assert trigger_count == total


# ---------------------------------------------------------------------------
Expand All @@ -101,9 +102,9 @@ def test_no_regex_rules(self):
content, _ = ge.generate_accenti_pack()
assert "regex:" not in content

def test_contains_trigger_rules(self):
def test_contains_triggers_rules(self):
content, _ = ge.generate_accenti_pack()
assert "trigger:" in content
assert "triggers:" in content

def test_hardcoded_short_word_rules_present(self):
content, _ = ge.generate_accenti_pack()
Expand Down Expand Up @@ -133,11 +134,11 @@ def test_no_accent_variants_in_triggers(self):
content, _ = ge.generate_dev_pack()
doc = _parse(content)
for match in doc["matches"]:
trigger = match.get("trigger", "")
for ch in ACCENTED_CHARS:
assert ch not in trigger, (
f"Accented char '{ch}' found in dev trigger '{trigger}'"
)
for trigger in match.get("triggers", []):
for ch in ACCENTED_CHARS:
assert ch not in trigger, (
f"Accented char '{ch}' found in dev trigger '{trigger}'"
)


# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -167,8 +168,8 @@ def test_no_accent_variants_in_triggers(self):
content, _ = ge.generate_local_pack("local", ["playwright", "turborepo"])
doc = _parse(content)
for match in doc.get("matches") or []:
trigger = match.get("trigger", "")
for ch in ACCENTED_CHARS:
assert ch not in trigger, (
f"Accented char '{ch}' found in local trigger '{trigger}'"
)
for trigger in match.get("triggers", []):
for ch in ACCENTED_CHARS:
assert ch not in trigger, (
f"Accented char '{ch}' found in local trigger '{trigger}'"
)
Loading