Skip to content

Commit

Permalink
fix: (cspell) Mark forbidden and no suggest words (#2302)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason3S committed Jan 23, 2022
1 parent 1794be2 commit c474cec
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 55 deletions.
6 changes: 6 additions & 0 deletions cspell-ignore-words.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
!fuck
# Prevent suggesting these words
crap
shit
flagger
flaggy
12 changes: 11 additions & 1 deletion cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@
"description": "Custom Workspace Dictionary",
"addWords": true,
"scope": "workspace"
},
{
"name": "ignore words",
"path": "./cspell-ignore-words.txt",
"description": "Words to be Ignored",
"addWords": true,
"noSuggest": true
}
],
"dictionaries": [
"workspace"
"workspace",
"ignore words"
],
"ignorePaths": [
".eslintignore",
Expand All @@ -27,6 +35,7 @@
".yarn",
"*.{png,jpg,pdf}",
"/cspell-dict.txt",
"/cspell-ignore-words.txt",
"**/.gitignore",
"**/.vscode/**",
"**/{cspell.*,cSpell.*,.cspell.*,cspell.config.*}",
Expand All @@ -53,6 +62,7 @@
"test-packages/test-cspell-tools/src/*.txt"
],
"useGitignore": true,
"flagWords": [],
"ignoreWords": [
"commitcomment"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ describe('Validate Normalize Settings', () => {
describe('Validate Dependencies', () => {
test.each`
filename | relativeTo | expected
${r('../../cspell.config.json')} | ${undefined} | ${{ configFiles: [r(root, 'cspell.json'), r('../../cspell.config.json')], dictionaryFiles: [r(root, 'cspell-dict.txt')] }}
${r('../../cspell.config.json')} | ${undefined} | ${{ configFiles: [r(root, 'cspell.json'), r('../../cspell.config.json')], dictionaryFiles: [r(root, 'cspell-dict.txt'), r(root, 'cspell-ignore-words.txt')] }}
`('tests readSettings $filename $relativeTo', ({ filename, relativeTo, expected }) => {
const settings = readSettings(filename, relativeTo);
const dependencies = extractDependencies(settings);
Expand Down
46 changes: 30 additions & 16 deletions packages/cspell-lib/src/suggestions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import type { CSpellSettings, LocaleId } from '@cspell/cspell-types';
import { LanguageId } from './LanguageIds';
import { finalizeSettings, getDefaultSettings, getGlobalSettings, mergeSettings } from './Settings';
import { calcSettingsForLanguageId } from './Settings/LanguageSettings';
import type { SuggestionResult, SuggestOptions } from './SpellingDictionary';
import { getDictionary, SpellingDictionaryCollection } from './SpellingDictionary';
import type { FindOptions, SuggestionResult, SuggestOptions } from './SpellingDictionary';
import { getDictionary, SpellingDictionaryCollection, refreshDictionaryCache } from './SpellingDictionary';
import * as util from './util/util';

export interface SuggestedWord extends SuggestionResult {
interface SuggestedWordBase extends SuggestionResult {
dictionaries: string[];
}
export interface SuggestedWord extends SuggestedWordBase {
noSuggest: boolean;
forbidden: boolean;
}

export interface SuggestionsForWordResult {
word: string;
Expand Down Expand Up @@ -92,8 +96,9 @@ export async function suggestionsForWord(
} = options || {};
const ignoreCase = !strict;

async function finalize(config: CSpellSettings): Promise<{
async function determineDictionaries(config: CSpellSettings): Promise<{
dictionaryCollection: SpellingDictionaryCollection;
allDictionaryCollection: SpellingDictionaryCollection;
}> {
const withLocale = mergeSettings(config, {
language: language || config.language,
Expand All @@ -104,37 +109,46 @@ export async function suggestionsForWord(
languageId ?? withLocale.languageId ?? 'plaintext'
);
const settings = finalizeSettings(withLanguageId);

settings.dictionaries = dictionaries?.length ? dictionaries : settings.dictionaries;

validateDictionaries(settings, dictionaries);

const dictionaryCollection = await getDictionary(settings);
settings.dictionaries = settings.dictionaryDefinitions?.map((def) => def.name) || [];
const allDictionaryCollection = await getDictionary(settings);
return {
dictionaryCollection,
allDictionaryCollection,
};
}

const config = includeDefaultConfig ? mergeSettings(getDefaultSettings(), getGlobalSettings(), settings) : settings;

const { dictionaryCollection } = await finalize(config);
await refreshDictionaryCache();

const config = includeDefaultConfig ? mergeSettings(getDefaultSettings(), getGlobalSettings(), settings) : settings;
const { dictionaryCollection, allDictionaryCollection } = await determineDictionaries(config);
const opts: SuggestOptions = { ignoreCase, numChanges, numSuggestions, includeTies };

const allResults = dictionaryCollection.dictionaries.map((dict) =>
const suggestionsByDictionary = dictionaryCollection.dictionaries.map((dict) =>
dict.suggest(word, opts).map((r) => ({ ...r, dictName: dict.name }))
);

const allSugs = combine(util.flatten(allResults).sort((a, b) => a.cost - b.cost || (a.word <= b.word ? -1 : 1)));
const combined = combine(
util.flatten(suggestionsByDictionary).sort((a, b) => a.cost - b.cost || (a.word <= b.word ? -1 : 1))
);
const findOpts: FindOptions = {};
const allSugs = combined.map((sug) => {
const found = allDictionaryCollection.find(sug.word, findOpts);
return {
...sug,
forbidden: found?.forbidden || false,
noSuggest: found?.noSuggest || false,
};
});

return {
word,
suggestions: limitResults(allSugs, numSuggestions, includeTies),
};
}

function combine(suggestions: { word: string; cost: number; dictName: string }[]): SuggestedWord[] {
const words: Map<string, SuggestedWord> = new Map();
function combine(suggestions: { word: string; cost: number; dictName: string }[]): SuggestedWordBase[] {
const words: Map<string, SuggestedWordBase> = new Map();

for (const sug of suggestions) {
const { word, cost, dictName } = sug;
Expand Down
5 changes: 3 additions & 2 deletions packages/cspell-lib/src/trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { genSequence } from 'gensequence';
import { LanguageId } from './LanguageIds';
import { finalizeSettings, mergeSettings } from './Settings';
import { calcSettingsForLanguageId } from './Settings/LanguageSettings';
import { getDictionary, HasOptions, SpellingDictionaryCollection } from './SpellingDictionary';
import { getDictionary, HasOptions, refreshDictionaryCache, SpellingDictionaryCollection } from './SpellingDictionary';
import * as util from './util/util';

export interface TraceResult {
Expand Down Expand Up @@ -73,8 +73,9 @@ export async function* traceWordsAsync(
dicts,
};
}
const { config, dicts, activeDictionaries } = await finalize(settings);

await refreshDictionaryCache();
const { config, dicts, activeDictionaries } = await finalize(settings);
const setOfActiveDicts = new Set(activeDictionaries);
const opts: HasOptions = { ignoreCase, useCompounds: config.allowCompoundWords };

Expand Down
54 changes: 28 additions & 26 deletions packages/cspell/src/__snapshots__/app.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -561,14 +561,14 @@ exports[`Validate cli app suggest ["sug", "--stdin", "-d=en_us", "-v"] 1`] = `Ar
exports[`Validate cli app suggest ["sug", "--stdin", "-d=en_us", "-v"] 2`] = `
"mexico
- Mexico - 1 en_us
- medico - 97 en_us
- Mexico's - 186 en_us
- Mexican - 188 en_us
- medicos - 190 en_us
- medick - 191 en_us
- medics - 191 en_us
- metics - 191 en_us"
- Mexico - 1 en_us
- medico - 97 en_us
- Mexico's - 186 en_us
- Mexican - 188 en_us
- medicos - 190 en_us
- medick - 191 en_us
- medics - 191 en_us
- metics - 191 en_us"
`;
exports[`Validate cli app suggest ["sug", "--stdin", "-d=en_us", "-v"] 3`] = `""`;
Expand All @@ -577,8 +577,8 @@ exports[`Validate cli app suggest ["sug", "dutch", "--dictionaries=en_us", "--di
exports[`Validate cli app suggest ["sug", "dutch", "--dictionaries=en_us", "--dictionary=en-gb", "-v", "--num-suggestions=2"] 2`] = `
"dutch
- dutch - 0 en-gb, en_us
- Dutch - 1 en_us"
- dutch - 0 en-gb, en_us
- Dutch - 1 en_us"
`;
exports[`Validate cli app suggest ["sug", "dutch", "--dictionaries=en_us", "--dictionary=en-gb", "-v", "--num-suggestions=2"] 3`] = `""`;
Expand All @@ -587,8 +587,8 @@ exports[`Validate cli app suggest ["sug", "dutch", "--dictionaries=en_us", "-v",
exports[`Validate cli app suggest ["sug", "dutch", "--dictionaries=en_us", "-v", "--num-suggestions=2"] 2`] = `
"dutch
- dutch - 0 en_us
- Dutch - 1 en_us"
- dutch - 0 en_us
- Dutch - 1 en_us"
`;
exports[`Validate cli app suggest ["sug", "dutch", "--dictionaries=en_us", "-v", "--num-suggestions=2"] 3`] = `""`;
Expand All @@ -597,8 +597,8 @@ exports[`Validate cli app suggest ["sug", "dutch", "--dictionaries=en_us", "-v",
exports[`Validate cli app suggest ["sug", "dutch", "--dictionaries=en_us", "-v", "--num-suggestions=2"] 5`] = `
"dutch
- dutch - 0 en_us
- Dutch - 1 en_us"
- dutch - 0 en_us
- Dutch - 1 en_us"
`;
exports[`Validate cli app suggest ["sug", "dutch", "--dictionaries=en_us", "-v", "--num-suggestions=2"] 6`] = `""`;
Expand All @@ -607,8 +607,8 @@ exports[`Validate cli app suggest ["sug", "dutch", "-d=en_us", "-d=en-gb", "-v",
exports[`Validate cli app suggest ["sug", "dutch", "-d=en_us", "-d=en-gb", "-v", "--num-suggestions=2"] 2`] = `
"dutch
- dutch - 0 en-gb, en_us
- Dutch - 1 en_us"
- dutch - 0 en-gb, en_us
- Dutch - 1 en_us"
`;
exports[`Validate cli app suggest ["sug", "dutch", "-d=en_us", "-d=en-gb", "-v", "--num-suggestions=2"] 3`] = `""`;
Expand All @@ -626,14 +626,14 @@ exports[`Validate cli app suggest ["sug", "mexico", "-d=en_us", "-v"] 1`] = `Arr
exports[`Validate cli app suggest ["sug", "mexico", "-d=en_us", "-v"] 2`] = `
"mexico
- Mexico - 1 en_us
- medico - 97 en_us
- Mexico's - 186 en_us
- Mexican - 188 en_us
- medicos - 190 en_us
- medick - 191 en_us
- medics - 191 en_us
- metics - 191 en_us"
- Mexico - 1 en_us
- medico - 97 en_us
- Mexico's - 186 en_us
- Mexican - 188 en_us
- medicos - 190 en_us
- medick - 191 en_us
- medics - 191 en_us
- metics - 191 en_us"
`;
exports[`Validate cli app suggest ["sug", "mexico", "-d=en_us", "-v"] 3`] = `""`;
Expand Down Expand Up @@ -703,8 +703,10 @@ Array [
" that have the same edit cost.",
" --stdin Use stdin for input.",
" -v, --verbose Show detailed output. (default: 0)",
" -d, --dictionary <dictionary name> Use dictionary.",
" --dictionaries <dictionary names...> Use dictionaries",
" -d, --dictionary <dictionary name> Use the dictionary specified. Only",
" dictionaries specified will be used.",
" --dictionaries <dictionary names...> Use the dictionaries specified. Only",
" dictionaries specified will be used.",
" --no-color Turn off color.",
" --color Force color",
" -h, --help display help for command",
Expand Down
11 changes: 9 additions & 2 deletions packages/cspell/src/commandSuggestion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,15 @@ export function commandSuggestion(prog: Command): Command {
)
.option('--stdin', 'Use stdin for input.')
.option('-v, --verbose', 'Show detailed output.', count, 0)
.option('-d, --dictionary <dictionary name>', 'Use dictionary.', collect)
.option('--dictionaries <dictionary names...>', 'Use dictionaries')
.option(
'-d, --dictionary <dictionary name>',
'Use the dictionary specified. Only dictionaries specified will be used.',
collect
)
.option(
'--dictionaries <dictionary names...>',
'Use the dictionaries specified. Only dictionaries specified will be used.'
)
.option('--no-color', 'Turn off color.')
.option('--color', 'Force color')
.arguments('[words...]')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`suggestionsEmitter emitSuggestionResult walk {"cost": 0, "dictionaries": [Array], "forbidden": false, "noSuggest": false, "word": "walk"} {"cost": 2, "dictionaries": [Array], "forbidden": false, "noSuggest": false, "word": "walked"} {"verbose": 1} 1`] = `
"walk
- walk - 0 dict-a
- walked - 2 dict-a"
`;

exports[`suggestionsEmitter emitSuggestionResult walk {"cost": 0, "dictionaries": [Array], "forbidden": false, "noSuggest": false, "word": "walk"} {"cost": 2, "dictionaries": [Array], "forbidden": false, "noSuggest": false, "word": "walked"} {} 1`] = `
"walk
- walk
- walked"
`;

exports[`suggestionsEmitter emitSuggestionResult walk {"cost": 0, "dictionaries": [Array], "forbidden": false, "noSuggest": false, "word": "walk"} {"cost": 2, "dictionaries": [Array], "forbidden": false, "noSuggest": true, "word": "walked"} {"verbose": 1} 1`] = `
"walk
- walk - 0 dict-a
- walked N - 2 dict-a"
`;

exports[`suggestionsEmitter emitSuggestionResult walk {"cost": 0, "dictionaries": [Array], "forbidden": false, "noSuggest": false, "word": "walk"} {"cost": 2, "dictionaries": [Array], "forbidden": true, "noSuggest": false, "word": "walked"} {"verbose": 1} 1`] = `
"walk
- walk - 0 dict-a
- walked X - 2 dict-a"
`;

exports[`suggestionsEmitter emitSuggestionResult walk {"cost": 0, "dictionaries": [Array], "forbidden": false, "noSuggest": false, "word": "walk"} {"cost": 2, "dictionaries": [Array], "forbidden": true, "noSuggest": true, "word": "walked"} {"verbose": 1} 1`] = `
"walk
- walk - 0 dict-a
- walked XN - 2 dict-a"
`;
35 changes: 35 additions & 0 deletions packages/cspell/src/emitters/suggestionsEmitter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { emitSuggestionResult, EmitSuggestionOptions } from './suggestionsEmitter';
import type { SuggestedWord } from 'cspell-lib';
import chalk = require('chalk');

chalk.level = 0;

describe('suggestionsEmitter', () => {
test.each`
word | sug1 | sug2 | options
${'walk'} | ${sw('walk', 0)} | ${sw('walked', 2)} | ${opts({})}
${'walk'} | ${sw('walk', 0)} | ${sw('walked', 2)} | ${opts({ verbose: 1 })}
${'walk'} | ${sw('walk', 0)} | ${sw('walked', 2, { noSuggest: true })} | ${opts({ verbose: 1 })}
${'walk'} | ${sw('walk', 0)} | ${sw('walked', 2, { forbidden: true })} | ${opts({ verbose: 1 })}
${'walk'} | ${sw('walk', 0)} | ${sw('walked', 2, { forbidden: true, noSuggest: true })} | ${opts({ verbose: 1 })}
`('emitSuggestionResult $word $sug1 $sug2 $options', ({ word, sug1, sug2, options }) => {
const log = jest.fn();
const sr = {
word,
suggestions: [sug1, sug2].filter((a) => !!a),
};

emitSuggestionResult(sr, opts(options, { output: { log } }));

expect(log.mock.calls.join('\n')).toMatchSnapshot();
});
});

function opts(a: Partial<EmitSuggestionOptions>, b: Partial<EmitSuggestionOptions> = {}): EmitSuggestionOptions {
return { ...a, ...b };
}

function sw(word: string, cost: number, s: Partial<SuggestedWord> = {}): SuggestedWord {
const { dictionaries = ['dict-a'], noSuggest = false, forbidden = false } = s;
return { word, cost, dictionaries, noSuggest, forbidden };
}
Loading

0 comments on commit c474cec

Please sign in to comment.