Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix search provider returns invalid URIs #134

Merged
merged 1 commit into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion fs-provider/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"onSearch:vscode-test-web"
],
"enabledApiProposals": [
"fileSearchProvider"
"fileSearchProvider",
"textSearchProvider"
],
"contributes": {
"resourceLabelFormatters": [
Expand Down
14 changes: 9 additions & 5 deletions fs-provider/src/fsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,30 +141,34 @@ export class MemFileSystemProvider implements FileSystemProvider, FileSearchProv

async provideFileSearchResults(query: FileSearchQuery, options: FileSearchOptions, token: CancellationToken): Promise<Uri[]> {
const pattern = query.pattern;

// Pattern is always blank: https://github.com/microsoft/vscode/issues/200892
const glob = pattern ? new Minimatch(pattern) : undefined;

const result: Uri[] = [];
const dive = async (currentDirectory: Directory, pathSegments: string[] = []) => {
for (const [name, entry] of await currentDirectory.entries) {
const dive = async (folderUri: Uri) => {
const directory = await this._lookupAsDirectory(folderUri, false);
for (const [name, entry] of await directory.entries) {
/* support options.includes && options.excludes */

if (typeof options.maxResults !== 'undefined' && result.length >= options.maxResults) {
break;
}

const uri = Uri.joinPath(this.extensionUri, ...pathSegments, entry.name);
const uri = Uri.joinPath(folderUri, entry.name);
if (entry.type === FileType.File) {
const toMatch = uri.toString();
// Pattern is always blank: https://github.com/microsoft/vscode/issues/200892
if (!glob || glob.match(toMatch)) {
result.push(uri);
}
} else if (entry.type === FileType.Directory) {
await dive(entry, [...pathSegments, name]);
await dive(uri);
}
}
};

await dive(this.root);
await dive(options.folder);
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/

declare module 'vscode' {

// https://github.com/microsoft/vscode/issues/73524

/**
Expand All @@ -12,6 +13,12 @@ declare module 'vscode' {
export interface FileSearchQuery {
/**
* The search pattern to match against file paths.
* To be correctly interpreted by Quick Open, this is interpreted in a relaxed way. The picker will apply its own highlighting and scoring on the results.
*
* Tips for matching in Quick Open:
* With the pattern, the picker will use the file name and file paths to score each entry. The score will determine the ordering and filtering.
* The scoring prioritizes prefix and substring matching. Then, it checks and it checks whether the pattern's letters appear in the same order as in the target (file name and path).
* If a file does not match at all using our criteria, it will be omitted from Quick Open.
*/
pattern: string;
}
Expand Down Expand Up @@ -48,11 +55,7 @@ declare module 'vscode' {
* @param options A set of options to consider while searching files.
* @param token A cancellation token.
*/
provideFileSearchResults(
query: FileSearchQuery,
options: FileSearchOptions,
token: CancellationToken
): ProviderResult<Uri[]>;
provideFileSearchResults(query: FileSearchQuery, options: FileSearchOptions, token: CancellationToken): ProviderResult<Uri[]>;
}

export namespace workspace {
Expand Down
281 changes: 281 additions & 0 deletions fs-provider/vscode.proposed.textSearchProvider.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

declare module 'vscode' {

// https://github.com/microsoft/vscode/issues/59921

/**
* The parameters of a query for text search.
*/
export interface TextSearchQuery {
/**
* The text pattern to search for.
*/
pattern: string;

/**
* Whether or not `pattern` should match multiple lines of text.
*/
isMultiline?: boolean;

/**
* Whether or not `pattern` should be interpreted as a regular expression.
*/
isRegExp?: boolean;

/**
* Whether or not the search should be case-sensitive.
*/
isCaseSensitive?: boolean;

/**
* Whether or not to search for whole word matches only.
*/
isWordMatch?: boolean;
}

/**
* A file glob pattern to match file paths against.
* TODO@roblourens merge this with the GlobPattern docs/definition in vscode.d.ts.
* @see {@link GlobPattern}
*/
export type GlobString = string;

/**
* Options common to file and text search
*/
export interface SearchOptions {
/**
* The root folder to search within.
*/
folder: Uri;

/**
* Files that match an `includes` glob pattern should be included in the search.
*/
includes: GlobString[];

/**
* Files that match an `excludes` glob pattern should be excluded from the search.
*/
excludes: GlobString[];

/**
* Whether external files that exclude files, like .gitignore, should be respected.
* See the vscode setting `"search.useIgnoreFiles"`.
*/
useIgnoreFiles: boolean;

/**
* Whether symlinks should be followed while searching.
* See the vscode setting `"search.followSymlinks"`.
*/
followSymlinks: boolean;

/**
* Whether global files that exclude files, like .gitignore, should be respected.
* See the vscode setting `"search.useGlobalIgnoreFiles"`.
*/
useGlobalIgnoreFiles: boolean;

/**
* Whether files in parent directories that exclude files, like .gitignore, should be respected.
* See the vscode setting `"search.useParentIgnoreFiles"`.
*/
useParentIgnoreFiles: boolean;
}

/**
* Options to specify the size of the result text preview.
* These options don't affect the size of the match itself, just the amount of preview text.
*/
export interface TextSearchPreviewOptions {
/**
* The maximum number of lines in the preview.
* Only search providers that support multiline search will ever return more than one line in the match.
*/
matchLines: number;

/**
* The maximum number of characters included per line.
*/
charsPerLine: number;
}

/**
* Options that apply to text search.
*/
export interface TextSearchOptions extends SearchOptions {
/**
* The maximum number of results to be returned.
*/
maxResults: number;

/**
* Options to specify the size of the result text preview.
*/
previewOptions?: TextSearchPreviewOptions;

/**
* Exclude files larger than `maxFileSize` in bytes.
*/
maxFileSize?: number;

/**
* Interpret files using this encoding.
* See the vscode setting `"files.encoding"`
*/
encoding?: string;

/**
* Number of lines of context to include before each match.
*/
beforeContext?: number;

/**
* Number of lines of context to include after each match.
*/
afterContext?: number;
}

/**
* Represents the severity of a TextSearchComplete message.
*/
export enum TextSearchCompleteMessageType {
Information = 1,
Warning = 2,
}

/**
* A message regarding a completed search.
*/
export interface TextSearchCompleteMessage {
/**
* Markdown text of the message.
*/
text: string;
/**
* Whether the source of the message is trusted, command links are disabled for untrusted message sources.
* Messaged are untrusted by default.
*/
trusted?: boolean;
/**
* The message type, this affects how the message will be rendered.
*/
type: TextSearchCompleteMessageType;
}

/**
* Information collected when text search is complete.
*/
export interface TextSearchComplete {
/**
* Whether the search hit the limit on the maximum number of search results.
* `maxResults` on {@linkcode TextSearchOptions} specifies the max number of results.
* - If exactly that number of matches exist, this should be false.
* - If `maxResults` matches are returned and more exist, this should be true.
* - If search hits an internal limit which is less than `maxResults`, this should be true.
*/
limitHit?: boolean;

/**
* Additional information regarding the state of the completed search.
*
* Messages with "Information" style support links in markdown syntax:
* - Click to [run a command](command:workbench.action.OpenQuickPick)
* - Click to [open a website](https://aka.ms)
*
* Commands may optionally return { triggerSearch: true } to signal to the editor that the original search should run be again.
*/
message?: TextSearchCompleteMessage | TextSearchCompleteMessage[];
}

/**
* A preview of the text result.
*/
export interface TextSearchMatchPreview {
/**
* The matching lines of text, or a portion of the matching line that contains the match.
*/
text: string;

/**
* The Range within `text` corresponding to the text of the match.
* The number of matches must match the TextSearchMatch's range property.
*/
matches: Range | Range[];
}

/**
* A match from a text search
*/
export interface TextSearchMatch {
/**
* The uri for the matching document.
*/
uri: Uri;

/**
* The range of the match within the document, or multiple ranges for multiple matches.
*/
ranges: Range | Range[];

/**
* A preview of the text match.
*/
preview: TextSearchMatchPreview;
}

/**
* A line of context surrounding a TextSearchMatch.
*/
export interface TextSearchContext {
/**
* The uri for the matching document.
*/
uri: Uri;

/**
* One line of text.
* previewOptions.charsPerLine applies to this
*/
text: string;

/**
* The line number of this line of context.
*/
lineNumber: number;
}

export type TextSearchResult = TextSearchMatch | TextSearchContext;

/**
* A TextSearchProvider provides search results for text results inside files in the workspace.
*/
export interface TextSearchProvider {
/**
* Provide results that match the given text pattern.
* @param query The parameters for this query.
* @param options A set of options to consider while searching.
* @param progress A progress callback that must be invoked for all results.
* @param token A cancellation token.
*/
provideTextSearchResults(query: TextSearchQuery, options: TextSearchOptions, progress: Progress<TextSearchResult>, token: CancellationToken): ProviderResult<TextSearchComplete>;
}

export namespace workspace {
/**
* Register a text search provider.
*
* Only one provider can be registered per scheme.
*
* @param scheme The provider will be invoked for workspace folders that have this file scheme.
* @param provider The provider.
* @return A {@link Disposable} that unregisters this provider when being disposed.
*/
export function registerTextSearchProvider(scheme: string, provider: TextSearchProvider): Disposable;
}
}
2 changes: 1 addition & 1 deletion sample/src/web/test/suite/search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ suite('Workspace search', () => {
}

// commented out because of https://github.com/microsoft/vscode/issues/227248
test.skip('Find files', async () => {
test('Find files', async () => {
debugger;
await assertEntries('/folder', ['x.txt'], ['.bar']);
await assertEntries('/folder/', ['x.txt'], ['.bar']);
Expand Down
Loading