@xterm/addon-program-status 0.0.0-stage → 0.2.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +19 -0
- package/README.md +90 -2
- package/lib/addon-program-status.js +2 -0
- package/lib/addon-program-status.js.map +1 -0
- package/lib/addon-program-status.mjs +18 -0
- package/lib/addon-program-status.mjs.map +7 -0
- package/package.json +26 -3
- package/src/ProgramStatus.ts +418 -0
- package/src/ProgramStatusAddon.ts +83 -0
- package/typings/addon-program-status.d.ts +123 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2026, The xterm.js authors (https://github.com/xtermjs/xterm.js)
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,91 @@
|
|
|
1
|
-
|
|
1
|
+
## @xterm/addon-program-status
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An xterm.js addon for the program status sequence, OSC 7501. Programs use it to report what they are doing, such as working, blocked on the user, done or failed, so the embedder can show that status outside the terminal, for example as a dot on the terminal's tab.
|
|
4
|
+
See https://www.superlogical.com/rex/docs/build/program-status for the specification.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
### Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install --save @xterm/addon-program-status
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Usage
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { Terminal } from '@xterm/xterm';
|
|
18
|
+
import { ProgramStatusAddon, IProgramStatusRecord } from '@xterm/addon-program-status';
|
|
19
|
+
|
|
20
|
+
const terminal = new Terminal();
|
|
21
|
+
const programStatusAddon = new ProgramStatusAddon();
|
|
22
|
+
terminal.loadAddon(programStatusAddon);
|
|
23
|
+
programStatusAddon.onChange((records: ReadonlyArray<IProgramStatusRecord>) => {
|
|
24
|
+
// records: every record the terminal holds, from the oldest update to the newest
|
|
25
|
+
|
|
26
|
+
// show the status here
|
|
27
|
+
...
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Load the addon only in terminals whose status is shown. The addon answers the feature detection query, and a terminal that answers tells programs that their status is visible.
|
|
32
|
+
|
|
33
|
+
See the full [API](https://github.com/xtermjs/xterm.js/blob/master/addons/addon-program-status/typings/addon-program-status.d.ts) for more advanced usage.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
### Sequence
|
|
37
|
+
|
|
38
|
+
A report has the following format:
|
|
39
|
+
|
|
40
|
+
```plain
|
|
41
|
+
ESC ] 7501 ; key=value:key=value ESC \
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
BEL can end it instead of `ESC \`. The keys are:
|
|
45
|
+
|
|
46
|
+
- `state`: Required. One of `idle`, `working`, `done`, `blocked`, `error` or `clear`.
|
|
47
|
+
- `id`: The record's path, such as `deploy/eu-west`: up to 8 segments of `[A-Za-z0-9_.+-]{1,32}` joined by `/`, at most 128 bytes. A report without an id addresses the root record.
|
|
48
|
+
- `kind`: With `blocked` only. One of `permission`, `question` or `auth`.
|
|
49
|
+
- `progress`: With `working` or `blocked` only. 0 to 100.
|
|
50
|
+
- `app`: The program's name, in the form of one id segment.
|
|
51
|
+
- `title`: A short label, as base64 of UTF-8 text of at most 192 bytes.
|
|
52
|
+
- `msg`: One line, as base64 of UTF-8 text of at most 2048 bytes.
|
|
53
|
+
|
|
54
|
+
Each report replaces its record whole, so a key missing from a report is missing from the record afterwards. A `clear` report removes the record with its id and every record beneath it, or every record if it has no id.
|
|
55
|
+
|
|
56
|
+
The addon skips a pair that it cannot read and ignores keys that it does not know. It discards the whole report if the state is missing or unknown, the id is malformed, a value or the whole sequence is over its limit, or text does not decode to UTF-8 without control characters.
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
### Feature detection
|
|
60
|
+
|
|
61
|
+
A program queries support with:
|
|
62
|
+
|
|
63
|
+
```plain
|
|
64
|
+
ESC ] 7501 ; ? ESC \
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The addon answers with the same sequence. The answer always ends with `ESC \`, whichever terminator the query used, and goes out before the terminal's answer to a query that follows it, such as DA1. It goes out through `onData`, so a terminal with `disableStdin` set sends no answer.
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
### Records
|
|
71
|
+
|
|
72
|
+
The addon keeps up to 256 records. When a report would create one more, it removes the record that was updated least recently. A record's `effectiveApp` is the `app` of the record itself or of its nearest ancestor that has one.
|
|
73
|
+
|
|
74
|
+
Records belong to the terminal, not to a screen: they survive switching to the alternate screen and a soft reset (DECSTR). A full reset (RIS) removes them all.
|
|
75
|
+
|
|
76
|
+
The text in a record is untrusted. The addon refuses control characters, but `title` and `message` can still contain text direction overrides and invisible formatting characters. Remove those before showing the text outside the terminal, and show which terminal a record came from.
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
### Embedder duties
|
|
80
|
+
|
|
81
|
+
The addon sees only what the terminal parses. The embedder tells it about the rest:
|
|
82
|
+
|
|
83
|
+
- Call `clear()` after `terminal.reset()`, which does not remove records.
|
|
84
|
+
- Call `processExited()` when the attached process exits, after its last output is parsed, for example in the callback of `terminal.write('', callback)`. This removes `working` and `blocked` records.
|
|
85
|
+
- Call `promptStarted()` when a new top-level shell prompt starts, for example from shell integration. This also removes `working` and `blocked` records.
|
|
86
|
+
- Call `clear(id)` when the user dismisses a record, such as a `done` or `error` record they have seen.
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
### Headless
|
|
90
|
+
|
|
91
|
+
The addon also loads in `@xterm/headless`. In `@xterm/headless` 6.0.0, the `parser` property that the addon uses requires `allowProposedApi`.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.ProgramStatusAddon=t():e.ProgramStatusAddon=t()}(globalThis,()=>(()=>{"use strict";var e={414(e,t,s){Object.defineProperty(t,"__esModule",{value:!0}),t.EventUtils=t.Emitter=void 0;const r=s(426);var i;t.Emitter=class{constructor(){this._listeners=[],this._disposed=!1}get event(){return this._event||(this._event=(e,t,s)=>{if(this._disposed)return(0,r.toDisposable)(()=>{});const i={fn:e,thisArgs:t};this._listeners=this._listeners.slice(),this._listeners.push(i);const o=(0,r.toDisposable)(()=>{const e=this._listeners.indexOf(i);-1!==e&&(this._listeners=this._listeners.slice(),this._listeners.splice(e,1))});return s&&(Array.isArray(s)?s.push(o):s.add(o)),o}),this._event}fire(e){if(this._disposed||!this._listeners.length)return;if(1===this._listeners.length)return void this._listeners[0].fn.call(this._listeners[0].thisArgs,e);const t=this._listeners;for(let s=0,r=t.length;s<r;++s)t[s].fn.call(t[s].thisArgs,e)}dispose(){this._disposed||(this._disposed=!0,this._listeners.length=0)}},function(e){e.forward=function(e,t){return e(e=>t.fire(e))},e.map=function(e,t){return(s,r,i)=>e(e=>s.call(r,t(e)),void 0,i)},e.any=function(...e){return(t,s,i)=>{const o=new r.DisposableStore;for(const r of e)o.add(r(e=>t.call(s,e)));return i&&(Array.isArray(i)?i.push(o):i.add(o)),o}},e.runAndSubscribe=function(e,t,s){return t(s),e(e=>t(e))}}(i||(t.EventUtils=i={}))},426(e,t){function s(e){return{dispose:e}}function r(e){if(!e)return e;if(Array.isArray(e)){for(const t of e)t.dispose();return[]}return e.dispose(),e}Object.defineProperty(t,"__esModule",{value:!0}),t.MutableDisposable=t.Disposable=t.DisposableStore=void 0,t.toDisposable=s,t.dispose=r,t.combinedDisposable=function(...e){return s(()=>r(e))};class i{constructor(){this._disposables=new Set,this._isDisposed=!1}get isDisposed(){return this._isDisposed}add(e){return this._isDisposed?e.dispose():this._disposables.add(e),e}dispose(){if(!this._isDisposed){this._isDisposed=!0;for(const e of this._disposables)e.dispose();this._disposables.clear()}}clear(){for(const e of this._disposables)e.dispose();this._disposables.clear()}}t.DisposableStore=i;class o{constructor(){this._store=new i}dispose(){this._store.dispose()}_register(e){return this._store.add(e)}}t.Disposable=o,o.None=Object.freeze({dispose(){}}),t.MutableDisposable=class{constructor(){this._isDisposed=!1}get value(){return this._isDisposed?void 0:this._value}set value(e){this._isDisposed||e===this._value||(this._value?.dispose(),this._value=e)}clear(){this.value=void 0}dispose(){this._isDisposed=!0,this._value?.dispose(),this._value=void 0}}},259(e,t){function s(e){if(""===e)return;const t=e.lastIndexOf("/");return-1===t?"":e.slice(0,t)}function r(e){switch(e){case"msg":return 2732;case"title":return 256;case"app":return 32;case"id":return 128}}function i(e){return 32===e||e>=9&&e<=13}function o(e){let t=0,s=e.length;for(;t<s&&i(e.charCodeAt(t));)t++;for(;s>t&&i(e.charCodeAt(s-1));)s--;return e.slice(t,s)}function n(e){return e>=65&&e<=90||e>=97&&e<=122||e>=48&&e<=57}function c(e){if(!e)return!1;for(let t=0;t<e.length;t++){const s=e.charCodeAt(t);if(s<97||s>122)return!1}return!0}function d(e){for(let t=0;t<e.length;t++){const s=e.charCodeAt(t);if(!n(s)&&95!==s&&46!==s&&44!==s&&43!==s&&47!==s&&61!==s&&45!==s)return!1}return!0}function a(e){if(e.length<1||e.length>32)return!1;for(let t=0;t<e.length;t++){const s=e.charCodeAt(t);if(!n(s)&&95!==s&&46!==s&&43!==s&&45!==s)return!1}return!0}function l(e){if(!e||u(e)>128)return!1;const t=e.split("/");return t.length<=8&&t.every(a)}function u(e){let t=0;for(let s=0;s<e.length;s++){const r=e.charCodeAt(s);r<128?t+=1:r<2048?t+=2:r>=55296&&r<=56319&&s+1<e.length&&56320==(64512&e.charCodeAt(s+1))?(t+=4,s++):t+=3}return t}function h(e){return e>=65&&e<=90?e-65:e>=97&&e<=122?e-97+26:e>=48&&e<=57?e-48+52:43===e?62:47===e?63:-1}let f;function p(e,t){let s=e.indexOf("=");-1===s&&(s=e.length);const r=e.length-s,i=s%4;if(1===i||r>2)return;for(let t=s;t<e.length;t++)if(61!==e.charCodeAt(t))return;if(0!==r&&(e.length%4!=0||r!==4-i))return;const o=new Uint8Array(Math.floor(3*s/4));let n,c=0,d=0,a=0;for(let r=0;r<s;r++){const s=h(e.charCodeAt(r));if(-1===s)return;if(d=d<<6|s,a+=6,a>=8){if(a-=8,c===t)return;o[c++]=d>>a&255,d&=(1<<a)-1}}if(0===d){try{f??=new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}),n=f.decode(o.subarray(0,c))}catch{return}for(let e=0;e<n.length;e++){const t=n.charCodeAt(e);if(t<=31||t>=127&&t<=159)return}return n}}Object.defineProperty(t,"__esModule",{value:!0}),t.ProgramStatusStore=void 0,t.parseProgramStatusReport=function(e){if(e.length>4087||u(e)>4087)return;const t={};for(const s of e.split(":")){const e=s.indexOf("=");if(-1===e)continue;const i=o(s.slice(0,e)),n=o(s.slice(e+1));if(u(i)>16)return;if(!c(i))continue;const a=r(i);if(void 0!==a&&u(n)>a)return;if("id"===i&&!l(n))return;if(d(n))switch(i){case"msg":case"title":{const e=p(n,"msg"===i?2048:192);if(void 0===e)return;t[i]=e;break}case"app":case"id":case"kind":case"progress":case"state":t[i]=n}}const s=t.id??"";if("clear"===t.state)return{clear:!0,id:s};const i=t.state;if("idle"!==(n=i)&&"working"!==n&&"done"!==n&&"blocked"!==n&&"error"!==n)return;var n;const h={id:s,state:i};if("blocked"===i&&function(e){return"permission"===e||"question"===e||"auth"===e}(t.kind)&&(h.kind=t.kind),"working"===i||"blocked"===i){const e=function(e){if(!e)return;let t=0;for(let s=0;s<e.length;s++){const r=e.charCodeAt(s);if(r<48||r>57)return;if(t=10*t+r-48,t>100)return}return t}(t.progress);void 0!==e&&(h.progress=e)}return void 0!==t.app&&a(t.app)&&(h.app=t.app),void 0!==t.title&&(h.title=t.title),void 0!==t.msg&&(h.message=t.msg),{clear:!1,record:Object.freeze(h)}},t.ProgramStatusStore=class{constructor(){this._records=new Map}get records(){return this._snapshot??=Object.freeze(Array.from(this._records.values(),e=>{const t=this._getEffectiveApp(e.id);return void 0===t?e:Object.freeze({...e,effectiveApp:t})})),this._snapshot}replace(e){if(!this._records.delete(e.id)&&this._records.size>=256){const e=this._records.keys().next();e.done||this._records.delete(e.value)}this._records.set(e.id,e),this._snapshot=void 0}clear(e){const t=e+"/";return this._remove(s=>""===e||s.id===e||s.id.startsWith(t))}removeActiveRecords(){return this._remove(e=>"working"===e.state||"blocked"===e.state)}_remove(e){let t=!1;for(const[s,r]of this._records)e(r)&&(this._records.delete(s),t=!0);return t&&(this._snapshot=void 0),t}_getEffectiveApp(e){for(let t=e;void 0!==t;t=s(t)){const e=this._records.get(t)?.app;if(void 0!==e)return e}}}}},t={};function s(r){var i=t[r];if(void 0!==i)return i.exports;var o=t[r]={exports:{}};return e[r](o,o.exports,s),o.exports}var r={};return(()=>{var e=r;Object.defineProperty(e,"__esModule",{value:!0}),e.ProgramStatusAddon=void 0;const t=s(414),i=s(426),o=s(259);class n extends i.Disposable{constructor(){super(...arguments),this._recordStore=new o.ProgramStatusStore,this._onChange=this._register(new t.Emitter),this.onChange=this._onChange.event}get records(){return this._recordStore.records}activate(e){this._register(e.parser.registerOscHandler(7501,t=>{if("?"===t)return e.input("]7501;?\\",!1),!0;const s=(0,o.parseProgramStatusReport)(t);return s?.clear?this.clear(s.id):s&&(this._recordStore.replace(s.record),this._fireChange()),!0})),this._register(e.parser.registerEscHandler({final:"c"},()=>(this.clear(),!1)))}dispose(){this._recordStore.clear(""),super.dispose()}clear(e=""){this._recordStore.clear(e)&&this._fireChange()}processExited(){this._recordStore.removeActiveRecords()&&this._fireChange()}promptStarted(){this._recordStore.removeActiveRecords()&&this._fireChange()}_fireChange(){this._onChange.fire(this._recordStore.records)}}e.ProgramStatusAddon=n})(),r})());
|
|
2
|
+
//# sourceMappingURL=addon-program-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addon-program-status.js","mappings":"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","sources":["webpack://ProgramStatusAddon/webpack/universalModuleDefinition","webpack://ProgramStatusAddon/../src/common/Event.ts","webpack://ProgramStatusAddon/../src/common/Lifecycle.ts","webpack://ProgramStatusAddon/./src/ProgramStatus.ts","webpack://ProgramStatusAddon/webpack/bootstrap","webpack://ProgramStatusAddon/./src/ProgramStatusAddon.ts"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ProgramStatusAddon\"] = factory();\n\telse\n\t\troot[\"ProgramStatusAddon\"] = factory();\n})(globalThis, () => {\nreturn ","/**\n * Copyright (c) 2024-2026 The xterm.js authors. All rights reserved.\n * @license MIT\n *\n * Minimal event utilities for xterm.js core.\n * Simplified from VS Code's event.ts - no leak detection/profiling.\n */\n\nimport { IDisposable, DisposableStore, toDisposable } from './Lifecycle';\n\nexport interface IEvent<T> {\n (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable;\n}\n\nexport class Emitter<T> {\n private _listeners: { fn: (e: T) => any, thisArgs: any }[] = [];\n private _disposed = false;\n private _event: IEvent<T> | undefined;\n\n public get event(): IEvent<T> {\n if (this._event) {\n return this._event;\n }\n this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {\n if (this._disposed) {\n return toDisposable(() => {});\n }\n\n const entry = { fn: listener, thisArgs };\n this._listeners = this._listeners.slice();\n this._listeners.push(entry);\n\n const result = toDisposable(() => {\n const idx = this._listeners.indexOf(entry);\n if (idx !== -1) {\n this._listeners = this._listeners.slice();\n this._listeners.splice(idx, 1);\n }\n });\n\n if (disposables) {\n if (Array.isArray(disposables)) {\n disposables.push(result);\n } else {\n disposables.add(result);\n }\n }\n\n return result;\n };\n return this._event;\n }\n\n public fire(event: T): void {\n if (this._disposed || !this._listeners.length) {\n return;\n }\n if (this._listeners.length === 1) {\n this._listeners[0].fn.call(this._listeners[0].thisArgs, event);\n return;\n }\n const listeners = this._listeners;\n for (let i = 0, len = listeners.length; i < len; ++i) {\n listeners[i].fn.call(listeners[i].thisArgs, event);\n }\n }\n\n public dispose(): void {\n if (this._disposed) {\n return;\n }\n this._disposed = true;\n this._listeners.length = 0;\n }\n}\n\nexport namespace EventUtils {\n export function forward<T>(from: IEvent<T>, to: Emitter<T>): IDisposable {\n return from(e => to.fire(e));\n }\n\n export function map<I, O>(event: IEvent<I>, map: (i: I) => O): IEvent<O> {\n return (listener: (e: O) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {\n return event(i => listener.call(thisArgs, map(i)), undefined, disposables);\n };\n }\n\n export function any<T>(...events: IEvent<T>[]): IEvent<T>;\n export function any(...events: IEvent<any>[]): IEvent<void>;\n export function any<T>(...events: IEvent<T>[]): IEvent<T> {\n return (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {\n const store = new DisposableStore();\n for (const event of events) {\n store.add(event(e => listener.call(thisArgs, e)));\n }\n if (disposables) {\n if (Array.isArray(disposables)) {\n disposables.push(store);\n } else {\n disposables.add(store);\n }\n }\n return store;\n };\n }\n\n export function runAndSubscribe<T>(event: IEvent<T>, handler: (e: T) => void, initial: T): IDisposable;\n export function runAndSubscribe<T>(event: IEvent<T>, handler: (e: T | undefined) => void): IDisposable;\n export function runAndSubscribe<T>(event: IEvent<T>, handler: (e: T | undefined) => void, initial?: T): IDisposable {\n handler(initial);\n return event(e => handler(e));\n }\n}\n","/**\n * Copyright (c) 2024-2026 The xterm.js authors. All rights reserved.\n * @license MIT\n *\n * Minimal lifecycle utilities for xterm.js core.\n * Simplified from VS Code's lifecycle.ts - no tracking/leak detection.\n */\n\nexport interface IDisposable {\n dispose(): void;\n}\n\nexport function toDisposable(fn: () => void): IDisposable {\n return { dispose: fn };\n}\n\nexport function dispose<T extends IDisposable>(disposable: T): T;\nexport function dispose<T extends IDisposable>(disposable: T | undefined): T | undefined;\nexport function dispose<T extends IDisposable>(disposables: T[]): T[];\nexport function dispose<T extends IDisposable>(arg: T | T[] | undefined): T | T[] | undefined {\n if (!arg) {\n return arg;\n }\n if (Array.isArray(arg)) {\n for (const d of arg) {\n d.dispose();\n }\n return [];\n }\n arg.dispose();\n return arg;\n}\n\nexport function combinedDisposable(...disposables: IDisposable[]): IDisposable {\n return toDisposable(() => dispose(disposables));\n}\n\nexport class DisposableStore implements IDisposable {\n private readonly _disposables = new Set<IDisposable>();\n private _isDisposed = false;\n\n public get isDisposed(): boolean {\n return this._isDisposed;\n }\n\n public add<T extends IDisposable>(o: T): T {\n if (this._isDisposed) {\n o.dispose();\n } else {\n this._disposables.add(o);\n }\n return o;\n }\n\n public dispose(): void {\n if (this._isDisposed) {\n return;\n }\n this._isDisposed = true;\n for (const d of this._disposables) {\n d.dispose();\n }\n this._disposables.clear();\n }\n\n public clear(): void {\n for (const d of this._disposables) {\n d.dispose();\n }\n this._disposables.clear();\n }\n}\n\nexport abstract class Disposable implements IDisposable {\n public static readonly None: IDisposable = Object.freeze({ dispose() { } });\n\n protected readonly _store = new DisposableStore();\n\n public dispose(): void {\n this._store.dispose();\n }\n\n protected _register<T extends IDisposable>(o: T): T {\n return this._store.add(o);\n }\n}\n\nexport class MutableDisposable<T extends IDisposable> implements IDisposable {\n private _value: T | undefined;\n private _isDisposed = false;\n\n public get value(): T | undefined {\n return this._isDisposed ? undefined : this._value;\n }\n\n public set value(value: T | undefined) {\n if (this._isDisposed || value === this._value) {\n return;\n }\n this._value?.dispose();\n this._value = value;\n }\n\n public clear(): void {\n this.value = undefined;\n }\n\n public dispose(): void {\n this._isDisposed = true;\n this._value?.dispose();\n this._value = undefined;\n }\n}\n","/**\n * Copyright (c) 2026 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport type { IProgramStatusRecord } from '@xterm/addon-program-status';\n\ntype ProgramStatusState = IProgramStatusRecord['state'];\ntype ProgramStatusKind = NonNullable<IProgramStatusRecord['kind']>;\ntype Mutable<T> = { -readonly [P in keyof T]: T[P] };\n\n/**\n * Byte limits are counted in UTF-8.\n */\nconst enum Limits {\n /**\n * The whole sequence may take 4096 bytes, of which `ESC ] 7501 ;` and `ESC \\` take 9.\n */\n PAYLOAD = 4087,\n KEY = 16,\n MSG_ENCODED = 2732,\n MSG_DECODED = 2048,\n TITLE_ENCODED = 256,\n TITLE_DECODED = 192,\n APP = 32,\n ID = 128,\n ID_LEVELS = 8,\n SEGMENT = 32,\n RECORDS = 256,\n PROGRESS = 100\n}\n\nexport type ProgramStatusReport =\n { readonly clear: true, readonly id: string } |\n { readonly clear: false, readonly record: IProgramStatusRecord };\n\ninterface IFields {\n app?: string;\n id?: string;\n kind?: string;\n msg?: string;\n progress?: string;\n state?: string;\n title?: string;\n}\n\n/**\n * Parses the payload of an OSC 7501 report. Returns undefined when the report\n * must be discarded whole.\n */\nexport function parseProgramStatusReport(data: string): ProgramStatusReport | undefined {\n // UTF-8 never takes fewer bytes than UTF-16 takes code units.\n if (data.length > Limits.PAYLOAD || utf8Length(data) > Limits.PAYLOAD) {\n return undefined;\n }\n const fields: IFields = {};\n for (const pair of data.split(':')) {\n const equal = pair.indexOf('=');\n if (equal === -1) {\n continue;\n }\n const key = trim(pair.slice(0, equal));\n const value = trim(pair.slice(equal + 1));\n if (utf8Length(key) > Limits.KEY) {\n return undefined;\n }\n if (!isKey(key)) {\n continue;\n }\n const encodedLimit = getEncodedLimit(key);\n if (encodedLimit !== undefined && utf8Length(value) > encodedLimit) {\n return undefined;\n }\n // A malformed id must never select the root record.\n if (key === 'id' && !isId(value)) {\n return undefined;\n }\n if (!isValue(value)) {\n continue;\n }\n switch (key) {\n case 'msg':\n case 'title': {\n const text = decodeText(value, key === 'msg' ? Limits.MSG_DECODED : Limits.TITLE_DECODED);\n if (text === undefined) {\n return undefined;\n }\n fields[key] = text;\n break;\n }\n case 'app':\n case 'id':\n case 'kind':\n case 'progress':\n case 'state':\n fields[key] = value;\n break;\n }\n }\n\n const id = fields.id ?? '';\n if (fields.state === 'clear') {\n return { clear: true, id };\n }\n const state = fields.state;\n if (!isState(state)) {\n return undefined;\n }\n const record: Mutable<IProgramStatusRecord> = { id, state };\n if (state === 'blocked' && isKind(fields.kind)) {\n record.kind = fields.kind;\n }\n if (state === 'working' || state === 'blocked') {\n const progress = parseProgress(fields.progress);\n if (progress !== undefined) {\n record.progress = progress;\n }\n }\n if (fields.app !== undefined && isSegment(fields.app)) {\n record.app = fields.app;\n }\n if (fields.title !== undefined) {\n record.title = fields.title;\n }\n if (fields.msg !== undefined) {\n record.message = fields.msg;\n }\n return { clear: false, record: Object.freeze(record) };\n}\n\n/**\n * The records of one terminal, keyed by id.\n */\nexport class ProgramStatusStore {\n // A Map iterates in insertion order, so the first key was updated least recently.\n private readonly _records = new Map<string, IProgramStatusRecord>();\n private _snapshot: ReadonlyArray<IProgramStatusRecord> | undefined;\n\n /**\n * The records from the oldest update to the newest, with `effectiveApp` filled in.\n */\n public get records(): ReadonlyArray<IProgramStatusRecord> {\n this._snapshot ??= Object.freeze(Array.from(this._records.values(), record => {\n const effectiveApp = this._getEffectiveApp(record.id);\n return effectiveApp === undefined ? record : Object.freeze({ ...record, effectiveApp });\n }));\n return this._snapshot;\n }\n\n public replace(record: IProgramStatusRecord): void {\n if (!this._records.delete(record.id) && this._records.size >= Limits.RECORDS) {\n const oldest = this._records.keys().next();\n if (!oldest.done) {\n this._records.delete(oldest.value);\n }\n }\n this._records.set(record.id, record);\n this._snapshot = undefined;\n }\n\n /**\n * Removes a record and its descendants. The empty id removes every record.\n * @returns Whether any record was removed.\n */\n public clear(id: string): boolean {\n const prefix = id + '/';\n return this._remove(record => id === '' || record.id === id || record.id.startsWith(prefix));\n }\n\n /**\n * Removes `working` and `blocked` records.\n * @returns Whether any record was removed.\n */\n public removeActiveRecords(): boolean {\n return this._remove(record => record.state === 'working' || record.state === 'blocked');\n }\n\n private _remove(predicate: (record: IProgramStatusRecord) => boolean): boolean {\n let removed = false;\n for (const [id, record] of this._records) {\n if (predicate(record)) {\n this._records.delete(id);\n removed = true;\n }\n }\n if (removed) {\n this._snapshot = undefined;\n }\n return removed;\n }\n\n private _getEffectiveApp(id: string): string | undefined {\n for (let ancestor: string | undefined = id; ancestor !== undefined; ancestor = getParentId(ancestor)) {\n const app = this._records.get(ancestor)?.app;\n if (app !== undefined) {\n return app;\n }\n }\n return undefined;\n }\n}\n\nfunction getParentId(id: string): string | undefined {\n if (id === '') {\n return undefined;\n }\n const slash = id.lastIndexOf('/');\n return slash === -1 ? '' : id.slice(0, slash);\n}\n\nfunction getEncodedLimit(key: string): number | undefined {\n switch (key) {\n case 'msg': return Limits.MSG_ENCODED;\n case 'title': return Limits.TITLE_ENCODED;\n case 'app': return Limits.APP;\n case 'id': return Limits.ID;\n }\n return undefined;\n}\n\nfunction isState(value: string | undefined): value is ProgramStatusState {\n return value === 'idle' || value === 'working' || value === 'done' || value === 'blocked' || value === 'error';\n}\n\nfunction isKind(value: string | undefined): value is ProgramStatusKind {\n return value === 'permission' || value === 'question' || value === 'auth';\n}\n\n/**\n * Digits only, leading zeros allowed. Anything else, or a number past 100, is treated as absent.\n */\nfunction parseProgress(value: string | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n let progress = 0;\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (code < 0x30 || code > 0x39) {\n return undefined;\n }\n progress = progress * 10 + code - 0x30;\n if (progress > Limits.PROGRESS) {\n return undefined;\n }\n }\n return progress;\n}\n\nfunction isWhitespace(code: number): boolean {\n return code === 0x20 || (code >= 0x09 && code <= 0x0D);\n}\n\nfunction trim(value: string): string {\n let start = 0;\n let end = value.length;\n while (start < end && isWhitespace(value.charCodeAt(start))) {\n start++;\n }\n while (end > start && isWhitespace(value.charCodeAt(end - 1))) {\n end--;\n }\n return value.slice(start, end);\n}\n\nfunction isAlphanumeric(code: number): boolean {\n return (code >= 0x41 && code <= 0x5A) || (code >= 0x61 && code <= 0x7A) || (code >= 0x30 && code <= 0x39);\n}\n\n/**\n * `[a-z]+`\n */\nfunction isKey(key: string): boolean {\n if (!key) {\n return false;\n }\n for (let i = 0; i < key.length; i++) {\n const code = key.charCodeAt(i);\n if (code < 0x61 || code > 0x7A) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * `[A-Za-z0-9_.,+/=-]*`\n */\nfunction isValue(value: string): boolean {\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n // _ . , + / = -\n if (!isAlphanumeric(code) && code !== 0x5F && code !== 0x2E && code !== 0x2C && code !== 0x2B && code !== 0x2F && code !== 0x3D && code !== 0x2D) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * `[A-Za-z0-9_.+-]{1,32}`\n */\nfunction isSegment(segment: string): boolean {\n if (segment.length < 1 || segment.length > Limits.SEGMENT) {\n return false;\n }\n for (let i = 0; i < segment.length; i++) {\n const code = segment.charCodeAt(i);\n // _ . + -\n if (!isAlphanumeric(code) && code !== 0x5F && code !== 0x2E && code !== 0x2B && code !== 0x2D) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Segments joined by `/`, at most 8 levels and 128 bytes.\n */\nfunction isId(id: string): boolean {\n if (!id || utf8Length(id) > Limits.ID) {\n return false;\n }\n const segments = id.split('/');\n return segments.length <= Limits.ID_LEVELS && segments.every(isSegment);\n}\n\nfunction utf8Length(value: string): number {\n let length = 0;\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (code < 0x80) {\n length += 1;\n } else if (code < 0x800) {\n length += 2;\n } else if (code >= 0xD800 && code <= 0xDBFF && i + 1 < value.length && (value.charCodeAt(i + 1) & 0xFC00) === 0xDC00) {\n length += 4;\n i++;\n } else {\n length += 3;\n }\n }\n return length;\n}\n\nfunction getBase64Value(code: number): number {\n if (code >= 0x41 && code <= 0x5A) return code - 0x41;\n if (code >= 0x61 && code <= 0x7A) return code - 0x61 + 26;\n if (code >= 0x30 && code <= 0x39) return code - 0x30 + 52;\n if (code === 0x2B) return 62;\n if (code === 0x2F) return 63;\n return -1;\n}\n\nlet utf8Decoder: TextDecoder | undefined;\n\n/**\n * Decodes standard base64 with optional padding into UTF-8 text without control characters.\n */\nfunction decodeText(value: string, limit: number): string | undefined {\n let contentLength = value.indexOf('=');\n if (contentLength === -1) {\n contentLength = value.length;\n }\n const padding = value.length - contentLength;\n const remainder = contentLength % 4;\n if (remainder === 1 || padding > 2) {\n return undefined;\n }\n for (let i = contentLength; i < value.length; i++) {\n if (value.charCodeAt(i) !== 0x3D) {\n return undefined;\n }\n }\n if (padding !== 0 && (value.length % 4 !== 0 || padding !== 4 - remainder)) {\n return undefined;\n }\n\n const bytes = new Uint8Array(Math.floor(contentLength * 3 / 4));\n let length = 0;\n let bits = 0;\n let bitCount = 0;\n for (let i = 0; i < contentLength; i++) {\n const sextet = getBase64Value(value.charCodeAt(i));\n if (sextet === -1) {\n return undefined;\n }\n bits = (bits << 6) | sextet;\n bitCount += 6;\n if (bitCount >= 8) {\n bitCount -= 8;\n if (length === limit) {\n return undefined;\n }\n bytes[length++] = (bits >> bitCount) & 0xFF;\n bits &= (1 << bitCount) - 1;\n }\n }\n if (bits !== 0) {\n return undefined;\n }\n\n let text: string;\n try {\n utf8Decoder ??= new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });\n text = utf8Decoder.decode(bytes.subarray(0, length));\n } catch {\n return undefined;\n }\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n // C0, DEL and C1\n if (code <= 0x1F || (code >= 0x7F && code <= 0x9F)) {\n return undefined;\n }\n }\n return text;\n}\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","/**\n * Copyright (c) 2026 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport type { Terminal, ITerminalAddon } from '@xterm/xterm';\nimport type { ProgramStatusAddon as IProgramStatusApi, IProgramStatusRecord } from '@xterm/addon-program-status';\nimport { Emitter } from 'common/Event';\nimport { Disposable } from 'common/Lifecycle';\nimport { parseProgramStatusReport, ProgramStatusStore } from './ProgramStatus';\n\nconst enum Constants {\n OSC_IDENT = 7501,\n // Handlers do not learn whether BEL or ST ended the query, so the reply always ends with ST.\n REPLY = '\\x1b]7501;?\\x1b\\\\'\n}\n\n/**\n * @vt: #E[Supported via @xterm/addon-program-status.] OSC 7501 \"Program Status\" \"OSC 7501 ; Pt BEL\" \"Report what a program is doing, or query support with `?`.\"\n *\n * See [addon readme](https://github.com/xtermjs/xterm.js/tree/master/addons/addon-program-status) for more details.\n */\nexport class ProgramStatusAddon extends Disposable implements ITerminalAddon, IProgramStatusApi {\n private readonly _recordStore = new ProgramStatusStore();\n\n private readonly _onChange = this._register(new Emitter<ReadonlyArray<IProgramStatusRecord>>());\n public readonly onChange = this._onChange.event;\n\n public get records(): ReadonlyArray<IProgramStatusRecord> {\n return this._recordStore.records;\n }\n\n public activate(terminal: Terminal): void {\n this._register(terminal.parser.registerOscHandler(Constants.OSC_IDENT, data => {\n if (data === '?') {\n // Reply before the parser moves on, so the reply precedes core's reply to a following\n // query such as DA1.\n terminal.input(Constants.REPLY, false);\n return true;\n }\n const report = parseProgramStatusReport(data);\n if (report?.clear) {\n this.clear(report.id);\n } else if (report) {\n this._recordStore.replace(report.record);\n this._fireChange();\n }\n return true;\n }));\n // RIS removes every record. Returning false lets core run its full reset.\n this._register(terminal.parser.registerEscHandler({ final: 'c' }, () => {\n this.clear();\n return false;\n }));\n }\n\n public dispose(): void {\n this._recordStore.clear('');\n super.dispose();\n }\n\n public clear(id: string = ''): void {\n if (this._recordStore.clear(id)) {\n this._fireChange();\n }\n }\n\n public processExited(): void {\n if (this._recordStore.removeActiveRecords()) {\n this._fireChange();\n }\n }\n\n public promptStarted(): void {\n if (this._recordStore.removeActiveRecords()) {\n this._fireChange();\n }\n }\n\n private _fireChange(): void {\n this._onChange.fire(this._recordStore.records);\n }\n}\n"],"names":["root","factory","exports","module","define","amd","globalThis","Lifecycle_1","__webpack_require__","EventUtils","constructor","this","_listeners","_disposed","event","_event","listener","thisArgs","disposables","toDisposable","entry","fn","slice","push","result","idx","indexOf","splice","Array","isArray","add","fire","length","call","listeners","i","len","dispose","forward","from","to","e","map","undefined","any","events","store","DisposableStore","runAndSubscribe","handler","initial","arg","d","_disposables","Set","_isDisposed","isDisposed","o","clear","Disposable","_store","_register","None","Object","freeze","value","_value","getParentId","id","slash","lastIndexOf","getEncodedLimit","key","isWhitespace","code","trim","start","end","charCodeAt","isAlphanumeric","isKey","isValue","isSegment","segment","isId","utf8Length","segments","split","every","getBase64Value","utf8Decoder","decodeText","limit","contentLength","padding","remainder","bytes","Uint8Array","Math","floor","text","bits","bitCount","sextet","TextDecoder","fatal","ignoreBOM","decode","subarray","data","fields","pair","equal","encodedLimit","state","record","isKind","kind","progress","parseProgress","app","title","msg","message","_records","Map","records","_snapshot","values","effectiveApp","_getEffectiveApp","replace","delete","size","oldest","keys","next","done","set","prefix","_remove","startsWith","removeActiveRecords","predicate","removed","ancestor","get","__webpack_module_cache__","moduleId","cachedModule","__webpack_modules__","Event_1","ProgramStatus_1","ProgramStatusAddon","_recordStore","ProgramStatusStore","_onChange","Emitter","onChange","activate","terminal","parser","registerOscHandler","input","report","parseProgramStatusReport","_fireChange","registerEscHandler","final","super","processExited","promptStarted"],"sourceRoot":""}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2014-2024 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
6
|
+
* @license MIT
|
|
7
|
+
*
|
|
8
|
+
* Originally forked from (with the author's permission):
|
|
9
|
+
* Fabrice Bellard's javascript vt100 for jslinux:
|
|
10
|
+
* http://bellard.org/jslinux/
|
|
11
|
+
* Copyright (c) 2011 Fabrice Bellard
|
|
12
|
+
*/
|
|
13
|
+
/*---------------------------------------------------------------------------------------------
|
|
14
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
15
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
16
|
+
*--------------------------------------------------------------------------------------------*/
|
|
17
|
+
function _(e){return{dispose:e}}var p=class{constructor(){this._disposables=new Set;this._isDisposed=!1}get isDisposed(){return this._isDisposed}add(t){return this._isDisposed?t.dispose():this._disposables.add(t),t}dispose(){if(!this._isDisposed){this._isDisposed=!0;for(let t of this._disposables)t.dispose();this._disposables.clear()}}clear(){for(let t of this._disposables)t.dispose();this._disposables.clear()}},c=class{constructor(){this._store=new p}dispose(){this._store.dispose()}_register(t){return this._store.add(t)}};c.None=Object.freeze({dispose(){}});var h=class{constructor(){this._listeners=[];this._disposed=!1}get event(){return this._event?this._event:(this._event=(t,r,n)=>{if(this._disposed)return _(()=>{});let s={fn:t,thisArgs:r};this._listeners=this._listeners.slice(),this._listeners.push(s);let o=_(()=>{let a=this._listeners.indexOf(s);a!==-1&&(this._listeners=this._listeners.slice(),this._listeners.splice(a,1))});return n&&(Array.isArray(n)?n.push(o):n.add(o)),o},this._event)}fire(t){if(this._disposed||!this._listeners.length)return;if(this._listeners.length===1){this._listeners[0].fn.call(this._listeners[0].thisArgs,t);return}let r=this._listeners;for(let n=0,s=r.length;n<s;++n)r[n].fn.call(r[n].thisArgs,t)}dispose(){this._disposed||(this._disposed=!0,this._listeners.length=0)}},S;(s=>{function e(o,a){return o(i=>a.fire(i))}s.forward=e;function t(o,a){return(i,d,l)=>o(u=>i.call(d,a(u)),void 0,l)}s.map=t;function r(...o){return(a,i,d)=>{let l=new p;for(let u of o)l.add(u(f=>a.call(i,f)));return d&&(Array.isArray(d)?d.push(l):d.add(l)),l}}s.any=r;function n(o,a,i){return a(i),o(d=>a(d))}s.runAndSubscribe=n})(S||={});function I(e){if(e.length>4087||g(e)>4087)return;let t={};for(let o of e.split(":")){let a=o.indexOf("=");if(a===-1)continue;let i=D(o.slice(0,a)),d=D(o.slice(a+1));if(g(i)>16)return;if(!O(i))continue;let l=A(i);if(l!==void 0&&g(d)>l||i==="id"&&!w(d))return;if(k(d))switch(i){case"msg":case"title":{let u=N(d,i==="msg"?2048:192);if(u===void 0)return;t[i]=u;break}case"app":case"id":case"kind":case"progress":case"state":t[i]=d;break}}let r=t.id??"";if(t.state==="clear")return{clear:!0,id:r};let n=t.state;if(!P(n))return;let s={id:r,state:n};if(n==="blocked"&&C(t.kind)&&(s.kind=t.kind),n==="working"||n==="blocked"){let o=R(t.progress);o!==void 0&&(s.progress=o)}return t.app!==void 0&&v(t.app)&&(s.app=t.app),t.title!==void 0&&(s.title=t.title),t.msg!==void 0&&(s.message=t.msg),{clear:!1,record:Object.freeze(s)}}var b=class{constructor(){this._records=new Map}get records(){return this._snapshot??=Object.freeze(Array.from(this._records.values(),t=>{let r=this._getEffectiveApp(t.id);return r===void 0?t:Object.freeze({...t,effectiveApp:r})})),this._snapshot}replace(t){if(!this._records.delete(t.id)&&this._records.size>=256){let r=this._records.keys().next();r.done||this._records.delete(r.value)}this._records.set(t.id,t),this._snapshot=void 0}clear(t){let r=t+"/";return this._remove(n=>t===""||n.id===t||n.id.startsWith(r))}removeActiveRecords(){return this._remove(t=>t.state==="working"||t.state==="blocked")}_remove(t){let r=!1;for(let[n,s]of this._records)t(s)&&(this._records.delete(n),r=!0);return r&&(this._snapshot=void 0),r}_getEffectiveApp(t){for(let r=t;r!==void 0;r=y(r)){let n=this._records.get(r)?.app;if(n!==void 0)return n}}};function y(e){if(e==="")return;let t=e.lastIndexOf("/");return t===-1?"":e.slice(0,t)}function A(e){switch(e){case"msg":return 2732;case"title":return 256;case"app":return 32;case"id":return 128}}function P(e){return e==="idle"||e==="working"||e==="done"||e==="blocked"||e==="error"}function C(e){return e==="permission"||e==="question"||e==="auth"}function R(e){if(!e)return;let t=0;for(let r=0;r<e.length;r++){let n=e.charCodeAt(r);if(n<48||n>57||(t=t*10+n-48,t>100))return}return t}function x(e){return e===32||e>=9&&e<=13}function D(e){let t=0,r=e.length;for(;t<r&&x(e.charCodeAt(t));)t++;for(;r>t&&x(e.charCodeAt(r-1));)r--;return e.slice(t,r)}function T(e){return e>=65&&e<=90||e>=97&&e<=122||e>=48&&e<=57}function O(e){if(!e)return!1;for(let t=0;t<e.length;t++){let r=e.charCodeAt(t);if(r<97||r>122)return!1}return!0}function k(e){for(let t=0;t<e.length;t++){let r=e.charCodeAt(t);if(!T(r)&&r!==95&&r!==46&&r!==44&&r!==43&&r!==47&&r!==61&&r!==45)return!1}return!0}function v(e){if(e.length<1||e.length>32)return!1;for(let t=0;t<e.length;t++){let r=e.charCodeAt(t);if(!T(r)&&r!==95&&r!==46&&r!==43&&r!==45)return!1}return!0}function w(e){if(!e||g(e)>128)return!1;let t=e.split("/");return t.length<=8&&t.every(v)}function g(e){let t=0;for(let r=0;r<e.length;r++){let n=e.charCodeAt(r);n<128?t+=1:n<2048?t+=2:n>=55296&&n<=56319&&r+1<e.length&&(e.charCodeAt(r+1)&64512)===56320?(t+=4,r++):t+=3}return t}function F(e){return e>=65&&e<=90?e-65:e>=97&&e<=122?e-97+26:e>=48&&e<=57?e-48+52:e===43?62:e===47?63:-1}var m;function N(e,t){let r=e.indexOf("=");r===-1&&(r=e.length);let n=e.length-r,s=r%4;if(s===1||n>2)return;for(let u=r;u<e.length;u++)if(e.charCodeAt(u)!==61)return;if(n!==0&&(e.length%4!==0||n!==4-s))return;let o=new Uint8Array(Math.floor(r*3/4)),a=0,i=0,d=0;for(let u=0;u<r;u++){let f=F(e.charCodeAt(u));if(f===-1)return;if(i=i<<6|f,d+=6,d>=8){if(d-=8,a===t)return;o[a++]=i>>d&255,i&=(1<<d)-1}}if(i!==0)return;let l;try{m??=new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}),l=m.decode(o.subarray(0,a))}catch{return}for(let u=0;u<l.length;u++){let f=l.charCodeAt(u);if(f<=31||f>=127&&f<=159)return}return l}var E=class extends c{constructor(){super(...arguments);this._recordStore=new b;this._onChange=this._register(new h);this.onChange=this._onChange.event}get records(){return this._recordStore.records}activate(r){this._register(r.parser.registerOscHandler(7501,n=>{if(n==="?")return r.input("\x1B]7501;?\x1B\\",!1),!0;let s=I(n);return s?.clear?this.clear(s.id):s&&(this._recordStore.replace(s.record),this._fireChange()),!0})),this._register(r.parser.registerEscHandler({final:"c"},()=>(this.clear(),!1)))}dispose(){this._recordStore.clear(""),super.dispose()}clear(r=""){this._recordStore.clear(r)&&this._fireChange()}processExited(){this._recordStore.removeActiveRecords()&&this._fireChange()}promptStarted(){this._recordStore.removeActiveRecords()&&this._fireChange()}_fireChange(){this._onChange.fire(this._recordStore.records)}};export{E as ProgramStatusAddon};
|
|
18
|
+
//# sourceMappingURL=addon-program-status.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/common/Lifecycle.ts", "../../../src/common/Event.ts", "../src/ProgramStatus.ts", "../src/ProgramStatusAddon.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) 2024-2026 The xterm.js authors. All rights reserved.\n * @license MIT\n *\n * Minimal lifecycle utilities for xterm.js core.\n * Simplified from VS Code's lifecycle.ts - no tracking/leak detection.\n */\n\nexport interface IDisposable {\n dispose(): void;\n}\n\nexport function toDisposable(fn: () => void): IDisposable {\n return { dispose: fn };\n}\n\nexport function dispose<T extends IDisposable>(disposable: T): T;\nexport function dispose<T extends IDisposable>(disposable: T | undefined): T | undefined;\nexport function dispose<T extends IDisposable>(disposables: T[]): T[];\nexport function dispose<T extends IDisposable>(arg: T | T[] | undefined): T | T[] | undefined {\n if (!arg) {\n return arg;\n }\n if (Array.isArray(arg)) {\n for (const d of arg) {\n d.dispose();\n }\n return [];\n }\n arg.dispose();\n return arg;\n}\n\nexport function combinedDisposable(...disposables: IDisposable[]): IDisposable {\n return toDisposable(() => dispose(disposables));\n}\n\nexport class DisposableStore implements IDisposable {\n private readonly _disposables = new Set<IDisposable>();\n private _isDisposed = false;\n\n public get isDisposed(): boolean {\n return this._isDisposed;\n }\n\n public add<T extends IDisposable>(o: T): T {\n if (this._isDisposed) {\n o.dispose();\n } else {\n this._disposables.add(o);\n }\n return o;\n }\n\n public dispose(): void {\n if (this._isDisposed) {\n return;\n }\n this._isDisposed = true;\n for (const d of this._disposables) {\n d.dispose();\n }\n this._disposables.clear();\n }\n\n public clear(): void {\n for (const d of this._disposables) {\n d.dispose();\n }\n this._disposables.clear();\n }\n}\n\nexport abstract class Disposable implements IDisposable {\n public static readonly None: IDisposable = Object.freeze({ dispose() { } });\n\n protected readonly _store = new DisposableStore();\n\n public dispose(): void {\n this._store.dispose();\n }\n\n protected _register<T extends IDisposable>(o: T): T {\n return this._store.add(o);\n }\n}\n\nexport class MutableDisposable<T extends IDisposable> implements IDisposable {\n private _value: T | undefined;\n private _isDisposed = false;\n\n public get value(): T | undefined {\n return this._isDisposed ? undefined : this._value;\n }\n\n public set value(value: T | undefined) {\n if (this._isDisposed || value === this._value) {\n return;\n }\n this._value?.dispose();\n this._value = value;\n }\n\n public clear(): void {\n this.value = undefined;\n }\n\n public dispose(): void {\n this._isDisposed = true;\n this._value?.dispose();\n this._value = undefined;\n }\n}\n", "/**\n * Copyright (c) 2024-2026 The xterm.js authors. All rights reserved.\n * @license MIT\n *\n * Minimal event utilities for xterm.js core.\n * Simplified from VS Code's event.ts - no leak detection/profiling.\n */\n\nimport { IDisposable, DisposableStore, toDisposable } from './Lifecycle';\n\nexport interface IEvent<T> {\n (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable;\n}\n\nexport class Emitter<T> {\n private _listeners: { fn: (e: T) => any, thisArgs: any }[] = [];\n private _disposed = false;\n private _event: IEvent<T> | undefined;\n\n public get event(): IEvent<T> {\n if (this._event) {\n return this._event;\n }\n this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {\n if (this._disposed) {\n return toDisposable(() => {});\n }\n\n const entry = { fn: listener, thisArgs };\n this._listeners = this._listeners.slice();\n this._listeners.push(entry);\n\n const result = toDisposable(() => {\n const idx = this._listeners.indexOf(entry);\n if (idx !== -1) {\n this._listeners = this._listeners.slice();\n this._listeners.splice(idx, 1);\n }\n });\n\n if (disposables) {\n if (Array.isArray(disposables)) {\n disposables.push(result);\n } else {\n disposables.add(result);\n }\n }\n\n return result;\n };\n return this._event;\n }\n\n public fire(event: T): void {\n if (this._disposed || !this._listeners.length) {\n return;\n }\n if (this._listeners.length === 1) {\n this._listeners[0].fn.call(this._listeners[0].thisArgs, event);\n return;\n }\n const listeners = this._listeners;\n for (let i = 0, len = listeners.length; i < len; ++i) {\n listeners[i].fn.call(listeners[i].thisArgs, event);\n }\n }\n\n public dispose(): void {\n if (this._disposed) {\n return;\n }\n this._disposed = true;\n this._listeners.length = 0;\n }\n}\n\nexport namespace EventUtils {\n export function forward<T>(from: IEvent<T>, to: Emitter<T>): IDisposable {\n return from(e => to.fire(e));\n }\n\n export function map<I, O>(event: IEvent<I>, map: (i: I) => O): IEvent<O> {\n return (listener: (e: O) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {\n return event(i => listener.call(thisArgs, map(i)), undefined, disposables);\n };\n }\n\n export function any<T>(...events: IEvent<T>[]): IEvent<T>;\n export function any(...events: IEvent<any>[]): IEvent<void>;\n export function any<T>(...events: IEvent<T>[]): IEvent<T> {\n return (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {\n const store = new DisposableStore();\n for (const event of events) {\n store.add(event(e => listener.call(thisArgs, e)));\n }\n if (disposables) {\n if (Array.isArray(disposables)) {\n disposables.push(store);\n } else {\n disposables.add(store);\n }\n }\n return store;\n };\n }\n\n export function runAndSubscribe<T>(event: IEvent<T>, handler: (e: T) => void, initial: T): IDisposable;\n export function runAndSubscribe<T>(event: IEvent<T>, handler: (e: T | undefined) => void): IDisposable;\n export function runAndSubscribe<T>(event: IEvent<T>, handler: (e: T | undefined) => void, initial?: T): IDisposable {\n handler(initial);\n return event(e => handler(e));\n }\n}\n", "/**\n * Copyright (c) 2026 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport type { IProgramStatusRecord } from '@xterm/addon-program-status';\n\ntype ProgramStatusState = IProgramStatusRecord['state'];\ntype ProgramStatusKind = NonNullable<IProgramStatusRecord['kind']>;\ntype Mutable<T> = { -readonly [P in keyof T]: T[P] };\n\n/**\n * Byte limits are counted in UTF-8.\n */\nconst enum Limits {\n /**\n * The whole sequence may take 4096 bytes, of which `ESC ] 7501 ;` and `ESC \\` take 9.\n */\n PAYLOAD = 4087,\n KEY = 16,\n MSG_ENCODED = 2732,\n MSG_DECODED = 2048,\n TITLE_ENCODED = 256,\n TITLE_DECODED = 192,\n APP = 32,\n ID = 128,\n ID_LEVELS = 8,\n SEGMENT = 32,\n RECORDS = 256,\n PROGRESS = 100\n}\n\nexport type ProgramStatusReport =\n { readonly clear: true, readonly id: string } |\n { readonly clear: false, readonly record: IProgramStatusRecord };\n\ninterface IFields {\n app?: string;\n id?: string;\n kind?: string;\n msg?: string;\n progress?: string;\n state?: string;\n title?: string;\n}\n\n/**\n * Parses the payload of an OSC 7501 report. Returns undefined when the report\n * must be discarded whole.\n */\nexport function parseProgramStatusReport(data: string): ProgramStatusReport | undefined {\n // UTF-8 never takes fewer bytes than UTF-16 takes code units.\n if (data.length > Limits.PAYLOAD || utf8Length(data) > Limits.PAYLOAD) {\n return undefined;\n }\n const fields: IFields = {};\n for (const pair of data.split(':')) {\n const equal = pair.indexOf('=');\n if (equal === -1) {\n continue;\n }\n const key = trim(pair.slice(0, equal));\n const value = trim(pair.slice(equal + 1));\n if (utf8Length(key) > Limits.KEY) {\n return undefined;\n }\n if (!isKey(key)) {\n continue;\n }\n const encodedLimit = getEncodedLimit(key);\n if (encodedLimit !== undefined && utf8Length(value) > encodedLimit) {\n return undefined;\n }\n // A malformed id must never select the root record.\n if (key === 'id' && !isId(value)) {\n return undefined;\n }\n if (!isValue(value)) {\n continue;\n }\n switch (key) {\n case 'msg':\n case 'title': {\n const text = decodeText(value, key === 'msg' ? Limits.MSG_DECODED : Limits.TITLE_DECODED);\n if (text === undefined) {\n return undefined;\n }\n fields[key] = text;\n break;\n }\n case 'app':\n case 'id':\n case 'kind':\n case 'progress':\n case 'state':\n fields[key] = value;\n break;\n }\n }\n\n const id = fields.id ?? '';\n if (fields.state === 'clear') {\n return { clear: true, id };\n }\n const state = fields.state;\n if (!isState(state)) {\n return undefined;\n }\n const record: Mutable<IProgramStatusRecord> = { id, state };\n if (state === 'blocked' && isKind(fields.kind)) {\n record.kind = fields.kind;\n }\n if (state === 'working' || state === 'blocked') {\n const progress = parseProgress(fields.progress);\n if (progress !== undefined) {\n record.progress = progress;\n }\n }\n if (fields.app !== undefined && isSegment(fields.app)) {\n record.app = fields.app;\n }\n if (fields.title !== undefined) {\n record.title = fields.title;\n }\n if (fields.msg !== undefined) {\n record.message = fields.msg;\n }\n return { clear: false, record: Object.freeze(record) };\n}\n\n/**\n * The records of one terminal, keyed by id.\n */\nexport class ProgramStatusStore {\n // A Map iterates in insertion order, so the first key was updated least recently.\n private readonly _records = new Map<string, IProgramStatusRecord>();\n private _snapshot: ReadonlyArray<IProgramStatusRecord> | undefined;\n\n /**\n * The records from the oldest update to the newest, with `effectiveApp` filled in.\n */\n public get records(): ReadonlyArray<IProgramStatusRecord> {\n this._snapshot ??= Object.freeze(Array.from(this._records.values(), record => {\n const effectiveApp = this._getEffectiveApp(record.id);\n return effectiveApp === undefined ? record : Object.freeze({ ...record, effectiveApp });\n }));\n return this._snapshot;\n }\n\n public replace(record: IProgramStatusRecord): void {\n if (!this._records.delete(record.id) && this._records.size >= Limits.RECORDS) {\n const oldest = this._records.keys().next();\n if (!oldest.done) {\n this._records.delete(oldest.value);\n }\n }\n this._records.set(record.id, record);\n this._snapshot = undefined;\n }\n\n /**\n * Removes a record and its descendants. The empty id removes every record.\n * @returns Whether any record was removed.\n */\n public clear(id: string): boolean {\n const prefix = id + '/';\n return this._remove(record => id === '' || record.id === id || record.id.startsWith(prefix));\n }\n\n /**\n * Removes `working` and `blocked` records.\n * @returns Whether any record was removed.\n */\n public removeActiveRecords(): boolean {\n return this._remove(record => record.state === 'working' || record.state === 'blocked');\n }\n\n private _remove(predicate: (record: IProgramStatusRecord) => boolean): boolean {\n let removed = false;\n for (const [id, record] of this._records) {\n if (predicate(record)) {\n this._records.delete(id);\n removed = true;\n }\n }\n if (removed) {\n this._snapshot = undefined;\n }\n return removed;\n }\n\n private _getEffectiveApp(id: string): string | undefined {\n for (let ancestor: string | undefined = id; ancestor !== undefined; ancestor = getParentId(ancestor)) {\n const app = this._records.get(ancestor)?.app;\n if (app !== undefined) {\n return app;\n }\n }\n return undefined;\n }\n}\n\nfunction getParentId(id: string): string | undefined {\n if (id === '') {\n return undefined;\n }\n const slash = id.lastIndexOf('/');\n return slash === -1 ? '' : id.slice(0, slash);\n}\n\nfunction getEncodedLimit(key: string): number | undefined {\n switch (key) {\n case 'msg': return Limits.MSG_ENCODED;\n case 'title': return Limits.TITLE_ENCODED;\n case 'app': return Limits.APP;\n case 'id': return Limits.ID;\n }\n return undefined;\n}\n\nfunction isState(value: string | undefined): value is ProgramStatusState {\n return value === 'idle' || value === 'working' || value === 'done' || value === 'blocked' || value === 'error';\n}\n\nfunction isKind(value: string | undefined): value is ProgramStatusKind {\n return value === 'permission' || value === 'question' || value === 'auth';\n}\n\n/**\n * Digits only, leading zeros allowed. Anything else, or a number past 100, is treated as absent.\n */\nfunction parseProgress(value: string | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n let progress = 0;\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (code < 0x30 || code > 0x39) {\n return undefined;\n }\n progress = progress * 10 + code - 0x30;\n if (progress > Limits.PROGRESS) {\n return undefined;\n }\n }\n return progress;\n}\n\nfunction isWhitespace(code: number): boolean {\n return code === 0x20 || (code >= 0x09 && code <= 0x0D);\n}\n\nfunction trim(value: string): string {\n let start = 0;\n let end = value.length;\n while (start < end && isWhitespace(value.charCodeAt(start))) {\n start++;\n }\n while (end > start && isWhitespace(value.charCodeAt(end - 1))) {\n end--;\n }\n return value.slice(start, end);\n}\n\nfunction isAlphanumeric(code: number): boolean {\n return (code >= 0x41 && code <= 0x5A) || (code >= 0x61 && code <= 0x7A) || (code >= 0x30 && code <= 0x39);\n}\n\n/**\n * `[a-z]+`\n */\nfunction isKey(key: string): boolean {\n if (!key) {\n return false;\n }\n for (let i = 0; i < key.length; i++) {\n const code = key.charCodeAt(i);\n if (code < 0x61 || code > 0x7A) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * `[A-Za-z0-9_.,+/=-]*`\n */\nfunction isValue(value: string): boolean {\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n // _ . , + / = -\n if (!isAlphanumeric(code) && code !== 0x5F && code !== 0x2E && code !== 0x2C && code !== 0x2B && code !== 0x2F && code !== 0x3D && code !== 0x2D) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * `[A-Za-z0-9_.+-]{1,32}`\n */\nfunction isSegment(segment: string): boolean {\n if (segment.length < 1 || segment.length > Limits.SEGMENT) {\n return false;\n }\n for (let i = 0; i < segment.length; i++) {\n const code = segment.charCodeAt(i);\n // _ . + -\n if (!isAlphanumeric(code) && code !== 0x5F && code !== 0x2E && code !== 0x2B && code !== 0x2D) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Segments joined by `/`, at most 8 levels and 128 bytes.\n */\nfunction isId(id: string): boolean {\n if (!id || utf8Length(id) > Limits.ID) {\n return false;\n }\n const segments = id.split('/');\n return segments.length <= Limits.ID_LEVELS && segments.every(isSegment);\n}\n\nfunction utf8Length(value: string): number {\n let length = 0;\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (code < 0x80) {\n length += 1;\n } else if (code < 0x800) {\n length += 2;\n } else if (code >= 0xD800 && code <= 0xDBFF && i + 1 < value.length && (value.charCodeAt(i + 1) & 0xFC00) === 0xDC00) {\n length += 4;\n i++;\n } else {\n length += 3;\n }\n }\n return length;\n}\n\nfunction getBase64Value(code: number): number {\n if (code >= 0x41 && code <= 0x5A) return code - 0x41;\n if (code >= 0x61 && code <= 0x7A) return code - 0x61 + 26;\n if (code >= 0x30 && code <= 0x39) return code - 0x30 + 52;\n if (code === 0x2B) return 62;\n if (code === 0x2F) return 63;\n return -1;\n}\n\nlet utf8Decoder: TextDecoder | undefined;\n\n/**\n * Decodes standard base64 with optional padding into UTF-8 text without control characters.\n */\nfunction decodeText(value: string, limit: number): string | undefined {\n let contentLength = value.indexOf('=');\n if (contentLength === -1) {\n contentLength = value.length;\n }\n const padding = value.length - contentLength;\n const remainder = contentLength % 4;\n if (remainder === 1 || padding > 2) {\n return undefined;\n }\n for (let i = contentLength; i < value.length; i++) {\n if (value.charCodeAt(i) !== 0x3D) {\n return undefined;\n }\n }\n if (padding !== 0 && (value.length % 4 !== 0 || padding !== 4 - remainder)) {\n return undefined;\n }\n\n const bytes = new Uint8Array(Math.floor(contentLength * 3 / 4));\n let length = 0;\n let bits = 0;\n let bitCount = 0;\n for (let i = 0; i < contentLength; i++) {\n const sextet = getBase64Value(value.charCodeAt(i));\n if (sextet === -1) {\n return undefined;\n }\n bits = (bits << 6) | sextet;\n bitCount += 6;\n if (bitCount >= 8) {\n bitCount -= 8;\n if (length === limit) {\n return undefined;\n }\n bytes[length++] = (bits >> bitCount) & 0xFF;\n bits &= (1 << bitCount) - 1;\n }\n }\n if (bits !== 0) {\n return undefined;\n }\n\n let text: string;\n try {\n utf8Decoder ??= new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });\n text = utf8Decoder.decode(bytes.subarray(0, length));\n } catch {\n return undefined;\n }\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n // C0, DEL and C1\n if (code <= 0x1F || (code >= 0x7F && code <= 0x9F)) {\n return undefined;\n }\n }\n return text;\n}\n", "/**\n * Copyright (c) 2026 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport type { Terminal, ITerminalAddon } from '@xterm/xterm';\nimport type { ProgramStatusAddon as IProgramStatusApi, IProgramStatusRecord } from '@xterm/addon-program-status';\nimport { Emitter } from 'common/Event';\nimport { Disposable } from 'common/Lifecycle';\nimport { parseProgramStatusReport, ProgramStatusStore } from './ProgramStatus';\n\nconst enum Constants {\n OSC_IDENT = 7501,\n // Handlers do not learn whether BEL or ST ended the query, so the reply always ends with ST.\n REPLY = '\\x1b]7501;?\\x1b\\\\'\n}\n\n/**\n * @vt: #E[Supported via @xterm/addon-program-status.] OSC 7501 \"Program Status\" \"OSC 7501 ; Pt BEL\" \"Report what a program is doing, or query support with `?`.\"\n *\n * See [addon readme](https://github.com/xtermjs/xterm.js/tree/master/addons/addon-program-status) for more details.\n */\nexport class ProgramStatusAddon extends Disposable implements ITerminalAddon, IProgramStatusApi {\n private readonly _recordStore = new ProgramStatusStore();\n\n private readonly _onChange = this._register(new Emitter<ReadonlyArray<IProgramStatusRecord>>());\n public readonly onChange = this._onChange.event;\n\n public get records(): ReadonlyArray<IProgramStatusRecord> {\n return this._recordStore.records;\n }\n\n public activate(terminal: Terminal): void {\n this._register(terminal.parser.registerOscHandler(Constants.OSC_IDENT, data => {\n if (data === '?') {\n // Reply before the parser moves on, so the reply precedes core's reply to a following\n // query such as DA1.\n terminal.input(Constants.REPLY, false);\n return true;\n }\n const report = parseProgramStatusReport(data);\n if (report?.clear) {\n this.clear(report.id);\n } else if (report) {\n this._recordStore.replace(report.record);\n this._fireChange();\n }\n return true;\n }));\n // RIS removes every record. Returning false lets core run its full reset.\n this._register(terminal.parser.registerEscHandler({ final: 'c' }, () => {\n this.clear();\n return false;\n }));\n }\n\n public dispose(): void {\n this._recordStore.clear('');\n super.dispose();\n }\n\n public clear(id: string = ''): void {\n if (this._recordStore.clear(id)) {\n this._fireChange();\n }\n }\n\n public processExited(): void {\n if (this._recordStore.removeActiveRecords()) {\n this._fireChange();\n }\n }\n\n public promptStarted(): void {\n if (this._recordStore.removeActiveRecords()) {\n this._fireChange();\n }\n }\n\n private _fireChange(): void {\n this._onChange.fire(this._recordStore.records);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["toDisposable", "fn", "DisposableStore", "o", "d", "Disposable", "Emitter", "listener", "thisArgs", "disposables", "toDisposable", "entry", "result", "idx", "event", "listeners", "i", "len", "EventUtils", "forward", "from", "to", "e", "map", "any", "events", "store", "DisposableStore", "runAndSubscribe", "handler", "initial", "parseProgramStatusReport", "data", "utf8Length", "fields", "pair", "equal", "key", "trim", "value", "isKey", "encodedLimit", "getEncodedLimit", "isId", "isValue", "text", "decodeText", "id", "state", "isState", "record", "isKind", "progress", "parseProgress", "isSegment", "ProgramStatusStore", "effectiveApp", "oldest", "prefix", "predicate", "removed", "ancestor", "getParentId", "app", "slash", "i", "code", "isWhitespace", "start", "end", "isAlphanumeric", "segment", "segments", "length", "getBase64Value", "utf8Decoder", "limit", "contentLength", "padding", "remainder", "bytes", "bits", "bitCount", "sextet", "ProgramStatusAddon", "Disposable", "ProgramStatusStore", "Emitter", "terminal", "data", "report", "parseProgramStatusReport", "id"]
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xterm/addon-program-status",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
|
|
3
|
+
"version": "0.2.0-beta.1",
|
|
4
|
+
"author": {
|
|
5
|
+
"name": "The xterm.js authors",
|
|
6
|
+
"url": "https://xtermjs.org/"
|
|
7
|
+
},
|
|
8
|
+
"main": "lib/addon-program-status.js",
|
|
9
|
+
"module": "lib/addon-program-status.mjs",
|
|
10
|
+
"types": "typings/addon-program-status.d.ts",
|
|
11
|
+
"repository": "https://github.com/xtermjs/xterm.js/tree/master/addons/addon-program-status",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"terminal",
|
|
15
|
+
"xterm",
|
|
16
|
+
"xterm.js"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "../../node_modules/.bin/tsgo -p .",
|
|
20
|
+
"prepackage": "npm run build",
|
|
21
|
+
"package": "../../node_modules/.bin/webpack",
|
|
22
|
+
"prepublishOnly": "npm run package",
|
|
23
|
+
"start": "node ../../demo/start"
|
|
24
|
+
},
|
|
25
|
+
"commit": "66d176327e3b4b92cabe73150406fa6ab36ebb37",
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@xterm/xterm": "^6.1.0-beta.317"
|
|
28
|
+
}
|
|
6
29
|
}
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { IProgramStatusRecord } from '@xterm/addon-program-status';
|
|
7
|
+
|
|
8
|
+
type ProgramStatusState = IProgramStatusRecord['state'];
|
|
9
|
+
type ProgramStatusKind = NonNullable<IProgramStatusRecord['kind']>;
|
|
10
|
+
type Mutable<T> = { -readonly [P in keyof T]: T[P] };
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Byte limits are counted in UTF-8.
|
|
14
|
+
*/
|
|
15
|
+
const enum Limits {
|
|
16
|
+
/**
|
|
17
|
+
* The whole sequence may take 4096 bytes, of which `ESC ] 7501 ;` and `ESC \` take 9.
|
|
18
|
+
*/
|
|
19
|
+
PAYLOAD = 4087,
|
|
20
|
+
KEY = 16,
|
|
21
|
+
MSG_ENCODED = 2732,
|
|
22
|
+
MSG_DECODED = 2048,
|
|
23
|
+
TITLE_ENCODED = 256,
|
|
24
|
+
TITLE_DECODED = 192,
|
|
25
|
+
APP = 32,
|
|
26
|
+
ID = 128,
|
|
27
|
+
ID_LEVELS = 8,
|
|
28
|
+
SEGMENT = 32,
|
|
29
|
+
RECORDS = 256,
|
|
30
|
+
PROGRESS = 100
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type ProgramStatusReport =
|
|
34
|
+
{ readonly clear: true, readonly id: string } |
|
|
35
|
+
{ readonly clear: false, readonly record: IProgramStatusRecord };
|
|
36
|
+
|
|
37
|
+
interface IFields {
|
|
38
|
+
app?: string;
|
|
39
|
+
id?: string;
|
|
40
|
+
kind?: string;
|
|
41
|
+
msg?: string;
|
|
42
|
+
progress?: string;
|
|
43
|
+
state?: string;
|
|
44
|
+
title?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Parses the payload of an OSC 7501 report. Returns undefined when the report
|
|
49
|
+
* must be discarded whole.
|
|
50
|
+
*/
|
|
51
|
+
export function parseProgramStatusReport(data: string): ProgramStatusReport | undefined {
|
|
52
|
+
// UTF-8 never takes fewer bytes than UTF-16 takes code units.
|
|
53
|
+
if (data.length > Limits.PAYLOAD || utf8Length(data) > Limits.PAYLOAD) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const fields: IFields = {};
|
|
57
|
+
for (const pair of data.split(':')) {
|
|
58
|
+
const equal = pair.indexOf('=');
|
|
59
|
+
if (equal === -1) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const key = trim(pair.slice(0, equal));
|
|
63
|
+
const value = trim(pair.slice(equal + 1));
|
|
64
|
+
if (utf8Length(key) > Limits.KEY) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
if (!isKey(key)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const encodedLimit = getEncodedLimit(key);
|
|
71
|
+
if (encodedLimit !== undefined && utf8Length(value) > encodedLimit) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
// A malformed id must never select the root record.
|
|
75
|
+
if (key === 'id' && !isId(value)) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
if (!isValue(value)) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
switch (key) {
|
|
82
|
+
case 'msg':
|
|
83
|
+
case 'title': {
|
|
84
|
+
const text = decodeText(value, key === 'msg' ? Limits.MSG_DECODED : Limits.TITLE_DECODED);
|
|
85
|
+
if (text === undefined) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
fields[key] = text;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
case 'app':
|
|
92
|
+
case 'id':
|
|
93
|
+
case 'kind':
|
|
94
|
+
case 'progress':
|
|
95
|
+
case 'state':
|
|
96
|
+
fields[key] = value;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const id = fields.id ?? '';
|
|
102
|
+
if (fields.state === 'clear') {
|
|
103
|
+
return { clear: true, id };
|
|
104
|
+
}
|
|
105
|
+
const state = fields.state;
|
|
106
|
+
if (!isState(state)) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
const record: Mutable<IProgramStatusRecord> = { id, state };
|
|
110
|
+
if (state === 'blocked' && isKind(fields.kind)) {
|
|
111
|
+
record.kind = fields.kind;
|
|
112
|
+
}
|
|
113
|
+
if (state === 'working' || state === 'blocked') {
|
|
114
|
+
const progress = parseProgress(fields.progress);
|
|
115
|
+
if (progress !== undefined) {
|
|
116
|
+
record.progress = progress;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (fields.app !== undefined && isSegment(fields.app)) {
|
|
120
|
+
record.app = fields.app;
|
|
121
|
+
}
|
|
122
|
+
if (fields.title !== undefined) {
|
|
123
|
+
record.title = fields.title;
|
|
124
|
+
}
|
|
125
|
+
if (fields.msg !== undefined) {
|
|
126
|
+
record.message = fields.msg;
|
|
127
|
+
}
|
|
128
|
+
return { clear: false, record: Object.freeze(record) };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The records of one terminal, keyed by id.
|
|
133
|
+
*/
|
|
134
|
+
export class ProgramStatusStore {
|
|
135
|
+
// A Map iterates in insertion order, so the first key was updated least recently.
|
|
136
|
+
private readonly _records = new Map<string, IProgramStatusRecord>();
|
|
137
|
+
private _snapshot: ReadonlyArray<IProgramStatusRecord> | undefined;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The records from the oldest update to the newest, with `effectiveApp` filled in.
|
|
141
|
+
*/
|
|
142
|
+
public get records(): ReadonlyArray<IProgramStatusRecord> {
|
|
143
|
+
this._snapshot ??= Object.freeze(Array.from(this._records.values(), record => {
|
|
144
|
+
const effectiveApp = this._getEffectiveApp(record.id);
|
|
145
|
+
return effectiveApp === undefined ? record : Object.freeze({ ...record, effectiveApp });
|
|
146
|
+
}));
|
|
147
|
+
return this._snapshot;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public replace(record: IProgramStatusRecord): void {
|
|
151
|
+
if (!this._records.delete(record.id) && this._records.size >= Limits.RECORDS) {
|
|
152
|
+
const oldest = this._records.keys().next();
|
|
153
|
+
if (!oldest.done) {
|
|
154
|
+
this._records.delete(oldest.value);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
this._records.set(record.id, record);
|
|
158
|
+
this._snapshot = undefined;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Removes a record and its descendants. The empty id removes every record.
|
|
163
|
+
* @returns Whether any record was removed.
|
|
164
|
+
*/
|
|
165
|
+
public clear(id: string): boolean {
|
|
166
|
+
const prefix = id + '/';
|
|
167
|
+
return this._remove(record => id === '' || record.id === id || record.id.startsWith(prefix));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Removes `working` and `blocked` records.
|
|
172
|
+
* @returns Whether any record was removed.
|
|
173
|
+
*/
|
|
174
|
+
public removeActiveRecords(): boolean {
|
|
175
|
+
return this._remove(record => record.state === 'working' || record.state === 'blocked');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private _remove(predicate: (record: IProgramStatusRecord) => boolean): boolean {
|
|
179
|
+
let removed = false;
|
|
180
|
+
for (const [id, record] of this._records) {
|
|
181
|
+
if (predicate(record)) {
|
|
182
|
+
this._records.delete(id);
|
|
183
|
+
removed = true;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (removed) {
|
|
187
|
+
this._snapshot = undefined;
|
|
188
|
+
}
|
|
189
|
+
return removed;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private _getEffectiveApp(id: string): string | undefined {
|
|
193
|
+
for (let ancestor: string | undefined = id; ancestor !== undefined; ancestor = getParentId(ancestor)) {
|
|
194
|
+
const app = this._records.get(ancestor)?.app;
|
|
195
|
+
if (app !== undefined) {
|
|
196
|
+
return app;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function getParentId(id: string): string | undefined {
|
|
204
|
+
if (id === '') {
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
const slash = id.lastIndexOf('/');
|
|
208
|
+
return slash === -1 ? '' : id.slice(0, slash);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function getEncodedLimit(key: string): number | undefined {
|
|
212
|
+
switch (key) {
|
|
213
|
+
case 'msg': return Limits.MSG_ENCODED;
|
|
214
|
+
case 'title': return Limits.TITLE_ENCODED;
|
|
215
|
+
case 'app': return Limits.APP;
|
|
216
|
+
case 'id': return Limits.ID;
|
|
217
|
+
}
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function isState(value: string | undefined): value is ProgramStatusState {
|
|
222
|
+
return value === 'idle' || value === 'working' || value === 'done' || value === 'blocked' || value === 'error';
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function isKind(value: string | undefined): value is ProgramStatusKind {
|
|
226
|
+
return value === 'permission' || value === 'question' || value === 'auth';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Digits only, leading zeros allowed. Anything else, or a number past 100, is treated as absent.
|
|
231
|
+
*/
|
|
232
|
+
function parseProgress(value: string | undefined): number | undefined {
|
|
233
|
+
if (!value) {
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
let progress = 0;
|
|
237
|
+
for (let i = 0; i < value.length; i++) {
|
|
238
|
+
const code = value.charCodeAt(i);
|
|
239
|
+
if (code < 0x30 || code > 0x39) {
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
progress = progress * 10 + code - 0x30;
|
|
243
|
+
if (progress > Limits.PROGRESS) {
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return progress;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function isWhitespace(code: number): boolean {
|
|
251
|
+
return code === 0x20 || (code >= 0x09 && code <= 0x0D);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function trim(value: string): string {
|
|
255
|
+
let start = 0;
|
|
256
|
+
let end = value.length;
|
|
257
|
+
while (start < end && isWhitespace(value.charCodeAt(start))) {
|
|
258
|
+
start++;
|
|
259
|
+
}
|
|
260
|
+
while (end > start && isWhitespace(value.charCodeAt(end - 1))) {
|
|
261
|
+
end--;
|
|
262
|
+
}
|
|
263
|
+
return value.slice(start, end);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function isAlphanumeric(code: number): boolean {
|
|
267
|
+
return (code >= 0x41 && code <= 0x5A) || (code >= 0x61 && code <= 0x7A) || (code >= 0x30 && code <= 0x39);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* `[a-z]+`
|
|
272
|
+
*/
|
|
273
|
+
function isKey(key: string): boolean {
|
|
274
|
+
if (!key) {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
for (let i = 0; i < key.length; i++) {
|
|
278
|
+
const code = key.charCodeAt(i);
|
|
279
|
+
if (code < 0x61 || code > 0x7A) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* `[A-Za-z0-9_.,+/=-]*`
|
|
288
|
+
*/
|
|
289
|
+
function isValue(value: string): boolean {
|
|
290
|
+
for (let i = 0; i < value.length; i++) {
|
|
291
|
+
const code = value.charCodeAt(i);
|
|
292
|
+
// _ . , + / = -
|
|
293
|
+
if (!isAlphanumeric(code) && code !== 0x5F && code !== 0x2E && code !== 0x2C && code !== 0x2B && code !== 0x2F && code !== 0x3D && code !== 0x2D) {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* `[A-Za-z0-9_.+-]{1,32}`
|
|
302
|
+
*/
|
|
303
|
+
function isSegment(segment: string): boolean {
|
|
304
|
+
if (segment.length < 1 || segment.length > Limits.SEGMENT) {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
for (let i = 0; i < segment.length; i++) {
|
|
308
|
+
const code = segment.charCodeAt(i);
|
|
309
|
+
// _ . + -
|
|
310
|
+
if (!isAlphanumeric(code) && code !== 0x5F && code !== 0x2E && code !== 0x2B && code !== 0x2D) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Segments joined by `/`, at most 8 levels and 128 bytes.
|
|
319
|
+
*/
|
|
320
|
+
function isId(id: string): boolean {
|
|
321
|
+
if (!id || utf8Length(id) > Limits.ID) {
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
const segments = id.split('/');
|
|
325
|
+
return segments.length <= Limits.ID_LEVELS && segments.every(isSegment);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function utf8Length(value: string): number {
|
|
329
|
+
let length = 0;
|
|
330
|
+
for (let i = 0; i < value.length; i++) {
|
|
331
|
+
const code = value.charCodeAt(i);
|
|
332
|
+
if (code < 0x80) {
|
|
333
|
+
length += 1;
|
|
334
|
+
} else if (code < 0x800) {
|
|
335
|
+
length += 2;
|
|
336
|
+
} else if (code >= 0xD800 && code <= 0xDBFF && i + 1 < value.length && (value.charCodeAt(i + 1) & 0xFC00) === 0xDC00) {
|
|
337
|
+
length += 4;
|
|
338
|
+
i++;
|
|
339
|
+
} else {
|
|
340
|
+
length += 3;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return length;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function getBase64Value(code: number): number {
|
|
347
|
+
if (code >= 0x41 && code <= 0x5A) return code - 0x41;
|
|
348
|
+
if (code >= 0x61 && code <= 0x7A) return code - 0x61 + 26;
|
|
349
|
+
if (code >= 0x30 && code <= 0x39) return code - 0x30 + 52;
|
|
350
|
+
if (code === 0x2B) return 62;
|
|
351
|
+
if (code === 0x2F) return 63;
|
|
352
|
+
return -1;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
let utf8Decoder: TextDecoder | undefined;
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Decodes standard base64 with optional padding into UTF-8 text without control characters.
|
|
359
|
+
*/
|
|
360
|
+
function decodeText(value: string, limit: number): string | undefined {
|
|
361
|
+
let contentLength = value.indexOf('=');
|
|
362
|
+
if (contentLength === -1) {
|
|
363
|
+
contentLength = value.length;
|
|
364
|
+
}
|
|
365
|
+
const padding = value.length - contentLength;
|
|
366
|
+
const remainder = contentLength % 4;
|
|
367
|
+
if (remainder === 1 || padding > 2) {
|
|
368
|
+
return undefined;
|
|
369
|
+
}
|
|
370
|
+
for (let i = contentLength; i < value.length; i++) {
|
|
371
|
+
if (value.charCodeAt(i) !== 0x3D) {
|
|
372
|
+
return undefined;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (padding !== 0 && (value.length % 4 !== 0 || padding !== 4 - remainder)) {
|
|
376
|
+
return undefined;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const bytes = new Uint8Array(Math.floor(contentLength * 3 / 4));
|
|
380
|
+
let length = 0;
|
|
381
|
+
let bits = 0;
|
|
382
|
+
let bitCount = 0;
|
|
383
|
+
for (let i = 0; i < contentLength; i++) {
|
|
384
|
+
const sextet = getBase64Value(value.charCodeAt(i));
|
|
385
|
+
if (sextet === -1) {
|
|
386
|
+
return undefined;
|
|
387
|
+
}
|
|
388
|
+
bits = (bits << 6) | sextet;
|
|
389
|
+
bitCount += 6;
|
|
390
|
+
if (bitCount >= 8) {
|
|
391
|
+
bitCount -= 8;
|
|
392
|
+
if (length === limit) {
|
|
393
|
+
return undefined;
|
|
394
|
+
}
|
|
395
|
+
bytes[length++] = (bits >> bitCount) & 0xFF;
|
|
396
|
+
bits &= (1 << bitCount) - 1;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (bits !== 0) {
|
|
400
|
+
return undefined;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
let text: string;
|
|
404
|
+
try {
|
|
405
|
+
utf8Decoder ??= new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
|
|
406
|
+
text = utf8Decoder.decode(bytes.subarray(0, length));
|
|
407
|
+
} catch {
|
|
408
|
+
return undefined;
|
|
409
|
+
}
|
|
410
|
+
for (let i = 0; i < text.length; i++) {
|
|
411
|
+
const code = text.charCodeAt(i);
|
|
412
|
+
// C0, DEL and C1
|
|
413
|
+
if (code <= 0x1F || (code >= 0x7F && code <= 0x9F)) {
|
|
414
|
+
return undefined;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return text;
|
|
418
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Terminal, ITerminalAddon } from '@xterm/xterm';
|
|
7
|
+
import type { ProgramStatusAddon as IProgramStatusApi, IProgramStatusRecord } from '@xterm/addon-program-status';
|
|
8
|
+
import { Emitter } from 'common/Event';
|
|
9
|
+
import { Disposable } from 'common/Lifecycle';
|
|
10
|
+
import { parseProgramStatusReport, ProgramStatusStore } from './ProgramStatus';
|
|
11
|
+
|
|
12
|
+
const enum Constants {
|
|
13
|
+
OSC_IDENT = 7501,
|
|
14
|
+
// Handlers do not learn whether BEL or ST ended the query, so the reply always ends with ST.
|
|
15
|
+
REPLY = '\x1b]7501;?\x1b\\'
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @vt: #E[Supported via @xterm/addon-program-status.] OSC 7501 "Program Status" "OSC 7501 ; Pt BEL" "Report what a program is doing, or query support with `?`."
|
|
20
|
+
*
|
|
21
|
+
* See [addon readme](https://github.com/xtermjs/xterm.js/tree/master/addons/addon-program-status) for more details.
|
|
22
|
+
*/
|
|
23
|
+
export class ProgramStatusAddon extends Disposable implements ITerminalAddon, IProgramStatusApi {
|
|
24
|
+
private readonly _recordStore = new ProgramStatusStore();
|
|
25
|
+
|
|
26
|
+
private readonly _onChange = this._register(new Emitter<ReadonlyArray<IProgramStatusRecord>>());
|
|
27
|
+
public readonly onChange = this._onChange.event;
|
|
28
|
+
|
|
29
|
+
public get records(): ReadonlyArray<IProgramStatusRecord> {
|
|
30
|
+
return this._recordStore.records;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public activate(terminal: Terminal): void {
|
|
34
|
+
this._register(terminal.parser.registerOscHandler(Constants.OSC_IDENT, data => {
|
|
35
|
+
if (data === '?') {
|
|
36
|
+
// Reply before the parser moves on, so the reply precedes core's reply to a following
|
|
37
|
+
// query such as DA1.
|
|
38
|
+
terminal.input(Constants.REPLY, false);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
const report = parseProgramStatusReport(data);
|
|
42
|
+
if (report?.clear) {
|
|
43
|
+
this.clear(report.id);
|
|
44
|
+
} else if (report) {
|
|
45
|
+
this._recordStore.replace(report.record);
|
|
46
|
+
this._fireChange();
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
}));
|
|
50
|
+
// RIS removes every record. Returning false lets core run its full reset.
|
|
51
|
+
this._register(terminal.parser.registerEscHandler({ final: 'c' }, () => {
|
|
52
|
+
this.clear();
|
|
53
|
+
return false;
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public dispose(): void {
|
|
58
|
+
this._recordStore.clear('');
|
|
59
|
+
super.dispose();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public clear(id: string = ''): void {
|
|
63
|
+
if (this._recordStore.clear(id)) {
|
|
64
|
+
this._fireChange();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public processExited(): void {
|
|
69
|
+
if (this._recordStore.removeActiveRecords()) {
|
|
70
|
+
this._fireChange();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public promptStarted(): void {
|
|
75
|
+
if (this._recordStore.removeActiveRecords()) {
|
|
76
|
+
this._fireChange();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private _fireChange(): void {
|
|
81
|
+
this._onChange.fire(this._recordStore.records);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Terminal, ITerminalAddon, IDisposable, IEvent } from '@xterm/xterm';
|
|
7
|
+
|
|
8
|
+
declare module '@xterm/addon-program-status' {
|
|
9
|
+
/**
|
|
10
|
+
* An xterm.js addon that keeps the records that programs report through the
|
|
11
|
+
* program status sequence, OSC 7501, and answers its feature detection query.
|
|
12
|
+
*
|
|
13
|
+
* Load it only where the records are shown: a terminal that answers the
|
|
14
|
+
* query tells programs that their status is visible.
|
|
15
|
+
*/
|
|
16
|
+
export class ProgramStatusAddon implements ITerminalAddon, IDisposable {
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new program status addon.
|
|
20
|
+
*/
|
|
21
|
+
constructor();
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Activates the addon.
|
|
25
|
+
* @param terminal The terminal the addon is being loaded in.
|
|
26
|
+
*/
|
|
27
|
+
public activate(terminal: Terminal): void;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Disposes the addon. This removes its handlers and records without
|
|
31
|
+
* firing {@link onChange}.
|
|
32
|
+
*/
|
|
33
|
+
public dispose(): void;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The current records, from the oldest update to the newest.
|
|
37
|
+
*/
|
|
38
|
+
public readonly records: ReadonlyArray<IProgramStatusRecord>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* An event that fires with the full list of records after any change.
|
|
42
|
+
*/
|
|
43
|
+
public readonly onChange: IEvent<ReadonlyArray<IProgramStatusRecord>>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Removes a record and its descendants.
|
|
47
|
+
* @param id The record to remove. With no id, or the root record's empty
|
|
48
|
+
* id, every record is removed.
|
|
49
|
+
*/
|
|
50
|
+
public clear(id?: string): void;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Removes `working` and `blocked` records. Call this after the attached
|
|
54
|
+
* process exits and its last output is parsed, for example in the
|
|
55
|
+
* callback of `terminal.write('', callback)`.
|
|
56
|
+
*/
|
|
57
|
+
public processExited(): void;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Removes `working` and `blocked` records. Call this when a new top-level
|
|
61
|
+
* shell prompt starts, not for repaints, right or continuation prompts, or
|
|
62
|
+
* prompt marks inside a running command.
|
|
63
|
+
*/
|
|
64
|
+
public promptStarted(): void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* One record, as the last report with its id described it.
|
|
69
|
+
*
|
|
70
|
+
* The text is untrusted. It has no control characters, but it can contain
|
|
71
|
+
* text direction overrides and invisible formatting characters, which an
|
|
72
|
+
* embedder should remove before it shows the text outside the terminal.
|
|
73
|
+
*/
|
|
74
|
+
export interface IProgramStatusRecord {
|
|
75
|
+
/**
|
|
76
|
+
* The record's path, segments joined by `/`. An empty string identifies
|
|
77
|
+
* the root record.
|
|
78
|
+
*/
|
|
79
|
+
readonly id: string;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* What the program is doing.
|
|
83
|
+
*
|
|
84
|
+
* - `idle`: At rest, waiting for the user's next instruction.
|
|
85
|
+
* - `working`: Running.
|
|
86
|
+
* - `done`: Finished a piece of work that the user has not seen yet.
|
|
87
|
+
* - `blocked`: Cannot continue until the user does something.
|
|
88
|
+
* - `error`: Failed and stopped.
|
|
89
|
+
*/
|
|
90
|
+
readonly state: 'idle' | 'working' | 'done' | 'blocked' | 'error';
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* What a `blocked` program needs from the user.
|
|
94
|
+
*/
|
|
95
|
+
readonly kind?: 'permission' | 'question' | 'auth';
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Progress from 0 to 100 for a `working` or `blocked` record.
|
|
99
|
+
*/
|
|
100
|
+
readonly progress?: number;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The program name from this record's last report.
|
|
104
|
+
*/
|
|
105
|
+
readonly app?: string;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The program name from this record or its nearest ancestor that has
|
|
109
|
+
* one.
|
|
110
|
+
*/
|
|
111
|
+
readonly effectiveApp?: string;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* A short label, decoded from the report's `title`.
|
|
115
|
+
*/
|
|
116
|
+
readonly title?: string;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* One line about the record, decoded from the report's `msg`.
|
|
120
|
+
*/
|
|
121
|
+
readonly message?: string;
|
|
122
|
+
}
|
|
123
|
+
}
|