Skip to content

Commit 330e91e

Browse files
authored
Merge pull request #5251 from jerch/progress-addon
progress-addon
2 parents 0692d48 + 9caff8d commit 330e91e

22 files changed

+720
-15
lines changed

.eslintrc.json

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
"addons/addon-image/src/tsconfig.json",
2424
"addons/addon-image/test/tsconfig.json",
2525
"addons/addon-ligatures/src/tsconfig.json",
26+
"addons/addon-progress/src/tsconfig.json",
27+
"addons/addon-progress/test/tsconfig.json",
2628
"addons/addon-search/src/tsconfig.json",
2729
"addons/addon-search/test/tsconfig.json",
2830
"addons/addon-serialize/src/tsconfig.json",

.github/workflows/ci.yml

+5
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ jobs:
4444
./addons/addon-ligatures/lib/* \
4545
./addons/addon-ligatures/out/* \
4646
./addons/addon-ligatures/out-*/* \
47+
./addons/addon-progress/lib/* \
48+
./addons/addon-progress/out/* \
49+
./addons/addon-progress/out-*/* \
4750
./addons/addon-search/lib/* \
4851
./addons/addon-search/out/* \
4952
./addons/addon-search/out-*/* \
@@ -212,6 +215,8 @@ jobs:
212215
run: yarn test-integration-${{ matrix.browser }} --workers=50% --forbid-only --suite=addon-fit
213216
- name: Integration tests (addon-image)
214217
run: yarn test-integration-${{ matrix.browser }} --workers=50% --forbid-only --suite=addon-image
218+
- name: Integration tests (addon-progress)
219+
run: yarn test-integration-${{ matrix.browser }} --workers=50% --forbid-only --suite=addon-progress
215220
- name: Integration tests (addon-search)
216221
run: yarn test-integration-${{ matrix.browser }} --workers=50% --forbid-only --suite=addon-search
217222
- name: Integration tests (addon-serialize)

addons/addon-progress/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lib
2+
node_modules

addons/addon-progress/.npmignore

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Blacklist - exclude everything except npm defaults such as LICENSE, etc
2+
*
3+
!*/
4+
5+
# Whitelist - lib/
6+
!lib/**/*.d.ts
7+
8+
!lib/**/*.js
9+
!lib/**/*.js.map
10+
11+
!lib/**/*.mjs
12+
!lib/**/*.mjs.map
13+
14+
!lib/**/*.css
15+
16+
# Whitelist - src/
17+
!src/**/*.ts
18+
!src/**/*.d.ts
19+
20+
!src/**/*.js
21+
!src/**/*.js.map
22+
23+
!src/**/*.css
24+
25+
# Blacklist - src/ test files
26+
src/**/*.test.ts
27+
src/**/*.test.d.ts
28+
src/**/*.test.js
29+
src/**/*.test.js.map
30+
31+
# Whitelist - typings/
32+
!typings/*.d.ts

addons/addon-progress/LICENSE

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2024, 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.

addons/addon-progress/README.md

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
## @xterm/addon-progress
2+
3+
An xterm.js addon providing an interface for ConEmu's progress sequence.
4+
See https://conemu.github.io/en/AnsiEscapeCodes.html#ConEmu_specific_OSC for sequence details.
5+
6+
7+
### Install
8+
9+
```bash
10+
npm install --save @xterm/addon-progress
11+
```
12+
13+
14+
### Usage
15+
16+
```ts
17+
import { Terminal } from '@xterm/xterm';
18+
import { ProgressAddon, IProgressState } from '@xterm/addon-progress';
19+
20+
const terminal = new Terminal();
21+
const progressAddon = new ProgressAddon();
22+
terminal.loadAddon(progressAddon);
23+
progressAddon.onChange({state, value}: IProgressState) => {
24+
// state: 0-4 integer (see below for meaning)
25+
// value: 0-100 integer (percent value)
26+
27+
// do your visualisation based on state/value here
28+
...
29+
});
30+
```
31+
32+
See the full [API](https://github.com/xtermjs/xterm.js/blob/master/addons/addon-progress/typings/addon-progress.d.ts) for more advanced usage.
33+
34+
### Sequence
35+
36+
The sequence to set progress information has the following format:
37+
38+
```plain
39+
ESC ] 9 ; 4 ; <state> ; <progress value> BEL
40+
```
41+
42+
where state is a decimal number in 0 to 4 and progress value is a decimal number in 0 to 100.
43+
The states have the following meaning:
44+
45+
- 0: Remove any progress indication. Also resets progress value to 0. A given progress value will be ignored.
46+
- 1: Normal state to set a progress value. The value should be in 0..100, greater values are clamped to 100.
47+
If the value is omitted, it will be set to 0.
48+
- 2: Error state with an optional progress value. An omitted value will be set to 0,
49+
which has a special meaning using the last active value.
50+
- 3: Actual progress is "indeterminate", any progress value will be ignored. Meant to be used to indicate
51+
a running task without progress information (e.g. by a spinner). A previously set progress value
52+
by any other state sequence will be left untouched.
53+
- 4: Pause or warning state with an optional progress value. An omitted value will be set to 0,
54+
which has a special meaning using the last active value.
55+
56+
The addon resolves most of those semantic nuances and will provide these ready-to-go values:
57+
- For the remove state (0) any progress value wont be parsed, thus is even allowed to contain garbage.
58+
It will always emit `{state: 0, value: 0}`.
59+
- For the set state (1) an omitted value will be set to 0 emitting `{state: 1, value: 0}`.
60+
If a value was given, it must be decimal digits only, any characters outside will mark the whole sequence
61+
as faulty (no sloppy integer parsing). The value will be clamped to max 100 giving
62+
`{state: 1, value: parsedAndClampedValue}`.
63+
- For the error and pause state (2 & 4) an omitted or zero value will emit `{state: 2|4, value: lastValue}`.
64+
If a value was given, it must be decimal digits only, any characters outside will mark the whole sequence
65+
as faulty (no sloppy integer parsing). The value will be clamped to max 100 giving
66+
`{state: 2|4, value: parsedAndClampedValue}`.
67+
- For the indeterminate state (3) a value notion will be ignored.
68+
It still emits the value as `{state: 3, value: lastValue}`. Keep in mind not use that value while
69+
that state is active, as a task might have entered that state without a proper reset at the beginning.

addons/addon-progress/package.json

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "@xterm/addon-progress",
3+
"version": "0.1.0",
4+
"author": {
5+
"name": "The xterm.js authors",
6+
"url": "https://xtermjs.org/"
7+
},
8+
"main": "lib/addon-progress.js",
9+
"module": "lib/addon-progress.mjs",
10+
"types": "typings/addon-progress.d.ts",
11+
"repository": "https://github.com/xtermjs/xterm.js/tree/master/addons/addon-progress",
12+
"license": "MIT",
13+
"keywords": [
14+
"terminal",
15+
"xterm",
16+
"xterm.js"
17+
],
18+
"scripts": {
19+
"build": "../../node_modules/.bin/tsc -p .",
20+
"prepackage": "npm run build",
21+
"package": "../../node_modules/.bin/webpack",
22+
"prepublishOnly": "npm run package",
23+
"start": "node ../../demo/start"
24+
},
25+
"peerDependencies": {
26+
"@xterm/xterm": "^5.0.0"
27+
}
28+
}
+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/**
2+
* Copyright (c) 2024 The xterm.js authors. All rights reserved.
3+
* @license MIT
4+
*/
5+
6+
import type { Terminal, ITerminalAddon, IDisposable } from '@xterm/xterm';
7+
import type { ProgressAddon as IProgressApi, IProgressState } from '@xterm/addon-progress';
8+
import type { Emitter, Event } from 'vs/base/common/event';
9+
10+
11+
const enum ProgressType {
12+
REMOVE = 0,
13+
SET = 1,
14+
ERROR = 2,
15+
INDETERMINATE = 3,
16+
PAUSE = 4
17+
}
18+
19+
20+
/**
21+
* Strict integer parsing, only decimal digits allowed.
22+
*/
23+
function toInt(s: string): number {
24+
let v = 0;
25+
for (let i = 0; i < s.length; ++i) {
26+
const c = s.charCodeAt(i);
27+
if (c < 0x30 || 0x39 < c) {
28+
return -1;
29+
}
30+
v = v * 10 + c - 48;
31+
}
32+
return v;
33+
}
34+
35+
36+
export class ProgressAddon implements ITerminalAddon, IProgressApi {
37+
private _seqHandler: IDisposable | undefined;
38+
private _st: ProgressType = ProgressType.REMOVE;
39+
private _pr = 0;
40+
private _onChange: Emitter<IProgressState> | undefined;
41+
public onChange: Event<IProgressState> | undefined;
42+
43+
public dispose(): void {
44+
this._seqHandler?.dispose();
45+
this._onChange?.dispose();
46+
}
47+
48+
public activate(terminal: Terminal): void {
49+
this._seqHandler = terminal.parser.registerOscHandler(9, data => {
50+
if (!data.startsWith('4;')) {
51+
return false;
52+
}
53+
const parts = data.split(';');
54+
55+
if (parts.length > 3) {
56+
return true; // faulty sequence, just exit
57+
}
58+
if (parts.length === 2) {
59+
parts.push('');
60+
}
61+
const st = toInt(parts[1]);
62+
const pr = toInt(parts[2]);
63+
64+
switch (st) {
65+
case ProgressType.REMOVE:
66+
this.progress = { state: st, value: 0 };
67+
break;
68+
case ProgressType.SET:
69+
if (pr < 0) return true; // faulty sequence, just exit
70+
this.progress = { state: st, value: pr };
71+
break;
72+
case ProgressType.ERROR:
73+
case ProgressType.PAUSE:
74+
if (pr < 0) return true; // faulty sequence, just exit
75+
this.progress = { state: st, value: pr || this._pr };
76+
break;
77+
case ProgressType.INDETERMINATE:
78+
this.progress = { state: st, value: this._pr };
79+
break;
80+
}
81+
return true;
82+
});
83+
// FIXME: borrow emitter ctor from xterm, to be changed once #5283 is resolved
84+
this._onChange = new (terminal as any)._core._onData.constructor();
85+
this.onChange = this._onChange!.event;
86+
}
87+
88+
public get progress(): IProgressState {
89+
return { state: this._st, value: this._pr };
90+
}
91+
92+
public set progress(progress: IProgressState) {
93+
if (progress.state < 0 || progress.state > 4) {
94+
console.warn(`progress state out of bounds, not applied`);
95+
return;
96+
}
97+
this._st = progress.state;
98+
this._pr = Math.min(Math.max(progress.value, 0), 100);
99+
this._onChange?.fire({ state: this._st, value: this._pr });
100+
}
101+
}
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"compilerOptions": {
3+
"module": "commonjs",
4+
"target": "es2021",
5+
"lib": [
6+
"dom",
7+
"es2015"
8+
],
9+
"rootDir": ".",
10+
"outDir": "../out",
11+
"sourceMap": true,
12+
"removeComments": true,
13+
"strict": true,
14+
"types": [
15+
"../../../node_modules/@types/mocha",
16+
"../../../src/vs/typings/thenable"
17+
],
18+
"paths": {
19+
"browser/*": [
20+
"../../../src/browser/*"
21+
],
22+
"vs/*": [
23+
"../../../src/vs/*"
24+
],
25+
"@xterm/addon-progress": [
26+
"../typings/addon-progress.d.ts"
27+
]
28+
}
29+
},
30+
"include": [
31+
"./**/*",
32+
"../../../typings/xterm.d.ts"
33+
],
34+
"references": [
35+
{
36+
"path": "../../../src/browser"
37+
},
38+
{
39+
"path": "../../../src/vs"
40+
}
41+
]
42+
}

0 commit comments

Comments
 (0)