mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-07 10:16:03 -10:00
Spell check: fewer false typos (programming terms, British spellings, possessives) (#113)
* feat(spell): Fewer false typos: programming terms, British spellings, possessives - Bundle ~8.7k programming terms, tool and library names from cspell-dicts (MIT), plus a hand-kept list of tool names, file names and abbreviations. These pass on their own but never as part of an identifier compound. - Accept en_GB spellings (colour, behaviour, normalise, cancelled) alongside en_US. - Possessives of known words pass (backend's); programming terms take -ed / -ing / -able endings (stringified, memoizing). - Plurals of terms no longer accept doubled or already-inflected forms (filess, contextes, checkings), and agent nouns aren't built from abbreviations (perfer). - A word split from a known term is checked as the whole term (IntelliJ, PostgreSQL). - Settings › Natural Languages lists English (USA, UK). * chore: Regenerate bindings
This commit is contained in:
1 parent
44b021392a
commit
75b5f6f972
10 files changed
+10447
-43
No files matched your search
+12
-2
@@ -79,15 +79,25 @@ user's app-data directory only when the user asks; none of them ships with OpenI
|
||||
unmodified, and its source is available from the repository above.
|
||||
- **Eclipse JDT Language Server** (jdtls): EPL-2.0, from download.eclipse.org.
|
||||
|
||||
## en_US Hunspell dictionary
|
||||
## en_US / en_GB Hunspell dictionaries
|
||||
|
||||
`crates/ide-spell/src/dict/en_US.{aff,dic}` (the spell checker's bundled dictionary) is the
|
||||
SCOWL-derived en_US Hunspell dictionary (version 2020.12.07, from the `dictionary-en` npm
|
||||
package 4.0.0), copied unmodified. Copyright Kevin Atkinson and the SCOWL / Hunspell
|
||||
dictionary contributors; MIT- and BSD-style licences, full text in
|
||||
`crates/ide-spell/src/dict/LICENSE-en_US`. It is checked with the
|
||||
`crates/ide-spell/src/dict/LICENSE-en_US`. `crates/ide-spell/src/dict/en_GB-extra.dic` holds the
|
||||
entries of the matching en_GB dictionary (`dictionary-en-gb` npm package 3.0.0, same SCOWL
|
||||
version, licence and affix file) that en_US lacks. They are checked with the
|
||||
[spellbook](https://github.com/helix-editor/spellbook) crate (MPL-2.0).
|
||||
|
||||
## cspell-dicts word lists
|
||||
|
||||
`crates/ide-spell/src/dict/cspell-terms.txt` (programming terms the spell checker accepts)
|
||||
is derived from the software-terms, typescript, node, rust, fullstack, golang, java, cpp,
|
||||
shell and css dictionaries of [cspell-dicts](https://github.com/streetsidesoftware/cspell-dicts)
|
||||
(October 2026): lowercased, filtered and merged by OpenIDEA. Copyright Street Side Software;
|
||||
MIT licence, full text in `crates/ide-spell/src/dict/LICENSE-cspell-dicts`.
|
||||
|
||||
## nvim-treesitter queries
|
||||
|
||||
`crates/ide-syntax/queries/<grammar>/locals.scm` are derived from the `locals.scm`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ide-spell"
|
||||
description = "Spell checking (Proofreading › Typo): word extraction from comments, strings and declared names, Hunspell en_US dictionary, user dictionaries"
|
||||
description = "Spell checking (Proofreading › Typo): word extraction from comments, strings and declared names, Hunspell en_US / en_GB dictionary, programming terms, user dictionaries"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017-2025 Street Side Software <[email protected]>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,246 @@
|
||||
# Tool and file names, abbreviations and words common in code the other lists lack.
|
||||
# Accepted on their own, never as part of a compound (`conf` would pass `conflift`).
|
||||
# One lowercase word per line; checked case-insensitively.
|
||||
accel
|
||||
acked
|
||||
adoc
|
||||
adoptium
|
||||
allman
|
||||
askpass
|
||||
assignees
|
||||
avif
|
||||
basedpyright
|
||||
bytea
|
||||
canceller
|
||||
cand
|
||||
cands
|
||||
cjs
|
||||
closable
|
||||
clsx
|
||||
codelldb
|
||||
colima
|
||||
commitish
|
||||
condvar
|
||||
conf
|
||||
conftest
|
||||
conns
|
||||
cte
|
||||
ctes
|
||||
cts
|
||||
customizations
|
||||
dap
|
||||
ddl
|
||||
debuggee
|
||||
decapitalize
|
||||
deemphasize
|
||||
defmodule
|
||||
desync
|
||||
dialogs
|
||||
dic
|
||||
disassembler
|
||||
dists
|
||||
dlsym
|
||||
dlv
|
||||
dnd
|
||||
dup
|
||||
emmet
|
||||
envrc
|
||||
eslintrc
|
||||
expando
|
||||
exs
|
||||
fallbacks
|
||||
fixup
|
||||
fori
|
||||
gdscript
|
||||
gdshader
|
||||
gfm
|
||||
gitattributes
|
||||
gitoxide
|
||||
gix
|
||||
glyphs
|
||||
gomod
|
||||
gopath
|
||||
gopls
|
||||
goroot
|
||||
gpgsign
|
||||
gradle
|
||||
gradlew
|
||||
graphql
|
||||
guice
|
||||
hamcrest
|
||||
haspopup
|
||||
hcl
|
||||
hotswap
|
||||
htdocs
|
||||
hxx
|
||||
ideavimrc
|
||||
ime
|
||||
inflight
|
||||
inlines
|
||||
inplace
|
||||
integrations
|
||||
intelephense
|
||||
interp
|
||||
inv
|
||||
ipynb
|
||||
jacoco
|
||||
javac
|
||||
javaw
|
||||
javax
|
||||
jdt
|
||||
jdtls
|
||||
jdwp
|
||||
jenkinsfile
|
||||
jre
|
||||
jsdom
|
||||
jshell
|
||||
jsonl
|
||||
kapt
|
||||
kotlinc
|
||||
kts
|
||||
labelledby
|
||||
latencies
|
||||
lcov
|
||||
lemminx
|
||||
lexically
|
||||
lezer
|
||||
linkify
|
||||
lldb
|
||||
lockb
|
||||
logpoint
|
||||
logpoints
|
||||
lombok
|
||||
lossily
|
||||
lossy
|
||||
mapleader
|
||||
matview
|
||||
memmem
|
||||
menlo
|
||||
menuitemcheckbox
|
||||
mjs
|
||||
msvc
|
||||
mts
|
||||
mvn
|
||||
mvnw
|
||||
natively
|
||||
nextest
|
||||
nocapture
|
||||
nodelay
|
||||
nonmatching
|
||||
noopener
|
||||
noreferrer
|
||||
noremap
|
||||
notif
|
||||
notnull
|
||||
nvm
|
||||
ord
|
||||
osgi
|
||||
pathing
|
||||
pdm
|
||||
pipfile
|
||||
pred
|
||||
preds
|
||||
prunable
|
||||
psvm
|
||||
publickey
|
||||
pwa
|
||||
pyc
|
||||
pycache
|
||||
pyenv
|
||||
pyi
|
||||
pylsp
|
||||
pyvenv
|
||||
recency
|
||||
recents
|
||||
redb
|
||||
redecl
|
||||
reformats
|
||||
reinstalls
|
||||
rekey
|
||||
replit
|
||||
rerunnable
|
||||
rescan
|
||||
restorable
|
||||
retarget
|
||||
rfind
|
||||
rollup
|
||||
rsplit
|
||||
rsplitn
|
||||
rss
|
||||
rst
|
||||
runserver
|
||||
sbt
|
||||
scm
|
||||
sdkman
|
||||
segs
|
||||
sel
|
||||
severities
|
||||
shorthands
|
||||
sig
|
||||
sigil
|
||||
solarized
|
||||
sout
|
||||
specta
|
||||
splitn
|
||||
storable
|
||||
stty
|
||||
subclassed
|
||||
subsequence
|
||||
subsequences
|
||||
subtest
|
||||
subtests
|
||||
supabase
|
||||
sym
|
||||
syms
|
||||
taplo
|
||||
tauri
|
||||
tcpip
|
||||
tcsh
|
||||
temurin
|
||||
texlab
|
||||
tgz
|
||||
timescaledb
|
||||
timestamptz
|
||||
toks
|
||||
topo
|
||||
tpl
|
||||
tsdk
|
||||
tsv
|
||||
unclosed
|
||||
unformatted
|
||||
unlisten
|
||||
unmarking
|
||||
unmatch
|
||||
unminimize
|
||||
unqueue
|
||||
unshelve
|
||||
unsplit
|
||||
unsub
|
||||
unsubs
|
||||
untag
|
||||
untagged
|
||||
uptime
|
||||
vcs
|
||||
vendored
|
||||
vimrc
|
||||
visibilities
|
||||
vite
|
||||
vitest
|
||||
vmargs
|
||||
volar
|
||||
vsix
|
||||
vtsls
|
||||
wasi
|
||||
wasmtime
|
||||
webflux
|
||||
webmanifest
|
||||
wip
|
||||
xcrun
|
||||
xdebug
|
||||
zig
|
||||
zlogin
|
||||
zls
|
||||
zprofile
|
||||
zshenv
|
||||
zshrc
|
||||
zustand
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+143
-36
@@ -1,6 +1,6 @@
|
||||
//! Spell checking for IDEA's "Proofreading › Typo" inspection: words of
|
||||
//! comments, string literals and declared names (regions come from the
|
||||
//! syntax layer), checked against the bundled en_US Hunspell dictionary, a
|
||||
//! syntax layer), checked against the bundled en_US / en_GB Hunspell dictionary, a
|
||||
//! list of programming terms and the user's accepted words and dictionaries.
|
||||
//! Regular agent nouns of known words (`checkpointer`) pass everywhere; in
|
||||
//! identifiers so do closed compounds of known words (`codebase`).
|
||||
@@ -98,12 +98,17 @@ impl SpellScope {
|
||||
/// At most this many typos are reported per text.
|
||||
pub const MAX_TYPOS: usize = 2000;
|
||||
|
||||
/// The en_GB entries en_US lacks (`colour`, `behaviour`, `normalise`), in the
|
||||
/// same affix scheme: either spelling passes.
|
||||
const EN_GB_EXTRA: &str = include_str!("dict/en_GB-extra.dic");
|
||||
|
||||
/// The en_US dictionary plus [`EN_GB_EXTRA`].
|
||||
fn english() -> &'static spellbook::Dictionary {
|
||||
static DICT: OnceLock<spellbook::Dictionary> = OnceLock::new();
|
||||
DICT.get_or_init(|| {
|
||||
let aff = include_str!("dict/en_US.aff");
|
||||
let dic = include_str!("dict/en_US.dic");
|
||||
spellbook::Dictionary::new(aff, dic).expect("bundled en_US dictionary parses")
|
||||
let dic = format!("{}{EN_GB_EXTRA}", include_str!("dict/en_US.dic"));
|
||||
spellbook::Dictionary::new(aff, &dic).expect("bundled en dictionary parses")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -114,6 +119,7 @@ fn lemmas() -> &'static HashSet<&'static str> {
|
||||
include_str!("dict/en_US.dic")
|
||||
.lines()
|
||||
.skip(1)
|
||||
.chain(EN_GB_EXTRA.lines())
|
||||
.map(|l| l.split('/').next().unwrap_or(l).trim())
|
||||
.filter(|w| !w.is_empty() && w.chars().all(|c| c.is_ascii_lowercase()))
|
||||
.collect()
|
||||
@@ -136,13 +142,12 @@ fn doubles_final_consonant(stem: &str) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether dropping one letter or swapping two adjacent ones gives a dictionary
|
||||
/// Whether dropping one letter or swapping two adjacent ones gives a `known`
|
||||
/// word: then a compound (`writ`+`ting`) is more likely a typo of
|
||||
/// it (`writing`), as Hunspell's CHECKCOMPOUNDREP reasons.
|
||||
fn near_word(lower: &str) -> bool {
|
||||
fn near_word(lower: &str, known: impl Fn(&str) -> bool) -> bool {
|
||||
let b = lower.as_bytes();
|
||||
let dict = english();
|
||||
let check = |v: &[u8]| std::str::from_utf8(v).is_ok_and(|w| dict.check(w));
|
||||
let check = |v: &[u8]| std::str::from_utf8(v).is_ok_and(&known);
|
||||
(0..b.len()).any(|i| check(&[&b[..i], &b[i + 1..]].concat()))
|
||||
|| (0..b.len().saturating_sub(1)).any(|i| {
|
||||
let mut v = b.to_vec();
|
||||
@@ -151,23 +156,41 @@ fn near_word(lower: &str) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
fn software_terms() -> &'static HashSet<&'static str> {
|
||||
fn term_list(text: &'static str) -> HashSet<&'static str> {
|
||||
text.lines().map(str::trim).filter(|l| !l.is_empty() && !l.starts_with('#')).collect()
|
||||
}
|
||||
|
||||
/// Hand-picked programming terms: short ones (`url`) may be part of a compound.
|
||||
fn curated_terms() -> &'static HashSet<&'static str> {
|
||||
static TERMS: OnceLock<HashSet<&'static str>> = OnceLock::new();
|
||||
TERMS.get_or_init(|| term_list(include_str!("dict/software.txt")))
|
||||
}
|
||||
|
||||
/// Imported programming terms, tool and library names, and abbreviations:
|
||||
/// never part of a compound.
|
||||
fn other_terms() -> &'static HashSet<&'static str> {
|
||||
static TERMS: OnceLock<HashSet<&'static str>> = OnceLock::new();
|
||||
TERMS.get_or_init(|| {
|
||||
include_str!("dict/software.txt")
|
||||
.lines()
|
||||
.map(str::trim)
|
||||
.filter(|l| !l.is_empty() && !l.starts_with('#'))
|
||||
.collect()
|
||||
let mut terms = term_list(include_str!("dict/cspell-terms.txt"));
|
||||
terms.extend(term_list(include_str!("dict/code-words.txt")));
|
||||
terms
|
||||
})
|
||||
}
|
||||
|
||||
/// A software term, or its plural (`endpoints`, `regexes`).
|
||||
fn term(lower: &str) -> bool {
|
||||
curated_terms().contains(lower) || other_terms().contains(lower)
|
||||
}
|
||||
|
||||
/// A software term, or the plural of one Hunspell doesn't know (`endpoints`,
|
||||
/// `regexes`; not `filess`, `contextes`, `checkings`). [`other_terms`] need
|
||||
/// 4+ letters for that (`acses` stays flagged).
|
||||
fn software_term(lower: &str) -> bool {
|
||||
let terms = software_terms();
|
||||
terms.contains(lower)
|
||||
|| lower.strip_suffix('s').is_some_and(|w| terms.contains(w))
|
||||
|| lower.strip_suffix("es").is_some_and(|w| terms.contains(w))
|
||||
let plural_of = |w: &str| (curated_terms().contains(w) || w.len() >= MIN_PART && term(w)) && !english().check(w);
|
||||
term(lower)
|
||||
|| lower.strip_suffix('s').is_some_and(|w| !w.ends_with('s') && plural_of(w))
|
||||
|| lower
|
||||
.strip_suffix("es")
|
||||
.is_some_and(|w| ["s", "x", "z", "ch", "sh"].iter().any(|e| w.ends_with(e)) && plural_of(w))
|
||||
}
|
||||
|
||||
/// Words of a custom dictionary file: a plain word list or a Hunspell `.dic`
|
||||
@@ -224,11 +247,15 @@ impl Speller {
|
||||
|
||||
/// Whether `word` (of prose, a comment or a string) is spelt correctly.
|
||||
/// Case is forgiven the way identifiers need it: `url` passes for `URL`,
|
||||
/// `paris` for `Paris`. Regular agent nouns of known words pass too
|
||||
/// (`checkpointer`, `serializers`).
|
||||
/// `paris` for `Paris`. Possessives (`backend's`), regular agent nouns
|
||||
/// (`checkpointer`, `serializers`) and `-ed` / `-ing` / `-able` forms of
|
||||
/// programming terms (`stringified`) pass too.
|
||||
pub fn is_correct(&self, word: &str) -> bool {
|
||||
if let Some(base) = word.strip_suffix("'s") {
|
||||
return self.is_correct(base);
|
||||
}
|
||||
let lower = word.to_lowercase();
|
||||
self.listed(word, &lower) || self.agent_noun(&lower)
|
||||
self.listed(word, &lower) || self.agent_noun(&lower) || self.term_form(&lower)
|
||||
}
|
||||
|
||||
/// [`Self::is_correct`] for a part of an identifier, which may also be two
|
||||
@@ -261,30 +288,63 @@ impl Speller {
|
||||
let singular = lower.strip_suffix('s').unwrap_or(lower);
|
||||
let Some(before_r) = singular.strip_suffix('r') else { return false };
|
||||
let Some(before_er) = before_r.strip_suffix('e') else { return false };
|
||||
// (stem, root the `-or` noun would be built on)
|
||||
let mut stems = vec![(before_r.to_string(), before_er)];
|
||||
let mut stems = vec![before_r.to_string()];
|
||||
if let Some(y) = before_er.strip_suffix('i') {
|
||||
stems.push((format!("{y}y"), before_er));
|
||||
stems.push(format!("{y}y"));
|
||||
} else if !before_er.ends_with('e') && !doubles_final_consonant(before_er) {
|
||||
stems.push((before_er.to_string(), before_er));
|
||||
stems.push(before_er.to_string());
|
||||
}
|
||||
stems.into_iter().any(|(stem, root)| {
|
||||
stem.len() >= MIN_PART
|
||||
&& (lemmas().contains(stem.as_str()) || self.user_word(&stem))
|
||||
&& !english().check(&format!("{root}or"))
|
||||
})
|
||||
let or_noun = format!("{before_er}or");
|
||||
stems
|
||||
.into_iter()
|
||||
.any(|stem| stem.len() >= MIN_PART && (lemmas().contains(stem.as_str()) || self.term_stem(&stem)))
|
||||
&& !self.listed(&or_noun, &or_noun)
|
||||
}
|
||||
|
||||
/// A programming term or accepted word of 5+ letters Hunspell doesn't know
|
||||
/// (`stringify`; not `calls` or `calc`), to derive other words from.
|
||||
fn term_stem(&self, s: &str) -> bool {
|
||||
s.len() > MIN_PART && self.user_word(s) && !english().check(s)
|
||||
}
|
||||
|
||||
/// `<term>ed` / `<term>ing` / `<term>able` of a programming term or an
|
||||
/// accepted word of 5+ letters: `stringified` (stringify), `memoizing`
|
||||
/// (memoize), `upserted`. Dictionary words only take the endings Hunspell
|
||||
/// knows: `falled`, `quiting` stay flagged. Not when one letter off a known
|
||||
/// word (`preprocesssing`).
|
||||
fn term_form(&self, lower: &str) -> bool {
|
||||
if !lower.bytes().all(|c| c.is_ascii_lowercase()) {
|
||||
return false;
|
||||
}
|
||||
let stem = |s: &str| self.term_stem(s);
|
||||
let derived = ["ed", "ing", "able"].into_iter().any(|suffix| {
|
||||
let Some(root) = lower.strip_suffix(suffix) else { return false };
|
||||
let b = root.as_bytes();
|
||||
(stem(root) && !doubles_final_consonant(root))
|
||||
|| stem(&format!("{root}e"))
|
||||
|| (suffix != "ing" && root.strip_suffix('i').is_some_and(|y| stem(&format!("{y}y"))))
|
||||
|| (b.len() > 2 && b[b.len() - 1] == b[b.len() - 2] && stem(&root[..root.len() - 1]))
|
||||
});
|
||||
derived && !near_word(lower, |w| english().check(w) || self.user_word(w))
|
||||
}
|
||||
|
||||
/// Two known words run together, each at least [`MIN_PART`] letters (or a
|
||||
/// 3-letter programming term: `urlpath`). Proper nouns don't count.
|
||||
/// hand-picked or accepted 3-letter term: `urlpath`). Proper nouns and
|
||||
/// [`other_terms`] don't count (`guid` + `lines` would pass `guidlines`).
|
||||
fn compound(&self, lower: &str) -> bool {
|
||||
if lower.len() < 6 || !lower.bytes().all(|c| c.is_ascii_lowercase()) || NOT_COMPOUNDS.contains(&lower) {
|
||||
return false;
|
||||
}
|
||||
let part = |p: &str| {
|
||||
(p.len() >= 3 && self.user_word(p)) || (p.len() >= MIN_PART && (english().check(p) || self.agent_noun(p)))
|
||||
let known = |p: &str| {
|
||||
self.accepted.contains(p) || curated_terms().contains(p) || self.custom.iter().any(|d| d.contains(p))
|
||||
};
|
||||
(3..=lower.len() - 3).any(|i| part(&lower[..i]) && part(&lower[i..])) && !near_word(lower)
|
||||
let part = |p: &str| match p.len() {
|
||||
0..3 => false,
|
||||
3 => known(p),
|
||||
_ => known(p) || english().check(p) || self.agent_noun(p),
|
||||
};
|
||||
(3..=lower.len() - 3).any(|i| part(&lower[..i]) && part(&lower[i..]))
|
||||
&& !near_word(lower, |w| english().check(w))
|
||||
}
|
||||
|
||||
/// Replacements for `word`, best first, in the word's case style.
|
||||
@@ -301,6 +361,14 @@ impl Speller {
|
||||
out
|
||||
}
|
||||
|
||||
/// Whether the letter run `w` was split from is a known term as a whole:
|
||||
/// `IntelliJ` (`Intelli` + `J`), `PostgreSQL` (`Postgre` + `SQL`).
|
||||
fn known_run(&self, text: &str, w: &WordSpan) -> bool {
|
||||
let start = text[..w.start].rfind(|c: char| !c.is_alphabetic()).map_or(0, |i| i + 1);
|
||||
let end = text[w.end..].find(|c: char| !c.is_alphabetic()).map_or(text.len(), |i| w.end + i);
|
||||
(start, end) != (w.start, w.end) && self.user_word(&text[start..end].to_lowercase())
|
||||
}
|
||||
|
||||
/// Misspelt words of `regions` (document order) in `text`; `None` when
|
||||
/// `cancelled` fires.
|
||||
pub fn check(&self, text: &str, regions: &[Region], cancelled: &dyn Fn() -> bool) -> Option<Vec<Typo>> {
|
||||
@@ -319,7 +387,7 @@ impl Speller {
|
||||
let ok = *verdicts
|
||||
.entry((word, name))
|
||||
.or_insert_with(|| if name { self.is_correct_identifier(word) } else { self.is_correct(word) });
|
||||
if !ok {
|
||||
if !ok && !self.known_run(text, w) {
|
||||
bad.push((*w, r.kind));
|
||||
}
|
||||
}
|
||||
@@ -451,6 +519,45 @@ mod tests {
|
||||
for ok in ["breakpoint", "breakpoints", "endpoints", "datasets", "regexes"] {
|
||||
assert!(s.is_correct(ok), "{ok}");
|
||||
}
|
||||
for ok in
|
||||
["stringify", "instanceof", "keydown", "submenu", "truthy", "vitest", "gradle", "unstaged", "rebasing"]
|
||||
{
|
||||
assert!(s.is_correct(ok), "{ok}");
|
||||
}
|
||||
for bad in ["filess", "contextes", "checkings", "acses"] {
|
||||
assert!(!s.is_correct(bad), "{bad}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn british_spellings() {
|
||||
let s = Speller::default();
|
||||
for ok in ["colour", "behaviours", "normalised", "centred", "analyse", "cancelled", "dialogs"] {
|
||||
assert!(s.is_correct(ok), "{ok}");
|
||||
}
|
||||
for bad in ["colur", "behavour", "normalsed"] {
|
||||
assert!(!s.is_correct(bad), "{bad}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_terms_checked_whole() {
|
||||
let s = Speller::default();
|
||||
let text = "// Open IntelliJ or PostgreSQL, not Intelli alone";
|
||||
let words: Vec<_> =
|
||||
s.check(text, &whole(text, RegionKind::Comment), &|| false).unwrap().into_iter().map(|t| t.word).collect();
|
||||
assert_eq!(words, ["Intelli"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn possessives_and_term_forms() {
|
||||
let s = Speller::default();
|
||||
for ok in ["backend's", "commit's", "stringified", "memoizing", "upserted"] {
|
||||
assert!(s.is_correct(ok), "{ok}");
|
||||
}
|
||||
for bad in ["recieve's", "falled", "quiting", "preprocesssing", "perfer", "callser"] {
|
||||
assert!(!s.is_correct(bad), "{bad}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -471,7 +578,7 @@ mod tests {
|
||||
for ok in ["filepath", "dataframe", "username", "codebase", "pathname", "urlpath", "timestampfile"] {
|
||||
assert!(s.is_correct_identifier(ok), "{ok}");
|
||||
}
|
||||
assert!(!s.is_correct("dataframe"));
|
||||
assert!(!s.is_correct("timestampfile"));
|
||||
for bad in ["eachother", "everytime", "publically", "mesage", "lenght", "recieve", "comming", "withold"] {
|
||||
assert!(!s.is_correct_identifier(bad), "{bad}");
|
||||
}
|
||||
|
||||
+1
-1
@@ -1073,7 +1073,7 @@ export type AgentTask = {
|
||||
branch: string | null,
|
||||
/** Branch (or revision) the worktree was created from. */
|
||||
base: string | null,
|
||||
/** Commit the task's changes are compared against. */
|
||||
/** Commit the task's changes are compared against (worktree tasks; local ones use `HEAD`). */
|
||||
baseCommit: string | null,
|
||||
/** Why the task failed, when it did. */
|
||||
error: string | null,
|
||||
|
||||
@@ -15,7 +15,10 @@ import styles from "../../components/Form.module.css";
|
||||
function NaturalLanguagesPage() {
|
||||
return (
|
||||
<Section title="Languages">
|
||||
<Row label="English (USA)" hint="Bundled Hunspell dictionary (SCOWL en_US) and common programming terms.">
|
||||
<Row
|
||||
label="English (USA, UK)"
|
||||
hint="Bundled Hunspell dictionaries (SCOWL en_US and en_GB) and common programming terms."
|
||||
>
|
||||
<span className={styles.hint}>
|
||||
<T>Used by Proofreading › Typo</T>
|
||||
</span>
|
||||
|
||||
@@ -3014,8 +3014,8 @@
|
||||
"Reports tables, columns and aliases in query consoles that the data source's schema does not contain.": "报告查询控制台中数据源架构不包含的表、列和别名。",
|
||||
"Proofreading": "校对",
|
||||
"Reports misspelt words in comments, string literals and the names declarations introduce (camelCase and snake_case parts checked separately), and in plain text and Markdown. Agent nouns of known words (checkpointer) and, in names, two known words run together (filepath) are accepted. Words can be saved to the project or application dictionary (Editor › Natural Languages › Spelling). Correcting a name renames the symbol and its references.": "报告注释、字符串字面量和声明引入的名称(camelCase 和 snake_case 的各部分分别检查)以及纯文本和 Markdown 中拼写错误的单词。已知单词的施动名词(checkpointer)以及名称中连写的两个已知单词(filepath)视为正确。单词可以保存到项目词典或应用程序词典(编辑器 › 自然语言 › 拼写)。更正名称会重命名该符号及其引用。",
|
||||
"English (USA)": "英语(美国)",
|
||||
"Bundled Hunspell dictionary (SCOWL en_US) and common programming terms.": "捆绑的 Hunspell 词典 (SCOWL en_US) 和常用编程术语。",
|
||||
"English (USA, UK)": "英语(美国、英国)",
|
||||
"Bundled Hunspell dictionaries (SCOWL en_US and en_GB) and common programming terms.": "捆绑的 Hunspell 词典 (SCOWL en_US 和 en_GB) 和常用编程术语。",
|
||||
"Used by Proofreading › Typo": "由“校对 › 拼写错误”使用",
|
||||
"Accepted words": "已接受的单词",
|
||||
"Project dictionary": "项目词典",
|
||||
|
||||
Reference in new issue
Block a user