Skip to content

Commit

Permalink
fix: Improve user experience when creating CSpell config or a custom …
Browse files Browse the repository at this point in the history
…dictionary. (#1131)

* dev: Improve VS Code Jest Mocks
    Support
    - workspace.openTextDocument
    - window.showTextDocument
    - TextEditor
    - TextDocument - unit tests
* dev: scroll to the `cspell` section of `package.json`
* dev: open the newly created dictionary
  • Loading branch information
Jason3S authored Aug 6, 2021
1 parent fff3ebd commit fb86d94
Show file tree
Hide file tree
Showing 18 changed files with 459 additions and 143 deletions.
5 changes: 4 additions & 1 deletion packages/client/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import { mapConfigTargetToClientConfigTarget } from './settings/mappers/configTa
import { configurationTargetToDictionaryScope, dictionaryScopeToConfigurationTarget } from './settings/targetAndScope';
import { catchErrors, handleErrors, handleErrorsEx, logError, onError, OnErrorHandler } from './util/errors';
import { performance, toMilliseconds } from './util/perf';
import { scrollToText } from './util/textEditor';
import { findMatchingDocument } from './vscode/findDocument';

const commandsFromServer: ClientSideCommandHandlerApi = {
Expand Down Expand Up @@ -483,7 +484,9 @@ function fnWTarget<TT>(
async function createCSpellConfig(): Promise<void> {
const uri = await createConfigFileRelativeToDocumentUri(window.activeTextEditor?.document.uri);
if (uri) {
await window.showTextDocument(uri);
const editor = await window.showTextDocument(uri);
// for `package.json` files, we might need to scroll to the right position.
scrollToText(editor, '"cspell":');
}
}

Expand Down
8 changes: 7 additions & 1 deletion packages/client/src/settings/DictionaryHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
CustomDictionaryScope,
DictionaryDefinitionCustom,
} from '../server';
import { scrollToText } from '../util/textEditor';
import { ClientConfigTarget } from './clientConfigTarget';
import { ConfigKeysByField } from './configFields';
import { ConfigRepository, CSpellConfigRepository, VSCodeRepository } from './configRepository';
Expand Down Expand Up @@ -159,7 +160,12 @@ export class DictionaryHelper {
public async createCustomDictionary(cfgRep: ConfigRepository, name?: string): Promise<void> {
const dictInfo = await createCustomDictionaryForConfigRep(cfgRep);
if (!dictInfo) throw new Error('Unable to determine location to create dictionary.');
return this.addCustomDictionaryToConfig(cfgRep, dictInfo.relPath, name || dictInfo.name, dictInfo.scope);
await this.addCustomDictionaryToConfig(cfgRep, dictInfo.relPath, name || dictInfo.name, dictInfo.scope);
if (CSpellConfigRepository.isCSpellConfigRepository(cfgRep)) {
const editor = await vscode.window.showTextDocument(cfgRep.configFileUri, { viewColumn: vscode.ViewColumn.Active });
scrollToText(editor, 'dictionaryDefinitions');
}
await vscode.window.showTextDocument(dictInfo.uri, { viewColumn: vscode.ViewColumn.Beside });
}

/**
Expand Down
1 change: 0 additions & 1 deletion packages/client/src/settings/settings.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { CSpellSettings } from '@cspell/cspell-types';
import { fileExists } from 'common-utils/file.js';
import * as fs from 'fs-extra';
import * as path from 'path';
import * as vscode from 'vscode';
Expand Down
12 changes: 12 additions & 0 deletions packages/client/src/util/textEditor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as vscode from 'vscode';

export function scrollToText(editor: vscode.TextEditor, text: string): boolean {
const doc = editor.document;
const offset = doc.getText().indexOf(text);
if (offset < 0) return false;

const pos = doc.positionAt(offset);
const range = new vscode.Range(pos.line, pos.character, pos.line, pos.character + text.length);
range && editor.revealRange(range, vscode.TextEditorRevealType.InCenterIfOutsideViewport);
return true;
}
104 changes: 0 additions & 104 deletions packages/jest-mock-vscode/src/vscode-mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,6 @@

import type * as vscode from 'vscode';

enum StatusBarAlignment {
Left = 1,
Right = 2,
}

enum ColorThemeKind {
Light = 1,
Dark = 2,
HighContrast = 3,
}

export type Window = typeof vscode.window;
export type CreateStatusBarItemFn = typeof window.createStatusBarItem;
export type Languages = typeof vscode.languages;

export const languages: Languages = {
Expand Down Expand Up @@ -61,59 +48,6 @@ export const languages: Languages = {
setTextDocumentLanguage: jest.fn(),
};

export const window: Window = {
// Attributes
activeColorTheme: { kind: ColorThemeKind.Dark },
activeTerminal: undefined,
activeTextEditor: undefined,
state: { focused: true },
terminals: [],
visibleTextEditors: [],

// Fully mocked methods
createStatusBarItem: jest.fn(createStatusBarItem),

// Partial mocked methods
createInputBox: jest.fn(),
createOutputChannel: jest.fn(),
createQuickPick: jest.fn(),
createTerminal: jest.fn(),
createTextEditorDecorationType: jest.fn(),
createTreeView: jest.fn(),
createWebviewPanel: jest.fn(),
onDidChangeActiveColorTheme: jest.fn(),
onDidChangeActiveTerminal: jest.fn(),
onDidChangeActiveTextEditor: jest.fn(),
onDidChangeTextEditorOptions: jest.fn(),
onDidChangeTextEditorSelection: jest.fn(),
onDidChangeTextEditorViewColumn: jest.fn(),
onDidChangeTextEditorVisibleRanges: jest.fn(),
onDidChangeVisibleTextEditors: jest.fn(),
onDidChangeWindowState: jest.fn(),
onDidCloseTerminal: jest.fn(),
onDidOpenTerminal: jest.fn(),
registerCustomEditorProvider: jest.fn(),
registerFileDecorationProvider: jest.fn(),
registerTerminalLinkProvider: jest.fn(),
registerTerminalProfileProvider: jest.fn(),
registerTreeDataProvider: jest.fn(),
registerUriHandler: jest.fn(),
registerWebviewPanelSerializer: jest.fn(),
registerWebviewViewProvider: jest.fn(),
setStatusBarMessage: jest.fn(),
showErrorMessage: jest.fn(() => Promise.resolve(undefined)),
showInformationMessage: jest.fn(() => Promise.resolve(undefined)),
showInputBox: jest.fn(() => Promise.resolve(undefined)),
showOpenDialog: jest.fn(() => Promise.resolve(undefined)),
showQuickPick: jest.fn(() => Promise.resolve(undefined)),
showSaveDialog: jest.fn(() => Promise.resolve(undefined)),
showTextDocument: jest.fn(),
showWarningMessage: jest.fn(() => Promise.resolve(undefined)),
showWorkspaceFolderPick: jest.fn(() => Promise.resolve(undefined)),
withProgress: jest.fn(),
withScmProgress: jest.fn(),
};

export const OverviewRulerLane = {
Left: null,
};
Expand All @@ -127,42 +61,4 @@ export const commands = {
executeCommand: jest.fn(),
};

function createStatusBarItem(id: string, alignment?: StatusBarAlignment, priority?: number): vscode.StatusBarItem;
function createStatusBarItem(alignment?: StatusBarAlignment, priority?: number): vscode.StatusBarItem;
function createStatusBarItem(
id: string | StatusBarAlignment | undefined,
alignment: StatusBarAlignment | number | undefined,
priority?: number
): vscode.StatusBarItem;
function createStatusBarItem(
id: string | StatusBarAlignment | undefined,
alignment: StatusBarAlignment | number | undefined,
priority?: number
): vscode.StatusBarItem {
if (typeof id === 'string') {
return _createStatusBarItem(id, alignment, priority);
}
return _createStatusBarItem('mock-id', id, alignment);
}
function _createStatusBarItem(id: string, alignment?: StatusBarAlignment, priority?: number): vscode.StatusBarItem {
alignment = alignment || StatusBarAlignment.Left;

const sb: vscode.StatusBarItem = {
id,
alignment,
priority,
name: id,
text: '',
tooltip: undefined,
color: undefined,
backgroundColor: undefined,
command: undefined,
show: jest.fn(),
hide: jest.fn(),
dispose: jest.fn(),
};

return sb;
}

// cspell:word Evaluatable
64 changes: 58 additions & 6 deletions packages/jest-mock-vscode/src/vscode/TextDocument.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type * as vscode from 'vscode';
import { TextDocument } from './TextDocument';
import { MockTextDocument } from './TextDocument';
import { Uri } from './uri';
// import { Range } from './extHostTypes';
import * as vsMocks from '..';

describe('Validate TextDocument', () => {
test('create', () => {
const uri = Uri.file(__filename);
const td = TextDocument.create(uri, content());
const td = MockTextDocument.create(uri, content());
expect(td.getText()).toBe(content());
});

Expand All @@ -22,11 +22,61 @@ describe('Validate TextDocument', () => {
expect(pos).toEqual(expect.objectContaining({ line, character: col }));
expect(doc.offsetAt(pos)).toBe(offset);
});

test.each`
key | expected
${'fileName'} | ${Uri.file(__filename).fsPath}
${'lineCount'} | ${10}
${'languageId'} | ${'plaintext'}
${'isUntitled'} | ${false}
`('simple getters $method', ({ key, expected }) => {
const doc = createDoc();
expect((doc as any)[key]).toEqual(expected);
});

test.each`
searchFor | expected
${'ge At Position'} | ${'Range'}
${'ne 4'} | ${'Line'}
${' Line 4'} | ${undefined}
`('getWordRangeAtPosition', ({ searchFor, expected }) => {
const doc = createDoc();
const pos = doc.positionAt(doc.getText().indexOf(searchFor));
const r = doc.getWordRangeAtPosition(pos);
expect(r && doc.getText(r)).toEqual(expected);
});

test.each`
range | expected
${r(0, 0, 4, 4)} | ${r(0, 0, 4, 4)}
${r(3, 10, 10, 4)} | ${r(3, 1, 9, 3)}
`('validateRange $range', ({ range, expected }) => {
const doc = createDoc();
expect(doc.validateRange(range)).toEqual(expected);
});

test('isDirty', () => {
const doc = createDoc();
expect(doc.isDirty).toEqual(false);
MockTextDocument.setContents(doc, content());
expect(doc.isDirty).toEqual(true);
});

test('save', async () => {
const doc = createDoc();
expect(await doc.save()).toEqual(false);
MockTextDocument.setContents(doc, content());
expect(() => doc.save()).toThrowError('Method not implemented.');
});
});

function createDoc(): vscode.TextDocument {
function r(lineA: number, rowA: number, lineB: number, rowB: number): vscode.Range {
return new vsMocks.Range(lineA, rowA, lineB, rowB);
}

function createDoc(): MockTextDocument {
const uri = Uri.file(__filename);
return TextDocument.create(uri, content());
return MockTextDocument.create(uri, content());
}

function content() {
Expand All @@ -37,5 +87,7 @@ Line 2
Line 4
Position 5
`;
get Word Range At Position
eof`;
}
Loading

0 comments on commit fb86d94

Please sign in to comment.