Repository: TabbyML/tabby
File: clients/vscode/src/chat/webview.ts (TypeScript)

Code before:
                uri: (tab.input as TabInputText).uri,
                label: tab.label,
              })),
          );

          this.logger.info(`No query provided, listing ${openTabs.length} opened editors.`);

          return openTabs
            .filter((tab) => tab.uri.scheme === "file")
            .map((tab) => uriToListFileItem(tab.uri, this.gitProvider));
        }

        const globPattern = `**/${query}*`;
        this.logger.info(`Searching files with pattern: ${globPattern}, limit: ${maxResults}.`);
        try {
          const files = await workspace.findFiles(globPattern, null, maxResults);
          this.logger.info(`Found ${files.length} files.`);
          return files.map((uri) => uriToListFileItem(uri, this.gitProvider));
        } catch (error) {
          this.logger.warn("Failed to find files:", error);
          return [];
        }
      },

      readFileContent: async (info: FileRange): Promise<string | null> => {
        if (info.range) {
          try {
            const uri = chatPanelFilepathToLocalUri(info.filepath, this.gitProvider);
            if (!uri) {
              this.logger.warn(`Could not resolve URI from filepath: ${JSON.stringify(info.filepath)}`);
              return null;
            }
            const document = await workspace.openTextDocument(uri);

            return extractTextFromRange(document, info.range);
          } catch (error) {
            this.logger.error("Failed to get file content by range:", error);
            return null;
          }
        } else {
          try {
            const uri = chatPanelFilepathToLocalUri(info.filepath, this.gitProvider);
            if (!uri) {
              this.logger.warn(`Could not resolve URI from filepath: ${JSON.stringify(info.filepath)}`);
              return null;
            }
            const document = await workspace.openTextDocument(uri);
            return document.getText();
          } catch (error) {
            this.logger.error("Failed to get file content:", error);
            return null;

Review comment (suggestion):
There's no need for an `if` branch here. `document.getText()` can accept a range or `undefined` as parameters.

Code after:

        const fileContext = await getFileContextFromSelection(editor, this.gitProvider);
        return fileContext;
      },

      fetchSessionState: async (keys?: string[] | undefined): Promise<Record<string, unknown> | null> => {
        if (!keys) {
          return { ...this.sessionState };
        }

        const filtered: Record<string, unknown> = {};
        for (const key of keys) {
          if (key in this.sessionState) {
            filtered[key] = this.sessionState[key];
          }
        }
        return filtered;
      },

      storeSessionState: async (state: Record<string, unknown>) => {
        this.sessionState = {
          ...this.sessionState,
          ...state,
        };
      },

      listFileInWorkspace: async (params: ListFilesInWorkspaceParams): Promise<ListFileItem[]> => {
        const maxResults = params.limit || 50;
        const searchQuery = params.query?.trim();

        if (!searchQuery) {
          const openTabs = window.tabGroups.all
            .flatMap((group) => group.tabs)
            .filter((tab) => tab.input && (tab.input as TabInputText).uri);

          this.logger.info(`No query provided, listing ${openTabs.length} opened editors.`);
          return openTabs.map((tab) => uriToListFileItem((tab.input as TabInputText).uri, this.gitProvider));
        }

        try {
          const caseInsensitivePattern = searchQuery
            .split("")
            .map((char) => {
              if (char.toLowerCase() !== char.toUpperCase()) {
                return `{${char.toLowerCase()},${char.toUpperCase()}}`;
              }
              return escapeGlobPattern(char);
            })
            .join("");

          const globPattern = `**/${caseInsensitivePattern}*`;