Skip to content

Commit

Permalink
Merge pull request #3230 from marvinthepa/682_url_selector
Browse files Browse the repository at this point in the history
Use linkifier2 to double click select links
  • Loading branch information
Tyriar authored Mar 30, 2021
2 parents 36c436d + d2471b4 commit dd952ac
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 21 deletions.
13 changes: 2 additions & 11 deletions src/browser/Linkifier2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,20 @@
* @license MIT
*/

import { ILinkifier2, ILinkProvider, IBufferCellPosition, ILink, ILinkifierEvent, ILinkDecorations } from 'browser/Types';
import { ILinkifier2, ILinkProvider, IBufferCellPosition, ILink, ILinkifierEvent, ILinkDecorations, ILinkWithState } from 'browser/Types';
import { IDisposable } from 'common/Types';
import { IMouseService, IRenderService } from './services/Services';
import { IBufferService } from 'common/services/Services';
import { EventEmitter, IEvent } from 'common/EventEmitter';
import { Disposable, getDisposeArrayDisposable, disposeArray } from 'common/Lifecycle';
import { addDisposableDomListener } from 'browser/Lifecycle';

interface ILinkState {
decorations: ILinkDecorations;
isHovered: boolean;
}

interface ILinkWithState {
link: ILink;
state?: ILinkState;
}

export class Linkifier2 extends Disposable implements ILinkifier2 {
private _element: HTMLElement | undefined;
private _mouseService: IMouseService | undefined;
private _renderService: IRenderService | undefined;
private _linkProviders: ILinkProvider[] = [];
public get currentLink(): ILinkWithState | undefined { return this._currentLink; }
protected _currentLink: ILinkWithState | undefined;
private _lastMouseEvent: MouseEvent | undefined;
private _linkCacheDisposables: IDisposable[] = [];
Expand Down
4 changes: 3 additions & 1 deletion src/browser/Terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,9 @@ export class Terminal extends CoreTerminal implements ITerminal {

this._selectionService = this.register(this._instantiationService.createInstance(SelectionService,
this.element,
this.screenElement));
this.screenElement,
this.linkifier2
));
this._instantiationService.setService(ISelectionService, this._selectionService);
this.register(this._selectionService.onRequestScrollLines(e => this.scrollLines(e.amount, e.suppressScrollEvent)));
this.register(this._selectionService.onSelectionChange(() => this._onSelectionChange.fire()));
Expand Down
10 changes: 10 additions & 0 deletions src/browser/Types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,19 @@ export interface ILinkifier {
deregisterLinkMatcher(matcherId: number): boolean;
}

interface ILinkState {
decorations: ILinkDecorations;
isHovered: boolean;
}
export interface ILinkWithState {
link: ILink;
state?: ILinkState;
}

export interface ILinkifier2 {
onShowLinkUnderline: IEvent<ILinkifierEvent>;
onHideLinkUnderline: IEvent<ILinkifierEvent>;
readonly currentLink: ILinkWithState | undefined;

attachToDom(element: HTMLElement, mouseService: IMouseService, renderService: IRenderService): void;
registerLinkProvider(linkProvider: ILinkProvider): IDisposable;
Expand Down
2 changes: 1 addition & 1 deletion src/browser/services/SelectionService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class TestSelectionService extends SelectionService {
optionsService: IOptionsService,
renderService: IRenderService
) {
super(null!, null!, bufferService, new MockCoreService(), new MockMouseService(), optionsService, renderService);
super(null!, null!, null!, bufferService, new MockCoreService(), new MockMouseService(), optionsService, renderService);
}

public get model(): SelectionModel { return this._model; }
Expand Down
27 changes: 19 additions & 8 deletions src/browser/services/SelectionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { SelectionModel } from 'browser/selection/SelectionModel';
import { CellData } from 'common/buffer/CellData';
import { EventEmitter, IEvent } from 'common/EventEmitter';
import { ICharSizeService, IMouseService, ISelectionService, IRenderService } from 'browser/services/Services';
import { ILinkifier2 } from 'browser/Types';
import { IBufferService, IOptionsService, ICoreService } from 'common/services/Services';
import { getCoordsRelativeToElement } from 'browser/input/Mouse';
import { moveToCellSequence } from 'browser/input/MoveToCell';
Expand Down Expand Up @@ -121,6 +122,7 @@ export class SelectionService extends Disposable implements ISelectionService {
constructor(
private readonly _element: HTMLElement,
private readonly _screenElement: HTMLElement,
private readonly _linkifier: ILinkifier2,
@IBufferService private readonly _bufferService: IBufferService,
@ICoreService private readonly _coreService: ICoreService,
@IMouseService private readonly _mouseService: IMouseService,
Expand Down Expand Up @@ -316,13 +318,22 @@ export class SelectionService extends Disposable implements ISelectionService {
* Selects word at the current mouse event coordinates.
* @param event The mouse event.
*/
private _selectWordAtCursor(event: MouseEvent): void {
private _selectWordAtCursor(event: MouseEvent, allowWhitespaceOnlySelection: boolean): boolean {
// Check if there is a link under the cursor first and select that if so
const range = this._linkifier.currentLink?.link?.range;
if (range) {
this._model.selectionStart = [range.start.x - 1, range.start.y - 1];
this._model.selectionEnd = [range.end.x, range.end.y - 1];
return true;
}

const coords = this._getMouseBufferCoords(event);
if (coords) {
this._selectWordAt(coords, false);
this._selectWordAt(coords, allowWhitespaceOnlySelection);
this._model.selectionEnd = undefined;
this.refresh(true);
return true;
}
return false;
}

/**
Expand Down Expand Up @@ -527,14 +538,12 @@ export class SelectionService extends Disposable implements ISelectionService {
}

/**
* Performs a double click, selecting the current work.
* Performs a double click, selecting the current word.
* @param event The mouse event.
*/
private _onDoubleClick(event: MouseEvent): void {
const coords = this._getMouseBufferCoords(event);
if (coords) {
if (this._selectWordAtCursor(event, true)) {
this._activeSelectionMode = SelectionMode.WORD;
this._selectWordAt(coords, true);
}
}

Expand Down Expand Up @@ -764,7 +773,9 @@ export class SelectionService extends Disposable implements ISelectionService {

public rightClickSelect(ev: MouseEvent): void {
if (!this._isClickInSelection(ev)) {
this._selectWordAtCursor(ev);
if (this._selectWordAtCursor(ev, false)) {
this.refresh(true);
}
this._fireEventIfSelectionChanged();
}
}
Expand Down

0 comments on commit dd952ac

Please sign in to comment.