Skip to content

Commit 35911fd

Browse files
committed
Merge branch 'main' into joh/systematic-mockingbird
2 parents efce3c6 + 62f57f9 commit 35911fd

File tree

38 files changed

+588
-140
lines changed

38 files changed

+588
-140
lines changed

.github/commands.json

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,5 +538,62 @@
538538
"addLabel": "info-needed",
539539
"removeLabel": "~confirmation-needed",
540540
"comment": "Please diagnose the root cause of the issue by running the command `F1 > Help: Troubleshoot Issue` and following the instructions. Once you have done that, please update the issue with the results.\n\nHappy Coding!"
541+
},
542+
{
543+
"type": "label",
544+
"name": "~chat-rate-limiting",
545+
"removeLabel": "~chat-rate-limiting",
546+
"action": "close",
547+
"reason": "not_planned",
548+
"comment": "This issue is a duplicate of https://github.com/microsoft/vscode-copilot-release/issues/2627. Please refer to that issue for updates and discussions. Feel free to open a new issue if you think this is a different problem."
549+
},
550+
{
551+
"type": "label",
552+
"name": "~chat-request-failed",
553+
"removeLabel": "~chat-request-failed",
554+
"action": "close",
555+
"reason": "not_planned",
556+
"comment": "This issue is a duplicate of https://github.com/microsoft/vscode-copilot-release/issues/4332. Please refer to that issue for updates and discussions. Feel free to open a new issue if you think this is a different problem."
557+
},
558+
{
559+
"type": "label",
560+
"name": "~chat-rai-content-filters",
561+
"removeLabel": "~chat-rai-content-filters",
562+
"action": "close",
563+
"reason": "not_planned",
564+
"comment": "This issue is a duplicate of https://github.com/microsoft/vscode-copilot-release/issues/2625. Please refer to that issue for updates and discussions. Feel free to open a new issue if you think this is a different problem."
565+
},
566+
{
567+
"type": "label",
568+
"name": "~chat-public-code-blocking",
569+
"removeLabel": "~chat-public-code-blocking",
570+
"action": "close",
571+
"reason": "not_planned",
572+
"comment": "This issue is a duplicate of https://github.com/microsoft/vscode-copilot-release/issues/2626. Please refer to that issue for updates and discussions. Feel free to open a new issue if you think this is a different problem."
573+
},
574+
{
575+
"type": "label",
576+
"name": "~chat-lm-unavailable",
577+
"removeLabel": "~chat-lm-unavailable",
578+
"action": "close",
579+
"reason": "not_planned",
580+
"comment": "This issue is a duplicate of https://github.com/microsoft/vscode-copilot-release/issues/2116. Please refer to that issue for updates and discussions. Feel free to open a new issue if you think this is a different problem."
581+
},
582+
{
583+
"type": "label",
584+
"name": "~chat-authentication",
585+
"removeLabel": "~chat-authentication",
586+
"action": "close",
587+
"reason": "not_planned",
588+
"comment": "Please look at the following meta issue: https://github.com/microsoft/vscode-copilot-release/issues/11078, if the bug you are experiencing is not there, please comment on this closed issue thread so we can re-open it.",
589+
"assign": ["TylerLeonhardt"]
590+
},
591+
{
592+
"type": "label",
593+
"name": "~chat-no-response-returned",
594+
"removeLabel": "~chat-no-response-returned",
595+
"action": "close",
596+
"reason": "not_planned",
597+
"comment": "Please look at the following meta issue: https://github.com/microsoft/vscode-copilot-release/issues/7034. Please refer to that issue for updates and discussions. Feel free to open a new issue if you think this is a different problem."
541598
}
542599
]

.vscode/launch.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@
254254
"VSCODE_SKIP_PRELAUNCH": "1",
255255
},
256256
"cleanUp": "wholeBrowser",
257+
"killBehavior": "polite",
257258
"runtimeArgs": [
258259
"--inspect-brk=5875",
259260
"--no-cached-data",

build/lib/stylelint/vscode-known-variables.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@
320320
"--vscode-editorPane-background",
321321
"--vscode-editorRuler-foreground",
322322
"--vscode-editorStickyScroll-background",
323+
"--vscode-editorStickyScrollGutter-background",
323324
"--vscode-editorStickyScroll-border",
324325
"--vscode-editorStickyScroll-shadow",
325326
"--vscode-editorStickyScrollHover-background",
@@ -562,6 +563,7 @@
562563
"--vscode-peekViewEditor-matchHighlightBorder",
563564
"--vscode-peekViewEditorGutter-background",
564565
"--vscode-peekViewEditorStickyScroll-background",
566+
"--vscode-peekViewEditorStickyScrollGutter-background",
565567
"--vscode-peekViewResult-background",
566568
"--vscode-peekViewResult-fileForeground",
567569
"--vscode-peekViewResult-lineForeground",

extensions/terminal-suggest/src/fig/figInterface.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,11 @@ export async function getFigSuggestions(
3131
specs: Fig.Spec[],
3232
terminalContext: { commandLine: string; cursorPosition: number },
3333
availableCommands: ICompletionResource[],
34-
prefix: string,
34+
currentCommandAndArgString: string,
3535
tokenType: TokenType,
3636
shellIntegrationCwd: vscode.Uri | undefined,
3737
env: Record<string, string>,
3838
name: string,
39-
precedingText: string,
4039
executeExternals: IFigExecuteExternals,
4140
token?: vscode.CancellationToken,
4241
): Promise<IFigSpecSuggestionsResult> {
@@ -46,6 +45,7 @@ export async function getFigSuggestions(
4645
hasCurrentArg: false,
4746
items: [],
4847
};
48+
const currentCommand = currentCommandAndArgString.split(' ')[0];
4949
for (const spec of specs) {
5050
const specLabels = getFigSuggestionLabel(spec);
5151

@@ -66,7 +66,7 @@ export async function getFigSuggestions(
6666
const description = getFixSuggestionDescription(spec);
6767
result.items.push(createCompletionItem(
6868
terminalContext.cursorPosition,
69-
prefix,
69+
currentCommandAndArgString,
7070
{
7171
label: { label: specLabel, description },
7272
kind: vscode.TerminalCompletionItemKind.Method
@@ -83,8 +83,8 @@ export async function getFigSuggestions(
8383
: availableCommands.filter(command => specLabel === (command.definitionCommand ?? (typeof command.label === 'string' ? command.label : command.label.label))));
8484
if (
8585
!(osIsWindows()
86-
? commandAndAliases.some(e => precedingText.startsWith(`${removeAnyFileExtension((typeof e.label === 'string' ? e.label : e.label.label))} `))
87-
: commandAndAliases.some(e => precedingText.startsWith(`${typeof e.label === 'string' ? e.label : e.label.label} `)))
86+
? commandAndAliases.some(e => currentCommand.startsWith(removeAnyFileExtension((typeof e.label === 'string' ? e.label : e.label.label))))
87+
: commandAndAliases.some(e => currentCommand.startsWith(typeof e.label === 'string' ? e.label : e.label.label)))
8888
) {
8989
continue;
9090
}
@@ -93,7 +93,7 @@ export async function getFigSuggestions(
9393
if (!actualSpec) {
9494
continue;
9595
}
96-
const completionItemResult = await getFigSpecSuggestions(actualSpec, terminalContext, prefix, shellIntegrationCwd, env, name, executeExternals, token);
96+
const completionItemResult = await getFigSpecSuggestions(actualSpec, terminalContext, currentCommandAndArgString, shellIntegrationCwd, env, name, executeExternals, token);
9797
result.hasCurrentArg ||= !!completionItemResult?.hasCurrentArg;
9898
if (completionItemResult) {
9999
result.filesRequested ||= completionItemResult.filesRequested;

extensions/terminal-suggest/src/helpers/completionItem.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
import * as vscode from 'vscode';
77
import type { ICompletionResource } from '../types';
88

9-
export function createCompletionItem(cursorPosition: number, prefix: string, commandResource: ICompletionResource, detail?: string, documentation?: string | vscode.MarkdownString, kind?: vscode.TerminalCompletionItemKind): vscode.TerminalCompletionItem {
10-
const endsWithSpace = prefix.endsWith(' ');
11-
const lastWord = endsWithSpace ? '' : prefix.split(' ').at(-1) ?? '';
9+
export function createCompletionItem(cursorPosition: number, currentCommandString: string, commandResource: ICompletionResource, detail?: string, documentation?: string | vscode.MarkdownString, kind?: vscode.TerminalCompletionItemKind): vscode.TerminalCompletionItem {
10+
const endsWithSpace = currentCommandString.endsWith(' ');
11+
const lastWord = endsWithSpace ? '' : currentCommandString.split(' ').at(-1) ?? '';
1212
return {
1313
label: commandResource.label,
1414
detail: detail ?? commandResource.detail ?? '',

extensions/terminal-suggest/src/terminalSuggestMain.ts

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { getBashGlobals } from './shell/bash';
2020
import { getFishGlobals } from './shell/fish';
2121
import { getPwshGlobals } from './shell/pwsh';
2222
import { getZshGlobals } from './shell/zsh';
23-
import { getTokenType, TokenType } from './tokens';
23+
import { getTokenType, TokenType, shellTypeResetChars, defaultShellTypeResetChars } from './tokens';
2424
import type { ICompletionResource } from './types';
2525
import { createCompletionItem } from './helpers/completionItem';
2626
import { getFigSuggestions } from './fig/figInterface';
@@ -113,15 +113,15 @@ export async function activate(context: vscode.ExtensionContext) {
113113
}
114114
// Order is important here, add shell globals first so they are prioritized over path commands
115115
const commands = [...shellGlobals, ...commandsInPath.completionResources];
116-
const prefix = getPrefix(terminalContext.commandLine, terminalContext.cursorPosition);
116+
const currentCommandString = getCurrentCommandAndArgs(terminalContext.commandLine, terminalContext.cursorPosition, terminalShellType);
117117
const pathSeparator = isWindows ? '\\' : '/';
118118
const tokenType = getTokenType(terminalContext, terminalShellType);
119119
const result = await Promise.race([
120120
getCompletionItemsFromSpecs(
121121
availableSpecs,
122122
terminalContext,
123123
commands,
124-
prefix,
124+
currentCommandString,
125125
tokenType,
126126
terminal.shellIntegration?.cwd,
127127
getEnvAsRecord(currentTerminalEnv),
@@ -152,12 +152,14 @@ export async function activate(context: vscode.ExtensionContext) {
152152
}
153153

154154
/**
155-
* Adjusts the current working directory based on a given prefix if it is a folder.
156-
* @param prefix - The folder path prefix.
155+
* Adjusts the current working directory based on a given current command string if it is a folder.
156+
* @param currentCommandString - The current command string, which might contain a folder path prefix.
157157
* @param currentCwd - The current working directory.
158158
* @returns The new working directory.
159159
*/
160-
export async function resolveCwdFromPrefix(prefix: string, currentCwd?: vscode.Uri): Promise<vscode.Uri | undefined> {
160+
export async function resolveCwdFromCurrentCommandString(currentCommandString: string, currentCwd?: vscode.Uri): Promise<vscode.Uri | undefined> {
161+
const prefix = currentCommandString.split(/\s+/).pop()?.trim() ?? '';
162+
161163
if (!currentCwd) {
162164
return;
163165
}
@@ -195,7 +197,10 @@ export async function resolveCwdFromPrefix(prefix: string, currentCwd?: vscode.U
195197
return undefined;
196198
}
197199

198-
function getPrefix(commandLine: string, cursorPosition: number): string {
200+
// Retrurns the string that represents the current command and its arguments up to the cursor position.
201+
// Uses shell specific separators to determine the current command and its arguments.
202+
export function getCurrentCommandAndArgs(commandLine: string, cursorPosition: number, shellType: TerminalShellType | undefined): string {
203+
199204
// Return an empty string if the command line is empty after trimming
200205
if (commandLine.trim() === '') {
201206
return '';
@@ -209,11 +214,21 @@ function getPrefix(commandLine: string, cursorPosition: number): string {
209214
// Extract the part of the line up to the cursor position
210215
const beforeCursor = commandLine.slice(0, cursorPosition);
211216

212-
// Find the last sequence of non-whitespace characters before the cursor
213-
const match = beforeCursor.match(/(\S+)\s*$/);
217+
const resetChars = shellType ? shellTypeResetChars.get(shellType) ?? defaultShellTypeResetChars : defaultShellTypeResetChars;
218+
// Find the last reset character before the cursor
219+
let lastResetIndex = -1;
220+
for (const char of resetChars) {
221+
const idx = beforeCursor.lastIndexOf(char);
222+
if (idx > lastResetIndex) {
223+
lastResetIndex = idx;
224+
}
225+
}
226+
227+
// The start of the current command string is after the last reset char (plus one for the char itself)
228+
const currentCommandStart = lastResetIndex + 1;
229+
const currentCommandString = beforeCursor.slice(currentCommandStart).replace(/^\s+/, '');
214230

215-
// Return the match if found, otherwise undefined
216-
return match ? match[0] : '';
231+
return currentCommandString;
217232
}
218233

219234
export function asArray<T>(x: T | T[]): T[];
@@ -226,7 +241,7 @@ export async function getCompletionItemsFromSpecs(
226241
specs: Fig.Spec[],
227242
terminalContext: vscode.TerminalCompletionContext,
228243
availableCommands: ICompletionResource[],
229-
prefix: string,
244+
currentCommandString: string,
230245
tokenType: TokenType,
231246
shellIntegrationCwd: vscode.Uri | undefined,
232247
env: Record<string, string>,
@@ -240,17 +255,16 @@ export async function getCompletionItemsFromSpecs(
240255
let hasCurrentArg = false;
241256
let fileExtensions: string[] | undefined;
242257

243-
let precedingText = terminalContext.commandLine.slice(0, terminalContext.cursorPosition + 1);
244258
if (isWindows) {
245-
const spaceIndex = precedingText.indexOf(' ');
246-
const commandEndIndex = spaceIndex === -1 ? precedingText.length : spaceIndex;
247-
const lastDotIndex = precedingText.lastIndexOf('.', commandEndIndex);
259+
const spaceIndex = currentCommandString.indexOf(' ');
260+
const commandEndIndex = spaceIndex === -1 ? currentCommandString.length : spaceIndex;
261+
const lastDotIndex = currentCommandString.lastIndexOf('.', commandEndIndex);
248262
if (lastDotIndex > 0) { // Don't treat dotfiles as extensions
249-
precedingText = precedingText.substring(0, lastDotIndex) + precedingText.substring(spaceIndex);
263+
currentCommandString = currentCommandString.substring(0, lastDotIndex) + currentCommandString.substring(spaceIndex);
250264
}
251265
}
252266

253-
const result = await getFigSuggestions(specs, terminalContext, availableCommands, prefix, tokenType, shellIntegrationCwd, env, name, precedingText, executeExternals ?? { executeCommand, executeCommandTimeout }, token);
267+
const result = await getFigSuggestions(specs, terminalContext, availableCommands, currentCommandString, tokenType, shellIntegrationCwd, env, name, executeExternals ?? { executeCommand, executeCommandTimeout }, token);
254268
if (result) {
255269
hasCurrentArg ||= result.hasCurrentArg;
256270
filesRequested ||= result.filesRequested;
@@ -266,10 +280,12 @@ export async function getCompletionItemsFromSpecs(
266280
const labels = new Set(items.map((i) => typeof i.label === 'string' ? i.label : i.label.label));
267281
for (const command of availableCommands) {
268282
const commandTextLabel = typeof command.label === 'string' ? command.label : command.label.label;
269-
if (!labels.has(commandTextLabel)) {
283+
// Remove any file extension for matching on Windows
284+
const labelWithoutExtension = isWindows ? commandTextLabel.replace(/\.[^ ]+$/, '') : commandTextLabel;
285+
if (!labels.has(labelWithoutExtension)) {
270286
items.push(createCompletionItem(
271287
terminalContext.cursorPosition,
272-
prefix,
288+
currentCommandString,
273289
command,
274290
command.detail,
275291
command.documentation,
@@ -300,7 +316,7 @@ export async function getCompletionItemsFromSpecs(
300316

301317
let cwd: vscode.Uri | undefined;
302318
if (shellIntegrationCwd && (filesRequested || foldersRequested)) {
303-
cwd = await resolveCwdFromPrefix(prefix, shellIntegrationCwd);
319+
cwd = await resolveCwdFromCurrentCommandString(currentCommandString, shellIntegrationCwd);
304320
}
305321

306322
return { items, filesRequested, foldersRequested, fileExtensions, cwd };
@@ -361,3 +377,4 @@ export function sanitizeProcessEnvironment(env: Record<string, string>, ...prese
361377
}
362378
});
363379
}
380+

extensions/terminal-suggest/src/test/terminalSuggestMain.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { deepStrictEqual, strictEqual } from 'assert';
77
import 'mocha';
88
import { basename } from 'path';
9-
import { asArray, getCompletionItemsFromSpecs } from '../terminalSuggestMain';
9+
import { asArray, getCompletionItemsFromSpecs, getCurrentCommandAndArgs } from '../terminalSuggestMain';
1010
import { getTokenType } from '../tokens';
1111
import { cdTestSuiteSpec as cdTestSuite } from './completions/cd.test';
1212
import { codeSpecOptionsAndSubcommands, codeTestSuite, codeTunnelTestSuite } from './completions/code.test';
@@ -92,15 +92,15 @@ suite('Terminal Suggest', () => {
9292
test(`'${testSpec.input}' -> ${expectedString}`, async () => {
9393
const commandLine = testSpec.input.split('|')[0];
9494
const cursorPosition = testSpec.input.indexOf('|');
95-
const prefix = commandLine.slice(0, cursorPosition).split(' ').at(-1) || '';
95+
const currentCommandString = getCurrentCommandAndArgs(commandLine, cursorPosition, undefined);
9696
const filesRequested = testSpec.expectedResourceRequests?.type === 'files' || testSpec.expectedResourceRequests?.type === 'both';
9797
const foldersRequested = testSpec.expectedResourceRequests?.type === 'folders' || testSpec.expectedResourceRequests?.type === 'both';
9898
const terminalContext = { commandLine, cursorPosition, allowFallbackCompletions: true };
9999
const result = await getCompletionItemsFromSpecs(
100100
completionSpecs,
101101
terminalContext,
102102
availableCommands.map(c => { return { label: c }; }),
103-
prefix,
103+
currentCommandString,
104104
getTokenType(terminalContext, undefined),
105105
testPaths.cwd,
106106
{},

0 commit comments

Comments
 (0)