Skip to content

Commit a231a0c

Browse files
authored
Merge branch 'main' into extensionCodeblockLangFix
2 parents 5128f70 + afd7c3c commit a231a0c

File tree

17 files changed

+153
-76
lines changed

17 files changed

+153
-76
lines changed

src/vs/editor/common/config/editorOptions.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -4195,7 +4195,7 @@ export interface IInlineSuggestOptions {
41954195
edits?: {
41964196
experimental?: {
41974197
enabled?: boolean;
4198-
useMixedLinesDiff?: 'never' | 'whenPossible' | 'afterJumpWhenPossible';
4198+
useMixedLinesDiff?: 'never' | 'whenPossible' | 'forStableInsertions' | 'afterJumpWhenPossible';
41994199
useInterleavedLinesDiff?: 'never' | 'always' | 'afterJump';
42004200
onlyShowWhenCloseToCursor?: boolean;
42014201
};
@@ -4227,7 +4227,7 @@ class InlineEditorSuggest extends BaseEditorOption<EditorOption.inlineSuggest, I
42274227
edits: {
42284228
experimental: {
42294229
enabled: true,
4230-
useMixedLinesDiff: 'never',
4230+
useMixedLinesDiff: 'forStableInsertions',
42314231
useInterleavedLinesDiff: 'never',
42324232
onlyShowWhenCloseToCursor: true,
42334233
},
@@ -4277,7 +4277,7 @@ class InlineEditorSuggest extends BaseEditorOption<EditorOption.inlineSuggest, I
42774277
type: 'string',
42784278
default: defaults.edits.experimental.useMixedLinesDiff,
42794279
description: nls.localize('inlineSuggest.edits.experimental.useMixedLinesDiff', "Controls whether to enable experimental edits in inline suggestions."),
4280-
enum: ['never', 'whenPossible'],
4280+
enum: ['never', 'whenPossible', 'forStableInsertions', 'afterJumpWhenPossible'],
42814281
},
42824282
'editor.inlineSuggest.edits.experimental.useInterleavedLinesDiff': {
42834283
type: 'string',
@@ -4310,7 +4310,7 @@ class InlineEditorSuggest extends BaseEditorOption<EditorOption.inlineSuggest, I
43104310
edits: {
43114311
experimental: {
43124312
enabled: boolean(input.edits?.experimental?.enabled, this.defaultValue.edits.experimental.enabled),
4313-
useMixedLinesDiff: stringSet(input.edits?.experimental?.useMixedLinesDiff, this.defaultValue.edits.experimental.useMixedLinesDiff, ['never', 'whenPossible', 'afterJumpWhenPossible']),
4313+
useMixedLinesDiff: stringSet(input.edits?.experimental?.useMixedLinesDiff, this.defaultValue.edits.experimental.useMixedLinesDiff, ['never', 'whenPossible', 'forStableInsertions', 'afterJumpWhenPossible']),
43144314
useInterleavedLinesDiff: stringSet(input.edits?.experimental?.useInterleavedLinesDiff, this.defaultValue.edits.experimental.useInterleavedLinesDiff, ['never', 'always', 'afterJump']),
43154315
onlyShowWhenCloseToCursor: boolean(input.edits?.experimental?.onlyShowWhenCloseToCursor, this.defaultValue.edits.experimental.onlyShowWhenCloseToCursor),
43164316
},

src/vs/editor/contrib/hover/browser/contentHoverWidget.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,15 @@ export class ContentHoverWidget extends ResizableContentWidget {
138138

139139
private _setHoverWidgetMaxDimensions(width: number | string, height: number | string): void {
140140
ContentHoverWidget._applyMaxDimensions(this._hover.contentsDomNode, width, height);
141+
ContentHoverWidget._applyMaxDimensions(this._hover.scrollbar.getDomNode(), width, height);
141142
ContentHoverWidget._applyMaxDimensions(this._hover.containerDomNode, width, height);
142143
this._hover.containerDomNode.style.setProperty('--vscode-hover-maxWidth', typeof width === 'number' ? `${width}px` : width);
143144
this._layoutContentWidget();
144145
}
145146

146147
private _setAdjustedHoverWidgetDimensions(size: dom.Dimension): void {
147148
this._setHoverWidgetMaxDimensions('none', 'none');
148-
const width = size.width;
149-
const height = size.height;
150-
this._setHoverWidgetDimensions(width, height);
149+
this._setHoverWidgetDimensions(size.width, size.height);
151150
}
152151

153152
private _updateResizableNodeMaxDimensions(): void {
@@ -297,14 +296,14 @@ export class ContentHoverWidget extends ResizableContentWidget {
297296
private _updateMaxDimensions() {
298297
const height = Math.max(this._editor.getLayoutInfo().height / 4, 250, ContentHoverWidget._lastDimensions.height);
299298
const width = Math.max(this._editor.getLayoutInfo().width * 0.66, 750, ContentHoverWidget._lastDimensions.width);
299+
this._resizableNode.maxSize = new dom.Dimension(width, height);
300300
this._setHoverWidgetMaxDimensions(width, height);
301301
}
302302

303303
private _render(renderedHover: RenderedContentHover) {
304304
this._setRenderedHover(renderedHover);
305305
this._updateFont();
306306
this._updateContent(renderedHover.domNode);
307-
this._updateMaxDimensions();
308307
this.onContentsChanged();
309308
// Simply force a synchronous render on the editor
310309
// such that the widget does not really render with left = '0px'
@@ -371,6 +370,7 @@ export class ContentHoverWidget extends ResizableContentWidget {
371370
const layoutInfo = this._editor.getLayoutInfo();
372371
this._resizableNode.layout(layoutInfo.height, layoutInfo.width);
373372
this._setHoverWidgetDimensions('auto', 'auto');
373+
this._updateMaxDimensions();
374374
}
375375

376376
public setMinimumDimensions(dimensions: dom.Dimension): void {

src/vs/editor/contrib/hover/browser/hover.css

+8-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@
1313
box-sizing: content-box;
1414
}
1515

16+
.monaco-editor .monaco-resizable-hover > .monaco-hover {
17+
border: none;
18+
border-radius: none;
19+
}
20+
1621
.monaco-editor .monaco-hover {
22+
border: 1px solid var(--vscode-editorHoverWidget-border);
23+
border-radius: 3px;
1724
color: var(--vscode-editorHoverWidget-foreground);
1825
background-color: var(--vscode-editorHoverWidget-background);
1926
}
@@ -31,7 +38,7 @@
3138
}
3239

3340
.monaco-editor .monaco-hover .hover-row .hover-row-contents {
34-
min-width:0;
41+
min-width: 0;
3542
display: flex;
3643
flex-direction: column;
3744
}
@@ -65,5 +72,3 @@
6572
.monaco-editor .monaco-hover code {
6673
background-color: var(--vscode-textCodeBlock-background);
6774
}
68-
69-

src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsModel.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export class InlineCompletionsModel extends Disposable {
4747

4848
// We use a semantic id to keep the same inline completion selected even if the provider reorders the completions.
4949
private readonly _selectedInlineCompletionId = observableValue<string | undefined>(this, undefined);
50-
private readonly _primaryPosition = derived(this, reader => this._positions.read(reader)[0] ?? new Position(1, 1));
50+
public readonly primaryPosition = derived(this, reader => this._positions.read(reader)[0] ?? new Position(1, 1));
5151

5252
private _isAcceptingPartially = false;
5353
public get isAcceptingPartially() { return this._isAcceptingPartially; }
@@ -194,7 +194,7 @@ export class InlineCompletionsModel extends Disposable {
194194
});
195195
}
196196

197-
const cursorPosition = this._primaryPosition.get();
197+
const cursorPosition = this.primaryPosition.get();
198198
if (changeSummary.dontRefetch) {
199199
return Promise.resolve(true);
200200
}
@@ -257,7 +257,7 @@ export class InlineCompletionsModel extends Disposable {
257257
private readonly _inlineCompletionItems = derivedOpts({ owner: this }, reader => {
258258
const c = this._source.inlineCompletions.read(reader);
259259
if (!c) { return undefined; }
260-
const cursorPosition = this._primaryPosition.read(reader);
260+
const cursorPosition = this.primaryPosition.read(reader);
261261
let inlineEdit: InlineCompletionWithUpdatedRange | undefined = undefined;
262262
const visibleCompletions: InlineCompletionWithUpdatedRange[] = [];
263263
for (const completion of c.inlineCompletions) {
@@ -355,10 +355,10 @@ export class InlineCompletionsModel extends Disposable {
355355
let edit = item.inlineEdit.toSingleTextEdit(reader);
356356
edit = singleTextRemoveCommonPrefix(edit, model);
357357

358-
const cursorPos = this._primaryPosition.read(reader);
358+
const cursorPos = this.primaryPosition.read(reader);
359359
const cursorAtInlineEdit = LineRange.fromRangeInclusive(edit.range).addMargin(1, 1).contains(cursorPos.lineNumber);
360360

361-
const cursorDist = LineRange.fromRange(edit.range).distanceToLine(this._primaryPosition.read(reader).lineNumber);
361+
const cursorDist = LineRange.fromRange(edit.range).distanceToLine(this.primaryPosition.read(reader).lineNumber);
362362

363363
if (this._onlyShowWhenCloseToCursor.read(reader) && cursorDist > 3 && !item.inlineEdit.request.isExplicitRequest && !this._inAcceptFlow.read(reader)) {
364364
return undefined;

src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineDiffView.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { classNames } from './utils.js';
2323
export interface IOriginalEditorInlineDiffViewState {
2424
diff: DetailedLineRangeMapping[];
2525
modifiedText: AbstractText;
26-
mode: 'mixedLines' | 'interleavedLines' | 'sideBySide';
26+
mode: 'mixedLines' | 'ghostText' | 'interleavedLines' | 'sideBySide';
2727

2828
modifiedCodeEditor: ICodeEditor;
2929
}
@@ -111,7 +111,7 @@ export class OriginalEditorInlineDiffView extends Disposable {
111111
if (!diff) { return undefined; }
112112

113113
const modified = diff.modifiedText;
114-
const showInline = diff.mode === 'mixedLines';
114+
const showInline = diff.mode === 'mixedLines' || diff.mode === 'ghostText';
115115

116116
const showEmptyDecorations = true;
117117

@@ -214,7 +214,7 @@ export class OriginalEditorInlineDiffView extends Disposable {
214214
description: 'inserted-text',
215215
before: {
216216
content: insertedText,
217-
inlineClassName: 'inlineCompletions-char-insert',
217+
inlineClassName: diff.mode === 'ghostText' ? 'ghost-text-decoration' : 'inlineCompletions-char-insert',
218218
},
219219
zIndex: 2,
220220
showIfCollapsed: true,

src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/view.ts

+61-17
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,23 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { Disposable } from '../../../../../../base/common/lifecycle.js';
7-
import { derived, IObservable } from '../../../../../../base/common/observable.js';
7+
import { derived, IObservable, IReader } from '../../../../../../base/common/observable.js';
88
import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js';
99
import { ICodeEditor } from '../../../../../browser/editorBrowser.js';
1010
import { observableCodeEditor } from '../../../../../browser/observableCodeEditor.js';
1111
import { EditorOption } from '../../../../../common/config/editorOptions.js';
1212
import { LineRange } from '../../../../../common/core/lineRange.js';
13+
import { Position } from '../../../../../common/core/position.js';
1314
import { StringText } from '../../../../../common/core/textEdit.js';
1415
import { DetailedLineRangeMapping, lineRangeMappingFromRangeMappings, RangeMapping } from '../../../../../common/diff/rangeMapping.js';
1516
import { TextModel } from '../../../../../common/model/textModel.js';
16-
import './view.css';
17+
import { InlineCompletionsModel } from '../../model/inlineCompletionsModel.js';
18+
import { IInlineEditsIndicatorState, InlineEditsIndicator } from './indicatorView.js';
1719
import { IOriginalEditorInlineDiffViewState, OriginalEditorInlineDiffView } from './inlineDiffView.js';
20+
import { InlineEditsSideBySideDiff } from './sideBySideDiff.js';
1821
import { applyEditToModifiedRangeMappings, createReindentEdit } from './utils.js';
19-
import { IInlineEditsIndicatorState, InlineEditsIndicator } from './indicatorView.js';
20-
import { InlineCompletionsModel } from '../../model/inlineCompletionsModel.js';
22+
import './view.css';
2123
import { InlineEditWithChanges } from './viewAndDiffProducer.js';
22-
import { InlineEditsSideBySideDiff } from './sideBySideDiff.js';
2324

2425
export class InlineEditsView extends Disposable {
2526
private readonly _editorObs = observableCodeEditor(this._editor);
@@ -37,7 +38,7 @@ export class InlineEditsView extends Disposable {
3738
}
3839

3940
private readonly _uiState = derived<{
40-
state: 'collapsed' | 'mixedLines' | 'interleavedLines' | 'sideBySide';
41+
state: 'collapsed' | 'mixedLines' | 'ghostText' | 'interleavedLines' | 'sideBySide';
4142
diff: DetailedLineRangeMapping[];
4243
edit: InlineEditWithChanges;
4344
newText: string;
@@ -55,17 +56,7 @@ export class InlineEditsView extends Disposable {
5556
let newText = edit.edit.apply(edit.originalText);
5657
let diff = lineRangeMappingFromRangeMappings(mappings, edit.originalText, new StringText(newText));
5758

58-
let state: 'collapsed' | 'mixedLines' | 'interleavedLines' | 'sideBySide';
59-
if (edit.isCollapsed) {
60-
state = 'collapsed';
61-
} else if (diff.every(m => OriginalEditorInlineDiffView.supportsInlineDiffRendering(m)) &&
62-
(this._useMixedLinesDiff.read(reader) === 'whenPossible' || (edit.userJumpedToIt && this._useMixedLinesDiff.read(reader) === 'afterJumpWhenPossible'))) {
63-
state = 'mixedLines';
64-
} else if ((this._useInterleavedLinesDiff.read(reader) === 'always' || (edit.userJumpedToIt && this._useInterleavedLinesDiff.read(reader) === 'afterJump'))) {
65-
state = 'interleavedLines';
66-
} else {
67-
state = 'sideBySide';
68-
}
59+
const state = this.determinRenderState(edit, reader, diff);
6960

7061
if (state === 'sideBySide') {
7162
const indentationAdjustmentEdit = createReindentEdit(newText, edit.modifiedLineRange);
@@ -140,4 +131,57 @@ export class InlineEditsView extends Disposable {
140131
}),
141132
this._model,
142133
));
134+
135+
private determinRenderState(edit: InlineEditWithChanges, reader: IReader, diff: DetailedLineRangeMapping[]) {
136+
if (edit.isCollapsed) {
137+
return 'collapsed';
138+
}
139+
140+
if (
141+
(this._useMixedLinesDiff.read(reader) === 'whenPossible' || (edit.userJumpedToIt && this._useMixedLinesDiff.read(reader) === 'afterJumpWhenPossible'))
142+
&& diff.every(m => OriginalEditorInlineDiffView.supportsInlineDiffRendering(m))
143+
) {
144+
return 'mixedLines';
145+
}
146+
147+
if (
148+
this._useMixedLinesDiff.read(reader) === 'forStableInsertions'
149+
&& isInsertionAfterPosition(diff, edit.cursorPosition)
150+
) {
151+
return 'ghostText';
152+
}
153+
154+
if (this._useInterleavedLinesDiff.read(reader) === 'always' || (edit.userJumpedToIt && this._useInterleavedLinesDiff.read(reader) === 'afterJump')) {
155+
return 'interleavedLines';
156+
}
157+
158+
return 'sideBySide';
159+
}
160+
}
161+
162+
function isInsertionAfterPosition(diff: DetailedLineRangeMapping[], position: Position | null) {
163+
if (!position) {
164+
return false;
165+
}
166+
const pos = position;
167+
168+
return diff.every(m => m.innerChanges!.every(r => isStableWordInsertion(r)));
169+
170+
function isStableWordInsertion(r: RangeMapping) {
171+
if (!r.originalRange.isEmpty()) {
172+
return false;
173+
}
174+
const isInsertionWithinLine = r.modifiedRange.startLineNumber === r.modifiedRange.endLineNumber;
175+
if (!isInsertionWithinLine) {
176+
return false;
177+
}
178+
const insertPosition = r.originalRange.getStartPosition();
179+
if (pos.isBeforeOrEqual(insertPosition)) {
180+
return true;
181+
}
182+
if (insertPosition.lineNumber < pos.lineNumber) {
183+
return true;
184+
}
185+
return false;
186+
}
143187
}

src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/viewAndDiffProducer.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ export class InlineEditsViewAndDiffProducer extends Disposable {
5353
});
5454

5555
private readonly _inlineEditPromise = derived<IObservable<InlineEditWithChanges | undefined> | undefined>(this, (reader) => {
56+
const model = this._model.read(reader);
57+
if (!model) { return undefined; }
5658
const inlineEdit = this._edit.read(reader);
5759
if (!inlineEdit) { return undefined; }
5860

@@ -86,7 +88,7 @@ export class InlineEditsViewAndDiffProducer extends Disposable {
8688
));
8789
const diffEdits = new TextEdit(edits);
8890

89-
return new InlineEditWithChanges(text, diffEdits, inlineEdit.isCollapsed, inlineEdit.renderExplicitly, inlineEdit.commands, inlineEdit.inlineCompletion); //inlineEdit.showInlineIfPossible);
91+
return new InlineEditWithChanges(text, diffEdits, inlineEdit.isCollapsed, model.primaryPosition.get(), inlineEdit.renderExplicitly, inlineEdit.commands, inlineEdit.inlineCompletion); //inlineEdit.showInlineIfPossible);
9092
});
9193
});
9294

@@ -116,6 +118,7 @@ export class InlineEditWithChanges {
116118
public readonly originalText: AbstractText,
117119
public readonly edit: TextEdit,
118120
public readonly isCollapsed: boolean,
121+
public readonly cursorPosition: Position,
119122
public readonly userJumpedToIt: boolean,
120123
public readonly commands: readonly Command[],
121124
public readonly inlineCompletion: InlineCompletionItem,
@@ -126,6 +129,7 @@ export class InlineEditWithChanges {
126129
return this.originalText.getValue() === other.originalText.getValue() &&
127130
this.edit.equals(other.edit) &&
128131
this.isCollapsed === other.isCollapsed &&
132+
this.cursorPosition.equals(other.cursorPosition) &&
129133
this.userJumpedToIt === other.userJumpedToIt &&
130134
this.commands === other.commands &&
131135
this.inlineCompletion === other.inlineCompletion;

src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ export class StickyScrollController extends Disposable implements IEditorContrib
468468
this._readConfiguration();
469469
}
470470

471-
if (event.hasChanged(EditorOption.lineNumbers)) {
471+
if (event.hasChanged(EditorOption.lineNumbers) || event.hasChanged(EditorOption.folding) || event.hasChanged(EditorOption.showFoldingControls)) {
472472
this._renderStickyScroll(0);
473473
}
474474
}

src/vs/monaco.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4602,7 +4602,7 @@ declare namespace monaco.editor {
46024602
edits?: {
46034603
experimental?: {
46044604
enabled?: boolean;
4605-
useMixedLinesDiff?: 'never' | 'whenPossible' | 'afterJumpWhenPossible';
4605+
useMixedLinesDiff?: 'never' | 'whenPossible' | 'forStableInsertions' | 'afterJumpWhenPossible';
46064606
useInterleavedLinesDiff?: 'never' | 'always' | 'afterJump';
46074607
onlyShowWhenCloseToCursor?: boolean;
46084608
};

src/vs/platform/theme/common/iconRegistry.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,19 @@ export interface IIconRegistry {
145145
getIconFont(id: string): IconFontDefinition | undefined;
146146
}
147147

148+
// regexes for validation of font properties
149+
150+
export const fontIdRegex = /^([\w_-]+)$/;
151+
export const fontStyleRegex = /^(normal|italic|(oblique[ \w\s-]+))$/;
152+
export const fontWeightRegex = /^(normal|bold|lighter|bolder|(\d{0-1000}))$/;
153+
export const fontSizeRegex = /^([\w_.%+-]+)$/;
154+
export const fontFormatRegex = /^woff|woff2|truetype|opentype|embedded-opentype|svg$/;
155+
export const fontCharacterRegex = /^([^\\]|\\[a-fA-F0-9]+)$/u;
156+
export const fontColorRegex = /^#[0-9a-fA-F]{0,6}$/;
157+
158+
export const fontCharacterErrorMessage = localize('schema.fontCharacter.formatError', 'The fontCharacter must be a single letter or a backslash followed by unicode code points in hexadecimal.');
159+
export const fontIdErrorMessage = localize('schema.fontId.formatError', 'The font ID must only contain letters, numbers, underscores and dashes.');
160+
148161
class IconRegistry implements IIconRegistry {
149162

150163
private readonly _onDidChange = new Emitter<void>();
@@ -156,8 +169,8 @@ class IconRegistry implements IIconRegistry {
156169
icons: {
157170
type: 'object',
158171
properties: {
159-
fontId: { type: 'string', description: localize('iconDefinition.fontId', 'The id of the font to use. If not set, the font that is defined first is used.') },
160-
fontCharacter: { type: 'string', description: localize('iconDefinition.fontCharacter', 'The font character associated with the icon definition.') }
172+
fontId: { type: 'string', description: localize('iconDefinition.fontId', 'The id of the font to use. If not set, the font that is defined first is used.'), pattern: fontIdRegex.source, patternErrorMessage: fontIdErrorMessage },
173+
fontCharacter: { type: 'string', description: localize('iconDefinition.fontCharacter', 'The font character associated with the icon definition.'), pattern: fontCharacterRegex.source, patternErrorMessage: fontCharacterErrorMessage }
161174
},
162175
additionalProperties: false,
163176
defaultSnippets: [{ body: { fontCharacter: '\\\\e030' } }]
@@ -318,7 +331,6 @@ iconRegistry.onDidChange(() => {
318331
}
319332
});
320333

321-
322334
//setTimeout(_ => console.log(iconRegistry.toString()), 5000);
323335

324336

src/vs/workbench/api/browser/mainThreadDebugService.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
397397
}
398398

399399
public $acceptDAExit(handle: number, code: number, signal: string) {
400-
this.getDebugAdapter(handle).fireExit(handle, code, signal);
400+
// don't use getDebugAdapter since an error can be expected on a post-close
401+
this._debugAdapters.get(handle)?.fireExit(handle, code, signal);
401402
}
402403

403404
private getDebugAdapter(handle: number): ExtensionHostDebugAdapter {

0 commit comments

Comments
 (0)