Merge branch 'master' into notebook/outputs
This commit is contained in:
commit
e3d0d9c00c
22
.github/workflows/author-verified.yml
vendored
22
.github/workflows/author-verified.yml
vendored
|
@ -1,9 +1,5 @@
|
|||
name: Author Verified
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: [trigger-author-verified]
|
||||
schedule:
|
||||
- cron: 20 14 * * * # 4:20pm Zurich
|
||||
issues:
|
||||
types: [closed]
|
||||
|
||||
|
@ -13,28 +9,22 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'author-verification-requested')
|
||||
if: contains(github.event.issue.labels.*.name, 'author-verification-requested') && contains(github.event.issue.labels.*.name, 'insiders-released')
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v42
|
||||
ref: stable
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'author-verification-requested')
|
||||
if: contains(github.event.issue.labels.*.name, 'author-verification-requested') && contains(github.event.issue.labels.*.name, 'insiders-released')
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Checkout Repo
|
||||
if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'author-verification-requested')
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: ./repo
|
||||
fetch-depth: 0
|
||||
- name: Run Author Verified
|
||||
if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'author-verification-requested')
|
||||
if: contains(github.event.issue.labels.*.name, 'author-verification-requested') && contains(github.event.issue.labels.*.name, 'insiders-released')
|
||||
uses: ./actions/author-verified
|
||||
with:
|
||||
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
|
||||
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
|
||||
requestVerificationComment: "This bug has been fixed in to the latest release of [VS Code Insiders](https://code.visualstudio.com/insiders/)!\n\n@${author}, you can help us out by commenting `/verified` if things are now working as expected.\n\nIf things still don't seem right, please ensure you're on version ${commit} of Insiders (today's or later - you can use `Help: About` in the command palette to check), and leave a comment letting us know what isn't working as expected.\n\nHappy Coding!"
|
||||
pendingReleaseLabel: awaiting-insiders-release
|
||||
requestVerificationComment: "This bug has been fixed in the latest release of [VS Code Insiders](https://code.visualstudio.com/insiders/)!\n\n@${author}, you can help us out by commenting `/verified` if things are now working as expected.\n\nIf things still don't seem right, please ensure you're on version ${commit} of Insiders (today's or later - you can use `Help: About` in the command palette to check), and leave a comment letting us know what isn't working as expected.\n\nHappy Coding!"
|
||||
releasedLabel: insiders-released
|
||||
verifiedLabel: verified
|
||||
authorVerificationRequestedLabel: author-verification-requested
|
||||
|
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v42
|
||||
ref: stable
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
|
|
2
.github/workflows/deep-classifier-runner.yml
vendored
2
.github/workflows/deep-classifier-runner.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v42
|
||||
ref: stable
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
|
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v42
|
||||
ref: stable
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
|
|
2
.github/workflows/english-please.yml
vendored
2
.github/workflows/english-please.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v42
|
||||
ref: stable
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
if: contains(github.event.issue.labels.*.name, '*english-please')
|
||||
|
|
2
.github/workflows/feature-request.yml
vendored
2
.github/workflows/feature-request.yml
vendored
|
@ -18,7 +18,7 @@ jobs:
|
|||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
path: ./actions
|
||||
ref: v42
|
||||
ref: stable
|
||||
- name: Install Actions
|
||||
if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'feature-request')
|
||||
run: npm install --production --prefix ./actions
|
||||
|
|
2
.github/workflows/latest-release-monitor.yml
vendored
2
.github/workflows/latest-release-monitor.yml
vendored
|
@ -14,7 +14,7 @@ jobs:
|
|||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
path: ./actions
|
||||
ref: v42
|
||||
ref: stable
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Install Storage Module
|
||||
|
|
2
.github/workflows/locker.yml
vendored
2
.github/workflows/locker.yml
vendored
|
@ -14,7 +14,7 @@ jobs:
|
|||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
path: ./actions
|
||||
ref: v42
|
||||
ref: stable
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run Locker
|
||||
|
|
2
.github/workflows/needs-more-info-closer.yml
vendored
2
.github/workflows/needs-more-info-closer.yml
vendored
|
@ -14,7 +14,7 @@ jobs:
|
|||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
path: ./actions
|
||||
ref: v42
|
||||
ref: stable
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run Needs More Info Closer
|
||||
|
|
3
.github/workflows/no-yarn-lock-changes.yml
vendored
3
.github/workflows/no-yarn-lock-changes.yml
vendored
|
@ -1,8 +1,9 @@
|
|||
name: "Prevent yarn.lock changes in PRs"
|
||||
name: Prevent yarn.lock changes in PRs
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
main:
|
||||
name: Prevent yarn.lock changes in PRs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: file_changes
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name: Commands
|
||||
name: On Comment
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
@ -13,7 +13,7 @@ jobs:
|
|||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
path: ./actions
|
||||
ref: v42
|
||||
ref: stable
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run Commands
|
||||
|
@ -22,3 +22,10 @@ jobs:
|
|||
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
|
||||
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
|
||||
config-path: commands
|
||||
- name: "Run Release Pipeline Labeler"
|
||||
uses: ./actions/release-pipeline
|
||||
with:
|
||||
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
|
||||
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
|
||||
notYetReleasedLabel: unreleased
|
||||
insidersReleasedLabel: insiders-released
|
18
.github/workflows/on-label.yml
vendored
18
.github/workflows/on-label.yml
vendored
|
@ -11,29 +11,25 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v42
|
||||
ref: stable
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
|
||||
# source of truth in ./author-verified.yml
|
||||
- name: Checkout Repo
|
||||
if: contains(github.event.issue.labels.*.name, 'author-verification-requested')
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: ./repo
|
||||
fetch-depth: 0
|
||||
- name: Run Author Verified
|
||||
if: contains(github.event.issue.labels.*.name, 'author-verification-requested')
|
||||
if: contains(github.event.issue.labels.*.name, 'author-verification-requested') && contains(github.event.issue.labels.*.name, 'insiders-released')
|
||||
uses: ./actions/author-verified
|
||||
with:
|
||||
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
|
||||
requestVerificationComment: "This bug has been fixed in to the latest release of [VS Code Insiders](https://code.visualstudio.com/insiders/)!\n\n@${author}, you can help us out by confirming things are working as expected in the latest Insiders release. If things look good, please leave a comment with the text `/verified` to let us know. If not, please ensure you're on version ${commit} of Insiders (today's or later - you can use `Help: About` in the command palette to check), and leave a comment letting us know what isn't working as expected.\n\nHappy Coding!"
|
||||
pendingReleaseLabel: awaiting-insiders-release
|
||||
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
|
||||
requestVerificationComment: "This bug has been fixed in the latest release of [VS Code Insiders](https://code.visualstudio.com/insiders/)!\n\n@${author}, you can help us out by commenting `/verified` if things are now working as expected.\n\nIf things still don't seem right, please ensure you're on version ${commit} of Insiders (today's or later - you can use `Help: About` in the command palette to check), and leave a comment letting us know what isn't working as expected.\n\nHappy Coding!"
|
||||
releasedLabel: insiders-released
|
||||
verifiedLabel: verified
|
||||
authorVerificationRequestedLabel: author-verification-requested
|
||||
|
||||
# source of truth in ./commands.yml
|
||||
|
||||
# also make changes in ./on-comment.yml
|
||||
- name: Run Commands
|
||||
uses: ./actions/commands
|
||||
with:
|
||||
|
|
2
.github/workflows/on-open.yml
vendored
2
.github/workflows/on-open.yml
vendored
|
@ -11,7 +11,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v42
|
||||
ref: stable
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
|
|
|
@ -13,7 +13,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
ref: v42
|
||||
ref: stable
|
||||
path: ./actions
|
||||
- name: Checkout Repo
|
||||
if: github.event_name != 'issues'
|
||||
|
|
|
@ -14,7 +14,7 @@ jobs:
|
|||
with:
|
||||
repository: "microsoft/vscode-github-triage-actions"
|
||||
path: ./actions
|
||||
ref: v42
|
||||
ref: stable
|
||||
- name: Install Actions
|
||||
if: contains(github.event.issue.labels.*.name, 'testplan-item') || contains(github.event.issue.labels.*.name, 'invalid-testplan-item')
|
||||
run: npm install --production --prefix ./actions
|
||||
|
|
3
.mailmap
3
.mailmap
|
@ -1,2 +1,5 @@
|
|||
Eric Amodio <eamodio@microsoft.com> Eric Amodio <eamodio@gmail.com>
|
||||
Daniel Imms <daimms@microsoft.com> Daniel Imms <tyriar@tyriar.com>
|
||||
Tanha Kabir <tanha.kabir@microsoft.com> Tanha Kabir <tanhakabir.ca@gmail.com>
|
||||
Raymond Zhao <raymondzhao@microsoft.com>
|
||||
Tyler Leonhardt <tyleonha@microsoft.com> Tyler Leonhardt <me@tylerleonhardt.com>
|
||||
|
|
|
@ -244,6 +244,16 @@ steps:
|
|||
displayName: Run smoke tests (Electron)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH)
|
||||
APP_NAME="`ls $APP_ROOT | head -n 1`"
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin" \
|
||||
yarn smoketest-no-compile --build "$APP_ROOT/$APP_NAME" --remote
|
||||
timeoutInMinutes: 5
|
||||
displayName: Run smoke tests (Remote)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \
|
||||
|
|
|
@ -218,6 +218,10 @@
|
|||
"name": "vs/workbench/contrib/webviewPanel",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/workspace",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/workspaces",
|
||||
"project": "vscode-workbench"
|
||||
|
|
|
@ -61,6 +61,18 @@
|
|||
"default": true,
|
||||
"description": "%css.validate.desc%"
|
||||
},
|
||||
"css.hover.documentation": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": true,
|
||||
"description": "%css.hover.documentation%"
|
||||
},
|
||||
"css.hover.references": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": true,
|
||||
"description": "%css.hover.references%"
|
||||
},
|
||||
"css.lint.compatibleVendorPrefixes": {
|
||||
"type": "string",
|
||||
"scope": "resource",
|
||||
|
@ -316,6 +328,18 @@
|
|||
"default": true,
|
||||
"description": "%scss.validate.desc%"
|
||||
},
|
||||
"scss.hover.documentation": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": true,
|
||||
"description": "%scss.hover.documentation%"
|
||||
},
|
||||
"scss.hover.references": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": true,
|
||||
"description": "%scss.hover.references%"
|
||||
},
|
||||
"scss.lint.compatibleVendorPrefixes": {
|
||||
"type": "string",
|
||||
"scope": "resource",
|
||||
|
@ -561,6 +585,18 @@
|
|||
"default": true,
|
||||
"description": "%less.validate.desc%"
|
||||
},
|
||||
"less.hover.documentation": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": true,
|
||||
"description": "%less.hover.documentation%"
|
||||
},
|
||||
"less.hover.references": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
"default": true,
|
||||
"description": "%less.hover.references%"
|
||||
},
|
||||
"less.lint.compatibleVendorPrefixes": {
|
||||
"type": "string",
|
||||
"scope": "resource",
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
"css.trace.server.desc": "Traces the communication between VS Code and the CSS language server.",
|
||||
"css.validate.title": "Controls CSS validation and problem severities.",
|
||||
"css.validate.desc": "Enables or disables all validations.",
|
||||
"css.hover.documentation": "Show tag and attribute documentation in CSS hovers.",
|
||||
"css.hover.references": "Show references to MDN in CSS hovers.",
|
||||
"less.title": "LESS",
|
||||
"less.completion.triggerPropertyValueCompletion.desc": "By default, VS Code triggers property value completion after selecting a CSS property. Use this setting to disable this behavior.",
|
||||
"less.completion.completePropertyWithSemicolon.desc": "Insert semicolon at end of line when completing CSS properties",
|
||||
|
@ -53,6 +55,8 @@
|
|||
"less.lint.zeroUnits.desc": "No unit for zero needed.",
|
||||
"less.validate.title": "Controls LESS validation and problem severities.",
|
||||
"less.validate.desc": "Enables or disables all validations.",
|
||||
"less.hover.documentation": "Show tag and attribute documentation in LESS hovers.",
|
||||
"less.hover.references": "Show references to MDN in LESS hovers.",
|
||||
"scss.title": "SCSS (Sass)",
|
||||
"scss.completion.triggerPropertyValueCompletion.desc": "By default, VS Code triggers property value completion after selecting a CSS property. Use this setting to disable this behavior.",
|
||||
"scss.completion.completePropertyWithSemicolon.desc": "Insert semicolon at end of line when completing CSS properties",
|
||||
|
@ -78,6 +82,8 @@
|
|||
"scss.lint.zeroUnits.desc": "No unit for zero needed.",
|
||||
"scss.validate.title": "Controls SCSS validation and problem severities.",
|
||||
"scss.validate.desc": "Enables or disables all validations.",
|
||||
"scss.hover.documentation": "Show tag and attribute documentation in SCSS hovers.",
|
||||
"scss.hover.references": "Show references to MDN in SCSS hovers.",
|
||||
"css.colorDecorators.enable.deprecationMessage": "The setting `css.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.",
|
||||
"scss.colorDecorators.enable.deprecationMessage": "The setting `scss.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.",
|
||||
"less.colorDecorators.enable.deprecationMessage": "The setting `less.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`."
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"main": "./out/node/cssServerMain",
|
||||
"browser": "./dist/browser/cssServerMain",
|
||||
"dependencies": {
|
||||
"vscode-css-languageservice": "^5.0.3",
|
||||
"vscode-css-languageservice": "^5.1.0",
|
||||
"vscode-languageserver": "^7.0.0",
|
||||
"vscode-uri": "^3.0.2"
|
||||
},
|
||||
|
|
|
@ -206,10 +206,10 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment)
|
|||
return runSafeAsync(async () => {
|
||||
const document = documents.get(textDocumentPosition.textDocument.uri);
|
||||
if (document) {
|
||||
await dataProvidersReady;
|
||||
const [settings,] = await Promise.all([getDocumentSettings(document), dataProvidersReady]);
|
||||
const styleSheet = stylesheets.get(document);
|
||||
const documentContext = getDocumentContext(document.uri, workspaceFolders);
|
||||
return getLanguageService(document).doComplete2(document, textDocumentPosition.position, styleSheet, documentContext);
|
||||
return getLanguageService(document).doComplete2(document, textDocumentPosition.position, styleSheet, documentContext, settings?.completion);
|
||||
}
|
||||
return null;
|
||||
}, null, `Error while computing completions for ${textDocumentPosition.textDocument.uri}`, token);
|
||||
|
@ -219,9 +219,9 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment)
|
|||
return runSafeAsync(async () => {
|
||||
const document = documents.get(textDocumentPosition.textDocument.uri);
|
||||
if (document) {
|
||||
await dataProvidersReady;
|
||||
const [settings,] = await Promise.all([getDocumentSettings(document), dataProvidersReady]);
|
||||
const styleSheet = stylesheets.get(document);
|
||||
return getLanguageService(document).doHover(document, textDocumentPosition.position, styleSheet);
|
||||
return getLanguageService(document).doHover(document, textDocumentPosition.position, styleSheet, settings?.hover);
|
||||
}
|
||||
return null;
|
||||
}, null, `Error while computing hover for ${textDocumentPosition.textDocument.uri}`, token);
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679"
|
||||
integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q==
|
||||
|
||||
vscode-css-languageservice@^5.0.3:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-5.0.3.tgz#2d400a47e73d0bfc5bc0d3fdf5be487cfdca341b"
|
||||
integrity sha512-KJt4jhCxqrgGrC02UsQsKw90dPkFknMHsH5HTInT7gkDRRfGFwEd+e2O1/E75br3TdFhvRmzjljYz5thZ58L3A==
|
||||
vscode-css-languageservice@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-5.1.0.tgz#cd172d13e9e7ae23ba567c73778aee10475ff716"
|
||||
integrity sha512-iLHd/WjRKgaZBXMNeUooHG+r0qlhJBkXa+3MpQQR6Rpm928cis/3OV2Mp1R80yAQevIMeDL32RIJfHoJCT/RRg==
|
||||
dependencies:
|
||||
vscode-languageserver-textdocument "^1.0.1"
|
||||
vscode-languageserver-types "^3.16.0"
|
||||
|
|
|
@ -439,7 +439,7 @@
|
|||
"@emmetio/html-matcher": "^0.3.3",
|
||||
"@emmetio/math-expression": "^1.0.4",
|
||||
"image-size": "^0.5.2",
|
||||
"vscode-emmet-helper": "2.2.4-3",
|
||||
"vscode-emmet-helper": "2.2.4",
|
||||
"vscode-languageserver-textdocument": "^1.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,10 +75,10 @@ jsonc-parser@^2.3.0:
|
|||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.3.1.tgz#59549150b133f2efacca48fe9ce1ec0659af2342"
|
||||
integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==
|
||||
|
||||
vscode-emmet-helper@2.2.4-3:
|
||||
version "2.2.4-3"
|
||||
resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.2.4-3.tgz#b1aed7eaaf0ecc2480c65c819f6e9d42d2d3cf5a"
|
||||
integrity sha512-M+pAiAro8nRiHb0/9lRoRzBod6DPlSwhOX26ZfM8n9a7/zr9ZJojxohDyGmnsApU5xVPhcrsNVI/fEagSeeO0Q==
|
||||
vscode-emmet-helper@2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.2.4.tgz#8ab86d2b7fe9e6270b4c77c9fd8d1eb8f3f4c401"
|
||||
integrity sha512-1N6bMzP1ZzkDGzamvsKxQ/lOmBc4+OQdj0dA2C9A5PSeYV9gh5xbJ061sm+VyFHOGZE+VyUQq5m/WFmFsLbKnA==
|
||||
dependencies:
|
||||
emmet "https://github.com/rzhao271/emmet.git#1b2df677d8925ef5ea6da9df8845968403979a0a"
|
||||
jsonc-parser "^2.3.0"
|
||||
|
|
|
@ -2140,6 +2140,15 @@
|
|||
"highContrast": "#c74e39"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gitDecoration.renamedResourceForeground",
|
||||
"description": "%colors.renamed%",
|
||||
"defaults": {
|
||||
"light": "#007100",
|
||||
"dark": "#73C991",
|
||||
"highContrast": "#73C991"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gitDecoration.untrackedResourceForeground",
|
||||
"description": "%colors.untracked%",
|
||||
|
@ -2180,9 +2189,9 @@
|
|||
"id": "gitDecoration.conflictingResourceForeground",
|
||||
"description": "%colors.conflict%",
|
||||
"defaults": {
|
||||
"light": "#6c6cc4",
|
||||
"dark": "#6c6cc4",
|
||||
"highContrast": "#6c6cc4"
|
||||
"light": "#ad0707",
|
||||
"dark": "#e4676b",
|
||||
"highContrast": "#c74e39"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -198,6 +198,7 @@
|
|||
"colors.stageModified": "Color for modified resources which have been staged.",
|
||||
"colors.stageDeleted": "Color for deleted resources which have been staged.",
|
||||
"colors.deleted": "Color for deleted resources.",
|
||||
"colors.renamed": "Color for renamed or copied resources.",
|
||||
"colors.untracked": "Color for untracked resources.",
|
||||
"colors.ignored": "Color for ignored resources.",
|
||||
"colors.conflict": "Color for resources with conflicts.",
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder, TimelineItem, env, Selection, TextDocumentContentProvider } from 'vscode';
|
||||
import { Command, commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder, TimelineItem, env, Selection, TextDocumentContentProvider } from 'vscode';
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Branch, ForcePushMode, GitErrorCodes, Ref, RefType, Status, CommitOptions, RemoteSourceProvider } from './api/git';
|
||||
|
@ -153,21 +153,21 @@ class AddRemoteItem implements QuickPickItem {
|
|||
}
|
||||
}
|
||||
|
||||
interface CommandOptions {
|
||||
interface ScmCommandOptions {
|
||||
repository?: boolean;
|
||||
diff?: boolean;
|
||||
}
|
||||
|
||||
interface Command {
|
||||
interface ScmCommand {
|
||||
commandId: string;
|
||||
key: string;
|
||||
method: Function;
|
||||
options: CommandOptions;
|
||||
options: ScmCommandOptions;
|
||||
}
|
||||
|
||||
const Commands: Command[] = [];
|
||||
const Commands: ScmCommand[] = [];
|
||||
|
||||
function command(commandId: string, options: CommandOptions = {}): Function {
|
||||
function command(commandId: string, options: ScmCommandOptions = {}): Function {
|
||||
return (_target: any, key: string, descriptor: any) => {
|
||||
if (!(typeof descriptor.value === 'function')) {
|
||||
throw new Error('not supported');
|
||||
|
@ -2612,6 +2612,22 @@ export class CommandCenter {
|
|||
|
||||
@command('git.timeline.openDiff', { repository: false })
|
||||
async timelineOpenDiff(item: TimelineItem, uri: Uri | undefined, _source: string) {
|
||||
const cmd = this.resolveTimelineOpenDiffCommand(
|
||||
item, uri,
|
||||
{
|
||||
preserveFocus: true,
|
||||
preview: true,
|
||||
viewColumn: ViewColumn.Active
|
||||
},
|
||||
);
|
||||
if (cmd === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return commands.executeCommand(cmd.command, ...(cmd.arguments ?? []));
|
||||
}
|
||||
|
||||
resolveTimelineOpenDiffCommand(item: TimelineItem, uri: Uri | undefined, options?: TextDocumentShowOptions): Command | undefined {
|
||||
if (uri === undefined || uri === null || !GitTimelineItem.is(item)) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -2628,13 +2644,11 @@ export class CommandCenter {
|
|||
title = localize('git.title.diffRefs', '{0} ({1}) ⟷ {0} ({2})', basename, item.shortPreviousRef, item.shortRef);
|
||||
}
|
||||
|
||||
const options: TextDocumentShowOptions = {
|
||||
preserveFocus: true,
|
||||
preview: true,
|
||||
viewColumn: ViewColumn.Active
|
||||
return {
|
||||
command: 'vscode.diff',
|
||||
title: 'Open Comparison',
|
||||
arguments: [toGitUri(uri, item.previousRef), item.ref === '' ? uri : toGitUri(uri, item.ref), title, options]
|
||||
};
|
||||
|
||||
return commands.executeCommand('vscode.diff', toGitUri(uri, item.previousRef), item.ref === '' ? uri : toGitUri(uri, item.ref), title, options);
|
||||
}
|
||||
|
||||
@command('git.timeline.copyCommitId', { repository: false })
|
||||
|
@ -2664,7 +2678,7 @@ export class CommandCenter {
|
|||
}
|
||||
}
|
||||
|
||||
private createCommand(id: string, key: string, method: Function, options: CommandOptions): (...args: any[]) => any {
|
||||
private createCommand(id: string, key: string, method: Function, options: ScmCommandOptions): (...args: any[]) => any {
|
||||
const result = (...args: any[]) => {
|
||||
let result: Promise<any>;
|
||||
|
||||
|
|
|
@ -73,12 +73,13 @@ async function createModel(context: ExtensionContext, outputChannel: OutputChann
|
|||
git.onOutput.addListener('log', onOutput);
|
||||
disposables.push(toDisposable(() => git.onOutput.removeListener('log', onOutput)));
|
||||
|
||||
const cc = new CommandCenter(git, model, outputChannel, telemetryReporter);
|
||||
disposables.push(
|
||||
new CommandCenter(git, model, outputChannel, telemetryReporter),
|
||||
cc,
|
||||
new GitFileSystemProvider(model),
|
||||
new GitDecorations(model),
|
||||
new GitProtocolHandler(),
|
||||
new GitTimelineProvider(model)
|
||||
new GitTimelineProvider(model, cc)
|
||||
);
|
||||
|
||||
checkGitVersion(info);
|
||||
|
|
|
@ -55,13 +55,13 @@ export class Resource implements SourceControlResourceState {
|
|||
case Status.UNTRACKED: return localize('untracked', "Untracked");
|
||||
case Status.IGNORED: return localize('ignored', "Ignored");
|
||||
case Status.INTENT_TO_ADD: return localize('intent to add', "Intent to Add");
|
||||
case Status.BOTH_DELETED: return localize('both deleted', "Both Deleted");
|
||||
case Status.ADDED_BY_US: return localize('added by us', "Added By Us");
|
||||
case Status.DELETED_BY_THEM: return localize('deleted by them', "Deleted By Them");
|
||||
case Status.ADDED_BY_THEM: return localize('added by them', "Added By Them");
|
||||
case Status.DELETED_BY_US: return localize('deleted by us', "Deleted By Us");
|
||||
case Status.BOTH_ADDED: return localize('both added', "Both Added");
|
||||
case Status.BOTH_MODIFIED: return localize('both modified', "Both Modified");
|
||||
case Status.BOTH_DELETED: return localize('both deleted', "Conflict: Both Deleted");
|
||||
case Status.ADDED_BY_US: return localize('added by us', "Conflict: Added By Us");
|
||||
case Status.DELETED_BY_THEM: return localize('deleted by them', "Conflict: Deleted By Them");
|
||||
case Status.ADDED_BY_THEM: return localize('added by them', "Conflict: Added By Them");
|
||||
case Status.DELETED_BY_US: return localize('deleted by us', "Conflict: Deleted By Us");
|
||||
case Status.BOTH_ADDED: return localize('both added', "Conflict: Both Added");
|
||||
case Status.BOTH_MODIFIED: return localize('both modified', "Conflict: Both Modified");
|
||||
default: return '';
|
||||
}
|
||||
}
|
||||
|
@ -199,12 +199,13 @@ export class Resource implements SourceControlResourceState {
|
|||
case Status.DELETED_BY_US:
|
||||
return 'D';
|
||||
case Status.INDEX_COPIED:
|
||||
return 'C';
|
||||
case Status.BOTH_DELETED:
|
||||
case Status.ADDED_BY_US:
|
||||
case Status.ADDED_BY_THEM:
|
||||
case Status.BOTH_ADDED:
|
||||
case Status.BOTH_MODIFIED:
|
||||
return 'C';
|
||||
return '!'; // Using ! instead of ⚠, because the latter looks really bad on windows
|
||||
default:
|
||||
throw new Error('Unknown git status: ' + this.type);
|
||||
}
|
||||
|
@ -223,12 +224,13 @@ export class Resource implements SourceControlResourceState {
|
|||
case Status.INDEX_ADDED:
|
||||
case Status.INTENT_TO_ADD:
|
||||
return new ThemeColor('gitDecoration.addedResourceForeground');
|
||||
case Status.INDEX_COPIED:
|
||||
case Status.INDEX_RENAMED:
|
||||
return new ThemeColor('gitDecoration.renamedResourceForeground');
|
||||
case Status.UNTRACKED:
|
||||
return new ThemeColor('gitDecoration.untrackedResourceForeground');
|
||||
case Status.IGNORED:
|
||||
return new ThemeColor('gitDecoration.ignoredResourceForeground');
|
||||
case Status.INDEX_COPIED:
|
||||
case Status.BOTH_DELETED:
|
||||
case Status.ADDED_BY_US:
|
||||
case Status.DELETED_BY_THEM:
|
||||
|
@ -246,10 +248,10 @@ export class Resource implements SourceControlResourceState {
|
|||
switch (this.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.MODIFIED:
|
||||
case Status.INDEX_COPIED:
|
||||
return 2;
|
||||
case Status.IGNORED:
|
||||
return 3;
|
||||
case Status.INDEX_COPIED:
|
||||
case Status.BOTH_DELETED:
|
||||
case Status.ADDED_BY_US:
|
||||
case Status.DELETED_BY_THEM:
|
||||
|
|
|
@ -9,6 +9,7 @@ import { Model } from './model';
|
|||
import { Repository, Resource } from './repository';
|
||||
import { debounce } from './decorators';
|
||||
import { emojify, ensureEmojis } from './emoji';
|
||||
import { CommandCenter } from './commands';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
@ -73,7 +74,7 @@ export class GitTimelineProvider implements TimelineProvider {
|
|||
private repoDisposable: Disposable | undefined;
|
||||
private repoStatusDate: Date | undefined;
|
||||
|
||||
constructor(private readonly model: Model) {
|
||||
constructor(private readonly model: Model, private commands: CommandCenter) {
|
||||
this.disposable = Disposable.from(
|
||||
model.onDidOpenRepository(this.onRepositoriesChanged, this),
|
||||
workspace.onDidChangeConfiguration(this.onConfigurationChanged, this)
|
||||
|
@ -161,16 +162,20 @@ export class GitTimelineProvider implements TimelineProvider {
|
|||
const message = emojify(c.message);
|
||||
|
||||
const item = new GitTimelineItem(c.hash, commits[i + 1]?.hash ?? `${c.hash}^`, message, date?.getTime() ?? 0, c.hash, 'git:file:commit');
|
||||
item.iconPath = new (ThemeIcon as any)('git-commit');
|
||||
item.iconPath = new ThemeIcon('git-commit');
|
||||
if (showAuthor) {
|
||||
item.description = c.authorName;
|
||||
}
|
||||
item.detail = `${c.authorName} (${c.authorEmail}) — ${c.hash.substr(0, 8)}\n${dateFormatter.format(date)}\n\n${message}`;
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: 'git.timeline.openDiff',
|
||||
arguments: [item, uri, this.id]
|
||||
};
|
||||
|
||||
const cmd = this.commands.resolveTimelineOpenDiffCommand(item, uri);
|
||||
if (cmd) {
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: cmd.command,
|
||||
arguments: cmd.arguments,
|
||||
};
|
||||
}
|
||||
|
||||
return item;
|
||||
});
|
||||
|
@ -184,14 +189,18 @@ export class GitTimelineProvider implements TimelineProvider {
|
|||
|
||||
const item = new GitTimelineItem('~', 'HEAD', localize('git.timeline.stagedChanges', 'Staged Changes'), date.getTime(), 'index', 'git:file:index');
|
||||
// TODO@eamodio: Replace with a better icon -- reflecting its status maybe?
|
||||
item.iconPath = new (ThemeIcon as any)('git-commit');
|
||||
item.iconPath = new ThemeIcon('git-commit');
|
||||
item.description = '';
|
||||
item.detail = localize('git.timeline.detail', '{0} — {1}\n{2}\n\n{3}', you, localize('git.index', 'Index'), dateFormatter.format(date), Resource.getStatusText(index.type));
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: 'git.timeline.openDiff',
|
||||
arguments: [item, uri, this.id]
|
||||
};
|
||||
|
||||
const cmd = this.commands.resolveTimelineOpenDiffCommand(item, uri);
|
||||
if (cmd) {
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: cmd.command,
|
||||
arguments: cmd.arguments,
|
||||
};
|
||||
}
|
||||
|
||||
items.splice(0, 0, item);
|
||||
}
|
||||
|
@ -202,14 +211,18 @@ export class GitTimelineProvider implements TimelineProvider {
|
|||
|
||||
const item = new GitTimelineItem('', index ? '~' : 'HEAD', localize('git.timeline.uncommitedChanges', 'Uncommitted Changes'), date.getTime(), 'working', 'git:file:working');
|
||||
// TODO@eamodio: Replace with a better icon -- reflecting its status maybe?
|
||||
item.iconPath = new (ThemeIcon as any)('git-commit');
|
||||
item.iconPath = new ThemeIcon('git-commit');
|
||||
item.description = '';
|
||||
item.detail = localize('git.timeline.detail', '{0} — {1}\n{2}\n\n{3}', you, localize('git.workingTree', 'Working Tree'), dateFormatter.format(date), Resource.getStatusText(working.type));
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: 'git.timeline.openDiff',
|
||||
arguments: [item, uri, this.id]
|
||||
};
|
||||
|
||||
const cmd = this.commands.resolveTimelineOpenDiffCommand(item, uri);
|
||||
if (cmd) {
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: cmd.command,
|
||||
arguments: cmd.arguments,
|
||||
};
|
||||
}
|
||||
|
||||
items.splice(0, 0, item);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
},
|
||||
"main": "./out/node/htmlServerMain",
|
||||
"dependencies": {
|
||||
"vscode-css-languageservice": "^5.0.3",
|
||||
"vscode-css-languageservice": "^5.1.0",
|
||||
"vscode-html-languageservice": "^4.0.1",
|
||||
"vscode-languageserver": "^7.0.0",
|
||||
"vscode-nls": "^5.0.0",
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache';
|
||||
import { Stylesheet, LanguageService as CSSLanguageService } from 'vscode-css-languageservice';
|
||||
import { LanguageMode, Workspace, Color, TextDocument, Position, Range, CompletionList, DocumentContext, Settings } from './languageModes';
|
||||
import { LanguageMode, Workspace, Color, TextDocument, Position, Range, CompletionList, DocumentContext } from './languageModes';
|
||||
import { HTMLDocumentRegions, CSS_STYLE_RULE } from './embeddedSupport';
|
||||
|
||||
export function getCSSMode(cssLanguageService: CSSLanguageService, documentRegions: LanguageModelCache<HTMLDocumentRegions>, workspace: Workspace): LanguageMode {
|
||||
|
@ -23,11 +23,11 @@ export function getCSSMode(cssLanguageService: CSSLanguageService, documentRegio
|
|||
async doComplete(document: TextDocument, position: Position, documentContext: DocumentContext, _settings = workspace.settings) {
|
||||
let embedded = embeddedCSSDocuments.get(document);
|
||||
const stylesheet = cssStylesheets.get(embedded);
|
||||
return cssLanguageService.doComplete2(embedded, position, stylesheet, documentContext) || CompletionList.create();
|
||||
return cssLanguageService.doComplete2(embedded, position, stylesheet, documentContext, _settings?.css?.completion) || CompletionList.create();
|
||||
},
|
||||
async doHover(document: TextDocument, position: Position, settings?: Settings) {
|
||||
async doHover(document: TextDocument, position: Position, settings = workspace.settings) {
|
||||
let embedded = embeddedCSSDocuments.get(document);
|
||||
return cssLanguageService.doHover(embedded, position, cssStylesheets.get(embedded), settings?.html?.hover);
|
||||
return cssLanguageService.doHover(embedded, position, cssStylesheets.get(embedded), settings?.css?.hover);
|
||||
},
|
||||
async findDocumentHighlight(document: TextDocument, position: Position) {
|
||||
let embedded = embeddedCSSDocuments.get(document);
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679"
|
||||
integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q==
|
||||
|
||||
vscode-css-languageservice@^5.0.3:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-5.0.3.tgz#2d400a47e73d0bfc5bc0d3fdf5be487cfdca341b"
|
||||
integrity sha512-KJt4jhCxqrgGrC02UsQsKw90dPkFknMHsH5HTInT7gkDRRfGFwEd+e2O1/E75br3TdFhvRmzjljYz5thZ58L3A==
|
||||
vscode-css-languageservice@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-5.1.0.tgz#cd172d13e9e7ae23ba567c73778aee10475ff716"
|
||||
integrity sha512-iLHd/WjRKgaZBXMNeUooHG+r0qlhJBkXa+3MpQQR6Rpm928cis/3OV2Mp1R80yAQevIMeDL32RIJfHoJCT/RRg==
|
||||
dependencies:
|
||||
vscode-languageserver-textdocument "^1.0.1"
|
||||
vscode-languageserver-types "^3.16.0"
|
||||
|
|
|
@ -324,7 +324,7 @@ export async function createTask(packageManager: string, script: NpmTaskDefiniti
|
|||
const result: (string | ShellQuotedString)[] = new Array(cmd.length);
|
||||
for (let i = 0; i < cmd.length; i++) {
|
||||
if (/\s/.test(cmd[i])) {
|
||||
result[i] = { value: `${cmd[i]}`, quoting: ShellQuoting.Strong };
|
||||
result[i] = { value: cmd[i], quoting: cmd[i].includes('--') ? ShellQuoting.Weak : ShellQuoting.Strong };
|
||||
} else {
|
||||
result[i] = cmd[i];
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"jsonc-parser": "^2.2.1",
|
||||
"rimraf": "^2.6.3",
|
||||
"semver": "5.5.1",
|
||||
"typescript-vscode-sh-plugin": "^0.6.14",
|
||||
"vscode-extension-telemetry": "0.1.1",
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as rimraf from 'rimraf';
|
||||
import * as fs from 'fs';
|
||||
import * as vscode from 'vscode';
|
||||
import { Api, getExtensionApi } from './api';
|
||||
import { CommandManager } from './commands/commandManager';
|
||||
import { registerBaseCommands } from './commands/index';
|
||||
import { LanguageConfigurationManager } from './languageFeatures/languageConfiguration';
|
||||
import { createLazyClientHost, lazilyActivateClient } from './lazyClientHost';
|
||||
|
@ -13,7 +14,6 @@ import { nodeRequestCancellerFactory } from './tsServer/cancellation.electron';
|
|||
import { NodeLogDirectoryProvider } from './tsServer/logDirectoryProvider.electron';
|
||||
import { ChildServerProcess } from './tsServer/serverProcess.electron';
|
||||
import { DiskTypeScriptVersionProvider } from './tsServer/versionProvider.electron';
|
||||
import { CommandManager } from './commands/commandManager';
|
||||
import { onCaseInsenitiveFileSystem } from './utils/fileSystem.electron';
|
||||
import { PluginManager } from './utils/plugins';
|
||||
import * as temp from './utils/temp.electron';
|
||||
|
@ -62,5 +62,5 @@ export function activate(
|
|||
}
|
||||
|
||||
export function deactivate() {
|
||||
rimraf.sync(temp.getInstanceTempDir());
|
||||
fs.rmdirSync(temp.getInstanceTempDir(), { recursive: true });
|
||||
}
|
||||
|
|
|
@ -47,24 +47,6 @@ applicationinsights@1.0.8:
|
|||
diagnostic-channel-publishers "0.2.1"
|
||||
zone.js "0.7.6"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
diagnostic-channel-publishers@0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
|
||||
|
@ -77,67 +59,11 @@ diagnostic-channel@0.2.0:
|
|||
dependencies:
|
||||
semver "^5.3.0"
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
glob@^7.1.3:
|
||||
version "7.1.6"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
||||
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
jsonc-parser@^2.2.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.3.1.tgz#59549150b133f2efacca48fe9ce1ec0659af2342"
|
||||
integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==
|
||||
|
||||
minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
path-is-absolute@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
||||
|
||||
rimraf@^2.6.3:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
|
||||
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
semver@5.5.1:
|
||||
version "5.5.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477"
|
||||
|
@ -165,11 +91,6 @@ vscode-nls@^4.1.1:
|
|||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167"
|
||||
integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw==
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
zone.js@0.7.6:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"publisher": "vscode",
|
||||
"license": "MIT",
|
||||
"enableProposedApi": true,
|
||||
"requiresWorkspaceTrust": "onDemand",
|
||||
"private": true,
|
||||
"activationEvents": [],
|
||||
"main": "./out/extension",
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'mocha';
|
||||
import * as assert from 'assert';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
suite('vscode server cli', () => {
|
||||
|
||||
|
||||
test('extension is installed and enabled when installed by server cli', function () {
|
||||
const extension = process.env.TESTRESOLVER_INSTALL_BUILTIN_EXTENSION;
|
||||
if (!process.env.BUILD_SOURCEVERSION // Skip it when running out of sources
|
||||
|| !process.env.REMOTE_VSCODE // Skip it when not a remote integration test
|
||||
|| !extension // Skip it when extension is not provided to server
|
||||
) {
|
||||
this.skip();
|
||||
}
|
||||
|
||||
assert.ok(vscode.extensions.getExtension(extension!));
|
||||
});
|
||||
|
||||
});
|
|
@ -3,8 +3,8 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { window, Pseudoterminal, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget, Disposable, UIKind, env, EnvironmentVariableMutatorType, EnvironmentVariableMutator, extensions, ExtensionContext, TerminalOptions, ExtensionTerminalOptions } from 'vscode';
|
||||
import { doesNotThrow, equal, ok, deepEqual, throws } from 'assert';
|
||||
import { window, Pseudoterminal, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget, Disposable, UIKind, env, EnvironmentVariableMutatorType, EnvironmentVariableMutator, extensions, ExtensionContext, TerminalOptions, ExtensionTerminalOptions, Terminal } from 'vscode';
|
||||
import { doesNotThrow, equal, deepEqual, throws } from 'assert';
|
||||
import { assertNoRpc } from '../utils';
|
||||
|
||||
// Disable terminal tests:
|
||||
|
@ -36,19 +36,25 @@ import { assertNoRpc } from '../utils';
|
|||
disposables.length = 0;
|
||||
});
|
||||
|
||||
test('sendText immediately after createTerminal should not throw', (done) => {
|
||||
disposables.push(window.onDidOpenTerminal(term => {
|
||||
try {
|
||||
equal(terminal, term);
|
||||
} catch (e) {
|
||||
done(e);
|
||||
return;
|
||||
}
|
||||
terminal.dispose();
|
||||
disposables.push(window.onDidCloseTerminal(() => done()));
|
||||
}));
|
||||
test('sendText immediately after createTerminal should not throw', async () => {
|
||||
const terminal = window.createTerminal();
|
||||
const result = await new Promise<Terminal>(r => {
|
||||
disposables.push(window.onDidOpenTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r(t);
|
||||
}
|
||||
}));
|
||||
});
|
||||
equal(result, terminal);
|
||||
doesNotThrow(terminal.sendText.bind(terminal, 'echo "foo"'));
|
||||
await new Promise<void>(r => {
|
||||
disposables.push(window.onDidCloseTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r();
|
||||
}
|
||||
}));
|
||||
terminal.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
(process.platform === 'linux' ? test.skip : test)('echo works in the default shell', (done) => {
|
||||
|
@ -96,124 +102,133 @@ import { assertNoRpc } from '../utils';
|
|||
});
|
||||
});
|
||||
|
||||
test('onDidCloseTerminal event fires when terminal is disposed', (done) => {
|
||||
disposables.push(window.onDidOpenTerminal(term => {
|
||||
try {
|
||||
equal(terminal, term);
|
||||
} catch (e) {
|
||||
done(e);
|
||||
return;
|
||||
}
|
||||
terminal.dispose();
|
||||
disposables.push(window.onDidCloseTerminal(() => done()));
|
||||
}));
|
||||
test('onDidCloseTerminal event fires when terminal is disposed', async () => {
|
||||
const terminal = window.createTerminal();
|
||||
});
|
||||
|
||||
test('processId immediately after createTerminal should fetch the pid', (done) => {
|
||||
disposables.push(window.onDidOpenTerminal(term => {
|
||||
try {
|
||||
equal(terminal, term);
|
||||
} catch (e) {
|
||||
done(e);
|
||||
return;
|
||||
}
|
||||
terminal.processId.then(id => {
|
||||
try {
|
||||
ok(id && id > 0);
|
||||
} catch (e) {
|
||||
done(e);
|
||||
return;
|
||||
const result = await new Promise<Terminal>(r => {
|
||||
disposables.push(window.onDidOpenTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r(t);
|
||||
}
|
||||
terminal.dispose();
|
||||
disposables.push(window.onDidCloseTerminal(() => done()));
|
||||
});
|
||||
}));
|
||||
}));
|
||||
});
|
||||
equal(result, terminal);
|
||||
await new Promise<void>(r => {
|
||||
disposables.push(window.onDidCloseTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r();
|
||||
}
|
||||
}));
|
||||
terminal.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
test('processId immediately after createTerminal should fetch the pid', async () => {
|
||||
const terminal = window.createTerminal();
|
||||
const result = await new Promise<Terminal>(r => {
|
||||
disposables.push(window.onDidOpenTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r(t);
|
||||
}
|
||||
}));
|
||||
});
|
||||
equal(result, terminal);
|
||||
let pid = await result.processId;
|
||||
equal(true, pid && pid > 0);
|
||||
await new Promise<void>(r => {
|
||||
disposables.push(window.onDidCloseTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r();
|
||||
}
|
||||
}));
|
||||
terminal.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
test('name in constructor should set terminal.name', (done) => {
|
||||
disposables.push(window.onDidOpenTerminal(term => {
|
||||
try {
|
||||
equal(terminal, term);
|
||||
} catch (e) {
|
||||
done(e);
|
||||
return;
|
||||
}
|
||||
terminal.dispose();
|
||||
disposables.push(window.onDidCloseTerminal(() => done()));
|
||||
}));
|
||||
test('name in constructor should set terminal.name', async () => {
|
||||
const terminal = window.createTerminal('a');
|
||||
try {
|
||||
equal(terminal.name, 'a');
|
||||
} catch (e) {
|
||||
done(e);
|
||||
return;
|
||||
}
|
||||
const result = await new Promise<Terminal>(r => {
|
||||
disposables.push(window.onDidOpenTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r(t);
|
||||
}
|
||||
}));
|
||||
});
|
||||
equal(result, terminal);
|
||||
await new Promise<void>(r => {
|
||||
disposables.push(window.onDidCloseTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r();
|
||||
}
|
||||
}));
|
||||
terminal.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
test('creationOptions should be set and readonly for TerminalOptions terminals', (done) => {
|
||||
disposables.push(window.onDidOpenTerminal(term => {
|
||||
try {
|
||||
equal(terminal, term);
|
||||
} catch (e) {
|
||||
done(e);
|
||||
return;
|
||||
}
|
||||
terminal.dispose();
|
||||
disposables.push(window.onDidCloseTerminal(() => done()));
|
||||
}));
|
||||
test('creationOptions should be set and readonly for TerminalOptions terminals', async () => {
|
||||
const options = {
|
||||
name: 'foo',
|
||||
hideFromUser: true
|
||||
};
|
||||
const terminal = window.createTerminal(options);
|
||||
try {
|
||||
equal(terminal.name, 'foo');
|
||||
const terminalOptions = terminal.creationOptions as TerminalOptions;
|
||||
equal(terminalOptions.name, 'foo');
|
||||
equal(terminalOptions.hideFromUser, true);
|
||||
throws(() => terminalOptions.name = 'bad', 'creationOptions should be readonly at runtime');
|
||||
} catch (e) {
|
||||
done(e);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
test('onDidOpenTerminal should fire when a terminal is created', (done) => {
|
||||
disposables.push(window.onDidOpenTerminal(term => {
|
||||
try {
|
||||
equal(term.name, 'b');
|
||||
} catch (e) {
|
||||
done(e);
|
||||
return;
|
||||
}
|
||||
disposables.push(window.onDidCloseTerminal(() => done()));
|
||||
terminal.dispose();
|
||||
}));
|
||||
const terminal = window.createTerminal('b');
|
||||
});
|
||||
|
||||
test('exitStatus.code should be set to undefined after a terminal is disposed', (done) => {
|
||||
disposables.push(window.onDidOpenTerminal(term => {
|
||||
try {
|
||||
equal(term, terminal);
|
||||
} catch (e) {
|
||||
done(e);
|
||||
return;
|
||||
}
|
||||
disposables.push(window.onDidCloseTerminal(t => {
|
||||
try {
|
||||
deepEqual(t.exitStatus, { code: undefined });
|
||||
} catch (e) {
|
||||
done(e);
|
||||
return;
|
||||
const terminalOptions = terminal.creationOptions as TerminalOptions;
|
||||
const result = await new Promise<Terminal>(r => {
|
||||
disposables.push(window.onDidOpenTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r(t);
|
||||
}
|
||||
}));
|
||||
});
|
||||
equal(result, terminal);
|
||||
await new Promise<void>(r => {
|
||||
disposables.push(window.onDidCloseTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r();
|
||||
}
|
||||
done();
|
||||
}));
|
||||
terminal.dispose();
|
||||
}));
|
||||
});
|
||||
throws(() => terminalOptions.name = 'bad', 'creationOptions should be readonly at runtime');
|
||||
});
|
||||
|
||||
test('onDidOpenTerminal should fire when a terminal is created', async () => {
|
||||
const terminal = window.createTerminal('b');
|
||||
const result = await new Promise<Terminal>(r => {
|
||||
disposables.push(window.onDidOpenTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r(t);
|
||||
}
|
||||
}));
|
||||
});
|
||||
equal(result, terminal);
|
||||
await new Promise<void>(r => {
|
||||
disposables.push(window.onDidCloseTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r();
|
||||
}
|
||||
}));
|
||||
terminal.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
test('exitStatus.code should be set to undefined after a terminal is disposed', async () => {
|
||||
const terminal = window.createTerminal();
|
||||
const result = await new Promise<Terminal>(r => {
|
||||
disposables.push(window.onDidOpenTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r(t);
|
||||
}
|
||||
}));
|
||||
});
|
||||
equal(result, terminal);
|
||||
await new Promise<void>(r => {
|
||||
disposables.push(window.onDidCloseTerminal(t => {
|
||||
if (t === terminal) {
|
||||
deepEqual(t.exitStatus, { code: undefined });
|
||||
r();
|
||||
}
|
||||
}));
|
||||
terminal.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
// test('onDidChangeActiveTerminal should fire when new terminals are created', (done) => {
|
||||
|
@ -287,23 +302,25 @@ import { assertNoRpc } from '../utils';
|
|||
// });
|
||||
|
||||
suite('hideFromUser', () => {
|
||||
test('should be available to terminals API', done => {
|
||||
test('should be available to terminals API', async () => {
|
||||
const terminal = window.createTerminal({ name: 'bg', hideFromUser: true });
|
||||
disposables.push(window.onDidOpenTerminal(t => {
|
||||
try {
|
||||
equal(t, terminal);
|
||||
equal(t.name, 'bg');
|
||||
ok(window.terminals.indexOf(terminal) !== -1);
|
||||
} catch (e) {
|
||||
done(e);
|
||||
return;
|
||||
}
|
||||
disposables.push(window.onDidCloseTerminal(() => {
|
||||
// reg3.dispose();
|
||||
done();
|
||||
const result = await new Promise<Terminal>(r => {
|
||||
disposables.push(window.onDidOpenTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r(t);
|
||||
}
|
||||
}));
|
||||
});
|
||||
equal(result, terminal);
|
||||
equal(true, window.terminals.indexOf(terminal) !== -1);
|
||||
await new Promise<void>(r => {
|
||||
disposables.push(window.onDidCloseTerminal(t => {
|
||||
if (t === terminal) {
|
||||
r();
|
||||
}
|
||||
}));
|
||||
terminal.dispose();
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -83,12 +83,6 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
const env = getNewEnv();
|
||||
const remoteDataDir = process.env['TESTRESOLVER_DATA_FOLDER'] || path.join(os.homedir(), serverDataFolderName || `${dataFolderName}-testresolver`);
|
||||
|
||||
const remoteExtension = process.env['TESTRESOLVER_REMOTE_EXTENSION'];
|
||||
if (remoteExtension) {
|
||||
commandArgs.push('--install-extension', remoteExtension);
|
||||
commandArgs.push('--start-server');
|
||||
}
|
||||
|
||||
env['VSCODE_AGENT_FOLDER'] = remoteDataDir;
|
||||
outputChannel.appendLine(`Using data folder at ${remoteDataDir}`);
|
||||
|
||||
|
@ -98,6 +92,11 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
const serverCommandPath = path.join(vscodePath, 'resources', 'server', 'bin-dev', serverCommand);
|
||||
extHostProcess = cp.spawn(serverCommandPath, commandArgs, { env, cwd: vscodePath });
|
||||
} else {
|
||||
const extensionToInstall = process.env['TESTRESOLVER_INSTALL_BUILTIN_EXTENSION'];
|
||||
if (extensionToInstall) {
|
||||
commandArgs.push('--install-builtin-extension', extensionToInstall);
|
||||
commandArgs.push('--start-server');
|
||||
}
|
||||
const serverCommand = process.platform === 'win32' ? 'server.cmd' : 'server.sh';
|
||||
let serverLocation = env['VSCODE_REMOTE_SERVER_PATH']; // support environment variable to specify location of server on disk
|
||||
if (!serverLocation) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.54.0",
|
||||
"distro": "a1836302c2aaab6ded8ad4a0871f74dbc42359f5",
|
||||
"distro": "e555ce6c25c9e08034b3ba25b24e32bc1b0815fb",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
|
@ -82,7 +82,7 @@
|
|||
"vscode-ripgrep": "^1.11.1",
|
||||
"vscode-sqlite3": "4.0.10",
|
||||
"vscode-textmate": "5.2.0",
|
||||
"xterm": "4.11.0-beta.2",
|
||||
"xterm": "4.11.0-beta.3",
|
||||
"xterm-addon-search": "0.8.0",
|
||||
"xterm-addon-unicode11": "0.3.0-beta.3",
|
||||
"xterm-addon-webgl": "0.10.0-beta.2",
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"vscode-regexpp": "^3.1.0",
|
||||
"vscode-ripgrep": "^1.11.1",
|
||||
"vscode-textmate": "5.2.0",
|
||||
"xterm": "4.11.0-beta.2",
|
||||
"xterm": "4.11.0-beta.3",
|
||||
"xterm-addon-search": "0.8.0",
|
||||
"xterm-addon-unicode11": "0.3.0-beta.3",
|
||||
"xterm-addon-webgl": "0.10.0-beta.2",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"tas-client-umd": "0.1.2",
|
||||
"vscode-oniguruma": "1.3.1",
|
||||
"vscode-textmate": "5.2.0",
|
||||
"xterm": "4.11.0-beta.2",
|
||||
"xterm": "4.11.0-beta.3",
|
||||
"xterm-addon-search": "0.8.0",
|
||||
"xterm-addon-unicode11": "0.3.0-beta.3",
|
||||
"xterm-addon-webgl": "0.10.0-beta.2"
|
||||
|
|
|
@ -42,7 +42,7 @@ xterm-addon-webgl@0.10.0-beta.2:
|
|||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.10.0-beta.2.tgz#520547b2f845b2f9265f1817140b0f4e114c4a55"
|
||||
integrity sha512-DLfmF5+H1M/0BABEaqJlLUasKck7TjyRWVlzGflFTWVCr7/Kqaf0al4KMlw3yWX76A1ITGXrWj0qbDn2Sixl2Q==
|
||||
|
||||
xterm@4.11.0-beta.2:
|
||||
version "4.11.0-beta.2"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.11.0-beta.2.tgz#a95560b61c771f54a336c2eb10e1472e556d9f4b"
|
||||
integrity sha512-0BUaAfuclnowirdOuB13OGgq6OUGg/8etnRVT6apgnOrLGOLRCE1NiL3KhxotleAf4gVP0m3iCxsIr3csDY40g==
|
||||
xterm@4.11.0-beta.3:
|
||||
version "4.11.0-beta.3"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.11.0-beta.3.tgz#f19b4aaabdd634a6e62a96d770d6a8e8be0664b9"
|
||||
integrity sha512-hmAbSwmgYDgQPE5A2UtfpU+Wta4PYIpsDlnGwbhC783OwcYK8ZW0XajhTIQGZywpZb9bXusNmpcGeVsqHYWGLg==
|
||||
|
|
|
@ -465,10 +465,10 @@ xterm-addon-webgl@0.10.0-beta.2:
|
|||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.10.0-beta.2.tgz#520547b2f845b2f9265f1817140b0f4e114c4a55"
|
||||
integrity sha512-DLfmF5+H1M/0BABEaqJlLUasKck7TjyRWVlzGflFTWVCr7/Kqaf0al4KMlw3yWX76A1ITGXrWj0qbDn2Sixl2Q==
|
||||
|
||||
xterm@4.11.0-beta.2:
|
||||
version "4.11.0-beta.2"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.11.0-beta.2.tgz#a95560b61c771f54a336c2eb10e1472e556d9f4b"
|
||||
integrity sha512-0BUaAfuclnowirdOuB13OGgq6OUGg/8etnRVT6apgnOrLGOLRCE1NiL3KhxotleAf4gVP0m3iCxsIr3csDY40g==
|
||||
xterm@4.11.0-beta.3:
|
||||
version "4.11.0-beta.3"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.11.0-beta.3.tgz#f19b4aaabdd634a6e62a96d770d6a8e8be0664b9"
|
||||
integrity sha512-hmAbSwmgYDgQPE5A2UtfpU+Wta4PYIpsDlnGwbhC783OwcYK8ZW0XajhTIQGZywpZb9bXusNmpcGeVsqHYWGLg==
|
||||
|
||||
yauzl@^2.9.2:
|
||||
version "2.10.0"
|
||||
|
|
|
@ -119,4 +119,5 @@ export const isWebkitWebView = (!isChrome && !isSafari && isWebKit);
|
|||
export const isIPad = (userAgent.indexOf('iPad') >= 0 || (isSafari && navigator.maxTouchPoints > 0));
|
||||
export const isEdgeLegacyWebView = isEdgeLegacy && (userAgent.indexOf('WebView/') >= 0);
|
||||
export const isElectron = (userAgent.indexOf('Electron/') >= 0);
|
||||
export const isAndroid = (userAgent.indexOf('Android') >= 0);
|
||||
export const isStandalone = (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches);
|
||||
|
|
|
@ -1476,12 +1476,13 @@ export class ModifierKeyEmitter extends Emitter<IModifierKeyStatus> {
|
|||
};
|
||||
|
||||
this._subscriptions.add(domEvent(document.body, 'keydown', true)(e => {
|
||||
// if keydown event is repeated, ignore it #112347
|
||||
if (e.repeat) {
|
||||
return;
|
||||
}
|
||||
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
// If Alt-key keydown event is repeated, ignore it #112347
|
||||
// Only known to be necessary for Alt-Key at the moment #115810
|
||||
if (event.keyCode === KeyCode.Alt && e.repeat) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.altKey && !this._keyStatus.altKey) {
|
||||
this._keyStatus.lastKeyPressed = 'alt';
|
||||
|
|
|
@ -746,7 +746,7 @@ export class MenuBar extends Disposable {
|
|||
private setUnfocusedState(): void {
|
||||
if (this.options.visibility === 'toggle' || this.options.visibility === 'hidden') {
|
||||
this.focusState = MenubarState.HIDDEN;
|
||||
} else if (this.options.visibility === 'default' && browser.isFullscreen()) {
|
||||
} else if (this.options.visibility === 'classic' && browser.isFullscreen()) {
|
||||
this.focusState = MenubarState.HIDDEN;
|
||||
} else {
|
||||
this.focusState = MenubarState.VISIBLE;
|
||||
|
@ -838,6 +838,22 @@ export class MenuBar extends Disposable {
|
|||
this._mnemonicsInUse = value;
|
||||
}
|
||||
|
||||
private get shouldAltKeyFocus(): boolean {
|
||||
if (isMacintosh) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.options.disableAltFocus) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.options.visibility === 'toggle') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public get onVisibilityChange(): Event<boolean> {
|
||||
return this._onVisibilityChange.event;
|
||||
}
|
||||
|
@ -869,7 +885,7 @@ export class MenuBar extends Disposable {
|
|||
}
|
||||
|
||||
// Prevent alt-key default if the menu is not hidden and we use alt to focus
|
||||
if (modifierKeyStatus.event && !this.options.disableAltFocus) {
|
||||
if (modifierKeyStatus.event && this.shouldAltKeyFocus) {
|
||||
if (ScanCodeUtils.toEnum(modifierKeyStatus.event.code) === ScanCode.AltLeft) {
|
||||
modifierKeyStatus.event.preventDefault();
|
||||
}
|
||||
|
@ -885,7 +901,7 @@ export class MenuBar extends Disposable {
|
|||
// Clean alt key press and release
|
||||
if (allModifiersReleased && modifierKeyStatus.lastKeyPressed === 'alt' && modifierKeyStatus.lastKeyReleased === 'alt') {
|
||||
if (!this.awaitingAltRelease) {
|
||||
if (!this.isFocused && !(this.options.disableAltFocus && this.options.visibility !== 'toggle')) {
|
||||
if (!this.isFocused && this.shouldAltKeyFocus) {
|
||||
this.mnemonicsInUse = true;
|
||||
this.focusedMenu = { index: this.numMenusShown > 0 ? 0 : MenuBar.OVERFLOW_INDEX };
|
||||
this.focusState = MenubarState.FOCUSED;
|
||||
|
|
|
@ -547,8 +547,8 @@ export namespace FuzzyScore {
|
|||
*/
|
||||
export const Default: FuzzyScore = ([-100, 0]);
|
||||
|
||||
export function isDefault(score?: FuzzyScore): score is [-100, 0, 0] {
|
||||
return !score || (score[0] === -100 && score[1] === 0 && score[2] === 0);
|
||||
export function isDefault(score?: FuzzyScore): score is [-100, 0] {
|
||||
return !score || (score.length === 2 && score[0] === -100 && score[1] === 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,14 @@
|
|||
|
||||
(function () {
|
||||
|
||||
let MonacoEnvironment = (<any>self).MonacoEnvironment;
|
||||
let monacoBaseUrl = MonacoEnvironment && MonacoEnvironment.baseUrl ? MonacoEnvironment.baseUrl : '../../../';
|
||||
const MonacoEnvironment = (<any>self).MonacoEnvironment;
|
||||
const monacoBaseUrl = MonacoEnvironment && MonacoEnvironment.baseUrl ? MonacoEnvironment.baseUrl : '../../../';
|
||||
|
||||
const trustedTypesPolicy = self.trustedTypes?.createPolicy('amdLoader', { createScriptURL: value => value });
|
||||
const trustedTypesPolicy = (
|
||||
typeof self.trustedTypes?.createPolicy === 'function'
|
||||
? self.trustedTypes?.createPolicy('amdLoader', { createScriptURL: value => value })
|
||||
: undefined
|
||||
);
|
||||
|
||||
if (typeof (<any>self).define !== 'function' || !(<any>self).define.amd) {
|
||||
let loaderSrc: string | TrustedScriptURL = monacoBaseUrl + 'vs/loader.js';
|
||||
|
|
|
@ -29,7 +29,7 @@ import { TelemetryAppenderChannel } from 'vs/platform/telemetry/common/telemetry
|
|||
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
|
||||
import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
|
||||
import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
import { ILogService, ILoggerService, MultiplexLogService, ConsoleLogService } from 'vs/platform/log/common/log';
|
||||
import { ILogService, ILoggerService, MultiplexLogService, ConsoleLogger } from 'vs/platform/log/common/log';
|
||||
import { LoggerChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc';
|
||||
import { LocalizationsService } from 'vs/platform/localizations/node/localizations';
|
||||
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
|
||||
|
@ -41,7 +41,7 @@ import { LanguagePackCachedDataCleaner } from 'vs/code/electron-browser/sharedPr
|
|||
import { StorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner';
|
||||
import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner';
|
||||
import { IMainProcessService, MessagePortMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
|
||||
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
|
||||
import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog';
|
||||
import { DiagnosticsService, IDiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService';
|
||||
import { FileService } from 'vs/platform/files/common/fileService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
|
@ -144,8 +144,8 @@ class SharedProcessMain extends Disposable {
|
|||
const mainRouter = new StaticRouter(ctx => ctx === 'main');
|
||||
const loggerClient = new LoggerChannelClient(this.server.getChannel('logger', mainRouter)); // we only use this for log levels
|
||||
const multiplexLogger = this._register(new MultiplexLogService([
|
||||
this._register(new ConsoleLogService(this.configuration.logLevel)),
|
||||
this._register(new SpdLogService('sharedprocess', environmentService.logsPath, this.configuration.logLevel))
|
||||
this._register(new ConsoleLogger(this.configuration.logLevel)),
|
||||
this._register(new SpdLogLogger('sharedprocess', environmentService.logsPath, this.configuration.logLevel))
|
||||
]));
|
||||
|
||||
const logService = this._register(new FollowerLogService(loggerClient, multiplexLogger));
|
||||
|
|
|
@ -20,7 +20,7 @@ import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiati
|
|||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { ILogService, ConsoleLogMainService, MultiplexLogService, getLogLevel } from 'vs/platform/log/common/log';
|
||||
import { ILogService, ConsoleMainLogger, MultiplexLogService, getLogLevel } from 'vs/platform/log/common/log';
|
||||
import { StateService } from 'vs/platform/state/node/stateService';
|
||||
import { IStateService } from 'vs/platform/state/node/state';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
@ -31,7 +31,7 @@ import { IRequestService } from 'vs/platform/request/common/request';
|
|||
import { RequestMainService } from 'vs/platform/request/electron-main/requestMainService';
|
||||
import { CodeApplication } from 'vs/code/electron-main/app';
|
||||
import { getPathLabel, mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
|
||||
import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog';
|
||||
import { BufferLogService } from 'vs/platform/log/common/bufferLog';
|
||||
import { setUnexpectedErrorHandler } from 'vs/base/common/errors';
|
||||
import { IThemeMainService, ThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
|
||||
|
@ -133,7 +133,7 @@ class CodeMain {
|
|||
|
||||
const mainIpcServer = await this.doStartup(args, logService, environmentService, lifecycleMainService, instantiationService, true);
|
||||
|
||||
bufferLogService.logger = new SpdLogService('main', environmentService.logsPath, bufferLogService.getLevel());
|
||||
bufferLogService.logger = new SpdLogLogger('main', environmentService.logsPath, bufferLogService.getLevel());
|
||||
once(lifecycleMainService.onWillShutdown)(() => {
|
||||
fileService.dispose();
|
||||
(configurationService as ConfigurationService).dispose();
|
||||
|
@ -154,7 +154,7 @@ class CodeMain {
|
|||
services.set(IEnvironmentService, environmentService);
|
||||
services.set(IEnvironmentMainService, environmentService);
|
||||
|
||||
const logService = new MultiplexLogService([new ConsoleLogMainService(getLogLevel(environmentService)), bufferLogService]);
|
||||
const logService = new MultiplexLogService([new ConsoleMainLogger(getLogLevel(environmentService)), bufferLogService]);
|
||||
process.once('exit', () => logService.dispose());
|
||||
services.set(ILogService, logService);
|
||||
|
||||
|
|
|
@ -1192,7 +1192,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
|||
private getMenuBarVisibility(): MenuBarVisibility {
|
||||
let menuBarVisibility = getMenuBarVisibility(this.configurationService);
|
||||
if (['visible', 'toggle', 'hidden'].indexOf(menuBarVisibility) < 0) {
|
||||
menuBarVisibility = 'default';
|
||||
menuBarVisibility = 'classic';
|
||||
}
|
||||
|
||||
return menuBarVisibility;
|
||||
|
@ -1227,7 +1227,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
|||
const isFullscreen = this.isFullScreen;
|
||||
|
||||
switch (visibility) {
|
||||
case ('default'):
|
||||
case ('classic'):
|
||||
this._win.setMenuBarVisibility(!isFullscreen);
|
||||
this._win.autoHideMenuBar = isFullscreen;
|
||||
break;
|
||||
|
|
|
@ -30,9 +30,9 @@ import { ConfigurationService } from 'vs/platform/configuration/common/configura
|
|||
import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
|
||||
import { IStateService } from 'vs/platform/state/node/state';
|
||||
import { StateService } from 'vs/platform/state/node/stateService';
|
||||
import { ILogService, getLogLevel, LogLevel, ConsoleLogService, MultiplexLogService } from 'vs/platform/log/common/log';
|
||||
import { ILogService, getLogLevel, LogLevel, ConsoleLogger, MultiplexLogService, ILogger } from 'vs/platform/log/common/log';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
|
||||
import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog';
|
||||
import { buildTelemetryMessage } from 'vs/platform/telemetry/node/telemetry';
|
||||
import { FileService } from 'vs/platform/files/common/fileService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
|
@ -104,10 +104,10 @@ class CliMain extends Disposable {
|
|||
|
||||
// Log
|
||||
const logLevel = getLogLevel(environmentService);
|
||||
const loggers: ILogService[] = [];
|
||||
loggers.push(new SpdLogService('cli', environmentService.logsPath, logLevel));
|
||||
const loggers: ILogger[] = [];
|
||||
loggers.push(new SpdLogLogger('cli', environmentService.logsPath, logLevel));
|
||||
if (logLevel === LogLevel.Trace) {
|
||||
loggers.push(new ConsoleLogService(logLevel));
|
||||
loggers.push(new ConsoleLogger(logLevel));
|
||||
}
|
||||
|
||||
const logService = this._register(new MultiplexLogService(loggers));
|
||||
|
|
|
@ -1931,6 +1931,7 @@ registerOverwritableCommand(Handler.Type, {
|
|||
}]
|
||||
});
|
||||
registerOverwritableCommand(Handler.ReplacePreviousChar);
|
||||
registerOverwritableCommand(Handler.CompositionType);
|
||||
registerOverwritableCommand(Handler.CompositionStart);
|
||||
registerOverwritableCommand(Handler.CompositionEnd);
|
||||
registerOverwritableCommand(Handler.Paste);
|
||||
|
|
|
@ -42,6 +42,7 @@ export interface IPointerHandlerHelper {
|
|||
linesContentDomNode: HTMLElement;
|
||||
|
||||
focusTextArea(): void;
|
||||
dispatchTextAreaEvent(event: CustomEvent): void;
|
||||
|
||||
/**
|
||||
* Get the last rendered information for cursors & textarea.
|
||||
|
|
|
@ -13,6 +13,7 @@ import { EditorMouseEvent, EditorPointerEventFactory } from 'vs/editor/browser/e
|
|||
import { ViewController } from 'vs/editor/browser/view/viewController';
|
||||
import { ViewContext } from 'vs/editor/common/view/viewContext';
|
||||
import { BrowserFeatures } from 'vs/base/browser/canIUse';
|
||||
import { TextAreaSyntethicEvents } from 'vs/editor/browser/controller/textAreaInput';
|
||||
|
||||
interface IThrottledGestureEvent {
|
||||
translationX: number;
|
||||
|
@ -210,6 +211,11 @@ class TouchHandler extends MouseHandler {
|
|||
const target = this._createMouseTarget(new EditorMouseEvent(event, this.viewHelper.viewDomNode), false);
|
||||
|
||||
if (target.position) {
|
||||
// Send the tap event also to the <textarea> (for input purposes)
|
||||
const event = document.createEvent('CustomEvent');
|
||||
event.initEvent(TextAreaSyntethicEvents.Tap, false, true);
|
||||
this.viewHelper.dispatchTextAreaEvent(event);
|
||||
|
||||
this.viewController.moveTo(target.position);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import * as platform from 'vs/base/common/platform';
|
|||
import * as strings from 'vs/base/common/strings';
|
||||
import { Configuration } from 'vs/editor/browser/config/configuration';
|
||||
import { CopyOptions, ICompositionData, IPasteData, ITextAreaInputHost, TextAreaInput, ClipboardDataToCopy } from 'vs/editor/browser/controller/textAreaInput';
|
||||
import { ISimpleModel, ITypeData, PagedScreenReaderStrategy, TextAreaState } from 'vs/editor/browser/controller/textAreaState';
|
||||
import { ISimpleModel, ITypeData, PagedScreenReaderStrategy, TextAreaState, _debugComposition } from 'vs/editor/browser/controller/textAreaState';
|
||||
import { ViewController } from 'vs/editor/browser/view/viewController';
|
||||
import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart';
|
||||
import { LineNumbersOverlay } from 'vs/editor/browser/viewParts/lineNumbers/lineNumbers';
|
||||
|
@ -202,6 +202,22 @@ export class TextAreaHandler extends ViewPart {
|
|||
return TextAreaState.EMPTY;
|
||||
}
|
||||
|
||||
if (browser.isAndroid) {
|
||||
// when tapping in the editor on a word, Android enters composition mode.
|
||||
// in the `compositionstart` event we cannot clear the textarea, because
|
||||
// it then forgets to ever send a `compositionend`.
|
||||
// we therefore only write the current word in the textarea
|
||||
const selection = this._selections[0];
|
||||
if (selection.isEmpty()) {
|
||||
const position = selection.getStartPosition();
|
||||
const [wordAtPosition, positionOffsetInWord] = this._getAndroidWordAtPosition(position);
|
||||
if (wordAtPosition.length > 0) {
|
||||
return new TextAreaState(wordAtPosition, positionOffsetInWord, positionOffsetInWord, position, position);
|
||||
}
|
||||
}
|
||||
return TextAreaState.EMPTY;
|
||||
}
|
||||
|
||||
return PagedScreenReaderStrategy.fromEditorSelection(currentState, simpleModel, this._selections[0], this._accessibilityPageSize, this._accessibilitySupport === AccessibilitySupport.Unknown);
|
||||
},
|
||||
|
||||
|
@ -237,9 +253,16 @@ export class TextAreaHandler extends ViewPart {
|
|||
}));
|
||||
|
||||
this._register(this._textAreaInput.onType((e: ITypeData) => {
|
||||
if (e.replaceCharCnt) {
|
||||
this._viewController.replacePreviousChar(e.text, e.replaceCharCnt);
|
||||
if (e.replacePrevCharCnt || e.replaceNextCharCnt || e.positionDelta) {
|
||||
// must be handled through the new command
|
||||
if (_debugComposition) {
|
||||
console.log(` => compositionType: <<${e.text}>>, ${e.replacePrevCharCnt}, ${e.replaceNextCharCnt}, ${e.positionDelta}`);
|
||||
}
|
||||
this._viewController.compositionType(e.text, e.replacePrevCharCnt, e.replaceNextCharCnt, e.positionDelta);
|
||||
} else {
|
||||
if (_debugComposition) {
|
||||
console.log(` => type: <<${e.text}>>`);
|
||||
}
|
||||
this._viewController.type(e.text);
|
||||
}
|
||||
}));
|
||||
|
@ -250,7 +273,7 @@ export class TextAreaHandler extends ViewPart {
|
|||
|
||||
this._register(this._textAreaInput.onCompositionStart((e) => {
|
||||
const lineNumber = this._selections[0].startLineNumber;
|
||||
const column = this._selections[0].startColumn - (e.moveOneCharacterLeft ? 1 : 0);
|
||||
const column = this._selections[0].startColumn + e.revealDeltaColumns;
|
||||
|
||||
this._context.model.revealRange(
|
||||
'keyboard',
|
||||
|
@ -280,8 +303,11 @@ export class TextAreaHandler extends ViewPart {
|
|||
}));
|
||||
|
||||
this._register(this._textAreaInput.onCompositionUpdate((e: ICompositionData) => {
|
||||
if (!this._visibleTextArea) {
|
||||
return;
|
||||
}
|
||||
// adjust width by its size
|
||||
this._visibleTextArea = this._visibleTextArea!.setWidth(measureText(e.data, this._fontInfo));
|
||||
this._visibleTextArea = this._visibleTextArea.setWidth(measureText(e.data, this._fontInfo));
|
||||
this._render();
|
||||
}));
|
||||
|
||||
|
@ -308,6 +334,47 @@ export class TextAreaHandler extends ViewPart {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
private _getAndroidWordAtPosition(position: Position): [string, number] {
|
||||
const ANDROID_WORD_SEPARATORS = '`~!@#$%^&*()-=+[{]}\\|;:",.<>/?';
|
||||
const lineContent = this._context.model.getLineContent(position.lineNumber);
|
||||
const wordSeparators = getMapForWordSeparators(ANDROID_WORD_SEPARATORS);
|
||||
|
||||
let goingLeft = true;
|
||||
let startColumn = position.column;
|
||||
let goingRight = true;
|
||||
let endColumn = position.column;
|
||||
let distance = 0;
|
||||
while (distance < 50 && (goingLeft || goingRight)) {
|
||||
if (goingLeft && startColumn <= 1) {
|
||||
goingLeft = false;
|
||||
}
|
||||
if (goingLeft) {
|
||||
const charCode = lineContent.charCodeAt(startColumn - 2);
|
||||
const charClass = wordSeparators.get(charCode);
|
||||
if (charClass !== WordCharacterClass.Regular) {
|
||||
goingLeft = false;
|
||||
} else {
|
||||
startColumn--;
|
||||
}
|
||||
}
|
||||
if (goingRight && endColumn > lineContent.length) {
|
||||
goingRight = false;
|
||||
}
|
||||
if (goingRight) {
|
||||
const charCode = lineContent.charCodeAt(endColumn - 1);
|
||||
const charClass = wordSeparators.get(charCode);
|
||||
if (charClass !== WordCharacterClass.Regular) {
|
||||
goingRight = false;
|
||||
} else {
|
||||
endColumn++;
|
||||
}
|
||||
}
|
||||
distance++;
|
||||
}
|
||||
|
||||
return [lineContent.substring(startColumn - 1, endColumn - 1), position.column - startColumn];
|
||||
}
|
||||
|
||||
private _getWordBeforePosition(position: Position): string {
|
||||
const lineContent = this._context.model.getLineContent(position.lineNumber);
|
||||
const wordSeparators = getMapForWordSeparators(this._context.configuration.options.get(EditorOption.wordSeparators));
|
||||
|
|
|
@ -18,6 +18,10 @@ import { Position } from 'vs/editor/common/core/position';
|
|||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { BrowserFeatures } from 'vs/base/browser/canIUse';
|
||||
|
||||
export namespace TextAreaSyntethicEvents {
|
||||
export const Tap = '-monaco-textarea-synthetic-tap';
|
||||
}
|
||||
|
||||
export interface ICompositionData {
|
||||
data: string;
|
||||
}
|
||||
|
@ -96,7 +100,7 @@ export class InMemoryClipboardMetadataManager {
|
|||
}
|
||||
|
||||
export interface ICompositionStartEvent {
|
||||
moveOneCharacterLeft: boolean;
|
||||
revealDeltaColumns: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -204,7 +208,6 @@ export class TextAreaInput extends Disposable {
|
|||
}
|
||||
this._isDoingComposition = true;
|
||||
|
||||
let moveOneCharacterLeft = false;
|
||||
if (
|
||||
platform.isMacintosh
|
||||
&& lastKeyDown
|
||||
|
@ -212,17 +215,12 @@ export class TextAreaInput extends Disposable {
|
|||
&& this._textAreaState.selectionStart === this._textAreaState.selectionEnd
|
||||
&& this._textAreaState.selectionStart > 0
|
||||
&& this._textAreaState.value.substr(this._textAreaState.selectionStart - 1, 1) === e.data
|
||||
&& (lastKeyDown.code === 'ArrowRight' || lastKeyDown.code === 'ArrowLeft')
|
||||
) {
|
||||
// Handling long press case on macOS + arrow key => pretend the character was selected
|
||||
if (lastKeyDown.code === 'ArrowRight' || lastKeyDown.code === 'ArrowLeft') {
|
||||
if (_debugComposition) {
|
||||
console.log(`[compositionstart] Handling long press case on macOS + arrow key`, e);
|
||||
}
|
||||
moveOneCharacterLeft = true;
|
||||
if (_debugComposition) {
|
||||
console.log(`[compositionstart] Handling long press case on macOS + arrow key`, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (moveOneCharacterLeft) {
|
||||
this._textAreaState = new TextAreaState(
|
||||
this._textAreaState.value,
|
||||
this._textAreaState.selectionStart - 1,
|
||||
|
@ -230,11 +228,19 @@ export class TextAreaInput extends Disposable {
|
|||
this._textAreaState.selectionStartPosition ? new Position(this._textAreaState.selectionStartPosition.lineNumber, this._textAreaState.selectionStartPosition.column - 1) : null,
|
||||
this._textAreaState.selectionEndPosition
|
||||
);
|
||||
} else {
|
||||
this._setAndWriteTextAreaState('compositionstart', TextAreaState.EMPTY);
|
||||
this._onCompositionStart.fire({ revealDeltaColumns: -1 });
|
||||
return;
|
||||
}
|
||||
|
||||
this._onCompositionStart.fire({ moveOneCharacterLeft });
|
||||
if (browser.isAndroid) {
|
||||
// when tapping on the editor, Android enters composition mode to edit the current word
|
||||
// so we cannot clear the textarea on Android and we must pretend the current word was selected
|
||||
this._onCompositionStart.fire({ revealDeltaColumns: -this._textAreaState.selectionStart });
|
||||
return;
|
||||
}
|
||||
|
||||
this._setAndWriteTextAreaState('compositionstart', TextAreaState.EMPTY);
|
||||
this._onCompositionStart.fire({ revealDeltaColumns: 0 });
|
||||
}));
|
||||
|
||||
/**
|
||||
|
@ -246,6 +252,12 @@ export class TextAreaInput extends Disposable {
|
|||
return [newState, TextAreaState.deduceInput(oldState, newState, couldBeEmojiInput)];
|
||||
};
|
||||
|
||||
const deduceAndroidCompositionInput = (): [TextAreaState, ITypeData] => {
|
||||
const oldState = this._textAreaState;
|
||||
const newState = TextAreaState.readFromTextArea(this._textArea);
|
||||
return [newState, TextAreaState.deduceAndroidCompositionInput(oldState, newState)];
|
||||
};
|
||||
|
||||
/**
|
||||
* Deduce the composition input from a string.
|
||||
*/
|
||||
|
@ -254,7 +266,9 @@ export class TextAreaInput extends Disposable {
|
|||
const newState = TextAreaState.selectedText(text);
|
||||
const typeInput: ITypeData = {
|
||||
text: newState.value,
|
||||
replaceCharCnt: oldState.selectionEnd - oldState.selectionStart
|
||||
replacePrevCharCnt: oldState.selectionEnd - oldState.selectionStart,
|
||||
replaceNextCharCnt: 0,
|
||||
positionDelta: 0
|
||||
};
|
||||
return [newState, typeInput];
|
||||
};
|
||||
|
@ -263,6 +277,17 @@ export class TextAreaInput extends Disposable {
|
|||
if (_debugComposition) {
|
||||
console.log(`[compositionupdate]`, e);
|
||||
}
|
||||
if (browser.isAndroid) {
|
||||
// On Android, the data sent with the composition update event is unusable.
|
||||
// For example, if the cursor is in the middle of a word like Mic|osoft
|
||||
// and Microsoft is chosen from the keyboard's suggestions, the e.data will contain "Microsoft".
|
||||
// This is not really usable because it doesn't tell us where the edit began and where it ended.
|
||||
const [newState, typeInput] = deduceAndroidCompositionInput();
|
||||
this._textAreaState = newState;
|
||||
this._onType.fire(typeInput);
|
||||
this._onCompositionUpdate.fire(e);
|
||||
return;
|
||||
}
|
||||
const [newState, typeInput] = deduceComposition(e.data || '');
|
||||
this._textAreaState = newState;
|
||||
this._onType.fire(typeInput);
|
||||
|
@ -278,6 +303,19 @@ export class TextAreaInput extends Disposable {
|
|||
if (!this._isDoingComposition) {
|
||||
return;
|
||||
}
|
||||
this._isDoingComposition = false;
|
||||
|
||||
if (browser.isAndroid) {
|
||||
// On Android, the data sent with the composition update event is unusable.
|
||||
// For example, if the cursor is in the middle of a word like Mic|osoft
|
||||
// and Microsoft is chosen from the keyboard's suggestions, the e.data will contain "Microsoft".
|
||||
// This is not really usable because it doesn't tell us where the edit began and where it ended.
|
||||
const [newState, typeInput] = deduceAndroidCompositionInput();
|
||||
this._textAreaState = newState;
|
||||
this._onType.fire(typeInput);
|
||||
this._onCompositionEnd.fire();
|
||||
return;
|
||||
}
|
||||
|
||||
const [newState, typeInput] = deduceComposition(e.data || '');
|
||||
this._textAreaState = newState;
|
||||
|
@ -290,11 +328,6 @@ export class TextAreaInput extends Disposable {
|
|||
this._textAreaState = TextAreaState.readFromTextArea(this._textArea);
|
||||
}
|
||||
|
||||
if (!this._isDoingComposition) {
|
||||
return;
|
||||
}
|
||||
this._isDoingComposition = false;
|
||||
|
||||
this._onCompositionEnd.fire();
|
||||
}));
|
||||
|
||||
|
@ -308,18 +341,18 @@ export class TextAreaInput extends Disposable {
|
|||
}
|
||||
|
||||
const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/platform.isMacintosh);
|
||||
if (typeInput.replaceCharCnt === 0 && typeInput.text.length === 1 && strings.isHighSurrogate(typeInput.text.charCodeAt(0))) {
|
||||
if (typeInput.replacePrevCharCnt === 0 && typeInput.text.length === 1 && strings.isHighSurrogate(typeInput.text.charCodeAt(0))) {
|
||||
// Ignore invalid input but keep it around for next time
|
||||
return;
|
||||
}
|
||||
|
||||
this._textAreaState = newState;
|
||||
if (this._nextCommand === ReadFromTextArea.Type) {
|
||||
if (typeInput.text !== '') {
|
||||
if (typeInput.text !== '' || typeInput.replacePrevCharCnt !== 0) {
|
||||
this._onType.fire(typeInput);
|
||||
}
|
||||
} else {
|
||||
if (typeInput.text !== '' || typeInput.replaceCharCnt !== 0) {
|
||||
if (typeInput.text !== '' || typeInput.replacePrevCharCnt !== 0) {
|
||||
this._firePaste(typeInput.text, null);
|
||||
}
|
||||
this._nextCommand = ReadFromTextArea.Type;
|
||||
|
@ -388,6 +421,21 @@ export class TextAreaInput extends Disposable {
|
|||
}
|
||||
this._setHasFocus(false);
|
||||
}));
|
||||
this._register(dom.addDisposableListener(textArea.domNode, TextAreaSyntethicEvents.Tap, () => {
|
||||
if (browser.isAndroid && this._isDoingComposition) {
|
||||
// on Android, tapping does not cancel the current composition, so the
|
||||
// textarea is stuck showing the old composition
|
||||
|
||||
// Clear the flag to be able to write to the textarea
|
||||
this._isDoingComposition = false;
|
||||
|
||||
// Clear the textarea to avoid an unwanted cursor type
|
||||
this.writeScreenReaderContent('tapWithoutCompositionEnd');
|
||||
|
||||
// Fire artificial composition end
|
||||
this._onCompositionEnd.fire();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private _installSelectionChangeListener(): IDisposable {
|
||||
|
|
|
@ -27,7 +27,9 @@ export interface ISimpleModel {
|
|||
|
||||
export interface ITypeData {
|
||||
text: string;
|
||||
replaceCharCnt: number;
|
||||
replacePrevCharCnt: number;
|
||||
replaceNextCharCnt: number;
|
||||
positionDelta: number;
|
||||
}
|
||||
|
||||
export class TextAreaState {
|
||||
|
@ -105,7 +107,9 @@ export class TextAreaState {
|
|||
// This is the EMPTY state
|
||||
return {
|
||||
text: '',
|
||||
replaceCharCnt: 0
|
||||
replacePrevCharCnt: 0,
|
||||
replaceNextCharCnt: 0,
|
||||
positionDelta: 0
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -178,7 +182,9 @@ export class TextAreaState {
|
|||
if (/\uFE0F/.test(potentialEmojiInput) || strings.containsEmoji(potentialEmojiInput)) {
|
||||
return {
|
||||
text: potentialEmojiInput,
|
||||
replaceCharCnt: 0
|
||||
replacePrevCharCnt: 0,
|
||||
replaceNextCharCnt: 0,
|
||||
positionDelta: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +203,9 @@ export class TextAreaState {
|
|||
if (strings.containsFullWidthCharacter(currentValue)) {
|
||||
return {
|
||||
text: '',
|
||||
replaceCharCnt: 0
|
||||
replacePrevCharCnt: 0,
|
||||
replaceNextCharCnt: 0,
|
||||
positionDelta: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -210,7 +218,9 @@ export class TextAreaState {
|
|||
|
||||
return {
|
||||
text: currentValue,
|
||||
replaceCharCnt: replacePreviousCharacters
|
||||
replacePrevCharCnt: replacePreviousCharacters,
|
||||
replaceNextCharCnt: 0,
|
||||
positionDelta: 0
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -218,7 +228,57 @@ export class TextAreaState {
|
|||
const replacePreviousCharacters = previousSelectionEnd - previousSelectionStart;
|
||||
return {
|
||||
text: currentValue,
|
||||
replaceCharCnt: replacePreviousCharacters
|
||||
replacePrevCharCnt: replacePreviousCharacters,
|
||||
replaceNextCharCnt: 0,
|
||||
positionDelta: 0
|
||||
};
|
||||
}
|
||||
|
||||
public static deduceAndroidCompositionInput(previousState: TextAreaState, currentState: TextAreaState): ITypeData {
|
||||
if (!previousState) {
|
||||
// This is the EMPTY state
|
||||
return {
|
||||
text: '',
|
||||
replacePrevCharCnt: 0,
|
||||
replaceNextCharCnt: 0,
|
||||
positionDelta: 0
|
||||
};
|
||||
}
|
||||
|
||||
if (_debugComposition) {
|
||||
console.log('------------------------deduceAndroidCompositionInput');
|
||||
console.log('PREVIOUS STATE: ' + previousState.toString());
|
||||
console.log('CURRENT STATE: ' + currentState.toString());
|
||||
}
|
||||
|
||||
if (previousState.value === currentState.value) {
|
||||
return {
|
||||
text: '',
|
||||
replacePrevCharCnt: 0,
|
||||
replaceNextCharCnt: 0,
|
||||
positionDelta: currentState.selectionEnd - previousState.selectionEnd
|
||||
};
|
||||
}
|
||||
|
||||
const prefixLength = Math.min(strings.commonPrefixLength(previousState.value, currentState.value), previousState.selectionEnd);
|
||||
const suffixLength = Math.min(strings.commonSuffixLength(previousState.value, currentState.value), previousState.value.length - previousState.selectionEnd);
|
||||
const previousValue = previousState.value.substring(prefixLength, previousState.value.length - suffixLength);
|
||||
const currentValue = currentState.value.substring(prefixLength, currentState.value.length - suffixLength);
|
||||
const previousSelectionStart = previousState.selectionStart - prefixLength;
|
||||
const previousSelectionEnd = previousState.selectionEnd - prefixLength;
|
||||
const currentSelectionStart = currentState.selectionStart - prefixLength;
|
||||
const currentSelectionEnd = currentState.selectionEnd - prefixLength;
|
||||
|
||||
if (_debugComposition) {
|
||||
console.log('AFTER DIFFING PREVIOUS STATE: <' + previousValue + '>, selectionStart: ' + previousSelectionStart + ', selectionEnd: ' + previousSelectionEnd);
|
||||
console.log('AFTER DIFFING CURRENT STATE: <' + currentValue + '>, selectionStart: ' + currentSelectionStart + ', selectionEnd: ' + currentSelectionEnd);
|
||||
}
|
||||
|
||||
return {
|
||||
text: currentValue,
|
||||
replacePrevCharCnt: previousSelectionEnd,
|
||||
replaceNextCharCnt: previousValue.length - previousSelectionEnd,
|
||||
positionDelta: currentSelectionEnd - currentValue.length
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import { URI } from 'vs/base/common/uri';
|
|||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { EditorOpenContext } from 'vs/platform/editor/common/editor';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IExternalOpener, IExternalUriResolver, IOpener, IOpenerService, IResolvedExternalUri, IValidator, matchesScheme, OpenOptions, ResolveExternalUriOptions } from 'vs/platform/opener/common/opener';
|
||||
|
||||
class CommandOpener implements IOpener {
|
||||
|
@ -106,6 +107,7 @@ export class OpenerService implements IOpenerService {
|
|||
constructor(
|
||||
@ICodeEditorService editorService: ICodeEditorService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@ILogService private logService: ILogService
|
||||
) {
|
||||
// Default external opener is going through window.open()
|
||||
this._defaultExternalOpener = {
|
||||
|
@ -166,7 +168,8 @@ export class OpenerService implements IOpenerService {
|
|||
// check with contributed validators
|
||||
const targetURI = typeof target === 'string' ? URI.parse(target) : target;
|
||||
// validate against the original URI that this URI resolves to, if one exists
|
||||
const validationTarget = this._resolvedUriTargets.get(targetURI) ?? target;
|
||||
const validationTarget = this._resolvedUriTargets.get(targetURI) ?? targetURI;
|
||||
this.logService.trace(`OpenerService#open: ${targetURI.authority} validating via ${validationTarget.authority}`);
|
||||
for (const validator of this._validators) {
|
||||
if (!(await validator.shouldOpen(validationTarget))) {
|
||||
return false;
|
||||
|
@ -188,7 +191,10 @@ export class OpenerService implements IOpenerService {
|
|||
for (const resolver of this._resolvers) {
|
||||
const result = await resolver.resolveExternalUri(resource, options);
|
||||
if (result) {
|
||||
this._resolvedUriTargets.set(result.resolved, resource);
|
||||
if (!this._resolvedUriTargets.has(result.resolved)) {
|
||||
this.logService.trace(`OpenerService#resolveExternalUri: ${resource.authority} resolved to ${result.resolved.authority}`);
|
||||
this._resolvedUriTargets.set(result.resolved, resource);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ export interface IMouseDispatchData {
|
|||
export interface ICommandDelegate {
|
||||
paste(text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void;
|
||||
type(text: string): void;
|
||||
replacePreviousChar(text: string, replaceCharCnt: number): void;
|
||||
compositionType(text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): void;
|
||||
startComposition(): void;
|
||||
endComposition(): void;
|
||||
cut(): void;
|
||||
|
@ -70,8 +70,8 @@ export class ViewController {
|
|||
this.commandDelegate.type(text);
|
||||
}
|
||||
|
||||
public replacePreviousChar(text: string, replaceCharCnt: number): void {
|
||||
this.commandDelegate.replacePreviousChar(text, replaceCharCnt);
|
||||
public compositionType(text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): void {
|
||||
this.commandDelegate.compositionType(text, replacePrevCharCnt, replaceNextCharCnt, positionDelta);
|
||||
}
|
||||
|
||||
public compositionStart(): void {
|
||||
|
|
|
@ -239,6 +239,10 @@ export class View extends ViewEventHandler {
|
|||
this.focus();
|
||||
},
|
||||
|
||||
dispatchTextAreaEvent: (event: CustomEvent) => {
|
||||
this._textAreaHandler.textArea.domNode.dispatchEvent(event);
|
||||
},
|
||||
|
||||
getLastRenderData: (): PointerHandlerLastRenderData => {
|
||||
const lastViewCursorsRenderData = this._viewCursors.getLastRenderData() || [];
|
||||
const lastTextareaPosition = this._textAreaHandler.getLastRenderData();
|
||||
|
|
|
@ -1002,7 +1002,12 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
}
|
||||
case editorCommon.Handler.ReplacePreviousChar: {
|
||||
const args = <Partial<editorCommon.ReplacePreviousCharPayload>>payload;
|
||||
this._replacePreviousChar(source, args.text || '', args.replaceCharCnt || 0);
|
||||
this._compositionType(source, args.text || '', args.replaceCharCnt || 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
case editorCommon.Handler.CompositionType: {
|
||||
const args = <Partial<editorCommon.CompositionTypePayload>>payload;
|
||||
this._compositionType(source, args.text || '', args.replacePrevCharCnt || 0, args.replaceNextCharCnt || 0, args.positionDelta || 0);
|
||||
return;
|
||||
}
|
||||
case editorCommon.Handler.Paste: {
|
||||
|
@ -1061,11 +1066,11 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
}
|
||||
}
|
||||
|
||||
private _replacePreviousChar(source: string | null | undefined, text: string, replaceCharCnt: number): void {
|
||||
private _compositionType(source: string | null | undefined, text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): void {
|
||||
if (!this._modelData) {
|
||||
return;
|
||||
}
|
||||
this._modelData.viewModel.replacePreviousChar(text, replaceCharCnt, source);
|
||||
this._modelData.viewModel.compositionType(text, replacePrevCharCnt, replaceNextCharCnt, positionDelta, source);
|
||||
}
|
||||
|
||||
private _paste(source: string | null | undefined, text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void {
|
||||
|
@ -1583,8 +1588,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
type: (text: string) => {
|
||||
this._type('keyboard', text);
|
||||
},
|
||||
replacePreviousChar: (text: string, replaceCharCnt: number) => {
|
||||
this._replacePreviousChar('keyboard', text, replaceCharCnt);
|
||||
compositionType: (text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number) => {
|
||||
this._compositionType('keyboard', text, replacePrevCharCnt, replaceNextCharCnt, positionDelta);
|
||||
},
|
||||
startComposition: () => {
|
||||
this._startComposition();
|
||||
|
@ -1606,9 +1611,16 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
const payload: editorCommon.TypePayload = { text };
|
||||
this._commandService.executeCommand(editorCommon.Handler.Type, payload);
|
||||
},
|
||||
replacePreviousChar: (text: string, replaceCharCnt: number) => {
|
||||
const payload: editorCommon.ReplacePreviousCharPayload = { text, replaceCharCnt };
|
||||
this._commandService.executeCommand(editorCommon.Handler.ReplacePreviousChar, payload);
|
||||
compositionType: (text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number) => {
|
||||
// Try if possible to go through the existing `replacePreviousChar` command
|
||||
if (replaceNextCharCnt || positionDelta) {
|
||||
// must be handled through the new command
|
||||
const payload: editorCommon.CompositionTypePayload = { text, replacePrevCharCnt, replaceNextCharCnt, positionDelta };
|
||||
this._commandService.executeCommand(editorCommon.Handler.CompositionType, payload);
|
||||
} else {
|
||||
const payload: editorCommon.ReplacePreviousCharPayload = { text, replaceCharCnt: replacePrevCharCnt };
|
||||
this._commandService.executeCommand(editorCommon.Handler.ReplacePreviousChar, payload);
|
||||
}
|
||||
},
|
||||
startComposition: () => {
|
||||
this._commandService.executeCommand(editorCommon.Handler.CompositionStart, {});
|
||||
|
|
|
@ -509,7 +509,7 @@ const editorConfiguration: IConfigurationNode = {
|
|||
nls.localize('wordBasedSuggestionsMode.matchingDocuments', 'Suggest words from all open documents of the same language.'),
|
||||
nls.localize('wordBasedSuggestionsMode.allDocuments', 'Suggest words from all open documents.')
|
||||
],
|
||||
description: nls.localize('wordBasedSuggestionsMode', "Controls form what documents word based completions are computed.")
|
||||
description: nls.localize('wordBasedSuggestionsMode', "Controls from what documents word based completions are computed.")
|
||||
},
|
||||
'editor.semanticHighlighting.enabled': {
|
||||
enum: [true, false, 'configuredByTheme'],
|
||||
|
|
|
@ -659,9 +659,21 @@ export class Cursor extends Disposable {
|
|||
}, eventsCollector, source);
|
||||
}
|
||||
|
||||
public replacePreviousChar(eventsCollector: ViewModelEventsCollector, text: string, replaceCharCnt: number, source?: string | null | undefined): void {
|
||||
public compositionType(eventsCollector: ViewModelEventsCollector, text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number, source?: string | null | undefined): void {
|
||||
if (text.length === 0 && replacePrevCharCnt === 0 && replaceNextCharCnt === 0) {
|
||||
// this edit is a no-op
|
||||
if (positionDelta !== 0) {
|
||||
// but it still wants to move the cursor
|
||||
const newSelections = this.getSelections().map(selection => {
|
||||
const position = selection.getPosition();
|
||||
return new Selection(position.lineNumber, position.column + positionDelta, position.lineNumber, position.column + positionDelta);
|
||||
});
|
||||
this.setSelections(eventsCollector, source, newSelections, CursorChangeReason.NotSet);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this._executeEdit(() => {
|
||||
this._executeEditOperation(TypeOperations.replacePreviousChar(this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), text, replaceCharCnt));
|
||||
this._executeEditOperation(TypeOperations.compositionType(this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), text, replacePrevCharCnt, replaceNextCharCnt, positionDelta));
|
||||
}, eventsCollector, source);
|
||||
}
|
||||
|
||||
|
|
|
@ -258,34 +258,33 @@ export class TypeOperations {
|
|||
return commands;
|
||||
}
|
||||
|
||||
public static replacePreviousChar(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], txt: string, replaceCharCnt: number): EditOperationResult {
|
||||
let commands: Array<ICommand | null> = [];
|
||||
for (let i = 0, len = selections.length; i < len; i++) {
|
||||
const selection = selections[i];
|
||||
if (!selection.isEmpty()) {
|
||||
// looks like https://github.com/microsoft/vscode/issues/2773
|
||||
// where a cursor operation occurred before a canceled composition
|
||||
// => ignore composition
|
||||
commands[i] = null;
|
||||
continue;
|
||||
}
|
||||
const pos = selection.getPosition();
|
||||
const startColumn = Math.max(1, pos.column - replaceCharCnt);
|
||||
const range = new Range(pos.lineNumber, startColumn, pos.lineNumber, pos.column);
|
||||
const oldText = model.getValueInRange(range);
|
||||
if (oldText === txt) {
|
||||
// => ignore composition that doesn't do anything
|
||||
commands[i] = null;
|
||||
continue;
|
||||
}
|
||||
commands[i] = new ReplaceCommand(range, txt);
|
||||
}
|
||||
public static compositionType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): EditOperationResult {
|
||||
const commands = selections.map(selection => this._compositionType(model, selection, text, replacePrevCharCnt, replaceNextCharCnt, positionDelta));
|
||||
return new EditOperationResult(EditOperationType.Typing, commands, {
|
||||
shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing),
|
||||
shouldPushStackElementAfter: false
|
||||
});
|
||||
}
|
||||
|
||||
private static _compositionType(model: ITextModel, selection: Selection, text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): ICommand | null {
|
||||
if (!selection.isEmpty()) {
|
||||
// looks like https://github.com/microsoft/vscode/issues/2773
|
||||
// where a cursor operation occurred before a canceled composition
|
||||
// => ignore composition
|
||||
return null;
|
||||
}
|
||||
const pos = selection.getPosition();
|
||||
const startColumn = Math.max(1, pos.column - replacePrevCharCnt);
|
||||
const endColumn = Math.min(model.getLineMaxColumn(pos.lineNumber), pos.column + replaceNextCharCnt);
|
||||
const range = new Range(pos.lineNumber, startColumn, pos.lineNumber, endColumn);
|
||||
const oldText = model.getValueInRange(range);
|
||||
if (oldText === text && positionDelta === 0) {
|
||||
// => ignore composition that doesn't do anything
|
||||
return null;
|
||||
}
|
||||
return new ReplaceCommandWithOffsetCursorState(range, text, 0, positionDelta);
|
||||
}
|
||||
|
||||
private static _typeCommand(range: Range, text: string, keepPosition: boolean): ICommand {
|
||||
if (keepPosition) {
|
||||
return new ReplaceCommandWithoutChangingPosition(range, text, true);
|
||||
|
|
|
@ -700,6 +700,7 @@ export const enum Handler {
|
|||
CompositionEnd = 'compositionEnd',
|
||||
Type = 'type',
|
||||
ReplacePreviousChar = 'replacePreviousChar',
|
||||
CompositionType = 'compositionType',
|
||||
Paste = 'paste',
|
||||
Cut = 'cut',
|
||||
}
|
||||
|
@ -719,6 +720,16 @@ export interface ReplacePreviousCharPayload {
|
|||
replaceCharCnt: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface CompositionTypePayload {
|
||||
text: string;
|
||||
replacePrevCharCnt: number;
|
||||
replaceNextCharCnt: number;
|
||||
positionDelta: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
|
|
@ -15,6 +15,7 @@ export const enum SemanticTokensProviderStylingConstants {
|
|||
export class SemanticTokensProviderStyling {
|
||||
|
||||
private readonly _hashTable: HashTable;
|
||||
private _hasWarnedOverlappingTokens: boolean;
|
||||
|
||||
constructor(
|
||||
private readonly _legend: SemanticTokensLegend,
|
||||
|
@ -22,6 +23,7 @@ export class SemanticTokensProviderStyling {
|
|||
private readonly _logService: ILogService
|
||||
) {
|
||||
this._hashTable = new HashTable();
|
||||
this._hasWarnedOverlappingTokens = false;
|
||||
}
|
||||
|
||||
public getMetadata(tokenTypeIndex: number, tokenModifierSet: number, languageId: LanguageIdentifier): number {
|
||||
|
@ -90,6 +92,14 @@ export class SemanticTokensProviderStyling {
|
|||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public warnOverlappingSemanticTokens(lineNumber: number, startColumn: number): void {
|
||||
if (!this._hasWarnedOverlappingTokens) {
|
||||
this._hasWarnedOverlappingTokens = true;
|
||||
console.warn(`Overlapping semantic tokens detected at lineNumber ${lineNumber}, column ${startColumn}`);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const enum SemanticColoringConstants {
|
||||
|
@ -142,6 +152,9 @@ export function toMultilineTokens2(tokens: SemanticTokens, styling: SemanticToke
|
|||
let destData = new Uint32Array((tokenEndIndex - tokenStartIndex) * 4);
|
||||
let destOffset = 0;
|
||||
let areaLine = 0;
|
||||
let prevLineNumber = 0;
|
||||
let prevStartCharacter = 0;
|
||||
let prevEndCharacter = 0;
|
||||
while (tokenIndex < tokenEndIndex) {
|
||||
const srcOffset = 5 * tokenIndex;
|
||||
const deltaLine = srcData[srcOffset];
|
||||
|
@ -157,11 +170,25 @@ export function toMultilineTokens2(tokens: SemanticTokens, styling: SemanticToke
|
|||
if (areaLine === 0) {
|
||||
areaLine = lineNumber;
|
||||
}
|
||||
if (prevLineNumber === lineNumber && prevEndCharacter > startCharacter) {
|
||||
styling.warnOverlappingSemanticTokens(lineNumber, startCharacter + 1);
|
||||
if (prevStartCharacter < startCharacter) {
|
||||
// the previous token survives after the overlapping one
|
||||
destData[destOffset - 4 + 2] = startCharacter;
|
||||
} else {
|
||||
// the previous token is entirely covered by the overlapping one
|
||||
destOffset -= 4;
|
||||
}
|
||||
}
|
||||
destData[destOffset] = lineNumber - areaLine;
|
||||
destData[destOffset + 1] = startCharacter;
|
||||
destData[destOffset + 2] = startCharacter + length;
|
||||
destData[destOffset + 3] = metadata;
|
||||
destOffset += 4;
|
||||
|
||||
prevLineNumber = lineNumber;
|
||||
prevStartCharacter = startCharacter;
|
||||
prevEndCharacter = startCharacter + length;
|
||||
}
|
||||
|
||||
lastLineNumber = lineNumber;
|
||||
|
|
|
@ -948,8 +948,8 @@ export class ViewModel extends Disposable implements IViewModel {
|
|||
public type(text: string, source?: string | null | undefined): void {
|
||||
this._executeCursorEdit(eventsCollector => this._cursor.type(eventsCollector, text, source));
|
||||
}
|
||||
public replacePreviousChar(text: string, replaceCharCnt: number, source?: string | null | undefined): void {
|
||||
this._executeCursorEdit(eventsCollector => this._cursor.replacePreviousChar(eventsCollector, text, replaceCharCnt, source));
|
||||
public compositionType(text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number, source?: string | null | undefined): void {
|
||||
this._executeCursorEdit(eventsCollector => this._cursor.compositionType(eventsCollector, text, replacePrevCharCnt, replaceNextCharCnt, positionDelta, source));
|
||||
}
|
||||
public paste(text: string, pasteOnNewLine: boolean, multicursorText?: string[] | null | undefined, source?: string | null | undefined): void {
|
||||
this._executeCursorEdit(eventsCollector => this._cursor.paste(eventsCollector, text, pasteOnNewLine, multicursorText, source));
|
||||
|
|
|
@ -43,6 +43,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService
|
|||
import { StandaloneThemeServiceImpl } from 'vs/editor/standalone/browser/standaloneThemeServiceImpl';
|
||||
import { splitLines } from 'vs/base/common/strings';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
|
||||
|
@ -56,7 +57,7 @@ function withAllStandaloneServices<T extends IEditor>(domElement: HTMLElement, o
|
|||
}
|
||||
|
||||
if (!services.has(IOpenerService)) {
|
||||
services.set(IOpenerService, new OpenerService(services.get(ICodeEditorService), services.get(ICommandService)));
|
||||
services.set(IOpenerService, new OpenerService(services.get(ICodeEditorService), services.get(ICommandService), services.get(ILogService)));
|
||||
}
|
||||
|
||||
let result = callback(services);
|
||||
|
|
|
@ -32,7 +32,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
|||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IListService, ListService } from 'vs/platform/list/browser/listService';
|
||||
import { ConsoleLogService, ILogService } from 'vs/platform/log/common/log';
|
||||
import { ConsoleLogger, ILogService, LogService } from 'vs/platform/log/common/log';
|
||||
import { MarkerService } from 'vs/platform/markers/common/markerService';
|
||||
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
@ -152,7 +152,7 @@ export module StaticServices {
|
|||
|
||||
export const standaloneThemeService = define(IStandaloneThemeService, () => new StandaloneThemeServiceImpl());
|
||||
|
||||
export const logService = define(ILogService, () => new ConsoleLogService());
|
||||
export const logService = define(ILogService, () => new LogService(new ConsoleLogger()));
|
||||
|
||||
export const undoRedoService = define(IUndoRedoService, (o) => new UndoRedoService(dialogService.get(o), notificationService.get(o)));
|
||||
|
||||
|
|
|
@ -2079,16 +2079,16 @@ suite('Editor Controller - Regression tests', () => {
|
|||
|
||||
// Typing sennsei in Japanese - Hiragana
|
||||
viewModel.type('s', 'keyboard');
|
||||
viewModel.replacePreviousChar('せ', 1);
|
||||
viewModel.replacePreviousChar('せn', 1);
|
||||
viewModel.replacePreviousChar('せん', 2);
|
||||
viewModel.replacePreviousChar('せんs', 2);
|
||||
viewModel.replacePreviousChar('せんせ', 3);
|
||||
viewModel.replacePreviousChar('せんせ', 3);
|
||||
viewModel.replacePreviousChar('せんせい', 3);
|
||||
viewModel.replacePreviousChar('せんせい', 4);
|
||||
viewModel.replacePreviousChar('せんせい', 4);
|
||||
viewModel.replacePreviousChar('せんせい', 4);
|
||||
viewModel.compositionType('せ', 1, 0, 0);
|
||||
viewModel.compositionType('せn', 1, 0, 0);
|
||||
viewModel.compositionType('せん', 2, 0, 0);
|
||||
viewModel.compositionType('せんs', 2, 0, 0);
|
||||
viewModel.compositionType('せんせ', 3, 0, 0);
|
||||
viewModel.compositionType('せんせ', 3, 0, 0);
|
||||
viewModel.compositionType('せんせい', 3, 0, 0);
|
||||
viewModel.compositionType('せんせい', 4, 0, 0);
|
||||
viewModel.compositionType('せんせい', 4, 0, 0);
|
||||
viewModel.compositionType('せんせい', 4, 0, 0);
|
||||
|
||||
assert.strictEqual(model.getLineContent(1), 'せんせい');
|
||||
assertCursor(viewModel, new Position(1, 5));
|
||||
|
@ -5449,7 +5449,7 @@ suite('autoClosingPairs', () => {
|
|||
// Typing ` + e on the mac US intl kb layout
|
||||
viewModel.startComposition();
|
||||
viewModel.type('`', 'keyboard');
|
||||
viewModel.replacePreviousChar('è', 1, 'keyboard');
|
||||
viewModel.compositionType('è', 1, 0, 0, 'keyboard');
|
||||
viewModel.endComposition('keyboard');
|
||||
|
||||
assert.strictEqual(model.getValue(), 'è');
|
||||
|
@ -5470,8 +5470,8 @@ suite('autoClosingPairs', () => {
|
|||
// Typing ` + e on the mac US intl kb layout
|
||||
viewModel.startComposition();
|
||||
viewModel.type('\'', 'keyboard');
|
||||
viewModel.replacePreviousChar('\'', 1, 'keyboard');
|
||||
viewModel.replacePreviousChar('\'', 1, 'keyboard');
|
||||
viewModel.compositionType('\'', 1, 0, 0, 'keyboard');
|
||||
viewModel.compositionType('\'', 1, 0, 0, 'keyboard');
|
||||
viewModel.endComposition('keyboard');
|
||||
|
||||
assert.strictEqual(model.getValue(), '\'test\'');
|
||||
|
@ -5550,8 +5550,8 @@ suite('autoClosingPairs', () => {
|
|||
viewModel.startComposition();
|
||||
viewModel.type('`', 'keyboard');
|
||||
moveDown(editor, viewModel, true);
|
||||
viewModel.replacePreviousChar('`', 1, 'keyboard');
|
||||
viewModel.replacePreviousChar('`', 1, 'keyboard');
|
||||
viewModel.compositionType('`', 1, 0, 0, 'keyboard');
|
||||
viewModel.compositionType('`', 1, 0, 0, 'keyboard');
|
||||
viewModel.endComposition('keyboard');
|
||||
|
||||
assert.strictEqual(model.getValue(), '`hello\nworld');
|
||||
|
@ -5575,14 +5575,14 @@ suite('autoClosingPairs', () => {
|
|||
// Typing ' + space
|
||||
viewModel.startComposition();
|
||||
viewModel.type('\'', 'keyboard');
|
||||
viewModel.replacePreviousChar('\'', 1, 'keyboard');
|
||||
viewModel.compositionType('\'', 1, 0, 0, 'keyboard');
|
||||
viewModel.endComposition('keyboard');
|
||||
assert.strictEqual(model.getValue(), '\'\'');
|
||||
|
||||
// Typing one more ' + space
|
||||
viewModel.startComposition();
|
||||
viewModel.type('\'', 'keyboard');
|
||||
viewModel.replacePreviousChar('\'', 1, 'keyboard');
|
||||
viewModel.compositionType('\'', 1, 0, 0, 'keyboard');
|
||||
viewModel.endComposition('keyboard');
|
||||
assert.strictEqual(model.getValue(), '\'\'');
|
||||
|
||||
|
@ -5591,7 +5591,7 @@ suite('autoClosingPairs', () => {
|
|||
viewModel.setSelections('test', [new Selection(1, 5, 1, 5)]);
|
||||
viewModel.startComposition();
|
||||
viewModel.type('\'', 'keyboard');
|
||||
viewModel.replacePreviousChar('\'', 1, 'keyboard');
|
||||
viewModel.compositionType('\'', 1, 0, 0, 'keyboard');
|
||||
viewModel.endComposition('keyboard');
|
||||
|
||||
assert.strictEqual(model.getValue(), '\'abc\'');
|
||||
|
@ -5601,7 +5601,7 @@ suite('autoClosingPairs', () => {
|
|||
viewModel.setSelections('test', [new Selection(1, 10, 1, 10)]);
|
||||
viewModel.startComposition();
|
||||
viewModel.type('\'', 'keyboard');
|
||||
viewModel.replacePreviousChar('\'', 1, 'keyboard');
|
||||
viewModel.compositionType('\'', 1, 0, 0, 'keyboard');
|
||||
viewModel.endComposition('keyboard');
|
||||
|
||||
assert.strictEqual(model.getValue(), '\'abc\'def \'\'');
|
||||
|
@ -5611,7 +5611,7 @@ suite('autoClosingPairs', () => {
|
|||
viewModel.setSelections('test', [new Selection(1, 1, 1, 1)]);
|
||||
viewModel.startComposition();
|
||||
viewModel.type('\'', 'keyboard');
|
||||
viewModel.replacePreviousChar('\'', 1, 'keyboard');
|
||||
viewModel.compositionType('\'', 1, 0, 0, 'keyboard');
|
||||
viewModel.endComposition('keyboard');
|
||||
|
||||
// No auto closing if it's after a word.
|
||||
|
@ -5619,7 +5619,7 @@ suite('autoClosingPairs', () => {
|
|||
viewModel.setSelections('test', [new Selection(1, 4, 1, 4)]);
|
||||
viewModel.startComposition();
|
||||
viewModel.type('\'', 'keyboard');
|
||||
viewModel.replacePreviousChar('\'', 1, 'keyboard');
|
||||
viewModel.compositionType('\'', 1, 0, 0, 'keyboard');
|
||||
viewModel.endComposition('keyboard');
|
||||
|
||||
assert.strictEqual(model.getValue(), 'abc\'');
|
||||
|
@ -5640,7 +5640,7 @@ suite('autoClosingPairs', () => {
|
|||
// Typing a + backspace
|
||||
viewModel.startComposition();
|
||||
viewModel.type('a', 'keyboard');
|
||||
viewModel.replacePreviousChar('', 1, 'keyboard');
|
||||
viewModel.compositionType('', 1, 0, 0, 'keyboard');
|
||||
viewModel.endComposition('keyboard');
|
||||
assert.strictEqual(model.getValue(), '{}');
|
||||
});
|
||||
|
|
|
@ -151,9 +151,9 @@ function doCreateTest(description: string, inputStr: string, expectedStr: string
|
|||
};
|
||||
|
||||
handler.onType((e) => {
|
||||
console.log('type text: ' + e.text + ', replaceCharCnt: ' + e.replaceCharCnt);
|
||||
console.log('type text: ' + e.text + ', replaceCharCnt: ' + e.replacePrevCharCnt);
|
||||
let text = model.getModelLineContent(1);
|
||||
let preText = text.substring(0, cursorOffset - e.replaceCharCnt);
|
||||
let preText = text.substring(0, cursorOffset - e.replacePrevCharCnt);
|
||||
let postText = text.substring(cursorOffset + cursorLength);
|
||||
let midText = e.text;
|
||||
|
||||
|
|
|
@ -134,8 +134,12 @@ suite('TextAreaState', () => {
|
|||
let newState = TextAreaState.readFromTextArea(textArea);
|
||||
let actual = TextAreaState.deduceInput(prevState, newState, couldBeEmojiInput);
|
||||
|
||||
assert.strictEqual(actual.text, expected);
|
||||
assert.strictEqual(actual.replaceCharCnt, expectedCharReplaceCnt);
|
||||
assert.deepStrictEqual(actual, {
|
||||
text: expected,
|
||||
replacePrevCharCnt: expectedCharReplaceCnt,
|
||||
replaceNextCharCnt: 0,
|
||||
positionDelta: 0,
|
||||
});
|
||||
|
||||
textArea.dispose();
|
||||
}
|
||||
|
@ -503,6 +507,82 @@ suite('TextAreaState', () => {
|
|||
);
|
||||
});
|
||||
|
||||
function testDeduceAndroidCompositionInput(
|
||||
prevState: TextAreaState | null,
|
||||
value: string, selectionStart: number, selectionEnd: number,
|
||||
expected: string, expectedReplacePrevCharCnt: number, expectedReplaceNextCharCnt: number, expectedPositionDelta: number): void {
|
||||
prevState = prevState || TextAreaState.EMPTY;
|
||||
|
||||
let textArea = new MockTextAreaWrapper();
|
||||
textArea._value = value;
|
||||
textArea._selectionStart = selectionStart;
|
||||
textArea._selectionEnd = selectionEnd;
|
||||
|
||||
let newState = TextAreaState.readFromTextArea(textArea);
|
||||
let actual = TextAreaState.deduceAndroidCompositionInput(prevState, newState);
|
||||
|
||||
assert.deepStrictEqual(actual, {
|
||||
text: expected,
|
||||
replacePrevCharCnt: expectedReplacePrevCharCnt,
|
||||
replaceNextCharCnt: expectedReplaceNextCharCnt,
|
||||
positionDelta: expectedPositionDelta,
|
||||
});
|
||||
|
||||
textArea.dispose();
|
||||
}
|
||||
|
||||
test('Android composition input 1', () => {
|
||||
testDeduceAndroidCompositionInput(
|
||||
new TextAreaState(
|
||||
'Microsoft',
|
||||
4, 4,
|
||||
null, null
|
||||
),
|
||||
'Microsoft',
|
||||
4, 4,
|
||||
'', 0, 0, 0,
|
||||
);
|
||||
});
|
||||
|
||||
test('Android composition input 2', () => {
|
||||
testDeduceAndroidCompositionInput(
|
||||
new TextAreaState(
|
||||
'Microsoft',
|
||||
4, 4,
|
||||
null, null
|
||||
),
|
||||
'Microsoft',
|
||||
0, 9,
|
||||
'', 0, 0, 5,
|
||||
);
|
||||
});
|
||||
|
||||
test('Android composition input 3', () => {
|
||||
testDeduceAndroidCompositionInput(
|
||||
new TextAreaState(
|
||||
'Microsoft',
|
||||
0, 9,
|
||||
null, null
|
||||
),
|
||||
'Microsoft\'s',
|
||||
11, 11,
|
||||
'\'s', 0, 0, 0,
|
||||
);
|
||||
});
|
||||
|
||||
test('Android backspace', () => {
|
||||
testDeduceAndroidCompositionInput(
|
||||
new TextAreaState(
|
||||
'undefinedVariable',
|
||||
2, 2,
|
||||
null, null
|
||||
),
|
||||
'udefinedVariable',
|
||||
1, 1,
|
||||
'', 1, 0, 0,
|
||||
);
|
||||
});
|
||||
|
||||
suite('PagedScreenReaderStrategy', () => {
|
||||
|
||||
function testPagedScreenReaderStrategy(lines: string[], selection: Selection, expected: TextAreaState): void {
|
||||
|
|
|
@ -8,6 +8,7 @@ import { URI } from 'vs/base/common/uri';
|
|||
import { OpenerService } from 'vs/editor/browser/services/openerService';
|
||||
import { TestCodeEditorService } from 'vs/editor/test/browser/editorTestServices';
|
||||
import { CommandsRegistry, ICommandService, NullCommandService } from 'vs/platform/commands/common/commands';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { matchesScheme } from 'vs/platform/opener/common/opener';
|
||||
|
||||
suite('OpenerService', function () {
|
||||
|
@ -30,13 +31,13 @@ suite('OpenerService', function () {
|
|||
});
|
||||
|
||||
test('delegate to editorService, scheme:///fff', async function () {
|
||||
const openerService = new OpenerService(editorService, NullCommandService);
|
||||
const openerService = new OpenerService(editorService, NullCommandService, new NullLogService());
|
||||
await openerService.open(URI.parse('another:///somepath'));
|
||||
assert.equal(editorService.lastInput!.options!.selection, undefined);
|
||||
});
|
||||
|
||||
test('delegate to editorService, scheme:///fff#L123', async function () {
|
||||
const openerService = new OpenerService(editorService, NullCommandService);
|
||||
const openerService = new OpenerService(editorService, NullCommandService, new NullLogService());
|
||||
|
||||
await openerService.open(URI.parse('file:///somepath#L23'));
|
||||
assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
|
||||
|
@ -58,7 +59,7 @@ suite('OpenerService', function () {
|
|||
});
|
||||
|
||||
test('delegate to editorService, scheme:///fff#123,123', async function () {
|
||||
const openerService = new OpenerService(editorService, NullCommandService);
|
||||
const openerService = new OpenerService(editorService, NullCommandService, new NullLogService());
|
||||
|
||||
await openerService.open(URI.parse('file:///somepath#23'));
|
||||
assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
|
||||
|
@ -76,7 +77,7 @@ suite('OpenerService', function () {
|
|||
});
|
||||
|
||||
test('delegate to commandsService, command:someid', async function () {
|
||||
const openerService = new OpenerService(editorService, commandService);
|
||||
const openerService = new OpenerService(editorService, commandService, new NullLogService());
|
||||
|
||||
const id = `aCommand${Math.random()}`;
|
||||
CommandsRegistry.registerCommand(id, function () { });
|
||||
|
@ -98,7 +99,7 @@ suite('OpenerService', function () {
|
|||
});
|
||||
|
||||
test('links are protected by validators', async function () {
|
||||
const openerService = new OpenerService(editorService, commandService);
|
||||
const openerService = new OpenerService(editorService, commandService, new NullLogService());
|
||||
|
||||
openerService.registerValidator({ shouldOpen: () => Promise.resolve(false) });
|
||||
|
||||
|
@ -109,7 +110,7 @@ suite('OpenerService', function () {
|
|||
});
|
||||
|
||||
test('links validated by validators go to openers', async function () {
|
||||
const openerService = new OpenerService(editorService, commandService);
|
||||
const openerService = new OpenerService(editorService, commandService, new NullLogService());
|
||||
|
||||
openerService.registerValidator({ shouldOpen: () => Promise.resolve(true) });
|
||||
|
||||
|
@ -128,7 +129,7 @@ suite('OpenerService', function () {
|
|||
});
|
||||
|
||||
test('links validated by multiple validators', async function () {
|
||||
const openerService = new OpenerService(editorService, commandService);
|
||||
const openerService = new OpenerService(editorService, commandService, new NullLogService());
|
||||
|
||||
let v1 = 0;
|
||||
openerService.registerValidator({
|
||||
|
@ -165,7 +166,7 @@ suite('OpenerService', function () {
|
|||
});
|
||||
|
||||
test('links invalidated by first validator do not continue validating', async function () {
|
||||
const openerService = new OpenerService(editorService, commandService);
|
||||
const openerService = new OpenerService(editorService, commandService, new NullLogService());
|
||||
|
||||
let v1 = 0;
|
||||
openerService.registerValidator({
|
||||
|
|
|
@ -35,10 +35,10 @@ export function testCommand(
|
|||
|
||||
cursor.executeCommand(commandFactory(cursor.getSelection()), 'tests');
|
||||
|
||||
assert.deepEqual(model.getLinesContent(), expectedLines);
|
||||
assert.deepStrictEqual(model.getLinesContent(), expectedLines);
|
||||
|
||||
let actualSelection = cursor.getSelection();
|
||||
assert.deepEqual(actualSelection.toString(), expectedSelection.toString());
|
||||
assert.deepStrictEqual(actualSelection.toString(), expectedSelection.toString());
|
||||
|
||||
});
|
||||
model.dispose();
|
||||
|
|
|
@ -20,7 +20,7 @@ export function testApplyEditsWithSyncedModels(original: string[], edits: IIdent
|
|||
let inverseEdits = model.applyEdits(edits, true);
|
||||
|
||||
// Assert edits produced expected result
|
||||
assert.deepEqual(model.getValue(EndOfLinePreference.LF), expectedStr);
|
||||
assert.deepStrictEqual(model.getValue(EndOfLinePreference.LF), expectedStr);
|
||||
|
||||
assertMirrorModels();
|
||||
|
||||
|
@ -28,7 +28,7 @@ export function testApplyEditsWithSyncedModels(original: string[], edits: IIdent
|
|||
let inverseInverseEdits = model.applyEdits(inverseEdits, true);
|
||||
|
||||
// Assert the inverse edits brought back model to original state
|
||||
assert.deepEqual(model.getValue(EndOfLinePreference.LF), originalStr);
|
||||
assert.deepStrictEqual(model.getValue(EndOfLinePreference.LF), originalStr);
|
||||
|
||||
if (!inputEditsAreInvalid) {
|
||||
const simplifyEdit = (edit: IIdentifiedSingleEditOperation) => {
|
||||
|
@ -41,7 +41,7 @@ export function testApplyEditsWithSyncedModels(original: string[], edits: IIdent
|
|||
};
|
||||
};
|
||||
// Assert the inverse of the inverse edits are the original edits
|
||||
assert.deepEqual(inverseInverseEdits.map(simplifyEdit), edits.map(simplifyEdit));
|
||||
assert.deepStrictEqual(inverseInverseEdits.map(simplifyEdit), edits.map(simplifyEdit));
|
||||
}
|
||||
|
||||
assertMirrorModels();
|
||||
|
@ -59,16 +59,16 @@ function assertOneDirectionLineMapping(model: TextModel, direction: AssertDocume
|
|||
let line = 1, column = 1, previousIsCarriageReturn = false;
|
||||
for (let offset = 0; offset <= allText.length; offset++) {
|
||||
// The position coordinate system cannot express the position between \r and \n
|
||||
let position = new Position(line, column + (previousIsCarriageReturn ? -1 : 0));
|
||||
let position: Position = new Position(line, column + (previousIsCarriageReturn ? -1 : 0));
|
||||
|
||||
if (direction === AssertDocumentLineMappingDirection.OffsetToPosition) {
|
||||
let actualPosition = model.getPositionAt(offset);
|
||||
assert.equal(actualPosition.toString(), position.toString(), msg + ' - getPositionAt mismatch for offset ' + offset);
|
||||
assert.strictEqual(actualPosition.toString(), position.toString(), msg + ' - getPositionAt mismatch for offset ' + offset);
|
||||
} else {
|
||||
// The position coordinate system cannot express the position between \r and \n
|
||||
let expectedOffset = offset + (previousIsCarriageReturn ? -1 : 0);
|
||||
let expectedOffset: number = offset + (previousIsCarriageReturn ? -1 : 0);
|
||||
let actualOffset = model.getOffsetAt(position);
|
||||
assert.equal(actualOffset, expectedOffset, msg + ' - getOffsetAt mismatch for position ' + position.toString());
|
||||
assert.strictEqual(actualOffset, expectedOffset, msg + ' - getOffsetAt mismatch for position ' + position.toString());
|
||||
}
|
||||
|
||||
if (allText.charAt(offset) === '\n') {
|
||||
|
@ -112,8 +112,8 @@ export function assertSyncedModels(text: string, callback: (model: TextModel, as
|
|||
|
||||
let assertMirrorModels = () => {
|
||||
assertLineMapping(model, 'model');
|
||||
assert.equal(mirrorModel2.getText(), model.getValue(), 'mirror model 2 text OK');
|
||||
assert.equal(mirrorModel2.version, model.getVersionId(), 'mirror model 2 version OK');
|
||||
assert.strictEqual(mirrorModel2.getText(), model.getValue(), 'mirror model 2 text OK');
|
||||
assert.strictEqual(mirrorModel2.version, model.getVersionId(), 'mirror model 2 version OK');
|
||||
};
|
||||
|
||||
callback(model, assertMirrorModels);
|
||||
|
|
|
@ -148,6 +148,7 @@ export class MenuId {
|
|||
static readonly TimelineTitleContext = new MenuId('TimelineTitleContext');
|
||||
static readonly AccountsContext = new MenuId('AccountsContext');
|
||||
static readonly PanelTitle = new MenuId('PanelTitle');
|
||||
static readonly TerminalContext = new MenuId('TerminalContext');
|
||||
|
||||
readonly id: number;
|
||||
readonly _debugName: string;
|
||||
|
@ -174,7 +175,7 @@ export interface IMenuService {
|
|||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
createMenu(id: MenuId, scopedKeybindingService: IContextKeyService): IMenu;
|
||||
createMenu(id: MenuId, contextKeyService: IContextKeyService): IMenu;
|
||||
}
|
||||
|
||||
export type ICommandsMap = Map<string, ICommandAction>;
|
||||
|
|
|
@ -17,7 +17,7 @@ import { IWorkspaceBackupInfo } from 'vs/platform/backup/electron-main/backup';
|
|||
import { IBackupWorkspacesFormat, ISerializedWorkspace } from 'vs/platform/backup/node/backup';
|
||||
import { HotExitConfiguration } from 'vs/platform/files/common/files';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { ConsoleLogMainService } from 'vs/platform/log/common/log';
|
||||
import { ConsoleMainLogger, LogService } from 'vs/platform/log/common/log';
|
||||
import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { createHash } from 'crypto';
|
||||
import { flakySuite, getRandomTestPath } from 'vs/base/test/node/testUtils';
|
||||
|
@ -111,7 +111,7 @@ flakySuite('BackupMainService', () => {
|
|||
configService = new TestConfigurationService();
|
||||
service = new class TestBackupMainService extends BackupMainService {
|
||||
constructor() {
|
||||
super(environmentService, configService, new ConsoleLogMainService());
|
||||
super(environmentService, configService, new LogService(new ConsoleMainLogger()));
|
||||
|
||||
this.backupHome = backupHome;
|
||||
this.workspacesJsonPath = backupWorkspacesPath;
|
||||
|
|
|
@ -136,6 +136,8 @@ export interface IExtensionContributions {
|
|||
|
||||
export type ExtensionKind = 'ui' | 'workspace' | 'web';
|
||||
|
||||
export type ExtensionWorkspaceTrustRequirement = false | 'onStart' | 'onDemand';
|
||||
|
||||
export function isIExtensionIdentifier(thing: any): thing is IExtensionIdentifier {
|
||||
return thing
|
||||
&& typeof thing === 'object'
|
||||
|
@ -190,6 +192,7 @@ export interface IExtensionManifest {
|
|||
readonly enableProposedApi?: boolean;
|
||||
readonly api?: string;
|
||||
readonly scripts?: { [key: string]: string; };
|
||||
readonly requiresWorkspaceTrust?: ExtensionWorkspaceTrustRequirement;
|
||||
}
|
||||
|
||||
export const enum ExtensionType {
|
||||
|
|
|
@ -8,22 +8,22 @@ import { INormalizedVersion, IParsedVersion, IReducedExtensionDescription, isVal
|
|||
suite('Extension Version Validator', () => {
|
||||
|
||||
test('isValidVersionStr', () => {
|
||||
assert.equal(isValidVersionStr('0.10.0-dev'), true);
|
||||
assert.equal(isValidVersionStr('0.10.0'), true);
|
||||
assert.equal(isValidVersionStr('0.10.1'), true);
|
||||
assert.equal(isValidVersionStr('0.10.100'), true);
|
||||
assert.equal(isValidVersionStr('0.11.0'), true);
|
||||
assert.strictEqual(isValidVersionStr('0.10.0-dev'), true);
|
||||
assert.strictEqual(isValidVersionStr('0.10.0'), true);
|
||||
assert.strictEqual(isValidVersionStr('0.10.1'), true);
|
||||
assert.strictEqual(isValidVersionStr('0.10.100'), true);
|
||||
assert.strictEqual(isValidVersionStr('0.11.0'), true);
|
||||
|
||||
assert.equal(isValidVersionStr('x.x.x'), true);
|
||||
assert.equal(isValidVersionStr('0.x.x'), true);
|
||||
assert.equal(isValidVersionStr('0.10.0'), true);
|
||||
assert.equal(isValidVersionStr('0.10.x'), true);
|
||||
assert.equal(isValidVersionStr('^0.10.0'), true);
|
||||
assert.equal(isValidVersionStr('*'), true);
|
||||
assert.strictEqual(isValidVersionStr('x.x.x'), true);
|
||||
assert.strictEqual(isValidVersionStr('0.x.x'), true);
|
||||
assert.strictEqual(isValidVersionStr('0.10.0'), true);
|
||||
assert.strictEqual(isValidVersionStr('0.10.x'), true);
|
||||
assert.strictEqual(isValidVersionStr('^0.10.0'), true);
|
||||
assert.strictEqual(isValidVersionStr('*'), true);
|
||||
|
||||
assert.equal(isValidVersionStr('0.x.x.x'), false);
|
||||
assert.equal(isValidVersionStr('0.10'), false);
|
||||
assert.equal(isValidVersionStr('0.10.'), false);
|
||||
assert.strictEqual(isValidVersionStr('0.x.x.x'), false);
|
||||
assert.strictEqual(isValidVersionStr('0.10'), false);
|
||||
assert.strictEqual(isValidVersionStr('0.10.'), false);
|
||||
});
|
||||
|
||||
test('parseVersion', () => {
|
||||
|
@ -31,7 +31,7 @@ suite('Extension Version Validator', () => {
|
|||
const actual = parseVersion(version);
|
||||
const expected: IParsedVersion = { hasCaret, hasGreaterEquals, majorBase, majorMustEqual, minorBase, minorMustEqual, patchBase, patchMustEqual, preRelease };
|
||||
|
||||
assert.deepEqual(actual, expected, 'parseVersion for ' + version);
|
||||
assert.deepStrictEqual(actual, expected, 'parseVersion for ' + version);
|
||||
}
|
||||
|
||||
assertParseVersion('0.10.0-dev', false, false, 0, true, 10, true, 0, true, '-dev');
|
||||
|
@ -56,7 +56,7 @@ suite('Extension Version Validator', () => {
|
|||
function assertNormalizeVersion(version: string, majorBase: number, majorMustEqual: boolean, minorBase: number, minorMustEqual: boolean, patchBase: number, patchMustEqual: boolean, isMinimum: boolean): void {
|
||||
const actual = normalizeVersion(parseVersion(version));
|
||||
const expected: INormalizedVersion = { majorBase, majorMustEqual, minorBase, minorMustEqual, patchBase, patchMustEqual, isMinimum };
|
||||
assert.deepEqual(actual, expected, 'parseVersion for ' + version);
|
||||
assert.deepStrictEqual(actual, expected, 'parseVersion for ' + version);
|
||||
}
|
||||
|
||||
assertNormalizeVersion('0.10.0-dev', 0, true, 10, true, 0, true, false);
|
||||
|
@ -80,7 +80,7 @@ suite('Extension Version Validator', () => {
|
|||
test('isValidVersion', () => {
|
||||
function testIsValidVersion(version: string, desiredVersion: string, expectedResult: boolean): void {
|
||||
let actual = isValidVersion(version, desiredVersion);
|
||||
assert.equal(actual, expectedResult, 'extension - vscode: ' + version + ', desiredVersion: ' + desiredVersion + ' should be ' + expectedResult);
|
||||
assert.strictEqual(actual, expectedResult, 'extension - vscode: ' + version + ', desiredVersion: ' + desiredVersion + ' should be ' + expectedResult);
|
||||
}
|
||||
|
||||
testIsValidVersion('0.10.0-dev', 'x.x.x', true);
|
||||
|
@ -213,7 +213,7 @@ suite('Extension Version Validator', () => {
|
|||
let reasons: string[] = [];
|
||||
let actual = isValidExtensionVersion(version, desc, reasons);
|
||||
|
||||
assert.equal(actual, expectedResult, 'version: ' + version + ', desiredVersion: ' + desiredVersion + ', desc: ' + JSON.stringify(desc) + ', reasons: ' + JSON.stringify(reasons));
|
||||
assert.strictEqual(actual, expectedResult, 'version: ' + version + ', desiredVersion: ' + desiredVersion + ', desc: ' + JSON.stringify(desc) + ', reasons: ' + JSON.stringify(reasons));
|
||||
}
|
||||
|
||||
function testIsInvalidExtensionVersion(version: string, desiredVersion: string, isBuiltin: boolean, hasMain: boolean): void {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ILogService, DEFAULT_LOG_LEVEL, LogLevel, LogServiceAdapter } from 'vs/platform/log/common/log';
|
||||
import { DEFAULT_LOG_LEVEL, LogLevel, AdapterLogger, ILogger } from 'vs/platform/log/common/log';
|
||||
|
||||
interface IAutomatedWindow {
|
||||
codeAutomationLog(type: string, args: any[]): void;
|
||||
|
@ -14,14 +14,12 @@ interface IAutomatedWindow {
|
|||
* an automation such as playwright. We expect a global codeAutomationLog
|
||||
* to be defined that we can use to log to.
|
||||
*/
|
||||
export class ConsoleLogInAutomationService extends LogServiceAdapter implements ILogService {
|
||||
export class ConsoleLogInAutomationLogger extends AdapterLogger implements ILogger {
|
||||
|
||||
declare codeAutomationLog: any;
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) {
|
||||
super({ consoleLog: (type, args) => this.consoleLog(type, args) }, logLevel);
|
||||
super({ log: (type, args) => this.consoleLog(type, args) }, logLevel);
|
||||
}
|
||||
|
||||
private consoleLog(type: string, args: any[]): void {
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ILogService, LogLevel, AbstractLogService, DEFAULT_LOG_LEVEL } from 'vs/platform/log/common/log';
|
||||
import { ILogService, LogLevel, AbstractLogger, DEFAULT_LOG_LEVEL, ILogger } from 'vs/platform/log/common/log';
|
||||
|
||||
interface ILog {
|
||||
level: LogLevel;
|
||||
args: any[];
|
||||
}
|
||||
|
||||
function getLogFunction(logger: ILogService, level: LogLevel): Function {
|
||||
function getLogFunction(logger: ILogger, level: LogLevel): Function {
|
||||
switch (level) {
|
||||
case LogLevel.Trace: return logger.trace;
|
||||
case LogLevel.Debug: return logger.debug;
|
||||
|
@ -22,11 +22,11 @@ function getLogFunction(logger: ILogService, level: LogLevel): Function {
|
|||
}
|
||||
}
|
||||
|
||||
export class BufferLogService extends AbstractLogService implements ILogService {
|
||||
export class BufferLogService extends AbstractLogger implements ILogService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
private buffer: ILog[] = [];
|
||||
private _logger: ILogService | undefined = undefined;
|
||||
private _logger: ILogger | undefined = undefined;
|
||||
|
||||
constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) {
|
||||
super();
|
||||
|
@ -38,7 +38,7 @@ export class BufferLogService extends AbstractLogService implements ILogService
|
|||
}));
|
||||
}
|
||||
|
||||
set logger(logger: ILogService) {
|
||||
set logger(logger: ILogger) {
|
||||
this._logger = logger;
|
||||
|
||||
for (const { level, args } of this.buffer) {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ILogService, LogLevel, AbstractLogService, ILoggerService, ILogger } from 'vs/platform/log/common/log';
|
||||
import { ILogService, LogLevel, AbstractLogger, ILoggerService, ILogger } from 'vs/platform/log/common/log';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ByteSize, FileOperationError, FileOperationResult, IFileService, whenProviderRegistered } from 'vs/platform/files/common/files';
|
||||
import { Queue } from 'vs/base/common/async';
|
||||
|
@ -15,9 +15,7 @@ import { BufferLogService } from 'vs/platform/log/common/bufferLog';
|
|||
|
||||
const MAX_FILE_SIZE = 5 * ByteSize.MB;
|
||||
|
||||
export class FileLogService extends AbstractLogService implements ILogService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
export class FileLogger extends AbstractLogger implements ILogger {
|
||||
|
||||
private readonly initializePromise: Promise<void>;
|
||||
private readonly queue: Queue<void>;
|
||||
|
@ -181,7 +179,7 @@ export class FileLoggerService extends Disposable implements ILoggerService {
|
|||
if (!logger) {
|
||||
logger = new BufferLogService(this.logService.getLevel());
|
||||
this.loggers.set(resource.toString(), logger);
|
||||
whenProviderRegistered(resource, this.fileService).then(() => (<BufferLogService>logger).logger = this.instantiationService.createInstance(FileLogService, basename(resource), resource, this.logService.getLevel()));
|
||||
whenProviderRegistered(resource, this.fileService).then(() => (<BufferLogService>logger).logger = this.instantiationService.createInstance(FileLogger, basename(resource), resource, this.logService.getLevel()));
|
||||
}
|
||||
return logger;
|
||||
}
|
|
@ -59,7 +59,7 @@ export interface ILoggerService {
|
|||
getLogger(file: URI): ILogger;
|
||||
}
|
||||
|
||||
export abstract class AbstractLogService extends Disposable {
|
||||
export abstract class AbstractLogger extends Disposable {
|
||||
|
||||
private level: LogLevel = DEFAULT_LOG_LEVEL;
|
||||
private readonly _onDidChangeLogLevel: Emitter<LogLevel> = this._register(new Emitter<LogLevel>());
|
||||
|
@ -78,9 +78,8 @@ export abstract class AbstractLogService extends Disposable {
|
|||
|
||||
}
|
||||
|
||||
export class ConsoleLogMainService extends AbstractLogService implements ILogService {
|
||||
export class ConsoleMainLogger extends AbstractLogger implements ILogger {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
private useColors: boolean;
|
||||
|
||||
constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) {
|
||||
|
@ -159,9 +158,7 @@ export class ConsoleLogMainService extends AbstractLogService implements ILogSer
|
|||
|
||||
}
|
||||
|
||||
export class ConsoleLogService extends AbstractLogService implements ILogService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
export class ConsoleLogger extends AbstractLogger implements ILogger {
|
||||
|
||||
constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) {
|
||||
super();
|
||||
|
@ -213,48 +210,46 @@ export class ConsoleLogService extends AbstractLogService implements ILogService
|
|||
}
|
||||
}
|
||||
|
||||
export class LogServiceAdapter extends AbstractLogService implements ILogService {
|
||||
export class AdapterLogger extends AbstractLogger implements ILogger {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(private readonly adapter: { consoleLog: (type: string, args: any[]) => void }, logLevel: LogLevel = DEFAULT_LOG_LEVEL) {
|
||||
constructor(private readonly adapter: { log: (type: string, args: any[]) => void }, logLevel: LogLevel = DEFAULT_LOG_LEVEL) {
|
||||
super();
|
||||
this.setLevel(logLevel);
|
||||
}
|
||||
|
||||
trace(message: string, ...args: any[]): void {
|
||||
if (this.getLevel() <= LogLevel.Trace) {
|
||||
this.adapter.consoleLog('trace', [this.extractMessage(message), ...args]);
|
||||
this.adapter.log('trace', [this.extractMessage(message), ...args]);
|
||||
}
|
||||
}
|
||||
|
||||
debug(message: string, ...args: any[]): void {
|
||||
if (this.getLevel() <= LogLevel.Debug) {
|
||||
this.adapter.consoleLog('debug', [this.extractMessage(message), ...args]);
|
||||
this.adapter.log('debug', [this.extractMessage(message), ...args]);
|
||||
}
|
||||
}
|
||||
|
||||
info(message: string, ...args: any[]): void {
|
||||
if (this.getLevel() <= LogLevel.Info) {
|
||||
this.adapter.consoleLog('info', [this.extractMessage(message), ...args]);
|
||||
this.adapter.log('info', [this.extractMessage(message), ...args]);
|
||||
}
|
||||
}
|
||||
|
||||
warn(message: string | Error, ...args: any[]): void {
|
||||
if (this.getLevel() <= LogLevel.Warning) {
|
||||
this.adapter.consoleLog('warn', [this.extractMessage(message), ...args]);
|
||||
this.adapter.log('warn', [this.extractMessage(message), ...args]);
|
||||
}
|
||||
}
|
||||
|
||||
error(message: string | Error, ...args: any[]): void {
|
||||
if (this.getLevel() <= LogLevel.Error) {
|
||||
this.adapter.consoleLog('error', [this.extractMessage(message), ...args]);
|
||||
this.adapter.log('error', [this.extractMessage(message), ...args]);
|
||||
}
|
||||
}
|
||||
|
||||
critical(message: string | Error, ...args: any[]): void {
|
||||
if (this.getLevel() <= LogLevel.Critical) {
|
||||
this.adapter.consoleLog('critical', [this.extractMessage(message), ...args]);
|
||||
this.adapter.log('critical', [this.extractMessage(message), ...args]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,19 +270,17 @@ export class LogServiceAdapter extends AbstractLogService implements ILogService
|
|||
}
|
||||
}
|
||||
|
||||
export class ConsoleLogInMainService extends LogServiceAdapter implements ILogService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
export class ConsoleLogInMainService extends AdapterLogger implements ILogger {
|
||||
|
||||
constructor(client: LoggerChannelClient, logLevel: LogLevel = DEFAULT_LOG_LEVEL) {
|
||||
super({ consoleLog: (type, args) => client.consoleLog(type, args) }, logLevel);
|
||||
super({ log: (type, args) => client.consoleLog(type, args) }, logLevel);
|
||||
}
|
||||
}
|
||||
|
||||
export class MultiplexLogService extends AbstractLogService implements ILogService {
|
||||
export class MultiplexLogService extends AbstractLogger implements ILogService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(private readonly logServices: ReadonlyArray<ILogService>) {
|
||||
constructor(private readonly logServices: ReadonlyArray<ILogger>) {
|
||||
super();
|
||||
if (logServices.length) {
|
||||
this.setLevel(logServices[0].getLevel());
|
||||
|
@ -350,52 +343,52 @@ export class MultiplexLogService extends AbstractLogService implements ILogServi
|
|||
}
|
||||
}
|
||||
|
||||
export class DelegatedLogService extends Disposable implements ILogService {
|
||||
export class LogService extends Disposable implements ILogService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(private logService: ILogService) {
|
||||
constructor(private logger: ILogger) {
|
||||
super();
|
||||
this._register(logService);
|
||||
this._register(logger);
|
||||
}
|
||||
|
||||
get onDidChangeLogLevel(): Event<LogLevel> {
|
||||
return this.logService.onDidChangeLogLevel;
|
||||
return this.logger.onDidChangeLogLevel;
|
||||
}
|
||||
|
||||
setLevel(level: LogLevel): void {
|
||||
this.logService.setLevel(level);
|
||||
this.logger.setLevel(level);
|
||||
}
|
||||
|
||||
getLevel(): LogLevel {
|
||||
return this.logService.getLevel();
|
||||
return this.logger.getLevel();
|
||||
}
|
||||
|
||||
trace(message: string, ...args: any[]): void {
|
||||
this.logService.trace(message, ...args);
|
||||
this.logger.trace(message, ...args);
|
||||
}
|
||||
|
||||
debug(message: string, ...args: any[]): void {
|
||||
this.logService.debug(message, ...args);
|
||||
this.logger.debug(message, ...args);
|
||||
}
|
||||
|
||||
info(message: string, ...args: any[]): void {
|
||||
this.logService.info(message, ...args);
|
||||
this.logger.info(message, ...args);
|
||||
}
|
||||
|
||||
warn(message: string, ...args: any[]): void {
|
||||
this.logService.warn(message, ...args);
|
||||
this.logger.warn(message, ...args);
|
||||
}
|
||||
|
||||
error(message: string | Error, ...args: any[]): void {
|
||||
this.logService.error(message, ...args);
|
||||
this.logger.error(message, ...args);
|
||||
}
|
||||
|
||||
critical(message: string | Error, ...args: any[]): void {
|
||||
this.logService.critical(message, ...args);
|
||||
this.logger.critical(message, ...args);
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
this.logService.flush();
|
||||
this.logger.flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { LogLevel, ILogService, DelegatedLogService } from 'vs/platform/log/common/log';
|
||||
import { LogLevel, ILogService, LogService } from 'vs/platform/log/common/log';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
export class LoggerChannel implements IServerChannel {
|
||||
|
@ -72,7 +72,7 @@ export class LoggerChannelClient {
|
|||
}
|
||||
}
|
||||
|
||||
export class FollowerLogService extends DelegatedLogService implements ILogService {
|
||||
export class FollowerLogService extends LogService implements ILogService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(private parent: LoggerChannelClient, logService: ILogService) {
|
||||
|
|
|
@ -8,8 +8,8 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
|||
import { URI } from 'vs/base/common/uri';
|
||||
import { basename, extname, dirname } from 'vs/base/common/resources';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { FileLogService } from 'vs/platform/log/common/fileLogService';
|
||||
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
|
||||
import { FileLogger } from 'vs/platform/log/common/fileLog';
|
||||
import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
|
||||
export class LoggerService extends Disposable implements ILoggerService {
|
||||
|
@ -32,9 +32,9 @@ export class LoggerService extends Disposable implements ILoggerService {
|
|||
if (resource.scheme === Schemas.file) {
|
||||
const baseName = basename(resource);
|
||||
const ext = extname(resource);
|
||||
logger = new SpdLogService(baseName.substring(0, baseName.length - ext.length), dirname(resource).fsPath, this.logService.getLevel());
|
||||
logger = new SpdLogLogger(baseName.substring(0, baseName.length - ext.length), dirname(resource).fsPath, this.logService.getLevel());
|
||||
} else {
|
||||
logger = new FileLogService(basename(resource), resource, this.logService.getLevel(), this.fileService);
|
||||
logger = new FileLogger(basename(resource), resource, this.logService.getLevel(), this.fileService);
|
||||
}
|
||||
this.loggers.set(resource.toString(), logger);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { ILogService, LogLevel, AbstractLogService } from 'vs/platform/log/common/log';
|
||||
import { LogLevel, AbstractLogger, ILogger } from 'vs/platform/log/common/log';
|
||||
import * as spdlog from 'spdlog';
|
||||
import { ByteSize } from 'vs/platform/files/common/files';
|
||||
|
||||
|
@ -43,9 +43,7 @@ function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string): v
|
|||
}
|
||||
}
|
||||
|
||||
export class SpdLogService extends AbstractLogService implements ILogService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
export class SpdLogLogger extends AbstractLogger implements ILogger {
|
||||
|
||||
private buffer: ILog[] = [];
|
||||
private _loggerCreationPromise: Promise<void> | undefined = undefined;
|
|
@ -3,13 +3,12 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { LogLevel, ILoggerService, AbstractLogService, DEFAULT_LOG_LEVEL, ILogger } from 'vs/platform/log/common/log';
|
||||
import { LogLevel, ILoggerService, AbstractLogger, DEFAULT_LOG_LEVEL, ILogger } from 'vs/platform/log/common/log';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
class TestTelemetryLogger extends AbstractLogService implements ILogger {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
class TestTelemetryLogger extends AbstractLogger implements ILogger {
|
||||
|
||||
public logs: string[] = [];
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IUserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { AbstractLogService, ILoggerService, ILogger } from 'vs/platform/log/common/log';
|
||||
import { AbstractLogger, ILoggerService, ILogger } from 'vs/platform/log/common/log';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
export class UserDataSyncLogService extends AbstractLogService implements IUserDataSyncLogService {
|
||||
export class UserDataSyncLogService extends AbstractLogger implements IUserDataSyncLogService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
private readonly logger: ILogger;
|
||||
|
|
|
@ -81,14 +81,14 @@ export function isFileToOpen(uriToOpen: IWindowOpenable): uriToOpen is IFileToOp
|
|||
return !!(uriToOpen as IFileToOpen).fileUri;
|
||||
}
|
||||
|
||||
export type MenuBarVisibility = 'default' | 'visible' | 'toggle' | 'hidden' | 'compact';
|
||||
export type MenuBarVisibility = 'classic' | 'visible' | 'toggle' | 'hidden' | 'compact';
|
||||
|
||||
export function getMenuBarVisibility(configurationService: IConfigurationService): MenuBarVisibility {
|
||||
const titleBarStyle = getTitleBarStyle(configurationService);
|
||||
const menuBarVisibility = configurationService.getValue<MenuBarVisibility>('window.menuBarVisibility');
|
||||
const menuBarVisibility = configurationService.getValue<MenuBarVisibility | 'default'>('window.menuBarVisibility');
|
||||
|
||||
if (titleBarStyle === 'native' && menuBarVisibility === 'compact') {
|
||||
return 'default';
|
||||
if (menuBarVisibility === 'default' || (titleBarStyle === 'native' && menuBarVisibility === 'compact')) {
|
||||
return 'classic';
|
||||
} else {
|
||||
return menuBarVisibility;
|
||||
}
|
||||
|
|
375
src/vs/platform/workspace/common/workspaceTrust.ts
Normal file
375
src/vs/platform/workspace/common/workspaceTrust.ts
Normal file
|
@ -0,0 +1,375 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { IWorkspace, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
|
||||
export const WORKSPACE_TRUST_ENABLED = 'workspace.trustEnabled';
|
||||
export const WORKSPACE_TRUST_URI = URI.parse('workspaceTrust:/Trusted Workspaces');
|
||||
|
||||
export enum WorkspaceTrustScope {
|
||||
Local = 0,
|
||||
Remote = 1
|
||||
}
|
||||
|
||||
export enum WorkspaceTrustState {
|
||||
Untrusted = 0,
|
||||
Trusted = 1,
|
||||
Unknown = 2
|
||||
}
|
||||
|
||||
export function workspaceTrustStateToString(trustState: WorkspaceTrustState) {
|
||||
switch (trustState) {
|
||||
case WorkspaceTrustState.Trusted:
|
||||
return localize('trusted', "Trusted");
|
||||
case WorkspaceTrustState.Untrusted:
|
||||
return localize('untrusted', "Untrusted");
|
||||
case WorkspaceTrustState.Unknown:
|
||||
default:
|
||||
return localize('unknown', "Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
export const WorkspaceTrustContext = {
|
||||
PendingRequest: new RawContextKey<boolean>('workspaceTrustPendingRequest', false),
|
||||
TrustState: new RawContextKey<WorkspaceTrustState>('workspaceTrustState', WorkspaceTrustState.Unknown)
|
||||
};
|
||||
|
||||
export interface IWorkspaceTrustModel {
|
||||
|
||||
readonly onDidChangeTrustState: Event<void>;
|
||||
|
||||
setFolderTrustState(folder: URI, trustState: WorkspaceTrustState): void;
|
||||
getFolderTrustState(folder: URI): WorkspaceTrustState;
|
||||
}
|
||||
|
||||
export interface IWorkspaceTrustRequest {
|
||||
immediate: boolean;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface IWorkspaceTrustRequestModel {
|
||||
readonly trustRequest: IWorkspaceTrustRequest | undefined;
|
||||
|
||||
readonly onDidInitiateRequest: Event<void>;
|
||||
readonly onDidCompleteRequest: Event<WorkspaceTrustState | undefined>;
|
||||
|
||||
initiateRequest(request?: IWorkspaceTrustRequest): void;
|
||||
completeRequest(trustState?: WorkspaceTrustState): void;
|
||||
}
|
||||
|
||||
export interface WorkspaceTrustStateChangeEvent {
|
||||
previousTrustState: WorkspaceTrustState;
|
||||
currentTrustState: WorkspaceTrustState;
|
||||
}
|
||||
|
||||
export type WorkspaceTrustChangeEvent = Event<WorkspaceTrustStateChangeEvent>;
|
||||
|
||||
export const IWorkspaceTrustService = createDecorator<IWorkspaceTrustService>('workspaceTrustService');
|
||||
|
||||
export interface IWorkspaceTrustService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
readonly requestModel: IWorkspaceTrustRequestModel;
|
||||
|
||||
onDidChangeTrustState: WorkspaceTrustChangeEvent;
|
||||
getWorkspaceTrustState(): WorkspaceTrustState;
|
||||
isWorkspaceTrustEnabled(): boolean;
|
||||
requireWorkspaceTrust(request: IWorkspaceTrustRequest): Promise<WorkspaceTrustState>;
|
||||
resetWorkspaceTrust(): Promise<WorkspaceTrustState>;
|
||||
}
|
||||
|
||||
interface IWorkspaceTrustStateInfo {
|
||||
localFolders: { uri: string, trustState: WorkspaceTrustState }[]
|
||||
|
||||
// Removing complexity of remote items
|
||||
//trustedRemoteItems: { uri: string }[]
|
||||
}
|
||||
|
||||
export const WORKSPACE_TRUST_STORAGE_KEY = 'content.trust.model.key';
|
||||
|
||||
export class WorkspaceTrustModel extends Disposable implements IWorkspaceTrustModel {
|
||||
|
||||
private storageKey = WORKSPACE_TRUST_STORAGE_KEY;
|
||||
private trustStateInfo: IWorkspaceTrustStateInfo;
|
||||
|
||||
private readonly _onDidChangeTrustState = this._register(new Emitter<void>());
|
||||
readonly onDidChangeTrustState = this._onDidChangeTrustState.event;
|
||||
|
||||
constructor(
|
||||
private readonly storageService: IStorageService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.trustStateInfo = this.loadTrustInfo();
|
||||
this._register(this.storageService.onDidChangeValue(changeEvent => {
|
||||
if (changeEvent.key === this.storageKey) {
|
||||
this.onDidStorageChange();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private loadTrustInfo(): IWorkspaceTrustStateInfo {
|
||||
const infoAsString = this.storageService.get(this.storageKey, StorageScope.GLOBAL);
|
||||
|
||||
let result: IWorkspaceTrustStateInfo | undefined;
|
||||
try {
|
||||
if (infoAsString) {
|
||||
result = JSON.parse(infoAsString);
|
||||
}
|
||||
} catch { }
|
||||
|
||||
if (!result) {
|
||||
result = {
|
||||
localFolders: [],
|
||||
//trustedRemoteItems: []
|
||||
};
|
||||
}
|
||||
|
||||
if (!result.localFolders) {
|
||||
result.localFolders = [];
|
||||
}
|
||||
|
||||
// if (!result.trustedRemoteItems) {
|
||||
// result.trustedRemoteItems = [];
|
||||
// }
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private saveTrustInfo(): void {
|
||||
this.storageService.store(this.storageKey, JSON.stringify(this.trustStateInfo), StorageScope.GLOBAL, StorageTarget.MACHINE);
|
||||
}
|
||||
|
||||
private onDidStorageChange(): void {
|
||||
this.trustStateInfo = this.loadTrustInfo();
|
||||
|
||||
this._onDidChangeTrustState.fire();
|
||||
}
|
||||
|
||||
setFolderTrustState(folder: URI, trustState: WorkspaceTrustState): void {
|
||||
let changed = false;
|
||||
|
||||
if (trustState === WorkspaceTrustState.Unknown) {
|
||||
const before = this.trustStateInfo.localFolders.length;
|
||||
this.trustStateInfo.localFolders = this.trustStateInfo.localFolders.filter(info => info.uri !== folder.toString());
|
||||
|
||||
if (this.trustStateInfo.localFolders.length !== before) {
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
let found = false;
|
||||
for (const trustInfo of this.trustStateInfo.localFolders) {
|
||||
if (trustInfo.uri === folder.toString()) {
|
||||
found = true;
|
||||
if (trustInfo.trustState !== trustState) {
|
||||
trustInfo.trustState = trustState;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
this.trustStateInfo.localFolders.push({ uri: folder.toString(), trustState });
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
this.saveTrustInfo();
|
||||
}
|
||||
}
|
||||
|
||||
getFolderTrustState(folder: URI): WorkspaceTrustState {
|
||||
for (const trustInfo of this.trustStateInfo.localFolders) {
|
||||
if (trustInfo.uri === folder.toString()) {
|
||||
return trustInfo.trustState;
|
||||
}
|
||||
}
|
||||
|
||||
return WorkspaceTrustState.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
export class WorkspaceTrustRequestModel extends Disposable implements IWorkspaceTrustRequestModel {
|
||||
trustRequest: IWorkspaceTrustRequest | undefined;
|
||||
|
||||
_onDidInitiateRequest = this._register(new Emitter<void>());
|
||||
onDidInitiateRequest: Event<void> = this._onDidInitiateRequest.event;
|
||||
|
||||
_onDidCompleteRequest = this._register(new Emitter<WorkspaceTrustState | undefined>());
|
||||
onDidCompleteRequest = this._onDidCompleteRequest.event;
|
||||
|
||||
initiateRequest(request: IWorkspaceTrustRequest): void {
|
||||
if (this.trustRequest && (!request.immediate || this.trustRequest.immediate)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.trustRequest = request;
|
||||
this._onDidInitiateRequest.fire();
|
||||
}
|
||||
|
||||
completeRequest(trustState?: WorkspaceTrustState): void {
|
||||
this.trustRequest = undefined;
|
||||
this._onDidCompleteRequest.fire(trustState);
|
||||
}
|
||||
}
|
||||
|
||||
export class WorkspaceTrustService extends Disposable implements IWorkspaceTrustService {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
private readonly dataModel: IWorkspaceTrustModel;
|
||||
readonly requestModel: IWorkspaceTrustRequestModel;
|
||||
|
||||
private readonly _onDidChangeTrustState = this._register(new Emitter<WorkspaceTrustStateChangeEvent>());
|
||||
readonly onDidChangeTrustState = this._onDidChangeTrustState.event;
|
||||
|
||||
private _currentTrustState: WorkspaceTrustState = WorkspaceTrustState.Unknown;
|
||||
private _inFlightResolver?: (trustState: WorkspaceTrustState) => void;
|
||||
private _trustRequestPromise?: Promise<WorkspaceTrustState>;
|
||||
private _workspace: IWorkspace;
|
||||
|
||||
private readonly _ctxWorkspaceTrustState: IContextKey<WorkspaceTrustState>;
|
||||
private readonly _ctxWorkspaceTrustPendingRequest: IContextKey<boolean>;
|
||||
|
||||
constructor(
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService,
|
||||
@IConfigurationService readonly configurationService: IConfigurationService,
|
||||
@IContextKeyService readonly contextKeyService: IContextKeyService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.dataModel = this._register(new WorkspaceTrustModel(this.storageService));
|
||||
this.requestModel = this._register(new WorkspaceTrustRequestModel());
|
||||
|
||||
this._workspace = this.workspaceService.getWorkspace();
|
||||
this._currentTrustState = this.calculateWorkspaceTrustState();
|
||||
|
||||
this._register(this.dataModel.onDidChangeTrustState(() => this.currentTrustState = this.calculateWorkspaceTrustState()));
|
||||
this._register(this.requestModel.onDidCompleteRequest((trustState) => this.onTrustRequestCompleted(trustState)));
|
||||
|
||||
this._ctxWorkspaceTrustState = WorkspaceTrustContext.TrustState.bindTo(contextKeyService);
|
||||
this._ctxWorkspaceTrustPendingRequest = WorkspaceTrustContext.PendingRequest.bindTo(contextKeyService);
|
||||
this._ctxWorkspaceTrustState.set(this.currentTrustState);
|
||||
}
|
||||
|
||||
private get currentTrustState(): WorkspaceTrustState {
|
||||
return this._currentTrustState;
|
||||
}
|
||||
|
||||
private set currentTrustState(trustState: WorkspaceTrustState) {
|
||||
if (this._currentTrustState === trustState) { return; }
|
||||
const previousState = this._currentTrustState;
|
||||
this._currentTrustState = trustState;
|
||||
|
||||
this._onDidChangeTrustState.fire({ previousTrustState: previousState, currentTrustState: this._currentTrustState });
|
||||
}
|
||||
|
||||
private calculateWorkspaceTrustState(): WorkspaceTrustState {
|
||||
if (!this.isWorkspaceTrustEnabled()) {
|
||||
return WorkspaceTrustState.Trusted;
|
||||
}
|
||||
|
||||
if (this.workspaceService.getWorkbenchState() === WorkbenchState.EMPTY) {
|
||||
return WorkspaceTrustState.Trusted;
|
||||
}
|
||||
|
||||
let state = undefined;
|
||||
for (const folder of this._workspace.folders) {
|
||||
const folderTrust = this.dataModel.getFolderTrustState(folder.uri);
|
||||
|
||||
switch (folderTrust) {
|
||||
case WorkspaceTrustState.Untrusted:
|
||||
return WorkspaceTrustState.Untrusted;
|
||||
case WorkspaceTrustState.Unknown:
|
||||
state = folderTrust;
|
||||
break;
|
||||
case WorkspaceTrustState.Trusted:
|
||||
if (state === undefined) {
|
||||
state = folderTrust;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return state ?? WorkspaceTrustState.Unknown;
|
||||
}
|
||||
|
||||
private onTrustRequestCompleted(trustState?: WorkspaceTrustState): void {
|
||||
if (this._inFlightResolver) {
|
||||
this._inFlightResolver(trustState === undefined ? this.currentTrustState : trustState);
|
||||
}
|
||||
|
||||
this._inFlightResolver = undefined;
|
||||
this._trustRequestPromise = undefined;
|
||||
|
||||
if (trustState === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._workspace.folders.forEach(folder => {
|
||||
this.dataModel.setFolderTrustState(folder.uri, trustState);
|
||||
});
|
||||
|
||||
this._ctxWorkspaceTrustPendingRequest.set(false);
|
||||
this._ctxWorkspaceTrustState.set(trustState);
|
||||
}
|
||||
|
||||
getWorkspaceTrustState(): WorkspaceTrustState {
|
||||
return this.currentTrustState;
|
||||
}
|
||||
|
||||
isWorkspaceTrustEnabled(): boolean {
|
||||
return this.configurationService.getValue<boolean>(WORKSPACE_TRUST_ENABLED) ?? false;
|
||||
}
|
||||
|
||||
async requireWorkspaceTrust(request?: IWorkspaceTrustRequest): Promise<WorkspaceTrustState> {
|
||||
if (this.currentTrustState === WorkspaceTrustState.Trusted) {
|
||||
return this.currentTrustState;
|
||||
}
|
||||
if (this.currentTrustState === WorkspaceTrustState.Untrusted && !request?.immediate) {
|
||||
return this.currentTrustState;
|
||||
}
|
||||
|
||||
if (this._trustRequestPromise) {
|
||||
if (request?.immediate &&
|
||||
this.requestModel.trustRequest &&
|
||||
!this.requestModel.trustRequest.immediate) {
|
||||
this.requestModel.initiateRequest(request);
|
||||
}
|
||||
|
||||
return this._trustRequestPromise;
|
||||
}
|
||||
|
||||
this._trustRequestPromise = new Promise(resolve => {
|
||||
this._inFlightResolver = resolve;
|
||||
});
|
||||
|
||||
this.requestModel.initiateRequest(request);
|
||||
this._ctxWorkspaceTrustPendingRequest.set(true);
|
||||
|
||||
return this._trustRequestPromise;
|
||||
}
|
||||
|
||||
async resetWorkspaceTrust(): Promise<WorkspaceTrustState> {
|
||||
if (this.currentTrustState !== WorkspaceTrustState.Unknown) {
|
||||
this._workspace.folders.forEach(folder => {
|
||||
this.dataModel.setFolderTrustState(folder.uri, WorkspaceTrustState.Unknown);
|
||||
});
|
||||
}
|
||||
return Promise.resolve(WorkspaceTrustState.Unknown);
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IWorkspaceTrustService, WorkspaceTrustService);
|
31
src/vs/platform/workspace/test/common/testWorkspaceTrust.ts
Normal file
31
src/vs/platform/workspace/test/common/testWorkspaceTrust.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IWorkspaceTrustRequest, IWorkspaceTrustRequestModel, IWorkspaceTrustService, WorkspaceTrustChangeEvent, WorkspaceTrustRequestModel, WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
|
||||
export class TestWorkspaceTrustService implements IWorkspaceTrustService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
requestModel: IWorkspaceTrustRequestModel = new WorkspaceTrustRequestModel();
|
||||
|
||||
onDidChangeTrustState: WorkspaceTrustChangeEvent = Event.None;
|
||||
|
||||
getWorkspaceTrustState(): WorkspaceTrustState {
|
||||
return WorkspaceTrustState.Trusted;
|
||||
}
|
||||
|
||||
isWorkspaceTrustEnabled(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
requireWorkspaceTrust(request: IWorkspaceTrustRequest): Promise<WorkspaceTrustState> {
|
||||
return Promise.resolve(WorkspaceTrustState.Trusted);
|
||||
}
|
||||
|
||||
resetWorkspaceTrust(): Promise<WorkspaceTrustState> {
|
||||
return Promise.resolve(WorkspaceTrustState.Unknown);
|
||||
}
|
||||
}
|
70
src/vs/vscode.proposed.d.ts
vendored
70
src/vs/vscode.proposed.d.ts
vendored
|
@ -1084,6 +1084,11 @@ declare module 'vscode' {
|
|||
readonly outputs: CellOutput[];
|
||||
readonly outputs2: readonly NotebookCellOutput[];
|
||||
readonly metadata: NotebookCellMetadata;
|
||||
/** @deprecated use WorkspaceEdit.replaceCellOutput */
|
||||
// outputs: CellOutput[];
|
||||
// readonly outputs2: NotebookCellOutput[];
|
||||
/** @deprecated use WorkspaceEdit.replaceCellMetadata */
|
||||
// metadata: NotebookCellMetadata;
|
||||
}
|
||||
|
||||
export interface NotebookDocumentMetadata {
|
||||
|
@ -1497,13 +1502,16 @@ declare module 'vscode' {
|
|||
// todo@API use NotebookCellRange
|
||||
replaceNotebookCells(uri: Uri, start: number, end: number, cells: NotebookCellData[], metadata?: WorkspaceEditEntryMetadata): void;
|
||||
replaceNotebookCellMetadata(uri: Uri, index: number, cellMetadata: NotebookCellMetadata, metadata?: WorkspaceEditEntryMetadata): void;
|
||||
|
||||
replaceNotebookCellOutput(uri: Uri, index: number, outputs: (NotebookCellOutput | CellOutput)[], metadata?: WorkspaceEditEntryMetadata): void;
|
||||
appendNotebookCellOutput(uri: Uri, index: number, outputs: NotebookCellOutput[], metadata?: WorkspaceEditEntryMetadata): void;
|
||||
appendNotebookCellOutput(uri: Uri, index: number, outputs: (NotebookCellOutput | CellOutput)[], metadata?: WorkspaceEditEntryMetadata): void;
|
||||
|
||||
// TODO@api
|
||||
// https://jupyter-protocol.readthedocs.io/en/latest/messaging.html#update-display-data
|
||||
replaceNotebookCellOutputItems(uri: Uri, index: number, outputId: string, items: NotebookCellOutputItem[], metadata?: WorkspaceEditEntryMetadata): void;
|
||||
appendNotebookCellOutputItems(uri: Uri, index: number, outputId: string, items: NotebookCellOutputItem[], metadata?: WorkspaceEditEntryMetadata): void;
|
||||
// replaceNotebookCellOutput(uri: Uri, index: number, outputId:string, outputs: NotebookCellOutputItem[], metadata?: WorkspaceEditEntryMetadata): void;
|
||||
// appendNotebookCellOutput(uri: Uri, index: number, outputId:string, outputs: NotebookCellOutputItem[], metadata?: WorkspaceEditEntryMetadata): void;
|
||||
}
|
||||
|
||||
export interface NotebookEditorEdit {
|
||||
|
@ -1972,6 +1980,10 @@ declare module 'vscode' {
|
|||
|
||||
//#region https://github.com/microsoft/vscode/issues/16221
|
||||
|
||||
// todo@API rename to InlayHint
|
||||
// todo@API add InlayHintKind with type, argument, etc
|
||||
// todo@API add "mini-markdown" for links and styles
|
||||
|
||||
export namespace languages {
|
||||
/**
|
||||
* Register a inline hints provider.
|
||||
|
@ -2605,4 +2617,60 @@ declare module 'vscode' {
|
|||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region https://github.com/microsoft/vscode/issues/106488
|
||||
|
||||
export enum WorkspaceTrustState {
|
||||
/**
|
||||
* The workspace is untrusted, and it will have limited functionality.
|
||||
*/
|
||||
Untrusted = 0,
|
||||
|
||||
/**
|
||||
* The workspace is trusted, and all functionality will be available.
|
||||
*/
|
||||
Trusted = 1,
|
||||
|
||||
/**
|
||||
* The initial state of the workspace.
|
||||
*
|
||||
* If trust will be required, users will be prompted to make a choice.
|
||||
*/
|
||||
Unknown = 2
|
||||
}
|
||||
|
||||
/**
|
||||
* The event data that is fired when the trust state of the workspace changes
|
||||
*/
|
||||
export interface WorkspaceTrustStateChangeEvent {
|
||||
/**
|
||||
* Previous trust state of the workspace
|
||||
*/
|
||||
previousTrustState: WorkspaceTrustState;
|
||||
|
||||
/**
|
||||
* Current trust state of the workspace
|
||||
*/
|
||||
currentTrustState: WorkspaceTrustState;
|
||||
}
|
||||
|
||||
export namespace workspace {
|
||||
/**
|
||||
* The trust state of the current workspace
|
||||
*/
|
||||
export const trustState: WorkspaceTrustState;
|
||||
|
||||
/**
|
||||
* Prompt the user to chose whether to trust the current workspace
|
||||
* @param message Optional message which would be displayed in the prompt
|
||||
*/
|
||||
export function requireWorkspaceTrust(message?: string): Thenable<WorkspaceTrustState>;
|
||||
|
||||
/**
|
||||
* Event that fires when the trust state of the current workspace changes
|
||||
*/
|
||||
export const onDidChangeWorkspaceTrustState: Event<WorkspaceTrustStateChangeEvent>;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
|
|
@ -26,10 +26,9 @@ import { IExtensionManifest } from 'vs/workbench/workbench.web.api';
|
|||
|
||||
// this class contains the commands that the CLI server is reying on
|
||||
|
||||
CommandsRegistry.registerCommand('_remoteCLI.openExternal', function (accessor: ServicesAccessor, uri: UriComponents, options: { allowTunneling?: boolean }) {
|
||||
// TODO: discuss martin, ben where to put this
|
||||
CommandsRegistry.registerCommand('_remoteCLI.openExternal', function (accessor: ServicesAccessor, uri: UriComponents | string) {
|
||||
const openerService = accessor.get(IOpenerService);
|
||||
openerService.open(URI.revive(uri), { openExternal: true, allowTunneling: options?.allowTunneling === true });
|
||||
openerService.open(isString(uri) ? uri : URI.revive(uri), { openExternal: true, allowTunneling: true });
|
||||
});
|
||||
|
||||
interface ManageExtensionsArgs {
|
||||
|
|
|
@ -8,14 +8,14 @@ import { ILogService, LogLevel } from 'vs/platform/log/common/log';
|
|||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtHostContext, ExtHostContext, MainThreadLogShape, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { UriComponents, URI } from 'vs/base/common/uri';
|
||||
import { FileLogService } from 'vs/platform/log/common/fileLogService';
|
||||
import { FileLogger } from 'vs/platform/log/common/fileLog';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadLog)
|
||||
export class MainThreadLogService implements MainThreadLogShape {
|
||||
|
||||
private readonly _loggers = new Map<string, FileLogService>();
|
||||
private readonly _loggers = new Map<string, FileLogger>();
|
||||
private readonly _logListener: IDisposable;
|
||||
|
||||
constructor(
|
||||
|
@ -40,7 +40,7 @@ export class MainThreadLogService implements MainThreadLogShape {
|
|||
const uri = URI.revive(file);
|
||||
let logger = this._loggers.get(uri.toString());
|
||||
if (!logger) {
|
||||
logger = this._instaService.createInstance(FileLogService, basename(file.path), URI.revive(file), this._logService.getLevel());
|
||||
logger = this._instaService.createInstance(FileLogger, basename(file.path), URI.revive(file), this._logService.getLevel());
|
||||
this._loggers.set(uri.toString(), logger);
|
||||
}
|
||||
logger.log(level, message);
|
||||
|
|
|
@ -35,7 +35,8 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
|
|||
this._register(tunnelService.onTunnelClosed(() => this._proxy.$onDidTunnelsChange()));
|
||||
}
|
||||
|
||||
async $setCandidateFinder(): Promise<void> {
|
||||
async $setRemoteTunnelService(processId: number): Promise<void> {
|
||||
this.remoteExplorerService.namedProcesses.set(processId, 'Code Extension Host');
|
||||
if (this.remoteExplorerService.portsFeaturesEnabled) {
|
||||
this._proxy.$registerCandidateFinder(this.configurationService.getValue(PORT_AUTO_FORWARD_SETTING));
|
||||
} else {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue