diff --git a/addons/xterm-addon-web-links/src/WebLinksAddon.ts b/addons/xterm-addon-web-links/src/WebLinksAddon.ts index 26d5904b..3290a59c 100644 --- a/addons/xterm-addon-web-links/src/WebLinksAddon.ts +++ b/addons/xterm-addon-web-links/src/WebLinksAddon.ts @@ -26,7 +26,13 @@ const end = ')($|' + negatedPathCharacterSet + ')'; const strictUrlRegex = new RegExp(start + protocolClause + bodyClause + end); function handleLink(event: MouseEvent, uri: string): void { - window.open(uri, '_blank'); + const newWindow = window.open(); + if (newWindow) { + newWindow.opener = null; + newWindow.location.href = uri; + } else { + console.warn('Opening link blocked as opener could not be cleared'); + } } export class WebLinksAddon implements ITerminalAddon { diff --git a/bin/extract_vtfeatures.js b/bin/extract_vtfeatures.js new file mode 100644 index 00000000..7b77639d --- /dev/null +++ b/bin/extract_vtfeatures.js @@ -0,0 +1,503 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + * + * Script to extract vt features documented in docstrings. + */ +const fs = require('fs'); +const Mustache = require('mustache'); + +/** + * regexp to fetch all comments + * Fetches all multiline comments and single lines containing '// @vt:'. + */ +const REX_COMMENTS = /^\s*?[/][*][*]([\s\S]*?)[*][/]|^\s*?\/\/ ([@]vt[:].*?)$/mug; + +/** + * regexp to parse the @vt line + * expected data - "@vt: "" "" "" + */ +const REX_VT_LINE = /^[@]vt\:\s*(\w+|#\w+|#\w+\[.*?\])\s*(\w+)\s*(\w+)\s*"(.*?)"\s*"(.*?)"\s*"(.*?)".*$/; + +// known vt command types +const TYPES = [ + 'C0', + 'C1', + 'ESC', + 'CSI', + 'DCS', + 'OSC', + 'APC', + 'PM', + 'SOS' +]; + +const MARKDOWN_TMPL = ` +{::options parse_block_html="true" /} + +xterm.js version: {{version}} + +## Table of Contents + + + + +## General notes + +This document lists xterm.js' support of terminal sequences. The sequences are grouped by their sequence type: + +- C0: single byte command (7bit control codes, byte range \`\\x00\` .. \`\\x1F\`, \`\\x7F\`) +- C1: single byte command (8bit control codes, byte range \`\\x80\` .. \`\\x9F\`) +- ESC: sequence starting with \`ESC\` (\`\\x1B\`) +- CSI - Control Sequence Introducer: sequence starting with \`ESC [\` (7bit) or CSI (\`\\x9B\`, 8bit) +- DCS - Device Control String: sequence starting with \`ESC P\` (7bit) or DCS (\`\\x90\`, 8bit) +- OSC - Operating System Command: sequence starting with \`ESC ]\` (7bit) or OSC (\`\\x9D\`, 8bit) + +Application Program Command (APC), Privacy Message (PM) and Start of String (SOS) are recognized but not supported, +any sequence of these types will be ignored. They are also not hookable by the API. + +Note that the list only contains sequences implemented in xterm.js' core codebase. Missing sequences are either +not supported or unstable/experimental. Furthermore addons or integrations can provide additional custom sequences. + +To denote the sequences the tables use the same abbreviations as xterm does: +- \`Ps\`: A single (usually optional) numeric parameter, composed of one or more decimal digits. +- \`Pm\`: A multiple numeric parameter composed of any number of single numeric parameters, separated by ; character(s), + e.g. \` Ps ; Ps ; ... \`. +- \`Pt\`: A text parameter composed of printable characters. Note that for most commands with \`Pt\` only + ASCII printables are specified to work. Additionally the parser will let pass any codepoint greater than C1 as printable. + + + +{{#C0.length}} +## C0 + +| Mnemonic | Name | Sequence | Short Description | Support | +| -------- | ---- | -------- | ----------------- | ------- | +{{#C0}} +| {{mnemonic}} | {{name}} | \`{{sequence}}\` | {{{shortDescription}}} {{#longDescription.length}}_[more](#{{longTarget}}){: .link-details}_{{/longDescription.length}} | {{{status}}} | +{{/C0}} + +{{#C0.hasLongDescriptions}} +{{#C0}} +{{#longDescription.length}} +
+ +### {{name}} +{{#longDescription}} +{{{.}}} +{{/longDescription}} + +
+{{/longDescription.length}} +{{/C0}} +{{/C0.hasLongDescriptions}} + +{{/C0.length}} + + +{{#C1.length}} +## C1 + +| Mnemonic | Name | Sequence | Short Description | Support | +| -------- | ---- | -------- | ----------------- | ------- | +{{#C1}} +| {{mnemonic}} | {{name}} | \`{{sequence}}\` | {{{shortDescription}}} {{#longDescription.length}}_[more](#{{longTarget}}){: .link-details}_{{/longDescription.length}} | {{{status}}} | +{{/C1}} + +{{#C1.hasLongDescriptions}} +{{#C1}} +{{#longDescription.length}} +
+ +### {{name}} +{{#longDescription}} +{{{.}}} +{{/longDescription}} + +
+{{/longDescription.length}} +{{/C1}} +{{/C1.hasLongDescriptions}} + +{{/C1.length}} + + +{{#CSI.length}} +## CSI + +| Mnemonic | Name | Sequence | Short Description | Support | +| -------- | ---- | -------- | ----------------- | ------- | +{{#CSI}} +| {{mnemonic}} | {{name}} | \`\`{{{sequence}}}\`\` | {{{shortDescription}}} {{#longDescription.length}}_[more](#{{longTarget}}){: .link-details}_{{/longDescription.length}} | {{{status}}} | +{{/CSI}} + +{{#CSI.hasLongDescriptions}} +{{#CSI}} +{{#longDescription.length}} +
+ +### {{name}} +{{#longDescription}} +{{{.}}} +{{/longDescription}} + +
+{{/longDescription.length}} +{{/CSI}} +{{/CSI.hasLongDescriptions}} + +{{/CSI.length}} + + +{{#DCS.length}} +## DCS + +| Mnemonic | Name | Sequence | Short Description | Support | +| -------- | ---- | -------- | ----------------- | ------- | +{{#DCS}} +| {{mnemonic}} | {{name}} | \`{{sequence}}\` | {{{shortDescription}}} {{#longDescription.length}}_[more](#{{longTarget}}){: .link-details}_{{/longDescription.length}} | {{{status}}} | +{{/DCS}} + +{{#DCS.hasLongDescriptions}} +{{#DCS}} +{{#longDescription.length}} +
+ +### {{name}} +{{#longDescription}} +{{{.}}} +{{/longDescription}} + +
+{{/longDescription.length}} +{{/DCS}} +{{/DCS.hasLongDescriptions}} + +{{/DCS.length}} + + +{{#ESC.length}} +## ESC + +| Mnemonic | Name | Sequence | Short Description | Support | +| -------- | ---- | -------- | ----------------- | ------- | +{{#ESC}} +| {{mnemonic}} | {{name}} | \`{{sequence}}\` | {{{shortDescription}}} {{#longDescription.length}}_[more](#{{longTarget}}){: .link-details}_{{/longDescription.length}} | {{{status}}} | +{{/ESC}} + +{{#ESC.hasLongDescriptions}} +{{#ESC}} +{{#longDescription.length}} +
+ +### {{name}} +{{#longDescription}} +{{{.}}} +{{/longDescription}} + +
+{{/longDescription.length}} +{{/ESC}} +{{/ESC.hasLongDescriptions}} + +{{/ESC.length}} + + +{{#OSC.length}} +## OSC + +**Note**: Other than listed in the table, the parser recognizes both ST (ECMA-48) and BEL (xterm) as OSC sequence finalizer. + +| Identifier | Sequence | Short Description | Support | +| ---------- | -------- | ----------------- | ------- | +{{#OSC}} +| {{mnemonic}} | \`{{sequence}}\` | {{{shortDescription}}} {{#longDescription.length}}_[more](#{{longTarget}}){: .link-details}_{{/longDescription.length}} | {{{status}}} | +{{/OSC}} + +{{#OSC.hasLongDescriptions}} +{{#OSC}} +{{#longDescription.length}} +
+ +### {{name}} +{{#longDescription}} +{{{.}}} +{{/longDescription}} + +
+{{/longDescription.length}} +{{/OSC}} +{{/OSC.hasLongDescriptions}} + +{{/OSC.length}} + + +` + +// support status marcos +// applied for: +// - status field of single @vt line +// - all lines in long description +const MACRO = [ + // #Y - supported + [/#Y/g, s => ''], + // #N - unsupported + [/#N/g, s => ''], + // #P[reason] - partial support with a reason as title + [/#P\[(.*?)\]/g, (s, p1) => `Partial`], + // #B[reason] - supported but broken in a certain way, reason in title + [/#B\[(.*?)\]/g, (s, p1) => `Broken`] +]; + +function applyMacros(s) { + for (let i = 0; i < MACRO.length; ++i) { + s = s.replace(MACRO[i][0], MACRO[i][1]); + } + return s; +} + +function replaceStatus(s) { + if (s === 'supported') return ''; + if (s === 'unsupported') return ''; + return s; +} + +function createAnchorSlug(s) { + return s.toLowerCase().split(' ').join('-'); +} + +function empty(ar) { + return !ar.filter(Boolean, ar).length; +} + +function* parseMultiLineGen(filename, s) { + if (!~s.indexOf('@vt:')) { + return; + } + const lines = s.split('\n').map(el => el.trim().replace(/[*]/, '').replace(/\s/, '')); + let grabLine = false; + let longDescription = []; + let feature = undefined; + let noLineCount = 0; + for (const line of lines) { + if (grabLine) { + if (!line) noLineCount++; + if (noLineCount >= 2) { + if (feature) { + feature.longDescription = empty(longDescription) ? [] : longDescription; + feature.longTarget = createAnchorSlug(feature.name); + yield feature; + } + grabLine = false; + longDescription = []; + feature = undefined; + noLineCount = 0; + } + else if (line.indexOf('@vt:') === 0) { + if (feature) { + feature.longDescription = empty(longDescription) ? [] : longDescription; + feature.longTarget = createAnchorSlug(feature.name); + yield feature; + } + grabLine = true; + longDescription = []; + feature = undefined; + noLineCount = 0; + } else { + //longDescription.push(line); + longDescription.push(applyMacros(line)); + if (line) noLineCount = 0; + } + } + if (line.indexOf('@vt:') === 0) { + feature = parseSingleLine(filename, line); + grabLine = true; + } + } + if (grabLine && feature) { + feature.longDescription = empty(longDescription) ? [] : longDescription; + feature.longTarget = createAnchorSlug(feature.name); + yield feature; + } +} + +function parseSingleLine(filename, s) { + const line = s.trim(); + const match = line.match(REX_VT_LINE); + if (match !== null) { + if (!~TYPES.indexOf(match[2])) { + throw new Error(`unkown vt-command type "${match[2]}" specified in "${filename}"`); + } + return { + status: match[1], + type: match[2], + mnemonic: match[3], + name: match[4], + sequence: match[5], + shortDescription: match[6], + longDescription: [], + longTarget: '', + source: filename + }; + } +} + +function getSorter(entry) { + switch (entry) { + case 'C0': + case 'C1': + // NOTE: expects hex value notation at last position in sequence + return (a, b) => parseInt(a.sequence.slice(-2), 16) - parseInt(b.sequence.slice(-2), 16); + case 'OSC': + // NOTE: expects the decimal function identifier in mnemonic + return (a, b) => parseInt(a.mnemonic) - parseInt(b.mnemonic); + case 'DCS': + return (a, b) => a.mnemonic > b.mnemonic; + case 'CSI': + case 'ESC': + // default sort order by final byte + return (a, b) => { + // ugly hack to fix sorting of workaround in HPA sequence "CSI Ps ` " + // for HPA compare with length - 2 instead + const HPA = 'CSI Ps ` '; + const aa = a.sequence === HPA ? a.sequence.slice(0, -1) : a.sequence; + const bb = b.sequence === HPA ? b.sequence.slice(0, -1) : b.sequence; + return aa.charCodeAt(aa.length - 1) - bb.charCodeAt(bb.length - 1); + }; + default: + return (a, b) => a.sequence > b.sequence; + } +}; + +function postProcessData(features) { + const featureTable = {}; + for (const feature of features) { + // feature.status = replaceStatus(feature.status); + feature.status = applyMacros(feature.status); + if (featureTable[feature.type] === undefined) { + featureTable[feature.type] = []; + } + featureTable[feature.type].push(feature); + if (feature.longDescription.length) { + featureTable[feature.type].hasLongDescriptions = true; + } + } + for (const entry in featureTable) { + featureTable[entry].sort(getSorter(entry)); + } + // console.error(featureTable); + featureTable.version = require('../package.json').version; + console.log(Mustache.render(MARKDOWN_TMPL, featureTable)); +} + +function main(filenames) { + // console.error(filenames); + let leftToProcess = filenames.length; + const features = []; + for (const filename of filenames) { + fs.readFile(filename, 'utf-8', (err, data) => { + let match; + while ((match = REX_COMMENTS.exec(data)) !== null) { + if (match.index === REX_COMMENTS.lastIndex) { + REX_COMMENTS.lastIndex++; + } + if (match[1]) { + for (let feature of parseMultiLineGen(filename, match[1])) { + if (feature) features.push(feature); + } + } else { + const feature = parseSingleLine(filename, match[2]); + if (feature) features.push(feature); + } + } + leftToProcess--; + if (!leftToProcess) { + postProcessData(features); + } + }); + } +} + +main(process.argv.slice(2)) diff --git a/package.json b/package.json index 6918e11f..9f3c4a78 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "benchmark": "NODE_PATH=./out xterm-benchmark -r 5 -c test/benchmark/benchmark.json", "benchmark-baseline": "NODE_PATH=./out xterm-benchmark -r 5 -c test/benchmark/benchmark.json --baseline out-test/benchmark/test/benchmark/*benchmark.js", "benchmark-eval": "NODE_PATH=./out xterm-benchmark -r 5 -c test/benchmark/benchmark.json --eval out-test/benchmark/test/benchmark/*benchmark.js", - "clean": "rm -rf lib out addons/*/lib addons/*/out" + "clean": "rm -rf lib out addons/*/lib addons/*/out", + "vtfeatures": "node bin/extract_vtfeatures.js src/**/*.ts src/*.ts" }, "devDependencies": { "@types/chai": "^3.4.34", @@ -46,6 +47,7 @@ "glob": "^7.0.5", "jsdom": "^11.11.0", "mocha": "^6.1.4", + "mustache": "^3.0.1", "node-pty": "^0.9.0", "nyc": "13", "puppeteer": "^1.15.0", diff --git a/src/InputHandler.ts b/src/InputHandler.ts index ef8e93b9..b5b6e32f 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -27,6 +27,30 @@ import { DcsHandler } from 'common/parser/DcsParser'; */ const GLEVEL: {[key: string]: number} = {'(': 0, ')': 1, '*': 2, '+': 3, '-': 1, '.': 2}; +/** + * VT commands done by the parser - FIXME: move this to the parser? + */ +// @vt: #Y ESC CSI "Control Sequence Introducer" "ESC [" "Start of a CSI sequence." +// @vt: #Y ESC OSC "Operating System Command" "ESC ]" "Start of an OSC sequence." +// @vt: #Y ESC DCS "Device Control String" "ESC P" "Start of a DCS sequence." +// @vt: #Y ESC ST "String Terminator" "ESC \" "Terminator used for string type sequences." +// @vt: #Y ESC PM "Privacy Message" "ESC ^" "Start of a privacy message." +// @vt: #Y ESC APC "Application Program Command" "ESC _" "Start of an APC sequence." +// @vt: #Y C1 CSI "Control Sequence Introducer" "\x9B" "Start of a CSI sequence." +// @vt: #Y C1 OSC "Operating System Command" "\x9D" "Start of an OSC sequence." +// @vt: #Y C1 DCS "Device Control String" "\x90" "Start of a DCS sequence." +// @vt: #Y C1 ST "String Terminator" "\x9C" "Terminator used for string type sequences." +// @vt: #Y C1 PM "Privacy Message" "\x9E" "Start of a privacy message." +// @vt: #Y C1 APC "Application Program Command" "\x9F" "Start of an APC sequence." +// @vt: #Y C0 NUL "Null" "\0, \x00" "NUL is ignored." +// @vt: #Y C0 ESC "Escape" "\e, \x1B" "Start of a sequence. Cancels any other sequence." + +/** + * Document common VT features here that are currently unsupported + */ +// @vt: #N DCS SIXEL "SIXEL Graphics" "DCS Ps ; Ps ; Ps ; q Pt ST" "Draw SIXEL image starting at cursor position." +// @vt: #N OSC 1 "Set Icon Name" "OSC 1 ; Pt BEL" "Set icon name." + /** * Max length of the UTF32 input buffer. Real memory consumption is 4 times higher. */ @@ -42,6 +66,27 @@ const MAX_PARSEBUFFER_LENGTH = 131072; * DECRQSS (https://vt100.net/docs/vt510-rm/DECRQSS.html) * Request Status String (DECRQSS), VT420 and up. * Response: DECRPSS (https://vt100.net/docs/vt510-rm/DECRPSS.html) + * + * @vt: #P[See limited support below.] DCS DECRQSS "Request Selection or Setting" "DCS $ q Pt ST" "Request several terminal settings." + * Response is in the form `ESC P 1 $ r Pt ST` for valid requests, where `Pt` contains the corresponding CSI string, + * `ESC P 0 ST` for invalid requests. + * + * Supported requests and responses: + * + * | Type | Request | Response (`Pt`) | + * | -------------------------------- | ----------------- | ----------------------------------------------------- | + * | Graphic Rendition (SGR) | `DCS $ q m ST` | always reporting `0m` (currently broken) | + * | Top and Bottom Margins (DECSTBM) | `DCS $ q r ST` | `Ps ; Ps r` | + * | Cursor Style (DECSCUSR) | `DCS $ q SP q ST` | `Ps SP q` | + * | Protection Attribute (DECSCA) | `DCS $ q " q ST` | always reporting `0 " q` (DECSCA is unsupported) | + * | Conformance Level (DECSCL) | `DCS $ q " p ST` | always reporting `61 ; 1 " p` (DECSCL is unsupported) | + * + * + * TODO: + * - fix SGR report + * - either implement DECSCA or remove the report + * - either check which conformance is better suited or remove the report completely + * --> we are currently a mixture of all up to VT400 but dont follow anyone strictly */ class DECRQSS implements IDcsHandler { private _data: Uint32Array = new Uint32Array(0); @@ -73,7 +118,7 @@ class DECRQSS implements IDcsHandler { case '"q': // DECSCA return this._coreService.triggerDataEvent(`${C0.ESC}P1$r0"q${C0.ESC}\\`); case '"p': // DECSCL - return this._coreService.triggerDataEvent(`${C0.ESC}P1$r61"p${C0.ESC}\\`); + return this._coreService.triggerDataEvent(`${C0.ESC}P1$r61;1"p${C0.ESC}\\`); case 'r': // DECSTBM const pt = '' + (this._bufferService.buffer.scrollTop + 1) + ';' + (this._bufferService.buffer.scrollBottom + 1) + 'r'; @@ -98,18 +143,24 @@ class DECRQSS implements IDcsHandler { * DCS Ps; Ps| Pt ST * DECUDK (https://vt100.net/docs/vt510-rm/DECUDK.html) * not supported + * + * @vt: #N DCS DECUDK "User Defined Keys" "DCS Ps ; Ps | Pt ST" "Definitions for user-defined keys." */ /** * DCS + q Pt ST (xterm) * Request Terminfo String * not implemented + * + * @vt: #N DCS XTGETTCAP "Request Terminfo String" "DCS + q Pt ST" "Request Terminfo String." */ /** * DCS + p Pt ST (xterm) * Set Terminfo Data * not supported + * + * @vt: #N DCS XTSETTCAP "Set Terminfo Data" "DCS + p Pt ST" "Set Terminfo Data." */ @@ -425,7 +476,6 @@ export class InputHandler extends Disposable implements IInputHandler { } // insert combining char at last cursor position - // FIXME: needs handling after cursor jumps // buffer.x should never be 0 for a combining char // since they always follow a cell consuming char // therefore we can test for buffer.x to avoid overflow left @@ -442,10 +492,8 @@ export class InputHandler extends Disposable implements IInputHandler { } // goto next line if ch would overflow - // TODO: needs a global min terminal width of 2 - // FIXME: additionally ensure chWidth fits into a line - // --> maybe forbid cols= cols) { // autowrap - DECAWM // automatically wraps to the beginning of the next line @@ -554,6 +602,10 @@ export class InputHandler extends Disposable implements IInputHandler { /** * BEL * Bell (Ctrl-G). + * + * @vt: #Y C0 BEL "Bell" "\a, \x07" "Ring the bell." + * The behavior of the bell is further customizable with `ITerminalOptions.bellStyle` + * and `ITerminalOptions.bellSound`. */ public bell(): void { this._onRequestBell.fire(); @@ -562,6 +614,12 @@ export class InputHandler extends Disposable implements IInputHandler { /** * LF * Line Feed or New Line (NL). (LF is Ctrl-J). + * + * @vt: #Y C0 LF "Line Feed" "\n, \x0A" "Move the cursor one row down, scrolling if needed." + * Scrolling is restricted to scroll margins and will only happen on the bottom line. + * + * @vt: #Y C0 VT "Vertical Tabulation" "\v, \x0B" "Treated as LF." + * @vt: #Y C0 FF "Form Feed" "\f, \x0C" "Treated as LF." */ public lineFeed(): void { // make buffer local for faster access @@ -590,6 +648,8 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CR * Carriage Return (Ctrl-M). + * + * @vt: #Y C0 CR "Carriage Return" "\r, \x0D" "Move the cursor to the beginning of the row." */ public carriageReturn(): void { this._bufferService.buffer.x = 0; @@ -598,6 +658,8 @@ export class InputHandler extends Disposable implements IInputHandler { /** * BS * Backspace (Ctrl-H). + * + * @vt: #Y C0 BS "Backspace" "\b, \x08" "Move the cursor one position to the left." */ public backspace(): void { this._restrictCursor(); @@ -609,6 +671,8 @@ export class InputHandler extends Disposable implements IInputHandler { /** * TAB * Horizontal Tab (HT) (Ctrl-I). + * + * @vt: #Y C0 HT "Horizontal Tabulation" "\t, \x09" "Move the cursor to the next character tab stop." */ public tab(): void { if (this._bufferService.buffer.x >= this._bufferService.cols) { @@ -625,6 +689,8 @@ export class InputHandler extends Disposable implements IInputHandler { * SO * Shift Out (Ctrl-N) -> Switch to Alternate Character Set. This invokes the * G1 character set. + * + * @vt: #P[Only limited ISO-2022 charset support.] C0 SO "Shift Out" "\x0E" "Switch to an alternative character set." */ public shiftOut(): void { this._charsetService.setgLevel(1); @@ -634,6 +700,8 @@ export class InputHandler extends Disposable implements IInputHandler { * SI * Shift In (Ctrl-O) -> Switch to Standard Character Set. This invokes the G0 * character set (the default). + * + * @vt: #Y C0 SI "Shift In" "\x0F" "Return to regular character set after Shift Out." */ public shiftIn(): void { this._charsetService.setgLevel(0); @@ -679,6 +747,9 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps A * Cursor Up Ps Times (default = 1) (CUU). + * + * @vt: #Y CSI CUU "Cursor Up" "CSI Ps A" "Move cursor `Ps` times up (default=1)." + * If the cursor would pass the top scroll margin, it will stop there. */ public cursorUp(params: IParams): void { // stop at scrollTop @@ -693,6 +764,9 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps B * Cursor Down Ps Times (default = 1) (CUD). + * + * @vt: #Y CSI CUD "Cursor Down" "CSI Ps B" "Move cursor `Ps` times down (default=1)." + * If the cursor would pass the bottom scroll margin, it will stop there. */ public cursorDown(params: IParams): void { // stop at scrollBottom @@ -707,6 +781,8 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps C * Cursor Forward Ps Times (default = 1) (CUF). + * + * @vt: #Y CSI CUF "Cursor Forward" "CSI Ps C" "Move cursor `Ps` times forward (default=1)." */ public cursorForward(params: IParams): void { this._moveCursor(params.params[0] || 1, 0); @@ -715,6 +791,8 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps D * Cursor Backward Ps Times (default = 1) (CUB). + * + * @vt: #Y CSI CUB "Cursor Backward" "CSI Ps D" "Move cursor `Ps` times backward (default=1)." */ public cursorBackward(params: IParams): void { this._moveCursor(-(params.params[0] || 1), 0); @@ -724,6 +802,9 @@ export class InputHandler extends Disposable implements IInputHandler { * CSI Ps E * Cursor Next Line Ps Times (default = 1) (CNL). * Other than cursorDown (CUD) also set the cursor to first column. + * + * @vt: #Y CSI CNL "Cursor Next Line" "CSI Ps E" "Move cursor `Ps` times down (default=1) and to the first column." + * Same as CUD, additionally places the cursor at the first column. */ public cursorNextLine(params: IParams): void { this.cursorDown(params); @@ -734,6 +815,9 @@ export class InputHandler extends Disposable implements IInputHandler { * CSI Ps F * Cursor Previous Line Ps Times (default = 1) (CPL). * Other than cursorUp (CUU) also set the cursor to first column. + * + * @vt: #Y CSI CPL "Cursor Backward" "CSI Ps F" "Move cursor `Ps` times up (default=1) and to the first column." + * Same as CUU, additionally places the cursor at the first column. */ public cursorPrecedingLine(params: IParams): void { this.cursorUp(params); @@ -743,6 +827,8 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps G * Cursor Character Absolute [column] (default = [row,1]) (CHA). + * + * @vt: #Y CSI CHA "Cursor Horizontal Absolute" "CSI Ps G" "Move cursor to `Ps`-th column of the active row (default=1)." */ public cursorCharAbsolute(params: IParams): void { this._setCursor((params.params[0] || 1) - 1, this._bufferService.buffer.y); @@ -751,6 +837,11 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps ; Ps H * Cursor Position [row;column] (default = [1,1]) (CUP). + * + * @vt: #Y CSI CUP "Cursor Position" "CSI Ps ; Ps H" "Set cursor to position [`Ps`, `Ps`] (default = [1, 1])." + * If ORIGIN mode is set, places the cursor to the absolute position within the scroll margins. + * If ORIGIN mode is not set, places the cursor to the absolute position within the viewport. + * Note that the coordinates are 1-based, thus the top left position starts at `1 ; 1`. */ public cursorPosition(params: IParams): void { this._setCursor( @@ -764,6 +855,8 @@ export class InputHandler extends Disposable implements IInputHandler { * CSI Pm ` Character Position Absolute * [column] (default = [row,1]) (HPA). * Currently same functionality as CHA. + * + * @vt: #Y CSI HPA "Horizontal Position Absolute" "CSI Ps ` " "Same as CHA." */ public charPosAbsolute(params: IParams): void { this._setCursor((params.params[0] || 1) - 1, this._bufferService.buffer.y); @@ -772,7 +865,8 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Pm a Character Position Relative * [columns] (default = [row,col+1]) (HPR) - * Currently same functionality as CUF. + * + * @vt: #Y CSI HPR "Horizontal Position Relative" "CSI Ps a" "Same as CUF." */ public hPositionRelative(params: IParams): void { this._moveCursor(params.params[0] || 1, 0); @@ -781,6 +875,8 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Pm d Vertical Position Absolute (VPA) * [row] (default = [1,column]) + * + * @vt: #Y CSI VPA "Vertical Position Absolute" "CSI Ps d" "Move cursor to `Ps`-th row (default=1)." */ public linePosAbsolute(params: IParams): void { this._setCursor(this._bufferService.buffer.x, (params.params[0] || 1) - 1); @@ -790,6 +886,8 @@ export class InputHandler extends Disposable implements IInputHandler { * CSI Pm e Vertical Position Relative (VPR) * [rows] (default = [row+1,column]) * reuse CSI Ps B ? + * + * @vt: #Y CSI VPR "Vertical Position Relative" "CSI Ps e" "Move cursor `Ps` times down (default=1)." */ public vPositionRelative(params: IParams): void { this._moveCursor(0, params.params[0] || 1); @@ -800,6 +898,8 @@ export class InputHandler extends Disposable implements IInputHandler { * Horizontal and Vertical Position [row;column] (default = * [1,1]) (HVP). * Same as CUP. + * + * @vt: #Y CSI HVP "Horizontal and Vertical Position" "CSI Ps ; Ps f" "Same as CUP." */ public hVPosition(params: IParams): void { this.cursorPosition(params); @@ -812,6 +912,9 @@ export class InputHandler extends Disposable implements IInputHandler { * Potentially: * Ps = 2 -> Clear Stops on Line. * http://vt100.net/annarbor/aaa-ug/section6.html + * + * @vt: #Y CSI TBC "Tab Clear" "CSI Ps g" "Clear tab stops at current position (0) or all (3) (default=0)." + * Clearing tabstops off the active row (Ps = 2, VT100) is currently not supported. */ public tabClear(params: IParams): void { const param = params.params[0]; @@ -825,6 +928,8 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps I * Cursor Forward Tabulation Ps tab stops (default = 1) (CHT). + * + * @vt: #Y CSI CHT "Cursor Horizontal Tabulation" "CSI Ps I" "Move cursor `Ps` times tabs forward (default=1)." */ public cursorForwardTab(params: IParams): void { if (this._bufferService.buffer.x >= this._bufferService.cols) { @@ -838,6 +943,8 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps Z Cursor Backward Tabulation Ps tab stops (default = 1) (CBT). + * + * @vt: #Y CSI CBT "Cursor Backward Tabulation" "CSI Ps Z" "Move cursor `Ps` tabs backward (default=1)." */ public cursorBackwardTab(params: IParams): void { if (this._bufferService.buffer.x >= this._bufferService.cols) { @@ -896,6 +1003,18 @@ export class InputHandler extends Disposable implements IInputHandler { * Ps = 0 -> Selective Erase Below (default). * Ps = 1 -> Selective Erase Above. * Ps = 2 -> Selective Erase All. + * + * @vt: #Y CSI ED "Erase In Display" "CSI Ps J" "Erase various parts of the viewport." + * Supported param values: + * + * | Ps | Effect | + * | -- | ------------------------------------------------------------ | + * | 0 | Erase from the cursor through the end of the viewport. | + * | 1 | Erase from the beginning of the viewport through the cursor. | + * | 2 | Erase complete viewport. | + * | 3 | Erase scrollback. | + * + * @vt: #P[Protection attributes are not supported.] CSI DECSED "Selective Erase In Display" "CSI ? Ps J" "Currently the same as ED." */ public eraseInDisplay(params: IParams): void { this._restrictCursor(); @@ -956,6 +1075,17 @@ export class InputHandler extends Disposable implements IInputHandler { * Ps = 0 -> Selective Erase to Right (default). * Ps = 1 -> Selective Erase to Left. * Ps = 2 -> Selective Erase All. + * + * @vt: #Y CSI EL "Erase In Line" "CSI Ps K" "Erase various parts of the active row." + * Supported param values: + * + * | Ps | Effect | + * | -- | -------------------------------------------------------- | + * | 0 | Erase from the cursor through the end of the row. | + * | 1 | Erase from the beginning of the line through the cursor. | + * | 2 | Erase complete line. | + * + * @vt: #P[Protection attributes are not supported.] CSI DECSEL "Selective Erase In Line" "CSI ? Ps K" "Currently the same as EL." */ public eraseInLine(params: IParams): void { this._restrictCursor(); @@ -976,6 +1106,11 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps L * Insert Ps Line(s) (default = 1) (IL). + * + * @vt: #Y CSI IL "Insert Line" "CSI Ps L" "Insert `Ps` blank lines at active row (default=1)." + * For every inserted line at the scroll top one line at the scroll bottom gets removed. + * The cursor is set to the first column. + * IL has no effect if the cursor is outside the scroll margins. */ public insertLines(params: IParams): void { this._restrictCursor(); @@ -1006,6 +1141,11 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps M * Delete Ps Line(s) (default = 1) (DL). + * + * @vt: #Y CSI DL "Delete Line" "CSI Ps M" "Delete `Ps` lines at active row (default=1)." + * For every deleted line at the scroll top one blank line at the scroll bottom gets appended. + * The cursor is set to the first column. + * DL has no effect if the cursor is outside the scroll margins. */ public deleteLines(params: IParams): void { this._restrictCursor(); @@ -1037,6 +1177,13 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps @ * Insert Ps (Blank) Character(s) (default = 1) (ICH). + * + * @vt: #Y CSI ICH "Insert Characters" "CSI Ps @" "Insert `Ps` (blank) characters (default = 1)." + * The ICH sequence inserts `Ps` blank characters. The cursor remains at the beginning of the blank characters. + * Text between the cursor and right margin moves to the right. Characters moved past the right margin are lost. + * + * + * FIXME: check against xterm - should not work outside of scroll margins (see VT520 manual) */ public insertChars(params: IParams): void { this._restrictCursor(); @@ -1055,6 +1202,13 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps P * Delete Ps Character(s) (default = 1) (DCH). + * + * @vt: #Y CSI DCH "Delete Character" "CSI Ps P" "Delete `Ps` characters (default=1)." + * As characters are deleted, the remaining characters between the cursor and right margin move to the left. + * Character attributes move with the characters. The terminal adds blank characters at the right margin. + * + * + * FIXME: check against xterm - should not work outside of scroll margins (see VT520 manual) */ public deleteChars(params: IParams): void { this._restrictCursor(); @@ -1072,6 +1226,11 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps S Scroll up Ps lines (default = 1) (SU). + * + * @vt: #Y CSI SU "Scroll Up" "CSI Ps S" "Scroll `Ps` lines up (default=1)." + * + * + * FIXME: scrolled out lines at top = 1 should add to scrollback (xterm) */ public scrollUp(params: IParams): void { let param = params.params[0] || 1; @@ -1088,6 +1247,8 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps T Scroll down Ps lines (default = 1) (SD). + * + * @vt: #Y CSI SD "Scroll Down" "CSI Ps T" "Scroll `Ps` lines down (default=1)." */ public scrollDown(params: IParams): void { let param = params.params[0] || 1; @@ -1115,6 +1276,10 @@ export class InputHandler extends Disposable implements IInputHandler { * * Supported: * - always left shift (no line orientation setting respected) + * + * @vt: #Y CSI SL "Scroll Left" "CSI Ps SP @" "Scroll viewport `Ps` times to the left." + * SL moves the content of all lines within the scroll margins `Ps` times to the left. + * SL has no effect outside of the scroll margins. */ public scrollLeft(params: IParams): void { const buffer = this._bufferService.buffer; @@ -1143,6 +1308,11 @@ export class InputHandler extends Disposable implements IInputHandler { * * Supported: * - always right shift (no line orientation setting respected) + * + * @vt: #Y CSI SR "Scroll Right" "CSI Ps SP A" "Scroll viewport `Ps` times to the right." + * SL moves the content of all lines within the scroll margins `Ps` times to the right. + * Content at the right margin is lost. + * SL has no effect outside of the scroll margins. */ public scrollRight(params: IParams): void { const buffer = this._bufferService.buffer; @@ -1161,6 +1331,11 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Pm ' } * Insert Ps Column(s) (default = 1) (DECIC), VT420 and up. + * + * @vt: #Y CSI DECIC "Insert Columns" "CSI Ps ' }" "Insert `Ps` columns at cursor position." + * DECIC inserts `Ps` times blank columns at the cursor position for all lines with the scroll margins, + * moving content to the right. Content at the right margin is lost. + * DECIC has no effect outside the scrolling margins. */ public insertColumns(params: IParams): void { const buffer = this._bufferService.buffer; @@ -1179,6 +1354,11 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Pm ' ~ * Delete Ps Column(s) (default = 1) (DECDC), VT420 and up. + * + * @vt: #Y CSI DECDC "Delete Columns" "CSI Ps ' ~" "Delete `Ps` columns at cursor position." + * DECDC deletes `Ps` times columns at the cursor position for all lines with the scroll margins, + * moving content to the left. Blank columns are added at the right margin. + * DECDC has no effect outside the scrolling margins. */ public deleteColumns(params: IParams): void { const buffer = this._bufferService.buffer; @@ -1197,6 +1377,10 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Ps X * Erase Ps Character(s) (default = 1) (ECH). + * + * @vt: #Y CSI ECH "Erase Character" "CSI Ps X" "Erase `Ps` characters from current cursor position to the right (default=1)." + * ED erases `Ps` characters from current cursor position to the right. + * ED works inside or outside the scrolling margins. */ public eraseChars(params: IParams): void { this._restrictCursor(); @@ -1233,6 +1417,11 @@ export class InputHandler extends Disposable implements IInputHandler { * * Note: To get reset on a valid sequence working correctly without much runtime penalty, * the preceding codepoint is stored on the parser in `this.print` and reset during `parser.parse`. + * + * @vt: #Y CSI REP "Repeat Preceding Character" "CSI Ps b" "Repeat preceding character `Ps` times (default=1)." + * REP repeats the previous character `Ps` times advancing the cursor, also wrapping if DECAWM is set. + * REP has no effect if the sequence does not follow a printable ASCII character + * (NOOP for any other sequence in between or NON ASCII characters). */ public repeatPrecedingCharacter(params: IParams): void { if (!this._parser.precedingCodepoint) { @@ -1266,6 +1455,24 @@ export class InputHandler extends Disposable implements IInputHandler { * Ps = 1 5 -> Technical characters. * Ps = 2 2 -> ANSI color, e.g., VT525. * Ps = 2 9 -> ANSI text locator (i.e., DEC Locator mode). + * + * @vt: #Y CSI DA1 "Primary Device Attributes" "CSI c" "Send primary device attributes." + * + * + * TODO: fix and cleanup response + */ + public sendDeviceAttributesPrimary(params: IParams): void { + if (params.params[0] > 0) { + return; + } + if (this._terminal.is('xterm') || this._terminal.is('rxvt-unicode') || this._terminal.is('screen')) { + this._coreService.triggerDataEvent(C0.ESC + '[?1;2c'); + } else if (this._terminal.is('linux')) { + this._coreService.triggerDataEvent(C0.ESC + '[?6c'); + } + } + + /** * CSI > Ps c * Send Device Attributes (Secondary DA). * Ps = 0 or omitted -> request the terminal's identification @@ -1283,17 +1490,12 @@ export class InputHandler extends Disposable implements IInputHandler { * More information: * xterm/charproc.c - line 2012, for more information. * vim responds with ^[[?0c or ^[[?1c after the terminal's response (?) + * + * @vt: #Y CSI DA2 "Secondary Device Attributes" "CSI > c" "Send primary device attributes." + * + * + * TODO: fix and cleanup response */ - public sendDeviceAttributesPrimary(params: IParams): void { - if (params.params[0] > 0) { - return; - } - if (this._terminal.is('xterm') || this._terminal.is('rxvt-unicode') || this._terminal.is('screen')) { - this._coreService.triggerDataEvent(C0.ESC + '[?1;2c'); - } else if (this._terminal.is('linux')) { - this._coreService.triggerDataEvent(C0.ESC + '[?6c'); - } - } public sendDeviceAttributesSecondary(params: IParams): void { if (params.params[0] > 0) { return; @@ -1320,6 +1522,34 @@ export class InputHandler extends Disposable implements IInputHandler { * Ps = 4 -> Insert Mode (IRM). * Ps = 1 2 -> Send/receive (SRM). * Ps = 2 0 -> Automatic Newline (LNM). + * + * @vt: #P[Only IRM is supported.] CSI SM "Set Mode" "CSI Pm h" "Set various terminal modes." + * Supported param values by SM: + * + * | Param | Action | Support | + * | ----- | -------------------------------------- | ------- | + * | 2 | Keyboard Action Mode (KAM). Always on. | #N | + * | 4 | Insert Mode (IRM). | #Y | + * | 12 | Send/receive (SRM). Always off. | #N | + * | 20 | Automatic Newline (LNM). Always off. | #N | + * + * + * FIXME: why is LNM commented out? + */ + public setMode(params: IParams): void { + for (let i = 0; i < params.length; i++) { + switch (params.params[i]) { + case 4: + this._terminal.insertMode = true; + break; + case 20: + // this._t.convertEol = true; + break; + } + } + } + + /** * CSI ? Pm h * DEC Private Mode Set (DECSET). * Ps = 1 -> Application Cursor Keys (DECCKM). @@ -1399,19 +1629,38 @@ export class InputHandler extends Disposable implements IInputHandler { * Ps = 2 0 0 4 -> Set bracketed paste mode. * Modes: * http: *vt100.net/docs/vt220-rm/chapter4.html + * + * @vt: #P[See below for supported modes.] CSI DECSET "DEC Private Set Mode" "CSI ? Pm h" "Set various terminal attributes." + * Supported param values by DECSET: + * + * | param | Action | Support | + * | ----- | ------------------------------------------------------- | --------| + * | 1 | Application Cursor Keys (DECCKM). | #Y | + * | 2 | Designate US-ASCII for character sets G0-G3 (DECANM). | #Y | + * | 3 | 132 Column Mode (DECCOLM). | #Y | + * | 6 | Origin Mode (DECOM). | #Y | + * | 7 | Auto-wrap Mode (DECAWM). | #Y | + * | 8 | Auto-repeat Keys (DECARM). Always on. | #N | + * | 9 | X10 xterm mouse protocol. | #Y | + * | 12 | Start Blinking Cursor. | #Y | + * | 25 | Show Cursor (DECTCEM). | #Y | + * | 47 | Use Alternate Screen Buffer. | #Y | + * | 66 | Application keypad (DECNKM). | #Y | + * | 1000 | X11 xterm mouse protocol. | #Y | + * | 1002 | Use Cell Motion Mouse Tracking. | #Y | + * | 1003 | Use All Motion Mouse Tracking. | #Y | + * | 1004 | Send FocusIn/FocusOut events | #Y | + * | 1005 | Enable UTF-8 Mouse Mode. | #N | + * | 1006 | Enable SGR Mouse Mode. | #Y | + * | 1015 | Enable urxvt Mouse Mode. | #N | + * | 1047 | Use Alternate Screen Buffer. | #Y | + * | 1048 | Save cursor as in DECSC. | #Y | + * | 1049 | Save cursor and switch to alternate buffer clearing it. | #P[Does not clear the alternate buffer.] | + * | 2004 | Set bracketed paste mode. | #Y | + * + * + * FIXME: implement DECSCNM, 1049 should clear altbuffer */ - public setMode(params: IParams): void { - for (let i = 0; i < params.length; i++) { - switch (params.params[i]) { - case 4: - this._terminal.insertMode = true; - break; - case 20: - // this._t.convertEol = true; - break; - } - } - } public setModePrivate(params: IParams): void { for (let i = 0; i < params.length; i++) { switch (params.params[i]) { @@ -1506,6 +1755,34 @@ export class InputHandler extends Disposable implements IInputHandler { * Ps = 4 -> Replace Mode (IRM). * Ps = 1 2 -> Send/receive (SRM). * Ps = 2 0 -> Normal Linefeed (LNM). + * + * @vt: #P[Only IRM is supported.] CSI RM "Reset Mode" "CSI Pm l" "Set various terminal attributes." + * Supported param values by RM: + * + * | Param | Action | Support | + * | ----- | -------------------------------------- | ------- | + * | 2 | Keyboard Action Mode (KAM). Always on. | #N | + * | 4 | Replace Mode (IRM). (default) | #Y | + * | 12 | Send/receive (SRM). Always off. | #N | + * | 20 | Normal Linefeed (LNM). Always off. | #N | + * + * + * FIXME: why is LNM commented out? + */ + public resetMode(params: IParams): void { + for (let i = 0; i < params.length; i++) { + switch (params.params[i]) { + case 4: + this._terminal.insertMode = false; + break; + case 20: + // this._t.convertEol = false; + break; + } + } + } + + /** * CSI ? Pm l * DEC Private Mode Reset (DECRST). * Ps = 1 -> Normal Cursor Keys (DECCKM). @@ -1581,19 +1858,38 @@ export class InputHandler extends Disposable implements IInputHandler { * Ps = 1 0 6 0 -> Reset legacy keyboard emulation (X11R6). * Ps = 1 0 6 1 -> Reset keyboard emulation to Sun/PC style. * Ps = 2 0 0 4 -> Reset bracketed paste mode. + * + * @vt: #P[See below for supported modes.] CSI DECRST "DEC Private Reset Mode" "CSI ? Pm l" "Reset various terminal attributes." + * Supported param values by DECRST: + * + * | param | Action | Support | + * | ----- | ------------------------------------------------------- | ------- | + * | 1 | Normal Cursor Keys (DECCKM). | #Y | + * | 2 | Designate VT52 mode (DECANM). | #N | + * | 3 | 80 Column Mode (DECCOLM). | #B[Switches to old column width instead of 80.] | + * | 6 | Normal Cursor Mode (DECOM). | #Y | + * | 7 | No Wraparound Mode (DECAWM). | #Y | + * | 8 | No Auto-repeat Keys (DECARM). | #N | + * | 9 | Don't send Mouse X & Y on button press. | #Y | + * | 12 | Stop Blinking Cursor. | #Y | + * | 25 | Hide Cursor (DECTCEM). | #Y | + * | 47 | Use Normal Screen Buffer. | #Y | + * | 66 | Numeric keypad (DECNKM). | #Y | + * | 1000 | Don't send Mouse reports. | #Y | + * | 1002 | Don't use Cell Motion Mouse Tracking. | #Y | + * | 1003 | Don't use All Motion Mouse Tracking. | #Y | + * | 1004 | Don't send FocusIn/FocusOut events. | #Y | + * | 1005 | Disable UTF-8 Mouse Mode. | #N | + * | 1006 | Disable SGR Mouse Mode. | #Y | + * | 1015 | Disable urxvt Mouse Mode. | #N | + * | 1047 | Use Normal Screen Buffer (clearing screen if in alt). | #Y | + * | 1048 | Restore cursor as in DECRC. | #Y | + * | 1049 | Use Normal Screen Buffer and restore cursor. | #Y | + * | 2004 | Reset bracketed paste mode. | #Y | + * + * + * FIXME: DECCOLM is currently broken (already fixed in window options PR) */ - public resetMode(params: IParams): void { - for (let i = 0; i < params.length; i++) { - switch (params.params[i]) { - case 4: - this._terminal.insertMode = false; - break; - case 20: - // this._t.convertEol = false; - break; - } - } - } public resetModePrivate(params: IParams): void { for (let i = 0; i < params.length; i++) { switch (params.params[i]) { @@ -1743,68 +2039,72 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI Pm m Character Attributes (SGR). - * Ps = 0 -> Normal (default). - * Ps = 1 -> Bold. - * Ps = 2 -> Faint, decreased intensity (ISO 6429). - * Ps = 4 -> Underlined. - * Ps = 5 -> Blink (appears as Bold). - * Ps = 7 -> Inverse. - * Ps = 8 -> Invisible, i.e., hidden (VT300). - * Ps = 2 2 -> Normal (neither bold nor faint). - * Ps = 2 4 -> Not underlined. - * Ps = 2 5 -> Steady (not blinking). - * Ps = 2 7 -> Positive (not inverse). - * Ps = 2 8 -> Visible, i.e., not hidden (VT300). - * Ps = 3 0 -> Set foreground color to Black. - * Ps = 3 1 -> Set foreground color to Red. - * Ps = 3 2 -> Set foreground color to Green. - * Ps = 3 3 -> Set foreground color to Yellow. - * Ps = 3 4 -> Set foreground color to Blue. - * Ps = 3 5 -> Set foreground color to Magenta. - * Ps = 3 6 -> Set foreground color to Cyan. - * Ps = 3 7 -> Set foreground color to White. - * Ps = 3 9 -> Set foreground color to default (original). - * Ps = 4 0 -> Set background color to Black. - * Ps = 4 1 -> Set background color to Red. - * Ps = 4 2 -> Set background color to Green. - * Ps = 4 3 -> Set background color to Yellow. - * Ps = 4 4 -> Set background color to Blue. - * Ps = 4 5 -> Set background color to Magenta. - * Ps = 4 6 -> Set background color to Cyan. - * Ps = 4 7 -> Set background color to White. - * Ps = 4 9 -> Set background color to default (original). * - * If 16-color support is compiled, the following apply. Assume - * that xterm's resources are set so that the ISO color codes are - * the first 8 of a set of 16. Then the aixterm colors are the - * bright versions of the ISO colors: - * Ps = 9 0 -> Set foreground color to Black. - * Ps = 9 1 -> Set foreground color to Red. - * Ps = 9 2 -> Set foreground color to Green. - * Ps = 9 3 -> Set foreground color to Yellow. - * Ps = 9 4 -> Set foreground color to Blue. - * Ps = 9 5 -> Set foreground color to Magenta. - * Ps = 9 6 -> Set foreground color to Cyan. - * Ps = 9 7 -> Set foreground color to White. - * Ps = 1 0 0 -> Set background color to Black. - * Ps = 1 0 1 -> Set background color to Red. - * Ps = 1 0 2 -> Set background color to Green. - * Ps = 1 0 3 -> Set background color to Yellow. - * Ps = 1 0 4 -> Set background color to Blue. - * Ps = 1 0 5 -> Set background color to Magenta. - * Ps = 1 0 6 -> Set background color to Cyan. - * Ps = 1 0 7 -> Set background color to White. + * @vt: #P[See below for supported attributes.] CSI SGR "Select Graphic Rendition" "CSI Pm m" "Set/Reset various text attributes." + * SGR selects one or more character attributes at the same time. Multiple params (up to 32) + * are applied from in order from left to right. The changed attributes are applied to all new + * characters received. If you move characters in the viewport by scrolling or any other means, + * then the attributes move with the characters. * - * If xterm is compiled with the 16-color support disabled, it - * supports the following, from rxvt: - * Ps = 1 0 0 -> Set foreground and background color to - * default. + * Supported param values by SGR: * - * If 88- or 256-color support is compiled, the following apply. - * Ps = 3 8 ; 5 ; Ps -> Set foreground color to the second - * Ps. - * Ps = 4 8 ; 5 ; Ps -> Set background color to the second - * Ps. + * | Param | Meaning | Support | + * | --------- | -------------------------------------------------------- | ------- | + * | 0 | Normal (default). Resets any other preceding SGR. | #Y | + * | 1 | Bold. (also see `options.drawBoldTextInBrightColors`) | #Y | + * | 2 | Faint, decreased intensity. | #Y | + * | 3 | Italic. | #Y | + * | 4 | Underlined. (no support for newer underline styles) | #Y | + * | 5 | Slowly blinking. | #N | + * | 6 | Rapidly blinking. | #N | + * | 7 | Inverse. Flips foreground and background color. | #Y | + * | 8 | Invisible (hidden). | #Y | + * | 9 | Crossed-out characters. | #N | + * | 21 | Doubly underlined. | #N | + * | 22 | Normal (neither bold nor faint). | #Y | + * | 23 | No italic. | #Y | + * | 24 | Not underlined. | #Y | + * | 25 | Steady (not blinking). | #Y | + * | 27 | Positive (not inverse). | #Y | + * | 28 | Visible (not hidden). | #Y | + * | 29 | Not Crossed-out. | #N | + * | 30 | Foreground color: Black. | #Y | + * | 31 | Foreground color: Red. | #Y | + * | 32 | Foreground color: Green. | #Y | + * | 33 | Foreground color: Yellow. | #Y | + * | 34 | Foreground color: Blue. | #Y | + * | 35 | Foreground color: Magenta. | #Y | + * | 36 | Foreground color: Cyan. | #Y | + * | 37 | Foreground color: White. | #Y | + * | 38 | Foreground color: Extended color. | #P[Support for RGB and indexed colors, see below.] | + * | 39 | Foreground color: Default (original). | #Y | + * | 40 | Background color: Black. | #Y | + * | 41 | Background color: Red. | #Y | + * | 42 | Background color: Green. | #Y | + * | 43 | Background color: Yellow. | #Y | + * | 44 | Background color: Blue. | #Y | + * | 45 | Background color: Magenta. | #Y | + * | 46 | Background color: Cyan. | #Y | + * | 47 | Background color: White. | #Y | + * | 48 | Background color: Extended color. | #P[Support for RGB and indexed colors, see below.] | + * | 49 | Background color: Default (original). | #Y | + * | 90 - 97 | Bright foreground color (analogous to 30 - 37). | #Y | + * | 100 - 107 | Bright background color (analogous to 40 - 47). | #Y | + * + * Extended colors are supported for foreground (Ps=38) and background (Ps=48) as follows: + * + * | Ps + 1 | Meaning | Support | + * | ------ | ------------------------------------------------------------- | ------- | + * | 0 | Implementation defined. | #N | + * | 1 | Transparent. | #N | + * | 2 | RGB color as `Ps ; 2 ; R ; G ; B` or `Ps : 2 : : R : G : B`. | #Y | + * | 3 | CMY color. | #N | + * | 4 | CMYK color. | #N | + * | 5 | Indexed (256 colors) as `Ps ; 5 ; INDEX` or `Ps : 5 : INDEX`. | #Y | + * + * + * FIXME: blinking is implemented in attrs, but not working in renderers? + * FIXME: remove dead branch for p=100 */ public charAttributes(params: IParams): void { // Optimize a single SGR0. @@ -1892,7 +2192,7 @@ export class InputHandler extends Disposable implements IInputHandler { } else if (p === 38 || p === 48) { // fg color 256 and RGB i += this._extractColor(params, i, attr); - } else if (p === 100) { + } else if (p === 100) { // FIXME: dead branch, p=100 already handled above! // reset fg/bg attr.fg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK); attr.fg |= DEFAULT_ATTR_DATA.fg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK); @@ -1926,6 +2226,8 @@ export class InputHandler extends Disposable implements IInputHandler { * Ps = 5 3 -> Report Locator status as * CSI ? 5 3 n Locator available, if compiled-in, or * CSI ? 5 0 n No Locator, if not. + * + * @vt: #Y CSI DSR "Device Status Report" "CSI Ps n" "Request cursor position (CPR) with `Ps` = 6." */ public deviceStatus(params: IParams): void { switch (params.params[0]) { @@ -1942,6 +2244,7 @@ export class InputHandler extends Disposable implements IInputHandler { } } + // @vt: #P[Only CPR is supported.] CSI DECDSR "DEC Device Status Report" "CSI ? Ps n" "Only CPR is supported (same as DSR)." public deviceStatusPrivate(params: IParams): void { // modern xterm doesnt seem to // respond to any of these except ?6, 6, and 5 @@ -1974,6 +2277,20 @@ export class InputHandler extends Disposable implements IInputHandler { /** * CSI ! p Soft terminal reset (DECSTR). * http://vt100.net/docs/vt220-rm/table4-10.html + * + * @vt: #Y CSI DECSTR "Soft Terminal Reset" "CSI ! p" "Reset several terminal attributes to initial state." + * There are two terminal reset sequences - RIS and DECSTR. While RIS performs almost a full terminal bootstrap, + * DECSTR only resets certain attributes. For most needs DECSTR should be sufficient. + * + * The following terminal attributes are reset to default values: + * - cursor is reset (default = visible, home position) + * - IRM is reset (dafault = false) + * - scroll margins are reset (default = viewport size) + * - erase attributes are reset to default + * - charsets are reset + * + * + * FIXME: there are several more attributes missing (see VT520 manual) */ public softReset(params: IParams): void { this._coreService.isCursorHidden = false; @@ -1996,6 +2313,15 @@ export class InputHandler extends Disposable implements IInputHandler { * Ps = 4 -> steady underline. * Ps = 5 -> blinking bar (xterm). * Ps = 6 -> steady bar (xterm). + * + * @vt: #Y CSI DECSCUSR "Set Cursor Style" "CSI Ps SP q" "Set cursor style." + * Supported cursor styles: + * - empty, 0 or 1: steady block + * - 2: blink block + * - 3: steady underline + * - 4: blink underline + * - 5: steady bar + * - 6: blink bar */ public setCursorStyle(params: IParams): void { const param = params.params[0] || 1; @@ -2021,6 +2347,8 @@ export class InputHandler extends Disposable implements IInputHandler { * CSI Ps ; Ps r * Set Scrolling Region [top;bottom] (default = full size of win- * dow) (DECSTBM). + * + * @vt: #Y CSI DECSTBM "Set Top and Bottom Margin" "CSI Ps ; Ps r" "Set top and bottom margins of the viewport [top;bottom] (default = viewport size)." */ public setScrollRegion(params: IParams): void { const top = params.params[0] || 1; @@ -2042,6 +2370,9 @@ export class InputHandler extends Disposable implements IInputHandler { * CSI s * ESC 7 * Save cursor (ANSI.SYS). + * + * @vt: #P[TODO...] CSI SCOSC "Save Cursor" "CSI s" "Save cursor position, charmap and text attributes." + * @vt: #Y ESC SC "Save Cursor" "ESC 7" "Save cursor position, charmap and text attributes." */ public saveCursor(params?: IParams): void { this._bufferService.buffer.savedX = this._bufferService.buffer.x; @@ -2056,6 +2387,9 @@ export class InputHandler extends Disposable implements IInputHandler { * CSI u * ESC 8 * Restore cursor (ANSI.SYS). + * + * @vt: #P[TODO...] CSI SCORC "Restore Cursor" "CSI u" "Restore cursor position, charmap and text attributes." + * @vt: #Y ESC RC "Restore Cursor" "ESC 8" "Restore cursor position, charmap and text attributes." */ public restoreCursor(params?: IParams): void { this._bufferService.buffer.x = this._bufferService.buffer.savedX || 0; @@ -2074,6 +2408,12 @@ export class InputHandler extends Disposable implements IInputHandler { * OSC 0; ST (set icon name + window title) * OSC 2; ST (set window title) * Proxy to set window title. Icon name is not supported. + * + * @vt: #P[Icon name is not exposed.] OSC 0 "Set Windows Title and Icon Name" "OSC 0 ; Pt BEL" "Set window title and icon name." + * Icon name is not supported. For Window Title see below. + * + * @vt: #Y OSC 2 "Set Windows Title" "OSC 2 ; Pt BEL" "Set window title." + * xterm.js does not manipulate the title directly, instead exposes changes via the event `Terminal.onTitleChange`. */ public setTitle(data: string): void { this._terminal.handleTitle(data); @@ -2084,6 +2424,9 @@ export class InputHandler extends Disposable implements IInputHandler { * C1.NEL * DEC mnemonic: NEL (https://vt100.net/docs/vt510-rm/NEL) * Moves cursor to first position on next line. + * + * @vt: #Y C1 NEL "Next Line" "\x85" "Move the cursor to the beginning of the next row." + * @vt: #Y ESC NEL "Next Line" "ESC E" "Move the cursor to the beginning of the next row." */ public nextLine(): void { this._bufferService.buffer.x = 0; @@ -2156,6 +2499,9 @@ export class InputHandler extends Disposable implements IInputHandler { * C1.IND * DEC mnemonic: IND (https://vt100.net/docs/vt510-rm/IND.html) * Moves the cursor down one line in the same column. + * + * @vt: #Y C1 IND "Index" "\x84" "Move the cursor one line down scrolling if needed." + * @vt: #Y ESC IND "Index" "ESC D" "Move the cursor one line down scrolling if needed." */ public index(): void { this._restrictCursor(); @@ -2176,6 +2522,9 @@ export class InputHandler extends Disposable implements IInputHandler { * DEC mnemonic: HTS (https://vt100.net/docs/vt510-rm/HTS.html) * Sets a horizontal tab stop at the column position indicated by * the value of the active column when the terminal receives an HTS. + * + * @vt: #Y C1 HTS "Horizontal Tabulation Set" "\x88" "Places a tab stop at the current cursor position." + * @vt: #Y ESC HTS "Horizontal Tabulation Set" "ESC H" "Places a tab stop at the current cursor position." */ public tabSet(): void { this._bufferService.buffer.tabs[this._bufferService.buffer.x] = true; @@ -2187,6 +2536,8 @@ export class InputHandler extends Disposable implements IInputHandler { * DEC mnemonic: HTS * Moves the cursor up one line in the same column. If the cursor is at the top margin, * the page scrolls down. + * + * @vt: #Y ESC IR "Reverse Index" "ESC M" "Move the cursor one line up scrolling if needed." */ public reverseIndex(): void { this._restrictCursor(); @@ -2249,7 +2600,7 @@ export class InputHandler extends Disposable implements IInputHandler { * This control function fills the complete screen area with * a test pattern (E) used for adjusting screen alignment. * - * TODO: move DECALN into compat addon + * @vt: #Y ESC DECALN "Screen Alignment Pattern" "ESC # 8" "Fill viewport with a test pattern (E)." */ public screenAlignmentPattern(): void { // prepare cell data diff --git a/src/browser/Linkifier.ts b/src/browser/Linkifier.ts index 30c76e8a..971501b7 100644 --- a/src/browser/Linkifier.ts +++ b/src/browser/Linkifier.ts @@ -298,7 +298,13 @@ export class Linkifier implements ILinkifier { if (matcher.handler) { return matcher.handler(e, uri); } - window.open(uri, '_blank'); + const newWindow = window.open(); + if (newWindow) { + newWindow.opener = null; + newWindow.location.href = uri; + } else { + console.warn('Opening link blocked as opener could not be cleared'); + } }, () => { this._onLinkHover.fire(this._createLinkHoverEvent(x1, y1, x2, y2, fg)); diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 70795e6f..2af7e87e 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -1028,7 +1028,7 @@ declare module 'xterm' { } /** - * (EXPERIMENTAL) Data type to register a CSI, DCS or ESC callback in the parser + * Data type to register a CSI, DCS or ESC callback in the parser * in the form: * ESC I..I F * CSI Prefix P..P I..I F @@ -1072,7 +1072,7 @@ declare module 'xterm' { } /** - * (EXPERIMENTAL) Parser interface. + * Allows hooking into the parser for custom handling of escape sequences. */ export interface IParser { /** @@ -1089,11 +1089,6 @@ declare module 'xterm' { */ registerCsiHandler(id: IFunctionIdentifier, callback: (params: (number | number[])[]) => boolean): IDisposable; - /** - * @deprecated use `registerMarker` instead. - */ - addCsiHandler(id: IFunctionIdentifier, callback: (params: (number | number[])[]) => boolean): IDisposable; - /** * Adds a handler for DCS escape sequences. * @param id Specifies the function identifier under which the callback @@ -1113,11 +1108,6 @@ declare module 'xterm' { */ registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: (number | number[])[]) => boolean): IDisposable; - /** - * @deprecated use `registerMarker` instead. - */ - addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: (number | number[])[]) => boolean): IDisposable; - /** * Adds a handler for ESC escape sequences. * @param id Specifies the function identifier under which the callback @@ -1131,11 +1121,6 @@ declare module 'xterm' { */ registerEscHandler(id: IFunctionIdentifier, handler: () => boolean): IDisposable; - /** - * @deprecated use `registerMarker` instead. - */ - addEscHandler(id: IFunctionIdentifier, handler: () => boolean): IDisposable; - /** * Adds a handler for OSC escape sequences. * @param ident The number (first parameter) of the sequence. @@ -1153,11 +1138,6 @@ declare module 'xterm' { * @return An IDisposable you can call to remove this handler. */ registerOscHandler(ident: number, callback: (data: string) => boolean): IDisposable; - - /** - * @deprecated use `registerMarker` instead. - */ - addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable; } /** diff --git a/yarn.lock b/yarn.lock index e3932408..22e3acc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3421,6 +3421,11 @@ ms@2.1.1, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== +mustache@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mustache/-/mustache-3.0.1.tgz#873855f23aa8a95b150fb96d9836edbc5a1d248a" + integrity sha512-jFI/4UVRsRYdUbuDTKT7KzfOp7FiD5WzYmmwNwXyUVypC0xjoTL78Fqc0jHUPIvvGD+6DQSPHIt1NE7D1ArsqA== + mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"