Skip to content

Commit

Permalink
feat: support displaying suggestions (#881)
Browse files Browse the repository at this point in the history
* feat: support displaying suggestions

* Update app.test.ts.snap
  • Loading branch information
Jason3S committed Jan 22, 2021
1 parent f252dc3 commit e3f207f
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 8 deletions.
60 changes: 60 additions & 0 deletions packages/cspell-lib/src/__snapshots__/validator.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Validator validateText with suggestions 1`] = `
Array [
Object {
"isFlagged": false,
"isFound": false,
"line": Object {
"offset": 1,
"text": " Here is a bit of text witth a feww mistaks.
",
},
"offset": 35,
"suggestions": Array [
"witty",
"witt",
"witch",
"with",
"width",
],
"text": "witth",
},
Object {
"isFlagged": false,
"isFound": false,
"line": Object {
"offset": 1,
"text": " Here is a bit of text witth a feww mistaks.
",
},
"offset": 43,
"suggestions": Array [
"few",
"fewer",
"few's",
"fe's",
"feal",
],
"text": "feww",
},
Object {
"isFlagged": false,
"isFound": false,
"line": Object {
"offset": 1,
"text": " Here is a bit of text witth a feww mistaks.
",
},
"offset": 48,
"suggestions": Array [
"mistake",
"mistakes",
"mistaken",
"mistaker",
"mistake's",
],
"text": "mistaks",
},
]
`;
6 changes: 3 additions & 3 deletions packages/cspell-lib/src/util/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,11 @@ export function stringToRegExp(pattern: string | RegExp, defaultFlags = 'gim', f
return undefined;
}

export function calculateTextDocumentOffsets(
export function calculateTextDocumentOffsets<T extends TextOffset>(
uri: string,
doc: string,
wordOffsets: TextOffset[]
): TextDocumentOffset[] {
wordOffsets: T[]
): (TextDocumentOffset & T)[] {
const lines = [-1, ...match(/\n/g, doc).map((a) => a.index), doc.length];

let lastRow = -1;
Expand Down
11 changes: 11 additions & 0 deletions packages/cspell-lib/src/validator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,17 @@ describe('Validator', () => {
expect(last).toBe(sampleText.length);
});

// cspell:ignore witth feww mistaks
test('validateText with suggestions', async () => {
const text = `
Here is a bit of text witth a feww mistaks.
`;
const languageId = 'plaintext';
const settings = getSettings(text, languageId);
const result = await Validator.validateText(text, settings, { generateSuggestions: true, numSuggestions: 5 });
expect(result).toMatchSnapshot();
});

test('tests calcIncludeExcludeInfo exclude everything', async () => {
const words = sampleWords;
const info = await Validator.checkText(sampleText, {
Expand Down
27 changes: 25 additions & 2 deletions packages/cspell-lib/src/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,36 @@ export const diagSource = 'cSpell Checker';

import { CSpellUserSettings } from './Settings';
import * as TV from './textValidator';
import { CompoundWordsMethod } from './SpellingDictionary';

export { IncludeExcludeOptions } from './textValidator';

export async function validateText(text: string, settings: CSpellUserSettings): Promise<Text.TextOffset[]> {
export interface ValidationIssue extends Text.TextOffset {
suggestions?: string[];
}

export interface ValidateTextOptions {
generateSuggestions?: boolean;
numSuggestions?: number;
}

export async function validateText(
text: string,
settings: CSpellUserSettings,
options: ValidateTextOptions = {}
): Promise<ValidationIssue[]> {
const finalSettings = Settings.finalizeSettings(settings);
const dict = await Dictionary.getDictionary(finalSettings);
return [...TV.validateText(text, dict, finalSettings)];
const issues = [...TV.validateText(text, dict, finalSettings)];
if (!options.generateSuggestions) {
return issues;
}
const withSugs = issues.map((t) => {
const suggestions = dict.suggest(t.text, options.numSuggestions, CompoundWordsMethod.NONE).map((r) => r.word);
return { ...t, suggestions };
});

return withSugs;
}

export interface CheckTextInfo {
Expand Down
1 change: 1 addition & 0 deletions packages/cspell/src/__snapshots__/app.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ Array [
" -r, --root <root folder> Root directory, defaults to current directory.",
" --relative Issues are displayed relative to root.",
" --show-context Show the surrounding text around an issue.",
" --show-suggestions Show spelling suggestions.",
" --must-find-files Error if no files are found (default: true)",
" --no-must-find-files Do not error is no files are found",
" --legacy Legacy output",
Expand Down
11 changes: 10 additions & 1 deletion packages/cspell/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ type TraceOptions = App.TraceOptions;
// interface InitOptions extends Options {}

const templateIssue = `{green $uri}:{yellow $row:$col} - Unknown word ({red $text})`;
const templateIssueWithSuggestions = `{green $uri}:{yellow $row:$col} - Unknown word ({red $text}) Suggestions: {yellow [$suggestions]}`;
const templateIssueWithContext = `{green $uri}:{yellow $row:$col} $padRowCol- Unknown word ({red $text})$padContext -- {gray $contextLeft}{red {underline $text}}{gray $contextRight}`;
const templateIssueWithContextWithSuggestions = `{green $uri}:{yellow $row:$col} $padRowCol- Unknown word ({red $text})$padContext -- {gray $contextLeft}{red {underline $text}}{gray $contextRight}\n\t Suggestions: {yellow [$suggestions]}`;
const templateIssueLegacy = `${chalk.green('${uri}')}[\${row}, \${col}]: Unknown word: ${chalk.red('${text}')}`;
const templateIssueWordsOnly = '${text}';

Expand Down Expand Up @@ -83,7 +85,11 @@ function getEmitters(options: Options): Emitters {
: options.legacy
? templateIssueLegacy
: options.showContext
? templateIssueWithContext
? options.showSuggestions
? templateIssueWithContextWithSuggestions
: templateIssueWithContext
: options.showSuggestions
? templateIssueWithSuggestions
: templateIssue;
const { silent, issues, progress, verbose, debug } = options;

Expand Down Expand Up @@ -156,6 +162,7 @@ export async function run(program?: commander.Command, argv?: string[]): Promise
.option('-r, --root <root folder>', 'Root directory, defaults to current directory.')
.option('--relative', 'Issues are displayed relative to root.')
.option('--show-context', 'Show the surrounding text around an issue.')
.option('--show-suggestions', 'Show spelling suggestions.')
.option('--must-find-files', 'Error if no files are found', true)
.option('--no-must-find-files', 'Do not error is no files are found')
// The following options are planned features
Expand Down Expand Up @@ -387,6 +394,7 @@ function formatIssue(templateStr: string, issue: Issue, maxIssueTextWidth: numbe
const rowText = row.toString();
const colText = col.toString();
const padRowCol = ' '.repeat(Math.max(1, 8 - (rowText.length + colText.length)));
const suggestions = issue.suggestions?.join(', ') || '';
const t = template(templateStr);
return chalk(t)
.replace(/\$\{col\}/g, colText)
Expand All @@ -400,6 +408,7 @@ function formatIssue(templateStr: string, issue: Issue, maxIssueTextWidth: numbe
.replace(/\$padContext/g, padContext)
.replace(/\$padRowCol/g, padRowCol)
.replace(/\$row/g, rowText)
.replace(/\$suggestions/g, suggestions)
.replace(/\$text/g, text)
.replace(/\$uri/g, uri);
}
Expand Down
8 changes: 6 additions & 2 deletions packages/cspell/src/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import {
const UTF8: BufferEncoding = 'utf8';
const STDIN = 'stdin';
const defaultContextRange = 20;

export interface CSpellApplicationOptions extends BaseOptions {
/**
* Display verbose information
Expand Down Expand Up @@ -63,6 +62,10 @@ export interface CSpellApplicationOptions extends BaseOptions {
* if a number, it will shat number of characters on either side.
*/
showContext?: boolean | number;
/**
* Show suggestions for spelling errors.
*/
showSuggestions?: boolean;
}

export type TraceOptions = BaseOptions;
Expand Down Expand Up @@ -179,7 +182,8 @@ function runLint(cfg: CSpellApplicationConfiguration) {
cfg.debug(commentJson.stringify(debugCfg, undefined, 2));
const startTime = Date.now();
try {
const wordOffsets = await cspell.validateText(text, info.configInfo.config);
const validateOptions = { generateSuggestions: cfg.options.showSuggestions, numSuggestions: 5 };
const wordOffsets = await cspell.validateText(text, info.configInfo.config, validateOptions);
result.processed = true;
result.issues = cspell.Text.calculateTextDocumentOffsets(filename, text, wordOffsets).map(mapIssue);
} catch (e) {
Expand Down
1 change: 1 addition & 0 deletions packages/cspell/src/emitters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { TextDocumentOffset, TextOffset } from 'cspell-lib';
export interface Issue extends TextDocumentOffset {
/** text surrounding the issue text */
context: TextOffset;
suggestions?: string[];
}

export type MessageType = 'Debug' | 'Info';
Expand Down

0 comments on commit e3f207f

Please sign in to comment.