mirror of
https://github.com/Microsoft/vscode
synced 2024-09-18 01:58:27 +00:00
Merge pull request #163476 from microsoft/alexd/delighted-emu
Clamp the hover result range to make sure the hover stays on the same view line
This commit is contained in:
commit
fd0b0ae532
|
@ -24,6 +24,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
|||
import { Context as SuggestContext } from 'vs/editor/contrib/suggest/browser/suggest';
|
||||
import { AsyncIterableObject } from 'vs/base/common/async';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
|
@ -240,7 +241,7 @@ export class ContentHoverController extends Disposable {
|
|||
}
|
||||
|
||||
private _renderMessages(anchor: HoverAnchor, messages: IHoverPart[]): void {
|
||||
const { showAtPosition, showAtRange, highlightRange } = ContentHoverController.computeHoverRanges(anchor.range, messages);
|
||||
const { showAtPosition, showAtRange, highlightRange } = ContentHoverController.computeHoverRanges(this._editor, anchor.range, messages);
|
||||
|
||||
const disposables = new DisposableStore();
|
||||
const statusBar = disposables.add(new EditorHoverStatusBar(this._keybindingService));
|
||||
|
@ -301,7 +302,19 @@ export class ContentHoverController extends Disposable {
|
|||
className: 'hoverHighlight'
|
||||
});
|
||||
|
||||
public static computeHoverRanges(anchorRange: Range, messages: IHoverPart[]) {
|
||||
public static computeHoverRanges(editor: ICodeEditor, anchorRange: Range, messages: IHoverPart[]) {
|
||||
let startColumnBoundary = 1;
|
||||
let endColumnBoundary = Constants.MAX_SAFE_SMALL_INTEGER;
|
||||
if (editor.hasModel()) {
|
||||
// Ensure the range is on the current view line
|
||||
const viewModel = editor._getViewModel();
|
||||
const coordinatesConverter = viewModel.coordinatesConverter;
|
||||
const anchorViewRange = coordinatesConverter.convertModelRangeToViewRange(anchorRange);
|
||||
const anchorViewRangeStart = new Position(anchorViewRange.startLineNumber, viewModel.getLineMinColumn(anchorViewRange.startLineNumber));
|
||||
const anchorViewRangeEnd = new Position(anchorViewRange.endLineNumber, viewModel.getLineMaxColumn(anchorViewRange.endLineNumber));
|
||||
startColumnBoundary = coordinatesConverter.convertViewPositionToModelPosition(anchorViewRangeStart).column;
|
||||
endColumnBoundary = coordinatesConverter.convertViewPositionToModelPosition(anchorViewRangeEnd).column;
|
||||
}
|
||||
// The anchor range is always on a single line
|
||||
const anchorLineNumber = anchorRange.startLineNumber;
|
||||
let renderStartColumn = anchorRange.startColumn;
|
||||
|
@ -313,8 +326,8 @@ export class ContentHoverController extends Disposable {
|
|||
highlightRange = Range.plusRange(highlightRange, msg.range);
|
||||
if (msg.range.startLineNumber === anchorLineNumber && msg.range.endLineNumber === anchorLineNumber) {
|
||||
// this message has a range that is completely sitting on the line of the anchor
|
||||
renderStartColumn = Math.min(renderStartColumn, msg.range.startColumn);
|
||||
renderEndColumn = Math.max(renderEndColumn, msg.range.endColumn);
|
||||
renderStartColumn = Math.max(Math.min(renderStartColumn, msg.range.startColumn), startColumnBoundary);
|
||||
renderEndColumn = Math.min(Math.max(renderEndColumn, msg.range.endColumn), endColumnBoundary);
|
||||
}
|
||||
if (msg.forceShowAtRange) {
|
||||
forceShowAtRange = msg.range;
|
||||
|
|
|
@ -8,20 +8,45 @@ import { ContentHoverController } from 'vs/editor/contrib/hover/browser/contentH
|
|||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IHoverPart } from 'vs/editor/contrib/hover/browser/hoverTypes';
|
||||
import { TestCodeEditorInstantiationOptions, withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
|
||||
|
||||
suite('Content Hover', () => {
|
||||
test('issue #151235: Gitlens hover shows up in the wrong place', () => {
|
||||
const actual = ContentHoverController.computeHoverRanges(
|
||||
new Range(5, 5, 5, 5),
|
||||
[<IHoverPart>{ range: new Range(4, 1, 5, 6) }]
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
actual,
|
||||
{
|
||||
showAtPosition: new Position(5, 5),
|
||||
showAtRange: new Range(5, 5, 5, 5),
|
||||
highlightRange: new Range(4, 1, 5, 6)
|
||||
}
|
||||
);
|
||||
const text = 'just some text';
|
||||
withTestCodeEditor(text, {}, (editor) => {
|
||||
const actual = ContentHoverController.computeHoverRanges(
|
||||
editor,
|
||||
new Range(5, 5, 5, 5),
|
||||
[<IHoverPart>{ range: new Range(4, 1, 5, 6) }]
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
actual,
|
||||
{
|
||||
showAtPosition: new Position(5, 5),
|
||||
showAtRange: new Range(5, 5, 5, 5),
|
||||
highlightRange: new Range(4, 1, 5, 6)
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #95328: Hover placement with word-wrap', () => {
|
||||
const text = 'just some text';
|
||||
const opts: TestCodeEditorInstantiationOptions = { wordWrap: 'wordWrapColumn', wordWrapColumn: 6 };
|
||||
withTestCodeEditor(text, opts, (editor) => {
|
||||
const actual = ContentHoverController.computeHoverRanges(
|
||||
editor,
|
||||
new Range(1, 8, 1, 8),
|
||||
[<IHoverPart>{ range: new Range(1, 1, 1, 15) }]
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
actual,
|
||||
{
|
||||
showAtPosition: new Position(1, 6),
|
||||
showAtRange: new Range(1, 6, 1, 11),
|
||||
highlightRange: new Range(1, 1, 1, 15)
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -133,7 +133,7 @@ function isTextModel(arg: ITextModel | string | string[] | ITextBufferFactory):
|
|||
|
||||
function _withTestCodeEditor(arg: ITextModel | string | string[] | ITextBufferFactory, options: TestCodeEditorInstantiationOptions, callback: (editor: ITestCodeEditor, viewModel: ViewModel, instantiationService: TestInstantiationService) => void): void;
|
||||
function _withTestCodeEditor(arg: ITextModel | string | string[] | ITextBufferFactory, options: TestCodeEditorInstantiationOptions, callback: (editor: ITestCodeEditor, viewModel: ViewModel, instantiationService: TestInstantiationService) => Promise<void>): Promise<void>;
|
||||
async function _withTestCodeEditor(arg: ITextModel | string | string[] | ITextBufferFactory, options: TestCodeEditorInstantiationOptions, callback: (editor: ITestCodeEditor, viewModel: ViewModel, instantiationService: TestInstantiationService) => Promise<void> | void): Promise<Promise<void> | void> {
|
||||
function _withTestCodeEditor(arg: ITextModel | string | string[] | ITextBufferFactory, options: TestCodeEditorInstantiationOptions, callback: (editor: ITestCodeEditor, viewModel: ViewModel, instantiationService: TestInstantiationService) => Promise<void> | void): Promise<void> | void {
|
||||
const disposables = new DisposableStore();
|
||||
const instantiationService = createCodeEditorServices(disposables, options.serviceCollection);
|
||||
delete options.serviceCollection;
|
||||
|
@ -149,12 +149,12 @@ async function _withTestCodeEditor(arg: ITextModel | string | string[] | ITextBu
|
|||
const editor = disposables.add(instantiateTestCodeEditor(instantiationService, model, options));
|
||||
const viewModel = editor.getViewModel()!;
|
||||
viewModel.setHasFocus(true);
|
||||
try {
|
||||
const result = callback(<ITestCodeEditor>editor, editor.getViewModel()!, instantiationService);
|
||||
await result;
|
||||
} finally {
|
||||
disposables.dispose();
|
||||
const result = callback(<ITestCodeEditor>editor, editor.getViewModel()!, instantiationService);
|
||||
if (result) {
|
||||
return result.then(() => disposables.dispose());
|
||||
}
|
||||
|
||||
disposables.dispose();
|
||||
}
|
||||
|
||||
export function createCodeEditorServices(disposables: DisposableStore, services: ServiceCollection = new ServiceCollection()): TestInstantiationService {
|
||||
|
|
Loading…
Reference in a new issue