mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Progress on osc link service
This commit is contained in:
+13
-6
@@ -833,12 +833,19 @@ function addAnsiHyperlink() {
|
||||
term.writeln(`Regular link with no id:`);
|
||||
term.writeln('\x1b]8;;https://github.com\x07GitHub\x1b]8;;\x07');
|
||||
term.writeln('\x1b]8;;https://xtermjs.org\x07https://xtermjs.org\x1b]8;;\x07\x1b[C<- null cell');
|
||||
term.writeln(`\nShared ID links:`);
|
||||
term.writeln('╔════╗ ╔════╗');
|
||||
term.writeln('║\x1b]8;;https://github.com\x07GitH\x1b]8;;\x07║ ║ ║');
|
||||
term.writeln('║\x1b]8;;https://github.com\x07ub\x1b]8;;\x07 ║ ║ ║');
|
||||
term.writeln('╚════╝ ╚════╝');
|
||||
term.write('\x1b[3A\x1b[8C\x1b]8;;https://xtermjs.org\x07xter\x1b[B\x1b[4Dm.js\x1b]8;;\x07\x1b[2B\x1b[12D');
|
||||
term.writeln(`\nAdjacent links:`);
|
||||
term.writeln('\x1b]8;;https://github.com\x07GitHub\x1b]8;;https://xtermjs.org\x07xterm.js\x1b]8;;\x07');
|
||||
term.writeln(`\nShared ID link:`);
|
||||
term.writeln('╔════╗');
|
||||
term.writeln('║\x1b]8;id=testid;https://github.com\x07GitH\x1b]8;;\x07║');
|
||||
term.writeln('║\x1b]8;id=testid;https://github.com\x07ub\x1b]8;;\x07 ║');
|
||||
term.writeln('╚════╝');
|
||||
term.writeln(`\nWrapped link with no ID (not meant to share underline):`);
|
||||
term.writeln('╔════╗');
|
||||
term.writeln('║ ║');
|
||||
term.writeln('║ ║');
|
||||
term.writeln('╚════╝');
|
||||
term.write('\x1b[3A\x1b[1C\x1b]8;;https://xtermjs.org\x07xter\x1b[B\x1b[4Dm.js\x1b]8;;\x07\x1b[2B\x1b[5D');
|
||||
}
|
||||
|
||||
function addDecoration() {
|
||||
|
||||
@@ -228,7 +228,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
private _workCell: CellData = new CellData();
|
||||
private _windowTitle = '';
|
||||
private _iconName = '';
|
||||
private _currentHyperlink?: IOscLinkData;
|
||||
private _currentLinkId?: number;
|
||||
protected _windowTitleStack: string[] = [];
|
||||
protected _iconNameStack: string[] = [];
|
||||
|
||||
@@ -639,6 +639,9 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
if (screenReaderMode) {
|
||||
this._onA11yChar.fire(stringFromCodePoint(code));
|
||||
}
|
||||
if (this._currentLinkId !== undefined) {
|
||||
this._oscLinkService.addLineToLink(this._currentLinkId, this._activeBuffer.ybase + this._activeBuffer.y);
|
||||
}
|
||||
|
||||
// insert combining char at last cursor position
|
||||
// this._activeBuffer.x should never be 0 for a combining char
|
||||
@@ -2924,7 +2927,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
|
||||
private _createHyperlink(params: string, uri: string): boolean {
|
||||
// It's legal to open a new hyperlink without explicitly finishing the previous one
|
||||
if (this._currentHyperlink) {
|
||||
if (this._currentLinkId !== undefined) {
|
||||
this._finishHyperlink();
|
||||
}
|
||||
const parsedParams = params.split(':');
|
||||
@@ -2933,10 +2936,10 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
if (idParamIndex !== -1) {
|
||||
id = parsedParams[idParamIndex].slice(3) || undefined;
|
||||
}
|
||||
this._currentHyperlink = { id, uri };
|
||||
this._oscLinkService.registerLink(this._currentHyperlink);
|
||||
this._curAttrData.extended = this._curAttrData.extended.clone();
|
||||
this._curAttrData.extended.urlId = 1;
|
||||
this._currentLinkId = this._oscLinkService.registerLink({ id, uri });
|
||||
this._curAttrData.extended.urlId = this._currentLinkId;
|
||||
console.log('register', uri, `id=${this._curAttrData.extended.urlId}`);
|
||||
this._curAttrData.updateExtended();
|
||||
return true;
|
||||
}
|
||||
@@ -2946,7 +2949,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
this._curAttrData.extended = this._curAttrData.extended.clone();
|
||||
this._curAttrData.extended.urlId = 0;
|
||||
this._curAttrData.updateExtended();
|
||||
this._currentHyperlink = undefined;
|
||||
this._currentLinkId = undefined;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -146,6 +146,8 @@ export class MockOscLinkService implements IOscLinkService {
|
||||
public getLinkData(linkId: number): IOscLinkData | undefined {
|
||||
return undefined;
|
||||
}
|
||||
public addLineToLink(linkId: number, y: number): void {
|
||||
}
|
||||
}
|
||||
|
||||
// defaults to V6 always to keep tests passing
|
||||
|
||||
@@ -1,23 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2022 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
import { IBufferService, IOscLinkService } from 'common/services/Services';
|
||||
import { IOscLinkData } from 'common/Types';
|
||||
import { IMarker, IOscLinkData } from 'common/Types';
|
||||
|
||||
export class OscLinkService implements IOscLinkService {
|
||||
public serviceBrand: any;
|
||||
|
||||
private _nextId = 1;
|
||||
|
||||
// TODO: Evict on marker dispose
|
||||
private _entriesNoId: IOscLinkEntryNoId[] = [];
|
||||
private _entriesWithId: Map<string, IOscLinkEntryWithId> = new Map();
|
||||
|
||||
// The "link id" (number) which is the numberic representation of a unique link should not be
|
||||
// confused with "id" (string) which comes in with "id=" in the OSC link's properties
|
||||
private _dataByLinkId: Map<number, IOscLinkEntryNoId | IOscLinkEntryWithId> = new Map();
|
||||
|
||||
constructor(
|
||||
@IBufferService private readonly _bufferService: IBufferService
|
||||
) {
|
||||
}
|
||||
|
||||
public registerLink(linkData: IOscLinkData): number {
|
||||
console.log('register link');
|
||||
// TODO: Add and return properly
|
||||
return 1;
|
||||
public registerLink(data: IOscLinkData): number {
|
||||
// TODO: Extend range where appropriate
|
||||
const buffer = this._bufferService.buffer;
|
||||
|
||||
// Links with no id will only ever be registered a single time
|
||||
if (data.id === undefined) {
|
||||
const entry: IOscLinkEntryNoId = {
|
||||
data,
|
||||
id: this._nextId++,
|
||||
lines: [buffer.addMarker(buffer.ybase + buffer.y)]
|
||||
};
|
||||
this._entriesNoId.push(entry);
|
||||
this._dataByLinkId.set(entry.id, entry);
|
||||
return entry.id;
|
||||
}
|
||||
|
||||
const castData = data as Required<IOscLinkData>;
|
||||
const key = this._getEntryIdKey(castData);
|
||||
const match = this._entriesWithId.get(key);
|
||||
if (match) {
|
||||
this.addLineToLink(match.id, buffer.ybase + buffer.y);
|
||||
return match.id;
|
||||
}
|
||||
|
||||
const entry: IOscLinkEntryWithId = {
|
||||
id: this._nextId++,
|
||||
key: this._getEntryIdKey(castData),
|
||||
data: castData,
|
||||
lines: [buffer.addMarker(buffer.ybase + buffer.y)]
|
||||
};
|
||||
this._entriesWithId.set(entry.key, entry);
|
||||
this._dataByLinkId.set(entry.id, entry);
|
||||
return entry.id;
|
||||
}
|
||||
|
||||
public addLineToLink(linkId: number, y: number): void {
|
||||
const link = this._dataByLinkId.get(linkId);
|
||||
if (!link) {
|
||||
return;
|
||||
}
|
||||
if (link.lines.every(e => e.line !== y)) {
|
||||
console.log(' add new line', y);
|
||||
link.lines.push(this._bufferService.buffer.addMarker(y));
|
||||
}
|
||||
}
|
||||
|
||||
public getLinkData(linkId: number): IOscLinkData | undefined {
|
||||
return {
|
||||
uri: 'https://github.com'
|
||||
};
|
||||
return this._dataByLinkId.get(linkId)?.data;
|
||||
}
|
||||
|
||||
private _getEntryIdKey(linkData: Required<IOscLinkData>): string {
|
||||
return `${linkData.id};;${linkData.uri}`;
|
||||
}
|
||||
}
|
||||
|
||||
interface IOscLinkEntry<T extends IOscLinkData> {
|
||||
data: T;
|
||||
id: number;
|
||||
lines: IMarker[];
|
||||
}
|
||||
|
||||
interface IOscLinkEntryNoId extends IOscLinkEntry<IOscLinkData> {
|
||||
}
|
||||
|
||||
interface IOscLinkEntryWithId extends IOscLinkEntry<Required<IOscLinkData>> {
|
||||
key: string;
|
||||
}
|
||||
|
||||
@@ -280,6 +280,10 @@ export interface IOscLinkService {
|
||||
* service and will be freed when this current cursor position is trimmed off the buffer.
|
||||
*/
|
||||
registerLink(linkData: IOscLinkData): number;
|
||||
/**
|
||||
* Adds a line to a link if needed.
|
||||
*/
|
||||
addLineToLink(linkId: number, y: number): void;
|
||||
/** Get the link data associated with a link ID. */
|
||||
getLinkData(linkId: number): IOscLinkData | undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user