Skip to content

Commit

Permalink
fix: Issue with spell checking SCM message (#2774)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason3S authored Sep 6, 2023
1 parent 6261326 commit 1766a28
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 21 deletions.
20 changes: 20 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,26 @@
"skipFiles": [
"<node_internals>/**"
]
},
{
"name": "Client: Launch Extension - notebook",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--disable-extensions",
"--extensionDevelopmentPath=${workspaceRoot}",
"${workspaceRoot}/fixtures/workspaces/jupyter"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
"${workspaceRoot}/packages/client/dist/**/*.js"
],
"smartStep": true,
"skipFiles": [
"<node_internals>/**"
]
}
],
"compounds": []
Expand Down
2 changes: 1 addition & 1 deletion packages/_server/.vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"port": 60048,
"sourceMaps": true,
"outFiles": [
"${workspaceRoot}/dist/**/*.js"
"${workspaceFolder}/dist/**/*.js"
],
"protocol": "inspector",
"smartStep": false,
Expand Down
2 changes: 1 addition & 1 deletion packages/_server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
"clean": "shx rm -rf dist temp out coverage",
"test-watch": "vitest",
"test": "vitest run",
"watch": "concurrently yarn:watch:esbuild yarn:watch:api yarn:watch:tsc",
"watch": "yarn concurrently yarn:watch:esbuild yarn:watch:api yarn:watch:tsc",
"watch:esbuild": "yarn build:esbuild --watch",
"watch:api": "yarn build:api.d.ts --watch",
"watch:tsc": "yarn build:tsc --watch"
Expand Down
72 changes: 72 additions & 0 deletions packages/_server/src/config/docUriHelper.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// import type { WorkspaceFolder } from 'vscode';
import { URI as Uri, Utils as UriUtils } from 'vscode-uri';

export const schemasWithSpecialHandling = {
vscodeNoteBookCell: 'vscode-notebook-cell',
vscodeScm: 'vscode-scm',
} as const satisfies Readonly<Record<string, string>>;

type SpecialHandlingFunction = (uri: Uri) => Uri;

const _schemaMapToHandler = {
[schemasWithSpecialHandling.vscodeNoteBookCell]: forceToFileUri,
[schemasWithSpecialHandling.vscodeScm]: handleExtractUriFromQuery('rootUri', 'COMMIT_MSG.txt'),
} as const satisfies Readonly<Record<string, SpecialHandlingFunction>>;

const schemaMapToHandler: Readonly<Record<string, SpecialHandlingFunction>> = _schemaMapToHandler;

const _alwaysIncludeMatchedFiles = [/^vscode-scm:/];

// handleSpecialUri
export function handleSpecialUri(uri: Uri): Uri {
if (!uriNeedsSpecialHandling(uri)) return uri;
return getHandler(uri)(uri);
}

export function forceToFileUri(uri: Uri): Uri {
if (uri.scheme === 'file') return uri;

return uri.with({
scheme: 'file',
query: '',
fragment: '',
});
}

export function extractUriFromQueryParam(uri: Uri | string, param: string): Uri | undefined {
const url = new URL(uri.toString(true));
const newUrl = decodeURIComponent(url.searchParams.get(param) || '');
if (!newUrl) return undefined;
try {
return Uri.parse(newUrl);
} catch (e) {
return undefined;
}
}

export function uriNeedsSpecialHandling(uri: Uri): boolean {
return uri.scheme in schemaMapToHandler;
}

export function isUrlIncludedByDefault(uri: Uri | string): boolean {
const url = uri.toString();

for (const reg of _alwaysIncludeMatchedFiles) {
if (reg.test(url)) return true;
}
return false;
}

function handleExtractUriFromQuery(param: string, appendFile?: string): (uri: Uri) => Uri {
return (uri) => {
const _uri = extractUriFromQueryParam(uri, param);
if (_uri) {
return appendFile ? UriUtils.joinPath(_uri, appendFile) : _uri;
}
return uri;
};
}

function getHandler(uri: Uri): SpecialHandlingFunction {
return schemaMapToHandler[uri.scheme];
}
39 changes: 39 additions & 0 deletions packages/_server/src/config/docUriHelper.test.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { describe, expect, test } from 'vitest';
import { URI as Uri } from 'vscode-uri';

import { extractUriFromQueryParam, forceToFileUri, handleSpecialUri } from './docUriHelper.mjs';

// cspell:ignore jsmith

const sampleUrl1 = 'vscode-scm:git/scm0/input?rootUri=file:///c:/Users/jsmith/projects/cspell-dicts&name=Jonathan%20Smith&age=18';
const sampleUrl2 = 'vscode-scm:git/scm0/input?rootUri=file%3A///c%3A/Users/jsmith/projects/cspell-dicts&name=Jonathan%20Smith&age=18';

describe('', () => {
test.each`
uri | expected
${import.meta.url} | ${Uri.parse(import.meta.url)}
${new URL(import.meta.url).href} | ${Uri.parse(import.meta.url)}
${sampleUrl1} | ${'file:///git/scm0/input'}
`('forceToFileUri $uri', ({ uri, expected }) => {
expect(forceToFileUri(Uri.parse(uri)).toString()).toEqual(expected.toString());
});

test.each`
uri | expected
${import.meta.url} | ${Uri.parse(import.meta.url)}
${new URL(import.meta.url).href} | ${Uri.parse(import.meta.url)}
${sampleUrl1} | ${'file:///c%3A/Users/jsmith/projects/cspell-dicts/COMMIT_MSG.txt'}
`('handleSpecialUri $uri', ({ uri, expected }) => {
expect(handleSpecialUri(Uri.parse(uri)).toString()).toEqual(expected.toString());
});

test.each`
uri | param | expected
${import.meta.url} | ${'rootUri'} | ${undefined}
${sampleUrl1} | ${'rootUri'} | ${'file:///c%3A/Users/jsmith/projects/cspell-dicts'}
${sampleUrl2} | ${'rootUri'} | ${'file:///c%3A/Users/jsmith/projects/cspell-dicts'}
`('extractUriFromQueryParam $uri', ({ uri, param, expected }) => {
const r = extractUriFromQueryParam(uri, param);
expect(r?.toString()).toEqual(expected?.toString());
});
});
40 changes: 21 additions & 19 deletions packages/_server/src/config/documentSettings.mts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { uniqueFilter } from '../utils/index.mjs';
import { Connection, WorkspaceFolder } from '../vscodeLanguageServer/index.cjs';
import { CSpellUserSettings } from './cspellConfig/index.mjs';
import { canAddWordsToDictionary } from './customDictionaries.mjs';
import { handleSpecialUri } from './docUriHelper.mjs';
import { getConfiguration, getWorkspaceFolders, TextDocumentUri } from './vscode.config.mjs';
import { createWorkspaceNamesResolver, resolveSettings } from './WorkspacePathResolver.mjs';

Expand All @@ -53,6 +54,7 @@ export interface SettingsVSCode {
}

interface VsCodeSettings {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
}

Expand All @@ -64,14 +66,23 @@ interface ExtSettings {
includeGlobMatcher: GlobMatcher;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type PromiseType<T extends Promise<any>> = T extends Promise<infer R> ? R : never;
type GitignoreResultP = ReturnType<GitIgnore['isIgnoredEx']>;
type GitignoreResultInfo = PromiseType<GitignoreResultP>;

export interface ExcludeIncludeIgnoreInfo {
/** The requested uri */
uri: string;
/** The uri used to calculate the response */
uriUsed: string;
/** Is included */
include: boolean;
/** Is explicitly excluded */
exclude: boolean;
/** Ignored by .gitignore */
ignored: boolean | undefined;
/** Information related to .gitignore */
gitignoreInfo: GitignoreResultInfo | undefined;
}

Expand All @@ -87,15 +98,10 @@ const defaultRootUri = toFileUri(process.cwd()).toString();

const _defaultSettings: CSpellUserSettings = Object.freeze({});

const _schemaMapToFile = {
'vscode-notebook-cell': true,
} as const;

const schemeMapToFile: Record<string, true> = Object.freeze(_schemaMapToFile);

const defaultCheckOnlyEnabledFileTypes = true;

interface Clearable {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
clear: () => any;
}
export class DocumentSettings {
Expand Down Expand Up @@ -124,13 +130,16 @@ export class DocumentSettings {
}

async calcIncludeExclude(uri: Uri): Promise<ExcludeIncludeIgnoreInfo> {
const settings = await this.fetchSettingsForUri(uri.toString());
const ie = calcIncludeExclude(settings, uri);
const ignoredEx = await this._isGitIgnoredEx(settings, uri);
const _uri = handleSpecialUri(uri);
const settings = await this.fetchSettingsForUri(_uri.toString());
const ie = calcIncludeExclude(settings, _uri);
const ignoredEx = await this._isGitIgnoredEx(settings, _uri);
return {
...ie,
ignored: ignoredEx?.matched,
gitignoreInfo: ignoredEx,
uri: uri.toString(),
uriUsed: _uri.toString(),
};
}

Expand Down Expand Up @@ -293,8 +302,9 @@ export class DocumentSettings {
private async _fetchSettingsForUri(docUri: string): Promise<ExtSettings> {
log(`fetchFolderSettings: URI ${docUri}`);
const uri = Uri.parse(docUri);
if (uri.scheme in schemeMapToFile) {
return this.fetchSettingsForUri(mapToFileUri(uri).toString());
const uriSpecial = handleSpecialUri(uri);
if (uri !== uriSpecial) {
return this.fetchSettingsForUri(uriSpecial.toString());
}
const fsPath = path.normalize(uri.fsPath);
const cSpellConfigSettingsRel = await this.fetchSettingsFromVSCode(docUri);
Expand Down Expand Up @@ -678,14 +688,6 @@ export function isExcluded(settings: ExtSettings, uri: Uri): boolean {
return settings.excludeGlobMatcher.match(uri.fsPath);
}

function mapToFileUri(uri: Uri): Uri {
return uri.with({
scheme: 'file',
query: '',
fragment: '',
});
}

export const __testing__ = {
extractTargetDictionaries,
extractEnableFiletypes,
Expand Down

0 comments on commit 1766a28

Please sign in to comment.