From becec91e98cd2fe3c4bf4f6141ef47f551220af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Thu, 8 Dec 2022 17:35:45 +0100 Subject: [PATCH] better regexp, fix offset issue in #4294 --- .../src/WebLinksAddon.ts | 11 ++++++-- bin/test_weblinks.sh | 25 +++++++++++++------ src/browser/renderer/dom/DomRenderer.ts | 4 +-- .../dom/DomRendererRowFactory.test.ts | 2 +- .../renderer/dom/DomRendererRowFactory.ts | 4 +-- 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/addons/xterm-addon-web-links/src/WebLinksAddon.ts b/addons/xterm-addon-web-links/src/WebLinksAddon.ts index 44dabd452e..45a1b294fc 100644 --- a/addons/xterm-addon-web-links/src/WebLinksAddon.ts +++ b/addons/xterm-addon-web-links/src/WebLinksAddon.ts @@ -10,8 +10,15 @@ import { ILinkProviderOptions, WebLinkProvider } from './WebLinkProvider'; // up to first whitespace, `"` or `'` as url // NOTE: The repeated end clause is needed to not match a dangling `:` // resembling the old (...)*([^:"\'\\s]) final path clause -// also exclude final interpunction like ,.!? -const strictUrlRegex = /https?:[/]{2}[^\s^"^']*[^\s^"^'^:^,^.^!^?]/; +// additionally exclude early + final: +// - unsafe from rfc3986: !*'() +// - unsafe chars from rfc1738: {}|\^~[]` (minus [] as we need them for ipv6 adresses) +// also exclude as finals: +// - final interpunction like ,.!? +// - any sort of brackets <>()[]{} (not spec conform, but often used to enclose urls) +// - unsafe chars from rfc1738: {}|\^~[]` +const strictUrlRegex = /https?:[/]{2}[^\s"'!*(){}|\\\^~<>`]*[^\s"':,.!?{}|\\\^~\[\]`()<>]/; + function handleLink(event: MouseEvent, uri: string): void { const newWindow = window.open(); diff --git a/bin/test_weblinks.sh b/bin/test_weblinks.sh index c06354132b..1389eceeb1 100755 --- a/bin/test_weblinks.sh +++ b/bin/test_weblinks.sh @@ -1,25 +1,34 @@ #!/bin/bash -# all half width - only good case +# all half width echo "aaa http://example.com aaa http://example.com aaa" -# full width before - wrong offset +# full width before echo "¥¥¥ http://example.com aaa http://example.com aaa" -# full width between - wrong offset +# full width between echo "aaa http://example.com ¥¥¥ http://example.com aaa" -# full width before and between - error in offsets adding up +# full width before and between echo "¥¥¥ http://example.com ¥¥¥ http://example.com aaa" -# full width within url - partial wrong match +# full width within url echo "aaa https://ko.wikipedia.org/wiki/위키백과:대문 aaa https://ko.wikipedia.org/wiki/위키백과:대문 aaa" -# full width within and before - partial wrong match + wrong offsets +# full width within and before echo "¥¥¥ https://ko.wikipedia.org/wiki/위키백과:대문 aaa https://ko.wikipedia.org/wiki/위키백과:대문 ¥¥¥" -# not matching at all +# username + password scheme echo "http://test:password@example.com/some_path aaa" # overly long text with urls with final interpunction -echo "Lorem ipsum dolor sit amet, consetetur sadipscing elitr https://ko.wikipedia.org/wiki/위키백과:대문, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat: http://test:password@example.com/some_path." \ No newline at end of file +echo "Lorem ipsum dolor sit amet, consetetur sadipscing elitr https://ko.wikipedia.org/wiki/위키백과:대문, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat: http://test:password@example.com/some_path." + +# bracket enclosed urls +echo "[http://example.de]" +echo "(http://example.de)" +echo "" +echo "{http://example.de}" + +# ipv6 scheme +echo "ipv6 https://[::1]/with/some?vars=and&a#hash" \ No newline at end of file diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index 259f1607af..700a62b63f 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -38,7 +38,7 @@ export class DomRenderer extends Disposable implements IRenderer { private _rowContainer: HTMLElement; private _rowElements: HTMLElement[] = []; private _selectionContainer: HTMLElement; - private _cellToRowElements: Uint16Array[] = []; + private _cellToRowElements: Int16Array[] = []; public dimensions: IRenderDimensions; @@ -361,7 +361,7 @@ export class DomRenderer extends Disposable implements IRenderer { const lineData = this._bufferService.buffer.lines.get(row); const cursorStyle = this._optionsService.rawOptions.cursorStyle; if (!this._cellToRowElements[y] || this._cellToRowElements[y].length !== this._bufferService.cols) { - this._cellToRowElements[y] = new Uint16Array(this._bufferService.cols); + this._cellToRowElements[y] = new Int16Array(this._bufferService.cols); } rowElement.replaceChildren(this._rowFactory.createRow(lineData!, row, row === cursorAbsoluteY, cursorStyle, cursorX, cursorBlink, this.dimensions.css.cell.width, this._bufferService.cols, this._cellToRowElements[y])); } diff --git a/src/browser/renderer/dom/DomRendererRowFactory.test.ts b/src/browser/renderer/dom/DomRendererRowFactory.test.ts index 7d4adf85ad..5969abff21 100644 --- a/src/browser/renderer/dom/DomRendererRowFactory.test.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.test.ts @@ -14,7 +14,7 @@ import { MockCoreService, MockDecorationService, MockOptionsService } from 'comm import { css } from 'common/Color'; import { MockCharacterJoinerService, MockCoreBrowserService, MockThemeService } from 'browser/TestUtils.test'; -const EMPTY_ELEM_MAPPING = new Uint16Array(1000); +const EMPTY_ELEM_MAPPING = new Int16Array(1000); describe('DomRendererRowFactory', () => { let dom: jsdom.JSDOM; diff --git a/src/browser/renderer/dom/DomRendererRowFactory.ts b/src/browser/renderer/dom/DomRendererRowFactory.ts index b39c62c0e2..cc64a4383d 100644 --- a/src/browser/renderer/dom/DomRendererRowFactory.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.ts @@ -49,7 +49,7 @@ export class DomRendererRowFactory { this._columnSelectMode = columnSelectMode; } - public createRow(lineData: IBufferLine, row: number, isCursorRow: boolean, cursorStyle: string | undefined, cursorX: number, cursorBlink: boolean, cellWidth: number, cols: number, cellMap: Uint16Array): DocumentFragment { + public createRow(lineData: IBufferLine, row: number, isCursorRow: boolean, cursorStyle: string | undefined, cursorX: number, cursorBlink: boolean, cellWidth: number, cols: number, cellMap: Int16Array): DocumentFragment { // NOTE: `cellMap` maps cell positions to a span element index in a row. // All positions should be updated, even skipped ones after wide chars or left overs at the end, // otherwise the mouse hover logic might mark the wrong elements as underlined. @@ -316,7 +316,7 @@ export class DomRendererRowFactory { // since the loop above might exit early not handling all cells, // also set remaining cell positions to last element index if (x < cols - 1) { - cellMap.subarray(x + 1).fill(elemIndex); + cellMap.subarray(x).fill(++elemIndex); } return fragment;