Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c6f793aa2 | ||
|
|
f22ef02831 | ||
|
|
c569e5ab19 | ||
|
|
9a65429a30 |
+27
-19
@@ -11,9 +11,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v3
|
||||||
- name: Use Node.js 22.x
|
- name: Use Node.js 22.x
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 22.x
|
node-version: 22.x
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
@@ -69,7 +69,7 @@ jobs:
|
|||||||
./addons/addon-webgl/out/* \
|
./addons/addon-webgl/out/* \
|
||||||
./addons/addon-webgl/out-*st/*
|
./addons/addon-webgl/out-*st/*
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-artifacts
|
name: build-artifacts
|
||||||
path: compressed-build.zip
|
path: compressed-build.zip
|
||||||
@@ -79,9 +79,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v3
|
||||||
- name: Use Node.js 22.x
|
- name: Use Node.js 22.x
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 22.x
|
node-version: 22.x
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
@@ -100,16 +100,16 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v3
|
||||||
- name: Use Node.js 22.x
|
- name: Use Node.js 22.x
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 22.x
|
node-version: 22.x
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
npm ci
|
npm ci
|
||||||
- uses: actions/download-artifact@v7
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-artifacts
|
name: build-artifacts
|
||||||
- name: Unzip artifacts
|
- name: Unzip artifacts
|
||||||
@@ -129,7 +129,6 @@ jobs:
|
|||||||
exit $EXIT_CODE
|
exit $EXIT_CODE
|
||||||
|
|
||||||
test-unit:
|
test-unit:
|
||||||
needs: build
|
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@@ -137,16 +136,21 @@ jobs:
|
|||||||
runs-on: [ubuntu, macos, windows]
|
runs-on: [ubuntu, macos, windows]
|
||||||
runs-on: ${{ matrix.runs-on }}-latest
|
runs-on: ${{ matrix.runs-on }}-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v3
|
||||||
- name: Use Node.js ${{ matrix.node-version }}.x
|
- name: Use Node.js ${{ matrix.node-version }}.x
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}.x
|
node-version: ${{ matrix.node-version }}.x
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
npm ci
|
npm ci
|
||||||
- uses: actions/download-artifact@v7
|
- name: Wait for build job
|
||||||
|
uses: NathanFirmo/wait-for-other-job@v1.1.1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
job: build
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-artifacts
|
name: build-artifacts
|
||||||
- name: Unzip artifacts
|
- name: Unzip artifacts
|
||||||
@@ -162,7 +166,6 @@ jobs:
|
|||||||
run: npm run test-unit --forbid-only
|
run: npm run test-unit --forbid-only
|
||||||
|
|
||||||
test-integration:
|
test-integration:
|
||||||
needs: build
|
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@@ -171,9 +174,9 @@ jobs:
|
|||||||
browser: [chromium, firefox, webkit]
|
browser: [chromium, firefox, webkit]
|
||||||
runs-on: ${{ matrix.runs-on }}
|
runs-on: ${{ matrix.runs-on }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v3
|
||||||
- name: Use Node.js ${{ matrix.node-version }}.x
|
- name: Use Node.js ${{ matrix.node-version }}.x
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}.x
|
node-version: ${{ matrix.node-version }}.x
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
@@ -182,7 +185,12 @@ jobs:
|
|||||||
npm ci
|
npm ci
|
||||||
- name: Install playwright
|
- name: Install playwright
|
||||||
run: npx playwright install --with-deps ${{ matrix.browser }}
|
run: npx playwright install --with-deps ${{ matrix.browser }}
|
||||||
- uses: actions/download-artifact@v7
|
- name: Wait for build job
|
||||||
|
uses: NathanFirmo/wait-for-other-job@v1.1.1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
job: build
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-artifacts
|
name: build-artifacts
|
||||||
- name: Unzip artifacts
|
- name: Unzip artifacts
|
||||||
@@ -232,9 +240,9 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
node-version: [22]
|
node-version: [22]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v3
|
||||||
- name: Use Node.js ${{ matrix.node-version }}.x
|
- name: Use Node.js ${{ matrix.node-version }}.x
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}.x
|
node-version: ${{ matrix.node-version }}.x
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
@@ -243,7 +251,7 @@ jobs:
|
|||||||
npm ci
|
npm ci
|
||||||
- name: Install playwright
|
- name: Install playwright
|
||||||
run: npx playwright install
|
run: npx playwright install
|
||||||
- uses: actions/download-artifact@v7
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-artifacts
|
name: build-artifacts
|
||||||
- name: Unzip artifacts
|
- name: Unzip artifacts
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v3
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v4
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v4
|
uses: github/codeql-action/autobuild@v2
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v4
|
uses: github/codeql-action/analyze@v2
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v4
|
||||||
- name: Use Node.js 22.x
|
- name: Use Node.js 22.x
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 22.x
|
node-version: 22.x
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ jobs:
|
|||||||
release:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v3
|
||||||
- name: Use Node.js 22.x
|
- name: Use Node.js 22.x
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 22.x
|
node-version: 22.x
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ docs/
|
|||||||
npm-debug.log
|
npm-debug.log
|
||||||
/.idea/
|
/.idea/
|
||||||
.env
|
.env
|
||||||
mise.toml
|
|
||||||
build/
|
build/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
yarn.lock
|
yarn.lock
|
||||||
|
|||||||
-374
@@ -1,374 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
||||||
"plugins": [
|
|
||||||
"import",
|
|
||||||
"typescript"
|
|
||||||
],
|
|
||||||
"categories": {
|
|
||||||
"correctness": "off"
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"typeAware": true,
|
|
||||||
"maxWarnings": 0
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"builtin": true
|
|
||||||
},
|
|
||||||
"ignorePatterns": [
|
|
||||||
"addons/*/src/third-party/*.ts",
|
|
||||||
"**/out/*",
|
|
||||||
"**/out-test/*",
|
|
||||||
"**/out-esbuild/*",
|
|
||||||
"**/out-esbuild-test/*",
|
|
||||||
"**/inwasm-sdks/*",
|
|
||||||
"**/typings/*.d.ts",
|
|
||||||
"**/node_modules",
|
|
||||||
"**/*.js",
|
|
||||||
"**/*.mjs"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"constructor-super": "error",
|
|
||||||
"for-direction": "error",
|
|
||||||
"getter-return": "error",
|
|
||||||
"no-async-promise-executor": "error",
|
|
||||||
"no-case-declarations": "error",
|
|
||||||
"no-class-assign": "error",
|
|
||||||
"no-compare-neg-zero": "error",
|
|
||||||
"no-cond-assign": "error",
|
|
||||||
"no-const-assign": "error",
|
|
||||||
"no-constant-binary-expression": "error",
|
|
||||||
"no-constant-condition": "error",
|
|
||||||
"no-control-regex": "error",
|
|
||||||
"no-debugger": "error",
|
|
||||||
"no-delete-var": "error",
|
|
||||||
"no-dupe-class-members": "error",
|
|
||||||
"no-dupe-else-if": "error",
|
|
||||||
"no-dupe-keys": "error",
|
|
||||||
"no-duplicate-case": "error",
|
|
||||||
"no-empty": "error",
|
|
||||||
"no-empty-character-class": "error",
|
|
||||||
"no-empty-pattern": "error",
|
|
||||||
"no-empty-static-block": "error",
|
|
||||||
"no-ex-assign": "error",
|
|
||||||
"no-extra-boolean-cast": "error",
|
|
||||||
"no-fallthrough": "error",
|
|
||||||
"no-func-assign": "error",
|
|
||||||
"no-global-assign": "error",
|
|
||||||
"no-import-assign": "error",
|
|
||||||
"no-invalid-regexp": "error",
|
|
||||||
"no-irregular-whitespace": "error",
|
|
||||||
"no-loss-of-precision": "error",
|
|
||||||
"no-misleading-character-class": "error",
|
|
||||||
"no-new-native-nonconstructor": "error",
|
|
||||||
"no-nonoctal-decimal-escape": "error",
|
|
||||||
"no-obj-calls": "error",
|
|
||||||
"no-prototype-builtins": "error",
|
|
||||||
"no-redeclare": "error",
|
|
||||||
"no-regex-spaces": "error",
|
|
||||||
"no-self-assign": "error",
|
|
||||||
"no-setter-return": "error",
|
|
||||||
"no-shadow-restricted-names": "error",
|
|
||||||
"no-sparse-arrays": "error",
|
|
||||||
"no-this-before-super": "error",
|
|
||||||
"no-unassigned-vars": "error",
|
|
||||||
"no-unexpected-multiline": "error",
|
|
||||||
"no-unreachable": "error",
|
|
||||||
"no-unsafe-finally": "error",
|
|
||||||
"no-unsafe-negation": "error",
|
|
||||||
"no-unsafe-optional-chaining": "error",
|
|
||||||
"no-unused-labels": "error",
|
|
||||||
"no-unused-private-class-members": "error",
|
|
||||||
"no-unused-vars": "error",
|
|
||||||
"no-useless-backreference": "error",
|
|
||||||
"no-useless-catch": "error",
|
|
||||||
"no-useless-escape": "error",
|
|
||||||
"no-with": "error",
|
|
||||||
"preserve-caught-error": "error",
|
|
||||||
"require-yield": "error",
|
|
||||||
"use-isnan": "error",
|
|
||||||
"valid-typeof": "error",
|
|
||||||
"no-array-constructor": "error",
|
|
||||||
"no-unused-expressions": "error",
|
|
||||||
"typescript/ban-ts-comment": "error",
|
|
||||||
"typescript/no-duplicate-enum-values": "error",
|
|
||||||
"typescript/no-empty-object-type": "error",
|
|
||||||
"typescript/no-explicit-any": "error",
|
|
||||||
"typescript/no-extra-non-null-assertion": "error",
|
|
||||||
"typescript/no-misused-new": "error",
|
|
||||||
"typescript/no-namespace": "error",
|
|
||||||
"typescript/no-non-null-asserted-optional-chain": "error",
|
|
||||||
"typescript/no-require-imports": "error",
|
|
||||||
"typescript/no-this-alias": "error",
|
|
||||||
"typescript/no-unnecessary-type-constraint": "error",
|
|
||||||
"typescript/no-unsafe-declaration-merging": "error",
|
|
||||||
"typescript/no-unsafe-function-type": "error",
|
|
||||||
"typescript/no-wrapper-object-types": "error",
|
|
||||||
"typescript/prefer-as-const": "error",
|
|
||||||
"typescript/prefer-namespace-keyword": "error",
|
|
||||||
"typescript/triple-slash-reference": "error",
|
|
||||||
"import/no-cycle": "error"
|
|
||||||
},
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": [
|
|
||||||
"**/*.ts",
|
|
||||||
"**/*.tsx",
|
|
||||||
"**/*.mts",
|
|
||||||
"**/*.cts"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"constructor-super": "off",
|
|
||||||
"getter-return": "off",
|
|
||||||
"no-class-assign": "off",
|
|
||||||
"no-const-assign": "off",
|
|
||||||
"no-dupe-class-members": "off",
|
|
||||||
"no-dupe-keys": "off",
|
|
||||||
"no-func-assign": "off",
|
|
||||||
"no-import-assign": "off",
|
|
||||||
"no-new-native-nonconstructor": "off",
|
|
||||||
"no-obj-calls": "off",
|
|
||||||
"no-redeclare": "off",
|
|
||||||
"no-setter-return": "off",
|
|
||||||
"no-this-before-super": "off",
|
|
||||||
"no-unreachable": "off",
|
|
||||||
"no-unsafe-negation": "off",
|
|
||||||
"no-var": "error",
|
|
||||||
"no-with": "off",
|
|
||||||
"prefer-const": "error",
|
|
||||||
"prefer-rest-params": "error",
|
|
||||||
"prefer-spread": "error"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": [
|
|
||||||
"**/*.ts"
|
|
||||||
],
|
|
||||||
"jsPlugins": [
|
|
||||||
"@stylistic/eslint-plugin",
|
|
||||||
{
|
|
||||||
"name": "jsdoc-js",
|
|
||||||
"specifier": "eslint-plugin-jsdoc"
|
|
||||||
},
|
|
||||||
"oxlint-plugin-eslint"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"@stylistic/comma-spacing": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"before": false,
|
|
||||||
"after": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@stylistic/indent": [
|
|
||||||
"warn",
|
|
||||||
2
|
|
||||||
],
|
|
||||||
"@stylistic/semi": [
|
|
||||||
"warn",
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"@stylistic/quotes": [
|
|
||||||
"warn",
|
|
||||||
"single",
|
|
||||||
{
|
|
||||||
"allowTemplateLiterals": "always"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@stylistic/member-delimiter-style": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"multiline": {
|
|
||||||
"delimiter": "semi",
|
|
||||||
"requireLast": true
|
|
||||||
},
|
|
||||||
"singleline": {
|
|
||||||
"delimiter": "comma",
|
|
||||||
"requireLast": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@stylistic/type-annotation-spacing": "warn",
|
|
||||||
"@stylistic/space-unary-ops": "warn",
|
|
||||||
"@stylistic/keyword-spacing": "warn",
|
|
||||||
"@stylistic/max-len": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"code": 1000,
|
|
||||||
"comments": 100,
|
|
||||||
"ignoreTrailingComments": true,
|
|
||||||
"ignoreUrls": true,
|
|
||||||
"ignorePattern": "^ *((?<vt_comment>(//|\\*) @vt)|(?<table_comment>\\* \\| )|(?<commented_code>// ))"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@stylistic/new-parens": "warn",
|
|
||||||
"@stylistic/no-extra-semi": "error",
|
|
||||||
"@stylistic/no-trailing-spaces": "warn",
|
|
||||||
"eslint-js/object-curly-spacing": [
|
|
||||||
"warn",
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"@stylistic/spaced-comment": [
|
|
||||||
"warn",
|
|
||||||
"always",
|
|
||||||
{
|
|
||||||
"markers": [
|
|
||||||
"/"
|
|
||||||
],
|
|
||||||
"exceptions": [
|
|
||||||
"-"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"jsdoc-js/check-alignment": "warn",
|
|
||||||
"jsdoc-js/check-param-names": "warn",
|
|
||||||
"jsdoc-js/multiline-blocks": "warn",
|
|
||||||
"jsdoc-js/no-multi-asterisks": "warn",
|
|
||||||
"eslint-js/one-var": [
|
|
||||||
"warn",
|
|
||||||
"never"
|
|
||||||
],
|
|
||||||
"eslint-js/no-restricted-syntax": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"selector": "CallExpression[callee.name='requestAnimationFrame']",
|
|
||||||
"message": "The global requestAnimationFrame() should be avoided, call it on the parent window from ICoreBrowserService."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "CallExpression[callee.name='cancelAnimationFrame']",
|
|
||||||
"message": "The global cancelAnimationFrame() should be avoided, call it on the parent window from ICoreBrowserService."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "CallExpression > MemberExpression[object.name='window'][property.name='requestAnimationFrame']",
|
|
||||||
"message": "window.requestAnimationFrame() should be avoided, call it on the parent window from ICoreBrowserService."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "CallExpression > MemberExpression[object.name='window'][property.name='cancelAnimationFrame']",
|
|
||||||
"message": "window.cancelAnimationFrame() should be avoided, call it on the parent window from ICoreBrowserService."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "MemberExpression[object.name='window'][property.name='devicePixelRatio']",
|
|
||||||
"message": "window.devicePixelRatio should be avoided, get it from ICoreBrowserService."
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"curly": [
|
|
||||||
"warn",
|
|
||||||
"multi-line"
|
|
||||||
],
|
|
||||||
"eqeqeq": [
|
|
||||||
"warn",
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"no-duplicate-imports": "warn",
|
|
||||||
"no-else-return": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"allowElseIf": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"no-eval": "warn",
|
|
||||||
"no-irregular-whitespace": "warn",
|
|
||||||
"no-restricted-imports": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"patterns": [
|
|
||||||
".*\\/out\\/.*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"no-unsafe-finally": "warn",
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"no-var": "warn",
|
|
||||||
"no-empty": "off",
|
|
||||||
"no-empty-pattern": "off",
|
|
||||||
"no-cond-assign": "off",
|
|
||||||
"no-case-declarations": "off",
|
|
||||||
"for-direction": "off",
|
|
||||||
"no-prototype-builtins": "off",
|
|
||||||
"no-useless-escape": "off",
|
|
||||||
"no-self-assign": "off",
|
|
||||||
"no-async-promise-executor": "off",
|
|
||||||
"prefer-rest-params": "off",
|
|
||||||
"no-control-regex": "off",
|
|
||||||
"no-fallthrough": "off",
|
|
||||||
"prefer-spread": "off",
|
|
||||||
"prefer-const": "warn",
|
|
||||||
"no-unused-expressions": "off",
|
|
||||||
"typescript/array-type": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"default": "array",
|
|
||||||
"readonly": "generic"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"typescript/consistent-type-assertions": "warn",
|
|
||||||
"typescript/consistent-type-definitions": "warn",
|
|
||||||
"typescript/explicit-function-return-type": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"allowExpressions": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"typescript/explicit-member-accessibility": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"accessibility": "explicit",
|
|
||||||
"overrides": {
|
|
||||||
"constructors": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"typescript/no-confusing-void-expression": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"ignoreArrowShorthand": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"typescript/no-useless-constructor": "warn",
|
|
||||||
"typescript/prefer-nullish-coalescing": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"ignorePrimitives": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"typescript/prefer-namespace-keyword": "warn",
|
|
||||||
"typescript/no-unused-vars": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"vars": "all",
|
|
||||||
"args": "none"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"typescript/no-require-imports": "off",
|
|
||||||
"typescript/no-explicit-any": "off",
|
|
||||||
"typescript/no-wrapper-object-types": "off",
|
|
||||||
"typescript/no-empty-object-type": "off",
|
|
||||||
"typescript/no-unsafe-function-type": "off",
|
|
||||||
"typescript/no-this-alias": "off",
|
|
||||||
"typescript/no-namespace": "off",
|
|
||||||
"typescript/no-duplicate-enum-values": "off"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": [
|
|
||||||
"**/*.api.ts",
|
|
||||||
"**/*.test.ts"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"eslint-js/object-curly-spacing": "off",
|
|
||||||
"@stylistic/max-len": "off",
|
|
||||||
"typescript/no-unused-vars": "off",
|
|
||||||
"typescript/explicit-function-return-type": "off",
|
|
||||||
"typescript/explicit-member-accessibility": "off"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": [
|
|
||||||
"demo/**/*.ts",
|
|
||||||
"**/*.benchmark.ts"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"typescript/prefer-nullish-coalescing": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
||||||
"options": {
|
|
||||||
"maxWarnings": 0
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"builtin": true
|
|
||||||
},
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": [
|
|
||||||
"typings/**/*.d.ts"
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
"typescript"
|
|
||||||
],
|
|
||||||
"jsPlugins": [
|
|
||||||
"@stylistic/eslint-plugin",
|
|
||||||
{
|
|
||||||
"name": "jsdoc-js",
|
|
||||||
"specifier": "eslint-plugin-jsdoc"
|
|
||||||
},
|
|
||||||
"oxlint-plugin-eslint"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"@stylistic/indent": [
|
|
||||||
"warn",
|
|
||||||
2
|
|
||||||
],
|
|
||||||
"@stylistic/semi": [
|
|
||||||
"warn",
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"@stylistic/quotes": [
|
|
||||||
"warn",
|
|
||||||
"single",
|
|
||||||
{
|
|
||||||
"allowTemplateLiterals": "always"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@stylistic/member-delimiter-style": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"multiline": {
|
|
||||||
"delimiter": "semi",
|
|
||||||
"requireLast": true
|
|
||||||
},
|
|
||||||
"singleline": {
|
|
||||||
"delimiter": "comma",
|
|
||||||
"requireLast": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@stylistic/type-annotation-spacing": "warn",
|
|
||||||
"@stylistic/keyword-spacing": "warn",
|
|
||||||
"@stylistic/max-len": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"code": 1000,
|
|
||||||
"comments": 80,
|
|
||||||
"ignoreUrls": true,
|
|
||||||
"ignorePattern": "^ *(?<ps_description>\\* Ps=)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@stylistic/no-extra-semi": "error",
|
|
||||||
"@stylistic/no-trailing-spaces": "warn",
|
|
||||||
"eslint-js/object-curly-spacing": [
|
|
||||||
"warn",
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"@stylistic/spaced-comment": [
|
|
||||||
"warn",
|
|
||||||
"always",
|
|
||||||
{
|
|
||||||
"markers": [
|
|
||||||
"/"
|
|
||||||
],
|
|
||||||
"exceptions": [
|
|
||||||
"-"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@stylistic/comma-dangle": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"objects": "never",
|
|
||||||
"arrays": "never",
|
|
||||||
"functions": "never"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@stylistic/eol-last": "warn",
|
|
||||||
"curly": [
|
|
||||||
"warn",
|
|
||||||
"multi-line"
|
|
||||||
],
|
|
||||||
"eqeqeq": [
|
|
||||||
"warn",
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"jsdoc-js/check-alignment": "warn",
|
|
||||||
"jsdoc-js/check-param-names": "warn",
|
|
||||||
"no-irregular-whitespace": "warn",
|
|
||||||
"typescript/array-type": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"default": "array",
|
|
||||||
"readonly": "generic"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"typescript/explicit-function-return-type": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"allowExpressions": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"typescript/prefer-namespace-keyword": "warn"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Vendored
+3
@@ -15,6 +15,9 @@
|
|||||||
"--recursive",
|
"--recursive",
|
||||||
"${workspaceRoot}/out/**/*.test.js"
|
"${workspaceRoot}/out/**/*.test.js"
|
||||||
],
|
],
|
||||||
|
"env": {
|
||||||
|
"NODE_PATH": "${workspaceRoot}/out"
|
||||||
|
},
|
||||||
"sourceMaps": true,
|
"sourceMaps": true,
|
||||||
"outFiles": [ "${workspaceRoot}/out/**/*.js" ],
|
"outFiles": [ "${workspaceRoot}/out/**/*.js" ],
|
||||||
"internalConsoleOptions": "openOnSessionStart"
|
"internalConsoleOptions": "openOnSessionStart"
|
||||||
|
|||||||
@@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
## Architecture Overview
|
## Architecture Overview
|
||||||
|
|
||||||
**Core Structure**: xterm.js is a multi-target terminal emulator with three main distributions:
|
**Core Structure**: xterm.js is a multi-target terminal emulator with these main source areas:
|
||||||
- `src/browser/`: Full-featured browser terminal with DOM rendering
|
- `src/primitives/`: Building blocks (buffer, parser, input, data, utilities); TypeScript project `src/primitives/tsconfig.json`
|
||||||
- `src/headless/`: Server-side terminal for Node.js (no DOM)
|
- `src/runtime/`: Services, `CoreTerminal`, `InputHandler`, public API adapters; TypeScript project `src/runtime/tsconfig.json`
|
||||||
- `src/common/`: Shared core logic (parsing, buffer management, terminal state)
|
- `src/target-browser/`: Browser terminal with DOM rendering
|
||||||
|
- `src/target-headless/`: Node terminal without DOM
|
||||||
|
|
||||||
|
See `src/ARCHITECTURE.md` for the dependency graph and import-path conventions (`common/*`, `target-browser/*`, `target-headless/*`).
|
||||||
|
|
||||||
**Key Classes**:
|
**Key Classes**:
|
||||||
- `Terminal` (browser/headless): Public API wrapper
|
- `Terminal` (browser/headless): Public API wrapper
|
||||||
@@ -26,7 +29,6 @@ npm run build && npm run esbuild # Build all TypeScript and bundle
|
|||||||
- Integration tests: `npm run test-integration` (Playwright across Chrome/Firefox/WebKit)
|
- Integration tests: `npm run test-integration` (Playwright across Chrome/Firefox/WebKit)
|
||||||
- Integration tests by file: `npm run test-integration -- test/playwright/InputHandler.test.ts`. Never use grep to filter tests, it doesn't work
|
- Integration tests by file: `npm run test-integration -- test/playwright/InputHandler.test.ts`. Never use grep to filter tests, it doesn't work
|
||||||
- Integration tests by addon: `npm run test-integration -- --suite=addon-search`. Suites always follow the format `addon-<something>`
|
- Integration tests by addon: `npm run test-integration -- --suite=addon-search`. Suites always follow the format `addon-<something>`
|
||||||
- Lint: `npm run lint` (oxlint with type-aware rules, then ESLint for `naming-convention` only), `npm run lint-api` for `typings/`, `npm run lint-fix` for oxlint auto-fix
|
|
||||||
- Lint changes: `npm run lint-changes` to lint only changed files, `npm run lint-changes-fix` to fix them
|
- Lint changes: `npm run lint-changes` to lint only changed files, `npm run lint-changes-fix` to fix them
|
||||||
|
|
||||||
## Addon Development Pattern
|
## Addon Development Pattern
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ The preferred way to report bugs or request features is to use
|
|||||||
|
|
||||||
It's pretty common for maintainers of large open source projects to suffer from burnout, especially when needing to triage a large number of incoming issues instead of actually building things. Here are some of the steps we take to try mitigate this:
|
It's pretty common for maintainers of large open source projects to suffer from burnout, especially when needing to triage a large number of incoming issues instead of actually building things. Here are some of the steps we take to try mitigate this:
|
||||||
|
|
||||||
- Support questions live in [GH discussions](https://github.com/xtermjs/xterm.js/discussions), issues may be transferred there without further comment and core maintainers may or may not participate in discussions.
|
- Support questions live in [GH discussions](https://github.com/xtermjs/xterm.js/discussions), issues may be transfered there without further comment and core maintainers may or may not participate in discussions.
|
||||||
- Issues are strictly for well defined features or bugs that are _actionable_.
|
- Issues are strictly for well defined features or bugs that are _actionable_.
|
||||||
- Sometimes features are out of scope. A common example of this is a niche feature that the pricipal implementation ([VS Code](https://code.visualstudio.com/)) won't leverage and therefore would be difficult to maintain and likely suffer from bitrot. The reporter may not agree with this, but you could always create an addon if that works or maintain your own fork if it comes to that.
|
- Sometimes features are out of scope. A common example of this is a niche feature that the pricipal implementation ([VS Code](https://code.visualstudio.com/)) won't leverage and therefore would be difficult to maintain and likely suffer from bitrot. The reporter may not agree with this, but you could always create an addon if that works or maintain your own fork if it comes to that.
|
||||||
- If a feature does not have a clear way forward or needs more discussion it may be closed ro moved to a discussion.
|
- If a feature does not have a clear way forward or needs more discussion it may be closed ro moved to a discussion.
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ test.beforeAll(async ({ browser }) => {
|
|||||||
});
|
});
|
||||||
test.afterAll(async () => await ctx.page.close());
|
test.afterAll(async () => await ctx.page.close());
|
||||||
|
|
||||||
test.describe('AttachAddon', () => {
|
test.describe('Search Tests', () => {
|
||||||
|
|
||||||
test.beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
await ctx.proxy.reset();
|
await ctx.proxy.reset();
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"*": [
|
"*": [
|
||||||
"./*"
|
"./*"
|
||||||
@@ -31,10 +32,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../test/playwright"
|
"path": "../../../test/playwright"
|
||||||
|
|||||||
@@ -78,43 +78,13 @@ export class BrowserClipboardProvider implements IClipboardProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Once the base64 handling on Uint8Arrays is more common,
|
|
||||||
* remove the btoa/atob fallbacks below.
|
|
||||||
*/
|
|
||||||
interface IUint8ArrayB64 extends Uint8Array {
|
|
||||||
toBase64(): string;
|
|
||||||
}
|
|
||||||
interface IUint8ArrayB64Ctor extends Uint8ArrayConstructor {
|
|
||||||
fromBase64(s: string): IUint8ArrayB64;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Base64 implements IBase64 {
|
export class Base64 implements IBase64 {
|
||||||
public encodeText(data: string): string {
|
public encodeText(data: string): string {
|
||||||
const bytes = new TextEncoder().encode(data) as IUint8ArrayB64;
|
return btoa(data);
|
||||||
if (bytes.toBase64 !== undefined) {
|
|
||||||
return bytes.toBase64();
|
|
||||||
}
|
|
||||||
let bin = '';
|
|
||||||
for (let i = 0; i < bytes.length; i++) {
|
|
||||||
bin += String.fromCharCode(bytes[i]);
|
|
||||||
}
|
|
||||||
return btoa(bin);
|
|
||||||
}
|
}
|
||||||
public decodeText(data: string): string {
|
public decodeText(data: string): string {
|
||||||
if ((Uint8Array as IUint8ArrayB64Ctor).fromBase64 !== undefined) {
|
|
||||||
try {
|
|
||||||
return new TextDecoder().decode((Uint8Array as IUint8ArrayB64Ctor).fromBase64(data));
|
|
||||||
} catch {}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const bin = atob(data);
|
return atob(data);
|
||||||
const bytes = new Uint8Array(bin.length);
|
|
||||||
for (let i = 0; i < bin.length; ++i) {
|
|
||||||
bytes[i] = bin.charCodeAt(i);
|
|
||||||
}
|
|
||||||
return new TextDecoder().decode(bytes);
|
|
||||||
} catch {}
|
} catch {}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
"../../../node_modules/@types/mocha"
|
"../../../node_modules/@types/mocha"
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"@xterm/addon-clipboard": [
|
"@xterm/addon-clipboard": [
|
||||||
"../typings/addon-clipboard.d.ts"
|
"../typings/addon-clipboard.d.ts"
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ test.describe('ClipboardAddon', () => {
|
|||||||
await ctx.page.context().grantPermissions(['clipboard-read', 'clipboard-write']);
|
await ctx.page.context().grantPermissions(['clipboard-read', 'clipboard-write']);
|
||||||
}
|
}
|
||||||
await ctx.page.evaluate(`
|
await ctx.page.evaluate(`
|
||||||
window.term.reset();
|
window.term.reset()
|
||||||
window.clipboard?.dispose();
|
window.clipboard?.dispose();
|
||||||
window.clipboard = new ClipboardAddon();
|
window.clipboard = new ClipboardAddon();
|
||||||
window.term.loadAddon(window.clipboard);
|
window.term.loadAddon(window.clipboard);
|
||||||
@@ -92,22 +92,4 @@ test.describe('ClipboardAddon', () => {
|
|||||||
deepEqual(await ctx.page.evaluate(() => window.navigator.clipboard.readText()), '');
|
deepEqual(await ctx.page.evaluate(() => window.navigator.clipboard.readText()), '');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe('non-ASCII', () => {
|
|
||||||
const testDataEncoded = '4oKsbWzDpMO8dMOf';
|
|
||||||
const testDataDecoded = '€mläütß';
|
|
||||||
test('write simple string', async () => {
|
|
||||||
await ctx.proxy.write(`\x1b]52;c;${testDataEncoded}\x07`);
|
|
||||||
deepEqual(await ctx.page.evaluate(() => window.navigator.clipboard.readText()), testDataDecoded);
|
|
||||||
});
|
|
||||||
test('read simple string', async () => {
|
|
||||||
await ctx.page.evaluate(`
|
|
||||||
window.data2 = [];
|
|
||||||
window.term.onData(e => data2.push(e));
|
|
||||||
`);
|
|
||||||
await ctx.page.evaluate((d) => window.navigator.clipboard.writeText(d), testDataDecoded);
|
|
||||||
await ctx.proxy.write(`\x1b]52;c;?\x07`);
|
|
||||||
deepEqual(await ctx.page.evaluate('window.data2'), [`\x1b]52;c;${testDataEncoded}\x07`]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"*": [
|
"*": [
|
||||||
"./*"
|
"./*"
|
||||||
@@ -31,10 +32,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../test/playwright"
|
"path": "../../../test/playwright"
|
||||||
|
|||||||
+1
-1
@@ -82,7 +82,7 @@ declare module '@xterm/addon-clipboard' {
|
|||||||
/**
|
/**
|
||||||
* The clipboard provider interface that enables xterm.js to access the browser clipboard.
|
* The clipboard provider interface that enables xterm.js to access the browser clipboard.
|
||||||
*
|
*
|
||||||
* Note that this clipboard provider does not implement own cut buffers as xterm does,
|
* Note this this clipboard provider does not implement own cut buffers as xterm does,
|
||||||
* but redirect the selection parameter always to navigator.clipboard.
|
* but redirect the selection parameter always to navigator.clipboard.
|
||||||
*/
|
*/
|
||||||
export class BrowserClipboardProvider implements IClipboardProvider{
|
export class BrowserClipboardProvider implements IClipboardProvider{
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import type { Terminal, ITerminalAddon, IRenderDimensions } from '@xterm/xterm';
|
import type { Terminal, ITerminalAddon, IRenderDimensions } from '@xterm/xterm';
|
||||||
import type { FitAddon as IFitApi } from '@xterm/addon-fit';
|
import type { FitAddon as IFitApi } from '@xterm/addon-fit';
|
||||||
import { ViewportConstants } from 'browser/shared/Constants';
|
import { ViewportConstants } from 'target-browser/shared/Constants';
|
||||||
|
|
||||||
interface ITerminalDimensions {
|
interface ITerminalDimensions {
|
||||||
/**
|
/**
|
||||||
@@ -74,14 +74,14 @@ export class FitAddon implements ITerminalAddon, IFitApi {
|
|||||||
: (this._terminal.options.scrollbar?.width ?? ViewportConstants.DEFAULT_SCROLL_BAR_WIDTH));
|
: (this._terminal.options.scrollbar?.width ?? ViewportConstants.DEFAULT_SCROLL_BAR_WIDTH));
|
||||||
|
|
||||||
const parentElementStyle = _getComputedStyle(this._terminal.element.parentElement);
|
const parentElementStyle = _getComputedStyle(this._terminal.element.parentElement);
|
||||||
const parentElementHeight = Math.max(0, parseInt(parentElementStyle.getPropertyValue('height'), 10) || 0);
|
const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));
|
||||||
const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width'), 10) || 0);
|
const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')));
|
||||||
const elementStyle = _getComputedStyle(this._terminal.element);
|
const elementStyle = _getComputedStyle(this._terminal.element);
|
||||||
const elementPadding = {
|
const elementPadding = {
|
||||||
top: parseInt(elementStyle.getPropertyValue('padding-top'), 10) || 0,
|
top: parseInt(elementStyle.getPropertyValue('padding-top')),
|
||||||
bottom: parseInt(elementStyle.getPropertyValue('padding-bottom'), 10) || 0,
|
bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')),
|
||||||
right: parseInt(elementStyle.getPropertyValue('padding-right'), 10) || 0,
|
right: parseInt(elementStyle.getPropertyValue('padding-right')),
|
||||||
left: parseInt(elementStyle.getPropertyValue('padding-left'), 10) || 0
|
left: parseInt(elementStyle.getPropertyValue('padding-left'))
|
||||||
};
|
};
|
||||||
const elementPaddingVer = elementPadding.top + elementPadding.bottom;
|
const elementPaddingVer = elementPadding.top + elementPadding.bottom;
|
||||||
const elementPaddingHor = elementPadding.right + elementPadding.left;
|
const elementPaddingHor = elementPadding.right + elementPadding.left;
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
"../../../node_modules/@types/mocha"
|
"../../../node_modules/@types/mocha"
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"@xterm/addon-fit": [
|
"@xterm/addon-fit": [
|
||||||
"../typings/addon-fit.d.ts"
|
"../typings/addon-fit.d.ts"
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"*": [
|
"*": [
|
||||||
"./*"
|
"./*"
|
||||||
@@ -31,10 +32,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../test/playwright"
|
"path": "../../../test/playwright"
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ terminal.loadAddon(imageAddon);
|
|||||||
therefore palette animations cannot be used.
|
therefore palette animations cannot be used.
|
||||||
|
|
||||||
- **SIXEL Raster Attributes Handling**
|
- **SIXEL Raster Attributes Handling**
|
||||||
If raster attributes were found in the SIXEL data (level 2), the image will always be truncated to the given height/width extent. We deviate here from the specification on purpose, as it allows several processing optimizations. For level 1 SIXEL data without any raster attributes the image can freely grow in width and height up to the last data byte, which has a much higher processing penalty. In general encoding libraries should not create level 1 data anymore and should not produce pixel information beyond the announced height/width extent. Both is discouraged by the >30 years old specification.
|
If raster attributes were found in the SIXEL data (level 2), the image will always be truncated to the given height/width extend. We deviate here from the specification on purpose, as it allows several processing optimizations. For level 1 SIXEL data without any raster attributes the image can freely grow in width and height up to the last data byte, which has a much higher processing penalty. In general encoding libraries should not create level 1 data anymore and should not produce pixel information beyond the announced height/width extend. Both is discouraged by the >30 years old specification.
|
||||||
|
|
||||||
Currently the SIXEL implementation of the addon does not take custom pixel sizes into account, a SIXEL pixel will map 1:1 to a screen pixel.
|
Currently the SIXEL implementation of the addon does not take custom pixel sizes into account, a SIXEL pixel will map 1:1 to a screen pixel.
|
||||||
|
|
||||||
@@ -149,9 +149,9 @@ The addon provides the following API endpoints to retrieve raw image data as can
|
|||||||
|
|
||||||
### Memory Usage
|
### Memory Usage
|
||||||
|
|
||||||
The addon does most image processing in JavaScript and therefore can occupy a rather big amount of memory. To get an idea where the memory gets eaten, let's look at the data flow and processing steps:
|
The addon does most image processing in Javascript and therefore can occupy a rather big amount of memory. To get an idea where the memory gets eaten, lets look at the data flow and processing steps:
|
||||||
- Incoming image data chunk at `term.write` (terminal)
|
- Incomming image data chunk at `term.write` (terminal)
|
||||||
`term.write` might stack up incoming chunks. To circumvent this, you will need proper flow control (see xterm.js docs). Note that with image output it is more likely to run into this issue, as it can create lots of MBs in very short time.
|
`term.write` might stock up incoming chunks. To circumvent this, you will need proper flow control (see xterm.js docs). Note that with image output it is more likely to run into this issue, as it can create lots of MBs in very short time.
|
||||||
- Sequence Parser (terminal)
|
- Sequence Parser (terminal)
|
||||||
The parser operates on a buffer containing up to 2^17 codepoints (~0.5 MB).
|
The parser operates on a buffer containing up to 2^17 codepoints (~0.5 MB).
|
||||||
- Sequence Handler - Chunk Decoding (addon)
|
- Sequence Handler - Chunk Decoding (addon)
|
||||||
@@ -177,18 +177,18 @@ const totalActive = storageBytes + decodingBytes;
|
|||||||
```
|
```
|
||||||
|
|
||||||
Note that browsers have offloading tricks for rarely touched memory segments, esp. `storageBytes` might not directly translate into real memory usage. Usage peaks will happen during active decoding of multiple big images due to the need of 2 full pixel buffers at the same time, which cannot be offloaded. Thus you may want to keep an eye on `pixelLimit` under limited memory conditions.
|
Note that browsers have offloading tricks for rarely touched memory segments, esp. `storageBytes` might not directly translate into real memory usage. Usage peaks will happen during active decoding of multiple big images due to the need of 2 full pixel buffers at the same time, which cannot be offloaded. Thus you may want to keep an eye on `pixelLimit` under limited memory conditions.
|
||||||
Further note that the formulas above do not respect the JavaScript object's overhead. Compared to the raw buffer needs the bookkeeping by these objects is rather small (<<5%).
|
Further note that the formulas above do not respect the Javascript object's overhead. Compared to the raw buffer needs the book keeping by these objects is rather small (<<5%).
|
||||||
|
|
||||||
_Why should I care about memory usage at all?_
|
_Why should I care about memory usage at all?_
|
||||||
Well you don't have to, and it probably will just work fine with the addon defaults. But for bigger integrations, where much more data is held in the JavaScript context (like multiple terminals on one page), it is likely to hit the engine's memory limit sooner or later under decoding and/or storage pressure.
|
Well you don't have to, and it probably will just work fine with the addon defaults. But for bigger integrations, where much more data is held in the Javascript context (like multiple terminals on one page), it is likely to hit the engine's memory limit sooner or later under decoding and/or storage pressure.
|
||||||
|
|
||||||
_How can I adjust the memory usage?_
|
_How can I adjust the memory usage?_
|
||||||
- `pixelLimit`
|
- `pixelLimit`
|
||||||
A constructor setting, thus you would have to anticipate, whether (multiple) terminals in your page gonna do lots of concurrent decoding. Since this is normally not the case and the memory usage only peaks temporarily, a rather high value should work even with multiple terminals in one page.
|
A constructor setting, thus you would have to anticipate, whether (multiple) terminals in your page gonna do lots of concurrent decoding. Since this is normally not the case and the memory usage is only temporarily peaking, a rather high value should work even with multiple terminals in one page.
|
||||||
- `storageLimit`
|
- `storageLimit`
|
||||||
A constructor and a runtime setting. In conjunction with `storageUsage` you can do runtime checks and adjust the limit to your needs. If you have to lower the limit below the current usage, images will be removed in FIFO order and may turn into a placeholder in the terminal's scrollback (if `showPlaceholder` is set). When adjusting keep in mind to leave enough room for peak memory use during decoding.
|
A constructor and a runtime setting. In conjunction with `storageUsage` you can do runtime checks and adjust the limit to your needs. If you have to lower the limit below the current usage, images will be removed in FIFO order and may turn into a placeholder in the terminal's scrollback (if `showPlaceholder` is set). When adjusting keep in mind to leave enough room for memory peaking for decoding.
|
||||||
- `sixelSizeLimit | iipSizeLimit | kittySizeLimit`
|
- `sixelSizeLimit | iipSizeLimit | kittySizeLimit`
|
||||||
Constructor settings. This has only a small impact on peak memory during decoding. It is meant to avoid processing of overly big or broken image sequences at an earlier phase, thus may stop the invoked decoders from entering memory intensive tasks for potentially invalid data.
|
Constructor settings. This has only a small impact on peaking memory during decoding. It is meant to avoid processing of overly big or broken image sequences at an earlier phase, thus may stop the invoked decoders from entering memory intensive tasks for potentially invalid data.
|
||||||
|
|
||||||
|
|
||||||
### Terminal Interaction
|
### Terminal Interaction
|
||||||
|
|||||||
@@ -222,8 +222,8 @@ export class IIPHandler implements IOscHandler, IResetHandler {
|
|||||||
|
|
||||||
private _dim(s: string, total: number, cdim: number): number {
|
private _dim(s: string, total: number, cdim: number): number {
|
||||||
if (s === 'auto') return 0;
|
if (s === 'auto') return 0;
|
||||||
if (s.endsWith('%')) return parseInt(s.slice(0, -1), 10) * total / 100;
|
if (s.endsWith('%')) return parseInt(s.slice(0, -1)) * total / 100;
|
||||||
if (s.endsWith('px')) return parseInt(s.slice(0, -2), 10);
|
if (s.endsWith('px')) return parseInt(s.slice(0, -2));
|
||||||
return parseInt(s, 10) * cdim;
|
return parseInt(s) * cdim;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IAddImageOpts } from './Types';
|
import { IAddImageOpts } from 'Types';
|
||||||
import { ImageStorage } from './ImageStorage';
|
import { ImageStorage } from './ImageStorage';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -436,9 +436,9 @@ export class ImageStorage implements IDisposable {
|
|||||||
for (let col = 0; col < cols; ++col) {
|
for (let col = 0; col < cols; ++col) {
|
||||||
let e: IExtendedAttrsImage;
|
let e: IExtendedAttrsImage;
|
||||||
if (line.getBg(col) & BgFlags.HAS_EXTENDED) {
|
if (line.getBg(col) & BgFlags.HAS_EXTENDED) {
|
||||||
e = line._extendedAttrs?.[col] ?? EMPTY_ATTRS;
|
e = line._extendedAttrs[col] ?? EMPTY_ATTRS;
|
||||||
} else {
|
} else {
|
||||||
const maybeImg = line._extendedAttrs?.[col] as IExtendedAttrsImage | undefined;
|
const maybeImg = line._extendedAttrs[col] as IExtendedAttrsImage | undefined;
|
||||||
if (!maybeImg || maybeImg.imageId === undefined || maybeImg.imageId === -1) {
|
if (!maybeImg || maybeImg.imageId === undefined || maybeImg.imageId === -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -461,7 +461,7 @@ export class ImageStorage implements IDisposable {
|
|||||||
* Also check _extendedAttrs directly for cells where text cleared HAS_EXTENDED.
|
* Also check _extendedAttrs directly for cells where text cleared HAS_EXTENDED.
|
||||||
*/
|
*/
|
||||||
while (++col < cols) {
|
while (++col < cols) {
|
||||||
const nextE = line._extendedAttrs?.[col] as IExtendedAttrsImage | undefined;
|
const nextE = line._extendedAttrs[col] as IExtendedAttrsImage | undefined;
|
||||||
if (!nextE || nextE.imageId !== imageId || nextE.tileId !== startTile + count) {
|
if (!nextE || nextE.imageId !== imageId || nextE.tileId !== startTile + count) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -515,7 +515,7 @@ export class ImageStorage implements IDisposable {
|
|||||||
for (let row = 0; row < rows; ++row) {
|
for (let row = 0; row < rows; ++row) {
|
||||||
const line = buffer.lines.get(row) as IBufferLineExt;
|
const line = buffer.lines.get(row) as IBufferLineExt;
|
||||||
if (line.getBg(oldCol) & BgFlags.HAS_EXTENDED) {
|
if (line.getBg(oldCol) & BgFlags.HAS_EXTENDED) {
|
||||||
const e: IExtendedAttrsImage = line._extendedAttrs?.[oldCol] ?? EMPTY_ATTRS;
|
const e: IExtendedAttrsImage = line._extendedAttrs[oldCol] ?? EMPTY_ATTRS;
|
||||||
const imageId = e.imageId;
|
const imageId = e.imageId;
|
||||||
if (imageId === undefined || imageId === -1) {
|
if (imageId === undefined || imageId === -1) {
|
||||||
continue;
|
continue;
|
||||||
@@ -560,7 +560,7 @@ export class ImageStorage implements IDisposable {
|
|||||||
const buffer = this._terminal._core.buffer;
|
const buffer = this._terminal._core.buffer;
|
||||||
const line = buffer.lines.get(y) as IBufferLineExt;
|
const line = buffer.lines.get(y) as IBufferLineExt;
|
||||||
if (line && line.getBg(x) & BgFlags.HAS_EXTENDED) {
|
if (line && line.getBg(x) & BgFlags.HAS_EXTENDED) {
|
||||||
const e: IExtendedAttrsImage = line._extendedAttrs?.[x] ?? EMPTY_ATTRS;
|
const e: IExtendedAttrsImage = line._extendedAttrs[x] ?? EMPTY_ATTRS;
|
||||||
if (e.imageId && e.imageId !== -1) {
|
if (e.imageId && e.imageId !== -1) {
|
||||||
const orig = this._images.get(e.imageId)?.orig;
|
const orig = this._images.get(e.imageId)?.orig;
|
||||||
if (window.ImageBitmap && orig instanceof ImageBitmap) {
|
if (window.ImageBitmap && orig instanceof ImageBitmap) {
|
||||||
@@ -580,7 +580,7 @@ export class ImageStorage implements IDisposable {
|
|||||||
const buffer = this._terminal._core.buffer;
|
const buffer = this._terminal._core.buffer;
|
||||||
const line = buffer.lines.get(y) as IBufferLineExt;
|
const line = buffer.lines.get(y) as IBufferLineExt;
|
||||||
if (line && line.getBg(x) & BgFlags.HAS_EXTENDED) {
|
if (line && line.getBg(x) & BgFlags.HAS_EXTENDED) {
|
||||||
const e: IExtendedAttrsImage = line._extendedAttrs?.[x] ?? EMPTY_ATTRS;
|
const e: IExtendedAttrsImage = line._extendedAttrs[x] ?? EMPTY_ATTRS;
|
||||||
if (e.imageId && e.imageId !== -1 && e.tileId !== -1) {
|
if (e.imageId && e.imageId !== -1 && e.tileId !== -1) {
|
||||||
const spec = this._images.get(e.imageId);
|
const spec = this._images.get(e.imageId);
|
||||||
if (spec) {
|
if (spec) {
|
||||||
@@ -611,7 +611,7 @@ export class ImageStorage implements IDisposable {
|
|||||||
|
|
||||||
private _writeToCell(line: IBufferLineExt, x: number, imageId: number, tileId: number): void {
|
private _writeToCell(line: IBufferLineExt, x: number, imageId: number, tileId: number): void {
|
||||||
if (line._data[x * Cell.SIZE + Cell.BG] & BgFlags.HAS_EXTENDED) {
|
if (line._data[x * Cell.SIZE + Cell.BG] & BgFlags.HAS_EXTENDED) {
|
||||||
const old = line._extendedAttrs?.[x];
|
const old = line._extendedAttrs[x];
|
||||||
if (old) {
|
if (old) {
|
||||||
if (old.imageId !== undefined) {
|
if (old.imageId !== undefined) {
|
||||||
// found an old ExtendedAttrsImage, since we know that
|
// found an old ExtendedAttrsImage, since we know that
|
||||||
@@ -627,13 +627,13 @@ export class ImageStorage implements IDisposable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// found a plain ExtendedAttrs instance, clone it to new entry
|
// found a plain ExtendedAttrs instance, clone it to new entry
|
||||||
(line._extendedAttrs ??= {})[x] = new ExtendedAttrsImage(old.ext, old.urlId, imageId, tileId);
|
line._extendedAttrs[x] = new ExtendedAttrsImage(old.ext, old.urlId, imageId, tileId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// fall-through: always create new ExtendedAttrsImage entry
|
// fall-through: always create new ExtendedAttrsImage entry
|
||||||
line._data[x * Cell.SIZE + Cell.BG] |= BgFlags.HAS_EXTENDED;
|
line._data[x * Cell.SIZE + Cell.BG] |= BgFlags.HAS_EXTENDED;
|
||||||
(line._extendedAttrs ??= {})[x] = new ExtendedAttrsImage(0, 0, imageId, tileId);
|
line._extendedAttrs[x] = new ExtendedAttrsImage(0, 0, imageId, tileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _evictOnAlternate(): void {
|
private _evictOnAlternate(): void {
|
||||||
@@ -652,7 +652,7 @@ export class ImageStorage implements IDisposable {
|
|||||||
}
|
}
|
||||||
for (let x = 0; x < this._terminal.cols; ++x) {
|
for (let x = 0; x < this._terminal.cols; ++x) {
|
||||||
if (line._data[x * Cell.SIZE + Cell.BG] & BgFlags.HAS_EXTENDED) {
|
if (line._data[x * Cell.SIZE + Cell.BG] & BgFlags.HAS_EXTENDED) {
|
||||||
const imgId = line._extendedAttrs?.[x]?.imageId;
|
const imgId = line._extendedAttrs[x]?.imageId;
|
||||||
if (imgId) {
|
if (imgId) {
|
||||||
const spec = this._images.get(imgId);
|
const spec = this._images.get(imgId);
|
||||||
if (spec) {
|
if (spec) {
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ import { IDisposable, IMarker, Terminal } from '@xterm/xterm';
|
|||||||
import { Attributes, BgFlags, Content, ExtFlags, UnderlineStyle } from 'common/buffer/Constants';
|
import { Attributes, BgFlags, Content, ExtFlags, UnderlineStyle } from 'common/buffer/Constants';
|
||||||
import type { AttributeData } from 'common/buffer/AttributeData';
|
import type { AttributeData } from 'common/buffer/AttributeData';
|
||||||
import type { IParams, IDcsHandler, IOscHandler, IApcHandler, IEscapeSequenceParser } from 'common/parser/Types';
|
import type { IParams, IDcsHandler, IOscHandler, IApcHandler, IEscapeSequenceParser } from 'common/parser/Types';
|
||||||
import type { IInputHandler } from 'common/Types';
|
import type { IBufferLine, IExtendedAttrs, IInputHandler } from 'common/Types';
|
||||||
import type { IBufferLine, IExtendedAttrs } from 'common/buffer/Types';
|
import type { ITerminal, ReadonlyColorSet } from 'target-browser/Types';
|
||||||
import type { ITerminal, ReadonlyColorSet } from 'browser/Types';
|
import type { IRenderDimensions } from 'target-browser/renderer/shared/Types';
|
||||||
import type { IRenderDimensions } from 'browser/renderer/shared/Types';
|
import type { ICoreBrowserService, IRenderService, IThemeService } from 'target-browser/services/Services';
|
||||||
import type { ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services';
|
|
||||||
|
|
||||||
export const enum Cell {
|
export const enum Cell {
|
||||||
CONTENT = 0, // codepoint and wcwidth information (enum Content)
|
CONTENT = 0, // codepoint and wcwidth information (enum Content)
|
||||||
@@ -64,7 +63,7 @@ export interface IExtendedAttrsImage extends IExtendedAttrs {
|
|||||||
|
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export interface IBufferLineExt extends IBufferLine {
|
export interface IBufferLineExt extends IBufferLine {
|
||||||
_extendedAttrs: {[index: number]: IExtendedAttrsImage | undefined} | undefined;
|
_extendedAttrs: {[index: number]: IExtendedAttrsImage | undefined};
|
||||||
_data: Uint32Array;
|
_data: Uint32Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ export function parseKittyCommand(data: string): IKittyCommand {
|
|||||||
cmd.deleteSelector = value;
|
cmd.deleteSelector = value;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const numValue = parseInt(value, 10);
|
const numValue = parseInt(value);
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case KittyKey.FORMAT: cmd.format = numValue; break;
|
case KittyKey.FORMAT: cmd.format = numValue; break;
|
||||||
case KittyKey.ID: cmd.id = numValue; break;
|
case KittyKey.ID: cmd.id = numValue; break;
|
||||||
|
|||||||
@@ -12,8 +12,11 @@
|
|||||||
"../../../node_modules/@types/mocha"
|
"../../../node_modules/@types/mocha"
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"browser/*": [ "../../../src/browser/*" ],
|
"target-browser/*": [ "../../../src/target-browser/*" ],
|
||||||
"common/*": [ "../../../src/common/*" ],
|
"common/*": [
|
||||||
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
|
],
|
||||||
"@xterm/addon-image": [ "../typings/addon-image.d.ts" ],
|
"@xterm/addon-image": [ "../typings/addon-image.d.ts" ],
|
||||||
"*": [ "./*" ]
|
"*": [ "./*" ]
|
||||||
}
|
}
|
||||||
@@ -23,7 +26,7 @@
|
|||||||
"../../../typings/xterm.d.ts"
|
"../../../typings/xterm.d.ts"
|
||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../../../src/browser" },
|
{ "path": "../../../src/target-browser" },
|
||||||
{ "path": "../../../src/common" }
|
{ "path": "../../../src" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,10 +118,7 @@ test.describe('ImageAddon', () => {
|
|||||||
}
|
}
|
||||||
// bufferline privates
|
// bufferline privates
|
||||||
strictEqual(await ctx.page.evaluate('window.term._core.buffer.lines.get(0)._data instanceof Uint32Array'), true);
|
strictEqual(await ctx.page.evaluate('window.term._core.buffer.lines.get(0)._data instanceof Uint32Array'), true);
|
||||||
strictEqual(await ctx.page.evaluate(`(() => {
|
strictEqual(await ctx.page.evaluate('window.term._core.buffer.lines.get(0)._extendedAttrs instanceof Object'), true);
|
||||||
const ea = window.term._core.buffer.lines.get(0)._extendedAttrs;
|
|
||||||
return ea === undefined || (typeof ea === 'object' && ea !== null);
|
|
||||||
})()`), true);
|
|
||||||
// inputhandler privates
|
// inputhandler privates
|
||||||
strictEqual(await ctx.page.evaluate('window.term._core._inputHandler._curAttrData.constructor.name'), '_AttributeData');
|
strictEqual(await ctx.page.evaluate('window.term._core._inputHandler._curAttrData.constructor.name'), '_AttributeData');
|
||||||
strictEqual(await ctx.page.evaluate('window.term._core._inputHandler._parser.constructor.name'), 'EscapeSequenceParser');
|
strictEqual(await ctx.page.evaluate('window.term._core._inputHandler._parser.constructor.name'), 'EscapeSequenceParser');
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"*": [
|
"*": [
|
||||||
"./*"
|
"./*"
|
||||||
@@ -31,10 +32,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../test/playwright"
|
"path": "../../../test/playwright"
|
||||||
|
|||||||
@@ -25,8 +25,11 @@ const addon = {
|
|||||||
modules: ['./node_modules'],
|
modules: ['./node_modules'],
|
||||||
extensions: [ '.js' ],
|
extensions: [ '.js' ],
|
||||||
alias: {
|
alias: {
|
||||||
common: path.resolve('../../out/common'),
|
common: [
|
||||||
browser: path.resolve('../../out/browser'),
|
path.resolve('../../out/runtime'),
|
||||||
|
path.resolve('../../out/primitives'),
|
||||||
|
],
|
||||||
|
browser: path.resolve('../../out/target-browser'),
|
||||||
vs: path.resolve('../../out/vs')
|
vs: path.resolve('../../out/vs')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const CACHE_SIZE = 100000;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable ligature support for the provided Terminal instance. To function
|
* Enable ligature support for the provided Terminal instance. To function
|
||||||
* properly, this must be called after `open()` is called on the terminal. If
|
* properly, this must be called after `open()` is called on the therminal. If
|
||||||
* the font currently in use supports ligatures, the terminal will automatically
|
* the font currently in use supports ligatures, the terminal will automatically
|
||||||
* start to render them.
|
* start to render them.
|
||||||
* @param term Terminal instance from xterm.js
|
* @param term Terminal instance from xterm.js
|
||||||
|
|||||||
@@ -16,10 +16,11 @@
|
|||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"@xterm/addon-progress": [
|
"@xterm/addon-progress": [
|
||||||
"../typings/addon-progress.d.ts"
|
"../typings/addon-progress.d.ts"
|
||||||
@@ -32,10 +33,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"*": [
|
"*": [
|
||||||
"./*"
|
"./*"
|
||||||
@@ -31,10 +32,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../test/playwright"
|
"path": "../../../test/playwright"
|
||||||
|
|||||||
@@ -25,8 +25,11 @@ module.exports = {
|
|||||||
modules: ['./node_modules'],
|
modules: ['./node_modules'],
|
||||||
extensions: [ '.js' ],
|
extensions: [ '.js' ],
|
||||||
alias: {
|
alias: {
|
||||||
common: path.resolve('../../out/common'),
|
common: [
|
||||||
browser: path.resolve('../../out/browser'),
|
path.resolve('../../out/runtime'),
|
||||||
|
path.resolve('../../out/primitives'),
|
||||||
|
],
|
||||||
|
browser: path.resolve('../../out/target-browser'),
|
||||||
vs: path.resolve('../../out/vs')
|
vs: path.resolve('../../out/vs')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2026 The xterm.js authors. All rights reserved.
|
|
||||||
* @license MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { assert } from 'chai';
|
|
||||||
import { DecorationManager } from './DecorationManager';
|
|
||||||
import { SearchEngine } from './SearchEngine';
|
|
||||||
import { SearchLineCache } from './SearchLineCache';
|
|
||||||
import { Terminal } from 'browser/public/Terminal';
|
|
||||||
import type { ISearchDecorationOptions } from '@xterm/addon-search';
|
|
||||||
import type { IDecorationOptions } from '@xterm/xterm';
|
|
||||||
import { DisposableStore } from 'common/Lifecycle';
|
|
||||||
|
|
||||||
function writeP(terminal: Terminal, data: string): Promise<void> {
|
|
||||||
return new Promise(r => terminal.write(data, r));
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('DecorationManager', () => {
|
|
||||||
let store: DisposableStore;
|
|
||||||
let terminal: Terminal;
|
|
||||||
let decorationManager: DecorationManager;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
store = new DisposableStore();
|
|
||||||
terminal = store.add(new Terminal({ cols: 10, rows: 5 }));
|
|
||||||
decorationManager = store.add(new DecorationManager(terminal));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should split highlight decorations for a wrapped match', async () => {
|
|
||||||
await writeP(terminal, '0123456789abcde');
|
|
||||||
const searchEngine = new SearchEngine(terminal, store.add(new SearchLineCache(terminal)));
|
|
||||||
const match = searchEngine.find('9abc', 0, 0);
|
|
||||||
assert.ok(match);
|
|
||||||
|
|
||||||
const decorationOptions: IDecorationOptions[] = [];
|
|
||||||
const registerDecoration = terminal.registerDecoration.bind(terminal);
|
|
||||||
terminal.registerDecoration = (options: IDecorationOptions) => {
|
|
||||||
decorationOptions.push(options);
|
|
||||||
return registerDecoration(options);
|
|
||||||
};
|
|
||||||
|
|
||||||
const options: ISearchDecorationOptions = {
|
|
||||||
matchOverviewRuler: '#ff0000',
|
|
||||||
activeMatchColorOverviewRuler: '#00ff00'
|
|
||||||
};
|
|
||||||
decorationManager.createHighlightDecorations([match], options);
|
|
||||||
|
|
||||||
assert.strictEqual(decorationOptions.length, 2);
|
|
||||||
assert.strictEqual(decorationOptions[0].x, 9);
|
|
||||||
assert.strictEqual(decorationOptions[0].width, 1);
|
|
||||||
assert.strictEqual(decorationOptions[1].x, 0);
|
|
||||||
assert.strictEqual(decorationOptions[1].width, 3);
|
|
||||||
|
|
||||||
const withOverviewRuler = decorationOptions.filter(o => o.overviewRulerOptions !== undefined);
|
|
||||||
assert.strictEqual(withOverviewRuler.length, 2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should only add one overview ruler marker per buffer line', async () => {
|
|
||||||
await writeP(terminal, 'abcdefghij');
|
|
||||||
const decorationOptions: IDecorationOptions[] = [];
|
|
||||||
const registerDecoration = terminal.registerDecoration.bind(terminal);
|
|
||||||
terminal.registerDecoration = (options: IDecorationOptions) => {
|
|
||||||
decorationOptions.push(options);
|
|
||||||
return registerDecoration(options);
|
|
||||||
};
|
|
||||||
|
|
||||||
const options: ISearchDecorationOptions = {
|
|
||||||
matchOverviewRuler: '#ff0000',
|
|
||||||
activeMatchColorOverviewRuler: '#00ff00'
|
|
||||||
};
|
|
||||||
decorationManager.createHighlightDecorations([
|
|
||||||
{ term: 'a', col: 0, row: 0, size: 1 },
|
|
||||||
{ term: 'f', col: 5, row: 0, size: 1 }
|
|
||||||
], options);
|
|
||||||
|
|
||||||
const withOverviewRuler = decorationOptions.filter(o => o.overviewRulerOptions !== undefined);
|
|
||||||
assert.strictEqual(withOverviewRuler.length, 1);
|
|
||||||
assert.strictEqual(withOverviewRuler[0].x, 0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { SearchEngine } from './SearchEngine';
|
import { SearchEngine } from './SearchEngine';
|
||||||
import { SearchLineCache } from './SearchLineCache';
|
import { SearchLineCache } from './SearchLineCache';
|
||||||
import { Terminal } from 'browser/public/Terminal';
|
import { Terminal } from 'target-browser/public/Terminal';
|
||||||
import type { ISearchOptions } from '@xterm/addon-search';
|
import type { ISearchOptions } from '@xterm/addon-search';
|
||||||
import { DisposableStore } from 'common/Lifecycle';
|
import { DisposableStore } from 'common/Lifecycle';
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export class SearchEngine {
|
|||||||
this._terminal.clearSelection();
|
this._terminal.clearSelection();
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
if (startCol >= this._terminal.cols) {
|
if (startCol > this._terminal.cols) {
|
||||||
throw new Error(`Invalid col: ${startCol} to search in terminal of ${this._terminal.cols} cols`);
|
throw new Error(`Invalid col: ${startCol} to search in terminal of ${this._terminal.cols} cols`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { SearchLineCache, LineCacheEntry } from './SearchLineCache';
|
import { SearchLineCache, LineCacheEntry } from './SearchLineCache';
|
||||||
import { Terminal } from 'browser/public/Terminal';
|
import { Terminal } from 'target-browser/public/Terminal';
|
||||||
import { timeout } from 'common/Async';
|
import { timeout } from 'common/Async';
|
||||||
|
|
||||||
function writeP(terminal: Terminal, data: string): Promise<void> {
|
function writeP(terminal: Terminal, data: string): Promise<void> {
|
||||||
|
|||||||
@@ -16,10 +16,11 @@
|
|||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"@xterm/addon-search" : [
|
"@xterm/addon-search" : [
|
||||||
"../typings/addon-search.d.ts"
|
"../typings/addon-search.d.ts"
|
||||||
@@ -32,10 +33,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -417,7 +417,7 @@ test.describe('Search Tests', () => {
|
|||||||
test.describe('#2444 wrapped line content not being found', () => {
|
test.describe('#2444 wrapped line content not being found', () => {
|
||||||
let fixture: string;
|
let fixture: string;
|
||||||
test.beforeAll(async () => {
|
test.beforeAll(async () => {
|
||||||
fixture = (await new Promise<Buffer>((res, rej) => readFile(resolve(__dirname, '../fixtures/issue-2444'), (err, data) => err ? rej(err) : res(data)))).toString();
|
fixture = (await new Promise<Buffer>(r => readFile(resolve(__dirname, '../fixtures/issue-2444'), (err, data) => r(data)))).toString();
|
||||||
if (process.platform !== 'win32') {
|
if (process.platform !== 'win32') {
|
||||||
fixture = fixture.replace(/\n/g, '\n\r');
|
fixture = fixture.replace(/\n/g, '\n\r');
|
||||||
}
|
}
|
||||||
@@ -501,7 +501,7 @@ test.describe('Search Tests', () => {
|
|||||||
window.search.onDidChangeResults(e => window.calls.push(e));
|
window.search.onDidChangeResults(e => window.calls.push(e));
|
||||||
`);
|
`);
|
||||||
// Move cursor forward 1 time to create a null character, as opposed to regular whitespace
|
// Move cursor forward 1 time to create a null character, as opposed to regular whitespace
|
||||||
await ctx.proxy.write('\x1b[CHi Hi');
|
await ctx.proxy.write('\\x1b[CHi Hi');
|
||||||
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('h', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
|
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('h', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
|
||||||
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
|
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
|
||||||
{ resultCount: 2, resultIndex: 1 }
|
{ resultCount: 2, resultIndex: 1 }
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"*": [
|
"*": [
|
||||||
"./*"
|
"./*"
|
||||||
@@ -31,10 +32,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../test/playwright"
|
"path": "../../../test/playwright"
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ module.exports = {
|
|||||||
modules: ['./node_modules'],
|
modules: ['./node_modules'],
|
||||||
extensions: [ '.js' ],
|
extensions: [ '.js' ],
|
||||||
alias: {
|
alias: {
|
||||||
common: path.resolve('../../out/common'),
|
common: [
|
||||||
|
path.resolve('../../out/runtime'),
|
||||||
|
path.resolve('../../out/primitives'),
|
||||||
|
],
|
||||||
vs: path.resolve('../../out/vs')
|
vs: path.resolve('../../out/vs')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { perfContext, before, ThroughputRuntimeCase } from 'xterm-benchmark';
|
|||||||
|
|
||||||
import { spawn } from 'node-pty';
|
import { spawn } from 'node-pty';
|
||||||
import { Utf8ToUtf32, stringFromCodePoint } from 'common/input/TextDecoder';
|
import { Utf8ToUtf32, stringFromCodePoint } from 'common/input/TextDecoder';
|
||||||
import { Terminal } from 'browser/public/Terminal';
|
import { Terminal } from 'target-browser/public/Terminal';
|
||||||
import { SerializeAddon } from 'SerializeAddon';
|
import { SerializeAddon } from 'SerializeAddon';
|
||||||
|
|
||||||
class TestTerminal extends Terminal {
|
class TestTerminal extends Terminal {
|
||||||
|
|||||||
@@ -12,8 +12,11 @@
|
|||||||
"target": "es2021",
|
"target": "es2021",
|
||||||
"module": "nodenext",
|
"module": "nodenext",
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": ["../../../src/common/*"],
|
"common/*": [
|
||||||
"browser/*": ["../../../src/browser/*"],
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
|
],
|
||||||
|
"target-browser/*": ["../../../src/target-browser/*"],
|
||||||
"SerializeAddon": ["../src/SerializeAddon"],
|
"SerializeAddon": ["../src/SerializeAddon"],
|
||||||
"@xterm/addon-serialize": [
|
"@xterm/addon-serialize": [
|
||||||
"../typings/addon-serialize.d.ts"
|
"../typings/addon-serialize.d.ts"
|
||||||
@@ -23,7 +26,7 @@
|
|||||||
"include": ["../**/*", "../../../typings/xterm.d.ts"],
|
"include": ["../**/*", "../../../typings/xterm.d.ts"],
|
||||||
"exclude": ["../../../**/*test.ts", "../../**/*api.ts"],
|
"exclude": ["../../../**/*test.ts", "../../**/*api.ts"],
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../../../src/common" },
|
{ "path": "../../../src" },
|
||||||
{ "path": "../../../src/browser" }
|
{ "path": "../../../src/target-browser" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
"package": "../../node_modules/.bin/webpack",
|
"package": "../../node_modules/.bin/webpack",
|
||||||
"prepublishOnly": "npm run package",
|
"prepublishOnly": "npm run package",
|
||||||
"start": "node ../../demo/start",
|
"start": "node ../../demo/start",
|
||||||
"benchmark": "../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json",
|
"benchmark": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json",
|
||||||
"benchmark-baseline": "../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --baseline out-benchmark/benchmark/*benchmark.js",
|
"benchmark-baseline": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --baseline out-benchmark/benchmark/*benchmark.js",
|
||||||
"benchmark-eval": "../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --eval out-benchmark/benchmark/*benchmark.js"
|
"benchmark-eval": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --eval out-benchmark/benchmark/*benchmark.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
import jsdom = require('jsdom');
|
import jsdom = require('jsdom');
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { SerializeAddon } from './SerializeAddon';
|
import { SerializeAddon } from './SerializeAddon';
|
||||||
import { Terminal } from 'browser/public/Terminal';
|
import { Terminal } from 'target-browser/public/Terminal';
|
||||||
import { SelectionModel } from 'browser/selection/SelectionModel';
|
import { SelectionModel } from 'target-browser/selection/SelectionModel';
|
||||||
import { IBufferService } from 'common/services/Services';
|
import { IBufferService } from 'common/services/Services';
|
||||||
import { ThemeService } from 'browser/services/ThemeService';
|
import { ThemeService } from 'target-browser/services/ThemeService';
|
||||||
|
|
||||||
function sgr(...seq: string[]): string {
|
function sgr(...seq: string[]): string {
|
||||||
return `\x1b[${seq.join(';')}m`;
|
return `\x1b[${seq.join(';')}m`;
|
||||||
|
|||||||
@@ -7,9 +7,8 @@
|
|||||||
|
|
||||||
import type { IBuffer, IBufferCell, IBufferRange, ITerminalAddon, Terminal } from '@xterm/xterm';
|
import type { IBuffer, IBufferCell, IBufferRange, ITerminalAddon, Terminal } from '@xterm/xterm';
|
||||||
import type { IHTMLSerializeOptions, SerializeAddon as ISerializeApi, ISerializeOptions, ISerializeRange } from '@xterm/addon-serialize';
|
import type { IHTMLSerializeOptions, SerializeAddon as ISerializeApi, ISerializeOptions, ISerializeRange } from '@xterm/addon-serialize';
|
||||||
import { IColor } from 'common/Types';
|
import { IAttributeData, IColor } from 'common/Types';
|
||||||
import { IAttributeData } from 'common/buffer/Types';
|
import { DEFAULT_ANSI_COLORS } from 'target-browser/Types';
|
||||||
import { DEFAULT_ANSI_COLORS } from 'browser/Types';
|
|
||||||
import { UnderlineStyle } from 'common/buffer/Constants';
|
import { UnderlineStyle } from 'common/buffer/Constants';
|
||||||
|
|
||||||
function constrain(value: number, low: number, high: number): number {
|
function constrain(value: number, low: number, high: number): number {
|
||||||
@@ -173,7 +172,7 @@ class StringSerializeHandler extends BaseSerializeHandler {
|
|||||||
private _thisRowLastSecondChar: IBufferCell = this._buffer.getNullCell();
|
private _thisRowLastSecondChar: IBufferCell = this._buffer.getNullCell();
|
||||||
private _nextRowFirstChar: IBufferCell = this._buffer.getNullCell();
|
private _nextRowFirstChar: IBufferCell = this._buffer.getNullCell();
|
||||||
protected _rowEnd(row: number, isLastRow: boolean): void {
|
protected _rowEnd(row: number, isLastRow: boolean): void {
|
||||||
// if there is colorful empty cell at line end, we must pad it back, or the color block
|
// if there is colorful empty cell at line end, whe must pad it back, or the the color block
|
||||||
// will missing
|
// will missing
|
||||||
if (this._nullCellCount > 0 && !equalBg(this._cursorStyle, this._backgroundCell)) {
|
if (this._nullCellCount > 0 && !equalBg(this._cursorStyle, this._backgroundCell)) {
|
||||||
// use clear right to set background.
|
// use clear right to set background.
|
||||||
@@ -221,7 +220,7 @@ class StringSerializeHandler extends BaseSerializeHandler {
|
|||||||
// you can't use control sequence to move cursor to (x === row)
|
// you can't use control sequence to move cursor to (x === row)
|
||||||
(thisRowLastChar.getChars() || thisRowLastChar.getWidth() === 0) &&
|
(thisRowLastChar.getChars() || thisRowLastChar.getWidth() === 0) &&
|
||||||
// change background of the first wrapped cell also affects BCE
|
// change background of the first wrapped cell also affects BCE
|
||||||
// so we mark it as invalid to simplify the process to determine line separator
|
// so we mark it as invalid to simply the process to determine line separator
|
||||||
equalBg(thisRowLastChar, nextRowFirstChar)
|
equalBg(thisRowLastChar, nextRowFirstChar)
|
||||||
) {
|
) {
|
||||||
isValid = true;
|
isValid = true;
|
||||||
@@ -233,7 +232,7 @@ class StringSerializeHandler extends BaseSerializeHandler {
|
|||||||
isNextRowFirstCharDoubleWidth &&
|
isNextRowFirstCharDoubleWidth &&
|
||||||
(thisRowLastSecondChar.getChars() || thisRowLastSecondChar.getWidth() === 0) &&
|
(thisRowLastSecondChar.getChars() || thisRowLastSecondChar.getWidth() === 0) &&
|
||||||
// change background of the first wrapped cell also affects BCE
|
// change background of the first wrapped cell also affects BCE
|
||||||
// so we mark it as invalid to simplify the process to determine line separator
|
// so we mark it as invalid to simply the process to determine line separator
|
||||||
equalBg(thisRowLastChar, nextRowFirstChar) &&
|
equalBg(thisRowLastChar, nextRowFirstChar) &&
|
||||||
equalBg(thisRowLastSecondChar, nextRowFirstChar)
|
equalBg(thisRowLastSecondChar, nextRowFirstChar)
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -12,10 +12,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"@xterm/addon-serialize": [
|
"@xterm/addon-serialize": [
|
||||||
"../typings/addon-serialize.d.ts"
|
"../typings/addon-serialize.d.ts"
|
||||||
@@ -33,10 +34,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ test.describe('SerializeAddon', () => {
|
|||||||
const cols = 10;
|
const cols = 10;
|
||||||
const line = '+'.repeat(cols);
|
const line = '+'.repeat(cols);
|
||||||
const lines: string[] = [
|
const lines: string[] = [
|
||||||
sgr(FG_P16_GREEN) + line, // Workaround: If we clear all flags at the end, serialize will use \x1b[0m to clear instead of the specific disable sequence
|
sgr(FG_P16_GREEN) + line, // Workaround: If we clear all flags a the end, serialize will use \x1b[0m to clear instead of the sepcific disable sequence
|
||||||
sgr(INVERSE) + line,
|
sgr(INVERSE) + line,
|
||||||
sgr(BOLD) + line,
|
sgr(BOLD) + line,
|
||||||
sgr(UNDERLINED) + line,
|
sgr(UNDERLINED) + line,
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"strict": true,
|
"strict": true,
|
||||||
@@ -28,10 +29,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../test/playwright"
|
"path": "../../../test/playwright"
|
||||||
|
|||||||
@@ -25,8 +25,11 @@ module.exports = {
|
|||||||
modules: ['./node_modules'],
|
modules: ['./node_modules'],
|
||||||
extensions: [ '.js' ],
|
extensions: [ '.js' ],
|
||||||
alias: {
|
alias: {
|
||||||
common: path.resolve('../../out/common'),
|
common: [
|
||||||
browser: path.resolve('../../out/browser')
|
path.resolve('../../out/runtime'),
|
||||||
|
path.resolve('../../out/primitives'),
|
||||||
|
],
|
||||||
|
browser: path.resolve('../../out/target-browser')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { perfContext, before, ThroughputRuntimeCase } from 'xterm-benchmark';
|
|||||||
|
|
||||||
import { spawn } from 'node-pty';
|
import { spawn } from 'node-pty';
|
||||||
import { Utf8ToUtf32, stringFromCodePoint } from 'common/input/TextDecoder';
|
import { Utf8ToUtf32, stringFromCodePoint } from 'common/input/TextDecoder';
|
||||||
import { CoreBrowserTerminal } from 'browser/CoreBrowserTerminal';
|
import { CoreBrowserTerminal } from 'target-browser/CoreBrowserTerminal';
|
||||||
import { UnicodeGraphemeProvider } from 'UnicodeGraphemeProvider';
|
import { UnicodeGraphemeProvider } from 'UnicodeGraphemeProvider';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,11 @@
|
|||||||
"target": "es2015",
|
"target": "es2015",
|
||||||
"module": "nodenext",
|
"module": "nodenext",
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": ["../../../src/common/*"],
|
"common/*": [
|
||||||
"browser/*": ["../../../src/browser/*"],
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
|
],
|
||||||
|
"target-browser/*": ["../../../src/target-browser/*"],
|
||||||
"UnicodeGraphemeProvider": ["../src/UnicodeGraphemeProvider"],
|
"UnicodeGraphemeProvider": ["../src/UnicodeGraphemeProvider"],
|
||||||
"@xterm/addon-unicode-graphemes": [
|
"@xterm/addon-unicode-graphemes": [
|
||||||
"../typings/addon-unicode-graphemes.d.ts"
|
"../typings/addon-unicode-graphemes.d.ts"
|
||||||
@@ -20,7 +23,7 @@
|
|||||||
"include": ["../**/*", "../../../typings/xterm.d.ts"],
|
"include": ["../**/*", "../../../typings/xterm.d.ts"],
|
||||||
"exclude": ["../../../**/*test.ts", "../../**/*api.ts"],
|
"exclude": ["../../../**/*test.ts", "../../**/*api.ts"],
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../../../src/common" },
|
{ "path": "../../../src" },
|
||||||
{ "path": "../../../src/browser" }
|
{ "path": "../../../src/target-browser" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
"package": "../../node_modules/.bin/webpack",
|
"package": "../../node_modules/.bin/webpack",
|
||||||
"prepublishOnly": "npm run package",
|
"prepublishOnly": "npm run package",
|
||||||
"start": "node ../../demo/start",
|
"start": "node ../../demo/start",
|
||||||
"benchmark": "../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json out-benchmark/benchmark/*benchmark.js",
|
"benchmark": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json out-benchmark/benchmark/*benchmark.js",
|
||||||
"benchmark-baseline": "../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --baseline out-benchmark/benchmark/*benchmark.js",
|
"benchmark-baseline": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --baseline out-benchmark/benchmark/*benchmark.js",
|
||||||
"benchmark-eval": "../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --eval out-benchmark/benchmark/*benchmark.js"
|
"benchmark-eval": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --eval out-benchmark/benchmark/*benchmark.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { IUnicodeVersionProvider } from '@xterm/xterm';
|
import { IUnicodeVersionProvider } from '@xterm/xterm';
|
||||||
import { UnicodeCharProperties, UnicodeCharWidth } from 'common/services/Services';
|
import { createPropertyValue, extractCharKind, extractWidth } from 'common/input/UnicodeProperties';
|
||||||
import { UnicodeService } from 'common/services/UnicodeService';
|
import { UnicodeCharProperties, UnicodeCharWidth } from 'common/input/UnicodeTypes';
|
||||||
import * as UC from './third-party/UnicodeProperties';
|
import * as UC from './third-party/UnicodeProperties';
|
||||||
|
|
||||||
export class UnicodeGraphemeProvider implements IUnicodeVersionProvider {
|
export class UnicodeGraphemeProvider implements IUnicodeVersionProvider {
|
||||||
@@ -19,7 +19,7 @@ export class UnicodeGraphemeProvider implements IUnicodeVersionProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static readonly _plainNarrowProperties: UnicodeCharProperties
|
private static readonly _plainNarrowProperties: UnicodeCharProperties
|
||||||
= UnicodeService.createPropertyValue(UC.GRAPHEME_BREAK_Other, 1, false);
|
= createPropertyValue(UC.GRAPHEME_BREAK_Other, 1, false);
|
||||||
|
|
||||||
public charProperties(codepoint: number, preceding: UnicodeCharProperties): UnicodeCharProperties {
|
public charProperties(codepoint: number, preceding: UnicodeCharProperties): UnicodeCharProperties {
|
||||||
// Optimize the simple ASCII case, under the condition that
|
// Optimize the simple ASCII case, under the condition that
|
||||||
@@ -39,9 +39,9 @@ export class UnicodeGraphemeProvider implements IUnicodeVersionProvider {
|
|||||||
w = 1;
|
w = 1;
|
||||||
}
|
}
|
||||||
if (preceding !== 0) {
|
if (preceding !== 0) {
|
||||||
const oldWidth = UnicodeService.extractWidth(preceding);
|
const oldWidth = extractWidth(preceding);
|
||||||
if (this.handleGraphemes) {
|
if (this.handleGraphemes) {
|
||||||
charInfo = UC.shouldJoin(UnicodeService.extractCharKind(preceding), charInfo);
|
charInfo = UC.shouldJoin(extractCharKind(preceding), charInfo);
|
||||||
} else {
|
} else {
|
||||||
charInfo = w === 0 ? 1 : 0;
|
charInfo = w === 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ export class UnicodeGraphemeProvider implements IUnicodeVersionProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return UnicodeService.createPropertyValue(charInfo, w, shouldJoin);
|
return createPropertyValue(charInfo, w, shouldJoin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public wcwidth(codepoint: number): UnicodeCharWidth {
|
public wcwidth(codepoint: number): UnicodeCharWidth {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 2023 The xterm.js authors. All rights reserved.
|
* Copyright (c) 2023 The xterm.js authors. All rights reserved.
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*
|
*
|
||||||
* UnicodeVersionProvider for V15 with grapheme cluster handling.
|
* UnicodeVersionProvider for V15 with grapeme cluster handleing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Terminal, ITerminalAddon, IUnicodeHandling } from '@xterm/xterm';
|
import type { Terminal, ITerminalAddon, IUnicodeHandling } from '@xterm/xterm';
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
"strict": true,
|
"strict": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"@xterm/addon-unicode-graphemes": [
|
"@xterm/addon-unicode-graphemes": [
|
||||||
"../typings/addon-unicode-graphemes.d.ts"
|
"../typings/addon-unicode-graphemes.d.ts"
|
||||||
@@ -29,7 +30,7 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"strict": true,
|
"strict": true,
|
||||||
@@ -28,10 +29,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../test/playwright"
|
"path": "../../../test/playwright"
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ module.exports = {
|
|||||||
modules: ['./node_modules'],
|
modules: ['./node_modules'],
|
||||||
extensions: [ '.js' ],
|
extensions: [ '.js' ],
|
||||||
alias: {
|
alias: {
|
||||||
common: path.resolve('../../out/common'),
|
common: [
|
||||||
|
path.resolve('../../out/runtime'),
|
||||||
|
path.resolve('../../out/primitives'),
|
||||||
|
],
|
||||||
vs: path.resolve('../../out/vs')
|
vs: path.resolve('../../out/vs')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { IUnicodeVersionProvider } from '@xterm/xterm';
|
import { IUnicodeVersionProvider } from '@xterm/xterm';
|
||||||
import { UnicodeCharProperties, UnicodeCharWidth } from 'common/services/Services';
|
import { createPropertyValue, extractWidth } from 'common/input/UnicodeProperties';
|
||||||
import { UnicodeService } from 'common/services/UnicodeService';
|
import { UnicodeCharProperties, UnicodeCharWidth } from 'common/input/UnicodeTypes';
|
||||||
|
|
||||||
const BMP_COMBINING = [
|
const BMP_COMBINING = [
|
||||||
[0x0300, 0x036F], [0x0483, 0x0489], [0x0591, 0x05BD],
|
[0x0300, 0x036F], [0x0483, 0x0489], [0x0591, 0x05BD],
|
||||||
@@ -223,13 +223,13 @@ export class UnicodeV11 implements IUnicodeVersionProvider {
|
|||||||
let width = this.wcwidth(codepoint);
|
let width = this.wcwidth(codepoint);
|
||||||
let shouldJoin = width === 0 && preceding !== 0;
|
let shouldJoin = width === 0 && preceding !== 0;
|
||||||
if (shouldJoin) {
|
if (shouldJoin) {
|
||||||
const oldWidth = UnicodeService.extractWidth(preceding);
|
const oldWidth = extractWidth(preceding);
|
||||||
if (oldWidth === 0) {
|
if (oldWidth === 0) {
|
||||||
shouldJoin = false;
|
shouldJoin = false;
|
||||||
} else if (oldWidth > width) {
|
} else if (oldWidth > width) {
|
||||||
width = oldWidth;
|
width = oldWidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return UnicodeService.createPropertyValue(0, width, shouldJoin);
|
return createPropertyValue(0, width, shouldJoin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
"strict": true,
|
"strict": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"@xterm/addon-unicode11": [
|
"@xterm/addon-unicode11": [
|
||||||
"../typings/addon-unicode11.d.ts"
|
"../typings/addon-unicode11.d.ts"
|
||||||
@@ -32,7 +33,7 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"*": [
|
"*": [
|
||||||
"./*"
|
"./*"
|
||||||
@@ -31,10 +32,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../test/playwright"
|
"path": "../../../test/playwright"
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ module.exports = {
|
|||||||
modules: ['./node_modules'],
|
modules: ['./node_modules'],
|
||||||
extensions: [ '.js' ],
|
extensions: [ '.js' ],
|
||||||
alias: {
|
alias: {
|
||||||
common: path.resolve('../../out/common'),
|
common: [
|
||||||
|
path.resolve('../../out/runtime'),
|
||||||
|
path.resolve('../../out/primitives'),
|
||||||
|
],
|
||||||
vs: path.resolve('../../out/vs')
|
vs: path.resolve('../../out/vs')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"*": [
|
"*": [
|
||||||
"./*"
|
"./*"
|
||||||
@@ -31,10 +32,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../test/playwright"
|
"path": "../../../test/playwright"
|
||||||
|
|||||||
@@ -57,8 +57,7 @@ function isUrl(urlString: string): boolean {
|
|||||||
|
|
||||||
export class LinkComputer {
|
export class LinkComputer {
|
||||||
public static computeLink(y: number, regex: RegExp, terminal: Terminal, activate: (event: MouseEvent, uri: string) => void): ILink[] {
|
public static computeLink(y: number, regex: RegExp, terminal: Terminal, activate: (event: MouseEvent, uri: string) => void): ILink[] {
|
||||||
const flags = regex.flags.includes('g') ? regex.flags : `${regex.flags}g`;
|
const rex = new RegExp(regex.source, (regex.flags || '') + 'g');
|
||||||
const rex = new RegExp(regex.source, flags);
|
|
||||||
|
|
||||||
const [lines, startLineIndex] = LinkComputer._getWindowedLineStrings(y - 1, terminal);
|
const [lines, startLineIndex] = LinkComputer._getWindowedLineStrings(y - 1, terminal);
|
||||||
const line = lines.join('');
|
const line = lines.join('');
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ import type { Terminal, ITerminalAddon, IDisposable } from '@xterm/xterm';
|
|||||||
import type { WebLinksAddon as IWebLinksApi } from '@xterm/addon-web-links';
|
import type { WebLinksAddon as IWebLinksApi } from '@xterm/addon-web-links';
|
||||||
import { ILinkProviderOptions, WebLinkProvider } from './WebLinkProvider';
|
import { ILinkProviderOptions, WebLinkProvider } from './WebLinkProvider';
|
||||||
|
|
||||||
// consider everything starting with http:// or https://
|
// consider everthing starting with http:// or https://
|
||||||
// up to first whitespace, `"` or `'` as url
|
// up to first whitespace, `"` or `'` as url
|
||||||
// NOTE: The repeated end clause is needed to not match a dangling `:`
|
// NOTE: The repeated end clause is needed to not match a dangling `:`
|
||||||
// resembling the old (...)*([^:"\'\\s]) final path clause
|
// resembling the old (...)*([^:"\'\\s]) final path clause
|
||||||
// additionally exclude early + final:
|
// additionally exclude early + final:
|
||||||
// - unsafe from rfc3986: !*'()
|
// - unsafe from rfc3986: !*'()
|
||||||
// - unsafe chars from rfc1738: {}|\^~[]` (minus [] for ipv6 addresses, also allow ~)
|
// - unsafe chars from rfc1738: {}|\^~[]` (minus [] as we need them for ipv6 adresses, also allow ~)
|
||||||
// also exclude as finals:
|
// also exclude as finals:
|
||||||
// - final interpunction like ,.!?
|
// - final interpunction like ,.!?
|
||||||
// - any sort of brackets <>()[]{} (not spec conform, but often used to enclose urls)
|
// - any sort of brackets <>()[]{} (not spec conform, but often used to enclose urls)
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"*": [
|
"*": [
|
||||||
"./*"
|
"./*"
|
||||||
@@ -31,10 +32,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../test/playwright"
|
"path": "../../../test/playwright"
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ See the full [API](https://github.com/xtermjs/xterm.js/blob/master/addons/addon-
|
|||||||
|
|
||||||
### Handling Context Loss
|
### Handling Context Loss
|
||||||
|
|
||||||
The browser may drop WebGL contexts for various reasons like OOM or after the system has been suspended. There is an API exposed that fires the `webglcontextlost` event on the canvas so embedders can handle it however they wish. An easy, but suboptimal way, to handle this is by disposing of WebglAddon when the event fires:
|
The browser may drop WebGL contexts for various reasons like OOM or after the system has been suspended. There is an API exposed that fires the `webglcontextlost` event fired on the canvas so embedders can handle it however they wish. An easy, but suboptimal way, to handle this is by disposing of WebglAddon when the event fires:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const terminal = new Terminal();
|
const terminal = new Terminal();
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { ISelectionRenderModel } from 'browser/renderer/shared/Types';
|
import { ISelectionRenderModel } from 'target-browser/renderer/shared/Types';
|
||||||
import { ICoreBrowserService, IThemeService } from 'browser/services/Services';
|
import { ICoreBrowserService, IThemeService } from 'target-browser/services/Services';
|
||||||
import { ReadonlyColorSet } from 'browser/Types';
|
import { ReadonlyColorSet } from 'target-browser/Types';
|
||||||
import { Attributes, BgFlags, ExtFlags, FgFlags, NULL_CELL_CODE, UnderlineStyle } from 'common/buffer/Constants';
|
import { Attributes, BgFlags, ExtFlags, FgFlags, NULL_CELL_CODE, UnderlineStyle } from 'common/buffer/Constants';
|
||||||
import { IDecorationService, IOptionsService } from 'common/services/Services';
|
import { IDecorationService, IOptionsService } from 'common/services/Services';
|
||||||
import { ICellData } from 'common/buffer/Types';
|
import { ICellData } from 'common/Types';
|
||||||
import { Terminal } from '@xterm/xterm';
|
import { Terminal } from '@xterm/xterm';
|
||||||
import { rgba } from 'common/Color';
|
import { rgba } from 'common/Color';
|
||||||
import { treatGlyphAsBackgroundColor } from 'browser/renderer/shared/RendererUtils';
|
import { treatGlyphAsBackgroundColor } from 'target-browser/renderer/shared/RendererUtils';
|
||||||
import { blockPatternCodepoints } from './customGlyphs/CustomGlyphDefinitions';
|
import { blockPatternCodepoints } from './customGlyphs/CustomGlyphDefinitions';
|
||||||
|
|
||||||
// Work variables to avoid garbage collection
|
// Work variables to avoid garbage collection
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { TextureAtlas } from './TextureAtlas';
|
import { TextureAtlas } from './TextureAtlas';
|
||||||
import { ITerminalOptions, Terminal } from '@xterm/xterm';
|
import { ITerminalOptions, Terminal } from '@xterm/xterm';
|
||||||
import { ITerminal, ReadonlyColorSet } from 'browser/Types';
|
import { ITerminal, ReadonlyColorSet } from 'target-browser/Types';
|
||||||
import { ICharAtlasConfig, ITextureAtlas } from './Types';
|
import { ICharAtlasConfig, ITextureAtlas } from './Types';
|
||||||
import { generateConfig, configEquals } from './CharAtlasUtils';
|
import { generateConfig, configEquals } from './CharAtlasUtils';
|
||||||
import type { ILogService } from 'common/services/Services';
|
import type { ILogService } from 'common/services/Services';
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import { ICharAtlasConfig } from './Types';
|
import { ICharAtlasConfig } from './Types';
|
||||||
import { Attributes } from 'common/buffer/Constants';
|
import { Attributes } from 'common/buffer/Constants';
|
||||||
import { ITerminalOptions } from '@xterm/xterm';
|
import { ITerminalOptions } from '@xterm/xterm';
|
||||||
import { IColorSet, ReadonlyColorSet } from 'browser/Types';
|
import { IColorSet, ReadonlyColorSet } from 'target-browser/Types';
|
||||||
import { NULL_COLOR } from 'common/Color';
|
import { NULL_COLOR } from 'common/Color';
|
||||||
|
|
||||||
export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, options: Required<ITerminalOptions>, colors: ReadonlyColorSet, devicePixelRatio: number, deviceMaxTextureSize: number, customGlyphs: boolean = true): ICharAtlasConfig {
|
export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, options: Required<ITerminalOptions>, colors: ReadonlyColorSet, devicePixelRatio: number, deviceMaxTextureSize: number, customGlyphs: boolean = true): ICharAtlasConfig {
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RendererConstants } from 'browser/renderer/shared/Constants';
|
import { RendererConstants } from 'target-browser/renderer/shared/Constants';
|
||||||
import { ICoreBrowserService } from 'browser/services/Services';
|
import { ICoreBrowserService } from 'target-browser/services/Services';
|
||||||
|
|
||||||
const enum Constants {
|
const enum Constants {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
import { TextureAtlas } from './TextureAtlas';
|
import { TextureAtlas } from './TextureAtlas';
|
||||||
import { IRenderDimensions } from 'browser/renderer/shared/Types';
|
import { IRenderDimensions } from 'target-browser/renderer/shared/Types';
|
||||||
import { NULL_CELL_CODE } from 'common/buffer/Constants';
|
import { NULL_CELL_CODE } from 'common/buffer/Constants';
|
||||||
import { Disposable, toDisposable } from 'common/Lifecycle';
|
import { Disposable, toDisposable } from 'common/Lifecycle';
|
||||||
import { Terminal } from '@xterm/xterm';
|
import { Terminal } from '@xterm/xterm';
|
||||||
import { IRenderModel, IWebGL2RenderingContext, IWebGLVertexArrayObject, type IRasterizedGlyph, type ITextureAtlas } from './Types';
|
import { IRenderModel, IWebGL2RenderingContext, IWebGLVertexArrayObject, type IRasterizedGlyph, type ITextureAtlas } from './Types';
|
||||||
import { createProgram, GLTexture, PROJECTION_MATRIX } from './WebglUtils';
|
import { createProgram, GLTexture, PROJECTION_MATRIX } from './WebglUtils';
|
||||||
import type { ILogService, IOptionsService } from 'common/services/Services';
|
import type { ILogService, IOptionsService } from 'common/services/Services';
|
||||||
import { allowRescaling, throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
import { allowRescaling, throwIfFalsy } from 'target-browser/renderer/shared/RendererUtils';
|
||||||
|
|
||||||
interface IVertices {
|
interface IVertices {
|
||||||
attributes: Float32Array;
|
attributes: Float32Array;
|
||||||
@@ -220,7 +220,7 @@ export class GlyphRenderer extends Disposable {
|
|||||||
public updateCell(x: number, y: number, code: number, bg: number, fg: number, ext: number, chars: string, width: number, lastBg: number): void {
|
public updateCell(x: number, y: number, code: number, bg: number, fg: number, ext: number, chars: string, width: number, lastBg: number): void {
|
||||||
// Since this function is called for every cell (`rows*cols`), it must be very optimized. It
|
// Since this function is called for every cell (`rows*cols`), it must be very optimized. It
|
||||||
// should not instantiate any variables unless a new glyph is drawn to the cache where the
|
// should not instantiate any variables unless a new glyph is drawn to the cache where the
|
||||||
// slight slowdown is acceptable for the developer ergonomics provided as it's a one-off for
|
// slight slowdown is acceptable for the developer ergonomics provided as it's a once of for
|
||||||
// each glyph.
|
// each glyph.
|
||||||
this._updateCell(this._vertices.attributes, x, y, code, bg, fg, ext, chars, width, lastBg);
|
this._updateCell(this._vertices.attributes, x, y, code, bg, fg, ext, chars, width, lastBg);
|
||||||
}
|
}
|
||||||
@@ -389,9 +389,8 @@ export class GlyphRenderer extends Disposable {
|
|||||||
gl.bindTexture(gl.TEXTURE_2D, this._atlasTextures[i].texture);
|
gl.bindTexture(gl.TEXTURE_2D, this._atlasTextures[i].texture);
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, atlas.pages[i].canvas);
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, atlas.pages[i].canvas);
|
||||||
|
gl.generateMipmap(gl.TEXTURE_2D);
|
||||||
this._atlasTextures[i].version = atlas.pages[i].version;
|
this._atlasTextures[i].version = atlas.pages[i].version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IRenderDimensions } from 'browser/renderer/shared/Types';
|
import { IRenderDimensions } from 'target-browser/renderer/shared/Types';
|
||||||
import { IThemeService } from 'browser/services/Services';
|
import { IThemeService } from 'target-browser/services/Services';
|
||||||
import { ReadonlyColorSet } from 'browser/Types';
|
import { ReadonlyColorSet } from 'target-browser/Types';
|
||||||
import { Attributes, FgFlags } from 'common/buffer/Constants';
|
import { Attributes, FgFlags } from 'common/buffer/Constants';
|
||||||
import { Disposable, toDisposable } from 'common/Lifecycle';
|
import { Disposable, toDisposable } from 'common/Lifecycle';
|
||||||
import { IColor } from 'common/Types';
|
import { IColor } from 'common/Types';
|
||||||
@@ -13,7 +13,7 @@ import { Terminal } from '@xterm/xterm';
|
|||||||
import { RenderModelConstants } from './RenderModel';
|
import { RenderModelConstants } from './RenderModel';
|
||||||
import { IRenderModel, IWebGL2RenderingContext, IWebGLVertexArrayObject } from './Types';
|
import { IRenderModel, IWebGL2RenderingContext, IWebGLVertexArrayObject } from './Types';
|
||||||
import { createProgram, expandFloat32Array, PROJECTION_MATRIX } from './WebglUtils';
|
import { createProgram, expandFloat32Array, PROJECTION_MATRIX } from './WebglUtils';
|
||||||
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
import { throwIfFalsy } from 'target-browser/renderer/shared/RendererUtils';
|
||||||
import type { ILogService } from 'common/services/Services';
|
import type { ILogService } from 'common/services/Services';
|
||||||
|
|
||||||
const enum VertexAttribLocations {
|
const enum VertexAttribLocations {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ICursorRenderModel, IRenderModel } from './Types';
|
import { ICursorRenderModel, IRenderModel } from './Types';
|
||||||
import { ISelectionRenderModel } from 'browser/renderer/shared/Types';
|
import { ISelectionRenderModel } from 'target-browser/renderer/shared/Types';
|
||||||
import { createSelectionRenderModel } from 'browser/renderer/shared/SelectionRenderModel';
|
import { createSelectionRenderModel } from 'target-browser/renderer/shared/SelectionRenderModel';
|
||||||
|
|
||||||
export const enum RenderModelConstants {
|
export const enum RenderModelConstants {
|
||||||
INDICIES_PER_CELL = 4,
|
INDICIES_PER_CELL = 4,
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IColorContrastCache } from 'browser/Types';
|
import { IColorContrastCache } from 'target-browser/Types';
|
||||||
import { DIM_OPACITY, TEXT_BASELINE } from './Constants';
|
import { DIM_OPACITY, TEXT_BASELINE } from './Constants';
|
||||||
import { tryDrawCustomGlyph } from './customGlyphs/CustomGlyphRasterizer';
|
import { tryDrawCustomGlyph } from './customGlyphs/CustomGlyphRasterizer';
|
||||||
import { computeNextVariantOffset, treatGlyphAsBackgroundColor, isPowerlineGlyph, isRestrictedPowerlineGlyph, throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
import { computeNextVariantOffset, treatGlyphAsBackgroundColor, isPowerlineGlyph, isRestrictedPowerlineGlyph, throwIfFalsy } from 'target-browser/renderer/shared/RendererUtils';
|
||||||
import { IBoundingBox, ICharAtlasConfig, IRasterizedGlyph, ITextureAtlas } from './Types';
|
import { IBoundingBox, ICharAtlasConfig, IRasterizedGlyph, ITextureAtlas } from './Types';
|
||||||
import { NULL_COLOR, channels, color, rgba } from 'common/Color';
|
import { NULL_COLOR, channels, color, rgba } from 'common/Color';
|
||||||
import { FourKeyMap } from 'common/MultiKeyMap';
|
import { FourKeyMap } from 'common/MultiKeyMap';
|
||||||
@@ -69,7 +69,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|||||||
private _overflowSizePage: AtlasPage | undefined;
|
private _overflowSizePage: AtlasPage | undefined;
|
||||||
|
|
||||||
private _tmpCanvas: HTMLCanvasElement;
|
private _tmpCanvas: HTMLCanvasElement;
|
||||||
// A temporary context that glyphs are drawn to before being transferred to the atlas.
|
// A temporary context that glyphs are drawn to before being transfered to the atlas.
|
||||||
private _tmpCtx: CanvasRenderingContext2D;
|
private _tmpCtx: CanvasRenderingContext2D;
|
||||||
|
|
||||||
private _workBoundingBox: IBoundingBox = { top: 0, left: 0, bottom: 0, right: 0 };
|
private _workBoundingBox: IBoundingBox = { top: 0, left: 0, bottom: 0, right: 0 };
|
||||||
@@ -152,7 +152,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _createNewPage(): AtlasPage {
|
private _createNewPage(): AtlasPage {
|
||||||
// Try merge the set of the 4 most used pages of the largest size. This is deferred to a
|
// Try merge the set of the 4 most used pages of the largest size. This is is deferred to a
|
||||||
// microtask to ensure it does not interrupt textures that will be rendered in the current
|
// microtask to ensure it does not interrupt textures that will be rendered in the current
|
||||||
// animation frame which would result in blank rendered areas. This is actually not that
|
// animation frame which would result in blank rendered areas. This is actually not that
|
||||||
// expensive relative to drawing the glyphs, so there is no need to wait for an idle callback.
|
// expensive relative to drawing the glyphs, so there is no need to wait for an idle callback.
|
||||||
@@ -191,7 +191,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|||||||
return newPage;
|
return newPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortedMergingPagesIndexes = mergingPages.map(e => e.glyphs[0].texturePage).sort((a, b) => a - b);
|
const sortedMergingPagesIndexes = mergingPages.map(e => e.glyphs[0].texturePage).sort((a, b) => a > b ? 1 : -1);
|
||||||
const mergedPageIndex = this.pages.length - mergingPages.length;
|
const mergedPageIndex = this.pages.length - mergingPages.length;
|
||||||
|
|
||||||
// Merge into the new page
|
// Merge into the new page
|
||||||
@@ -1080,33 +1080,17 @@ class AtlasPage {
|
|||||||
size: number,
|
size: number,
|
||||||
sourcePages?: AtlasPage[]
|
sourcePages?: AtlasPage[]
|
||||||
) {
|
) {
|
||||||
|
if (sourcePages) {
|
||||||
|
for (const p of sourcePages) {
|
||||||
|
this._glyphs.push(...p.glyphs);
|
||||||
|
this._usedPixels += p._usedPixels;
|
||||||
|
}
|
||||||
|
}
|
||||||
this.canvas = createCanvas(document, size, size);
|
this.canvas = createCanvas(document, size, size);
|
||||||
// The canvas needs alpha because we use clearColor to convert the background color to alpha.
|
// The canvas needs alpha because we use clearColor to convert the background color to alpha.
|
||||||
// It might also contain some characters with transparent backgrounds if allowTransparency is
|
// It might also contain some characters with transparent backgrounds if allowTransparency is
|
||||||
// set.
|
// set.
|
||||||
this.ctx = throwIfFalsy(this.canvas.getContext('2d', { alpha: true }));
|
this.ctx = throwIfFalsy(this.canvas.getContext('2d', { alpha: true }));
|
||||||
if (sourcePages) {
|
|
||||||
if (sourcePages.length === 4) {
|
|
||||||
// optimized for quadmerge
|
|
||||||
this._glyphs = this._glyphs.concat(
|
|
||||||
sourcePages[0].glyphs,
|
|
||||||
sourcePages[1].glyphs,
|
|
||||||
sourcePages[2].glyphs,
|
|
||||||
sourcePages[3].glyphs
|
|
||||||
);
|
|
||||||
this._usedPixels = sourcePages[0]._usedPixels +
|
|
||||||
sourcePages[1]._usedPixels +
|
|
||||||
sourcePages[2]._usedPixels +
|
|
||||||
sourcePages[3]._usedPixels;
|
|
||||||
} else {
|
|
||||||
// fallback for non quadmerges (should never be used)
|
|
||||||
for (let i = 0; i < sourcePages.length; ++i) {
|
|
||||||
this._glyphs = this._glyphs.concat(sourcePages[i].glyphs);
|
|
||||||
this._usedPixels += sourcePages[i]._usedPixels;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public clear(): void {
|
public clear(): void {
|
||||||
@@ -1141,7 +1125,7 @@ function clearColor(imageData: ImageData, bg: IColor, fg: IColor, enableThreshol
|
|||||||
// were covered (fg=#8ae234, bg=#c4a000).
|
// were covered (fg=#8ae234, bg=#c4a000).
|
||||||
const threshold = Math.floor((Math.abs(r - fgR) + Math.abs(g - fgG) + Math.abs(b - fgB)) / 12);
|
const threshold = Math.floor((Math.abs(r - fgR) + Math.abs(g - fgG) + Math.abs(b - fgB)) / 12);
|
||||||
|
|
||||||
// Set alpha channel of relevant pixels to 0
|
// Set alpha channel of relevent pixels to 0
|
||||||
let isEmpty = true;
|
let isEmpty = true;
|
||||||
for (let offset = 0; offset < imageData.data.length; offset += 4) {
|
for (let offset = 0; offset < imageData.data.length; offset += 4) {
|
||||||
// Check exact match
|
// Check exact match
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { FontWeight } from '@xterm/xterm';
|
import { FontWeight } from '@xterm/xterm';
|
||||||
import { IColorSet } from 'browser/Types';
|
import { IColorSet } from 'target-browser/Types';
|
||||||
import { ISelectionRenderModel } from 'browser/renderer/shared/Types';
|
import { ISelectionRenderModel } from 'target-browser/renderer/shared/Types';
|
||||||
import { CursorInactiveStyle, CursorStyle, type IDisposable } from 'common/Types';
|
import { CursorInactiveStyle, CursorStyle, type IDisposable } from 'common/Types';
|
||||||
import type { IEvent } from 'common/Event';
|
import type { IEvent } from 'common/Event';
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
import type { ITerminalAddon, Terminal } from '@xterm/xterm';
|
import type { ITerminalAddon, Terminal } from '@xterm/xterm';
|
||||||
import type { IWebglAddonOptions, WebglAddon as IWebglApi } from '@xterm/addon-webgl';
|
import type { IWebglAddonOptions, WebglAddon as IWebglApi } from '@xterm/addon-webgl';
|
||||||
import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services';
|
import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService, IRenderService, IThemeService } from 'target-browser/services/Services';
|
||||||
import { ITerminal } from 'browser/Types';
|
import { ITerminal } from 'target-browser/Types';
|
||||||
import { Disposable, toDisposable } from 'common/Lifecycle';
|
import { Disposable, toDisposable } from 'common/Lifecycle';
|
||||||
import { getSafariVersion, isSafari } from 'common/Platform';
|
import { getSafariVersion, isSafari } from 'common/Platform';
|
||||||
import { ICoreService, IDecorationService, ILogService, IOptionsService } from 'common/services/Services';
|
import { ICoreService, IDecorationService, ILogService, IOptionsService } from 'common/services/Services';
|
||||||
@@ -40,7 +40,7 @@ export class WebglAddon extends Disposable implements ITerminalAddon, IWebglApi
|
|||||||
};
|
};
|
||||||
const gl = document.createElement('canvas').getContext('webgl2', contextAttributes) as IWebGL2RenderingContext;
|
const gl = document.createElement('canvas').getContext('webgl2', contextAttributes) as IWebGL2RenderingContext;
|
||||||
if (!gl) {
|
if (!gl) {
|
||||||
throw new Error('WebGL2 is only supported on Safari 16 and above');
|
throw new Error('Webgl2 is only supported on Safari 16 and above');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super();
|
super();
|
||||||
|
|||||||
@@ -3,18 +3,18 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ITerminal } from 'browser/Types';
|
import { ITerminal } from 'target-browser/Types';
|
||||||
import { CellColorResolver } from './CellColorResolver';
|
import { CellColorResolver } from './CellColorResolver';
|
||||||
import { acquireTextureAtlas, removeTerminalFromCache } from './CharAtlasCache';
|
import { acquireTextureAtlas, removeTerminalFromCache } from './CharAtlasCache';
|
||||||
import { CursorBlinkStateManager } from './CursorBlinkStateManager';
|
import { CursorBlinkStateManager } from './CursorBlinkStateManager';
|
||||||
import { observeDevicePixelDimensions } from './DevicePixelObserver';
|
import { observeDevicePixelDimensions } from './DevicePixelObserver';
|
||||||
import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/shared/Types';
|
import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'target-browser/renderer/shared/Types';
|
||||||
import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, IThemeService } from 'browser/services/Services';
|
import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, IThemeService } from 'target-browser/services/Services';
|
||||||
import { CharData, IBufferLine, ICellData } from 'common/buffer/Types';
|
import { CharData, IBufferLine, ICellData } from 'common/Types';
|
||||||
import { AttributeData } from 'common/buffer/AttributeData';
|
import { AttributeData } from 'common/buffer/AttributeData';
|
||||||
import { CellData } from 'common/buffer/CellData';
|
import { CellData } from 'common/buffer/CellData';
|
||||||
import { Attributes, Content, FgFlags, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants';
|
import { Attributes, Content, FgFlags, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants';
|
||||||
import { TextBlinkStateManager } from 'browser/renderer/shared/TextBlinkStateManager';
|
import { TextBlinkStateManager } from 'target-browser/renderer/shared/TextBlinkStateManager';
|
||||||
import { ICoreService, IDecorationService, ILogService, IOptionsService } from 'common/services/Services';
|
import { ICoreService, IDecorationService, ILogService, IOptionsService } from 'common/services/Services';
|
||||||
import { Terminal } from '@xterm/xterm';
|
import { Terminal } from '@xterm/xterm';
|
||||||
import { GlyphRenderer } from './GlyphRenderer';
|
import { GlyphRenderer } from './GlyphRenderer';
|
||||||
@@ -24,9 +24,9 @@ import { IWebGL2RenderingContext, type ITextureAtlas } from './Types';
|
|||||||
import { LinkRenderLayer } from './renderLayer/LinkRenderLayer';
|
import { LinkRenderLayer } from './renderLayer/LinkRenderLayer';
|
||||||
import { IRenderLayer } from './renderLayer/Types';
|
import { IRenderLayer } from './renderLayer/Types';
|
||||||
import { Emitter, EventUtils } from 'common/Event';
|
import { Emitter, EventUtils } from 'common/Event';
|
||||||
import { addDisposableListener } from 'browser/Dom';
|
import { addDisposableListener } from 'target-browser/Dom';
|
||||||
import { combinedDisposable, Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle';
|
import { combinedDisposable, Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle';
|
||||||
import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils';
|
import { createRenderDimensions } from 'target-browser/renderer/shared/RendererUtils';
|
||||||
|
|
||||||
const enum Constants {
|
const enum Constants {
|
||||||
MERGE_RETRY_LIMIT = 32
|
MERGE_RETRY_LIMIT = 32
|
||||||
@@ -456,18 +456,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
|
|
||||||
for (y = start; y <= end; y++) {
|
for (y = start; y <= end; y++) {
|
||||||
row = y + terminal.buffer.ydisp;
|
row = y + terminal.buffer.ydisp;
|
||||||
const bufferLine = terminal.buffer.lines.get(row);
|
line = terminal.buffer.lines.get(row)!;
|
||||||
if (!bufferLine) {
|
|
||||||
this._model.lineLengths[y] = 0;
|
|
||||||
for (x = 0; x < terminal.cols; x++) {
|
|
||||||
j = ((y * terminal.cols) + x) * RenderModelConstants.INDICIES_PER_CELL;
|
|
||||||
modelUpdated = true;
|
|
||||||
this._nullModelCell(x, y, j, 0, 0, 0);
|
|
||||||
}
|
|
||||||
this._setRowBlinkState(y, false);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
line = bufferLine;
|
|
||||||
let rowHasBlinkingCells = false;
|
let rowHasBlinkingCells = false;
|
||||||
this._model.lineLengths[y] = 0;
|
this._model.lineLengths[y] = 0;
|
||||||
isCursorRow = cursorY === row;
|
isCursorRow = cursorY === row;
|
||||||
@@ -598,9 +587,13 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
// Null out non-first cells
|
// Null out non-first cells
|
||||||
for (x++; x <= lastCharX; x++) {
|
for (x++; x <= lastCharX; x++) {
|
||||||
j = ((y * terminal.cols) + x) * RenderModelConstants.INDICIES_PER_CELL;
|
j = ((y * terminal.cols) + x) * RenderModelConstants.INDICIES_PER_CELL;
|
||||||
|
this._glyphRenderer.value!.updateCell(x, y, NULL_CELL_CODE, 0, 0, 0, NULL_CELL_CHAR, 0, 0);
|
||||||
|
this._model.cells[j] = NULL_CELL_CODE;
|
||||||
// Don't re-resolve the cell color since multi-colored ligature backgrounds are not
|
// Don't re-resolve the cell color since multi-colored ligature backgrounds are not
|
||||||
// supported
|
// supported
|
||||||
this._nullModelCell(x, y, j, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext);
|
this._model.cells[j + RenderModelConstants.BG_OFFSET] = this._cellColorResolver.result.bg;
|
||||||
|
this._model.cells[j + RenderModelConstants.FG_OFFSET] = this._cellColorResolver.result.fg;
|
||||||
|
this._model.cells[j + RenderModelConstants.EXT_OFFSET] = this._cellColorResolver.result.ext;
|
||||||
}
|
}
|
||||||
x--; // Go back to the previous update cell for next iteration
|
x--; // Go back to the previous update cell for next iteration
|
||||||
}
|
}
|
||||||
@@ -614,14 +607,6 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
this._updateTextBlinkState();
|
this._updateTextBlinkState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _nullModelCell(x: number, y: number, cellIndex: number, bg: number, fg: number, ext: number): void {
|
|
||||||
this._glyphRenderer.value!.updateCell(x, y, NULL_CELL_CODE, bg, fg, ext, NULL_CELL_CHAR, 0, 0);
|
|
||||||
this._model.cells[cellIndex] = NULL_CELL_CODE;
|
|
||||||
this._model.cells[cellIndex + RenderModelConstants.BG_OFFSET] = bg;
|
|
||||||
this._model.cells[cellIndex + RenderModelConstants.FG_OFFSET] = fg;
|
|
||||||
this._model.cells[cellIndex + RenderModelConstants.EXT_OFFSET] = ext;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _resetBlinkingRowState(): void {
|
private _resetBlinkingRowState(): void {
|
||||||
this._rowHasBlinkingCells = new Array(this._terminal.rows).fill(false);
|
this._rowHasBlinkingCells = new Array(this._terminal.rows).fill(false);
|
||||||
this._rowHasBlinkingCellsCount = 0;
|
this._rowHasBlinkingCellsCount = 0;
|
||||||
@@ -679,10 +664,10 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
this.dimensions.device.canvas.height = this._terminal.rows * this.dimensions.device.cell.height;
|
this.dimensions.device.canvas.height = this._terminal.rows * this.dimensions.device.cell.height;
|
||||||
this.dimensions.device.canvas.width = this._terminal.cols * this.dimensions.device.cell.width;
|
this.dimensions.device.canvas.width = this._terminal.cols * this.dimensions.device.cell.width;
|
||||||
|
|
||||||
// The size of the canvas on the page. It's important that this rounds to nearest integer
|
// The the size of the canvas on the page. It's important that this rounds to nearest integer
|
||||||
// and not ceils as browsers often have floating point precision issues where
|
// and not ceils as browsers often have floating point precision issues where
|
||||||
// `window.devicePixelRatio` ends up being something like `1.100000023841858` for example, when
|
// `window.devicePixelRatio` ends up being something like `1.100000023841858` for example, when
|
||||||
// it's actually 1.1. Ceiling may cause blurriness as the backing canvas image is 1 pixel too
|
// it's actually 1.1. Ceiling may causes blurriness as the backing canvas image is 1 pixel too
|
||||||
// large for the canvas element size.
|
// large for the canvas element size.
|
||||||
this.dimensions.css.canvas.height = Math.round(this.dimensions.device.canvas.height / this._devicePixelRatio);
|
this.dimensions.css.canvas.height = Math.round(this.dimensions.device.canvas.height / this._devicePixelRatio);
|
||||||
this.dimensions.css.canvas.width = Math.round(this.dimensions.device.canvas.width / this._devicePixelRatio);
|
this.dimensions.css.canvas.width = Math.round(this.dimensions.device.canvas.width / this._devicePixelRatio);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
import { throwIfFalsy } from 'target-browser/renderer/shared/RendererUtils';
|
||||||
import type { ILogService } from 'common/services/Services';
|
import type { ILogService } from 'common/services/Services';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { CustomGlyphDefinitionType, CustomGlyphScaleType, CustomGlyphVectorType, type CustomGlyphCharacterDefinition, type CustomGlyphDefinitionPart, type CustomGlyphPathDrawFunctionDefinition } from './Types';
|
import { CustomGlyphDefinitionType, CustomGlyphScaleType, CustomGlyphVectorType, type CustomGlyphCharacterDefinition, type CustomGlyphDefinitionPart, type CustomGlyphPathDrawFunctionDefinition } from './Types';
|
||||||
|
|
||||||
/* oxlint-disable @stylistic/max-len -- generated glyph path data */
|
/* eslint-disable max-len */
|
||||||
|
|
||||||
const enum Shapes {
|
const enum Shapes {
|
||||||
/** │ */ TOP_TO_BOTTOM = 'M.5,0 L.5,1',
|
/** │ */ TOP_TO_BOTTOM = 'M.5,0 L.5,1',
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
import { throwIfFalsy } from 'target-browser/renderer/shared/RendererUtils';
|
||||||
import type { ILogService } from 'common/services/Services';
|
import type { ILogService } from 'common/services/Services';
|
||||||
import { customGlyphDefinitions } from './CustomGlyphDefinitions';
|
import { customGlyphDefinitions } from './CustomGlyphDefinitions';
|
||||||
import { CustomGlyphDefinitionType, CustomGlyphScaleType, CustomGlyphVectorType, type CustomGlyphDefinitionPart, type CustomGlyphPathDrawFunctionDefinition, type CustomGlyphPatternDefinition, type ICustomGlyphSolidOctantBlockVector, type ICustomGlyphVectorShape } from './Types';
|
import { CustomGlyphDefinitionType, CustomGlyphScaleType, CustomGlyphVectorType, type CustomGlyphDefinitionPart, type CustomGlyphPathDrawFunctionDefinition, type CustomGlyphPatternDefinition, type ICustomGlyphSolidOctantBlockVector, type ICustomGlyphVectorShape } from './Types';
|
||||||
@@ -221,8 +221,8 @@ function drawPathDefinitionCharacter(
|
|||||||
const rx = parseFloat(args[0]) * deviceCellWidth;
|
const rx = parseFloat(args[0]) * deviceCellWidth;
|
||||||
const ry = parseFloat(args[1]) * deviceCellHeight;
|
const ry = parseFloat(args[1]) * deviceCellHeight;
|
||||||
const xAxisRotation = parseFloat(args[2]) * Math.PI / 180;
|
const xAxisRotation = parseFloat(args[2]) * Math.PI / 180;
|
||||||
const largeArcFlag = parseInt(args[3], 10);
|
const largeArcFlag = parseInt(args[3]);
|
||||||
const sweepFlag = parseInt(args[4], 10);
|
const sweepFlag = parseInt(args[4]);
|
||||||
const x = xOffset + parseFloat(args[5]) * deviceCellWidth;
|
const x = xOffset + parseFloat(args[5]) * deviceCellWidth;
|
||||||
const y = yOffset + parseFloat(args[6]) * deviceCellHeight;
|
const y = yOffset + parseFloat(args[6]) * deviceCellHeight;
|
||||||
drawSvgArc(ctx, currentX, currentY, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y);
|
drawSvgArc(ctx, currentX, currentY, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y);
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ReadonlyColorSet } from 'browser/Types';
|
import { ReadonlyColorSet } from 'target-browser/Types';
|
||||||
import { acquireTextureAtlas } from '../CharAtlasCache';
|
import { acquireTextureAtlas } from '../CharAtlasCache';
|
||||||
import { IRenderDimensions } from 'browser/renderer/shared/Types';
|
import { IRenderDimensions } from 'target-browser/renderer/shared/Types';
|
||||||
import { ICoreBrowserService, IThemeService } from 'browser/services/Services';
|
import { ICoreBrowserService, IThemeService } from 'target-browser/services/Services';
|
||||||
import { Disposable, toDisposable } from 'common/Lifecycle';
|
import { Disposable, toDisposable } from 'common/Lifecycle';
|
||||||
import { CellData } from 'common/buffer/CellData';
|
import { CellData } from 'common/buffer/CellData';
|
||||||
import { IOptionsService } from 'common/services/Services';
|
import { IOptionsService } from 'common/services/Services';
|
||||||
import { Terminal } from '@xterm/xterm';
|
import { Terminal } from '@xterm/xterm';
|
||||||
import { IRenderLayer } from './Types';
|
import { IRenderLayer } from './Types';
|
||||||
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
import { throwIfFalsy } from 'target-browser/renderer/shared/RendererUtils';
|
||||||
import { TEXT_BASELINE } from '../Constants';
|
import { TEXT_BASELINE } from '../Constants';
|
||||||
import type { ITextureAtlas } from '../Types';
|
import type { ITextureAtlas } from '../Types';
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { is256Color } from '../CharAtlasUtils';
|
import { is256Color } from '../CharAtlasUtils';
|
||||||
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/shared/Constants';
|
import { INVERTED_DEFAULT_COLOR } from 'target-browser/renderer/shared/Constants';
|
||||||
import { IRenderDimensions } from 'browser/renderer/shared/Types';
|
import { IRenderDimensions } from 'target-browser/renderer/shared/Types';
|
||||||
import { ICoreBrowserService, IThemeService } from 'browser/services/Services';
|
import { ICoreBrowserService, IThemeService } from 'target-browser/services/Services';
|
||||||
import { ILinkifier2, ILinkifierEvent } from 'browser/Types';
|
import { ILinkifier2, ILinkifierEvent } from 'target-browser/Types';
|
||||||
import { IOptionsService } from 'common/services/Services';
|
import { IOptionsService } from 'common/services/Services';
|
||||||
import { Terminal } from '@xterm/xterm';
|
import { Terminal } from '@xterm/xterm';
|
||||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { IDisposable, Terminal } from '@xterm/xterm';
|
import { IDisposable, Terminal } from '@xterm/xterm';
|
||||||
import { IRenderDimensions } from 'browser/renderer/shared/Types';
|
import { IRenderDimensions } from 'target-browser/renderer/shared/Types';
|
||||||
|
|
||||||
export interface IRenderLayer extends IDisposable {
|
export interface IRenderLayer extends IDisposable {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -12,10 +12,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"@xterm/addon-webgl": [
|
"@xterm/addon-webgl": [
|
||||||
"../typings/addon-webgl.d.ts"
|
"../typings/addon-webgl.d.ts"
|
||||||
@@ -36,10 +37,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"common/*": [
|
"common/*": [
|
||||||
"../../../src/common/*"
|
"../../../src/primitives/*",
|
||||||
|
"../../../src/runtime/*",
|
||||||
],
|
],
|
||||||
"browser/*": [
|
"target-browser/*": [
|
||||||
"../../../src/browser/*"
|
"../../../src/target-browser/*"
|
||||||
],
|
],
|
||||||
"*": [
|
"*": [
|
||||||
"./*"
|
"./*"
|
||||||
@@ -32,10 +33,10 @@
|
|||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../../../src/common"
|
"path": "../../../src"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../src/browser"
|
"path": "../../../src/target-browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../../test/playwright"
|
"path": "../../../test/playwright"
|
||||||
|
|||||||
+2
-2
@@ -23,12 +23,12 @@ declare module '@xterm/addon-webgl' {
|
|||||||
public readonly onChangeTextureAtlas: IEvent<HTMLCanvasElement>;
|
public readonly onChangeTextureAtlas: IEvent<HTMLCanvasElement>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event that is fired when a new page is added to the texture atlas.
|
* An event that is fired when the a new page is added to the texture atlas.
|
||||||
*/
|
*/
|
||||||
public readonly onAddTextureAtlasCanvas: IEvent<HTMLCanvasElement>;
|
public readonly onAddTextureAtlasCanvas: IEvent<HTMLCanvasElement>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event that is fired when a page is removed from the texture atlas.
|
* An event that is fired when the a page is removed from the texture atlas.
|
||||||
*/
|
*/
|
||||||
public readonly onRemoveTextureAtlasCanvas: IEvent<HTMLCanvasElement>;
|
public readonly onRemoveTextureAtlasCanvas: IEvent<HTMLCanvasElement>;
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,11 @@ module.exports = {
|
|||||||
modules: ['./node_modules'],
|
modules: ['./node_modules'],
|
||||||
extensions: [ '.js' ],
|
extensions: [ '.js' ],
|
||||||
alias: {
|
alias: {
|
||||||
common: path.resolve('../../out/common'),
|
common: [
|
||||||
browser: path.resolve('../../out/browser'),
|
path.resolve('../../out/runtime'),
|
||||||
|
path.resolve('../../out/primitives'),
|
||||||
|
],
|
||||||
|
browser: path.resolve('../../out/target-browser'),
|
||||||
vs: path.resolve('../../out/vs')
|
vs: path.resolve('../../out/vs')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
+37
-13
@@ -92,6 +92,9 @@ let outConfig = {
|
|||||||
}
|
}
|
||||||
let skipOut = false;
|
let skipOut = false;
|
||||||
|
|
||||||
|
/** @type {esbuild.BuildOptions[] | undefined} */
|
||||||
|
let outBuilds;
|
||||||
|
|
||||||
/** @type {esbuild.BuildOptions} */
|
/** @type {esbuild.BuildOptions} */
|
||||||
let outTestConfig = {
|
let outTestConfig = {
|
||||||
format: 'cjs',
|
format: 'cjs',
|
||||||
@@ -171,7 +174,7 @@ if (config.addon) {
|
|||||||
} else if (config.isHeadless) {
|
} else if (config.isHeadless) {
|
||||||
bundleConfig = {
|
bundleConfig = {
|
||||||
...bundleConfig,
|
...bundleConfig,
|
||||||
entryPoints: [`src/headless/public/Terminal.ts`],
|
entryPoints: [`src/target-headless/public/Terminal.ts`],
|
||||||
outfile: `headless/lib-headless/xterm-headless.mjs`
|
outfile: `headless/lib-headless/xterm-headless.mjs`
|
||||||
};
|
};
|
||||||
outConfig = {
|
outConfig = {
|
||||||
@@ -183,18 +186,35 @@ if (config.addon) {
|
|||||||
} else {
|
} else {
|
||||||
bundleConfig = {
|
bundleConfig = {
|
||||||
...bundleConfig,
|
...bundleConfig,
|
||||||
entryPoints: [`src/browser/public/Terminal.ts`],
|
entryPoints: [`src/target-browser/public/Terminal.ts`],
|
||||||
outfile: `lib/xterm.mjs`
|
outfile: `lib/xterm.mjs`
|
||||||
};
|
};
|
||||||
outConfig = {
|
outBuilds = [
|
||||||
...outConfig,
|
{
|
||||||
entryPoints: [
|
...outConfig,
|
||||||
'src/browser/**/*.ts',
|
entryPoints: ['src/primitives/**/*.ts'],
|
||||||
'src/common/**/*.ts',
|
outbase: 'src/primitives',
|
||||||
'src/headless/**/*.ts'
|
outdir: 'out-esbuild/common',
|
||||||
],
|
},
|
||||||
outdir: 'out-esbuild/'
|
{
|
||||||
};
|
...outConfig,
|
||||||
|
entryPoints: ['src/runtime/**/*.ts'],
|
||||||
|
outbase: 'src/runtime',
|
||||||
|
outdir: 'out-esbuild/common',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...outConfig,
|
||||||
|
entryPoints: ['src/target-browser/**/*.ts'],
|
||||||
|
outbase: 'src',
|
||||||
|
outdir: 'out-esbuild',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...outConfig,
|
||||||
|
entryPoints: ['src/target-headless/**/*.ts'],
|
||||||
|
outbase: 'src',
|
||||||
|
outdir: 'out-esbuild',
|
||||||
|
},
|
||||||
|
];
|
||||||
outTestConfig = {
|
outTestConfig = {
|
||||||
...outConfig,
|
...outConfig,
|
||||||
entryPoints: ['test/**/*.ts'],
|
entryPoints: ['test/**/*.ts'],
|
||||||
@@ -205,7 +225,9 @@ if (config.addon) {
|
|||||||
if (config.isWatch) {
|
if (config.isWatch) {
|
||||||
context(bundleConfig).then(e => e.watch());
|
context(bundleConfig).then(e => e.watch());
|
||||||
if (!skipOut) {
|
if (!skipOut) {
|
||||||
context(outConfig).then(e => e.watch());
|
for (const buildConfig of outBuilds ?? [outConfig]) {
|
||||||
|
context(buildConfig).then(e => e.watch());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!skipOutTest) {
|
if (!skipOutTest) {
|
||||||
context(outTestConfig).then(e => e.watch());
|
context(outTestConfig).then(e => e.watch());
|
||||||
@@ -213,7 +235,9 @@ if (config.isWatch) {
|
|||||||
} else {
|
} else {
|
||||||
await build(bundleConfig);
|
await build(bundleConfig);
|
||||||
if (!skipOut) {
|
if (!skipOut) {
|
||||||
await build(outConfig);
|
for (const buildConfig of outBuilds ?? [outConfig]) {
|
||||||
|
await build(buildConfig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!skipOutTest) {
|
if (!skipOutTest) {
|
||||||
await build(outTestConfig);
|
await build(outTestConfig);
|
||||||
|
|||||||
+2
-5
@@ -19,17 +19,14 @@ for (const addon of addons) {
|
|||||||
// Demo job - This requires the others to be built so it's not included when building all
|
// Demo job - This requires the others to be built so it's not included when building all
|
||||||
// jobs.push(createJob('demo-client', [`--demo-client`]));
|
// jobs.push(createJob('demo-client', [`--demo-client`]));
|
||||||
|
|
||||||
const codes = await Promise.all(jobs.map(job => {
|
await Promise.all(jobs.map((job, i) => {
|
||||||
return new Promise(r => {
|
return new Promise(r => {
|
||||||
job.cp.on('exit', code => {
|
job.cp.on('exit', code => {
|
||||||
log(`Finished \x1b[32m${job.name}\x1b[0m${code ? ' \x1b[31mwith errors\x1b[0m' : ''}`);
|
log(`Finished \x1b[32m${job.name}\x1b[0m${code ? ' \x1b[31mwith errors\x1b[0m' : ''}`);
|
||||||
r(code ?? 1);
|
r(code);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
if (codes.some(code => code !== 0)) {
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} message
|
* @param {string} message
|
||||||
|
|||||||
+11
-41
@@ -33,47 +33,17 @@ if (files.length === 0) {
|
|||||||
|
|
||||||
console.log(`Linting ${files.length} changed file(s)...`);
|
console.log(`Linting ${files.length} changed file(s)...`);
|
||||||
|
|
||||||
const cwd = path.join(__dirname, '..');
|
const eslintArgs = ['--max-warnings', '0', '--no-warn-ignored'];
|
||||||
const isWin = process.platform === 'win32';
|
if (fix) {
|
||||||
|
eslintArgs.push('--fix');
|
||||||
/**
|
|
||||||
* @param {string} command
|
|
||||||
* @param {string[]} args
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
function run(command, args) {
|
|
||||||
return new Promise(/** @type {(resolve: () => void, reject: (reason: Error) => void) => void} */ ((resolve, reject) => {
|
|
||||||
const child = spawn(command, args, {
|
|
||||||
stdio: 'inherit',
|
|
||||||
cwd,
|
|
||||||
shell: isWin
|
|
||||||
});
|
|
||||||
child.on('close', code => {
|
|
||||||
if (code === 0) {
|
|
||||||
resolve();
|
|
||||||
} else {
|
|
||||||
reject(new Error(`${command} exited with code ${code}`));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
eslintArgs.push(...files);
|
||||||
|
|
||||||
async function main() {
|
const eslint = process.platform === 'win32' ? 'eslint.cmd' : 'eslint';
|
||||||
const oxlintArgs = ['--type-aware', '--max-warnings', '0'];
|
const child = spawn(eslint, eslintArgs, {
|
||||||
if (fix) {
|
stdio: 'inherit',
|
||||||
oxlintArgs.push('--fix');
|
cwd: path.join(__dirname, '..'),
|
||||||
}
|
shell: process.platform === 'win32'
|
||||||
oxlintArgs.push(...files);
|
|
||||||
|
|
||||||
const oxlint = isWin ? 'oxlint.cmd' : 'oxlint';
|
|
||||||
await run(oxlint, oxlintArgs);
|
|
||||||
|
|
||||||
const eslintArgs = ['--config', 'eslint.config.naming.mjs', '--max-warnings', '0', ...files];
|
|
||||||
const eslint = isWin ? 'eslint.cmd' : 'eslint';
|
|
||||||
await run(eslint, eslintArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
main().catch(err => {
|
|
||||||
console.error(err.message);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
child.on('close', code => process.exit(code ?? 0));
|
||||||
|
|||||||
+1
-1
@@ -81,7 +81,7 @@ function checkAndPublishPackage(packageDir, repoCommit, peerDependencies, update
|
|||||||
|
|
||||||
// Update Version.ts with the new version
|
// Update Version.ts with the new version
|
||||||
if (updateVersionTs) {
|
if (updateVersionTs) {
|
||||||
const versionTsPath = path.join(packageDir, 'src/common/Version.ts');
|
const versionTsPath = path.join(packageDir, 'src/primitives/Version.ts');
|
||||||
const versionTsContent = fs.readFileSync(versionTsPath, 'utf8');
|
const versionTsContent = fs.readFileSync(versionTsPath, 'utf8');
|
||||||
const updatedVersionTs = versionTsContent.replace(
|
const updatedVersionTs = versionTsContent.replace(
|
||||||
/export const XTERM_VERSION = '[^']+';/,
|
/export const XTERM_VERSION = '[^']+';/,
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@ import { spawnSync } from 'node:child_process';
|
|||||||
import { basename, dirname, resolve, sep } from 'node:path';
|
import { basename, dirname, resolve, sep } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
|
||||||
const nodeModulesPath = resolve(repoRoot, 'node_modules');
|
const nodeModulesPath = resolve(repoRoot, 'node_modules');
|
||||||
const npmExecutable = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
const npmExecutable = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ const npmExecutable = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|||||||
|
|
||||||
/** @param {string} message */
|
/** @param {string} message */
|
||||||
function log(message) {
|
function log(message) {
|
||||||
console.info(`[setup-full] ${message}`);
|
console.info(`[setup-fast] ${message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {string[]} args */
|
/** @param {string[]} args */
|
||||||
|
|||||||
+3
-12
@@ -12,7 +12,7 @@ let argv = process.argv.slice(2);
|
|||||||
let suiteFilter = undefined;
|
let suiteFilter = undefined;
|
||||||
while (argv.some(e => e.startsWith('--suite='))) {
|
while (argv.some(e => e.startsWith('--suite='))) {
|
||||||
const i = argv.findIndex(e => e.startsWith('--suite='));
|
const i = argv.findIndex(e => e.startsWith('--suite='));
|
||||||
const match = argv[i].match(/--suite=(?<suitename>.+)/);
|
const match = argv[i].match(/--suite=(?<suitename>.+)/)
|
||||||
suiteFilter = match?.groups?.suitename ?? undefined;
|
suiteFilter = match?.groups?.suitename ?? undefined;
|
||||||
argv.splice(i, 1);
|
argv.splice(i, 1);
|
||||||
}
|
}
|
||||||
@@ -42,18 +42,12 @@ if (suiteFilter) {
|
|||||||
configs = configs.filter(e => e.name === suiteFilter);
|
configs = configs.filter(e => e.name === suiteFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (suiteFilter && configs.length === 0) {
|
|
||||||
console.error(`Unknown suite: ${suiteFilter}`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function npmBinScript(script) {
|
function npmBinScript(script) {
|
||||||
return path.resolve(__dirname, `../node_modules/.bin/` + (process.platform === 'win32' ?
|
return path.resolve(__dirname, `../node_modules/.bin/` + (process.platform === 'win32' ?
|
||||||
`${script}.cmd` : script));
|
`${script}.cmd` : script));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
let exitCode = 0;
|
|
||||||
for (const config of configs) {
|
for (const config of configs) {
|
||||||
const command = npmBinScript('playwright');
|
const command = npmBinScript('playwright');
|
||||||
const args = ['test', '-c', config.path, ...argv];
|
const args = ['test', '-c', config.path, ...argv];
|
||||||
@@ -68,13 +62,10 @@ async function run() {
|
|||||||
|
|
||||||
if (run.error) {
|
if (run.error) {
|
||||||
console.error(run.error);
|
console.error(run.error);
|
||||||
process.exit(run.status ?? 1);
|
process.exit(run.status ?? -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (run.status) {
|
process.exit(run.status);
|
||||||
exitCode = run.status;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
process.exit(exitCode);
|
|
||||||
}
|
}
|
||||||
run();
|
run();
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ const ENC = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function printMenu() {
|
function printMenu() {
|
||||||
console.log('\x1b[2J\x1b[HTest mouse reports [Ctrl-C to exit]');
|
console.log('\x1b[2J\x1b\[HTest mouse reports [Ctrl-C to exit]');
|
||||||
console.log();
|
console.log();
|
||||||
console.log(' Selected protocol [Ctrl-A to switch]');
|
console.log(' Selected protocol [Ctrl-A to switch]');
|
||||||
const protocols = Object.keys(PROTOCOLS);
|
const protocols = Object.keys(PROTOCOLS);
|
||||||
|
|||||||
+5
-3
@@ -8,7 +8,7 @@ const path = require('path');
|
|||||||
|
|
||||||
const COVERAGE_LINES_THRESHOLD = 40;
|
const COVERAGE_LINES_THRESHOLD = 40;
|
||||||
|
|
||||||
// Add `out-esbuild` to NODE_PATH so addon path-mapped imports (common/*, browser/*) resolve.
|
// Add `out` to the NODE_PATH so absolute paths can be resolved.
|
||||||
const env = { ...process.env };
|
const env = { ...process.env };
|
||||||
env.NODE_PATH = path.resolve(__dirname, '../out-esbuild');
|
env.NODE_PATH = path.resolve(__dirname, '../out-esbuild');
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ if (process.argv.length > 2) {
|
|||||||
flagArgs = args.filter(e => e.startsWith('--'));
|
flagArgs = args.filter(e => e.startsWith('--'));
|
||||||
// ability to inject particular test files via
|
// ability to inject particular test files via
|
||||||
// npm run test [testFileA testFileB ...]
|
// npm run test [testFileA testFileB ...]
|
||||||
const files = args.filter(e => !e.startsWith('--'));
|
files = args.filter(e => !e.startsWith('--'));
|
||||||
if (files.length) {
|
if (files.length) {
|
||||||
testFiles = files;
|
testFiles = files;
|
||||||
}
|
}
|
||||||
@@ -39,6 +39,8 @@ if (checkCoverage) {
|
|||||||
...testFiles,
|
...testFiles,
|
||||||
...flagArgs
|
...flagArgs
|
||||||
];
|
];
|
||||||
|
console.info('executable', executable);
|
||||||
|
console.info('args', args);
|
||||||
const run = cp.spawnSync(
|
const run = cp.spawnSync(
|
||||||
executable,
|
executable,
|
||||||
args,
|
args,
|
||||||
@@ -49,7 +51,7 @@ if (checkCoverage) {
|
|||||||
stdio: 'inherit'
|
stdio: 'inherit'
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
process.exit(run.status ?? -1);
|
process.exit(run.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
const run = cp.spawnSync(
|
const run = cp.spawnSync(
|
||||||
|
|||||||
@@ -38,4 +38,4 @@ function findUnusedSymbols(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Example usage
|
// Example usage
|
||||||
findUnusedSymbols("./src/browser/tsconfig.json");
|
findUnusedSymbols("./src/target-browser/tsconfig.json");
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export class GpuWindow extends BaseWindow implements IControlWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _styleAtlasPage(canvas: HTMLCanvasElement): void {
|
private _styleAtlasPage(canvas: HTMLCanvasElement): void {
|
||||||
// oxlint-disable-next-line eslint-js/no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
const dpr = window.devicePixelRatio;
|
const dpr = window.devicePixelRatio;
|
||||||
canvas.style.width = `${canvas.width / dpr}px`;
|
canvas.style.width = `${canvas.width / dpr}px`;
|
||||||
canvas.style.height = `${canvas.height / dpr}px`;
|
canvas.style.height = `${canvas.height / dpr}px`;
|
||||||
|
|||||||
@@ -11,33 +11,8 @@ export class WebglWindow extends BaseWindow implements IControlWindow {
|
|||||||
public readonly label = 'webgl';
|
public readonly label = 'webgl';
|
||||||
|
|
||||||
private _textureAtlasContainer!: HTMLElement;
|
private _textureAtlasContainer!: HTMLElement;
|
||||||
private _stressRunning = false;
|
|
||||||
private _stressScrolling: HTMLInputElement | undefined;
|
|
||||||
|
|
||||||
public build(container: HTMLElement): void {
|
public build(container: HTMLElement): void {
|
||||||
const stressDiv = document.createElement('div');
|
|
||||||
const stressStart = document.createElement('button');
|
|
||||||
stressStart.id = 'stress-start';
|
|
||||||
stressStart.textContent = 'atlas stress start';
|
|
||||||
stressStart.addEventListener('click', () => this._stress());
|
|
||||||
stressDiv.appendChild(stressStart);
|
|
||||||
|
|
||||||
const stressStop = document.createElement('button');
|
|
||||||
stressStop.id = 'stress-stop';
|
|
||||||
stressStop.textContent = 'atlas stress stop';
|
|
||||||
stressStop.addEventListener('click', () => this._stressRunning = false);
|
|
||||||
stressDiv.appendChild(stressStop);
|
|
||||||
|
|
||||||
this._stressScrolling = document.createElement('input');
|
|
||||||
this._stressScrolling.type = 'checkbox';
|
|
||||||
this._stressScrolling.id = 'stress-scrolling';
|
|
||||||
stressDiv.appendChild(this._stressScrolling);
|
|
||||||
const stressScrollingLabel = document.createElement('label');
|
|
||||||
stressScrollingLabel.htmlFor = 'stress-scrolling';
|
|
||||||
stressScrollingLabel.textContent = 'stress scrolling';
|
|
||||||
stressDiv.appendChild(stressScrollingLabel);
|
|
||||||
container.appendChild(stressDiv);
|
|
||||||
|
|
||||||
const zoomCheckbox = document.createElement('input');
|
const zoomCheckbox = document.createElement('input');
|
||||||
zoomCheckbox.type = 'checkbox';
|
zoomCheckbox.type = 'checkbox';
|
||||||
zoomCheckbox.id = 'texture-atlas-zoom';
|
zoomCheckbox.id = 'texture-atlas-zoom';
|
||||||
@@ -68,38 +43,9 @@ export class WebglWindow extends BaseWindow implements IControlWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _styleAtlasPage(canvas: HTMLCanvasElement): void {
|
private _styleAtlasPage(canvas: HTMLCanvasElement): void {
|
||||||
// oxlint-disable-next-line eslint-js/no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
const dpr = window.devicePixelRatio;
|
const dpr = window.devicePixelRatio;
|
||||||
canvas.style.width = `${canvas.width / dpr}px`;
|
canvas.style.width = `${canvas.width / dpr}px`;
|
||||||
canvas.style.height = `${canvas.height / dpr}px`;
|
canvas.style.height = `${canvas.height / dpr}px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _stress(): Promise<void> {
|
|
||||||
const TEXT = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
|
|
||||||
if (this._stressRunning) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._stressRunning = true;
|
|
||||||
const scrolling = !!(this._stressScrolling?.checked);
|
|
||||||
for (let r = 0; r < 256; r += 2) {
|
|
||||||
for (let g = 0; g < 256; g += 2) {
|
|
||||||
let s: string[] = [];
|
|
||||||
for (let b = 0; b < 256; b += 2) {
|
|
||||||
if (!this._stressRunning) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const rbg = `RGB: ${[r, g, b]}`;
|
|
||||||
s.push(`\r\x1b[38;2;${r};${g};${b}m${rbg.padEnd(18, ' ')}${TEXT}`);
|
|
||||||
if (s.length >= 16) {
|
|
||||||
if (scrolling) {
|
|
||||||
await new Promise<void>(r => this._terminal.write(s.join('\r\n') + '\r\n', r));
|
|
||||||
} else {
|
|
||||||
await new Promise<void>(r => this._terminal.write('\x1b[H' + s.join('\r\n'), r));
|
|
||||||
}
|
|
||||||
s = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user