106 lines · 4.3 KB
import * as vscode from "vscode";
import { compileQuery, matchLines } from "../lib/text-search";
import type { LineMatch } from "../lib/text-search";
import type { ForgeApi } from "./forge";
import type { GitforFileSystem } from "./fs";
import type { RoomClient } from "./room-client";

const DEFAULT_FILE_RESULTS = 512;
const MAX_TEXT_RESULTS = 2000;
const MAX_SKIP = 5000;
/** `**\/name` and `**\/name/**` excludes name a directory anywhere; the server can skip those subtrees. */
const DIR_EXCLUDE = /^\*\*\/([^*?/[{}\]]+)(?:\/\*\*)?$/;

/** Characters of `pattern` appear in `path` in order (Quick Open style); the workbench ranks the results. */
function fuzzyMatch(path: string, pattern: string): boolean {
  let index = 0;
  for (const char of path) {
    if (char === pattern[index]) index++;
    if (index === pattern.length) return true;
  }
  return index === pattern.length;
}

function toMatches(uri: vscode.Uri, lines: LineMatch[]): vscode.TextSearchMatch[] {
  return lines.map((line) => ({
    uri,
    ranges: line.ranges.map(([start, end]) => new vscode.Range(line.line, start, line.line, end)),
    preview: { text: line.text, matches: line.ranges.map(([start, end]) => new vscode.Range(0, start, 0, end)) },
  }));
}

/**
 * Search for the `gitfor:` workspace. VS Code for the Web only searches a virtual file system through these
 * providers; without them Search and Quick Open see nothing but the open editors. Quick Open lists the tree the
 * file system already loaded. Text search runs on the forge over the head tree, while files the live room holds
 * (edited, created or deleted in this session) are searched here from their shared text instead.
 */
export function registerSearch(api: ForgeApi, fs: GitforFileSystem, room: RoomClient): vscode.Disposable {
  const files: vscode.FileSearchProvider = {
    async provideFileSearchResults(query, options) {