Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions build/lib/stylelint/vscode-known-variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@
"--vscode-editorBracketHighlight-unexpectedBracket-foreground",
"--vscode-editorBracketMatch-background",
"--vscode-editorBracketMatch-border",
"--vscode-editorBracketMatch-foreground",
"--vscode-editorBracketPairGuide-activeBackground1",
"--vscode-editorBracketPairGuide-activeBackground2",
"--vscode-editorBracketPairGuide-activeBackground3",
Expand Down
1 change: 1 addition & 0 deletions extensions/git/src/api/git.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export interface Worktree {
readonly name: string;
readonly path: string;
readonly ref: string;
readonly main: boolean;
readonly detached: boolean;
}

Expand Down
26 changes: 15 additions & 11 deletions extensions/git/src/artifactProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { LogOutputChannel, SourceControlArtifactProvider, SourceControlArtifactGroup, SourceControlArtifact, Event, EventEmitter, ThemeIcon, l10n, workspace, Uri, Disposable, Command } from 'vscode';
import { coalesce, dispose, filterEvent, IDisposable, isCopilotWorktree } from './util';
import { Repository } from './repository';
import { Commit, Ref, RefType } from './api/git';
import { Ref, RefType, Worktree } from './api/git';
import { OperationKind } from './operation';

/**
Expand Down Expand Up @@ -55,11 +55,14 @@ function sortRefByName(refA: Ref, refB: Ref): number {
return 0;
}

function sortByCommitDateDesc(a: { commitDetails?: Commit }, b: { commitDetails?: Commit }): number {
const aCommitDate = a.commitDetails?.commitDate?.getTime() ?? 0;
const bCommitDate = b.commitDetails?.commitDate?.getTime() ?? 0;

return bCommitDate - aCommitDate;
function sortByWorktreeTypeAndNameAsc(a: Worktree, b: Worktree): number {
if (a.main && !b.main) {
return -1;
} else if (!a.main && b.main) {
return 1;
} else {
return a.name.localeCompare(b.name);
}
}

export class GitArtifactProvider implements SourceControlArtifactProvider, IDisposable {
Expand Down Expand Up @@ -164,18 +167,19 @@ export class GitArtifactProvider implements SourceControlArtifactProvider, IDisp
} else if (group === 'worktrees') {
const worktrees = await this.repository.getWorktreeDetails();

return worktrees.sort(sortByCommitDateDesc).map(w => ({
return worktrees.sort(sortByWorktreeTypeAndNameAsc).map(w => ({
id: w.path,
name: w.name,
description: coalesce([
w.detached ? l10n.t('detached') : w.ref.substring(11),
w.commitDetails?.hash.substring(0, shortCommitLength),
w.commitDetails?.message.split('\n')[0]
]).join(' \u2022 '),
icon: isCopilotWorktree(w.path)
? new ThemeIcon('chat-sparkle')
: new ThemeIcon('worktree'),
timestamp: w.commitDetails?.commitDate?.getTime(),
icon: w.main
? new ThemeIcon('repo')
: isCopilotWorktree(w.path)
? new ThemeIcon('chat-sparkle')
: new ThemeIcon('worktree')
}));
}
} catch (err) {
Expand Down
28 changes: 26 additions & 2 deletions extensions/git/src/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface IDotGit {
readonly path: string;
readonly commonPath?: string;
readonly superProjectPath?: string;
readonly isBare: boolean;
}

export interface IFileStatus {
Expand Down Expand Up @@ -575,7 +576,12 @@ export class Git {
commonDotGitPath = path.normalize(commonDotGitPath);
}

const raw = await fs.readFile(path.join(commonDotGitPath ?? dotGitPath, 'config'), 'utf8');
const coreSections = GitConfigParser.parse(raw).find(s => s.name === 'core');
const isBare = coreSections?.properties['bare'] === 'true';

return {
isBare,
path: dotGitPath,
commonPath: commonDotGitPath !== dotGitPath ? commonDotGitPath : undefined,
superProjectPath: superProjectPath ? path.normalize(superProjectPath) : undefined
Expand Down Expand Up @@ -2954,10 +2960,27 @@ export class Repository {
private async getWorktreesFS(): Promise<Worktree[]> {
try {
// List all worktree folder names
const worktreesPath = path.join(this.dotGit.commonPath ?? this.dotGit.path, 'worktrees');
const mainRepositoryPath = this.dotGit.commonPath ?? this.dotGit.path;
const worktreesPath = path.join(mainRepositoryPath, 'worktrees');
const dirents = await fs.readdir(worktreesPath, { withFileTypes: true });
const result: Worktree[] = [];

if (!this.dotGit.isBare) {
// Add main worktree for a non-bare repository
const headPath = path.join(mainRepositoryPath, 'HEAD');
const headContent = (await fs.readFile(headPath, 'utf8')).trim();

const mainRepositoryWorktreeName = path.basename(path.dirname(mainRepositoryPath));

result.push({
name: mainRepositoryWorktreeName,
path: path.dirname(mainRepositoryPath),
ref: headContent.replace(/^ref: /, ''),
detached: !headContent.startsWith('ref: '),
main: true
} satisfies Worktree);
}

for (const dirent of dirents) {
if (!dirent.isDirectory()) {
continue;
Expand All @@ -2977,7 +3000,8 @@ export class Repository {
// Remove 'ref: ' prefix
ref: headContent.replace(/^ref: /, ''),
// Detached if HEAD does not start with 'ref: '
detached: !headContent.startsWith('ref: ')
detached: !headContent.startsWith('ref: '),
main: false
});
} catch (err) {
if (/ENOENT/.test(err.message)) {
Expand Down
4 changes: 2 additions & 2 deletions extensions/git/src/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Branch, BranchQuery, Change, CommitOptions, DiffChange, FetchOptions, F
import { AutoFetcher } from './autofetch';
import { GitBranchProtectionProvider, IBranchProtectionProviderRegistry } from './branchProtection';
import { debounce, memoize, sequentialize, throttle } from './decorators';
import { Repository as BaseRepository, BlameInformation, Commit, CommitShortStat, GitError, LogFileOptions, LsTreeElement, PullOptions, RefQuery, Stash, Submodule, Worktree } from './git';
import { Repository as BaseRepository, BlameInformation, Commit, CommitShortStat, GitError, IDotGit, LogFileOptions, LsTreeElement, PullOptions, RefQuery, Stash, Submodule, Worktree } from './git';
import { GitHistoryProvider } from './historyProvider';
import { Operation, OperationKind, OperationManager, OperationResult } from './operation';
import { CommitCommandsCenter, IPostCommitCommandsProviderRegistry } from './postCommitCommands';
Expand Down Expand Up @@ -866,7 +866,7 @@ export class Repository implements Disposable {
return this.repository.rootRealPath;
}

get dotGit(): { path: string; commonPath?: string } {
get dotGit(): IDotGit {
return this.repository.dotGit;
}

Expand Down
16 changes: 4 additions & 12 deletions extensions/vb/language-configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,30 +32,22 @@
"flags": "i"
},
"increaseIndentPattern": {
"pattern": "^\\s*((If|ElseIf).*Then(?!\\s+(End\\s+If))\\s*(('|REM).*)?$)|\\b(Else|While|For|Do|Select\\s+Case|Case|Sub|Function|Class|Module|Enum|Structure|Interface|Namespace|With|Try|Catch|Finally|SyncLock|Using|Property|Get|Set|AddHandler|RaiseEvent|RemoveHandler|Event|Operator)\\b(?!.*\\bEnd\\s+(If|Sub|Function|Class|Module|Enum|Structure|Interface|Namespace|With|Select|Try|While|For|Property|Get|Set|SyncLock|Using|AddHandler|RaiseEvent|RemoveHandler|Event|Operator)\\b).*(('|REM).*)?$",
"pattern": "^\\s*((If|ElseIf).*Then(?!.*End\\s+If)\\s*(('|REM).*)?|(Else|While|For|Do|Select\\s+Case|Case|Sub|Function|Class|Module|Enum|Structure|Interface|Namespace|With|Try|Catch|Finally|SyncLock|Using|Property|Get|Set|AddHandler|RaiseEvent|RemoveHandler|Event|Operator)\\b(?!.*\\bEnd\\s+(If|Sub|Function|Class|Module|Enum|Structure|Interface|Namespace|With|Select|Try|While|For|Property|Get|Set|SyncLock|Using|AddHandler|RaiseEvent|RemoveHandler|Event|Operator)\\b).*(('|REM).*)?)$",
"flags": "i"
}
},
"onEnterRules": [
// Prevent indent after End statements, block terminators (Else, ElseIf, Loop, Next, etc.)
// Prevent indent after End statements and block terminators (Loop, Next, etc.)
{
"beforeText": { "pattern": "^\\s*((End\\s+(If|Sub|Function|Class|Module|Enum|Structure|Interface|Namespace|With|Select|Try|While|For|Property|Get|Set|SyncLock|Using|AddHandler|RaiseEvent|RemoveHandler|Event|Operator))|Else|ElseIf|Loop|Next|Wend|Until)\\b.*$", "flags": "i" },
"beforeText": { "pattern": "^\\s*((End\\s+(If|Sub|Function|Class|Module|Enum|Structure|Interface|Namespace|With|Select|Try|While|For|Property|Get|Set|SyncLock|Using|AddHandler|RaiseEvent|RemoveHandler|Event|Operator))|Loop|Next|Wend|Until)\\b.*$", "flags": "i" },
"action": {
"indent": "none"
}
},
// Prevent indent when pressing Enter on a blank line after End statements or block terminators
{
"beforeText": "^\\s*$",
"previousLineText": { "pattern": "^\\s*((End\\s+(If|Sub|Function|Class|Module|Enum|Structure|Interface|Namespace|With|Select|Try|While|For|Property|Get|Set|SyncLock|Using|AddHandler|RaiseEvent|RemoveHandler|Event|Operator))|Else|ElseIf|Loop|Next|Wend|Until)\\b.*$", "flags": "i" },
"action": {
"indent": "none"
}
},
// Prevent indent after lines ending with closing parenthesis (e.g., function calls, method invocations)
{
"beforeText": { "pattern": "^[^'\"]*\\)\\s*('.*)?$", "flags": "i" },
"afterText": "^(?!\\s*\\))",
"previousLineText": { "pattern": "^\\s*((End\\s+(If|Sub|Function|Class|Module|Enum|Structure|Interface|Namespace|With|Select|Try|While|For|Property|Get|Set|SyncLock|Using|AddHandler|RaiseEvent|RemoveHandler|Event|Operator))|Loop|Next|Wend|Until)\\b.*$", "flags": "i" },
"action": {
"indent": "none"
}
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.109.0",
"distro": "9ac7c0b1d7f8b73f10dc974777bccc7b55ee60d4",
"distro": "f84811280304020eab0bbc930e85b8f2180b1ed6",
"author": {
"name": "Microsoft Corporation"
},
Expand Down Expand Up @@ -240,4 +240,4 @@
"optionalDependencies": {
"windows-foreground-love": "0.5.0"
}
}
}
27 changes: 15 additions & 12 deletions src/vs/base/common/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,18 +208,7 @@ export interface IProductConfiguration {
readonly msftInternalDomains?: string[];
readonly linkProtectionTrustedDomains?: readonly string[];

readonly defaultAccount?: {
readonly authenticationProvider: {
readonly id: string;
readonly enterpriseProviderId: string;
readonly enterpriseProviderConfig: string;
readonly enterpriseProviderUriSetting: string;
readonly scopes: string[][];
};
readonly tokenEntitlementUrl: string;
readonly chatEntitlementUrl: string;
readonly mcpRegistryDataUrl: string;
};
readonly defaultAccount?: IDefaultAccountConfig;
readonly authClientIdMetadataUrl?: string;

readonly 'configurationSync.store'?: ConfigurationSyncStore;
Expand All @@ -242,6 +231,20 @@ export interface IProductConfiguration {
readonly extensionConfigurationPolicy?: IStringDictionary<IPolicy>;
}

export interface IDefaultAccountConfig {
readonly preferredExtensions: string[];
readonly authenticationProvider: {
readonly id: string;
readonly enterpriseProviderId: string;
readonly enterpriseProviderConfig: string;
readonly enterpriseProviderUriSetting: string;
readonly scopes: string[][];
};
readonly tokenEntitlementUrl: string;
readonly chatEntitlementUrl: string;
readonly mcpRegistryDataUrl: string;
}

export interface ITunnelApplicationConfig {
authenticationProviders: IStringDictionary<{ scopes: string[] }>;
editorWebUrl: string;
Expand Down
76 changes: 75 additions & 1 deletion src/vs/editor/browser/view/viewController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { IViewModel } from '../../common/viewModel.js';
import { IMouseWheelEvent } from '../../../base/browser/mouseEvent.js';
import { EditorOption } from '../../common/config/editorOptions.js';
import * as platform from '../../../base/common/platform.js';
import { StandardTokenType } from '../../common/encodedTokenAttributes.js';
import { ITextModel } from '../../common/model.js';

export interface IMouseDispatchData {
position: Position;
Expand Down Expand Up @@ -129,6 +131,67 @@ export class ViewController {
}
}

/**
* Selects content inside brackets if the position is right after an opening bracket or right before a closing bracket.
* @param pos The position in the model.
* @param model The text model.
*/
private static _trySelectBracketContent(model: ITextModel, pos: Position): Selection | undefined {
// Try to find bracket match if we're right after an opening bracket.
if (pos.column > 1) {
const pair = model.bracketPairs.matchBracket(pos.with(undefined, pos.column - 1));
if (pair && pair[0].getEndPosition().equals(pos)) {
return Selection.fromPositions(pair[0].getEndPosition(), pair[1].getStartPosition());
}
}

// Try to find bracket match if we're right before a closing bracket.
if (pos.column <= model.getLineMaxColumn(pos.lineNumber)) {
const pair = model.bracketPairs.matchBracket(pos);
if (pair && pair[1].getStartPosition().equals(pos)) {
return Selection.fromPositions(pair[0].getEndPosition(), pair[1].getStartPosition());
}
}

return undefined;
}

/**
* Selects content inside a string if the position is right after an opening quote or right before a closing quote.
* @param pos The position in the model.
* @param model The text model.
*/
private static _trySelectStringContent(model: ITextModel, pos: Position): Selection | undefined {
const { lineNumber, column } = pos;
const { tokenization: tokens } = model;

// Ensure we have accurate tokens for the line.
if (!tokens.hasAccurateTokensForLine(lineNumber)) {
if (tokens.isCheapToTokenize(lineNumber)) {
tokens.forceTokenization(lineNumber);
} else {
return undefined;
}
}

// Check if current token is a string.
const lineTokens = tokens.getLineTokens(lineNumber);
const index = lineTokens.findTokenIndexAtOffset(column - 1);
if (lineTokens.getStandardTokenType(index) !== StandardTokenType.String) {
return undefined;
}

// Get 1-based boundaries of the string content (excluding quotes).
const start = lineTokens.getStartOffset(index) + 2;
const end = lineTokens.getEndOffset(index);

if (column !== start && column !== end) {
return undefined;
}

return new Selection(lineNumber, start, lineNumber, end);
}

public dispatchMouse(data: IMouseDispatchData): void {
const options = this.configuration.options;
const selectionClipboardIsOn = (platform.isLinux && options.get(EditorOption.selectionClipboard));
Expand Down Expand Up @@ -179,7 +242,14 @@ export class ViewController {
if (data.inSelectionMode) {
this._wordSelectDrag(data.position, data.revealType);
} else {
this._wordSelect(data.position, data.revealType);
const model = this.viewModel.model;
const modelPos = this._convertViewToModelPosition(data.position);
const selection = ViewController._trySelectBracketContent(model, modelPos) || ViewController._trySelectStringContent(model, modelPos);
if (selection) {
this._select(selection);
} else {
this._wordSelect(data.position, data.revealType);
}
}
}
}
Expand Down Expand Up @@ -286,6 +356,10 @@ export class ViewController {
CoreNavigationCommands.LastCursorLineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));
}

private _select(selection: Selection): void {
CoreNavigationCommands.SetSelection.runCoreEditorCommand(this.viewModel, { source: 'mouse', selection });
}

private _selectAll(): void {
CoreNavigationCommands.SelectAll.runCoreEditorCommand(this.viewModel, { source: 'mouse' });
}
Expand Down
1 change: 1 addition & 0 deletions src/vs/editor/common/core/editorColorRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const editorCodeLensForeground = registerColor('editorCodeLens.foreground

export const editorBracketMatchBackground = registerColor('editorBracketMatch.background', { dark: '#0064001a', light: '#0064001a', hcDark: '#0064001a', hcLight: '#0000' }, nls.localize('editorBracketMatchBackground', 'Background color behind matching brackets'));
export const editorBracketMatchBorder = registerColor('editorBracketMatch.border', { dark: '#888', light: '#B9B9B9', hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('editorBracketMatchBorder', 'Color for matching brackets boxes'));
export const editorBracketMatchForeground = registerColor('editorBracketMatch.foreground', null, nls.localize('editorBracketMatchForeground', 'Foreground color for matching brackets'));

export const editorOverviewRulerBorder = registerColor('editorOverviewRuler.border', { dark: '#7f7f7f4d', light: '#7f7f7f4d', hcDark: '#7f7f7f4d', hcLight: '#666666' }, nls.localize('editorOverviewRulerBorder', 'Color of the overview ruler border.'));
export const editorOverviewRulerBackground = registerColor('editorOverviewRuler.background', null, nls.localize('editorOverviewRulerBackground', 'Background color of the editor overview ruler.'));
Expand Down
17 changes: 15 additions & 2 deletions src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import * as nls from '../../../../nls.js';
import { MenuId, MenuRegistry } from '../../../../platform/actions/common/actions.js';
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
import { registerColor } from '../../../../platform/theme/common/colorRegistry.js';
import { themeColorFromId } from '../../../../platform/theme/common/themeService.js';
import { registerThemingParticipant, themeColorFromId } from '../../../../platform/theme/common/themeService.js';
import { editorBracketMatchForeground } from '../../../common/core/editorColorRegistry.js';

const overviewRulerBracketMatchForeground = registerColor('editorOverviewRuler.bracketMatchForeground', '#A0A0A0', nls.localize('overviewRulerBracketMatchForeground', 'Overview ruler marker color for matching brackets.'));

Expand Down Expand Up @@ -300,6 +301,7 @@ export class BracketMatchingController extends Disposable implements IEditorCont
description: 'bracket-match-overview',
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
className: 'bracket-match',
inlineClassName: 'bracket-match-inline',
overviewRuler: {
color: themeColorFromId(overviewRulerBracketMatchForeground),
position: OverviewRulerLane.Center
Expand All @@ -309,7 +311,8 @@ export class BracketMatchingController extends Disposable implements IEditorCont
private static readonly _DECORATION_OPTIONS_WITHOUT_OVERVIEW_RULER = ModelDecorationOptions.register({
description: 'bracket-match-no-overview',
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
className: 'bracket-match'
className: 'bracket-match',
inlineClassName: 'bracket-match-inline'
});

private _updateBrackets(): void {
Expand Down Expand Up @@ -414,3 +417,13 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
},
order: 2
});

// Theming participant to ensure bracket-match color overrides bracket pair colorization
registerThemingParticipant((theme, collector) => {
const bracketMatchForeground = theme.getColor(editorBracketMatchForeground);
if (bracketMatchForeground) {
// Use higher specificity to override bracket pair colorization
// Apply color to inline class to avoid layout jumps
collector.addRule(`.monaco-editor .bracket-match-inline { color: ${bracketMatchForeground} !important; }`);
}
});
Loading
Loading