Update word link provider with new model
parent
000c0e1308
commit
5fc2e26dd9
|
@ -0,0 +1,19 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ILinkProvider, ILink } from 'xterm';
|
||||
import { TerminalLink } from 'vs/workbench/contrib/terminal/browser/links/terminalLink';
|
||||
|
||||
export abstract class TerminalBaseLinkProvider implements ILinkProvider {
|
||||
private _activeLinks: TerminalLink[] | undefined;
|
||||
|
||||
async provideLinks(bufferLineNumber: number, callback: (links: ILink[] | undefined) => void): Promise<void> {
|
||||
this._activeLinks?.forEach(l => l.dispose);
|
||||
this._activeLinks = await this._provideLinks(bufferLineNumber);
|
||||
callback(this._activeLinks);
|
||||
}
|
||||
|
||||
protected abstract _provideLinks(bufferLineNumber: number): Promise<TerminalLink[]> | TerminalLink[];
|
||||
}
|
|
@ -20,6 +20,9 @@ export const FOLDER_NOT_IN_WORKSPACE_LABEL = localize('openFolder', 'Open folder
|
|||
export class TerminalLink extends DisposableStore implements ILink {
|
||||
decorations: ILinkDecorations;
|
||||
|
||||
private _tooltipScheduler: RunOnceScheduler | undefined;
|
||||
private _hoverListeners: DisposableStore | undefined;
|
||||
|
||||
private readonly _onLeave = new Emitter<void>();
|
||||
public get onLeave(): Event<void> { return this._onLeave.event; }
|
||||
|
||||
|
@ -40,6 +43,14 @@ export class TerminalLink extends DisposableStore implements ILink {
|
|||
};
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
this._hoverListeners?.dispose();
|
||||
this._hoverListeners = undefined;
|
||||
this._tooltipScheduler?.dispose();
|
||||
this._tooltipScheduler = undefined;
|
||||
}
|
||||
|
||||
activate(event: MouseEvent | undefined, text: string): void {
|
||||
this._activateCallback(event, text);
|
||||
}
|
||||
|
@ -58,20 +69,21 @@ export class TerminalLink extends DisposableStore implements ILink {
|
|||
}));
|
||||
|
||||
const timeout = this._configurationService.getValue<number>('editor.hover.delay');
|
||||
const scheduler = new RunOnceScheduler(() => {
|
||||
this._tooltipScheduler = new RunOnceScheduler(() => {
|
||||
this._tooltipCallback(
|
||||
this,
|
||||
convertBufferRangeToViewport(this.range, this._viewportY),
|
||||
this._isHighConfidenceLink ? () => this._enableDecorations() : undefined,
|
||||
this._isHighConfidenceLink ? () => this._disableDecorations() : undefined
|
||||
);
|
||||
this.dispose();
|
||||
// this.dispose();
|
||||
}, timeout);
|
||||
this.add(scheduler);
|
||||
scheduler.schedule();
|
||||
this.add(this._tooltipScheduler);
|
||||
this._tooltipScheduler.schedule();
|
||||
|
||||
const origin = { x: event.pageX, y: event.pageY };
|
||||
this.add(dom.addDisposableListener(document, dom.EventType.MOUSE_MOVE, e => {
|
||||
this._hoverListeners = new DisposableStore();
|
||||
this._hoverListeners.add(dom.addDisposableListener(document, dom.EventType.MOUSE_MOVE, e => {
|
||||
// Update decorations
|
||||
if (this._isModifierDown(e)) {
|
||||
this._enableDecorations();
|
||||
|
@ -83,14 +95,17 @@ export class TerminalLink extends DisposableStore implements ILink {
|
|||
if (Math.abs(e.pageX - origin.x) > window.devicePixelRatio * 2 || Math.abs(e.pageY - origin.y) > window.devicePixelRatio * 2) {
|
||||
origin.x = e.pageX;
|
||||
origin.y = e.pageY;
|
||||
scheduler.schedule();
|
||||
this._tooltipScheduler?.schedule();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
leave(): void {
|
||||
this._hoverListeners?.dispose();
|
||||
this._hoverListeners = undefined;
|
||||
this._tooltipScheduler?.dispose();
|
||||
this._tooltipScheduler = undefined;
|
||||
this._onLeave.fire();
|
||||
this.dispose();
|
||||
}
|
||||
|
||||
private _enableDecorations(): void {
|
||||
|
|
|
@ -297,22 +297,22 @@ export class TerminalLinkManager extends DisposableStore {
|
|||
|
||||
public registerLinkProvider(): void {
|
||||
// Protocol links
|
||||
const wrappedActivateCallback = this._wrapLinkHandler((_, link) => this._handleProtocolLink(link));
|
||||
const protocolProvider = this._instantiationService.createInstance(TerminalProtocolLinkProvider, this._xterm, wrappedActivateCallback, this._tooltipCallback2.bind(this));
|
||||
this._linkProviders.push(this._xterm.registerLinkProvider(protocolProvider));
|
||||
// const wrappedActivateCallback = this._wrapLinkHandler((_, link) => this._handleProtocolLink(link));
|
||||
// const protocolProvider = this._instantiationService.createInstance(TerminalProtocolLinkProvider, this._xterm, wrappedActivateCallback, this._tooltipCallback2.bind(this));
|
||||
// this._linkProviders.push(this._xterm.registerLinkProvider(protocolProvider));
|
||||
|
||||
// Validated local links
|
||||
if (this._configurationService.getValue<ITerminalConfiguration>(TERMINAL_CONFIG_SECTION).enableFileLinks) {
|
||||
const wrappedTextLinkActivateCallback = this._wrapLinkHandler((_, link) => this._handleLocalLink(link));
|
||||
const validatedProvider = this._instantiationService.createInstance(TerminalValidatedLocalLinkProvider,
|
||||
this._xterm,
|
||||
this._processManager.os || OS,
|
||||
wrappedTextLinkActivateCallback,
|
||||
this._wrapLinkHandler.bind(this),
|
||||
this._tooltipCallback2.bind(this),
|
||||
async (link, cb) => cb(await this._resolvePath(link)));
|
||||
this._linkProviders.push(this._xterm.registerLinkProvider(validatedProvider));
|
||||
}
|
||||
// // Validated local links
|
||||
// if (this._configurationService.getValue<ITerminalConfiguration>(TERMINAL_CONFIG_SECTION).enableFileLinks) {
|
||||
// const wrappedTextLinkActivateCallback = this._wrapLinkHandler((_, link) => this._handleLocalLink(link));
|
||||
// const validatedProvider = this._instantiationService.createInstance(TerminalValidatedLocalLinkProvider,
|
||||
// this._xterm,
|
||||
// this._processManager.os || OS,
|
||||
// wrappedTextLinkActivateCallback,
|
||||
// this._wrapLinkHandler.bind(this),
|
||||
// this._tooltipCallback2.bind(this),
|
||||
// async (link, cb) => cb(await this._resolvePath(link)));
|
||||
// this._linkProviders.push(this._xterm.registerLinkProvider(validatedProvider));
|
||||
// }
|
||||
|
||||
// Word links
|
||||
const wordProvider = this._instantiationService.createInstance(TerminalWordLinkProvider, this._xterm, this._wrapLinkHandler.bind(this), this._tooltipCallback2.bind(this));
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Terminal, ILinkProvider, IViewportRange, IBufferCellPosition, ILink } from 'xterm';
|
||||
import { Terminal, IViewportRange } from 'xterm';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ITerminalConfiguration, TERMINAL_CONFIG_SECTION } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { TerminalLink } from 'vs/workbench/contrib/terminal/browser/links/terminalLink';
|
||||
|
@ -15,8 +15,9 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
|||
import { QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { XtermLinkMatcherHandler } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager';
|
||||
import { TerminalBaseLinkProvider } from 'vs/workbench/contrib/terminal/browser/links/terminalBaseLinkProvider';
|
||||
|
||||
export class TerminalWordLinkProvider implements ILinkProvider {
|
||||
export class TerminalWordLinkProvider extends TerminalBaseLinkProvider {
|
||||
private readonly _fileQueryBuilder = this._instantiationService.createInstance(QueryBuilder);
|
||||
|
||||
constructor(
|
||||
|
@ -30,54 +31,48 @@ export class TerminalWordLinkProvider implements ILinkProvider {
|
|||
@ISearchService private readonly _searchService: ISearchService,
|
||||
@IEditorService private readonly _editorService: IEditorService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public provideLink(position: IBufferCellPosition, callback: (link: ILink | undefined) => void): void {
|
||||
const start: IBufferCellPosition = { x: position.x, y: position.y };
|
||||
const end: IBufferCellPosition = { x: position.x, y: position.y };
|
||||
|
||||
protected _provideLinks(y: number): TerminalLink[] {
|
||||
// TODO: Support wrapping
|
||||
// Expand to the left until a word separator is hit
|
||||
const line = this._xterm.buffer.active.getLine(position.y - 1)!;
|
||||
let text = '';
|
||||
start.x++; // The hovered cell is considered first
|
||||
for (let x = position.x; x > 0; x--) {
|
||||
const cell = line.getCell(x - 1);
|
||||
if (!cell) {
|
||||
break;
|
||||
}
|
||||
const char = cell.getChars();
|
||||
const config = this._configurationService.getValue<ITerminalConfiguration>(TERMINAL_CONFIG_SECTION);
|
||||
if (cell.getWidth() !== 0 && config.wordSeparators.indexOf(char) >= 0) {
|
||||
break;
|
||||
}
|
||||
start.x = x;
|
||||
text = char + text;
|
||||
}
|
||||
|
||||
// No links were found (the hovered cell is whitespace)
|
||||
if (text.length === 0) {
|
||||
callback(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
// Expand to the right until a word separator is hit
|
||||
for (let x = position.x + 1; x <= line.length; x++) {
|
||||
const cell = line.getCell(x - 1);
|
||||
if (!cell) {
|
||||
break;
|
||||
}
|
||||
const char = cell.getChars();
|
||||
const config = this._configurationService.getValue<ITerminalConfiguration>(TERMINAL_CONFIG_SECTION);
|
||||
if (cell.getWidth() !== 0 && config.wordSeparators.indexOf(char) >= 0) {
|
||||
break;
|
||||
}
|
||||
end.x = x;
|
||||
text += char;
|
||||
}
|
||||
|
||||
// Dispose of all old links if new links are provides, links are only cached for the current line
|
||||
const result: TerminalLink[] = [];
|
||||
const wordSeparators = this._configurationService.getValue<ITerminalConfiguration>(TERMINAL_CONFIG_SECTION).wordSeparators;
|
||||
const activateCallback = this._wrapLinkHandler((_, link) => this._activate(link));
|
||||
callback(new TerminalLink({ start, end }, text, this._xterm.buffer.active.viewportY, activateCallback, this._tooltipCallback, false, localize('searchWorkspace', 'Search workspace'), this._configurationService));
|
||||
|
||||
const line = this._xterm.buffer.active.getLine(y - 1)!;
|
||||
let text = '';
|
||||
let startX = -1;
|
||||
const cellData = line.getCell(0)!;
|
||||
for (let x = 0; x < line.length; x++) {
|
||||
line.getCell(x, cellData);
|
||||
const chars = cellData.getChars();
|
||||
|
||||
// Add a link if this is a separator
|
||||
if (wordSeparators.indexOf(chars) >= 0) {
|
||||
if (startX !== -1) {
|
||||
result.push(new TerminalLink({ start: { x: startX + 1, y }, end: { x, y } }, text, this._xterm.buffer.active.viewportY, activateCallback, this._tooltipCallback, false, localize('searchWorkspace', 'Search workspace'), this._configurationService));
|
||||
text = '';
|
||||
startX = -1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Mark the start of a link if it hasn't started yet
|
||||
if (startX === -1) {
|
||||
startX = x;
|
||||
}
|
||||
|
||||
text += chars;
|
||||
}
|
||||
|
||||
// Add the final link if there is one
|
||||
if (startX !== -1) {
|
||||
result.push(new TerminalLink({ start: { x: startX + 1, y }, end: { x: line.length, y } }, text, this._xterm.buffer.active.viewportY, activateCallback, this._tooltipCallback, false, localize('searchWorkspace', 'Search workspace'), this._configurationService));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async _activate(link: string) {
|
||||
|
|
Loading…
Reference in New Issue