diff --git a/extensions/terminal-suggest/src/completions/upstream/gh.ts b/extensions/terminal-suggest/src/completions/gh.ts similarity index 92% rename from extensions/terminal-suggest/src/completions/upstream/gh.ts rename to extensions/terminal-suggest/src/completions/gh.ts index 6f6c0deee11a1..0c06cc35d7f88 100644 --- a/extensions/terminal-suggest/src/completions/upstream/gh.ts +++ b/extensions/terminal-suggest/src/completions/gh.ts @@ -1,4 +1,13 @@ -import { filepaths } from '../../helpers/filepaths'; import { keyValue } from '../../helpers/keyvalue'; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/* eslint-disable local/code-no-unexternalized-strings */ + +import * as vscode from 'vscode'; +import { filepaths } from '../helpers/filepaths'; +import { keyValue } from '../helpers/keyvalue'; const filterMessages = (out: string): string => { return out.startsWith("warning:") || out.startsWith("error:") @@ -29,6 +38,7 @@ const postProcessRemoteBranches: Fig.Generator["postProcess"] = (out) => { name: elm.replace("*", "").trim(), description: "Current branch", priority: 100, + // allow-any-unicode-next-line icon: "⭐️", }; } else if (parts[0] === "+") { @@ -40,7 +50,7 @@ const postProcessRemoteBranches: Fig.Generator["postProcess"] = (out) => { return { name, description: "Branch", - icon: "vscode://icon?type=11", + icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.Branch}`, priority: 75, }; }); @@ -56,6 +66,7 @@ const listRepoMapFunction = (repo: RepoDataType) => ({ name: repo.nameWithOwner, description: repo.description ?? undefined, //be able to see if the repo is private at a glance + // allow-any-unicode-next-line icon: repo.isPrivate ? "🔒" : "👀", }); @@ -68,7 +79,9 @@ const ghGenerators: Record = { const last = tokens.pop(); //gatekeeper - if (!last) return []; + if (!last) { + return []; + } /** * this turns this input: @@ -80,13 +93,17 @@ const ghGenerators: Record = { const userRepoSplit = last.split("/"); // make sure it has some length. - if (userRepoSplit.length === 0) return []; + if (userRepoSplit.length === 0) { + return []; + } //get first element of arr const userOrOrg = userRepoSplit.shift(); // make sure it has some existence. - if (!userOrOrg) return []; + if (!userOrOrg) { + return []; + } //run `gh repo list` cmd const { stdout, status } = await execute({ @@ -103,7 +120,9 @@ const ghGenerators: Record = { }); // make sure it has some existence. - if (status !== 0) return []; + if (status !== 0) { + return []; + } //parse the JSON string output of the command const repoArr: RepoDataType[] = JSON.parse(stdout); @@ -171,7 +190,7 @@ const ghGenerators: Record = { name: number.toString(), displayName: title, description: `#${number} | ${headRefName}`, - icon: state === "OPEN" ? "✅" : "☑️", + icon: `vscode://icon?type=${state === "OPEN" ? vscode.TerminalCompletionItemKind.PullRequest : vscode.TerminalCompletionItemKind.PullRequestDone}`, }; }); }, @@ -319,27 +338,124 @@ const completionSpec: Fig.Spec = { ], }, ], + }, { + name: "api", + description: "Make an authenticated GitHub API request", + args: { + name: " [flags]a", + }, + options: [ + { + name: "--cache", + description: 'Cache the response, e.g. "3600s", "60m", "1h"', + args: { name: "duration" }, + }, + { + name: ["-F", "--field"], + description: "Add a typed parameter in key=value format", + args: { name: "key:value" }, + }, + { + name: "--hostname", + description: + 'The GitHub hostname for the request (default "github.com")', + args: { + name: "string", + }, + }, + { + name: ["-i", "--include"], + description: + "Include HTTP response status line and headers in the output", + }, + { + name: "--input", + description: + 'The file to use as body for the HTTP request (use "-" to read from standard input)', + args: { name: "file" }, + }, + { + name: ["-q", "--jq"], + description: + "Query to select values from the response using jq syntax", + args: { name: "string" }, + }, + { + name: ["-X", "--method"], + description: "The HTTP method for the request", + args: { name: "string", description: '(default "GET")' }, + }, + { + name: "--paginate", + description: + "Make additional HTTP requests to fetch all pages of results", + }, + { + name: ["-p", "--preview"], + description: + 'GitHub API preview names to request (without the "-preview" suffix)', + args: { name: "names" }, + }, + { + name: ["-f", "--raw-field"], + description: "Add a string parameter in key=value format", + args: { name: "key=value" }, + }, + { + name: "--silent", + description: "Do not print the response body", + }, + { + name: "--slurp", + description: + 'Use with "--paginate" to return an array of all pages of either JSON arrays or objects', + }, + { + name: ["-t", "--template"], + description: + 'Format JSON output using a Go template; see "gh help formatting"', + args: { name: "string" }, + }, + { + name: "--verbose", + description: "Include full HTTP request and response in the output", + }, + ], }, - { name: "api", description: "Make an authenticated GitHub API request" }, { name: "auth", - description: "Login, logout, and refresh your authentication", + description: "Authenticate gh and git with GitHub", subcommands: [ { name: "login", - description: "Authenticate with a GitHub host", + description: "Gh auth login [flags]", options: [ + { + name: ["-p", "--git-protocol"], + description: + "The protocol to use for git operations on this host: {ssh|https}", + args: { name: "string" }, + }, { name: ["-h", "--hostname"], description: "The hostname of the GitHub instance to authenticate with", - args: { name: "hostname" }, + args: { name: "string" }, + }, + { + name: "--insecure-storage", + description: + "Save authentication credentials in plain text instead of credential store", }, { name: ["-s", "--scopes"], - description: "Additional authentication scopes for gh to have", - args: { name: "scopes" }, + description: "Additional authentication scopes to request", + args: { name: "strings" }, + }, + { + name: "--skip-ssh-key", + description: "Skip generate/upload SSH key prompt", }, { name: ["-w", "--web"], @@ -348,65 +464,123 @@ const completionSpec: Fig.Spec = { { name: "--with-token", description: "Read token from standard input", - args: { name: "token" }, }, ], }, { name: "logout", - description: "Log out of a GitHub host", + description: "Gh auth logout [flags]", options: [ { name: ["-h", "--hostname"], - description: - "The hostname of the GitHub instance to authenticate with", - args: { name: "hostname" }, + description: "The hostname of the GitHub instance to log out of", + args: { name: "string" }, + }, + { + name: ["-u", "--user"], + description: "The account to log out of", + args: { name: "string" }, }, ], }, { name: "refresh", - description: "Refresh stored authentication credentials", + description: "Gh auth refresh [flags]", options: [ { name: ["-h", "--hostname"], + description: "The GitHub host to use for authentication", + args: { name: "string" }, + }, + { + name: "--insecure-storage", description: - "The hostname of the GitHub instance to authenticate with", - args: { name: "hostname" }, + "Save authentication credentials in plain text instead of credential store", + }, + { + name: ["-r", "--remove-scopes"], + description: "Authentication scopes to remove from gh", + args: { name: "strings" }, + }, + { + name: "--reset-scopes", + description: + "Reset authentication scopes to the default minimum set of scopes", }, { name: ["-s", "--scopes"], description: "Additional authentication scopes for gh to have", - args: { name: "scopes" }, + args: { name: "strings" }, }, ], }, { name: "setup-git", - description: "Configure git to use GitHub CLI as a credential helper", + description: "Gh auth setup-git [flags]", options: [ { - name: ["-h", "--hostname"], + name: ["-f", "--force"], description: - "The hostname of the GitHub instance to authenticate with", - args: { name: "hostname" }, + "Force setup even if the host is not known. Must be used in conjunction with --hostname", + args: { name: "--hostname" }, + }, + { + name: ["-h", "--hostname"], + description: "The hostname to configure git for", + args: { name: "string" }, }, ], }, { name: "status", description: "View authentication status", + options: [ + { + name: ["-a", "--active"], + description: "Display the active account only", + }, + { + name: ["-h", "--hostname"], + description: "Check only a specific hostname's auth status", + args: { name: "string" }, + }, + { + name: ["-t", "--show-token"], + description: "Display the auth token", + }, + ], + }, + { + name: "switch", + description: "Switch the active account for a GitHub host", options: [ { name: ["-h", "--hostname"], description: - "The hostname of the GitHub instance to authenticate with", - args: { name: "hostname" }, + "The hostname of the GitHub instance to switch account for", + args: { name: "string" }, }, { - name: "--with-token", - description: "Read token from standard input", - args: { name: "token" }, + name: ["-u", "--user"], + description: "The account to switch to", + args: { name: "string" }, + }, + ], + }, + { + name: "token", + description: "Gh auth token [flags]", + options: [ + { + name: ["-h", "--hostname"], + description: + "The hostname of the GitHub instance authenticated with", + args: { name: "string" }, + }, + { + name: ["-u", "--user"], + description: "The account to output the token for", + args: { name: "string" }, }, ], }, @@ -1574,8 +1748,8 @@ Pass additional 'git clone' flags by listing them after '--'`, To create a repository interactively, use 'gh repo create' with no arguments. To create a remote repository non-interactively, supply the repository name and one of '--public', '--private', or '--internal'. Pass '--clone' to clone the new repository locally. -To create a remote repository from an existing local repository, specify the source directory with '--source'. -By default, the remote repository name will be the name of the source directory. +To create a remote repository from an existing local repository, specify the source directory with '--source'. +By default, the remote repository name will be the name of the source directory. Pass '--push' to push any local commits to the new repository`, args: { name: "name", @@ -1726,7 +1900,7 @@ Pass '--push' to push any local commits to the new repository`, name: "delete", description: `Delete a GitHub repository. With no argument, deletes the current repository. Otherwise, deletes the specified repository. -Deletion requires authorization with the "delete_repo" scope. +Deletion requires authorization with the "delete_repo" scope. To authorize, run "gh auth refresh -s delete_repo"`, isDangerous: true, args: { @@ -2003,7 +2177,7 @@ By default, this renames the current repository; otherwise renames the specified of the source repository to update the matching branch on the destination repository so they are equal. A fast forward update will be used execept when the '--force' flag is specified, then the two branches will -by synced using a hard reset. +by synced using a hard reset. Without an argument, the local repository is selected as the destination repository. The source repository is the parent of the destination repository by default. This can be overridden with the '--source' flag`, diff --git a/extensions/terminal-suggest/src/constants.ts b/extensions/terminal-suggest/src/constants.ts index 8b59563b97bce..7d877e73961e8 100644 --- a/extensions/terminal-suggest/src/constants.ts +++ b/extensions/terminal-suggest/src/constants.ts @@ -95,9 +95,6 @@ export const upstreamSpecs = [ 'nano', 'vim', - // SCM - 'gh', - // Shells 'ssh', diff --git a/extensions/terminal-suggest/src/fig/figInterface.ts b/extensions/terminal-suggest/src/fig/figInterface.ts index ca1b2d35cf3d0..35a8e12747bd3 100644 --- a/extensions/terminal-suggest/src/fig/figInterface.ts +++ b/extensions/terminal-suggest/src/fig/figInterface.ts @@ -242,7 +242,7 @@ export async function collectCompletionItemResult( terminalContext.cursorPosition, prefix, { label }, - undefined, + item.displayName, typeof item === 'string' ? item : item.description, convertIconToKind(item.icon) ?? kind )); @@ -377,6 +377,8 @@ function convertIconToKind(icon: string | undefined): vscode.TerminalCompletionI case 'vscode://icon?type=12': return vscode.TerminalCompletionItemKind.Tag; case 'vscode://icon?type=13': return vscode.TerminalCompletionItemKind.Stash; case 'vscode://icon?type=14': return vscode.TerminalCompletionItemKind.Remote; + case 'vscode://icon?type=15': return vscode.TerminalCompletionItemKind.PullRequest; + case 'vscode://icon?type=16': return vscode.TerminalCompletionItemKind.PullRequestDone; default: return undefined; } } diff --git a/extensions/terminal-suggest/src/terminalSuggestMain.ts b/extensions/terminal-suggest/src/terminalSuggestMain.ts index 5dbe59cfd9a0c..f105a135e2976 100644 --- a/extensions/terminal-suggest/src/terminalSuggestMain.ts +++ b/extensions/terminal-suggest/src/terminalSuggestMain.ts @@ -11,6 +11,7 @@ import codeInsidersCompletionSpec from './completions/code-insiders'; import codeTunnelCompletionSpec from './completions/code-tunnel'; import codeTunnelInsidersCompletionSpec from './completions/code-tunnel-insiders'; import gitCompletionSpec from './completions/git'; +import ghCompletionSpec from './completions/gh'; import npxCompletionSpec from './completions/npx'; import setLocationSpec from './completions/set-location'; import { upstreamSpecs } from './constants'; @@ -63,6 +64,7 @@ export const availableSpecs: Fig.Spec[] = [ codeTunnelCompletionSpec, codeTunnelInsidersCompletionSpec, gitCompletionSpec, + ghCompletionSpec, npxCompletionSpec, setLocationSpec, ]; diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 8b010c8962847..a8ee5a7d14f8a 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2166,6 +2166,8 @@ export enum TerminalCompletionItemKind { Tag = 12, Stash = 13, Remote = 14, + PullRequest = 15, + PullRequestDone = 16, } export class TerminalCompletionItem implements vscode.TerminalCompletionItem { diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionItem.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionItem.ts index 6ed0c54e4e271..30bdf4b578e64 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionItem.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalCompletionItem.ts @@ -26,6 +26,8 @@ export enum TerminalCompletionItemKind { Tag = 12, Stash = 13, Remote = 14, + PullRequest = 15, + PullRequestDone = 16, // Core-only kinds InlineSuggestion = 100, diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon.ts index 37c2028db330b..e1251efc550ee 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon.ts @@ -34,7 +34,7 @@ import { TerminalCompletionModel } from './terminalCompletionModel.js'; import { TerminalCompletionItem, TerminalCompletionItemKind, type ITerminalCompletion } from './terminalCompletionItem.js'; import { localize } from '../../../../../nls.js'; import { TerminalSuggestTelemetry } from './terminalSuggestTelemetry.js'; -import { terminalSymbolAliasIcon, terminalSymbolArgumentIcon, terminalSymbolEnumMember, terminalSymbolFileIcon, terminalSymbolFlagIcon, terminalSymbolInlineSuggestionIcon, terminalSymbolMethodIcon, terminalSymbolOptionIcon, terminalSymbolFolderIcon, terminalSymbolSymbolicLinkFileIcon, terminalSymbolSymbolicLinkFolderIcon, terminalSymbolCommitIcon, terminalSymbolBranchIcon, terminalSymbolTagIcon, terminalSymbolStashIcon, terminalSymbolRemoteIcon } from './terminalSymbolIcons.js'; +import { terminalSymbolAliasIcon, terminalSymbolArgumentIcon, terminalSymbolEnumMember, terminalSymbolFileIcon, terminalSymbolFlagIcon, terminalSymbolInlineSuggestionIcon, terminalSymbolMethodIcon, terminalSymbolOptionIcon, terminalSymbolFolderIcon, terminalSymbolSymbolicLinkFileIcon, terminalSymbolSymbolicLinkFolderIcon, terminalSymbolCommitIcon, terminalSymbolBranchIcon, terminalSymbolTagIcon, terminalSymbolStashIcon, terminalSymbolRemoteIcon, terminalSymbolPullRequestIcon, terminalSymbolPullRequestDoneIcon } from './terminalSymbolIcons.js'; import { TerminalSuggestShownTracker } from './terminalSuggestShownTracker.js'; export interface ISuggestController { @@ -123,6 +123,8 @@ export class SuggestAddon extends Disposable implements ITerminalAddon, ISuggest [TerminalCompletionItemKind.Tag, terminalSymbolTagIcon], [TerminalCompletionItemKind.Stash, terminalSymbolStashIcon], [TerminalCompletionItemKind.Remote, terminalSymbolRemoteIcon], + [TerminalCompletionItemKind.PullRequest, terminalSymbolPullRequestIcon], + [TerminalCompletionItemKind.PullRequestDone, terminalSymbolPullRequestDoneIcon], [TerminalCompletionItemKind.InlineSuggestion, terminalSymbolInlineSuggestionIcon], [TerminalCompletionItemKind.InlineSuggestionAlwaysOnTop, terminalSymbolInlineSuggestionIcon], ]); @@ -143,6 +145,8 @@ export class SuggestAddon extends Disposable implements ITerminalAddon, ISuggest [TerminalCompletionItemKind.Tag, localize('tag', 'Tag')], [TerminalCompletionItemKind.Stash, localize('stash', 'Stash')], [TerminalCompletionItemKind.Remote, localize('remote', 'Remote')], + [TerminalCompletionItemKind.PullRequest, localize('pullRequest', 'Pull Request')], + [TerminalCompletionItemKind.PullRequestDone, localize('pullRequestDone', 'Pull Request (Done)')], [TerminalCompletionItemKind.InlineSuggestion, localize('inlineSuggestion', 'Inline Suggestion')], [TerminalCompletionItemKind.InlineSuggestionAlwaysOnTop, localize('inlineSuggestionAlwaysOnTop', 'Inline Suggestion')], ]); diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSymbolIcons.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSymbolIcons.ts index cd464cc82c56c..7784efd9cdd17 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSymbolIcons.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSymbolIcons.ts @@ -25,6 +25,8 @@ export const TERMINAL_SYMBOL_ICON_BRANCH_FOREGROUND = registerColor('terminalSym export const TERMINAL_SYMBOL_ICON_TAG_FOREGROUND = registerColor('terminalSymbolIcon.tagForeground', SYMBOL_ICON_FILE_FOREGROUND, localize('terminalSymbolIcon.tagForeground', 'The foreground color for a tag icon. These icons will appear in the terminal suggest widget.')); export const TERMINAL_SYMBOL_ICON_STASH_FOREGROUND = registerColor('terminalSymbolIcon.stashForeground', SYMBOL_ICON_FILE_FOREGROUND, localize('terminalSymbolIcon.stashForeground', 'The foreground color for a stash icon. These icons will appear in the terminal suggest widget.')); export const TERMINAL_SYMBOL_ICON_REMOTE_FOREGROUND = registerColor('terminalSymbolIcon.remoteForeground', SYMBOL_ICON_FILE_FOREGROUND, localize('terminalSymbolIcon.remoteForeground', 'The foreground color for a remote icon. These icons will appear in the terminal suggest widget.')); +export const TERMINAL_SYMBOL_ICON_PULL_REQUEST_FOREGROUND = registerColor('terminalSymbolIcon.pullRequestForeground', SYMBOL_ICON_FILE_FOREGROUND, localize('terminalSymbolIcon.pullRequestForeground', 'The foreground color for a pull request icon. These icons will appear in the terminal suggest widget.')); +export const TERMINAL_SYMBOL_ICON_PULL_REQUEST_DONE_FOREGROUND = registerColor('terminalSymbolIcon.pullRequestDoneForeground', SYMBOL_ICON_FILE_FOREGROUND, localize('terminalSymbolIcon.pullRequestDoneForeground', 'The foreground color for a completed pull request icon. These icons will appear in the terminal suggest widget.')); export const TERMINAL_SYMBOL_ICON_SYMBOLIC_LINK_FILE_FOREGROUND = registerColor('terminalSymbolIcon.symbolicLinkFileForeground', SYMBOL_ICON_FILE_FOREGROUND, localize('terminalSymbolIcon.symbolicLinkFileForeground', 'The foreground color for a symbolic link file icon. These icons will appear in the terminal suggest widget.')); export const TERMINAL_SYMBOL_ICON_SYMBOLIC_LINK_FOLDER_FOREGROUND = registerColor('terminalSymbolIcon.symbolicLinkFolderForeground', SYMBOL_ICON_FOLDER_FOREGROUND, localize('terminalSymbolIcon.symbolicLinkFolderForeground', 'The foreground color for a symbolic link folder icon. These icons will appear in the terminal suggest widget.')); @@ -44,6 +46,8 @@ export const terminalSymbolBranchIcon = registerIcon('terminal-symbol-branch', C export const terminalSymbolTagIcon = registerIcon('terminal-symbol-tag', Codicon.tag, localize('terminalSymbolTagIcon', 'Icon for tags in the terminal suggest widget.'), TERMINAL_SYMBOL_ICON_TAG_FOREGROUND); export const terminalSymbolStashIcon = registerIcon('terminal-symbol-stash', Codicon.gitStash, localize('terminalSymbolStashIcon', 'Icon for stashes in the terminal suggest widget.'), TERMINAL_SYMBOL_ICON_STASH_FOREGROUND); export const terminalSymbolRemoteIcon = registerIcon('terminal-symbol-remote', Codicon.remote, localize('terminalSymbolRemoteIcon', 'Icon for remotes in the terminal suggest widget.'), TERMINAL_SYMBOL_ICON_REMOTE_FOREGROUND); +export const terminalSymbolPullRequestIcon = registerIcon('terminal-symbol-pull-request', Codicon.gitPullRequest, localize('terminalSymbolPullRequestIcon', 'Icon for pull requests in the terminal suggest widget.'), TERMINAL_SYMBOL_ICON_PULL_REQUEST_FOREGROUND); +export const terminalSymbolPullRequestDoneIcon = registerIcon('terminal-symbol-pull-request-done', Codicon.gitPullRequestDone, localize('terminalSymbolPullRequestDoneIcon', 'Icon for completed pull requests in the terminal suggest widget.'), TERMINAL_SYMBOL_ICON_PULL_REQUEST_DONE_FOREGROUND); export const terminalSymbolSymbolicLinkFileIcon = registerIcon('terminal-symbol-symbolic-link-file', Codicon.fileSymlinkFile, localize('terminalSymbolSymbolicLinkFileIcon', 'Icon for symbolic link files in the terminal suggest widget.'), TERMINAL_SYMBOL_ICON_SYMBOLIC_LINK_FILE_FOREGROUND); export const terminalSymbolSymbolicLinkFolderIcon = registerIcon('terminal-symbol-symbolic-link-folder', Codicon.fileSymlinkDirectory, localize('terminalSymbolSymbolicLinkFolderIcon', 'Icon for symbolic link folders in the terminal suggest widget.'), TERMINAL_SYMBOL_ICON_SYMBOLIC_LINK_FOLDER_FOREGROUND); diff --git a/src/vscode-dts/vscode.proposed.terminalCompletionProvider.d.ts b/src/vscode-dts/vscode.proposed.terminalCompletionProvider.d.ts index a7ea4d34fdd52..5824afff3d034 100644 --- a/src/vscode-dts/vscode.proposed.terminalCompletionProvider.d.ts +++ b/src/vscode-dts/vscode.proposed.terminalCompletionProvider.d.ts @@ -73,6 +73,8 @@ declare module 'vscode' { Tag = 12, Stash = 13, Remote = 14, + PullRequest = 15, + PullRequestDone = 16, } export interface TerminalCompletionContext {