Skip to content
Open
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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Plugin Playground is built to keep the full plugin prototyping workflow inside J
![Export format dropdown in editor toolbar](docs/images/readme/editor-toolbar-export-dropdown.png)
![Share target dropdown in editor toolbar](docs/images/readme/editor-toolbar-share-dropdown.png)

The right sidebar includes a single Plugin Playground panel with two collapsible sections. In **Extension Points**, the `Tokens` tab helps you discover available token strings and insert import/dependency updates, the `Commands` tab lets you search command IDs, inspect argument docs, and insert execution snippets (either directly or through AI-assisted prompt mode), and the `Packages` tab surfaces package docs plus npm and repository links for known modules.
The right sidebar includes a single Plugin Playground panel with two collapsible sections. In **Extension Points**, the `Tokens` tab helps you discover available token strings, insert import/dependency updates, and find existing usages, the `Commands` tab lets you search command IDs, inspect argument docs, find existing usages, and insert execution snippets (either directly or through AI-assisted prompt mode), and the `Packages` tab surfaces package docs plus npm and repository links for known modules.

![Extension Points token discovery and insertion actions](docs/images/readme/extension-points-tokens.png)
![Extension Points command discovery and insertion actions](docs/images/readme/extension-points-commands.png)
Expand Down Expand Up @@ -200,6 +200,8 @@ The same command row also includes the `f(n)` button to inspect command argument

![Command argument documentation expanded in Commands tab](docs/images/readme/command-argument-docs.png)

Token and command rows also include a `Find usages` action. It searches TypeScript files in the current file browser directory and the bundled `extension-examples/` folder when available, then shows matching file paths and line numbers inline.

The sidebar remembers your last-used command insert mode in:

- `commandInsertDefaultMode` (`insert` or `ai`, `insert` by default)
Expand Down
106 changes: 106 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,9 @@ const ARCHIVE_EXCLUDED_DIRECTORIES = new Set([
'node_modules'
]);
const ARCHIVE_FILE_READ_CONCURRENCY = 8;
const USAGE_SEARCH_FILE_READ_CONCURRENCY = 8;
const USAGE_SEARCH_LINE_PREVIEW_MAX_LENGTH = 240;
const USAGE_SEARCH_SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx']);
const HIDE_QUERY_KEY = 'hide';
const HIDE_QUERY_VALUE_ALL = 'all';
const HIDE_QUERY_VALUE_MENU = 'menu';
Expand Down Expand Up @@ -854,6 +857,7 @@ class PluginPlayground {
isImportEnabled: this._canInsertImport.bind(this),
onSetCommandInsertMode: this._setCommandInsertMode.bind(this),
onInsertCommand: this._insertCommandExecution.bind(this),
onFindUsages: this._findUsages.bind(this),
getCommandInsertMode: () => this._commandInsertMode,
isCommandInsertEnabled: this._hasEditableEditor.bind(this)
});
Expand Down Expand Up @@ -1874,6 +1878,108 @@ class PluginPlayground {
return results;
}

private async _findUsages(
value: string,
kind: TokenSidebar.UsageKind
): Promise<ReadonlyArray<TokenSidebar.IUsageMatch>> {
const terms = this._usageSearchTerms(value, kind);
if (terms.length === 0) {
return [];
}

const currentBrowser = this.fileBrowserFactory?.tracker.currentWidget;
let currentRoot = '';
if (currentBrowser) {
currentRoot = ContentUtils.normalizeContentsPath(
currentBrowser.model.path
).replace(/^\.$/, '');
} else {
const currentEditorPath = this.editorTracker.currentWidget?.context.path;
if (currentEditorPath) {
currentRoot = ContentUtils.normalizeContentsPath(
PathExt.dirname(currentEditorPath)
).replace(/^\.$/, '');
}
}

const roots = [...new Set([currentRoot, EXTENSION_EXAMPLES_ROOT])];
const filePathsByRoot = await Promise.all(
roots.map(async root => {
try {
return (await this._collectArchiveFilePaths(root)).filter(filePath =>
USAGE_SEARCH_SOURCE_EXTENSIONS.has(
PathExt.extname(filePath).toLowerCase()
)
);
} catch {
return [];
}
})
);
const filePaths = [...new Set(filePathsByRoot.flat())].sort((left, right) =>
left.localeCompare(right)
);
const matchesByFile = await this._mapWithConcurrency(
filePaths,
USAGE_SEARCH_FILE_READ_CONCURRENCY,
filePath => this._findUsageMatchesInFile(filePath, terms)
);
return matchesByFile.flat();
}

private _usageSearchTerms(
value: string,
kind: TokenSidebar.UsageKind
): string[] {
const terms = new Set<string>();
const normalizedValue = value.trim();
if (normalizedValue) {
terms.add(normalizedValue);
}
if (kind === 'token') {
const tokenReference = parseTokenReference(normalizedValue);
if (tokenReference) {
terms.add(tokenReference.tokenSymbol);
}
}
return [...terms].sort((left, right) => right.length - left.length);
}

private async _findUsageMatchesInFile(
filePath: string,
terms: ReadonlyArray<string>
): Promise<TokenSidebar.IUsageMatch[]> {
const source = await ContentUtils.readContentsFileAsText(
this.app.serviceManager,
filePath
);
if (source === null) {
return [];
}

const matches: TokenSidebar.IUsageMatch[] = [];
const lines = source.split(/\r\n|\r|\n/);
for (let index = 0; index < lines.length; index += 1) {
const line = lines[index];
if (terms.some(term => line.includes(term))) {
matches.push({
path: filePath,
line: index + 1,
lineText: this._usageLinePreview(line)
});
}
}
return matches;
}

private _usageLinePreview(line: string): string {
const trimmed = line.trim();
if (trimmed.length <= USAGE_SEARCH_LINE_PREVIEW_MAX_LENGTH) {
return trimmed;
}
return `${trimmed.slice(0, USAGE_SEARCH_LINE_PREVIEW_MAX_LENGTH - 3)}...`;
}

private _shouldSkipArchiveDirectory(name: string): boolean {
return ARCHIVE_EXCLUDED_DIRECTORIES.has(name);
}
Expand Down
Loading
Loading