Skip to content

Commit 826c057

Browse files
authored
Merge pull request #5003 from josiahhudson/master
Support semi-colons in OSC 8 hyperlink URIs
2 parents 1709d44 + d77b41e commit 826c057

File tree

2 files changed

+41
-8
lines changed

2 files changed

+41
-8
lines changed

src/common/InputHandler.test.ts

+31-2
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ import { Attributes, BgFlags, UnderlineStyle } from 'common/buffer/Constants';
1212
import { AttributeData, ExtendedAttrs } from 'common/buffer/AttributeData';
1313
import { Params } from 'common/parser/Params';
1414
import { MockCoreService, MockBufferService, MockOptionsService, MockLogService, MockCoreMouseService, MockCharsetService, MockUnicodeService, MockOscLinkService } from 'common/TestUtils.test';
15-
import { IBufferService, ICoreService } from 'common/services/Services';
15+
import { IBufferService, ICoreService, type IOscLinkService } from 'common/services/Services';
1616
import { DEFAULT_OPTIONS } from 'common/services/OptionsService';
1717
import { clone } from 'common/Clone';
1818
import { BufferService } from 'common/services/BufferService';
1919
import { CoreService } from 'common/services/CoreService';
20+
import { OscLinkService } from 'common/services/OscLinkService';
2021

2122

2223
function getCursor(bufferService: IBufferService): number[] {
@@ -59,15 +60,17 @@ describe('InputHandler', () => {
5960
let bufferService: IBufferService;
6061
let coreService: ICoreService;
6162
let optionsService: MockOptionsService;
63+
let oscLinkService: IOscLinkService;
6264
let inputHandler: TestInputHandler;
6365

6466
beforeEach(() => {
6567
optionsService = new MockOptionsService();
6668
bufferService = new BufferService(optionsService);
6769
bufferService.resize(80, 30);
6870
coreService = new CoreService(bufferService, new MockLogService(), optionsService);
71+
oscLinkService = new OscLinkService(bufferService);
6972

70-
inputHandler = new TestInputHandler(bufferService, new MockCharsetService(), coreService, new MockLogService(), optionsService, new MockOscLinkService(), new MockCoreMouseService(), new MockUnicodeService());
73+
inputHandler = new TestInputHandler(bufferService, new MockCharsetService(), coreService, new MockLogService(), optionsService, oscLinkService, new MockCoreMouseService(), new MockUnicodeService());
7174
});
7275

7376
describe('SL/SR/DECIC/DECDC', () => {
@@ -1982,6 +1985,32 @@ describe('InputHandler', () => {
19821985
assert.deepEqual(stack, [[{ type: ColorRequestType.SET, index: 0, color: [170, 187, 204] }, { type: ColorRequestType.SET, index: 123, color: [0, 17, 34] }]]);
19831986
stack.length = 0;
19841987
});
1988+
it('8: hyperlink with id', async () => {
1989+
await inputHandler.parseP('\x1b]8;id=100;http://localhost:3000\x07');
1990+
assert.notStrictEqual(inputHandler.curAttrData.extended.urlId, 0);
1991+
assert.deepStrictEqual(
1992+
oscLinkService.getLinkData(inputHandler.curAttrData.extended.urlId),
1993+
{
1994+
id: '100',
1995+
uri: 'http://localhost:3000'
1996+
}
1997+
);
1998+
await inputHandler.parseP('\x1b]8;;\x07');
1999+
assert.strictEqual(inputHandler.curAttrData.extended.urlId, 0);
2000+
});
2001+
it('8: hyperlink with semi-colon', async () => {
2002+
await inputHandler.parseP('\x1b]8;;http://localhost:3000;abc=def\x07');
2003+
assert.notStrictEqual(inputHandler.curAttrData.extended.urlId, 0);
2004+
assert.deepStrictEqual(
2005+
oscLinkService.getLinkData(inputHandler.curAttrData.extended.urlId),
2006+
{
2007+
id: undefined,
2008+
uri: 'http://localhost:3000;abc=def'
2009+
}
2010+
);
2011+
await inputHandler.parseP('\x1b]8;;\x07');
2012+
assert.strictEqual(inputHandler.curAttrData.extended.urlId, 0);
2013+
});
19852014
it('104: restore events', async () => {
19862015
const stack: IColorEvent[] = [];
19872016
inputHandler.onColor(ev => stack.push(ev));

src/common/InputHandler.ts

+10-6
Original file line numberDiff line numberDiff line change
@@ -2972,14 +2972,18 @@ export class InputHandler extends Disposable implements IInputHandler {
29722972
* feedback. Use `OSC 8 ; ; BEL` to finish the current hyperlink.
29732973
*/
29742974
public setHyperlink(data: string): boolean {
2975-
const args = data.split(';');
2976-
if (args.length < 2) {
2977-
return false;
2975+
// Arg parsing is special cases to support unencoded semi-colons in the URIs (#4944)
2976+
const idx = data.indexOf(';');
2977+
if (idx === -1) {
2978+
// malformed sequence, just return as handled
2979+
return true;
29782980
}
2979-
if (args[1]) {
2980-
return this._createHyperlink(args[0], args[1]);
2981+
const id = data.slice(0, idx).trim();
2982+
const uri = data.slice(idx + 1);
2983+
if (uri) {
2984+
return this._createHyperlink(id, uri);
29812985
}
2982-
if (args[0].trim()) {
2986+
if (id.trim()) {
29832987
return false;
29842988
}
29852989
return this._finishHyperlink();

0 commit comments

Comments
 (0)