mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-04-05 19:40:30 -04:00
Merge from vscode 1fbacccbc900bb59ba8a8f26a4128d48a1c97842
This commit is contained in:
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -22,6 +22,8 @@
|
|||||||
"i18n/**": true,
|
"i18n/**": true,
|
||||||
"extensions/**/out/**": true,
|
"extensions/**/out/**": true,
|
||||||
"test/smoke/out/**": true,
|
"test/smoke/out/**": true,
|
||||||
|
"test/automation/out/**": true,
|
||||||
|
"test/integration/browser/out/**": true,
|
||||||
"src/vs/base/test/node/uri.test.data.txt": true
|
"src/vs/base/test/node/uri.test.data.txt": true
|
||||||
},
|
},
|
||||||
"lcov.path": [
|
"lcov.path": [
|
||||||
|
|||||||
@@ -8,5 +8,7 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.cs.disable-library-validation</key>
|
<key>com.apple.security.cs.disable-library-validation</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||||
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -120,17 +120,19 @@ steps:
|
|||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \
|
APP_ROOT=$(agent.builddirectory)/VSCode-darwin
|
||||||
./resources/server/test/test-web-integration.sh --browser webkit
|
APP_NAME="`ls $APP_ROOT | head -n 1`"
|
||||||
displayName: Run integration tests (Browser)
|
INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \
|
||||||
|
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-darwin" \
|
||||||
|
./resources/server/test/test-remote-integration.sh
|
||||||
|
displayName: Run remote integration tests (Electron)
|
||||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \
|
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \
|
||||||
yarn smoketest --web --headless --browser webkit
|
./resources/server/test/test-web-integration.sh --browser webkit
|
||||||
continueOnError: true
|
displayName: Run integration tests (Browser)
|
||||||
displayName: Run smoke tests (Browser)
|
|
||||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ node build/azure-pipelines/common/createAsset.js \
|
|||||||
../vscode-server-darwin.zip
|
../vscode-server-darwin.zip
|
||||||
|
|
||||||
# publish hockeyapp symbols
|
# publish hockeyapp symbols
|
||||||
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" x64 "$VSCODE_HOCKEYAPP_ID_MACOS"
|
# node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" x64 "$VSCODE_HOCKEYAPP_ID_MACOS"
|
||||||
|
# Skip hockey app because build failure.
|
||||||
|
# https://github.com/microsoft/vscode/issues/90491
|
||||||
|
|
||||||
# upload configuration
|
# upload configuration
|
||||||
yarn gulp upload-vscode-configuration
|
yarn gulp upload-vscode-configuration
|
||||||
|
|||||||
@@ -123,20 +123,21 @@ steps:
|
|||||||
displayName: Run integration tests (Electron)
|
displayName: Run integration tests (Electron)
|
||||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||||
|
|
||||||
# Fails due to weird error: Protocol error (Target.getBrowserContexts): Target closed.
|
- script: |
|
||||||
# - script: |
|
set -e
|
||||||
# set -e
|
APP_ROOT=$(agent.builddirectory)/VSCode-linux-x64
|
||||||
# VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-x64" \
|
APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName")
|
||||||
# DISPLAY=:10 ./resources/server/test/test-web-integration.sh --browser chromium
|
INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \
|
||||||
# displayName: Run integration tests (Browser)
|
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-x64" \
|
||||||
# condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
DISPLAY=:10 ./resources/server/test/test-remote-integration.sh
|
||||||
|
displayName: Run remote integration tests (Electron)
|
||||||
|
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-x64" \
|
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-x64" \
|
||||||
yarn smoketest --web --headless --browser firefox
|
DISPLAY=:10 ./resources/server/test/test-web-integration.sh --browser chromium
|
||||||
continueOnError: true
|
displayName: Run integration tests (Browser)
|
||||||
displayName: Run smoke tests (Firefox)
|
|
||||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ rm -rf $ROOT/vscode-server-*.tar.*
|
|||||||
node build/azure-pipelines/common/createAsset.js "server-$PLATFORM_LINUX" archive-unsigned "$SERVER_TARBALL_FILENAME" "$SERVER_TARBALL_PATH"
|
node build/azure-pipelines/common/createAsset.js "server-$PLATFORM_LINUX" archive-unsigned "$SERVER_TARBALL_FILENAME" "$SERVER_TARBALL_PATH"
|
||||||
|
|
||||||
# Publish hockeyapp symbols
|
# Publish hockeyapp symbols
|
||||||
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "x64" "$VSCODE_HOCKEYAPP_ID_LINUX64"
|
# node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "x64" "$VSCODE_HOCKEYAPP_ID_LINUX64"
|
||||||
|
# Skip hockey app because build failure.
|
||||||
|
# https://github.com/microsoft/vscode/issues/90491
|
||||||
|
|
||||||
# Publish DEB
|
# Publish DEB
|
||||||
PLATFORM_DEB="linux-deb-x64"
|
PLATFORM_DEB="linux-deb-x64"
|
||||||
|
|||||||
@@ -135,16 +135,18 @@ steps:
|
|||||||
- powershell: |
|
- powershell: |
|
||||||
. build/azure-pipelines/win32/exec.ps1
|
. build/azure-pipelines/win32/exec.ps1
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
exec { $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)"; .\resources\server\test\test-web-integration.bat --browser chromium }
|
$AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)"
|
||||||
displayName: Run integration tests (Browser)
|
$AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json
|
||||||
|
$AppNameShort = $AppProductJson.nameShort
|
||||||
|
exec { $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe"; $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-win32-$(VSCODE_ARCH)"; .\resources\server\test\test-remote-integration.bat }
|
||||||
|
displayName: Run remote integration tests (Electron)
|
||||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||||
|
|
||||||
- powershell: |
|
- powershell: |
|
||||||
. build/azure-pipelines/win32/exec.ps1
|
. build/azure-pipelines/win32/exec.ps1
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
exec { $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)"; yarn smoketest --web --headless --browser chromium }
|
exec { $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)"; .\resources\server\test\test-web-integration.bat --browser firefox }
|
||||||
continueOnError: true
|
displayName: Run integration tests (Browser)
|
||||||
displayName: Run smoke tests (Browser)
|
|
||||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||||
|
|
||||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||||
|
|||||||
@@ -11,13 +11,12 @@ $SystemExe = "$Repo\.build\win32-$Arch\system-setup\VSCodeSetup.exe"
|
|||||||
$UserExe = "$Repo\.build\win32-$Arch\user-setup\VSCodeSetup.exe"
|
$UserExe = "$Repo\.build\win32-$Arch\user-setup\VSCodeSetup.exe"
|
||||||
$Zip = "$Repo\.build\win32-$Arch\archive\VSCode-win32-$Arch.zip"
|
$Zip = "$Repo\.build\win32-$Arch\archive\VSCode-win32-$Arch.zip"
|
||||||
$LegacyServer = "$Root\vscode-reh-win32-$Arch"
|
$LegacyServer = "$Root\vscode-reh-win32-$Arch"
|
||||||
$ServerName = "vscode-server-win32-$Arch"
|
$Server = "$Root\vscode-server-win32-$Arch"
|
||||||
$Server = "$Root\$ServerName"
|
|
||||||
$ServerZip = "$Repo\.build\vscode-server-win32-$Arch.zip"
|
$ServerZip = "$Repo\.build\vscode-server-win32-$Arch.zip"
|
||||||
$Build = "$Root\VSCode-win32-$Arch"
|
$Build = "$Root\VSCode-win32-$Arch"
|
||||||
|
|
||||||
# Create server archive
|
# Create server archive
|
||||||
exec { Rename-Item -Path $LegacyServer -NewName $ServerName }
|
exec { xcopy $LegacyServer $Server /H /E /I }
|
||||||
exec { .\node_modules\7zip\7zip-lite\7z.exe a -tzip $ServerZip $Server -r }
|
exec { .\node_modules\7zip\7zip-lite\7z.exe a -tzip $ServerZip $Server -r }
|
||||||
|
|
||||||
# get version
|
# get version
|
||||||
@@ -31,6 +30,8 @@ exec { node build/azure-pipelines/common/createAsset.js "$AssetPlatform" setup "
|
|||||||
exec { node build/azure-pipelines/common/createAsset.js "$AssetPlatform-user" setup "VSCodeUserSetup-$Arch-$Version.exe" $UserExe }
|
exec { node build/azure-pipelines/common/createAsset.js "$AssetPlatform-user" setup "VSCodeUserSetup-$Arch-$Version.exe" $UserExe }
|
||||||
exec { node build/azure-pipelines/common/createAsset.js "server-$AssetPlatform" archive "vscode-server-win32-$Arch.zip" $ServerZip }
|
exec { node build/azure-pipelines/common/createAsset.js "server-$AssetPlatform" archive "vscode-server-win32-$Arch.zip" $ServerZip }
|
||||||
|
|
||||||
|
# Skip hockey app because build failure.
|
||||||
|
# https://github.com/microsoft/vscode/issues/90491
|
||||||
# publish hockeyapp symbols
|
# publish hockeyapp symbols
|
||||||
$hockeyAppId = if ("$Arch" -eq "ia32") { "$env:VSCODE_HOCKEYAPP_ID_WIN32" } else { "$env:VSCODE_HOCKEYAPP_ID_WIN64" }
|
# $hockeyAppId = if ("$Arch" -eq "ia32") { "$env:VSCODE_HOCKEYAPP_ID_WIN32" } else { "$env:VSCODE_HOCKEYAPP_ID_WIN64" }
|
||||||
exec { node build/azure-pipelines/common/symbols.js "$env:VSCODE_MIXIN_PASSWORD" "$env:VSCODE_HOCKEYAPP_TOKEN" "$Arch" $hockeyAppId }
|
# exec { node build/azure-pipelines/common/symbols.js "$env:VSCODE_MIXIN_PASSWORD" "$env:VSCODE_HOCKEYAPP_TOKEN" "$Arch" $hockeyAppId }
|
||||||
|
|||||||
@@ -110,6 +110,10 @@
|
|||||||
"name": "vs/workbench/contrib/output",
|
"name": "vs/workbench/contrib/output",
|
||||||
"project": "vscode-workbench"
|
"project": "vscode-workbench"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "vs/workbench/contrib/openInDesktop",
|
||||||
|
"project": "vscode-workbench"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "vs/workbench/contrib/performance",
|
"name": "vs/workbench/contrib/performance",
|
||||||
"project": "vscode-workbench"
|
"project": "vscode-workbench"
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export class ApiWrapper {
|
|||||||
return vscode.workspace.asRelativePath(uri);
|
return vscode.workspace.asRelativePath(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getWorkspaceFolders(): vscode.WorkspaceFolder[] {
|
public getWorkspaceFolders(): readonly vscode.WorkspaceFolder[] {
|
||||||
return vscode.workspace.workspaceFolders;
|
return vscode.workspace.workspaceFolders;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ export class ApiWrapper {
|
|||||||
return vscode.window.createStatusBarItem(alignment, priority);
|
return vscode.window.createStatusBarItem(alignment, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get workspaceFolders(): vscode.WorkspaceFolder[] {
|
public get workspaceFolders(): readonly vscode.WorkspaceFolder[] {
|
||||||
return vscode.workspace.workspaceFolders;
|
return vscode.workspace.workspaceFolders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export class ApiWrapper {
|
|||||||
return vscode.workspace.asRelativePath(uri);
|
return vscode.workspace.asRelativePath(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getWorkspaceFolders(): vscode.WorkspaceFolder[] {
|
public getWorkspaceFolders(): readonly vscode.WorkspaceFolder[] {
|
||||||
return vscode.workspace.workspaceFolders;
|
return vscode.workspace.workspaceFolders;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ export class ApiWrapper {
|
|||||||
return vscode.window.createStatusBarItem(alignment, priority);
|
return vscode.window.createStatusBarItem(alignment, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get workspaceFolders(): vscode.WorkspaceFolder[] {
|
public get workspaceFolders(): readonly vscode.WorkspaceFolder[] {
|
||||||
return vscode.workspace.workspaceFolders;
|
return vscode.workspace.workspaceFolders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export class SettingsDocument {
|
|||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
// Value
|
// Value
|
||||||
return this.provideLanguageCompletionItems(location, range);
|
return this.provideLanguageCompletionItemsForLanguageOverrides(location, range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,6 +158,11 @@ export class SettingsDocument {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private provideLanguageCompletionItems(_location: Location, range: vscode.Range, formatFunc: (string: string) => string = (l) => JSON.stringify(l)): Thenable<vscode.CompletionItem[]> {
|
private provideLanguageCompletionItems(_location: Location, range: vscode.Range, formatFunc: (string: string) => string = (l) => JSON.stringify(l)): Thenable<vscode.CompletionItem[]> {
|
||||||
|
return vscode.languages.getLanguages()
|
||||||
|
.then(languages => languages.map(l => this.newSimpleCompletionItem(formatFunc(l), range)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private provideLanguageCompletionItemsForLanguageOverrides(_location: Location, range: vscode.Range, formatFunc: (string: string) => string = (l) => JSON.stringify(l)): Thenable<vscode.CompletionItem[]> {
|
||||||
return vscode.languages.getLanguages().then(languages => {
|
return vscode.languages.getLanguages().then(languages => {
|
||||||
const completionItems = [];
|
const completionItems = [];
|
||||||
const configuration = vscode.workspace.getConfiguration();
|
const configuration = vscode.workspace.getConfiguration();
|
||||||
@@ -182,7 +187,7 @@ export class SettingsDocument {
|
|||||||
let text = this.document.getText(range);
|
let text = this.document.getText(range);
|
||||||
if (text && text.trim().startsWith('[')) {
|
if (text && text.trim().startsWith('[')) {
|
||||||
range = new vscode.Range(new vscode.Position(range.start.line, range.start.character + text.indexOf('[')), range.end);
|
range = new vscode.Range(new vscode.Position(range.start.line, range.start.character + text.indexOf('[')), range.end);
|
||||||
return this.provideLanguageCompletionItems(location, range, language => `"[${language}]"`);
|
return this.provideLanguageCompletionItemsForLanguageOverrides(location, range, language => `"[${language}]"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
range = this.document.getWordRangeAtPosition(position) || new vscode.Range(position, position);
|
range = this.document.getWordRangeAtPosition(position) || new vscode.Range(position, position);
|
||||||
@@ -209,7 +214,7 @@ export class SettingsDocument {
|
|||||||
// Suggestion model word matching includes closed sqaure bracket and ending quote
|
// Suggestion model word matching includes closed sqaure bracket and ending quote
|
||||||
// Hence include them in the proposal to replace
|
// Hence include them in the proposal to replace
|
||||||
let range = this.document.getWordRangeAtPosition(position) || new vscode.Range(position, position);
|
let range = this.document.getWordRangeAtPosition(position) || new vscode.Range(position, position);
|
||||||
return this.provideLanguageCompletionItems(location, range, language => `"[${language}]"`);
|
return this.provideLanguageCompletionItemsForLanguageOverrides(location, range, language => `"[${language}]"`);
|
||||||
}
|
}
|
||||||
return Promise.resolve([]);
|
return Promise.resolve([]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export class ApiWrapper {
|
|||||||
return vscode.window.showTextDocument(document, options);
|
return vscode.window.showTextDocument(document, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get workspaceFolders(): vscode.WorkspaceFolder[] {
|
public get workspaceFolders(): readonly vscode.WorkspaceFolder[] {
|
||||||
return vscode.workspace.workspaceFolders;
|
return vscode.workspace.workspaceFolders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
let workspaceFolders = vscode.workspace.workspaceFolders || [];
|
let workspaceFolders = vscode.workspace.workspaceFolders?.slice() ?? [];
|
||||||
const bookTreeViewProvider = new BookTreeViewProvider(workspaceFolders, extensionContext, false, BOOKS_VIEWID);
|
const bookTreeViewProvider = new BookTreeViewProvider(workspaceFolders, extensionContext, false, BOOKS_VIEWID);
|
||||||
await bookTreeViewProvider.initialized;
|
await bookTreeViewProvider.initialized;
|
||||||
const untitledBookTreeViewProvider = new BookTreeViewProvider([], extensionContext, true, READONLY_BOOKS_VIEWID);
|
const untitledBookTreeViewProvider = new BookTreeViewProvider([], extensionContext, true, READONLY_BOOKS_VIEWID);
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
// todo@jackson
|
|
||||||
/* eslint code-no-unexternalized-strings: 0 */
|
|
||||||
|
|
||||||
const mappings = [
|
const mappings = [
|
||||||
['bat', 'source.batchfile'],
|
['bat', 'source.batchfile'],
|
||||||
@@ -40,6 +38,7 @@ const mappings = [
|
|||||||
['perl', 'source.perl'],
|
['perl', 'source.perl'],
|
||||||
['php', 'source.php'],
|
['php', 'source.php'],
|
||||||
['pl', 'source.perl'],
|
['pl', 'source.perl'],
|
||||||
|
['pm', 'source.perl'],
|
||||||
['ps1', 'source.powershell'],
|
['ps1', 'source.powershell'],
|
||||||
['pug', 'text.pug'],
|
['pug', 'text.pug'],
|
||||||
['py', 'source.python'],
|
['py', 'source.python'],
|
||||||
@@ -104,43 +103,43 @@ mappings.forEach(([ext, scope, regexp]) =>
|
|||||||
repository[ext] = {
|
repository[ext] = {
|
||||||
name: scopes.resultBlock.meta,
|
name: scopes.resultBlock.meta,
|
||||||
begin: `^(?!\\s)(.*?)([^\\\\\\/\\n]*${regexp || `\\.${ext}`})(:)$`,
|
begin: `^(?!\\s)(.*?)([^\\\\\\/\\n]*${regexp || `\\.${ext}`})(:)$`,
|
||||||
end: "^(?!\\s)",
|
end: '^(?!\\s)',
|
||||||
beginCaptures: {
|
beginCaptures: {
|
||||||
"0": { name: scopes.resultBlock.path.meta },
|
'0': { name: scopes.resultBlock.path.meta },
|
||||||
"1": { name: scopes.resultBlock.path.dirname },
|
'1': { name: scopes.resultBlock.path.dirname },
|
||||||
"2": { name: scopes.resultBlock.path.basename },
|
'2': { name: scopes.resultBlock.path.basename },
|
||||||
"3": { name: scopes.resultBlock.path.colon },
|
'3': { name: scopes.resultBlock.path.colon },
|
||||||
},
|
},
|
||||||
patterns: [
|
patterns: [
|
||||||
{
|
{
|
||||||
name: [scopes.resultBlock.result.meta, scopes.resultBlock.result.metaMultiLine].join(' '),
|
name: [scopes.resultBlock.result.meta, scopes.resultBlock.result.metaMultiLine].join(' '),
|
||||||
begin: "^ ((\\d+) )",
|
begin: '^ ((\\d+) )',
|
||||||
while: "^ (?:((\\d+)(:))|((\\d+) ))",
|
while: '^ (?:((\\d+)(:))|((\\d+) ))',
|
||||||
beginCaptures: {
|
beginCaptures: {
|
||||||
"0": { name: scopes.resultBlock.result.prefix.meta },
|
'0': { name: scopes.resultBlock.result.prefix.meta },
|
||||||
"1": { name: scopes.resultBlock.result.prefix.metaContext },
|
'1': { name: scopes.resultBlock.result.prefix.metaContext },
|
||||||
"2": { name: scopes.resultBlock.result.prefix.lineNumber },
|
'2': { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||||
},
|
},
|
||||||
whileCaptures: {
|
whileCaptures: {
|
||||||
"0": { name: scopes.resultBlock.result.prefix.meta },
|
'0': { name: scopes.resultBlock.result.prefix.meta },
|
||||||
"1": { name: scopes.resultBlock.result.prefix.metaMatch },
|
'1': { name: scopes.resultBlock.result.prefix.metaMatch },
|
||||||
"2": { name: scopes.resultBlock.result.prefix.lineNumber },
|
'2': { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||||
"3": { name: scopes.resultBlock.result.prefix.colon },
|
'3': { name: scopes.resultBlock.result.prefix.colon },
|
||||||
|
|
||||||
"4": { name: scopes.resultBlock.result.prefix.metaContext },
|
'4': { name: scopes.resultBlock.result.prefix.metaContext },
|
||||||
"5": { name: scopes.resultBlock.result.prefix.lineNumber },
|
'5': { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||||
},
|
},
|
||||||
patterns: [{ include: scope }]
|
patterns: [{ include: scope }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
begin: "^ ((\\d+)(:))",
|
begin: '^ ((\\d+)(:))',
|
||||||
while: "(?=not)possible",
|
while: '(?=not)possible',
|
||||||
name: [scopes.resultBlock.result.meta, scopes.resultBlock.result.metaSingleLine].join(' '),
|
name: [scopes.resultBlock.result.meta, scopes.resultBlock.result.metaSingleLine].join(' '),
|
||||||
beginCaptures: {
|
beginCaptures: {
|
||||||
"0": { name: scopes.resultBlock.result.prefix.meta },
|
'0': { name: scopes.resultBlock.result.prefix.meta },
|
||||||
"1": { name: scopes.resultBlock.result.prefix.metaMatch },
|
'1': { name: scopes.resultBlock.result.prefix.metaMatch },
|
||||||
"2": { name: scopes.resultBlock.result.prefix.lineNumber },
|
'2': { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||||
"3": { name: scopes.resultBlock.result.prefix.colon },
|
'3': { name: scopes.resultBlock.result.prefix.colon },
|
||||||
},
|
},
|
||||||
patterns: [{ include: scope }]
|
patterns: [{ include: scope }]
|
||||||
}
|
}
|
||||||
@@ -149,10 +148,10 @@ mappings.forEach(([ext, scope, regexp]) =>
|
|||||||
|
|
||||||
const header = [
|
const header = [
|
||||||
{
|
{
|
||||||
begin: "^(# Query): ",
|
begin: '^(# Query): ',
|
||||||
end: "\n",
|
end: '\n',
|
||||||
name: scopes.header.meta,
|
name: scopes.header.meta,
|
||||||
beginCaptures: { "1": { name: scopes.header.key }, },
|
beginCaptures: { '1': { name: scopes.header.key }, },
|
||||||
patterns: [
|
patterns: [
|
||||||
{
|
{
|
||||||
match: '(\\\\n)|(\\\\\\\\)',
|
match: '(\\\\n)|(\\\\\\\\)',
|
||||||
@@ -169,10 +168,10 @@ const header = [
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
begin: "^(# Flags): ",
|
begin: '^(# Flags): ',
|
||||||
end: "\n",
|
end: '\n',
|
||||||
name: scopes.header.meta,
|
name: scopes.header.meta,
|
||||||
beginCaptures: { "1": { name: scopes.header.key }, },
|
beginCaptures: { '1': { name: scopes.header.key }, },
|
||||||
patterns: [
|
patterns: [
|
||||||
{
|
{
|
||||||
match: '(RegExp|CaseSensitive|IgnoreExcludeSettings|WordMatch)',
|
match: '(RegExp|CaseSensitive|IgnoreExcludeSettings|WordMatch)',
|
||||||
@@ -182,10 +181,10 @@ const header = [
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
begin: "^(# ContextLines): ",
|
begin: '^(# ContextLines): ',
|
||||||
end: "\n",
|
end: '\n',
|
||||||
name: scopes.header.meta,
|
name: scopes.header.meta,
|
||||||
beginCaptures: { "1": { name: scopes.header.key }, },
|
beginCaptures: { '1': { name: scopes.header.key }, },
|
||||||
patterns: [
|
patterns: [
|
||||||
{
|
{
|
||||||
match: '\\d',
|
match: '\\d',
|
||||||
@@ -195,42 +194,42 @@ const header = [
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(# (?:Including|Excluding)): (.*)$",
|
match: '^(# (?:Including|Excluding)): (.*)$',
|
||||||
name: scopes.header.meta,
|
name: scopes.header.meta,
|
||||||
captures: {
|
captures: {
|
||||||
"1": { name: scopes.header.key },
|
'1': { name: scopes.header.key },
|
||||||
"2": { name: scopes.header.value }
|
'2': { name: scopes.header.value }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const plainText = [
|
const plainText = [
|
||||||
{
|
{
|
||||||
match: "^(?!\\s)(.*?)([^\\\\\\/\\n]*)(:)$",
|
match: '^(?!\\s)(.*?)([^\\\\\\/\\n]*)(:)$',
|
||||||
name: [scopes.resultBlock.meta, scopes.resultBlock.path.meta].join(' '),
|
name: [scopes.resultBlock.meta, scopes.resultBlock.path.meta].join(' '),
|
||||||
captures: {
|
captures: {
|
||||||
"1": { name: scopes.resultBlock.path.dirname },
|
'1': { name: scopes.resultBlock.path.dirname },
|
||||||
"2": { name: scopes.resultBlock.path.basename },
|
'2': { name: scopes.resultBlock.path.basename },
|
||||||
"3": { name: scopes.resultBlock.path.colon }
|
'3': { name: scopes.resultBlock.path.colon }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^ (?:((\\d+)(:))|((\\d+)( ))(.*))",
|
match: '^ (?:((\\d+)(:))|((\\d+)( ))(.*))',
|
||||||
name: [scopes.resultBlock.meta, scopes.resultBlock.result.meta].join(' '),
|
name: [scopes.resultBlock.meta, scopes.resultBlock.result.meta].join(' '),
|
||||||
captures: {
|
captures: {
|
||||||
"1": { name: [scopes.resultBlock.result.prefix.meta, scopes.resultBlock.result.prefix.metaMatch].join(' ') },
|
'1': { name: [scopes.resultBlock.result.prefix.meta, scopes.resultBlock.result.prefix.metaMatch].join(' ') },
|
||||||
"2": { name: scopes.resultBlock.result.prefix.lineNumber },
|
'2': { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||||
"3": { name: scopes.resultBlock.result.prefix.colon },
|
'3': { name: scopes.resultBlock.result.prefix.colon },
|
||||||
|
|
||||||
"4": { name: [scopes.resultBlock.result.prefix.meta, scopes.resultBlock.result.prefix.metaContext].join(' ') },
|
'4': { name: [scopes.resultBlock.result.prefix.meta, scopes.resultBlock.result.prefix.metaContext].join(' ') },
|
||||||
"5": { name: scopes.resultBlock.result.prefix.lineNumber },
|
'5': { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const tmLanguage = {
|
const tmLanguage = {
|
||||||
"information_for_contributors": "This file is generated from ./generateTMLanguage.js.",
|
'information_for_contributors': 'This file is generated from ./generateTMLanguage.js.',
|
||||||
name: "Search Results",
|
name: 'Search Results',
|
||||||
scopeName: scopes.root,
|
scopeName: scopes.root,
|
||||||
patterns: [
|
patterns: [
|
||||||
...header,
|
...header,
|
||||||
|
|||||||
@@ -189,6 +189,9 @@
|
|||||||
{
|
{
|
||||||
"include": "#pl"
|
"include": "#pl"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"include": "#pm"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"include": "#ps1"
|
"include": "#ps1"
|
||||||
},
|
},
|
||||||
@@ -3457,6 +3460,92 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"pm": {
|
||||||
|
"name": "meta.resultBlock.search",
|
||||||
|
"begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.pm)(:)$",
|
||||||
|
"end": "^(?!\\s)",
|
||||||
|
"beginCaptures": {
|
||||||
|
"0": {
|
||||||
|
"name": "string meta.path.search"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"name": "meta.path.dirname.search"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"name": "meta.path.basename.search"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"name": "punctuation.separator"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patterns": [
|
||||||
|
{
|
||||||
|
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||||
|
"begin": "^ ((\\d+) )",
|
||||||
|
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||||
|
"beginCaptures": {
|
||||||
|
"0": {
|
||||||
|
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"name": "meta.resultLinePrefix.contextLinePrefix.search"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"name": "meta.resultLinePrefix.lineNumber.search"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"whileCaptures": {
|
||||||
|
"0": {
|
||||||
|
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"name": "meta.resultLinePrefix.matchLinePrefix.search"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"name": "meta.resultLinePrefix.lineNumber.search"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"name": "punctuation.separator"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"name": "meta.resultLinePrefix.contextLinePrefix.search"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"name": "meta.resultLinePrefix.lineNumber.search"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patterns": [
|
||||||
|
{
|
||||||
|
"include": "source.perl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"begin": "^ ((\\d+)(:))",
|
||||||
|
"while": "(?=not)possible",
|
||||||
|
"name": "meta.resultLine.search meta.resultLine.singleLine.search",
|
||||||
|
"beginCaptures": {
|
||||||
|
"0": {
|
||||||
|
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"name": "meta.resultLinePrefix.matchLinePrefix.search"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"name": "meta.resultLinePrefix.lineNumber.search"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"name": "punctuation.separator"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patterns": [
|
||||||
|
{
|
||||||
|
"include": "source.perl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"ps1": {
|
"ps1": {
|
||||||
"name": "meta.resultBlock.search",
|
"name": "meta.resultBlock.search",
|
||||||
"begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.ps1)(:)$",
|
"begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.ps1)(:)$",
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
"vscode-ripgrep": "^1.5.8",
|
"vscode-ripgrep": "^1.5.8",
|
||||||
"vscode-sqlite3": "4.0.9",
|
"vscode-sqlite3": "4.0.9",
|
||||||
"vscode-textmate": "4.4.0",
|
"vscode-textmate": "4.4.0",
|
||||||
"xterm": "4.4.0",
|
"xterm": "4.5.0-beta.4",
|
||||||
"xterm-addon-search": "0.5.0",
|
"xterm-addon-search": "0.5.0",
|
||||||
"xterm-addon-unicode11": "0.1.1",
|
"xterm-addon-unicode11": "0.1.1",
|
||||||
"xterm-addon-web-links": "0.2.1",
|
"xterm-addon-web-links": "0.2.1",
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
"vscode-proxy-agent": "^0.5.2",
|
"vscode-proxy-agent": "^0.5.2",
|
||||||
"vscode-ripgrep": "^1.5.8",
|
"vscode-ripgrep": "^1.5.8",
|
||||||
"vscode-textmate": "4.4.0",
|
"vscode-textmate": "4.4.0",
|
||||||
"xterm": "4.4.0",
|
"xterm": "4.5.0-beta.4",
|
||||||
"xterm-addon-search": "0.5.0",
|
"xterm-addon-search": "0.5.0",
|
||||||
"xterm-addon-unicode11": "0.1.1",
|
"xterm-addon-unicode11": "0.1.1",
|
||||||
"xterm-addon-web-links": "0.2.1",
|
"xterm-addon-web-links": "0.2.1",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"onigasm-umd": "2.2.5",
|
"onigasm-umd": "2.2.5",
|
||||||
"semver-umd": "^5.5.5",
|
"semver-umd": "^5.5.5",
|
||||||
"vscode-textmate": "4.4.0",
|
"vscode-textmate": "4.4.0",
|
||||||
"xterm": "4.4.0",
|
"xterm": "4.5.0-beta.4",
|
||||||
"xterm-addon-search": "0.5.0",
|
"xterm-addon-search": "0.5.0",
|
||||||
"xterm-addon-unicode11": "0.1.1",
|
"xterm-addon-unicode11": "0.1.1",
|
||||||
"xterm-addon-web-links": "0.2.1",
|
"xterm-addon-web-links": "0.2.1",
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ xterm-addon-webgl@0.5.0:
|
|||||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.5.0.tgz#c1031dc7599cce3509824643ab5f15361c928e3e"
|
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.5.0.tgz#c1031dc7599cce3509824643ab5f15361c928e3e"
|
||||||
integrity sha512-hQrvabKCnwXFaEZ+YtoJM9Pm0CIBXL5KSwoU+RiGStU3KYTAcqYP2GsH3dWdvKX6kTWhWLS81dtDsGkfbOciuA==
|
integrity sha512-hQrvabKCnwXFaEZ+YtoJM9Pm0CIBXL5KSwoU+RiGStU3KYTAcqYP2GsH3dWdvKX6kTWhWLS81dtDsGkfbOciuA==
|
||||||
|
|
||||||
xterm@4.4.0:
|
xterm@4.5.0-beta.4:
|
||||||
version "4.4.0"
|
version "4.5.0-beta.4"
|
||||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.4.0.tgz#5915d3c4c8800fadbcf555a0a603c672ab9df589"
|
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.5.0-beta.4.tgz#701f05553b643236d3fcd8bb7f14045bd4537c92"
|
||||||
integrity sha512-JGIpigWM3EBWvnS3rtBuefkiToIILSK1HYMXy4BCsUpO+O4UeeV+/U1AdAXgCB6qJrnPNb7yLgBsVCQUNMteig==
|
integrity sha512-Yv1Bf60LTLBMaig1rv033hPz8hQGXZN6VYW2oe/409t2NbJXPg5xZgf47qyaWFV7a5k1BFiwjayJCWaL2nYBew==
|
||||||
|
|||||||
@@ -433,10 +433,10 @@ xterm-addon-webgl@0.5.0:
|
|||||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.5.0.tgz#c1031dc7599cce3509824643ab5f15361c928e3e"
|
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.5.0.tgz#c1031dc7599cce3509824643ab5f15361c928e3e"
|
||||||
integrity sha512-hQrvabKCnwXFaEZ+YtoJM9Pm0CIBXL5KSwoU+RiGStU3KYTAcqYP2GsH3dWdvKX6kTWhWLS81dtDsGkfbOciuA==
|
integrity sha512-hQrvabKCnwXFaEZ+YtoJM9Pm0CIBXL5KSwoU+RiGStU3KYTAcqYP2GsH3dWdvKX6kTWhWLS81dtDsGkfbOciuA==
|
||||||
|
|
||||||
xterm@4.4.0:
|
xterm@4.5.0-beta.4:
|
||||||
version "4.4.0"
|
version "4.5.0-beta.4"
|
||||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.4.0.tgz#5915d3c4c8800fadbcf555a0a603c672ab9df589"
|
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.5.0-beta.4.tgz#701f05553b643236d3fcd8bb7f14045bd4537c92"
|
||||||
integrity sha512-JGIpigWM3EBWvnS3rtBuefkiToIILSK1HYMXy4BCsUpO+O4UeeV+/U1AdAXgCB6qJrnPNb7yLgBsVCQUNMteig==
|
integrity sha512-Yv1Bf60LTLBMaig1rv033hPz8hQGXZN6VYW2oe/409t2NbJXPg5xZgf47qyaWFV7a5k1BFiwjayJCWaL2nYBew==
|
||||||
|
|
||||||
yauzl@^2.9.2:
|
yauzl@^2.9.2:
|
||||||
version "2.10.0"
|
version "2.10.0"
|
||||||
|
|||||||
@@ -67,10 +67,6 @@ if %errorlevel% neq 0 exit /b %errorlevel%
|
|||||||
call .\scripts\node-electron.bat .\node_modules\mocha\bin\_mocha .\extensions\*\server\out\test\**\*.test.js
|
call .\scripts\node-electron.bat .\node_modules\mocha\bin\_mocha .\extensions\*\server\out\test\**\*.test.js
|
||||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
|
||||||
if exist ".\resources\server\test\test-remote-integration.bat" (
|
|
||||||
call .\resources\server\test\test-remote-integration.bat
|
|
||||||
)
|
|
||||||
|
|
||||||
rmdir /s /q %VSCODEUSERDATADIR%
|
rmdir /s /q %VSCODEUSERDATADIR%
|
||||||
|
|
||||||
popd
|
popd
|
||||||
|
|||||||
@@ -51,11 +51,6 @@ fi
|
|||||||
|
|
||||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/azurecore/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
|
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/azurecore/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
|
||||||
|
|
||||||
# Remote Integration Tests
|
|
||||||
if [ -f ./resources/server/test/test-remote-integration.sh ]; then
|
|
||||||
./resources/server/test/test-remote-integration.sh
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Tests in commonJS
|
# Tests in commonJS
|
||||||
cd $ROOT/extensions/css-language-features/server && $ROOT/scripts/node-electron.sh test/index.js
|
cd $ROOT/extensions/css-language-features/server && $ROOT/scripts/node-electron.sh test/index.js
|
||||||
cd $ROOT/extensions/html-language-features/server && $ROOT/scripts/node-electron.sh test/index.js
|
cd $ROOT/extensions/html-language-features/server && $ROOT/scripts/node-electron.sh test/index.js
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/commo
|
|||||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
|
import { UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
||||||
|
|
||||||
class MainThreadNotebookEditor extends Disposable {
|
class MainThreadNotebookEditor extends Disposable {
|
||||||
private _contentChangedEmitter = new Emitter<NotebookContentChange>();
|
private _contentChangedEmitter = new Emitter<NotebookContentChange>();
|
||||||
@@ -458,12 +459,17 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
|||||||
};
|
};
|
||||||
let isUntitled: boolean = uri.scheme === Schemas.untitled;
|
let isUntitled: boolean = uri.scheme === Schemas.untitled;
|
||||||
|
|
||||||
let fileInput;
|
let fileInput: UntitledTextEditorInput | FileEditorInput;
|
||||||
if (isUntitled && path.isAbsolute(uri.fsPath)) {
|
if (isUntitled && path.isAbsolute(uri.fsPath)) {
|
||||||
fileInput = this._untitledEditorService.create({ associatedResource: uri, mode: 'notebook', initialValue: options.initialContent });
|
const model = this._untitledEditorService.create({ associatedResource: uri, mode: 'notebook', initialValue: options.initialContent });
|
||||||
|
fileInput = this._instantiationService.createInstance(UntitledTextEditorInput, model);
|
||||||
} else {
|
} else {
|
||||||
fileInput = isUntitled ? this._untitledEditorService.create({ untitledResource: uri, mode: 'notebook', initialValue: options.initialContent }) :
|
if (isUntitled) {
|
||||||
this._editorService.createInput({ resource: uri, mode: 'notebook' });
|
const model = this._untitledEditorService.create({ untitledResource: uri, mode: 'notebook', initialValue: options.initialContent });
|
||||||
|
fileInput = this._instantiationService.createInstance(UntitledTextEditorInput, model);
|
||||||
|
} else {
|
||||||
|
fileInput = this._editorService.createInput({ forceFile: true, resource: uri, mode: 'notebook' }) as FileEditorInput;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let input: NotebookInput;
|
let input: NotebookInput;
|
||||||
if (isUntitled) {
|
if (isUntitled) {
|
||||||
@@ -478,7 +484,7 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
|||||||
await untitledModel.load();
|
await untitledModel.load();
|
||||||
input.untitledEditorModel = untitledModel;
|
input.untitledEditorModel = untitledModel;
|
||||||
if (options.initialDirtyState === false) {
|
if (options.initialDirtyState === false) {
|
||||||
input.untitledEditorModel.setDirty(false);
|
(input.untitledEditorModel as UntitledTextEditorModel).setDirty(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let editor = await this._editorService.openEditor(input, editorOptions, viewColumnToEditorGroup(this._editorGroupService, options.position));
|
let editor = await this._editorService.openEditor(input, editorOptions, viewColumnToEditorGroup(this._editorGroupService, options.position));
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/vie
|
|||||||
import { attachModalDialogStyler, attachPanelStyler } from 'sql/workbench/common/styler';
|
import { attachModalDialogStyler, attachPanelStyler } from 'sql/workbench/common/styler';
|
||||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||||
import { ServiceOptionType } from 'sql/platform/connection/common/interfaces';
|
import { ServiceOptionType } from 'sql/platform/connection/common/interfaces';
|
||||||
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
|
|
||||||
export class CategoryView extends ViewPane {
|
export class CategoryView extends ViewPane {
|
||||||
|
|
||||||
@@ -48,9 +49,11 @@ export class CategoryView extends ViewPane {
|
|||||||
@IConfigurationService configurationService: IConfigurationService,
|
@IConfigurationService configurationService: IConfigurationService,
|
||||||
@IContextKeyService contextKeyService: IContextKeyService,
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
@IInstantiationService instantiationService: IInstantiationService,
|
@IInstantiationService instantiationService: IInstantiationService,
|
||||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService
|
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||||
|
@IOpenerService protected openerService: IOpenerService,
|
||||||
|
@IThemeService protected themeService: IThemeService
|
||||||
) {
|
) {
|
||||||
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService);
|
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, opener, themeService);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we want a fixed size, so when we render to will measure our content and set that to be our
|
// we want a fixed size, so when we render to will measure our content and set that to be our
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
|||||||
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
|
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
|
||||||
import { SimpleProgressIndicator } from 'sql/workbench/services/progress/browser/simpleProgressIndicator';
|
import { SimpleProgressIndicator } from 'sql/workbench/services/progress/browser/simpleProgressIndicator';
|
||||||
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/platform/dashboard/browser/interfaces';
|
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/platform/dashboard/browser/interfaces';
|
||||||
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
template: '',
|
template: '',
|
||||||
@@ -47,7 +48,8 @@ export default class EditorComponent extends ComponentBase implements IComponent
|
|||||||
@Inject(IInstantiationService) private _instantiationService: IInstantiationService,
|
@Inject(IInstantiationService) private _instantiationService: IInstantiationService,
|
||||||
@Inject(IModelService) private _modelService: IModelService,
|
@Inject(IModelService) private _modelService: IModelService,
|
||||||
@Inject(IModeService) private _modeService: IModeService,
|
@Inject(IModeService) private _modeService: IModeService,
|
||||||
@Inject(ILogService) private _logService: ILogService
|
@Inject(ILogService) private _logService: ILogService,
|
||||||
|
@Inject(IEditorService) private readonly editorService: IEditorService
|
||||||
) {
|
) {
|
||||||
super(changeRef, el);
|
super(changeRef, el);
|
||||||
}
|
}
|
||||||
@@ -66,7 +68,7 @@ export default class EditorComponent extends ComponentBase implements IComponent
|
|||||||
this._editor.create(this._el.nativeElement);
|
this._editor.create(this._el.nativeElement);
|
||||||
this._editor.setVisible(true);
|
this._editor.setVisible(true);
|
||||||
let uri = this.createUri();
|
let uri = this.createUri();
|
||||||
this._editorInput = this._instantiationService.createInstance(UntitledTextEditorInput, uri, false, 'plaintext', '', '');
|
this._editorInput = this.editorService.createInput({ forceUntitled: true, resource: uri, mode: 'plaintext' }) as UntitledTextEditorInput;
|
||||||
await this._editor.setInput(this._editorInput, undefined);
|
await this._editor.setInput(this._editorInput, undefined);
|
||||||
const model = await this._editorInput.resolve();
|
const model = await this._editorInput.resolve();
|
||||||
this._editorModel = model.textEditorModel;
|
this._editorModel = model.textEditorModel;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels';
|
|||||||
import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { dirname, basename } from 'vs/base/common/resources';
|
import { dirname, basename } from 'vs/base/common/resources';
|
||||||
import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||||
import { FileKind } from 'vs/platform/files/common/files';
|
import { FileKind } from 'vs/platform/files/common/files';
|
||||||
import { WorkbenchAsyncDataTree, TreeResourceNavigator } from 'vs/platform/list/browser/listService';
|
import { WorkbenchAsyncDataTree, TreeResourceNavigator } from 'vs/platform/list/browser/listService';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
@@ -63,9 +63,11 @@ export class CustomTreeViewPanel extends ViewPane {
|
|||||||
@IConfigurationService configurationService: IConfigurationService,
|
@IConfigurationService configurationService: IConfigurationService,
|
||||||
@IContextKeyService contextKeyService: IContextKeyService,
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
@IInstantiationService instantiationService: IInstantiationService,
|
@IInstantiationService instantiationService: IInstantiationService,
|
||||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService
|
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||||
|
@IOpenerService protected openerService: IOpenerService,
|
||||||
|
@IThemeService protected themeService: IThemeService
|
||||||
) {
|
) {
|
||||||
super({ ...(options as IViewPaneOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService);
|
super({ ...(options as IViewPaneOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService);
|
||||||
const { treeView } = (<ITreeViewDescriptor>Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).getView(options.id));
|
const { treeView } = (<ITreeViewDescriptor>Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).getView(options.id));
|
||||||
this.treeView = treeView as ITreeView;
|
this.treeView = treeView as ITreeView;
|
||||||
this._register(this.treeView.onDidChangeActions(() => this.updateActions(), this));
|
this._register(this.treeView.onDidChangeActions(() => this.updateActions(), this));
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
|||||||
import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||||
import { attachModalDialogStyler, attachPanelStyler } from 'sql/workbench/common/styler';
|
import { attachModalDialogStyler, attachPanelStyler } from 'sql/workbench/common/styler';
|
||||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||||
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
|
|
||||||
class AccountPanel extends ViewPane {
|
class AccountPanel extends ViewPane {
|
||||||
public index: number;
|
public index: number;
|
||||||
@@ -48,12 +49,13 @@ class AccountPanel extends ViewPane {
|
|||||||
@IKeybindingService keybindingService: IKeybindingService,
|
@IKeybindingService keybindingService: IKeybindingService,
|
||||||
@IContextMenuService contextMenuService: IContextMenuService,
|
@IContextMenuService contextMenuService: IContextMenuService,
|
||||||
@IConfigurationService configurationService: IConfigurationService,
|
@IConfigurationService configurationService: IConfigurationService,
|
||||||
@IThemeService private themeService: IThemeService,
|
@IThemeService themeService: IThemeService,
|
||||||
@IContextKeyService contextKeyService: IContextKeyService,
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
@IInstantiationService instantiationService: IInstantiationService,
|
@IInstantiationService instantiationService: IInstantiationService,
|
||||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService
|
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||||
|
@IOpenerService openerService: IOpenerService,
|
||||||
) {
|
) {
|
||||||
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService);
|
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderBody(container: HTMLElement): void {
|
protected renderBody(container: HTMLElement): void {
|
||||||
@@ -130,7 +132,8 @@ export class AccountDialog extends Modal {
|
|||||||
@IClipboardService clipboardService: IClipboardService,
|
@IClipboardService clipboardService: IClipboardService,
|
||||||
@ILogService logService: ILogService,
|
@ILogService logService: ILogService,
|
||||||
@IViewDescriptorService private viewDescriptorService: IViewDescriptorService,
|
@IViewDescriptorService private viewDescriptorService: IViewDescriptorService,
|
||||||
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService
|
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService,
|
||||||
|
@IOpenerService protected readonly openerService: IOpenerService
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
localize('linkedAccounts', "Linked accounts"),
|
localize('linkedAccounts', "Linked accounts"),
|
||||||
@@ -301,7 +304,8 @@ export class AccountDialog extends Modal {
|
|||||||
this._themeService,
|
this._themeService,
|
||||||
this.contextKeyService,
|
this.contextKeyService,
|
||||||
this._instantiationService,
|
this._instantiationService,
|
||||||
this.viewDescriptorService
|
this.viewDescriptorService,
|
||||||
|
this.openerService
|
||||||
);
|
);
|
||||||
|
|
||||||
attachPanelStyler(providerView, this._themeService);
|
attachPanelStyler(providerView, this._themeService);
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ function createInstantiationService(addAccountFailureEmitter?: Emitter<string>):
|
|||||||
.returns(() => undefined);
|
.returns(() => undefined);
|
||||||
|
|
||||||
// Create a mock account dialog
|
// Create a mock account dialog
|
||||||
let accountDialog = new AccountDialog(undefined!, undefined!, instantiationService.object, undefined!, undefined!, undefined!, undefined!, new MockContextKeyService(), undefined!, undefined!, undefined!, undefined!);
|
let accountDialog = new AccountDialog(undefined!, undefined!, instantiationService.object, undefined!, undefined!, undefined!, undefined!, new MockContextKeyService(), undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||||
let mockAccountDialog = TypeMoq.Mock.ofInstance(accountDialog);
|
let mockAccountDialog = TypeMoq.Mock.ofInstance(accountDialog);
|
||||||
mockAccountDialog.setup(x => x.onAddAccountErrorEvent)
|
mockAccountDialog.setup(x => x.onAddAccountErrorEvent)
|
||||||
.returns(() => { return addAccountFailureEmitter ? addAccountFailureEmitter.event : mockEvent.event; });
|
.returns(() => { return addAccountFailureEmitter ? addAccountFailureEmitter.event : mockEvent.event; });
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import { VSBuffer } from 'vs/base/common/buffer';
|
|||||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
import { assign } from 'vs/base/common/objects';
|
import { assign } from 'vs/base/common/objects';
|
||||||
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
|
|
||||||
export interface IChartActionContext {
|
export interface IChartActionContext {
|
||||||
options: IInsightOptions;
|
options: IInsightOptions;
|
||||||
@@ -35,7 +37,8 @@ export class CreateInsightAction extends Action {
|
|||||||
constructor(
|
constructor(
|
||||||
@IEditorService private editorService: IEditorService,
|
@IEditorService private editorService: IEditorService,
|
||||||
@INotificationService private notificationService: INotificationService,
|
@INotificationService private notificationService: INotificationService,
|
||||||
@IUntitledTextEditorService private untitledEditorService: IUntitledTextEditorService
|
@IUntitledTextEditorService private untitledEditorService: IUntitledTextEditorService,
|
||||||
|
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||||
) {
|
) {
|
||||||
super(CreateInsightAction.ID, CreateInsightAction.LABEL, CreateInsightAction.ICON);
|
super(CreateInsightAction.ID, CreateInsightAction.LABEL, CreateInsightAction.ICON);
|
||||||
}
|
}
|
||||||
@@ -74,7 +77,7 @@ export class CreateInsightAction extends Action {
|
|||||||
|
|
||||||
let input = this.untitledEditorService.create({ mode: 'json', initialValue: JSON.stringify(widgetConfig) });
|
let input = this.untitledEditorService.create({ mode: 'json', initialValue: JSON.stringify(widgetConfig) });
|
||||||
|
|
||||||
return this.editorService.openEditor(input, { pinned: true })
|
return this.editorService.openEditor(this.instantiationService.createInstance(UntitledTextEditorInput, input), { pinned: true })
|
||||||
.then(
|
.then(
|
||||||
() => true,
|
() => true,
|
||||||
error => {
|
error => {
|
||||||
|
|||||||
@@ -22,19 +22,18 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
|||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||||
import { TestEditorService, TestDialogService, TestFileService } from 'vs/workbench/test/browser/workbenchTestServices';
|
import { TestEditorService, TestDialogService, workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||||
import { TestQueryModelService } from 'sql/workbench/services/query/test/common/testQueryModelService';
|
import { TestQueryModelService } from 'sql/workbench/services/query/test/common/testQueryModelService';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel';
|
import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel';
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
|
||||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||||
import { isUndefinedOrNull } from 'vs/base/common/types';
|
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
import { LabelService } from 'vs/workbench/services/label/common/labelService';
|
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||||
|
|
||||||
class TestParsedArgs implements ParsedArgs {
|
class TestParsedArgs implements ParsedArgs {
|
||||||
[arg: string]: any;
|
[arg: string]: any;
|
||||||
@@ -391,9 +390,11 @@ suite('commandLineService tests', () => {
|
|||||||
const querymodelService = TypeMoq.Mock.ofType<IQueryModelService>(TestQueryModelService, TypeMoq.MockBehavior.Strict);
|
const querymodelService = TypeMoq.Mock.ofType<IQueryModelService>(TestQueryModelService, TypeMoq.MockBehavior.Strict);
|
||||||
querymodelService.setup(c => c.onRunQueryStart).returns(() => Event.None);
|
querymodelService.setup(c => c.onRunQueryStart).returns(() => Event.None);
|
||||||
querymodelService.setup(c => c.onRunQueryComplete).returns(() => Event.None);
|
querymodelService.setup(c => c.onRunQueryComplete).returns(() => Event.None);
|
||||||
const instantiationService = new TestInstantiationService();
|
|
||||||
let uri = URI.file(args._[0]);
|
let uri = URI.file(args._[0]);
|
||||||
const untitledEditorInput = new UntitledTextEditorInput(uri, false, undefined, undefined, undefined, instantiationService, undefined, new LabelService(undefined, undefined), undefined, undefined, new TestFileService(), undefined);
|
const workbenchinstantiationService = workbenchInstantiationService();
|
||||||
|
const accessor = workbenchinstantiationService.createInstance(ServiceAccessor);
|
||||||
|
const service = accessor.untitledTextEditorService;
|
||||||
|
const untitledEditorInput = workbenchinstantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: uri }));
|
||||||
const queryInput = new UntitledQueryEditorInput(undefined, untitledEditorInput, undefined, connectionManagementService.object, querymodelService.object, configurationService.object);
|
const queryInput = new UntitledQueryEditorInput(undefined, untitledEditorInput, undefined, connectionManagementService.object, querymodelService.object, configurationService.object);
|
||||||
queryInput.state.connected = true;
|
queryInput.state.connected = true;
|
||||||
const editorService: TypeMoq.Mock<IEditorService> = TypeMoq.Mock.ofType<IEditorService>(TestEditorService, TypeMoq.MockBehavior.Strict);
|
const editorService: TypeMoq.Mock<IEditorService> = TypeMoq.Mock.ofType<IEditorService>(TestEditorService, TypeMoq.MockBehavior.Strict);
|
||||||
@@ -567,3 +568,9 @@ suite('commandLineService tests', () => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
class ServiceAccessor {
|
||||||
|
constructor(
|
||||||
|
@IUntitledTextEditorService public readonly untitledTextEditorService: IUntitledTextEditorService
|
||||||
|
) { }
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
|||||||
import { ITree } from 'vs/base/parts/tree/browser/tree';
|
import { ITree } from 'vs/base/parts/tree/browser/tree';
|
||||||
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||||
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
|
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||||
|
|
||||||
export class ConnectionViewletPanel extends ViewPane {
|
export class ConnectionViewletPanel extends ViewPane {
|
||||||
|
|
||||||
@@ -41,8 +43,10 @@ export class ConnectionViewletPanel extends ViewPane {
|
|||||||
@IObjectExplorerService private readonly objectExplorerService: IObjectExplorerService,
|
@IObjectExplorerService private readonly objectExplorerService: IObjectExplorerService,
|
||||||
@IContextKeyService contextKeyService: IContextKeyService,
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||||
|
@IOpenerService protected openerService: IOpenerService,
|
||||||
|
@IThemeService protected themeService: IThemeService
|
||||||
) {
|
) {
|
||||||
super({ ...(options as IViewPaneOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService);
|
super({ ...(options as IViewPaneOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, opener, themeService);
|
||||||
this._addServerAction = this.instantiationService.createInstance(AddServerAction,
|
this._addServerAction = this.instantiationService.createInstance(AddServerAction,
|
||||||
AddServerAction.ID,
|
AddServerAction.ID,
|
||||||
AddServerAction.LABEL);
|
AddServerAction.LABEL);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { EditorInput, EditorModel, EncodingMode, IEditorInput } from 'vs/workbench/common/editor';
|
import { EditorInput, EncodingMode, IEditorInput } from 'vs/workbench/common/editor';
|
||||||
import { IConnectionManagementService, IConnectableInput, INewConnectionParams } from 'sql/platform/connection/common/connectionManagement';
|
import { IConnectionManagementService, IConnectableInput, INewConnectionParams } from 'sql/platform/connection/common/connectionManagement';
|
||||||
import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel';
|
import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel';
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
@@ -15,6 +15,8 @@ import Severity from 'vs/base/common/severity';
|
|||||||
import { EditDataResultsInput } from 'sql/workbench/contrib/editData/browser/editDataResultsInput';
|
import { EditDataResultsInput } from 'sql/workbench/contrib/editData/browser/editDataResultsInput';
|
||||||
import { IEditorViewState } from 'vs/editor/common/editorCommon';
|
import { IEditorViewState } from 'vs/editor/common/editorCommon';
|
||||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
|
import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||||
|
import { IUntitledTextEditorModel, UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Input for the EditDataEditor.
|
* Input for the EditDataEditor.
|
||||||
@@ -61,7 +63,7 @@ export class EditDataInput extends EditorInput implements IConnectableInput {
|
|||||||
// also set dirty status to false to prevent rerendering.
|
// also set dirty status to false to prevent rerendering.
|
||||||
if (this._sql) {
|
if (this._sql) {
|
||||||
this._register(this._sql.onDidChangeDirty(async () => {
|
this._register(this._sql.onDidChangeDirty(async () => {
|
||||||
const model = await this._sql.resolve();
|
const model = await this._sql.resolve() as UntitledTextEditorModel;
|
||||||
model.setDirty(false);
|
model.setDirty(false);
|
||||||
this._onDidChangeDirty.fire();
|
this._onDidChangeDirty.fire();
|
||||||
}));
|
}));
|
||||||
@@ -222,11 +224,10 @@ export class EditDataInput extends EditorInput implements IConnectableInput {
|
|||||||
return this._connectionManagementService.getTabColorForUri(this.uri);
|
return this._connectionManagementService.getTabColorForUri(this.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get onDidModelChangeEncoding(): Event<void> { return this._sql.onDidModelChangeEncoding; }
|
public resolve(refresh?: boolean): Promise<IUntitledTextEditorModel & IResolvedTextEditorModel> { return this._sql.resolve(); }
|
||||||
public resolve(refresh?: boolean): Promise<EditorModel> { return this._sql.resolve(); }
|
|
||||||
public getEncoding(): string { return this._sql.getEncoding(); }
|
public getEncoding(): string { return this._sql.getEncoding(); }
|
||||||
public getName(): string { return this._sql.getName(); }
|
public getName(): string { return this._sql.getName(); }
|
||||||
public get hasAssociatedFilePath(): boolean { return this._sql.hasAssociatedFilePath; }
|
public get hasAssociatedFilePath(): boolean { return this._sql.model.hasAssociatedFilePath; }
|
||||||
|
|
||||||
public setEncoding(encoding: string, mode: EncodingMode /* ignored, we only have Encode */): void {
|
public setEncoding(encoding: string, mode: EncodingMode /* ignored, we only have Encode */): void {
|
||||||
this._sql.setEncoding(encoding, mode);
|
this._sql.setEncoding(encoding, mode);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/u
|
|||||||
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||||
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { NotebookServiceStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
import { NotebookServiceStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
||||||
|
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||||
|
|
||||||
const languageAssociations = Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations);
|
const languageAssociations = Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations);
|
||||||
|
|
||||||
@@ -122,7 +123,10 @@ suite('Editor Replacer Contribution', () => {
|
|||||||
const instantiationService = workbenchInstantiationService();
|
const instantiationService = workbenchInstantiationService();
|
||||||
instantiationService.stub(IEditorService, editorService);
|
instantiationService.stub(IEditorService, editorService);
|
||||||
const contrib = instantiationService.createInstance(EditorReplacementContribution);
|
const contrib = instantiationService.createInstance(EditorReplacementContribution);
|
||||||
const input = instantiationService.createInstance(UntitledTextEditorInput, URI.file('/test/file'), false, undefined, undefined, undefined);
|
const accessor = instantiationService.createInstance(ServiceAccessor);
|
||||||
|
const service = accessor.untitledTextEditorService;
|
||||||
|
|
||||||
|
const input = instantiationService.createInstance(UntitledTextEditorInput, service.create());
|
||||||
const response = editorService.fireOpenEditor(input, undefined, undefined as IEditorGroup);
|
const response = editorService.fireOpenEditor(input, undefined, undefined as IEditorGroup);
|
||||||
assert(response?.override);
|
assert(response?.override);
|
||||||
const newinput = <any>(await response.override) as EditorInput; // our test service returns this so we are fine to cast this
|
const newinput = <any>(await response.override) as EditorInput; // our test service returns this so we are fine to cast this
|
||||||
@@ -137,7 +141,9 @@ suite('Editor Replacer Contribution', () => {
|
|||||||
const instantiationService = workbenchInstantiationService();
|
const instantiationService = workbenchInstantiationService();
|
||||||
instantiationService.stub(IEditorService, editorService);
|
instantiationService.stub(IEditorService, editorService);
|
||||||
const contrib = instantiationService.createInstance(EditorReplacementContribution);
|
const contrib = instantiationService.createInstance(EditorReplacementContribution);
|
||||||
const untitled = instantiationService.createInstance(UntitledTextEditorInput, URI.file('/test/file'), false, undefined, undefined, undefined);
|
const accessor = instantiationService.createInstance(ServiceAccessor);
|
||||||
|
const service = accessor.untitledTextEditorService;
|
||||||
|
const untitled = instantiationService.createInstance(UntitledTextEditorInput, service.create());
|
||||||
const input = instantiationService.createInstance(UntitledQueryEditorInput, '', untitled, undefined);
|
const input = instantiationService.createInstance(UntitledQueryEditorInput, '', untitled, undefined);
|
||||||
const response = editorService.fireOpenEditor(input, undefined, undefined as IEditorGroup);
|
const response = editorService.fireOpenEditor(input, undefined, undefined as IEditorGroup);
|
||||||
assert(response === undefined);
|
assert(response === undefined);
|
||||||
@@ -150,7 +156,9 @@ suite('Editor Replacer Contribution', () => {
|
|||||||
const instantiationService = workbenchInstantiationService();
|
const instantiationService = workbenchInstantiationService();
|
||||||
instantiationService.stub(IEditorService, editorService);
|
instantiationService.stub(IEditorService, editorService);
|
||||||
const contrib = instantiationService.createInstance(EditorReplacementContribution);
|
const contrib = instantiationService.createInstance(EditorReplacementContribution);
|
||||||
const input = instantiationService.createInstance(UntitledTextEditorInput, URI.file('/test/file.unknown'), false, undefined, undefined, undefined);
|
const accessor = instantiationService.createInstance(ServiceAccessor);
|
||||||
|
const service = accessor.untitledTextEditorService;
|
||||||
|
const input = instantiationService.createInstance(UntitledTextEditorInput, service.create());
|
||||||
const response = editorService.fireOpenEditor(input, undefined, undefined as IEditorGroup);
|
const response = editorService.fireOpenEditor(input, undefined, undefined as IEditorGroup);
|
||||||
assert(response === undefined);
|
assert(response === undefined);
|
||||||
|
|
||||||
@@ -254,3 +262,9 @@ class TestModeService implements IModeService {
|
|||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ServiceAccessor {
|
||||||
|
constructor(
|
||||||
|
@IUntitledTextEditorService public readonly untitledTextEditorService: IUntitledTextEditorService
|
||||||
|
) { }
|
||||||
|
}
|
||||||
|
|||||||
@@ -210,11 +210,12 @@ export class CodeComponent extends CellView implements OnInit, OnChanges {
|
|||||||
let uri = this.cellModel.cellUri;
|
let uri = this.cellModel.cellUri;
|
||||||
let cellModelSource: string;
|
let cellModelSource: string;
|
||||||
cellModelSource = Array.isArray(this.cellModel.source) ? this.cellModel.source.join('') : this.cellModel.source;
|
cellModelSource = Array.isArray(this.cellModel.source) ? this.cellModel.source.join('') : this.cellModel.source;
|
||||||
this._editorInput = this._instantiationService.createInstance(UntitledTextEditorInput, uri, false, this.cellModel.language, cellModelSource, '');
|
const model = this._instantiationService.createInstance(UntitledTextEditorModel, uri, false, cellModelSource, this.cellModel.language, undefined);
|
||||||
|
this._editorInput = this._instantiationService.createInstance(UntitledTextEditorInput, model);
|
||||||
await this._editor.setInput(this._editorInput, undefined);
|
await this._editor.setInput(this._editorInput, undefined);
|
||||||
this.setFocusAndScroll();
|
this.setFocusAndScroll();
|
||||||
|
|
||||||
let untitledEditorModel: UntitledTextEditorModel = await this._editorInput.resolve();
|
let untitledEditorModel = await this._editorInput.resolve() as UntitledTextEditorModel;
|
||||||
this._editorModel = untitledEditorModel.textEditorModel;
|
this._editorModel = untitledEditorModel.textEditorModel;
|
||||||
|
|
||||||
let isActive = this.cellModel.id === this._activeCellId;
|
let isActive = this.cellModel.id === this._activeCellId;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
|||||||
import { INotebookModel, IContentManager, NotebookContentChange } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
|
import { INotebookModel, IContentManager, NotebookContentChange } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
|
||||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { ITextFileSaveOptions } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileSaveOptions, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager';
|
import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager';
|
||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
@@ -26,7 +26,7 @@ import { Deferred } from 'sql/base/common/promise';
|
|||||||
import { NotebookTextFileModel } from 'sql/workbench/contrib/notebook/browser/models/notebookTextFileModel';
|
import { NotebookTextFileModel } from 'sql/workbench/contrib/notebook/browser/models/notebookTextFileModel';
|
||||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
|
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||||
import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel';
|
import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel';
|
||||||
import { UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
import { UntitledTextEditorModel, IUntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
||||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
|
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
|
||||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||||
@@ -42,7 +42,7 @@ export class NotebookEditorModel extends EditorModel {
|
|||||||
private readonly _onDidChangeDirty: Emitter<void> = this._register(new Emitter<void>());
|
private readonly _onDidChangeDirty: Emitter<void> = this._register(new Emitter<void>());
|
||||||
private _lastEditFullReplacement: boolean;
|
private _lastEditFullReplacement: boolean;
|
||||||
constructor(public readonly notebookUri: URI,
|
constructor(public readonly notebookUri: URI,
|
||||||
private textEditorModel: TextFileEditorModel | UntitledTextEditorModel | ResourceEditorModel,
|
private textEditorModel: ITextFileEditorModel | IUntitledTextEditorModel | ResourceEditorModel,
|
||||||
@INotebookService private notebookService: INotebookService,
|
@INotebookService private notebookService: INotebookService,
|
||||||
@ITextResourcePropertiesService private textResourcePropertiesService: ITextResourcePropertiesService
|
@ITextResourcePropertiesService private textResourcePropertiesService: ITextResourcePropertiesService
|
||||||
) {
|
) {
|
||||||
@@ -198,7 +198,7 @@ export abstract class NotebookInput extends EditorInput {
|
|||||||
private _parentContainer: HTMLElement;
|
private _parentContainer: HTMLElement;
|
||||||
private readonly _layoutChanged: Emitter<void> = this._register(new Emitter<void>());
|
private readonly _layoutChanged: Emitter<void> = this._register(new Emitter<void>());
|
||||||
private _model: NotebookEditorModel;
|
private _model: NotebookEditorModel;
|
||||||
private _untitledEditorModel: UntitledTextEditorModel;
|
private _untitledEditorModel: IUntitledTextEditorModel;
|
||||||
private _contentManager: IContentManager;
|
private _contentManager: IContentManager;
|
||||||
private _providersLoaded: Promise<void>;
|
private _providersLoaded: Promise<void>;
|
||||||
private _dirtyListener: IDisposable;
|
private _dirtyListener: IDisposable;
|
||||||
@@ -328,11 +328,11 @@ export abstract class NotebookInput extends EditorInput {
|
|||||||
return this.resource;
|
return this.resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get untitledEditorModel(): UntitledTextEditorModel {
|
public get untitledEditorModel(): IUntitledTextEditorModel {
|
||||||
return this._untitledEditorModel;
|
return this._untitledEditorModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public set untitledEditorModel(value: UntitledTextEditorModel) {
|
public set untitledEditorModel(value: IUntitledTextEditorModel) {
|
||||||
this._untitledEditorModel = value;
|
this._untitledEditorModel = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,7 +346,7 @@ export abstract class NotebookInput extends EditorInput {
|
|||||||
if (this._model) {
|
if (this._model) {
|
||||||
return Promise.resolve(this._model);
|
return Promise.resolve(this._model);
|
||||||
} else {
|
} else {
|
||||||
let textOrUntitledEditorModel: TextFileEditorModel | UntitledTextEditorModel | ResourceEditorModel;
|
let textOrUntitledEditorModel: ITextFileEditorModel | IUntitledTextEditorModel | ResourceEditorModel;
|
||||||
if (this.resource.scheme === Schemas.untitled) {
|
if (this.resource.scheme === Schemas.untitled) {
|
||||||
if (this._untitledEditorModel) {
|
if (this._untitledEditorModel) {
|
||||||
this._untitledEditorModel.textEditorModel.onBeforeAttached();
|
this._untitledEditorModel.textEditorModel.onBeforeAttached();
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import { Range, IRange } from 'vs/editor/common/core/range';
|
|||||||
import { FindMatch } from 'vs/editor/common/model';
|
import { FindMatch } from 'vs/editor/common/model';
|
||||||
import { NotebookContentChange, INotebookModel } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
|
import { NotebookContentChange, INotebookModel } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
|
||||||
import { NotebookChangeType } from 'sql/workbench/services/notebook/common/contracts';
|
import { NotebookChangeType } from 'sql/workbench/services/notebook/common/contracts';
|
||||||
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
|
|
||||||
import { repeat } from 'vs/base/common/strings';
|
import { repeat } from 'vs/base/common/strings';
|
||||||
|
import { ITextEditorModel } from 'vs/workbench/common/editor';
|
||||||
|
|
||||||
export class NotebookTextFileModel {
|
export class NotebookTextFileModel {
|
||||||
// save active cell's line/column in editor model for the beginning of the source property
|
// save active cell's line/column in editor model for the beginning of the source property
|
||||||
@@ -33,7 +33,7 @@ export class NotebookTextFileModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public transformAndApplyEditForSourceUpdate(contentChange: NotebookContentChange, textEditorModel: BaseTextEditorModel): boolean {
|
public transformAndApplyEditForSourceUpdate(contentChange: NotebookContentChange, textEditorModel: ITextEditorModel): boolean {
|
||||||
let cellGuidRange = this.getCellNodeByGuid(textEditorModel, contentChange.cells[0].cellGuid);
|
let cellGuidRange = this.getCellNodeByGuid(textEditorModel, contentChange.cells[0].cellGuid);
|
||||||
|
|
||||||
// convert the range to leverage offsets in the json
|
// convert the range to leverage offsets in the json
|
||||||
@@ -109,7 +109,7 @@ export class NotebookTextFileModel {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public transformAndApplyEditForOutputUpdate(contentChange: NotebookContentChange, textEditorModel: BaseTextEditorModel): boolean {
|
public transformAndApplyEditForOutputUpdate(contentChange: NotebookContentChange, textEditorModel: ITextEditorModel): boolean {
|
||||||
if (Array.isArray(contentChange.cells[0].outputs) && contentChange.cells[0].outputs.length > 0) {
|
if (Array.isArray(contentChange.cells[0].outputs) && contentChange.cells[0].outputs.length > 0) {
|
||||||
let newOutput = JSON.stringify(contentChange.cells[0].outputs[contentChange.cells[0].outputs.length - 1], undefined, ' ');
|
let newOutput = JSON.stringify(contentChange.cells[0].outputs[contentChange.cells[0].outputs.length - 1], undefined, ' ');
|
||||||
if (contentChange.cells[0].outputs.length > 1) {
|
if (contentChange.cells[0].outputs.length > 1) {
|
||||||
@@ -136,7 +136,7 @@ export class NotebookTextFileModel {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public transformAndApplyEditForCellUpdated(contentChange: NotebookContentChange, textEditorModel: BaseTextEditorModel): boolean {
|
public transformAndApplyEditForCellUpdated(contentChange: NotebookContentChange, textEditorModel: ITextEditorModel): boolean {
|
||||||
let executionCountMatch = this.getExecutionCountRange(textEditorModel, contentChange.cells[0].cellGuid);
|
let executionCountMatch = this.getExecutionCountRange(textEditorModel, contentChange.cells[0].cellGuid);
|
||||||
if (executionCountMatch && executionCountMatch.range) {
|
if (executionCountMatch && executionCountMatch.range) {
|
||||||
// Execution count can be between 0 and n characters long
|
// Execution count can be between 0 and n characters long
|
||||||
@@ -161,7 +161,7 @@ export class NotebookTextFileModel {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public transformAndApplyEditForClearOutput(contentChange: NotebookContentChange, textEditorModel: BaseTextEditorModel): boolean {
|
public transformAndApplyEditForClearOutput(contentChange: NotebookContentChange, textEditorModel: ITextEditorModel): boolean {
|
||||||
if (!textEditorModel || !contentChange || !contentChange.cells || !contentChange.cells[0] || !contentChange.cells[0].cellGuid) {
|
if (!textEditorModel || !contentChange || !contentChange.cells || !contentChange.cells[0] || !contentChange.cells[0].cellGuid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@ export class NotebookTextFileModel {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public replaceEntireTextEditorModel(notebookModel: INotebookModel, type: NotebookChangeType, textEditorModel: BaseTextEditorModel) {
|
public replaceEntireTextEditorModel(notebookModel: INotebookModel, type: NotebookChangeType, textEditorModel: ITextEditorModel) {
|
||||||
let content = JSON.stringify(notebookModel.toJSON(type), undefined, ' ');
|
let content = JSON.stringify(notebookModel.toJSON(type), undefined, ' ');
|
||||||
let model = textEditorModel.textEditorModel;
|
let model = textEditorModel.textEditorModel;
|
||||||
let endLine = model.getLineCount();
|
let endLine = model.getLineCount();
|
||||||
@@ -190,7 +190,7 @@ export class NotebookTextFileModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the beginning of a cell's source in the text editor model
|
// Find the beginning of a cell's source in the text editor model
|
||||||
private updateSourceBeginRange(textEditorModel: BaseTextEditorModel, cellGuid: string): void {
|
private updateSourceBeginRange(textEditorModel: ITextEditorModel, cellGuid: string): void {
|
||||||
if (!cellGuid) {
|
if (!cellGuid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@ export class NotebookTextFileModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the beginning of a cell's outputs in the text editor model
|
// Find the beginning of a cell's outputs in the text editor model
|
||||||
private updateOutputBeginRange(textEditorModel: BaseTextEditorModel, cellGuid: string): void {
|
private updateOutputBeginRange(textEditorModel: ITextEditorModel, cellGuid: string): void {
|
||||||
if (!cellGuid) {
|
if (!cellGuid) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -230,7 +230,7 @@ export class NotebookTextFileModel {
|
|||||||
|
|
||||||
// Find the end of a cell's outputs in the text editor model
|
// Find the end of a cell's outputs in the text editor model
|
||||||
// This will be used as a starting point for any future outputs
|
// This will be used as a starting point for any future outputs
|
||||||
private getEndOfOutputs(textEditorModel: BaseTextEditorModel, cellGuid: string) {
|
private getEndOfOutputs(textEditorModel: ITextEditorModel, cellGuid: string) {
|
||||||
let outputsBegin;
|
let outputsBegin;
|
||||||
if (this._activeCellGuid === cellGuid) {
|
if (this._activeCellGuid === cellGuid) {
|
||||||
outputsBegin = this._outputBeginRange;
|
outputsBegin = this._outputBeginRange;
|
||||||
@@ -272,7 +272,7 @@ export class NotebookTextFileModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine what text needs to be replaced when execution counts are updated
|
// Determine what text needs to be replaced when execution counts are updated
|
||||||
private getExecutionCountRange(textEditorModel: BaseTextEditorModel, cellGuid: string) {
|
private getExecutionCountRange(textEditorModel: ITextEditorModel, cellGuid: string) {
|
||||||
let endOutputRange = this.getEndOfOutputs(textEditorModel, cellGuid);
|
let endOutputRange = this.getEndOfOutputs(textEditorModel, cellGuid);
|
||||||
if (endOutputRange && endOutputRange.endLineNumber) {
|
if (endOutputRange && endOutputRange.endLineNumber) {
|
||||||
return textEditorModel.textEditorModel.findNextMatch('"execution_count": ', { lineNumber: endOutputRange.endLineNumber, column: endOutputRange.endColumn }, false, true, undefined, true);
|
return textEditorModel.textEditorModel.findNextMatch('"execution_count": ', { lineNumber: endOutputRange.endLineNumber, column: endOutputRange.endColumn }, false, true, undefined, true);
|
||||||
@@ -282,14 +282,14 @@ export class NotebookTextFileModel {
|
|||||||
|
|
||||||
// Find a cell's location, given its cellGuid
|
// Find a cell's location, given its cellGuid
|
||||||
// If it doesn't exist (e.g. it's not the active cell), attempt to find it
|
// If it doesn't exist (e.g. it's not the active cell), attempt to find it
|
||||||
private getCellNodeByGuid(textEditorModel: BaseTextEditorModel, guid: string) {
|
private getCellNodeByGuid(textEditorModel: ITextEditorModel, guid: string) {
|
||||||
if (this._activeCellGuid !== guid || !this._sourceBeginRange) {
|
if (this._activeCellGuid !== guid || !this._sourceBeginRange) {
|
||||||
this.updateSourceBeginRange(textEditorModel, guid);
|
this.updateSourceBeginRange(textEditorModel, guid);
|
||||||
}
|
}
|
||||||
return this._sourceBeginRange;
|
return this._sourceBeginRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getOutputNodeByGuid(textEditorModel: BaseTextEditorModel, guid: string) {
|
private getOutputNodeByGuid(textEditorModel: ITextEditorModel, guid: string) {
|
||||||
if (this._activeCellGuid !== guid) {
|
if (this._activeCellGuid !== guid) {
|
||||||
this.updateOutputBeginRange(textEditorModel, guid);
|
this.updateOutputBeginRange(textEditorModel, guid);
|
||||||
}
|
}
|
||||||
@@ -302,7 +302,7 @@ function areRangePropertiesPopulated(range: Range) {
|
|||||||
return range && range.startLineNumber !== 0 && range.startColumn !== 0 && range.endLineNumber !== 0 && range.endColumn !== 0;
|
return range && range.startLineNumber !== 0 && range.startColumn !== 0 && range.endLineNumber !== 0 && range.endColumn !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findOrSetCellGuidMatch(textEditorModel: BaseTextEditorModel, cellGuid: string): FindMatch[] {
|
function findOrSetCellGuidMatch(textEditorModel: ITextEditorModel, cellGuid: string): FindMatch[] {
|
||||||
if (!textEditorModel || !cellGuid) {
|
if (!textEditorModel || !cellGuid) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import * as TypeMoq from 'typemoq';
|
import * as TypeMoq from 'typemoq';
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { nb } from 'azdata';
|
import { nb } from 'azdata';
|
||||||
import { workbenchInstantiationService, TestFileService } from 'vs/workbench/test/browser/workbenchTestServices';
|
import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { UntitledNotebookInput } from 'sql/workbench/contrib/notebook/common/models/untitledNotebookInput';
|
import { UntitledNotebookInput } from 'sql/workbench/contrib/notebook/common/models/untitledNotebookInput';
|
||||||
@@ -19,7 +19,7 @@ import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/u
|
|||||||
import { IExtensionService, NullExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService, NullExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { INotebookService, IProviderInfo } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { INotebookService, IProviderInfo } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
import { LabelService } from 'vs/workbench/services/label/common/labelService';
|
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||||
|
|
||||||
suite('Notebook Input', function (): void {
|
suite('Notebook Input', function (): void {
|
||||||
const instantiationService = workbenchInstantiationService();
|
const instantiationService = workbenchInstantiationService();
|
||||||
@@ -48,7 +48,9 @@ suite('Notebook Input', function (): void {
|
|||||||
let untitledNotebookInput: UntitledNotebookInput;
|
let untitledNotebookInput: UntitledNotebookInput;
|
||||||
|
|
||||||
setup(() => {
|
setup(() => {
|
||||||
untitledTextInput = new UntitledTextEditorInput(untitledUri, false, undefined, undefined, undefined, instantiationService, undefined, new LabelService(undefined, undefined), undefined, undefined, new TestFileService(), undefined);
|
const accessor = instantiationService.createInstance(ServiceAccessor);
|
||||||
|
const service = accessor.untitledTextEditorService;
|
||||||
|
untitledTextInput = instantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: untitledUri }));
|
||||||
untitledNotebookInput = new UntitledNotebookInput(
|
untitledNotebookInput = new UntitledNotebookInput(
|
||||||
testTitle, untitledUri, untitledTextInput,
|
testTitle, untitledUri, untitledTextInput,
|
||||||
undefined, instantiationService, mockNotebookService.object, mockExtensionService.object);
|
undefined, instantiationService, mockNotebookService.object, mockExtensionService.object);
|
||||||
@@ -169,9 +171,17 @@ suite('Notebook Input', function (): void {
|
|||||||
assert.ok(untitledNotebookInput.matches(untitledNotebookInput), 'Input should match itself.');
|
assert.ok(untitledNotebookInput.matches(untitledNotebookInput), 'Input should match itself.');
|
||||||
|
|
||||||
let otherTestUri = URI.from({ scheme: Schemas.untitled, path: 'OtherTestPath' });
|
let otherTestUri = URI.from({ scheme: Schemas.untitled, path: 'OtherTestPath' });
|
||||||
let otherTextInput = new UntitledTextEditorInput(otherTestUri, false, undefined, undefined, undefined, instantiationService, undefined, new LabelService(undefined, undefined), undefined, undefined, new TestFileService(), undefined);
|
const accessor = instantiationService.createInstance(ServiceAccessor);
|
||||||
|
const service = accessor.untitledTextEditorService;
|
||||||
|
let otherTextInput = instantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: otherTestUri }));
|
||||||
let otherInput = instantiationService.createInstance(UntitledNotebookInput, 'OtherTestInput', otherTestUri, otherTextInput);
|
let otherInput = instantiationService.createInstance(UntitledNotebookInput, 'OtherTestInput', otherTestUri, otherTextInput);
|
||||||
|
|
||||||
assert.strictEqual(untitledNotebookInput.matches(otherInput), false, 'Input should not match different input.');
|
assert.strictEqual(untitledNotebookInput.matches(otherInput), false, 'Input should not match different input.');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
class ServiceAccessor {
|
||||||
|
constructor(
|
||||||
|
@IUntitledTextEditorService public readonly untitledTextEditorService: IUntitledTextEditorService
|
||||||
|
) { }
|
||||||
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import { ITextResourcePropertiesService } from 'vs/editor/common/services/textRe
|
|||||||
import { find } from 'vs/base/common/arrays';
|
import { find } from 'vs/base/common/arrays';
|
||||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
import { attachTabbedPanelStyler } from 'sql/workbench/common/styler';
|
import { attachTabbedPanelStyler } from 'sql/workbench/common/styler';
|
||||||
|
import { UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
||||||
|
|
||||||
class BasicView implements IView {
|
class BasicView implements IView {
|
||||||
public get element(): HTMLElement {
|
public get element(): HTMLElement {
|
||||||
@@ -433,7 +434,8 @@ export class ProfilerEditor extends BaseEditor {
|
|||||||
editorContainer.className = 'profiler-editor';
|
editorContainer.className = 'profiler-editor';
|
||||||
this._editor.create(editorContainer);
|
this._editor.create(editorContainer);
|
||||||
this._editor.setVisible(true);
|
this._editor.setVisible(true);
|
||||||
this._editorInput = this._instantiationService.createInstance(UntitledTextEditorInput, URI.from({ scheme: Schemas.untitled }), false, 'sql', '', '');
|
const model = this._instantiationService.createInstance(UntitledTextEditorModel, URI.from({ scheme: Schemas.untitled }), false, undefined, 'sql', undefined);
|
||||||
|
this._editorInput = this._instantiationService.createInstance(UntitledTextEditorInput, model);
|
||||||
this._editor.setInput(this._editorInput, undefined);
|
this._editor.setInput(this._editorInput, undefined);
|
||||||
this._editorInput.resolve().then(model => this._editorModel = model.textEditorModel);
|
this._editorInput.resolve().then(model => this._editorModel = model.textEditorModel);
|
||||||
return editorContainer;
|
return editorContainer;
|
||||||
|
|||||||
@@ -580,8 +580,7 @@ export abstract class GridTableBase<T> extends Disposable implements IView {
|
|||||||
let content = value.displayValue;
|
let content = value.displayValue;
|
||||||
|
|
||||||
const input = this.untitledEditorService.create({ mode: column.isXml ? 'xml' : 'json', initialValue: content });
|
const input = this.untitledEditorService.create({ mode: column.isXml ? 'xml' : 'json', initialValue: content });
|
||||||
const model = await input.resolve();
|
await this.instantiationService.invokeFunction(formatDocumentWithSelectedProvider, input.textEditorModel, FormattingMode.Explicit, CancellationToken.None);
|
||||||
await this.instantiationService.invokeFunction(formatDocumentWithSelectedProvider, model.textEditorModel, FormattingMode.Explicit, CancellationToken.None);
|
|
||||||
return this.editorService.openEditor(input);
|
return this.editorService.openEditor(input);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,12 @@ import { IEncodingSupport, EncodingMode } from 'vs/workbench/common/editor';
|
|||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
import { UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
import { IUntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
||||||
|
|
||||||
export class UntitledQueryEditorInput extends QueryEditorInput implements IEncodingSupport {
|
export class UntitledQueryEditorInput extends QueryEditorInput implements IEncodingSupport {
|
||||||
|
|
||||||
public static readonly ID = 'workbench.editorInput.untitledQueryInput';
|
public static readonly ID = 'workbench.editorInput.untitledQueryInput';
|
||||||
|
|
||||||
public readonly onDidModelChangeEncoding = this.text.onDidModelChangeEncoding;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
description: string,
|
description: string,
|
||||||
text: UntitledTextEditorInput,
|
text: UntitledTextEditorInput,
|
||||||
@@ -31,7 +29,7 @@ export class UntitledQueryEditorInput extends QueryEditorInput implements IEncod
|
|||||||
super(description, text, results, connectionManagementService, queryModelService, configurationService);
|
super(description, text, results, connectionManagementService, queryModelService, configurationService);
|
||||||
}
|
}
|
||||||
|
|
||||||
public resolve(): Promise<UntitledTextEditorModel & IResolvedTextEditorModel> {
|
public resolve(): Promise<IUntitledTextEditorModel & IResolvedTextEditorModel> {
|
||||||
return this.text.resolve();
|
return this.text.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +38,7 @@ export class UntitledQueryEditorInput extends QueryEditorInput implements IEncod
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get hasAssociatedFilePath(): boolean {
|
public get hasAssociatedFilePath(): boolean {
|
||||||
return this.text.hasAssociatedFilePath;
|
return this.text.model.hasAssociatedFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setMode(mode: string): void {
|
public setMode(mode: string): void {
|
||||||
|
|||||||
@@ -23,17 +23,16 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
|||||||
|
|
||||||
import * as TypeMoq from 'typemoq';
|
import * as TypeMoq from 'typemoq';
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { TestStorageService, TestFileService } from 'vs/workbench/test/browser/workbenchTestServices';
|
import { TestStorageService, TestFileService, workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||||
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
||||||
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||||
import { TestQueryModelService } from 'sql/workbench/services/query/test/common/testQueryModelService';
|
import { TestQueryModelService } from 'sql/workbench/services/query/test/common/testQueryModelService';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
|
||||||
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
|
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
|
||||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
import { LabelService } from 'vs/workbench/services/label/common/labelService';
|
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||||
|
|
||||||
suite('SQL QueryAction Tests', () => {
|
suite('SQL QueryAction Tests', () => {
|
||||||
|
|
||||||
@@ -69,8 +68,10 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
queryModelService.setup(q => q.onRunQueryComplete).returns(() => Event.None);
|
queryModelService.setup(q => q.onRunQueryComplete).returns(() => Event.None);
|
||||||
connectionManagementService = TypeMoq.Mock.ofType<TestConnectionManagementService>(TestConnectionManagementService);
|
connectionManagementService = TypeMoq.Mock.ofType<TestConnectionManagementService>(TestConnectionManagementService);
|
||||||
connectionManagementService.setup(q => q.onDisconnect).returns(() => Event.None);
|
connectionManagementService.setup(q => q.onDisconnect).returns(() => Event.None);
|
||||||
const instantiationService = new TestInstantiationService();
|
const workbenchinstantiationService = workbenchInstantiationService();
|
||||||
let fileInput = new UntitledTextEditorInput(URI.parse('file://testUri'), false, undefined, undefined, undefined, instantiationService, undefined, new LabelService(undefined, undefined), undefined, undefined, new TestFileService(), undefined);
|
const accessor = workbenchinstantiationService.createInstance(ServiceAccessor);
|
||||||
|
const service = accessor.untitledTextEditorService;
|
||||||
|
let fileInput = workbenchinstantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: URI.parse('file://testUri') }));
|
||||||
// Setup a reusable mock QueryInput
|
// Setup a reusable mock QueryInput
|
||||||
testQueryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Strict, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
|
testQueryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Strict, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
|
||||||
testQueryInput.setup(x => x.uri).returns(() => testUri);
|
testQueryInput.setup(x => x.uri).returns(() => testUri);
|
||||||
@@ -174,8 +175,10 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
let queryModelService = TypeMoq.Mock.ofType(QueryModelService, TypeMoq.MockBehavior.Loose);
|
let queryModelService = TypeMoq.Mock.ofType(QueryModelService, TypeMoq.MockBehavior.Loose);
|
||||||
queryModelService.setup(x => x.onRunQueryStart).returns(() => Event.None);
|
queryModelService.setup(x => x.onRunQueryStart).returns(() => Event.None);
|
||||||
queryModelService.setup(x => x.onRunQueryComplete).returns(() => Event.None);
|
queryModelService.setup(x => x.onRunQueryComplete).returns(() => Event.None);
|
||||||
const instantiationService = new TestInstantiationService();
|
const workbenchinstantiationService = workbenchInstantiationService();
|
||||||
let fileInput = new UntitledTextEditorInput(URI.parse('file://testUri'), false, undefined, undefined, undefined, instantiationService, undefined, new LabelService(undefined, undefined), undefined, undefined, new TestFileService(), undefined);
|
const accessor = workbenchinstantiationService.createInstance(ServiceAccessor);
|
||||||
|
const service = accessor.untitledTextEditorService;
|
||||||
|
let fileInput = workbenchinstantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: URI.parse('file://testUri') }));
|
||||||
|
|
||||||
// ... Mock "isSelectionEmpty" in QueryEditor
|
// ... Mock "isSelectionEmpty" in QueryEditor
|
||||||
let queryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Strict, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
|
let queryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Strict, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
|
||||||
@@ -223,8 +226,10 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
let predefinedSelection: ISelectionData = { startLine: 1, startColumn: 2, endLine: 3, endColumn: 4 };
|
let predefinedSelection: ISelectionData = { startLine: 1, startColumn: 2, endLine: 3, endColumn: 4 };
|
||||||
|
|
||||||
// ... Mock "getSelection" in QueryEditor
|
// ... Mock "getSelection" in QueryEditor
|
||||||
const instantiationService = new TestInstantiationService();
|
const workbenchinstantiationService = workbenchInstantiationService();
|
||||||
let fileInput = new UntitledTextEditorInput(URI.parse('file://testUri'), false, undefined, undefined, undefined, instantiationService, undefined, new LabelService(undefined, undefined), undefined, undefined, new TestFileService(), undefined);
|
const accessor = workbenchinstantiationService.createInstance(ServiceAccessor);
|
||||||
|
const service = accessor.untitledTextEditorService;
|
||||||
|
let fileInput = workbenchinstantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: URI.parse('file://testUri') }));
|
||||||
|
|
||||||
let queryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Loose, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
|
let queryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Loose, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
|
||||||
queryInput.setup(x => x.uri).returns(() => testUri);
|
queryInput.setup(x => x.uri).returns(() => testUri);
|
||||||
@@ -556,3 +561,9 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
assert.equal(listItem.currentDatabaseName, eventParams.connectionProfile.databaseName);
|
assert.equal(listItem.currentDatabaseName, eventParams.connectionProfile.databaseName);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
class ServiceAccessor {
|
||||||
|
constructor(
|
||||||
|
@IUntitledTextEditorService public readonly untitledTextEditorService: IUntitledTextEditorService
|
||||||
|
) { }
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,15 +17,15 @@ import * as TypeMoq from 'typemoq';
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||||
import { TestFileService, TestStorageService } from 'vs/workbench/test/browser/workbenchTestServices';
|
import { TestStorageService, workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||||
import { TestQueryModelService } from 'sql/workbench/services/query/test/common/testQueryModelService';
|
import { TestQueryModelService } from 'sql/workbench/services/query/test/common/testQueryModelService';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { LabelService } from 'vs/workbench/services/label/common/labelService';
|
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||||
import { TestCapabilitiesService } from 'sql/platform/capabilities/test/common/testCapabilitiesService';
|
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
|
import { TestCapabilitiesService } from 'sql/platform/capabilities/test/common/testCapabilitiesService';
|
||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||||
|
|
||||||
suite('SQL QueryEditor Tests', () => {
|
suite('SQL QueryEditor Tests', () => {
|
||||||
@@ -302,7 +302,10 @@ suite('SQL QueryEditor Tests', () => {
|
|||||||
return new RunQueryAction(undefined, undefined, undefined);
|
return new RunQueryAction(undefined, undefined, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
let fileInput = new UntitledTextEditorInput(URI.parse('file://testUri'), false, undefined, undefined, undefined, instantiationService.object, undefined, new LabelService(undefined, undefined), undefined, undefined, new TestFileService(), undefined);
|
const workbenchinstantiationService = workbenchInstantiationService();
|
||||||
|
const accessor = workbenchinstantiationService.createInstance(ServiceAccessor);
|
||||||
|
const service = accessor.untitledTextEditorService;
|
||||||
|
let fileInput = workbenchinstantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: URI.parse('file://testUri') }));
|
||||||
queryModelService = TypeMoq.Mock.ofType(TestQueryModelService, TypeMoq.MockBehavior.Strict);
|
queryModelService = TypeMoq.Mock.ofType(TestQueryModelService, TypeMoq.MockBehavior.Strict);
|
||||||
queryModelService.setup(x => x.disposeQuery(TypeMoq.It.isAny()));
|
queryModelService.setup(x => x.disposeQuery(TypeMoq.It.isAny()));
|
||||||
queryModelService.setup(x => x.onRunQueryComplete).returns(() => Event.None);
|
queryModelService.setup(x => x.onRunQueryComplete).returns(() => Event.None);
|
||||||
@@ -343,3 +346,9 @@ suite('SQL QueryEditor Tests', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
class ServiceAccessor {
|
||||||
|
constructor(
|
||||||
|
@IUntitledTextEditorService public readonly untitledTextEditorService: IUntitledTextEditorService
|
||||||
|
) { }
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { IConnectionManagementService, IConnectionCompletionOptions, IConnection
|
|||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
|
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||||
|
|
||||||
suite('Query Input Factory', () => {
|
suite('Query Input Factory', () => {
|
||||||
|
|
||||||
@@ -63,13 +64,22 @@ suite('Query Input Factory', () => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
class ServiceAccessor {
|
||||||
|
constructor(
|
||||||
|
@IUntitledTextEditorService public readonly untitledTextEditorService: IUntitledTextEditorService
|
||||||
|
) { }
|
||||||
|
}
|
||||||
|
|
||||||
class MockEditorService extends TestEditorService {
|
class MockEditorService extends TestEditorService {
|
||||||
public readonly activeEditor: IEditorInput | undefined = undefined;
|
public readonly activeEditor: IEditorInput | undefined = undefined;
|
||||||
|
|
||||||
constructor(instantiationService?: IInstantiationService) {
|
constructor(instantiationService?: IInstantiationService) {
|
||||||
super();
|
super();
|
||||||
if (instantiationService) {
|
if (instantiationService) {
|
||||||
const untitledInput = instantiationService.createInstance(UntitledTextEditorInput, URI.file('/test/file'), false, undefined, undefined, undefined);
|
const workbenchinstantiationService = workbenchInstantiationService();
|
||||||
|
const accessor = workbenchinstantiationService.createInstance(ServiceAccessor);
|
||||||
|
const service = accessor.untitledTextEditorService;
|
||||||
|
const untitledInput = instantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: URI.file('/test/file') }));
|
||||||
this.activeEditor = instantiationService.createInstance(UntitledQueryEditorInput, '', untitledInput, undefined);
|
this.activeEditor = instantiationService.createInstance(UntitledQueryEditorInput, '', untitledInput, undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
|||||||
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||||
import { attachPanelStyler, attachModalDialogStyler } from 'sql/workbench/common/styler';
|
import { attachPanelStyler, attachModalDialogStyler } from 'sql/workbench/common/styler';
|
||||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||||
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
|
|
||||||
const labelDisplay = nls.localize("insights.item", "Item");
|
const labelDisplay = nls.localize("insights.item", "Item");
|
||||||
const valueDisplay = nls.localize("insights.value", "Value");
|
const valueDisplay = nls.localize("insights.value", "Value");
|
||||||
@@ -66,9 +67,11 @@ class InsightTableView<T> extends ViewPane {
|
|||||||
@IConfigurationService configurationService: IConfigurationService,
|
@IConfigurationService configurationService: IConfigurationService,
|
||||||
@IContextKeyService contextKeyService: IContextKeyService,
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
@IInstantiationService instantiationService: IInstantiationService,
|
@IInstantiationService instantiationService: IInstantiationService,
|
||||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService
|
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||||
|
@IOpenerService openerService: IOpenerService,
|
||||||
|
@IThemeService themeService: IThemeService,
|
||||||
) {
|
) {
|
||||||
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService);
|
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, opener, themeService);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderBody(container: HTMLElement): void {
|
protected renderBody(container: HTMLElement): void {
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import { replaceConnection } from 'sql/workbench/browser/taskUtilities';
|
|||||||
import { EditDataResultsInput } from 'sql/workbench/contrib/editData/browser/editDataResultsInput';
|
import { EditDataResultsInput } from 'sql/workbench/contrib/editData/browser/editDataResultsInput';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||||
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
|
import { UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service wrapper for opening and creating SQL documents as sql editor inputs
|
* Service wrapper for opening and creating SQL documents as sql editor inputs
|
||||||
@@ -52,8 +54,8 @@ export class QueryEditorService implements IQueryEditorService {
|
|||||||
let docUri: URI = URI.from({ scheme: Schemas.untitled, path: filePath });
|
let docUri: URI = URI.from({ scheme: Schemas.untitled, path: filePath });
|
||||||
|
|
||||||
// Create a sql document pane with accoutrements
|
// Create a sql document pane with accoutrements
|
||||||
const fileInput = this._untitledEditorService.create({ associatedResource: docUri, mode: 'sql' });
|
const fileInput = this._editorService.createInput({ forceUntitled: true, resource: docUri, mode: 'sql' }) as UntitledTextEditorInput;
|
||||||
let untitledEditorModel = await fileInput.resolve();
|
let untitledEditorModel = await fileInput.resolve() as UntitledTextEditorModel;
|
||||||
if (sqlContent) {
|
if (sqlContent) {
|
||||||
untitledEditorModel.textEditorModel.setValue(sqlContent);
|
untitledEditorModel.textEditorModel.setValue(sqlContent);
|
||||||
if (isDirty === false || (isDirty === undefined && !this._configurationService.getValue<boolean>('sql.promptToSaveGeneratedFiles'))) {
|
if (isDirty === false || (isDirty === undefined && !this._configurationService.getValue<boolean>('sql.promptToSaveGeneratedFiles'))) {
|
||||||
@@ -87,8 +89,8 @@ export class QueryEditorService implements IQueryEditorService {
|
|||||||
let docUri: URI = URI.from({ scheme: Schemas.untitled, path: filePath });
|
let docUri: URI = URI.from({ scheme: Schemas.untitled, path: filePath });
|
||||||
|
|
||||||
// Create a sql document pane with accoutrements
|
// Create a sql document pane with accoutrements
|
||||||
const fileInput = this._untitledEditorService.create({ associatedResource: docUri, mode: 'sql' });
|
const fileInput = this._editorService.createInput({ forceUntitled: true, resource: docUri, mode: 'sql' }) as UntitledTextEditorInput;
|
||||||
const m = await fileInput.resolve();
|
const m = await fileInput.resolve() as UntitledTextEditorModel;
|
||||||
//when associatedResource editor is created it is dirty, this must be set to false to be able to detect changes to the editor.
|
//when associatedResource editor is created it is dirty, this must be set to false to be able to detect changes to the editor.
|
||||||
m.setDirty(false);
|
m.setDirty(false);
|
||||||
// Create an EditDataInput for editing
|
// Create an EditDataInput for editing
|
||||||
|
|||||||
44
src/vs/base/browser/linkedText.ts
Normal file
44
src/vs/base/browser/linkedText.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
export interface ILink {
|
||||||
|
readonly label: string;
|
||||||
|
readonly href: string;
|
||||||
|
readonly title?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LinkedTextNode = string | ILink;
|
||||||
|
export type LinkedText = LinkedTextNode[];
|
||||||
|
|
||||||
|
const LINK_REGEX = /\[([^\]]+)\]\(((?:https?:\/\/|command:)[^\)\s]+)(?: "([^"]+)")?\)/gi;
|
||||||
|
|
||||||
|
export function parseLinkedText(text: string): LinkedText {
|
||||||
|
const result: LinkedTextNode[] = [];
|
||||||
|
|
||||||
|
let index = 0;
|
||||||
|
let match: RegExpExecArray | null;
|
||||||
|
|
||||||
|
while (match = LINK_REGEX.exec(text)) {
|
||||||
|
if (match.index - index > 0) {
|
||||||
|
result.push(text.substring(index, match.index));
|
||||||
|
}
|
||||||
|
|
||||||
|
const [, label, href, title] = match;
|
||||||
|
|
||||||
|
if (title) {
|
||||||
|
result.push({ label, href, title });
|
||||||
|
} else {
|
||||||
|
result.push({ label, href });
|
||||||
|
}
|
||||||
|
|
||||||
|
index = match.index + match[0].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < text.length) {
|
||||||
|
result.push(text.substring(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
|||||||
import { Gesture, EventType } from 'vs/base/browser/touch';
|
import { Gesture, EventType } from 'vs/base/browser/touch';
|
||||||
|
|
||||||
export interface IButtonOptions extends IButtonStyles {
|
export interface IButtonOptions extends IButtonStyles {
|
||||||
title?: boolean;
|
title?: boolean | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IButtonStyles {
|
export interface IButtonStyles {
|
||||||
@@ -151,10 +151,10 @@ export class Button extends Disposable {
|
|||||||
DOM.addClass(this._element, 'monaco-text-button');
|
DOM.addClass(this._element, 'monaco-text-button');
|
||||||
}
|
}
|
||||||
this._element.textContent = value;
|
this._element.textContent = value;
|
||||||
//{{SQL CARBON EDIT}}
|
this._element.setAttribute('aria-label', value); // {{SQL CARBON EDIT}}
|
||||||
this._element.setAttribute('aria-label', value);
|
if (typeof this.options.title === 'string') {
|
||||||
//{{END}}
|
this._element.title = this.options.title;
|
||||||
if (this.options.title) {
|
} else if (this.options.title) {
|
||||||
this._element.title = value;
|
this._element.title = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { Event } from 'vs/base/common/event';
|
|||||||
import { IView, IViewSize } from 'vs/base/browser/ui/grid/grid';
|
import { IView, IViewSize } from 'vs/base/browser/ui/grid/grid';
|
||||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
|
import { IBoundarySashes } from 'vs/base/browser/ui/grid/gridview';
|
||||||
|
|
||||||
export interface CenteredViewState {
|
export interface CenteredViewState {
|
||||||
leftMarginRatio: number;
|
leftMarginRatio: number;
|
||||||
@@ -72,6 +73,19 @@ export class CenteredViewLayout implements IDisposable {
|
|||||||
get maximumHeight(): number { return this.view.maximumHeight; }
|
get maximumHeight(): number { return this.view.maximumHeight; }
|
||||||
get onDidChange(): Event<IViewSize | undefined> { return this.view.onDidChange; }
|
get onDidChange(): Event<IViewSize | undefined> { return this.view.onDidChange; }
|
||||||
|
|
||||||
|
private _boundarySashes: IBoundarySashes = {};
|
||||||
|
get boundarySashes(): IBoundarySashes { return this._boundarySashes; }
|
||||||
|
set boundarySashes(boundarySashes: IBoundarySashes) {
|
||||||
|
this._boundarySashes = boundarySashes;
|
||||||
|
|
||||||
|
if (!this.splitView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.splitView.orthogonalStartSash = boundarySashes.top;
|
||||||
|
this.splitView.orthogonalEndSash = boundarySashes.bottom;
|
||||||
|
}
|
||||||
|
|
||||||
layout(width: number, height: number): void {
|
layout(width: number, height: number): void {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
@@ -119,6 +133,8 @@ export class CenteredViewLayout implements IDisposable {
|
|||||||
orientation: Orientation.HORIZONTAL,
|
orientation: Orientation.HORIZONTAL,
|
||||||
styles: this.style
|
styles: this.style
|
||||||
});
|
});
|
||||||
|
this.splitView.orthogonalStartSash = this.boundarySashes.top;
|
||||||
|
this.splitView.orthogonalEndSash = this.boundarySashes.bottom;
|
||||||
|
|
||||||
this.splitViewDisposables.add(this.splitView.onDidSashChange(() => {
|
this.splitViewDisposables.add(this.splitView.onDidSashChange(() => {
|
||||||
if (this.splitView) {
|
if (this.splitView) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "codicon";
|
font-family: "codicon";
|
||||||
src: url("./codicon.ttf?be537a78617db0869caa4b4cc683a24a") format("truetype");
|
src: url("./codicon.ttf?6caeeccc06315e827f3bff83885456fb") format("truetype");
|
||||||
}
|
}
|
||||||
|
|
||||||
.codicon[class*='codicon-'] {
|
.codicon[class*='codicon-'] {
|
||||||
@@ -413,4 +413,5 @@
|
|||||||
.codicon-feedback:before { content: "\eb96" }
|
.codicon-feedback:before { content: "\eb96" }
|
||||||
.codicon-group-by-ref-type:before { content: "\eb97" }
|
.codicon-group-by-ref-type:before { content: "\eb97" }
|
||||||
.codicon-ungroup-by-ref-type:before { content: "\eb98" }
|
.codicon-ungroup-by-ref-type:before { content: "\eb98" }
|
||||||
.codicon-debug-alt:before { content: "\f101" }
|
.codicon-debug-alt-2:before { content: "\f101" }
|
||||||
|
.codicon-debug-alt:before { content: "\f102" }
|
||||||
|
|||||||
Binary file not shown.
@@ -7,7 +7,7 @@ import 'vs/css!./gridview';
|
|||||||
import { Orientation } from 'vs/base/browser/ui/sash/sash';
|
import { Orientation } from 'vs/base/browser/ui/sash/sash';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { tail2 as tail, equals } from 'vs/base/common/arrays';
|
import { tail2 as tail, equals } from 'vs/base/common/arrays';
|
||||||
import { orthogonal, IView as IGridViewView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize, IGridViewOptions } from './gridview';
|
import { orthogonal, IView as IGridViewView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize, IGridViewOptions, IBoundarySashes } from './gridview';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
|
|
||||||
export { Orientation, Sizing as GridViewSizing, IViewSize, orthogonal, LayoutPriority } from './gridview';
|
export { Orientation, Sizing as GridViewSizing, IViewSize, orthogonal, LayoutPriority } from './gridview';
|
||||||
@@ -212,6 +212,9 @@ export class Grid<T extends IView = IView> extends Disposable {
|
|||||||
get maximumHeight(): number { return this.gridview.maximumHeight; }
|
get maximumHeight(): number { return this.gridview.maximumHeight; }
|
||||||
get onDidChange(): Event<{ width: number; height: number; } | undefined> { return this.gridview.onDidChange; }
|
get onDidChange(): Event<{ width: number; height: number; } | undefined> { return this.gridview.onDidChange; }
|
||||||
|
|
||||||
|
get boundarySashes(): IBoundarySashes { return this.gridview.boundarySashes; }
|
||||||
|
set boundarySashes(boundarySashes: IBoundarySashes) { this.gridview.boundarySashes = boundarySashes; }
|
||||||
|
|
||||||
get element(): HTMLElement { return this.gridview.element; }
|
get element(): HTMLElement { return this.gridview.element; }
|
||||||
|
|
||||||
private didLayout = false;
|
private didLayout = false;
|
||||||
|
|||||||
@@ -21,6 +21,20 @@ export interface IViewSize {
|
|||||||
readonly height: number;
|
readonly height: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IRelativeBoundarySashes {
|
||||||
|
readonly start?: Sash;
|
||||||
|
readonly end?: Sash;
|
||||||
|
readonly orthogonalStart?: Sash;
|
||||||
|
readonly orthogonalEnd?: Sash;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBoundarySashes {
|
||||||
|
readonly top?: Sash;
|
||||||
|
readonly right?: Sash;
|
||||||
|
readonly bottom?: Sash;
|
||||||
|
readonly left?: Sash;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IView {
|
export interface IView {
|
||||||
readonly element: HTMLElement;
|
readonly element: HTMLElement;
|
||||||
readonly minimumWidth: number;
|
readonly minimumWidth: number;
|
||||||
@@ -32,6 +46,7 @@ export interface IView {
|
|||||||
readonly snap?: boolean;
|
readonly snap?: boolean;
|
||||||
layout(width: number, height: number, top: number, left: number): void;
|
layout(width: number, height: number, top: number, left: number): void;
|
||||||
setVisible?(visible: boolean): void;
|
setVisible?(visible: boolean): void;
|
||||||
|
setBoundarySashes?(sashes: IBoundarySashes): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISerializableView extends IView {
|
export interface ISerializableView extends IView {
|
||||||
@@ -125,6 +140,22 @@ interface ILayoutContext {
|
|||||||
readonly absoluteOrthogonalSize: number;
|
readonly absoluteOrthogonalSize: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toAbsoluteBoundarySashes(sashes: IRelativeBoundarySashes, orientation: Orientation): IBoundarySashes {
|
||||||
|
if (orientation === Orientation.HORIZONTAL) {
|
||||||
|
return { left: sashes.start, right: sashes.end, top: sashes.orthogonalStart, bottom: sashes.orthogonalEnd };
|
||||||
|
} else {
|
||||||
|
return { top: sashes.start, bottom: sashes.end, left: sashes.orthogonalStart, right: sashes.orthogonalEnd };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromAbsoluteBoundarySashes(sashes: IBoundarySashes, orientation: Orientation): IRelativeBoundarySashes {
|
||||||
|
if (orientation === Orientation.HORIZONTAL) {
|
||||||
|
return { start: sashes.left, end: sashes.right, orthogonalStart: sashes.top, orthogonalEnd: sashes.bottom };
|
||||||
|
} else {
|
||||||
|
return { start: sashes.top, end: sashes.bottom, orthogonalStart: sashes.left, orthogonalEnd: sashes.right };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
|
class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
|
||||||
|
|
||||||
readonly element: HTMLElement;
|
readonly element: HTMLElement;
|
||||||
@@ -217,10 +248,27 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
|
|||||||
private splitviewSashResetDisposable: IDisposable = Disposable.None;
|
private splitviewSashResetDisposable: IDisposable = Disposable.None;
|
||||||
private childrenSashResetDisposable: IDisposable = Disposable.None;
|
private childrenSashResetDisposable: IDisposable = Disposable.None;
|
||||||
|
|
||||||
get orthogonalStartSash(): Sash | undefined { return this.splitview.orthogonalStartSash; }
|
private _boundarySashes: IRelativeBoundarySashes = {};
|
||||||
set orthogonalStartSash(sash: Sash | undefined) { this.splitview.orthogonalStartSash = sash; }
|
get boundarySashes(): IRelativeBoundarySashes { return this._boundarySashes; }
|
||||||
get orthogonalEndSash(): Sash | undefined { return this.splitview.orthogonalEndSash; }
|
set boundarySashes(boundarySashes: IRelativeBoundarySashes) {
|
||||||
set orthogonalEndSash(sash: Sash | undefined) { this.splitview.orthogonalEndSash = sash; }
|
this._boundarySashes = boundarySashes;
|
||||||
|
|
||||||
|
this.splitview.orthogonalStartSash = boundarySashes.orthogonalStart;
|
||||||
|
this.splitview.orthogonalEndSash = boundarySashes.orthogonalEnd;
|
||||||
|
|
||||||
|
for (let index = 0; index < this.children.length; index++) {
|
||||||
|
const child = this.children[index];
|
||||||
|
const first = index === 0;
|
||||||
|
const last = index === this.children.length - 1;
|
||||||
|
|
||||||
|
child.boundarySashes = {
|
||||||
|
start: boundarySashes.orthogonalStart,
|
||||||
|
end: boundarySashes.orthogonalEnd,
|
||||||
|
orthogonalStart: first ? boundarySashes.start : child.boundarySashes.orthogonalStart,
|
||||||
|
orthogonalEnd: last ? boundarySashes.end : child.boundarySashes.orthogonalEnd,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly orientation: Orientation,
|
readonly orientation: Orientation,
|
||||||
@@ -260,9 +308,15 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
|
|||||||
this.splitview = new SplitView(this.element, { ...options, descriptor });
|
this.splitview = new SplitView(this.element, { ...options, descriptor });
|
||||||
|
|
||||||
this.children.forEach((node, index) => {
|
this.children.forEach((node, index) => {
|
||||||
// Set up orthogonal sashes for children
|
const first = index === 0;
|
||||||
node.orthogonalStartSash = this.splitview.sashes[index - 1];
|
const last = index === this.children.length;
|
||||||
node.orthogonalEndSash = this.splitview.sashes[index];
|
|
||||||
|
node.boundarySashes = {
|
||||||
|
start: this.boundarySashes.orthogonalStart,
|
||||||
|
end: this.boundarySashes.orthogonalEnd,
|
||||||
|
orthogonalStart: first ? this.boundarySashes.start : this.splitview.sashes[index - 1],
|
||||||
|
orthogonalEnd: last ? this.boundarySashes.end : this.splitview.sashes[index],
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,15 +389,26 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
|
|||||||
const first = index === 0;
|
const first = index === 0;
|
||||||
const last = index === this.children.length;
|
const last = index === this.children.length;
|
||||||
this.children.splice(index, 0, node);
|
this.children.splice(index, 0, node);
|
||||||
node.orthogonalStartSash = this.splitview.sashes[index - 1];
|
|
||||||
node.orthogonalEndSash = this.splitview.sashes[index];
|
node.boundarySashes = {
|
||||||
|
start: this.boundarySashes.orthogonalStart,
|
||||||
|
end: this.boundarySashes.orthogonalEnd,
|
||||||
|
orthogonalStart: first ? this.boundarySashes.start : this.splitview.sashes[index - 1],
|
||||||
|
orthogonalEnd: last ? this.boundarySashes.end : this.splitview.sashes[index],
|
||||||
|
};
|
||||||
|
|
||||||
if (!first) {
|
if (!first) {
|
||||||
this.children[index - 1].orthogonalEndSash = this.splitview.sashes[index - 1];
|
this.children[index - 1].boundarySashes = {
|
||||||
|
...this.children[index - 1].boundarySashes,
|
||||||
|
orthogonalEnd: this.splitview.sashes[index - 1]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!last) {
|
if (!last) {
|
||||||
this.children[index + 1].orthogonalStartSash = this.splitview.sashes[index];
|
this.children[index + 1].boundarySashes = {
|
||||||
|
...this.children[index + 1].boundarySashes,
|
||||||
|
orthogonalStart: this.splitview.sashes[index]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,11 +428,17 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
|
|||||||
const [child] = this.children.splice(index, 1);
|
const [child] = this.children.splice(index, 1);
|
||||||
|
|
||||||
if (!first) {
|
if (!first) {
|
||||||
this.children[index - 1].orthogonalEndSash = this.splitview.sashes[index - 1];
|
this.children[index - 1].boundarySashes = {
|
||||||
|
...this.children[index - 1].boundarySashes,
|
||||||
|
orthogonalEnd: this.splitview.sashes[index - 1]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!last) { // [0,1,2,3] (2) => [0,1,3]
|
if (!last) { // [0,1,2,3] (2) => [0,1,3]
|
||||||
this.children[index].orthogonalStartSash = this.splitview.sashes[Math.max(index - 1, 0)];
|
this.children[index].boundarySashes = {
|
||||||
|
...this.children[index].boundarySashes,
|
||||||
|
orthogonalStart: this.splitview.sashes[Math.max(index - 1, 0)]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
@@ -408,7 +479,12 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
|
|||||||
to = clamp(to, 0, this.children.length);
|
to = clamp(to, 0, this.children.length);
|
||||||
|
|
||||||
this.splitview.swapViews(from, to);
|
this.splitview.swapViews(from, to);
|
||||||
[this.children[from].orthogonalStartSash, this.children[from].orthogonalEndSash, this.children[to].orthogonalStartSash, this.children[to].orthogonalEndSash] = [this.children[to].orthogonalStartSash, this.children[to].orthogonalEndSash, this.children[from].orthogonalStartSash, this.children[from].orthogonalEndSash];
|
|
||||||
|
// swap boundary sashes
|
||||||
|
[this.children[from].boundarySashes, this.children[to].boundarySashes]
|
||||||
|
= [this.children[from].boundarySashes, this.children[to].boundarySashes];
|
||||||
|
|
||||||
|
// swap children
|
||||||
[this.children[from], this.children[to]] = [this.children[to], this.children[from]];
|
[this.children[from], this.children[to]] = [this.children[to], this.children[from]];
|
||||||
|
|
||||||
this.onDidChildrenChange();
|
this.onDidChildrenChange();
|
||||||
@@ -655,12 +731,14 @@ class LeafNode implements ISplitView<ILayoutContext>, IDisposable {
|
|||||||
return this.orientation === Orientation.HORIZONTAL ? this.maximumWidth : this.maximumHeight;
|
return this.orientation === Orientation.HORIZONTAL ? this.maximumWidth : this.maximumHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
set orthogonalStartSash(sash: Sash) {
|
private _boundarySashes: IRelativeBoundarySashes = {};
|
||||||
// noop
|
get boundarySashes(): IRelativeBoundarySashes { return this._boundarySashes; }
|
||||||
}
|
set boundarySashes(boundarySashes: IRelativeBoundarySashes) {
|
||||||
|
this._boundarySashes = boundarySashes;
|
||||||
|
|
||||||
set orthogonalEndSash(sash: Sash) {
|
if (this.view.setBoundarySashes) {
|
||||||
// noop
|
this.view.setBoundarySashes(toAbsoluteBoundarySashes(boundarySashes, this.orientation));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
layout(size: number, offset: number, ctx: ILayoutContext | undefined): void {
|
layout(size: number, offset: number, ctx: ILayoutContext | undefined): void {
|
||||||
@@ -764,6 +842,7 @@ export class GridView implements IDisposable {
|
|||||||
const { size, orthogonalSize } = this._root;
|
const { size, orthogonalSize } = this._root;
|
||||||
this.root = flipNode(this._root, orthogonalSize, size);
|
this.root = flipNode(this._root, orthogonalSize, size);
|
||||||
this.root.layout(size, 0, { orthogonalSize, absoluteOffset: 0, absoluteOrthogonalOffset: 0, absoluteSize: size, absoluteOrthogonalSize: orthogonalSize });
|
this.root.layout(size, 0, { orthogonalSize, absoluteOffset: 0, absoluteOrthogonalOffset: 0, absoluteSize: size, absoluteOrthogonalSize: orthogonalSize });
|
||||||
|
this.boundarySashes = this.boundarySashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
get width(): number { return this.root.width; }
|
get width(): number { return this.root.width; }
|
||||||
@@ -777,6 +856,13 @@ export class GridView implements IDisposable {
|
|||||||
private _onDidChange = new Relay<IViewSize | undefined>();
|
private _onDidChange = new Relay<IViewSize | undefined>();
|
||||||
readonly onDidChange = this._onDidChange.event;
|
readonly onDidChange = this._onDidChange.event;
|
||||||
|
|
||||||
|
private _boundarySashes: IBoundarySashes = {};
|
||||||
|
get boundarySashes(): IBoundarySashes { return this._boundarySashes; }
|
||||||
|
set boundarySashes(boundarySashes: IBoundarySashes) {
|
||||||
|
this._boundarySashes = boundarySashes;
|
||||||
|
this.root.boundarySashes = fromAbsoluteBoundarySashes(boundarySashes, this.orientation);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The first layout controller makes sure layout only propagates
|
* The first layout controller makes sure layout only propagates
|
||||||
* to the views after the very first call to gridview.layout()
|
* to the views after the very first call to gridview.layout()
|
||||||
@@ -898,6 +984,7 @@ export class GridView implements IDisposable {
|
|||||||
// we must promote sibling to be the new root
|
// we must promote sibling to be the new root
|
||||||
parent.removeChild(0);
|
parent.removeChild(0);
|
||||||
this.root = sibling;
|
this.root = sibling;
|
||||||
|
this.boundarySashes = this.boundarySashes;
|
||||||
return node.view;
|
return node.view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,14 +128,14 @@ class AsyncDataTreeRenderer<TInput, T, TFilterData, TTemplateData> implements IT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function asTreeEvent<TInput, T>(e: ITreeEvent<IAsyncDataTreeNode<TInput, T>>): ITreeEvent<T> {
|
function asTreeEvent<TInput, T>(e: ITreeEvent<IAsyncDataTreeNode<TInput, T> | null>): ITreeEvent<T> {
|
||||||
return {
|
return {
|
||||||
browserEvent: e.browserEvent,
|
browserEvent: e.browserEvent,
|
||||||
elements: e.elements.map(e => e.element as T)
|
elements: e.elements.map(e => e!.element as T)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function asTreeMouseEvent<TInput, T>(e: ITreeMouseEvent<IAsyncDataTreeNode<TInput, T>>): ITreeMouseEvent<T> {
|
function asTreeMouseEvent<TInput, T>(e: ITreeMouseEvent<IAsyncDataTreeNode<TInput, T> | null>): ITreeMouseEvent<T> {
|
||||||
return {
|
return {
|
||||||
browserEvent: e.browserEvent,
|
browserEvent: e.browserEvent,
|
||||||
element: e.element && e.element.element as T,
|
element: e.element && e.element.element as T,
|
||||||
@@ -143,7 +143,7 @@ function asTreeMouseEvent<TInput, T>(e: ITreeMouseEvent<IAsyncDataTreeNode<TInpu
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function asTreeContextMenuEvent<TInput, T>(e: ITreeContextMenuEvent<IAsyncDataTreeNode<TInput, T>>): ITreeContextMenuEvent<T> {
|
function asTreeContextMenuEvent<TInput, T>(e: ITreeContextMenuEvent<IAsyncDataTreeNode<TInput, T> | null>): ITreeContextMenuEvent<T> {
|
||||||
return {
|
return {
|
||||||
browserEvent: e.browserEvent,
|
browserEvent: e.browserEvent,
|
||||||
element: e.element && e.element.element as T,
|
element: e.element && e.element.element as T,
|
||||||
@@ -793,7 +793,11 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
|
|||||||
return result.finally(() => this.refreshPromises.delete(node));
|
return result.finally(() => this.refreshPromises.delete(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onDidChangeCollapseState({ node, deep }: ICollapseStateChangeEvent<IAsyncDataTreeNode<TInput, T>, any>): void {
|
private _onDidChangeCollapseState({ node, deep }: ICollapseStateChangeEvent<IAsyncDataTreeNode<TInput, T> | null, any>): void {
|
||||||
|
if (node.element === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!node.collapsed && node.element.stale) {
|
if (!node.collapsed && node.element.stale) {
|
||||||
if (deep) {
|
if (deep) {
|
||||||
this.collapse(node.element.element as T);
|
this.collapse(node.element.element as T);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export class DataTree<TInput, T, TFilterData = void> extends AbstractTree<T | nu
|
|||||||
private dataSource: IDataSource<TInput, T>,
|
private dataSource: IDataSource<TInput, T>,
|
||||||
options: IDataTreeOptions<T, TFilterData> = {}
|
options: IDataTreeOptions<T, TFilterData> = {}
|
||||||
) {
|
) {
|
||||||
super(user, container, delegate, renderers, options);
|
super(user, container, delegate, renderers, options as IDataTreeOptions<T | null, TFilterData>);
|
||||||
this.identityProvider = options.identityProvider;
|
this.identityProvider = options.identityProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ export class DataTree<TInput, T, TFilterData = void> extends AbstractTree<T | nu
|
|||||||
throw new TreeError(this.user, 'Can\'t get tree view state without an identity provider');
|
throw new TreeError(this.user, 'Can\'t get tree view state without an identity provider');
|
||||||
}
|
}
|
||||||
|
|
||||||
const getId = (element: T) => this.identityProvider!.getId(element).toString();
|
const getId = (element: T | null) => this.identityProvider!.getId(element!).toString();
|
||||||
const focus = this.getFocus().map(getId);
|
const focus = this.getFocus().map(getId);
|
||||||
const selection = this.getSelection().map(getId);
|
const selection = this.getSelection().map(getId);
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export class ObjectTree<T extends NonNullable<any>, TFilterData = void> extends
|
|||||||
renderers: ITreeRenderer<T, TFilterData, any>[],
|
renderers: ITreeRenderer<T, TFilterData, any>[],
|
||||||
options: IObjectTreeOptions<T, TFilterData> = {}
|
options: IObjectTreeOptions<T, TFilterData> = {}
|
||||||
) {
|
) {
|
||||||
super(user, container, delegate, renderers, options);
|
super(user, container, delegate, renderers, options as IObjectTreeOptions<T | null, TFilterData>);
|
||||||
}
|
}
|
||||||
|
|
||||||
setChildren(element: T | null, children?: ISequence<ITreeElement<T>>): void {
|
setChildren(element: T | null, children?: ISequence<ITreeElement<T>>): void {
|
||||||
@@ -181,7 +181,7 @@ export class CompressibleObjectTree<T extends NonNullable<any>, TFilterData = vo
|
|||||||
) {
|
) {
|
||||||
const compressedTreeNodeProvider = () => this;
|
const compressedTreeNodeProvider = () => this;
|
||||||
const compressibleRenderers = renderers.map(r => new CompressibleRenderer<T, TFilterData, any>(compressedTreeNodeProvider, r));
|
const compressibleRenderers = renderers.map(r => new CompressibleRenderer<T, TFilterData, any>(compressedTreeNodeProvider, r));
|
||||||
super(user, container, delegate, compressibleRenderers, asObjectTreeOptions(compressedTreeNodeProvider, options));
|
super(user, container, delegate, compressibleRenderers, asObjectTreeOptions<T, TFilterData>(compressedTreeNodeProvider, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
setChildren(element: T | null, children?: ISequence<ICompressedTreeElement<T>>): void {
|
setChildren(element: T | null, children?: ISequence<ICompressedTreeElement<T>>): void {
|
||||||
|
|||||||
@@ -79,35 +79,47 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
|||||||
const insertedElements = new Set<T | null>();
|
const insertedElements = new Set<T | null>();
|
||||||
const insertedElementIds = new Set<string>();
|
const insertedElementIds = new Set<string>();
|
||||||
|
|
||||||
const _onDidCreateNode = (node: ITreeNode<T, TFilterData>) => {
|
const _onDidCreateNode = (node: ITreeNode<T | null, TFilterData>) => {
|
||||||
insertedElements.add(node.element);
|
if (node.element === null) {
|
||||||
this.nodes.set(node.element, node);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tnode = node as ITreeNode<T, TFilterData>;
|
||||||
|
|
||||||
|
insertedElements.add(tnode.element);
|
||||||
|
this.nodes.set(tnode.element, tnode);
|
||||||
|
|
||||||
if (this.identityProvider) {
|
if (this.identityProvider) {
|
||||||
const id = this.identityProvider.getId(node.element).toString();
|
const id = this.identityProvider.getId(tnode.element).toString();
|
||||||
insertedElementIds.add(id);
|
insertedElementIds.add(id);
|
||||||
this.nodesByIdentity.set(id, node);
|
this.nodesByIdentity.set(id, tnode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onDidCreateNode) {
|
if (onDidCreateNode) {
|
||||||
onDidCreateNode(node);
|
onDidCreateNode(tnode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const _onDidDeleteNode = (node: ITreeNode<T, TFilterData>) => {
|
const _onDidDeleteNode = (node: ITreeNode<T | null, TFilterData>) => {
|
||||||
if (!insertedElements.has(node.element)) {
|
if (node.element === null) {
|
||||||
this.nodes.delete(node.element);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tnode = node as ITreeNode<T, TFilterData>;
|
||||||
|
|
||||||
|
if (!insertedElements.has(tnode.element)) {
|
||||||
|
this.nodes.delete(tnode.element);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.identityProvider) {
|
if (this.identityProvider) {
|
||||||
const id = this.identityProvider.getId(node.element).toString();
|
const id = this.identityProvider.getId(tnode.element).toString();
|
||||||
if (!insertedElementIds.has(id)) {
|
if (!insertedElementIds.has(id)) {
|
||||||
this.nodesByIdentity.delete(id);
|
this.nodesByIdentity.delete(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onDidDeleteNode) {
|
if (onDidDeleteNode) {
|
||||||
onDidDeleteNode(node);
|
onDidDeleteNode(tnode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,18 +7,27 @@ import { Emitter, Event } from 'vs/base/common/event';
|
|||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
export interface CancellationToken {
|
export interface CancellationToken {
|
||||||
readonly isCancellationRequested: boolean;
|
|
||||||
/**
|
/**
|
||||||
* An event emitted when cancellation is requested
|
* A flag signalling is cancellation has been requested.
|
||||||
|
*/
|
||||||
|
readonly isCancellationRequested: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event which fires when cancellation is requested. This event
|
||||||
|
* only ever fires `once` as cancellation can only happen once. Listeners
|
||||||
|
* that are registered after cancellation will be called (next event loop run),
|
||||||
|
* but also only once.
|
||||||
|
*
|
||||||
* @event
|
* @event
|
||||||
*/
|
*/
|
||||||
readonly onCancellationRequested: Event<any>;
|
readonly onCancellationRequested: (listener: (e: any) => any, thisArgs?: any, disposables?: IDisposable[]) => IDisposable;
|
||||||
}
|
}
|
||||||
|
|
||||||
const shortcutEvent = Object.freeze(function (callback, context?): IDisposable {
|
const shortcutEvent: Event<any> = Object.freeze(function (callback, context?): IDisposable {
|
||||||
const handle = setTimeout(callback.bind(context), 0);
|
const handle = setTimeout(callback.bind(context), 0);
|
||||||
return { dispose() { clearTimeout(handle); } };
|
return { dispose() { clearTimeout(handle); } };
|
||||||
} as Event<any>);
|
});
|
||||||
|
|
||||||
export namespace CancellationToken {
|
export namespace CancellationToken {
|
||||||
|
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ export namespace Event {
|
|||||||
* Given a collection of events, returns a single event which emits
|
* Given a collection of events, returns a single event which emits
|
||||||
* whenever any of the provided events emit.
|
* whenever any of the provided events emit.
|
||||||
*/
|
*/
|
||||||
|
export function any<T>(...events: Event<T>[]): Event<T>;
|
||||||
|
export function any(...events: Event<any>[]): Event<void>;
|
||||||
export function any<T>(...events: Event<T>[]): Event<T> {
|
export function any<T>(...events: Event<T>[]): Event<T> {
|
||||||
return (listener, thisArgs = null, disposables?) => combinedDisposable(...events.map(event => event(e => listener.call(thisArgs, e), null, disposables)));
|
return (listener, thisArgs = null, disposables?) => combinedDisposable(...events.map(event => event(e => listener.call(thisArgs, e), null, disposables)));
|
||||||
}
|
}
|
||||||
@@ -271,6 +273,7 @@ export namespace Event {
|
|||||||
map<O>(fn: (i: T) => O): IChainableEvent<O>;
|
map<O>(fn: (i: T) => O): IChainableEvent<O>;
|
||||||
forEach(fn: (i: T) => void): IChainableEvent<T>;
|
forEach(fn: (i: T) => void): IChainableEvent<T>;
|
||||||
filter(fn: (e: T) => boolean): IChainableEvent<T>;
|
filter(fn: (e: T) => boolean): IChainableEvent<T>;
|
||||||
|
filter<R>(fn: (e: T | R) => e is R): IChainableEvent<R>;
|
||||||
reduce<R>(merge: (last: R | undefined, event: T) => R, initial?: R): IChainableEvent<R>;
|
reduce<R>(merge: (last: R | undefined, event: T) => R, initial?: R): IChainableEvent<R>;
|
||||||
latch(): IChainableEvent<T>;
|
latch(): IChainableEvent<T>;
|
||||||
debounce(merge: (last: T | undefined, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent<T>;
|
debounce(merge: (last: T | undefined, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent<T>;
|
||||||
@@ -291,6 +294,8 @@ export namespace Event {
|
|||||||
return new ChainableEvent(forEach(this.event, fn));
|
return new ChainableEvent(forEach(this.event, fn));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filter(fn: (e: T) => boolean): IChainableEvent<T>;
|
||||||
|
filter<R>(fn: (e: T | R) => e is R): IChainableEvent<R>;
|
||||||
filter(fn: (e: T) => boolean): IChainableEvent<T> {
|
filter(fn: (e: T) => boolean): IChainableEvent<T> {
|
||||||
return new ChainableEvent(filter(this.event, fn));
|
return new ChainableEvent(filter(this.event, fn));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,189 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import { dirname } from 'vs/base/common/path';
|
|
||||||
import * as objects from 'vs/base/common/objects';
|
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
|
||||||
import * as json from 'vs/base/common/json';
|
|
||||||
import { statLink } from 'vs/base/node/pfs';
|
|
||||||
import { realpath } from 'vs/base/node/extpath';
|
|
||||||
import { watchFolder, watchFile } from 'vs/base/node/watcher';
|
|
||||||
|
|
||||||
export interface IConfigurationChangeEvent<T> {
|
|
||||||
config: T;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IConfigWatcher<T> {
|
|
||||||
path: string;
|
|
||||||
hasParseErrors: boolean;
|
|
||||||
|
|
||||||
reload(callback: (config: T) => void): void;
|
|
||||||
getConfig(): T;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IConfigOptions<T> {
|
|
||||||
onError: (error: Error | string) => void;
|
|
||||||
defaultConfig: T;
|
|
||||||
changeBufferDelay?: number;
|
|
||||||
parse?: (content: string, errors: any[]) => T;
|
|
||||||
initCallback?: (config: T) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple helper to watch a configured file for changes and process its contents as JSON object.
|
|
||||||
* Supports:
|
|
||||||
* - comments in JSON files and errors
|
|
||||||
* - symlinks for the config file itself
|
|
||||||
* - delayed processing of changes to accomodate for lots of changes
|
|
||||||
* - configurable defaults
|
|
||||||
*/
|
|
||||||
export class ConfigWatcher<T> extends Disposable implements IConfigWatcher<T> {
|
|
||||||
private cache: T | undefined;
|
|
||||||
private parseErrors: json.ParseError[] | undefined;
|
|
||||||
private disposed: boolean | undefined;
|
|
||||||
private loaded: boolean | undefined;
|
|
||||||
private timeoutHandle: NodeJS.Timer | null | undefined;
|
|
||||||
private readonly _onDidUpdateConfiguration: Emitter<IConfigurationChangeEvent<T>>;
|
|
||||||
|
|
||||||
constructor(private _path: string, private options: IConfigOptions<T> = { defaultConfig: Object.create(null), onError: error => console.error(error) }) {
|
|
||||||
super();
|
|
||||||
this._onDidUpdateConfiguration = this._register(new Emitter<IConfigurationChangeEvent<T>>());
|
|
||||||
|
|
||||||
this.registerWatcher();
|
|
||||||
this.initAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
get path(): string {
|
|
||||||
return this._path;
|
|
||||||
}
|
|
||||||
|
|
||||||
get hasParseErrors(): boolean {
|
|
||||||
return !!this.parseErrors && this.parseErrors.length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
get onDidUpdateConfiguration(): Event<IConfigurationChangeEvent<T>> {
|
|
||||||
return this._onDidUpdateConfiguration.event;
|
|
||||||
}
|
|
||||||
|
|
||||||
private initAsync(): void {
|
|
||||||
this.loadAsync(config => {
|
|
||||||
if (!this.loaded) {
|
|
||||||
this.updateCache(config); // prevent race condition if config was loaded sync already
|
|
||||||
}
|
|
||||||
if (this.options.initCallback) {
|
|
||||||
this.options.initCallback(this.getConfig());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private updateCache(value: T): void {
|
|
||||||
this.cache = value;
|
|
||||||
this.loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private loadSync(): T {
|
|
||||||
try {
|
|
||||||
return this.parse(fs.readFileSync(this._path).toString());
|
|
||||||
} catch (error) {
|
|
||||||
return this.options.defaultConfig;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private loadAsync(callback: (config: T) => void): void {
|
|
||||||
fs.readFile(this._path, (error, raw) => {
|
|
||||||
if (error) {
|
|
||||||
return callback(this.options.defaultConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
return callback(this.parse(raw.toString()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private parse(raw: string): T {
|
|
||||||
let res: T;
|
|
||||||
try {
|
|
||||||
this.parseErrors = [];
|
|
||||||
res = this.options.parse ? this.options.parse(raw, this.parseErrors) : json.parse(raw, this.parseErrors);
|
|
||||||
|
|
||||||
return res || this.options.defaultConfig;
|
|
||||||
} catch (error) {
|
|
||||||
return this.options.defaultConfig; // Ignore parsing errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private registerWatcher(): void {
|
|
||||||
|
|
||||||
// Watch the parent of the path so that we detect ADD and DELETES
|
|
||||||
const parentFolder = dirname(this._path);
|
|
||||||
this.watch(parentFolder, true);
|
|
||||||
|
|
||||||
// Check if the path is a symlink and watch its target if so
|
|
||||||
this.handleSymbolicLink().then(undefined, () => { /* ignore error */ });
|
|
||||||
}
|
|
||||||
|
|
||||||
private async handleSymbolicLink(): Promise<void> {
|
|
||||||
const { stat, symbolicLink } = await statLink(this._path);
|
|
||||||
if (symbolicLink && !stat.isDirectory()) {
|
|
||||||
const realPath = await realpath(this._path);
|
|
||||||
|
|
||||||
this.watch(realPath, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private watch(path: string, isFolder: boolean): void {
|
|
||||||
if (this.disposed) {
|
|
||||||
return; // avoid watchers that will never get disposed by checking for being disposed
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isFolder) {
|
|
||||||
this._register(watchFolder(path, (type, path) => path === this._path ? this.onConfigFileChange() : undefined, error => this.options.onError(error)));
|
|
||||||
} else {
|
|
||||||
this._register(watchFile(path, () => this.onConfigFileChange(), error => this.options.onError(error)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private onConfigFileChange(): void {
|
|
||||||
if (this.timeoutHandle) {
|
|
||||||
global.clearTimeout(this.timeoutHandle);
|
|
||||||
this.timeoutHandle = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we can get multiple change events for one change, so we buffer through a timeout
|
|
||||||
this.timeoutHandle = global.setTimeout(() => this.reload(), this.options.changeBufferDelay || 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
reload(callback?: (config: T) => void): void {
|
|
||||||
this.loadAsync(currentConfig => {
|
|
||||||
if (!objects.equals(currentConfig, this.cache)) {
|
|
||||||
this.updateCache(currentConfig);
|
|
||||||
|
|
||||||
this._onDidUpdateConfiguration.fire({ config: currentConfig });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callback) {
|
|
||||||
return callback(currentConfig);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getConfig(): T {
|
|
||||||
this.ensureLoaded();
|
|
||||||
|
|
||||||
return this.cache!;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ensureLoaded(): void {
|
|
||||||
if (!this.loaded) {
|
|
||||||
this.updateCache(this.loadSync());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose(): void {
|
|
||||||
this.disposed = true;
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -52,7 +52,7 @@ export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions
|
|||||||
private bufferedChunks: Buffer[] = [];
|
private bufferedChunks: Buffer[] = [];
|
||||||
private bytesBuffered = 0;
|
private bytesBuffered = 0;
|
||||||
|
|
||||||
_write(chunk: Buffer, encoding: string, callback: (error: Error | null) => void): void {
|
_write(chunk: Buffer, encoding: string, callback: (error: Error | null | undefined) => void): void {
|
||||||
if (!Buffer.isBuffer(chunk)) {
|
if (!Buffer.isBuffer(chunk)) {
|
||||||
return callback(new Error('toDecodeStream(): data must be a buffer'));
|
return callback(new Error('toDecodeStream(): data must be a buffer'));
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_startDecodeStream(callback: (error: Error | null) => void): void {
|
_startDecodeStream(callback: (error: Error | null | undefined) => void): void {
|
||||||
|
|
||||||
// detect encoding from buffer
|
// detect encoding from buffer
|
||||||
this.decodeStreamPromise = Promise.resolve(detectEncodingFromBuffer({
|
this.decodeStreamPromise = Promise.resolve(detectEncodingFromBuffer({
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { mkdirp, rimraf } from 'vs/base/node/pfs';
|
|||||||
import { open as _openZip, Entry, ZipFile } from 'yauzl';
|
import { open as _openZip, Entry, ZipFile } from 'yauzl';
|
||||||
import * as yazl from 'yazl';
|
import * as yazl from 'yazl';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { Event } from 'vs/base/common/event';
|
|
||||||
|
|
||||||
export interface IExtractOptions {
|
export interface IExtractOptions {
|
||||||
overwrite?: boolean;
|
overwrite?: boolean;
|
||||||
@@ -80,7 +79,7 @@ function extractEntry(stream: Readable, fileName: string, mode: number, targetPa
|
|||||||
|
|
||||||
let istream: WriteStream;
|
let istream: WriteStream;
|
||||||
|
|
||||||
Event.once(token.onCancellationRequested)(() => {
|
token.onCancellationRequested(() => {
|
||||||
if (istream) {
|
if (istream) {
|
||||||
istream.destroy();
|
istream.destroy();
|
||||||
}
|
}
|
||||||
@@ -107,7 +106,7 @@ function extractZip(zipfile: ZipFile, targetPath: string, options: IOptions, tok
|
|||||||
let last = createCancelablePromise<void>(() => Promise.resolve());
|
let last = createCancelablePromise<void>(() => Promise.resolve());
|
||||||
let extractedEntriesCount = 0;
|
let extractedEntriesCount = 0;
|
||||||
|
|
||||||
Event.once(token.onCancellationRequested)(() => {
|
token.onCancellationRequested(() => {
|
||||||
last.cancel();
|
last.cancel();
|
||||||
zipfile.close();
|
zipfile.close();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -141,8 +141,8 @@ export class ItemRegistry {
|
|||||||
readonly onDidCollapseItem: Event<IItemCollapseEvent> = this._onDidCollapseItem.event;
|
readonly onDidCollapseItem: Event<IItemCollapseEvent> = this._onDidCollapseItem.event;
|
||||||
private _onDidAddTraitItem = new EventMultiplexer<IItemTraitEvent>();
|
private _onDidAddTraitItem = new EventMultiplexer<IItemTraitEvent>();
|
||||||
readonly onDidAddTraitItem: Event<IItemTraitEvent> = this._onDidAddTraitItem.event;
|
readonly onDidAddTraitItem: Event<IItemTraitEvent> = this._onDidAddTraitItem.event;
|
||||||
private _onDidRemoveTraitItem = new EventMultiplexer<IItemCollapseEvent>();
|
private _onDidRemoveTraitItem = new EventMultiplexer<IItemTraitEvent>();
|
||||||
readonly onDidRemoveTraitItem: Event<IItemCollapseEvent> = this._onDidRemoveTraitItem.event;
|
readonly onDidRemoveTraitItem: Event<IItemTraitEvent> = this._onDidRemoveTraitItem.event;
|
||||||
private _onDidRefreshItem = new EventMultiplexer<Item>();
|
private _onDidRefreshItem = new EventMultiplexer<Item>();
|
||||||
readonly onDidRefreshItem: Event<Item> = this._onDidRefreshItem.event;
|
readonly onDidRefreshItem: Event<Item> = this._onDidRefreshItem.event;
|
||||||
private _onRefreshItemChildren = new EventMultiplexer<IItemChildrenRefreshEvent>();
|
private _onRefreshItemChildren = new EventMultiplexer<IItemChildrenRefreshEvent>();
|
||||||
@@ -273,8 +273,8 @@ export class Item {
|
|||||||
readonly onDidCollapse: Event<IItemCollapseEvent> = this._onDidCollapse.event;
|
readonly onDidCollapse: Event<IItemCollapseEvent> = this._onDidCollapse.event;
|
||||||
private readonly _onDidAddTrait = new Emitter<IItemTraitEvent>();
|
private readonly _onDidAddTrait = new Emitter<IItemTraitEvent>();
|
||||||
readonly onDidAddTrait: Event<IItemTraitEvent> = this._onDidAddTrait.event;
|
readonly onDidAddTrait: Event<IItemTraitEvent> = this._onDidAddTrait.event;
|
||||||
private readonly _onDidRemoveTrait = new Emitter<IItemCollapseEvent>();
|
private readonly _onDidRemoveTrait = new Emitter<IItemTraitEvent>();
|
||||||
readonly onDidRemoveTrait: Event<IItemCollapseEvent> = this._onDidRemoveTrait.event;
|
readonly onDidRemoveTrait: Event<IItemTraitEvent> = this._onDidRemoveTrait.event;
|
||||||
private readonly _onDidRefresh = new Emitter<Item>();
|
private readonly _onDidRefresh = new Emitter<Item>();
|
||||||
readonly onDidRefresh: Event<Item> = this._onDidRefresh.event;
|
readonly onDidRefresh: Event<Item> = this._onDidRefresh.event;
|
||||||
private readonly _onRefreshChildren = new Emitter<IItemChildrenRefreshEvent>();
|
private readonly _onRefreshChildren = new Emitter<IItemChildrenRefreshEvent>();
|
||||||
@@ -895,8 +895,8 @@ export class TreeModel {
|
|||||||
readonly onDidCollapseItem: Event<IItemCollapseEvent> = this._onDidCollapseItem.event;
|
readonly onDidCollapseItem: Event<IItemCollapseEvent> = this._onDidCollapseItem.event;
|
||||||
private _onDidAddTraitItem = new Relay<IItemTraitEvent>();
|
private _onDidAddTraitItem = new Relay<IItemTraitEvent>();
|
||||||
readonly onDidAddTraitItem: Event<IItemTraitEvent> = this._onDidAddTraitItem.event;
|
readonly onDidAddTraitItem: Event<IItemTraitEvent> = this._onDidAddTraitItem.event;
|
||||||
private _onDidRemoveTraitItem = new Relay<IItemCollapseEvent>();
|
private _onDidRemoveTraitItem = new Relay<IItemTraitEvent>();
|
||||||
readonly onDidRemoveTraitItem: Event<IItemCollapseEvent> = this._onDidRemoveTraitItem.event;
|
readonly onDidRemoveTraitItem: Event<IItemTraitEvent> = this._onDidRemoveTraitItem.event;
|
||||||
private _onDidRefreshItem = new Relay<Item>();
|
private _onDidRefreshItem = new Relay<Item>();
|
||||||
readonly onDidRefreshItem: Event<Item> = this._onDidRefreshItem.event;
|
readonly onDidRefreshItem: Event<Item> = this._onDidRefreshItem.event;
|
||||||
private _onRefreshItemChildren = new Relay<IItemChildrenRefreshEvent>();
|
private _onRefreshItemChildren = new Relay<IItemChildrenRefreshEvent>();
|
||||||
|
|||||||
@@ -557,7 +557,7 @@ export class TreeView extends HeightMap {
|
|||||||
this.viewListeners.push(DOM.addDisposableListener(this.wrapper, 'MSGestureTap', (e) => this.onMsGestureTap(e)));
|
this.viewListeners.push(DOM.addDisposableListener(this.wrapper, 'MSGestureTap', (e) => this.onMsGestureTap(e)));
|
||||||
|
|
||||||
// these events come too fast, we throttle them
|
// these events come too fast, we throttle them
|
||||||
this.viewListeners.push(DOM.addDisposableThrottledListener<IThrottledGestureEvent>(this.wrapper, 'MSGestureChange', (e) => this.onThrottledMsGestureChange(e), (lastEvent: IThrottledGestureEvent, event: MSGestureEvent): IThrottledGestureEvent => {
|
this.viewListeners.push(DOM.addDisposableThrottledListener<IThrottledGestureEvent, MSGestureEvent>(this.wrapper, 'MSGestureChange', e => this.onThrottledMsGestureChange(e), (lastEvent, event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
|||||||
58
src/vs/base/test/browser/linkedText.test.ts
Normal file
58
src/vs/base/test/browser/linkedText.test.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as assert from 'assert';
|
||||||
|
import { parseLinkedText } from 'vs/base/browser/linkedText';
|
||||||
|
|
||||||
|
suite('LinkedText', () => {
|
||||||
|
test('parses correctly', () => {
|
||||||
|
assert.deepEqual(parseLinkedText(''), []);
|
||||||
|
assert.deepEqual(parseLinkedText('hello'), ['hello']);
|
||||||
|
assert.deepEqual(parseLinkedText('hello there'), ['hello there']);
|
||||||
|
assert.deepEqual(parseLinkedText('Some message with [link text](http://link.href).'), [
|
||||||
|
'Some message with ',
|
||||||
|
{ label: 'link text', href: 'http://link.href' },
|
||||||
|
'.'
|
||||||
|
]);
|
||||||
|
assert.deepEqual(parseLinkedText('Some message with [link text](http://link.href "and a title").'), [
|
||||||
|
'Some message with ',
|
||||||
|
{ label: 'link text', href: 'http://link.href', title: 'and a title' },
|
||||||
|
'.'
|
||||||
|
]);
|
||||||
|
assert.deepEqual(parseLinkedText('Some message with [link text](random stuff).'), [
|
||||||
|
'Some message with [link text](random stuff).'
|
||||||
|
]);
|
||||||
|
assert.deepEqual(parseLinkedText('Some message with [https link](https://link.href).'), [
|
||||||
|
'Some message with ',
|
||||||
|
{ label: 'https link', href: 'https://link.href' },
|
||||||
|
'.'
|
||||||
|
]);
|
||||||
|
assert.deepEqual(parseLinkedText('Some message with [https link](https:).'), [
|
||||||
|
'Some message with [https link](https:).'
|
||||||
|
]);
|
||||||
|
assert.deepEqual(parseLinkedText('Some message with [a command](command:foobar).'), [
|
||||||
|
'Some message with ',
|
||||||
|
{ label: 'a command', href: 'command:foobar' },
|
||||||
|
'.'
|
||||||
|
]);
|
||||||
|
assert.deepEqual(parseLinkedText('Some message with [a command](command:).'), [
|
||||||
|
'Some message with [a command](command:).'
|
||||||
|
]);
|
||||||
|
assert.deepEqual(parseLinkedText('link [one](command:foo "nice") and link [two](http://foo)...'), [
|
||||||
|
'link ',
|
||||||
|
{ label: 'one', href: 'command:foo', title: 'nice' },
|
||||||
|
' and link ',
|
||||||
|
{ label: 'two', href: 'http://foo' },
|
||||||
|
'...'
|
||||||
|
]);
|
||||||
|
assert.deepEqual(parseLinkedText('link\n[one](command:foo "nice")\nand link [two](http://foo)...'), [
|
||||||
|
'link\n',
|
||||||
|
{ label: 'one', href: 'command:foo', title: 'nice' },
|
||||||
|
'\nand link ',
|
||||||
|
{ label: 'two', href: 'http://foo' },
|
||||||
|
'...'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -108,6 +108,7 @@ suite('Resources', () => {
|
|||||||
assert.equal(joinPath(URI.file('/foo/bar'), '/./file.js').toString(), 'file:///foo/bar/file.js');
|
assert.equal(joinPath(URI.file('/foo/bar'), '/./file.js').toString(), 'file:///foo/bar/file.js');
|
||||||
assert.equal(joinPath(URI.file('/foo/bar'), '../file.js').toString(), 'file:///foo/file.js');
|
assert.equal(joinPath(URI.file('/foo/bar'), '../file.js').toString(), 'file:///foo/file.js');
|
||||||
}
|
}
|
||||||
|
assert.equal(joinPath(URI.parse('foo://a/foo/bar')).toString(), 'foo://a/foo/bar');
|
||||||
assert.equal(joinPath(URI.parse('foo://a/foo/bar'), '/file.js').toString(), 'foo://a/foo/bar/file.js');
|
assert.equal(joinPath(URI.parse('foo://a/foo/bar'), '/file.js').toString(), 'foo://a/foo/bar/file.js');
|
||||||
assert.equal(joinPath(URI.parse('foo://a/foo/bar'), 'file.js').toString(), 'foo://a/foo/bar/file.js');
|
assert.equal(joinPath(URI.parse('foo://a/foo/bar'), 'file.js').toString(), 'foo://a/foo/bar/file.js');
|
||||||
assert.equal(joinPath(URI.parse('foo://a/foo/bar/'), '/file.js').toString(), 'foo://a/foo/bar/file.js');
|
assert.equal(joinPath(URI.parse('foo://a/foo/bar/'), '/file.js').toString(), 'foo://a/foo/bar/file.js');
|
||||||
|
|||||||
@@ -1,163 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import * as assert from 'assert';
|
|
||||||
import * as os from 'os';
|
|
||||||
|
|
||||||
import * as path from 'vs/base/common/path';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as uuid from 'vs/base/common/uuid';
|
|
||||||
import { ConfigWatcher } from 'vs/base/node/config';
|
|
||||||
import { testFile } from 'vs/base/test/node/utils';
|
|
||||||
|
|
||||||
suite('Config', () => {
|
|
||||||
|
|
||||||
test('defaults', () => {
|
|
||||||
const id = uuid.generateUuid();
|
|
||||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
|
||||||
const newDir = path.join(parentDir, 'config', id);
|
|
||||||
const testFile = path.join(newDir, 'config.json');
|
|
||||||
|
|
||||||
let watcher = new ConfigWatcher<{}>(testFile);
|
|
||||||
|
|
||||||
let config = watcher.getConfig();
|
|
||||||
assert.ok(config);
|
|
||||||
assert.equal(Object.keys(config), 0);
|
|
||||||
|
|
||||||
watcher.dispose();
|
|
||||||
|
|
||||||
let watcher2 = new ConfigWatcher<any[]>(testFile, { defaultConfig: ['foo'], onError: console.error });
|
|
||||||
|
|
||||||
let config2 = watcher2.getConfig();
|
|
||||||
assert.ok(Array.isArray(config2));
|
|
||||||
assert.equal(config2.length, 1);
|
|
||||||
|
|
||||||
watcher.dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('getConfig / getValue', function () {
|
|
||||||
return testFile('config', 'config.json').then(res => {
|
|
||||||
fs.writeFileSync(res.testFile, '// my comment\n{ "foo": "bar" }');
|
|
||||||
|
|
||||||
let watcher = new ConfigWatcher<{ foo: string; }>(res.testFile);
|
|
||||||
|
|
||||||
let config = watcher.getConfig();
|
|
||||||
assert.ok(config);
|
|
||||||
assert.equal(config.foo, 'bar');
|
|
||||||
assert.ok(!watcher.hasParseErrors);
|
|
||||||
|
|
||||||
watcher.dispose();
|
|
||||||
|
|
||||||
return res.cleanUp();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('getConfig / getValue - broken JSON', function () {
|
|
||||||
return testFile('config', 'config.json').then(res => {
|
|
||||||
fs.writeFileSync(res.testFile, '// my comment\n "foo": "bar ... ');
|
|
||||||
|
|
||||||
let watcher = new ConfigWatcher<{ foo: string; }>(res.testFile);
|
|
||||||
|
|
||||||
let config = watcher.getConfig();
|
|
||||||
assert.ok(config);
|
|
||||||
assert.ok(!config.foo);
|
|
||||||
|
|
||||||
assert.ok(watcher.hasParseErrors);
|
|
||||||
|
|
||||||
watcher.dispose();
|
|
||||||
|
|
||||||
return res.cleanUp();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// test('watching', function (done) {
|
|
||||||
// this.timeout(10000); // watching is timing intense
|
|
||||||
|
|
||||||
// testFile('config', 'config.json').then(res => {
|
|
||||||
// fs.writeFileSync(res.testFile, '// my comment\n{ "foo": "bar" }');
|
|
||||||
|
|
||||||
// let watcher = new ConfigWatcher<{ foo: string; }>(res.testFile);
|
|
||||||
// watcher.getConfig(); // ensure we are in sync
|
|
||||||
|
|
||||||
// fs.writeFileSync(res.testFile, '// my comment\n{ "foo": "changed" }');
|
|
||||||
|
|
||||||
// watcher.onDidUpdateConfiguration(event => {
|
|
||||||
// assert.ok(event);
|
|
||||||
// assert.equal(event.config.foo, 'changed');
|
|
||||||
// assert.equal(watcher.getValue('foo'), 'changed');
|
|
||||||
|
|
||||||
// watcher.dispose();
|
|
||||||
|
|
||||||
// res.cleanUp().then(done, done);
|
|
||||||
// });
|
|
||||||
// }, done);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// test('watching also works when file created later', function (done) {
|
|
||||||
// this.timeout(10000); // watching is timing intense
|
|
||||||
|
|
||||||
// testFile('config', 'config.json').then(res => {
|
|
||||||
// let watcher = new ConfigWatcher<{ foo: string; }>(res.testFile);
|
|
||||||
// watcher.getConfig(); // ensure we are in sync
|
|
||||||
|
|
||||||
// fs.writeFileSync(res.testFile, '// my comment\n{ "foo": "changed" }');
|
|
||||||
|
|
||||||
// watcher.onDidUpdateConfiguration(event => {
|
|
||||||
// assert.ok(event);
|
|
||||||
// assert.equal(event.config.foo, 'changed');
|
|
||||||
// assert.equal(watcher.getValue('foo'), 'changed');
|
|
||||||
|
|
||||||
// watcher.dispose();
|
|
||||||
|
|
||||||
// res.cleanUp().then(done, done);
|
|
||||||
// });
|
|
||||||
// }, done);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// test('watching detects the config file getting deleted', function (done) {
|
|
||||||
// this.timeout(10000); // watching is timing intense
|
|
||||||
|
|
||||||
// testFile('config', 'config.json').then(res => {
|
|
||||||
// fs.writeFileSync(res.testFile, '// my comment\n{ "foo": "bar" }');
|
|
||||||
|
|
||||||
// let watcher = new ConfigWatcher<{ foo: string; }>(res.testFile);
|
|
||||||
// watcher.getConfig(); // ensure we are in sync
|
|
||||||
|
|
||||||
// watcher.onDidUpdateConfiguration(event => {
|
|
||||||
// assert.ok(event);
|
|
||||||
|
|
||||||
// watcher.dispose();
|
|
||||||
|
|
||||||
// res.cleanUp().then(done, done);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// fs.unlinkSync(res.testFile);
|
|
||||||
// }, done);
|
|
||||||
// });
|
|
||||||
|
|
||||||
test('reload', function (done) {
|
|
||||||
testFile('config', 'config.json').then(res => {
|
|
||||||
fs.writeFileSync(res.testFile, '// my comment\n{ "foo": "bar" }');
|
|
||||||
|
|
||||||
let watcher = new ConfigWatcher<{ foo: string; }>(res.testFile, { changeBufferDelay: 100, onError: console.error, defaultConfig: { foo: 'bar' } });
|
|
||||||
watcher.getConfig(); // ensure we are in sync
|
|
||||||
|
|
||||||
fs.writeFileSync(res.testFile, '// my comment\n{ "foo": "changed" }');
|
|
||||||
|
|
||||||
// still old values because change is not bubbling yet
|
|
||||||
assert.equal(watcher.getConfig().foo, 'bar');
|
|
||||||
|
|
||||||
// force a load from disk
|
|
||||||
watcher.reload(config => {
|
|
||||||
assert.equal(config.foo, 'changed');
|
|
||||||
assert.equal(watcher.getConfig().foo, 'changed');
|
|
||||||
|
|
||||||
watcher.dispose();
|
|
||||||
|
|
||||||
res.cleanUp().then(done, done);
|
|
||||||
});
|
|
||||||
}, done);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IWorkbenchConstructionOptions, create, URI, Event, Emitter, UriComponents, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace } from 'vs/workbench/workbench.web.api';
|
import { IWorkbenchConstructionOptions, create, URI, Event, Emitter, UriComponents, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace, IApplicationLinkProvider, IApplicationLink } from 'vs/workbench/workbench.web.api';
|
||||||
import { generateUuid } from 'vs/base/common/uuid';
|
import { generateUuid } from 'vs/base/common/uuid';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { streamToBuffer } from 'vs/base/common/buffer';
|
import { streamToBuffer } from 'vs/base/common/buffer';
|
||||||
@@ -12,6 +12,10 @@ import { request } from 'vs/base/parts/request/browser/request';
|
|||||||
import { isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/windows/common/windows';
|
import { isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/windows/common/windows';
|
||||||
import { isEqual } from 'vs/base/common/resources';
|
import { isEqual } from 'vs/base/common/resources';
|
||||||
import { isStandalone } from 'vs/base/browser/browser';
|
import { isStandalone } from 'vs/base/browser/browser';
|
||||||
|
import product from 'vs/platform/product/common/product';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
import { posix } from 'vs/base/common/path';
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
|
|
||||||
interface ICredential {
|
interface ICredential {
|
||||||
service: string;
|
service: string;
|
||||||
@@ -275,6 +279,39 @@ class WorkspaceProvider implements IWorkspaceProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ApplicationLinkProvider {
|
||||||
|
|
||||||
|
private links: IApplicationLink[] | undefined = undefined;
|
||||||
|
|
||||||
|
constructor(workspace: IWorkspace) {
|
||||||
|
this.computeLink(workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
private computeLink(workspace: IWorkspace): void {
|
||||||
|
if (!workspace) {
|
||||||
|
return; // not for empty workspaces
|
||||||
|
}
|
||||||
|
|
||||||
|
const workspaceUri = isWorkspaceToOpen(workspace) ? workspace.workspaceUri : isFolderToOpen(workspace) ? workspace.folderUri : undefined;
|
||||||
|
if (workspaceUri) {
|
||||||
|
this.links = [{
|
||||||
|
uri: URI.from({
|
||||||
|
scheme: product.quality === 'stable' ? 'vscode' : 'vscode-insiders',
|
||||||
|
authority: Schemas.vscodeRemote,
|
||||||
|
path: posix.join(posix.sep, workspaceUri.authority, workspaceUri.path),
|
||||||
|
query: workspaceUri.query,
|
||||||
|
fragment: workspaceUri.fragment,
|
||||||
|
}),
|
||||||
|
label: localize('openInDesktop', "Open in Desktop")
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get provider(): IApplicationLinkProvider {
|
||||||
|
return () => this.links;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
|
|
||||||
// Find config by checking for DOM
|
// Find config by checking for DOM
|
||||||
@@ -343,6 +380,7 @@ class WorkspaceProvider implements IWorkspaceProvider {
|
|||||||
...config,
|
...config,
|
||||||
workspaceProvider: new WorkspaceProvider(workspace, payload),
|
workspaceProvider: new WorkspaceProvider(workspace, payload),
|
||||||
urlCallbackProvider: new PollingURLCallbackProvider(),
|
urlCallbackProvider: new PollingURLCallbackProvider(),
|
||||||
credentialsProvider: new LocalStorageCredentialsProvider()
|
credentialsProvider: new LocalStorageCredentialsProvider(),
|
||||||
|
applicationLinkProvider: new ApplicationLinkProvider(workspace).provider
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -120,10 +120,20 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
|
|||||||
const mainProcessService = new MainProcessService(server, mainRouter);
|
const mainProcessService = new MainProcessService(server, mainRouter);
|
||||||
services.set(IMainProcessService, mainProcessService);
|
services.set(IMainProcessService, mainProcessService);
|
||||||
|
|
||||||
const configurationService = new ConfigurationService(environmentService.settingsResource);
|
// Files
|
||||||
|
const fileService = new FileService(logService);
|
||||||
|
services.set(IFileService, fileService);
|
||||||
|
disposables.add(fileService);
|
||||||
|
const diskFileSystemProvider = new DiskFileSystemProvider(logService);
|
||||||
|
disposables.add(diskFileSystemProvider);
|
||||||
|
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
const configurationService = new ConfigurationService(environmentService.settingsResource, fileService);
|
||||||
disposables.add(configurationService);
|
disposables.add(configurationService);
|
||||||
await configurationService.initialize();
|
await configurationService.initialize();
|
||||||
|
|
||||||
|
// Storage
|
||||||
const storageService = new NativeStorageService(new GlobalStorageDatabaseChannelClient(mainProcessService.getChannel('storage')), logService, environmentService);
|
const storageService = new NativeStorageService(new GlobalStorageDatabaseChannelClient(mainProcessService.getChannel('storage')), logService, environmentService);
|
||||||
await storageService.initialize();
|
await storageService.initialize();
|
||||||
services.set(IStorageService, storageService);
|
services.set(IStorageService, storageService);
|
||||||
@@ -136,19 +146,9 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
|
|||||||
services.set(IRequestService, new SyncDescriptor(RequestService));
|
services.set(IRequestService, new SyncDescriptor(RequestService));
|
||||||
services.set(ILoggerService, new SyncDescriptor(LoggerService));
|
services.set(ILoggerService, new SyncDescriptor(LoggerService));
|
||||||
|
|
||||||
|
|
||||||
const electronService = createChannelSender<IElectronService>(mainProcessService.getChannel('electron'), { context: configuration.windowId });
|
const electronService = createChannelSender<IElectronService>(mainProcessService.getChannel('electron'), { context: configuration.windowId });
|
||||||
services.set(IElectronService, electronService);
|
services.set(IElectronService, electronService);
|
||||||
|
|
||||||
// Files
|
|
||||||
const fileService = new FileService(logService);
|
|
||||||
services.set(IFileService, fileService);
|
|
||||||
disposables.add(fileService);
|
|
||||||
|
|
||||||
const diskFileSystemProvider = new DiskFileSystemProvider(logService);
|
|
||||||
disposables.add(diskFileSystemProvider);
|
|
||||||
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
|
|
||||||
|
|
||||||
services.set(IDownloadService, new SyncDescriptor(DownloadService));
|
services.set(IDownloadService, new SyncDescriptor(DownloadService));
|
||||||
|
|
||||||
const instantiationService = new InstantiationService(services);
|
const instantiationService = new InstantiationService(services);
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ import { MenubarMainService } from 'vs/platform/menubar/electron-main/menubarMai
|
|||||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||||
import { registerContextMenuListener } from 'vs/base/parts/contextmenu/electron-main/contextmenu';
|
import { registerContextMenuListener } from 'vs/base/parts/contextmenu/electron-main/contextmenu';
|
||||||
import { homedir } from 'os';
|
import { homedir } from 'os';
|
||||||
import { join, sep } from 'vs/base/common/path';
|
import { join, sep, posix } from 'vs/base/common/path';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { SnapUpdateService } from 'vs/platform/update/electron-main/updateService.snap';
|
import { SnapUpdateService } from 'vs/platform/update/electron-main/updateService.snap';
|
||||||
@@ -70,9 +70,6 @@ import { WorkspacesMainService, IWorkspacesMainService } from 'vs/platform/works
|
|||||||
import { statSync } from 'fs';
|
import { statSync } from 'fs';
|
||||||
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc';
|
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc';
|
||||||
import { IDiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService';
|
import { IDiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService';
|
||||||
import { FileService } from 'vs/platform/files/common/fileService';
|
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
|
||||||
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
|
|
||||||
import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
|
import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
|
||||||
import { IElectronMainService, ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService';
|
import { IElectronMainService, ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService';
|
||||||
import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService';
|
import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService';
|
||||||
@@ -434,12 +431,6 @@ export class CodeApplication extends Disposable {
|
|||||||
private async createServices(machineId: string, trueMachineId: string | undefined, sharedProcess: SharedProcess, sharedProcessReady: Promise<Client<string>>): Promise<IInstantiationService> {
|
private async createServices(machineId: string, trueMachineId: string | undefined, sharedProcess: SharedProcess, sharedProcessReady: Promise<Client<string>>): Promise<IInstantiationService> {
|
||||||
const services = new ServiceCollection();
|
const services = new ServiceCollection();
|
||||||
|
|
||||||
const fileService = this._register(new FileService(this.logService));
|
|
||||||
services.set(IFileService, fileService);
|
|
||||||
|
|
||||||
const diskFileSystemProvider = this._register(new DiskFileSystemProvider(this.logService));
|
|
||||||
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
|
|
||||||
|
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case 'win32':
|
case 'win32':
|
||||||
services.set(IUpdateService, new SyncDescriptor(Win32UpdateService));
|
services.set(IUpdateService, new SyncDescriptor(Win32UpdateService));
|
||||||
@@ -600,14 +591,42 @@ export class CodeApplication extends Disposable {
|
|||||||
urlService.registerHandler({
|
urlService.registerHandler({
|
||||||
async handleURL(uri: URI, options?: IOpenURLOptions): Promise<boolean> {
|
async handleURL(uri: URI, options?: IOpenURLOptions): Promise<boolean> {
|
||||||
|
|
||||||
// Catch file URLs
|
// Catch file/remote URLs
|
||||||
if (uri.authority === Schemas.file && !!uri.path) {
|
if ((uri.authority === Schemas.file || uri.authority === Schemas.vscodeRemote) && !!uri.path) {
|
||||||
const cli = assign(Object.create(null), environmentService.args);
|
const cli = assign(Object.create(null), environmentService.args);
|
||||||
const urisToOpen = [{ fileUri: URI.file(uri.fsPath) }];
|
const urisToOpen: IWindowOpenable[] = [];
|
||||||
|
|
||||||
windowsMainService.open({ context: OpenContext.API, cli, urisToOpen, gotoLineMode: true });
|
// File path
|
||||||
|
if (uri.authority === Schemas.file) {
|
||||||
|
// we configure as fileUri, but later validation will
|
||||||
|
// make sure to open as folder or workspace if possible
|
||||||
|
urisToOpen.push({ fileUri: URI.file(uri.fsPath) });
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
// Remote path
|
||||||
|
else {
|
||||||
|
// Example conversion:
|
||||||
|
// From: vscode://vscode-remote/wsl+ubuntu/mnt/c/GitDevelopment/monaco
|
||||||
|
// To: vscode-remote://wsl+ubuntu/mnt/c/GitDevelopment/monaco
|
||||||
|
const secondSlash = uri.path.indexOf(posix.sep, 1 /* skip over the leading slash */);
|
||||||
|
if (secondSlash !== -1) {
|
||||||
|
const authority = uri.path.substring(1, secondSlash);
|
||||||
|
const path = uri.path.substring(secondSlash);
|
||||||
|
const remoteUri = URI.from({ scheme: Schemas.vscodeRemote, authority, path, query: uri.query, fragment: uri.fragment });
|
||||||
|
|
||||||
|
if (hasWorkspaceFileExtension(path)) {
|
||||||
|
urisToOpen.push({ workspaceUri: remoteUri });
|
||||||
|
} else {
|
||||||
|
urisToOpen.push({ folderUri: remoteUri });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urisToOpen.length > 0) {
|
||||||
|
windowsMainService.open({ context: OpenContext.API, cli, urisToOpen, gotoLineMode: true });
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ import { once } from 'vs/base/common/functional';
|
|||||||
import { ISignService } from 'vs/platform/sign/common/sign';
|
import { ISignService } from 'vs/platform/sign/common/sign';
|
||||||
import { SignService } from 'vs/platform/sign/node/signService';
|
import { SignService } from 'vs/platform/sign/node/signService';
|
||||||
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc';
|
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc';
|
||||||
|
import { FileService } from 'vs/platform/files/common/fileService';
|
||||||
|
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
|
|
||||||
class ExpectedError extends Error {
|
class ExpectedError extends Error {
|
||||||
readonly isExpected = true;
|
readonly isExpected = true;
|
||||||
@@ -118,12 +122,16 @@ class CodeMain {
|
|||||||
const environmentService = accessor.get(IEnvironmentService);
|
const environmentService = accessor.get(IEnvironmentService);
|
||||||
const logService = accessor.get(ILogService);
|
const logService = accessor.get(ILogService);
|
||||||
const lifecycleMainService = accessor.get(ILifecycleMainService);
|
const lifecycleMainService = accessor.get(ILifecycleMainService);
|
||||||
|
const fileService = accessor.get(IFileService);
|
||||||
const configurationService = accessor.get(IConfigurationService);
|
const configurationService = accessor.get(IConfigurationService);
|
||||||
|
|
||||||
const mainIpcServer = await this.doStartup(logService, environmentService, lifecycleMainService, instantiationService, true);
|
const mainIpcServer = await this.doStartup(logService, environmentService, lifecycleMainService, instantiationService, true);
|
||||||
|
|
||||||
bufferLogService.logger = new SpdLogService('main', environmentService.logsPath, bufferLogService.getLevel());
|
bufferLogService.logger = new SpdLogService('main', environmentService.logsPath, bufferLogService.getLevel());
|
||||||
once(lifecycleMainService.onWillShutdown)(() => (configurationService as ConfigurationService).dispose());
|
once(lifecycleMainService.onWillShutdown)(() => {
|
||||||
|
fileService.dispose();
|
||||||
|
(configurationService as ConfigurationService).dispose();
|
||||||
|
});
|
||||||
|
|
||||||
return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup();
|
return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup();
|
||||||
});
|
});
|
||||||
@@ -143,7 +151,12 @@ class CodeMain {
|
|||||||
process.once('exit', () => logService.dispose());
|
process.once('exit', () => logService.dispose());
|
||||||
services.set(ILogService, logService);
|
services.set(ILogService, logService);
|
||||||
|
|
||||||
services.set(IConfigurationService, new ConfigurationService(environmentService.settingsResource));
|
const fileService = new FileService(logService);
|
||||||
|
services.set(IFileService, fileService);
|
||||||
|
const diskFileSystemProvider = new DiskFileSystemProvider(logService);
|
||||||
|
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
|
||||||
|
|
||||||
|
services.set(IConfigurationService, new ConfigurationService(environmentService.settingsResource, fileService));
|
||||||
services.set(ILifecycleMainService, new SyncDescriptor(LifecycleMainService));
|
services.set(ILifecycleMainService, new SyncDescriptor(LifecycleMainService));
|
||||||
services.set(IStateService, new SyncDescriptor(StateService));
|
services.set(IStateService, new SyncDescriptor(StateService));
|
||||||
services.set(IRequestService, new SyncDescriptor(RequestMainService));
|
services.set(IRequestService, new SyncDescriptor(RequestMainService));
|
||||||
|
|||||||
@@ -306,16 +306,6 @@ export async function main(argv: ParsedArgs): Promise<void> {
|
|||||||
await Promise.all<void | undefined>([environmentService.appSettingsHome.fsPath, environmentService.extensionsPath]
|
await Promise.all<void | undefined>([environmentService.appSettingsHome.fsPath, environmentService.extensionsPath]
|
||||||
.map((path): undefined | Promise<void> => path ? mkdirp(path) : undefined));
|
.map((path): undefined | Promise<void> => path ? mkdirp(path) : undefined));
|
||||||
|
|
||||||
const configurationService = new ConfigurationService(environmentService.settingsResource);
|
|
||||||
disposables.add(configurationService);
|
|
||||||
await configurationService.initialize();
|
|
||||||
|
|
||||||
services.set(IEnvironmentService, environmentService);
|
|
||||||
services.set(ILogService, logService);
|
|
||||||
services.set(IConfigurationService, configurationService);
|
|
||||||
services.set(IStateService, new SyncDescriptor(StateService));
|
|
||||||
services.set(IProductService, { _serviceBrand: undefined, ...product });
|
|
||||||
|
|
||||||
// Files
|
// Files
|
||||||
const fileService = new FileService(logService);
|
const fileService = new FileService(logService);
|
||||||
disposables.add(fileService);
|
disposables.add(fileService);
|
||||||
@@ -325,6 +315,16 @@ export async function main(argv: ParsedArgs): Promise<void> {
|
|||||||
disposables.add(diskFileSystemProvider);
|
disposables.add(diskFileSystemProvider);
|
||||||
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
|
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
|
||||||
|
|
||||||
|
const configurationService = new ConfigurationService(environmentService.settingsResource, fileService);
|
||||||
|
disposables.add(configurationService);
|
||||||
|
await configurationService.initialize();
|
||||||
|
|
||||||
|
services.set(IEnvironmentService, environmentService);
|
||||||
|
services.set(ILogService, logService);
|
||||||
|
services.set(IConfigurationService, configurationService);
|
||||||
|
services.set(IStateService, new SyncDescriptor(StateService));
|
||||||
|
services.set(IProductService, { _serviceBrand: undefined, ...product });
|
||||||
|
|
||||||
const instantiationService: IInstantiationService = new InstantiationService(services);
|
const instantiationService: IInstantiationService = new InstantiationService(services);
|
||||||
|
|
||||||
return instantiationService.invokeFunction(async accessor => {
|
return instantiationService.invokeFunction(async accessor => {
|
||||||
|
|||||||
@@ -103,7 +103,15 @@ export class OpenerService implements IOpenerService {
|
|||||||
// Default external opener is going through window.open()
|
// Default external opener is going through window.open()
|
||||||
this._externalOpener = {
|
this._externalOpener = {
|
||||||
openExternal: href => {
|
openExternal: href => {
|
||||||
dom.windowOpenNoOpener(href);
|
// ensure to open HTTP/HTTPS links into new windows
|
||||||
|
// to not trigger a navigation. Any other link is
|
||||||
|
// safe to be set as HREF to prevent a blank window
|
||||||
|
// from opening.
|
||||||
|
if (matchesScheme(href, Schemas.http) || matchesScheme(href, Schemas.https)) {
|
||||||
|
dom.windowOpenNoOpener(href);
|
||||||
|
} else {
|
||||||
|
window.location.href = href;
|
||||||
|
}
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ export class View extends ViewEventHandler {
|
|||||||
this._context = new ViewContext(configuration, themeService.getTheme(), model, this.eventDispatcher);
|
this._context = new ViewContext(configuration, themeService.getTheme(), model, this.eventDispatcher);
|
||||||
|
|
||||||
this._register(themeService.onThemeChange(theme => {
|
this._register(themeService.onThemeChange(theme => {
|
||||||
this._context.theme = theme;
|
this._context.theme.update(theme);
|
||||||
this.eventDispatcher.emit(new viewEvents.ViewThemeChangedEvent());
|
this.eventDispatcher.emit(new viewEvents.ViewThemeChangedEvent());
|
||||||
this.render(true, false);
|
this.render(true, false);
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ import { MinimapCharRenderer } from 'vs/editor/browser/viewParts/minimap/minimap
|
|||||||
import { Constants } from 'vs/editor/browser/viewParts/minimap/minimapCharSheet';
|
import { Constants } from 'vs/editor/browser/viewParts/minimap/minimapCharSheet';
|
||||||
import { MinimapTokensColorTracker } from 'vs/editor/common/viewModel/minimapTokensColorTracker';
|
import { MinimapTokensColorTracker } from 'vs/editor/common/viewModel/minimapTokensColorTracker';
|
||||||
import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';
|
import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';
|
||||||
import { ViewContext } from 'vs/editor/common/view/viewContext';
|
import { ViewContext, EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||||
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||||
import { ViewLineData } from 'vs/editor/common/viewModel/viewModel';
|
import { ViewLineData } from 'vs/editor/common/viewModel/viewModel';
|
||||||
import { minimapSelection, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, minimapBackground } from 'vs/platform/theme/common/colorRegistry';
|
import { minimapSelection, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, minimapBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||||
import { registerThemingParticipant, ITheme } from 'vs/platform/theme/common/themeService';
|
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||||
import { ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel';
|
import { ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel';
|
||||||
import { Selection } from 'vs/editor/common/core/selection';
|
import { Selection } from 'vs/editor/common/core/selection';
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
@@ -109,7 +109,7 @@ class MinimapOptions {
|
|||||||
|
|
||||||
public readonly backgroundColor: RGBA8;
|
public readonly backgroundColor: RGBA8;
|
||||||
|
|
||||||
constructor(configuration: IConfiguration, theme: ITheme, tokensColorTracker: MinimapTokensColorTracker) {
|
constructor(configuration: IConfiguration, theme: EditorTheme, tokensColorTracker: MinimapTokensColorTracker) {
|
||||||
const options = configuration.options;
|
const options = configuration.options;
|
||||||
const pixelRatio = options.get(EditorOption.pixelRatio);
|
const pixelRatio = options.get(EditorOption.pixelRatio);
|
||||||
const layoutInfo = options.get(EditorOption.layoutInfo);
|
const layoutInfo = options.get(EditorOption.layoutInfo);
|
||||||
@@ -137,7 +137,7 @@ class MinimapOptions {
|
|||||||
this.backgroundColor = MinimapOptions._getMinimapBackground(theme, tokensColorTracker);
|
this.backgroundColor = MinimapOptions._getMinimapBackground(theme, tokensColorTracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _getMinimapBackground(theme: ITheme, tokensColorTracker: MinimapTokensColorTracker): RGBA8 {
|
private static _getMinimapBackground(theme: EditorTheme, tokensColorTracker: MinimapTokensColorTracker): RGBA8 {
|
||||||
const themeColor = theme.getColor(minimapBackground);
|
const themeColor = theme.getColor(minimapBackground);
|
||||||
if (themeColor) {
|
if (themeColor) {
|
||||||
return new RGBA8(themeColor.rgba.r, themeColor.rgba.g, themeColor.rgba.b, themeColor.rgba.a);
|
return new RGBA8(themeColor.rgba.r, themeColor.rgba.g, themeColor.rgba.b, themeColor.rgba.a);
|
||||||
|
|||||||
@@ -12,9 +12,8 @@ import { IConfiguration } from 'vs/editor/common/editorCommon';
|
|||||||
import { TokenizationRegistry } from 'vs/editor/common/modes';
|
import { TokenizationRegistry } from 'vs/editor/common/modes';
|
||||||
import { editorCursorForeground, editorOverviewRulerBorder } from 'vs/editor/common/view/editorColorRegistry';
|
import { editorCursorForeground, editorOverviewRulerBorder } from 'vs/editor/common/view/editorColorRegistry';
|
||||||
import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';
|
import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';
|
||||||
import { ViewContext } from 'vs/editor/common/view/viewContext';
|
import { ViewContext, EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||||
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||||
import { ITheme } from 'vs/platform/theme/common/themeService';
|
|
||||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||||
|
|
||||||
class Settings {
|
class Settings {
|
||||||
@@ -42,7 +41,7 @@ class Settings {
|
|||||||
public readonly x: number[];
|
public readonly x: number[];
|
||||||
public readonly w: number[];
|
public readonly w: number[];
|
||||||
|
|
||||||
constructor(config: IConfiguration, theme: ITheme) {
|
constructor(config: IConfiguration, theme: EditorTheme) {
|
||||||
const options = config.options;
|
const options = config.options;
|
||||||
this.lineHeight = options.get(EditorOption.lineHeight);
|
this.lineHeight = options.get(EditorOption.lineHeight);
|
||||||
this.pixelRatio = options.get(EditorOption.pixelRatio);
|
this.pixelRatio = options.get(EditorOption.pixelRatio);
|
||||||
|
|||||||
@@ -29,12 +29,13 @@ import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageCo
|
|||||||
import { NULL_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/nullMode';
|
import { NULL_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/nullMode';
|
||||||
import { ignoreBracketsInToken } from 'vs/editor/common/modes/supports';
|
import { ignoreBracketsInToken } from 'vs/editor/common/modes/supports';
|
||||||
import { BracketsUtils, RichEditBracket, RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets';
|
import { BracketsUtils, RichEditBracket, RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets';
|
||||||
import { ITheme, ThemeColor } from 'vs/platform/theme/common/themeService';
|
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||||
import { withUndefinedAsNull } from 'vs/base/common/types';
|
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||||
import { VSBufferReadableStream, VSBuffer } from 'vs/base/common/buffer';
|
import { VSBufferReadableStream, VSBuffer } from 'vs/base/common/buffer';
|
||||||
import { TokensStore, MultilineTokens, countEOL, MultilineTokens2, TokensStore2 } from 'vs/editor/common/model/tokensStore';
|
import { TokensStore, MultilineTokens, countEOL, MultilineTokens2, TokensStore2 } from 'vs/editor/common/model/tokensStore';
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
import { Constants } from 'vs/base/common/uint';
|
import { Constants } from 'vs/base/common/uint';
|
||||||
|
import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||||
|
|
||||||
function createTextBufferBuilder() {
|
function createTextBufferBuilder() {
|
||||||
return new PieceTreeTextBufferBuilder();
|
return new PieceTreeTextBufferBuilder();
|
||||||
@@ -2945,7 +2946,7 @@ export class ModelDecorationOverviewRulerOptions extends DecorationOptions {
|
|||||||
this.position = (typeof options.position === 'number' ? options.position : model.OverviewRulerLane.Center);
|
this.position = (typeof options.position === 'number' ? options.position : model.OverviewRulerLane.Center);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getColor(theme: ITheme): string {
|
public getColor(theme: EditorTheme): string {
|
||||||
if (!this._resolvedColor) {
|
if (!this._resolvedColor) {
|
||||||
if (theme.type !== 'light' && this.darkColor) {
|
if (theme.type !== 'light' && this.darkColor) {
|
||||||
this._resolvedColor = this._resolveColor(this.darkColor, theme);
|
this._resolvedColor = this._resolveColor(this.darkColor, theme);
|
||||||
@@ -2960,7 +2961,7 @@ export class ModelDecorationOverviewRulerOptions extends DecorationOptions {
|
|||||||
this._resolvedColor = null;
|
this._resolvedColor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _resolveColor(color: string | ThemeColor, theme: ITheme): string {
|
private _resolveColor(color: string | ThemeColor, theme: EditorTheme): string {
|
||||||
if (typeof color === 'string') {
|
if (typeof color === 'string') {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
@@ -2982,7 +2983,7 @@ export class ModelDecorationMinimapOptions extends DecorationOptions {
|
|||||||
this.position = options.position;
|
this.position = options.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getColor(theme: ITheme): Color | undefined {
|
public getColor(theme: EditorTheme): Color | undefined {
|
||||||
if (!this._resolvedColor) {
|
if (!this._resolvedColor) {
|
||||||
if (theme.type !== 'light' && this.darkColor) {
|
if (theme.type !== 'light' && this.darkColor) {
|
||||||
this._resolvedColor = this._resolveColor(this.darkColor, theme);
|
this._resolvedColor = this._resolveColor(this.darkColor, theme);
|
||||||
@@ -2998,7 +2999,7 @@ export class ModelDecorationMinimapOptions extends DecorationOptions {
|
|||||||
this._resolvedColor = undefined;
|
this._resolvedColor = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _resolveColor(color: string | ThemeColor, theme: ITheme): Color | undefined {
|
private _resolveColor(color: string | ThemeColor, theme: EditorTheme): Color | undefined {
|
||||||
if (typeof color === 'string') {
|
if (typeof color === 'string') {
|
||||||
return Color.fromHex(color);
|
return Color.fromHex(color);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -615,7 +615,9 @@ export interface CodeActionProvider {
|
|||||||
/**
|
/**
|
||||||
* Optional list of CodeActionKinds that this provider returns.
|
* Optional list of CodeActionKinds that this provider returns.
|
||||||
*/
|
*/
|
||||||
providedCodeActionKinds?: ReadonlyArray<string>;
|
readonly providedCodeActionKinds?: ReadonlyArray<string>;
|
||||||
|
|
||||||
|
readonly documentation?: ReadonlyArray<{ readonly kind: string, readonly command: Command }>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
|||||||
@@ -7,7 +7,30 @@ import { IConfiguration } from 'vs/editor/common/editorCommon';
|
|||||||
import { ViewEventDispatcher } from 'vs/editor/common/view/viewEventDispatcher';
|
import { ViewEventDispatcher } from 'vs/editor/common/view/viewEventDispatcher';
|
||||||
import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';
|
import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';
|
||||||
import { IViewLayout, IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
import { IViewLayout, IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
||||||
import { ITheme } from 'vs/platform/theme/common/themeService';
|
import { ITheme, ThemeType } from 'vs/platform/theme/common/themeService';
|
||||||
|
import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry';
|
||||||
|
import { Color } from 'vs/base/common/color';
|
||||||
|
|
||||||
|
export class EditorTheme {
|
||||||
|
|
||||||
|
private _theme: ITheme;
|
||||||
|
|
||||||
|
public get type(): ThemeType {
|
||||||
|
return this._theme.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(theme: ITheme) {
|
||||||
|
this._theme = theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
public update(theme: ITheme): void {
|
||||||
|
this._theme = theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getColor(color: ColorIdentifier): Color | undefined {
|
||||||
|
return this._theme.getColor(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class ViewContext {
|
export class ViewContext {
|
||||||
|
|
||||||
@@ -15,8 +38,7 @@ export class ViewContext {
|
|||||||
public readonly model: IViewModel;
|
public readonly model: IViewModel;
|
||||||
public readonly viewLayout: IViewLayout;
|
public readonly viewLayout: IViewLayout;
|
||||||
public readonly privateViewEventBus: ViewEventDispatcher;
|
public readonly privateViewEventBus: ViewEventDispatcher;
|
||||||
|
public readonly theme: EditorTheme;
|
||||||
public theme: ITheme; // will be updated
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
configuration: IConfiguration,
|
configuration: IConfiguration,
|
||||||
@@ -25,7 +47,7 @@ export class ViewContext {
|
|||||||
privateViewEventBus: ViewEventDispatcher
|
privateViewEventBus: ViewEventDispatcher
|
||||||
) {
|
) {
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.theme = theme;
|
this.theme = new EditorTheme(theme);
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.viewLayout = model.viewLayout;
|
this.viewLayout = model.viewLayout;
|
||||||
this.privateViewEventBus = privateViewEventBus;
|
this.privateViewEventBus = privateViewEventBus;
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import { ModelDecorationOptions, ModelDecorationOverviewRulerOptions } from 'vs/
|
|||||||
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||||
import { PrefixSumIndexOfResult } from 'vs/editor/common/viewModel/prefixSumComputer';
|
import { PrefixSumIndexOfResult } from 'vs/editor/common/viewModel/prefixSumComputer';
|
||||||
import { ICoordinatesConverter, IOverviewRulerDecorations, ViewLineData } from 'vs/editor/common/viewModel/viewModel';
|
import { ICoordinatesConverter, IOverviewRulerDecorations, ViewLineData } from 'vs/editor/common/viewModel/viewModel';
|
||||||
import { ITheme } from 'vs/platform/theme/common/themeService';
|
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { FontInfo } from 'vs/editor/common/config/fontInfo';
|
import { FontInfo } from 'vs/editor/common/config/fontInfo';
|
||||||
|
import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||||
|
|
||||||
export class OutputPosition {
|
export class OutputPosition {
|
||||||
outputLineIndex: number;
|
outputLineIndex: number;
|
||||||
@@ -131,7 +131,7 @@ export interface IViewModelLinesCollection extends IDisposable {
|
|||||||
getViewLineData(viewLineNumber: number): ViewLineData;
|
getViewLineData(viewLineNumber: number): ViewLineData;
|
||||||
getViewLinesData(viewStartLineNumber: number, viewEndLineNumber: number, needed: boolean[]): Array<ViewLineData | null>;
|
getViewLinesData(viewStartLineNumber: number, viewEndLineNumber: number, needed: boolean[]): Array<ViewLineData | null>;
|
||||||
|
|
||||||
getAllOverviewRulerDecorations(ownerId: number, filterOutValidation: boolean, theme: ITheme): IOverviewRulerDecorations;
|
getAllOverviewRulerDecorations(ownerId: number, filterOutValidation: boolean, theme: EditorTheme): IOverviewRulerDecorations;
|
||||||
getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): IModelDecoration[];
|
getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): IModelDecoration[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -940,7 +940,7 @@ export class SplitLinesCollection implements IViewModelLinesCollection {
|
|||||||
return this.lines[lineIndex].getViewLineNumberOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1));
|
return this.lines[lineIndex].getViewLineNumberOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAllOverviewRulerDecorations(ownerId: number, filterOutValidation: boolean, theme: ITheme): IOverviewRulerDecorations {
|
public getAllOverviewRulerDecorations(ownerId: number, filterOutValidation: boolean, theme: EditorTheme): IOverviewRulerDecorations {
|
||||||
const decorations = this.model.getOverviewRulerDecorations(ownerId, filterOutValidation);
|
const decorations = this.model.getOverviewRulerDecorations(ownerId, filterOutValidation);
|
||||||
const result = new OverviewRulerDecorations();
|
const result = new OverviewRulerDecorations();
|
||||||
for (const decoration of decorations) {
|
for (const decoration of decorations) {
|
||||||
@@ -1561,7 +1561,7 @@ export class IdentityLinesCollection implements IViewModelLinesCollection {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAllOverviewRulerDecorations(ownerId: number, filterOutValidation: boolean, theme: ITheme): IOverviewRulerDecorations {
|
public getAllOverviewRulerDecorations(ownerId: number, filterOutValidation: boolean, theme: EditorTheme): IOverviewRulerDecorations {
|
||||||
const decorations = this.model.getOverviewRulerDecorations(ownerId, filterOutValidation);
|
const decorations = this.model.getOverviewRulerDecorations(ownerId, filterOutValidation);
|
||||||
const result = new OverviewRulerDecorations();
|
const result = new OverviewRulerDecorations();
|
||||||
for (const decoration of decorations) {
|
for (const decoration of decorations) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecorationOptions, T
|
|||||||
import { IViewEventListener } from 'vs/editor/common/view/viewEvents';
|
import { IViewEventListener } from 'vs/editor/common/view/viewEvents';
|
||||||
import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
|
import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
|
||||||
import { IEditorWhitespace, IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout';
|
import { IEditorWhitespace, IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout';
|
||||||
import { ITheme } from 'vs/platform/theme/common/themeService';
|
import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||||
|
|
||||||
export interface IViewWhitespaceViewportData {
|
export interface IViewWhitespaceViewportData {
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
@@ -127,7 +127,7 @@ export interface IViewModel {
|
|||||||
getLineMaxColumn(lineNumber: number): number;
|
getLineMaxColumn(lineNumber: number): number;
|
||||||
getLineFirstNonWhitespaceColumn(lineNumber: number): number;
|
getLineFirstNonWhitespaceColumn(lineNumber: number): number;
|
||||||
getLineLastNonWhitespaceColumn(lineNumber: number): number;
|
getLineLastNonWhitespaceColumn(lineNumber: number): number;
|
||||||
getAllOverviewRulerDecorations(theme: ITheme): IOverviewRulerDecorations;
|
getAllOverviewRulerDecorations(theme: EditorTheme): IOverviewRulerDecorations;
|
||||||
invalidateOverviewRulerColorCache(): void;
|
invalidateOverviewRulerColorCache(): void;
|
||||||
invalidateMinimapColorCache(): void;
|
invalidateMinimapColorCache(): void;
|
||||||
getValueInRange(range: Range, eol: EndOfLinePreference): string;
|
getValueInRange(range: Range, eol: EndOfLinePreference): string;
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ import { ViewLayout } from 'vs/editor/common/viewLayout/viewLayout';
|
|||||||
import { IViewModelLinesCollection, IdentityLinesCollection, SplitLinesCollection, ILineBreaksComputerFactory } from 'vs/editor/common/viewModel/splitLinesCollection';
|
import { IViewModelLinesCollection, IdentityLinesCollection, SplitLinesCollection, ILineBreaksComputerFactory } from 'vs/editor/common/viewModel/splitLinesCollection';
|
||||||
import { ICoordinatesConverter, IOverviewRulerDecorations, IViewModel, MinimapLinesRenderingData, ViewLineData, ViewLineRenderingData, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel';
|
import { ICoordinatesConverter, IOverviewRulerDecorations, IViewModel, MinimapLinesRenderingData, ViewLineData, ViewLineRenderingData, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel';
|
||||||
import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations';
|
import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations';
|
||||||
import { ITheme } from 'vs/platform/theme/common/themeService';
|
|
||||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||||
import * as platform from 'vs/base/common/platform';
|
import * as platform from 'vs/base/common/platform';
|
||||||
|
import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||||
|
|
||||||
const USE_IDENTITY_LINES_COLLECTION = true;
|
const USE_IDENTITY_LINES_COLLECTION = true;
|
||||||
|
|
||||||
@@ -595,7 +595,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAllOverviewRulerDecorations(theme: ITheme): IOverviewRulerDecorations {
|
public getAllOverviewRulerDecorations(theme: EditorTheme): IOverviewRulerDecorations {
|
||||||
return this.lines.getAllOverviewRulerDecorations(this.editorId, filterValidationDecorations(this.configuration.options), theme);
|
return this.lines.getAllOverviewRulerDecorations(this.editorId, filterValidationDecorations(this.configuration.options), theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { equals, flatten, isNonEmptyArray, mergeSort } from 'vs/base/common/arrays';
|
import { equals, flatten, isNonEmptyArray, mergeSort, coalesce } from 'vs/base/common/arrays';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { illegalArgument, isPromiseCanceledError, onUnexpectedExternalError } from 'vs/base/common/errors';
|
import { illegalArgument, isPromiseCanceledError, onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||||
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||||
@@ -27,6 +27,8 @@ export interface CodeActionSet extends IDisposable {
|
|||||||
readonly validActions: readonly modes.CodeAction[];
|
readonly validActions: readonly modes.CodeAction[];
|
||||||
readonly allActions: readonly modes.CodeAction[];
|
readonly allActions: readonly modes.CodeAction[];
|
||||||
readonly hasAutoFix: boolean;
|
readonly hasAutoFix: boolean;
|
||||||
|
|
||||||
|
readonly documentation: readonly modes.Command[];
|
||||||
}
|
}
|
||||||
|
|
||||||
class ManagedCodeActionSet extends Disposable implements CodeActionSet {
|
class ManagedCodeActionSet extends Disposable implements CodeActionSet {
|
||||||
@@ -48,7 +50,11 @@ class ManagedCodeActionSet extends Disposable implements CodeActionSet {
|
|||||||
public readonly validActions: readonly modes.CodeAction[];
|
public readonly validActions: readonly modes.CodeAction[];
|
||||||
public readonly allActions: readonly modes.CodeAction[];
|
public readonly allActions: readonly modes.CodeAction[];
|
||||||
|
|
||||||
public constructor(actions: readonly modes.CodeAction[], disposables: DisposableStore) {
|
public constructor(
|
||||||
|
actions: readonly modes.CodeAction[],
|
||||||
|
public readonly documentation: readonly modes.Command[],
|
||||||
|
disposables: DisposableStore,
|
||||||
|
) {
|
||||||
super();
|
super();
|
||||||
this._register(disposables);
|
this._register(disposables);
|
||||||
this.allActions = mergeSort([...actions], ManagedCodeActionSet.codeActionsComparator);
|
this.allActions = mergeSort([...actions], ManagedCodeActionSet.codeActionsComparator);
|
||||||
@@ -80,17 +86,23 @@ export function getCodeActions(
|
|||||||
const promises = providers.map(async provider => {
|
const promises = providers.map(async provider => {
|
||||||
try {
|
try {
|
||||||
const providedCodeActions = await provider.provideCodeActions(model, rangeOrSelection, codeActionContext, cts.token);
|
const providedCodeActions = await provider.provideCodeActions(model, rangeOrSelection, codeActionContext, cts.token);
|
||||||
if (cts.token.isCancellationRequested || !providedCodeActions) {
|
if (providedCodeActions) {
|
||||||
return [];
|
disposables.add(providedCodeActions);
|
||||||
}
|
}
|
||||||
disposables.add(providedCodeActions);
|
|
||||||
return providedCodeActions.actions.filter(action => action && filtersAction(filter, action));
|
if (cts.token.isCancellationRequested) {
|
||||||
|
return { actions: [] as modes.CodeAction[], documentation: undefined };
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredActions = (providedCodeActions?.actions || []).filter(action => action && filtersAction(filter, action));
|
||||||
|
const documentation = getDocumentation(provider, filteredActions, filter.include);
|
||||||
|
return { actions: filteredActions, documentation };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (isPromiseCanceledError(err)) {
|
if (isPromiseCanceledError(err)) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
onUnexpectedExternalError(err);
|
onUnexpectedExternalError(err);
|
||||||
return [];
|
return { actions: [] as modes.CodeAction[], documentation: undefined };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -101,9 +113,11 @@ export function getCodeActions(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(promises)
|
return Promise.all(promises).then(actions => {
|
||||||
.then(flatten)
|
const allActions = flatten(actions.map(x => x.actions));
|
||||||
.then(actions => new ManagedCodeActionSet(actions, disposables))
|
const allDocumentation = coalesce(actions.map(x => x.documentation));
|
||||||
|
return new ManagedCodeActionSet(allActions, allDocumentation, disposables);
|
||||||
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
listener.dispose();
|
listener.dispose();
|
||||||
cts.dispose();
|
cts.dispose();
|
||||||
@@ -125,6 +139,52 @@ function getCodeActionProviders(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDocumentation(
|
||||||
|
provider: modes.CodeActionProvider,
|
||||||
|
providedCodeActions: readonly modes.CodeAction[],
|
||||||
|
only?: CodeActionKind
|
||||||
|
): modes.Command | undefined {
|
||||||
|
if (!provider.documentation) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const documentation = provider.documentation.map(entry => ({ kind: new CodeActionKind(entry.kind), command: entry.command }));
|
||||||
|
|
||||||
|
if (only) {
|
||||||
|
let currentBest: { readonly kind: CodeActionKind, readonly command: modes.Command } | undefined;
|
||||||
|
for (const entry of documentation) {
|
||||||
|
if (entry.kind.contains(only)) {
|
||||||
|
if (!currentBest) {
|
||||||
|
currentBest = entry;
|
||||||
|
} else {
|
||||||
|
// Take best match
|
||||||
|
if (currentBest.kind.contains(entry.kind)) {
|
||||||
|
currentBest = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentBest) {
|
||||||
|
return currentBest?.command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, check to see if any of the provided actions match.
|
||||||
|
for (const action of providedCodeActions) {
|
||||||
|
if (!action.kind) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const entry of documentation) {
|
||||||
|
if (entry.kind.contains(new CodeActionKind(action.kind))) {
|
||||||
|
return entry.command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
registerLanguageCommand('_executeCodeActionProvider', async function (accessor, args): Promise<ReadonlyArray<modes.CodeAction>> {
|
registerLanguageCommand('_executeCodeActionProvider', async function (accessor, args): Promise<ReadonlyArray<modes.CodeAction>> {
|
||||||
const { resource, rangeOrSelection, kind } = args;
|
const { resource, rangeOrSelection, kind } = args;
|
||||||
if (!(resource instanceof URI)) {
|
if (!(resource instanceof URI)) {
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
|||||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||||
import { ScrollType } from 'vs/editor/common/editorCommon';
|
import { ScrollType } from 'vs/editor/common/editorCommon';
|
||||||
import { CodeAction, CodeActionProviderRegistry } from 'vs/editor/common/modes';
|
import { CodeAction, CodeActionProviderRegistry, Command } from 'vs/editor/common/modes';
|
||||||
import { codeActionCommandId, CodeActionSet, fixAllCommandId, organizeImportsCommandId, refactorCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/codeAction';
|
import { codeActionCommandId, CodeActionSet, fixAllCommandId, organizeImportsCommandId, refactorCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/codeAction';
|
||||||
import { CodeActionAutoApply, CodeActionCommandArgs, CodeActionKind, CodeActionTrigger } from 'vs/editor/contrib/codeAction/types';
|
import { CodeActionAutoApply, CodeActionCommandArgs, CodeActionTrigger, CodeActionKind } from 'vs/editor/contrib/codeAction/types';
|
||||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
|
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
|
||||||
@@ -84,7 +84,7 @@ export class CodeActionMenu extends Disposable {
|
|||||||
this._visible = true;
|
this._visible = true;
|
||||||
this._showingActions.value = codeActions;
|
this._showingActions.value = codeActions;
|
||||||
|
|
||||||
const menuActions = this.getMenuActions(trigger, actionsToShow);
|
const menuActions = this.getMenuActions(trigger, actionsToShow, codeActions.documentation);
|
||||||
|
|
||||||
const anchor = Position.isIPosition(at) ? this._toCoords(at) : at || { x: 0, y: 0 };
|
const anchor = Position.isIPosition(at) ? this._toCoords(at) : at || { x: 0, y: 0 };
|
||||||
const resolver = this._keybindingResolver.getResolver();
|
const resolver = this._keybindingResolver.getResolver();
|
||||||
@@ -101,28 +101,34 @@ export class CodeActionMenu extends Disposable {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getMenuActions(trigger: CodeActionTrigger, actionsToShow: readonly CodeAction[]): IAction[] {
|
private getMenuActions(
|
||||||
|
trigger: CodeActionTrigger,
|
||||||
|
actionsToShow: readonly CodeAction[],
|
||||||
|
documentation: readonly Command[]
|
||||||
|
): IAction[] {
|
||||||
const toCodeActionAction = (action: CodeAction): CodeActionAction => new CodeActionAction(action, () => this._delegate.onSelectCodeAction(action));
|
const toCodeActionAction = (action: CodeAction): CodeActionAction => new CodeActionAction(action, () => this._delegate.onSelectCodeAction(action));
|
||||||
|
|
||||||
const result: IAction[] = actionsToShow
|
const result: IAction[] = actionsToShow
|
||||||
.map(toCodeActionAction);
|
.map(toCodeActionAction);
|
||||||
|
|
||||||
|
const allDocumentation: Command[] = [...documentation];
|
||||||
|
|
||||||
const model = this._editor.getModel();
|
const model = this._editor.getModel();
|
||||||
if (model && result.length) {
|
if (model && result.length) {
|
||||||
for (const provider of CodeActionProviderRegistry.all(model)) {
|
for (const provider of CodeActionProviderRegistry.all(model)) {
|
||||||
if (provider._getAdditionalMenuItems) {
|
if (provider._getAdditionalMenuItems) {
|
||||||
const items = provider._getAdditionalMenuItems({ trigger: trigger.type, only: trigger.filter?.include?.value }, actionsToShow);
|
allDocumentation.push(...provider._getAdditionalMenuItems({ trigger: trigger.type, only: trigger.filter?.include?.value }, actionsToShow));
|
||||||
if (items.length) {
|
|
||||||
result.push(new Separator(), ...items.map(command => toCodeActionAction({
|
|
||||||
title: command.title,
|
|
||||||
command: command,
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (allDocumentation.length) {
|
||||||
|
result.push(new Separator(), ...allDocumentation.map(command => toCodeActionAction({
|
||||||
|
title: command.title,
|
||||||
|
command: command,
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { flatten, coalesce } from 'vs/base/common/arrays';
|
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||||
import { registerModelAndPositionCommand } from 'vs/editor/browser/editorExtensions';
|
import { registerModelAndPositionCommand } from 'vs/editor/browser/editorExtensions';
|
||||||
@@ -28,9 +27,18 @@ function getLocationLinks<T>(
|
|||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return Promise.all(promises)
|
|
||||||
.then(flatten)
|
return Promise.all(promises).then(values => {
|
||||||
.then(coalesce);
|
const result: LocationLink[] = [];
|
||||||
|
for (let value of values) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
result.push(...value);
|
||||||
|
} else if (value) {
|
||||||
|
result.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -181,6 +181,8 @@ export interface SelectionEvent {
|
|||||||
readonly element?: Location;
|
readonly element?: Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ReferencesTree extends WorkbenchAsyncDataTree<ReferencesModel | FileReferences, TreeElement, FuzzyScore> { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ZoneWidget that is shown inside the editor
|
* ZoneWidget that is shown inside the editor
|
||||||
*/
|
*/
|
||||||
@@ -195,7 +197,7 @@ export class ReferenceWidget extends peekView.PeekViewWidget {
|
|||||||
private readonly _onDidSelectReference = new Emitter<SelectionEvent>();
|
private readonly _onDidSelectReference = new Emitter<SelectionEvent>();
|
||||||
readonly onDidSelectReference = this._onDidSelectReference.event;
|
readonly onDidSelectReference = this._onDidSelectReference.event;
|
||||||
|
|
||||||
private _tree!: WorkbenchAsyncDataTree<ReferencesModel | FileReferences, TreeElement, FuzzyScore>;
|
private _tree!: ReferencesTree;
|
||||||
private _treeContainer!: HTMLElement;
|
private _treeContainer!: HTMLElement;
|
||||||
private _splitView!: SplitView;
|
private _splitView!: SplitView;
|
||||||
private _preview!: ICodeEditor;
|
private _preview!: ICodeEditor;
|
||||||
@@ -316,8 +318,8 @@ export class ReferenceWidget extends peekView.PeekViewWidget {
|
|||||||
listBackground: peekView.peekViewResultsBackground
|
listBackground: peekView.peekViewResultsBackground
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this._tree = this._instantiationService.createInstance<typeof WorkbenchAsyncDataTree, WorkbenchAsyncDataTree<ReferencesModel | FileReferences, TreeElement, FuzzyScore>>(
|
this._tree = this._instantiationService.createInstance(
|
||||||
WorkbenchAsyncDataTree,
|
ReferencesTree,
|
||||||
'ReferencesWidget',
|
'ReferencesWidget',
|
||||||
this._treeContainer,
|
this._treeContainer,
|
||||||
new Delegate(),
|
new Delegate(),
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
.monaco-editor .parameter-hints-widget .monaco-scrollable-element,
|
.monaco-editor .parameter-hints-widget .monaco-scrollable-element,
|
||||||
.monaco-editor .parameter-hints-widget .body {
|
.monaco-editor .parameter-hints-widget .body {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,8 +137,6 @@
|
|||||||
border-bottom-style: solid;
|
border-bottom-style: solid;
|
||||||
|
|
||||||
padding: 0 8px 0 4px;
|
padding: 0 8px 0 4px;
|
||||||
|
|
||||||
box-shadow: 0 -.5px 3px #ddd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .suggest-widget.list-right.docs-side > .suggest-status-bar {
|
.monaco-editor .suggest-widget.list-right.docs-side > .suggest-status-bar {
|
||||||
@@ -177,6 +175,11 @@
|
|||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .signature-label {
|
||||||
|
overflow: auto;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .qualifier-label {
|
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .qualifier-label {
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
@@ -213,8 +216,8 @@
|
|||||||
|
|
||||||
/** Details: if using CompletionItemLabel#details, always show **/
|
/** Details: if using CompletionItemLabel#details, always show **/
|
||||||
|
|
||||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right.always-show-details > .details-label,
|
.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents > .main > .right > .details-label,
|
||||||
.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .right.always-show-details > .details-label {
|
.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused:not(.string-label) > .contents > .main > .right > .details-label {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,6 +231,12 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .monaco-icon-label {
|
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .monaco-icon-label {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents > .main > .left > .monaco-icon-label {
|
||||||
|
max-width: 80%;
|
||||||
|
}
|
||||||
|
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label > .contents > .main > .left > .monaco-icon-label {
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
}
|
}
|
||||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right {
|
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right {
|
||||||
@@ -253,11 +262,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Do NOT display ReadMore when using plain CompletionItemLabel (details/documentation might not be resolved) **/
|
/** Do NOT display ReadMore when using plain CompletionItemLabel (details/documentation might not be resolved) **/
|
||||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right:not(.always-show-details) > .readMore {
|
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label > .contents > .main > .right > .readMore {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
/** Focused item can show ReadMore, but can't when docs is side/below **/
|
/** Focused item can show ReadMore, but can't when docs is side/below **/
|
||||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .right:not(.always-show-details) > .readMore {
|
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused.string-label > .contents > .main > .right > .readMore {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row > .contents > .main > .right > .readMore,
|
.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row > .contents > .main > .right > .readMore,
|
||||||
.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row.focused > .contents > .main > .right:not(.always-show-details) > .readMore {
|
.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row.focused.string-label > .contents > .main > .right > .readMore {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export const Context = {
|
|||||||
MakesTextEdit: new RawContextKey('suggestionMakesTextEdit', true),
|
MakesTextEdit: new RawContextKey('suggestionMakesTextEdit', true),
|
||||||
AcceptSuggestionsOnEnter: new RawContextKey<boolean>('acceptSuggestionOnEnter', true),
|
AcceptSuggestionsOnEnter: new RawContextKey<boolean>('acceptSuggestionOnEnter', true),
|
||||||
HasInsertAndReplaceRange: new RawContextKey('suggestionHasInsertAndReplaceRange', false),
|
HasInsertAndReplaceRange: new RawContextKey('suggestionHasInsertAndReplaceRange', false),
|
||||||
|
CanResolve: new RawContextKey('suggestionCanResolve', false),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const suggestWidgetStatusbarMenu = new MenuId('suggestWidgetStatusBar');
|
export const suggestWidgetStatusbarMenu = new MenuId('suggestWidgetStatusBar');
|
||||||
@@ -34,9 +35,12 @@ export class CompletionItem {
|
|||||||
|
|
||||||
_brand!: 'ISuggestionItem';
|
_brand!: 'ISuggestionItem';
|
||||||
|
|
||||||
|
private static readonly _defaultResolve = () => Promise.resolve();
|
||||||
|
|
||||||
readonly resolve: (token: CancellationToken) => Promise<void>;
|
readonly resolve: (token: CancellationToken) => Promise<void>;
|
||||||
isResolved: boolean = false;
|
isResolved: boolean = false;
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
readonly editStart: IPosition;
|
readonly editStart: IPosition;
|
||||||
readonly editInsertEnd: IPosition;
|
readonly editInsertEnd: IPosition;
|
||||||
@@ -87,13 +91,13 @@ export class CompletionItem {
|
|||||||
// create the suggestion resolver
|
// create the suggestion resolver
|
||||||
const { resolveCompletionItem } = provider;
|
const { resolveCompletionItem } = provider;
|
||||||
if (typeof resolveCompletionItem !== 'function') {
|
if (typeof resolveCompletionItem !== 'function') {
|
||||||
this.resolve = () => Promise.resolve();
|
this.resolve = CompletionItem._defaultResolve;
|
||||||
this.isResolved = true;
|
this.isResolved = true;
|
||||||
} else {
|
} else {
|
||||||
let cached: Promise<void> | undefined;
|
let cached: Promise<void> | undefined;
|
||||||
this.resolve = (token) => {
|
this.resolve = (token) => {
|
||||||
if (!cached) {
|
if (!cached) {
|
||||||
cached = Promise.resolve(resolveCompletionItem.call(provider, model, position, completion, token)).then(value => {
|
cached = Promise.resolve(resolveCompletionItem.call(provider, model, Position.lift(position), completion, token)).then(value => {
|
||||||
assign(completion, value);
|
assign(completion, value);
|
||||||
this.isResolved = true;
|
this.isResolved = true;
|
||||||
}, err => {
|
}, err => {
|
||||||
|
|||||||
@@ -139,10 +139,12 @@ export class SuggestController implements IEditorContribution {
|
|||||||
// Wire up makes text edit context key
|
// Wire up makes text edit context key
|
||||||
const ctxMakesTextEdit = SuggestContext.MakesTextEdit.bindTo(this._contextKeyService);
|
const ctxMakesTextEdit = SuggestContext.MakesTextEdit.bindTo(this._contextKeyService);
|
||||||
const ctxHasInsertAndReplace = SuggestContext.HasInsertAndReplaceRange.bindTo(this._contextKeyService);
|
const ctxHasInsertAndReplace = SuggestContext.HasInsertAndReplaceRange.bindTo(this._contextKeyService);
|
||||||
|
const ctxCanResolve = SuggestContext.CanResolve.bindTo(this._contextKeyService);
|
||||||
|
|
||||||
this._toDispose.add(toDisposable(() => {
|
this._toDispose.add(toDisposable(() => {
|
||||||
ctxMakesTextEdit.reset();
|
ctxMakesTextEdit.reset();
|
||||||
ctxHasInsertAndReplace.reset();
|
ctxHasInsertAndReplace.reset();
|
||||||
|
ctxCanResolve.reset();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._toDispose.add(widget.onDidFocus(({ item }) => {
|
this._toDispose.add(widget.onDidFocus(({ item }) => {
|
||||||
@@ -172,6 +174,9 @@ export class SuggestController implements IEditorContribution {
|
|||||||
|
|
||||||
// (ctx: hasInsertAndReplaceRange)
|
// (ctx: hasInsertAndReplaceRange)
|
||||||
ctxHasInsertAndReplace.set(!Position.equals(item.editInsertEnd, item.editReplaceEnd));
|
ctxHasInsertAndReplace.set(!Position.equals(item.editInsertEnd, item.editReplaceEnd));
|
||||||
|
|
||||||
|
// (ctx: canResolve)
|
||||||
|
ctxCanResolve.set(Boolean(item.provider.resolveCompletionItem) || Boolean(item.completion.documentation) || item.completion.detail !== item.completion.label);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._toDispose.add(widget.onDetailsKeyDown(e => {
|
this._toDispose.add(widget.onDetailsKeyDown(e => {
|
||||||
@@ -695,13 +700,13 @@ registerEditorCommand(new SuggestCommand({
|
|||||||
menuId: suggestWidgetStatusbarMenu,
|
menuId: suggestWidgetStatusbarMenu,
|
||||||
group: 'right',
|
group: 'right',
|
||||||
order: 1,
|
order: 1,
|
||||||
when: SuggestContext.DetailsVisible,
|
when: ContextKeyExpr.and(SuggestContext.DetailsVisible, SuggestContext.CanResolve),
|
||||||
title: nls.localize('detail.more', "show less")
|
title: nls.localize('detail.more', "show less")
|
||||||
}, {
|
}, {
|
||||||
menuId: suggestWidgetStatusbarMenu,
|
menuId: suggestWidgetStatusbarMenu,
|
||||||
group: 'right',
|
group: 'right',
|
||||||
order: 1,
|
order: 1,
|
||||||
when: SuggestContext.DetailsVisible.toNegated(),
|
when: ContextKeyExpr.and(SuggestContext.DetailsVisible.toNegated(), SuggestContext.CanResolve),
|
||||||
title: nls.localize('detail.less', "show more")
|
title: nls.localize('detail.less', "show more")
|
||||||
}]
|
}]
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -244,12 +244,12 @@ class ItemRenderer implements IListRenderer<CompletionItem, ISuggestionTemplateD
|
|||||||
data.signatureLabel.textContent = '';
|
data.signatureLabel.textContent = '';
|
||||||
data.qualifierLabel.textContent = '';
|
data.qualifierLabel.textContent = '';
|
||||||
data.detailsLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, '');
|
data.detailsLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, '');
|
||||||
removeClass(data.right, 'always-show-details');
|
addClass(data.root, 'string-label');
|
||||||
} else {
|
} else {
|
||||||
data.signatureLabel.textContent = (suggestion.label.signature || '').replace(/\n.*$/m, '');
|
data.signatureLabel.textContent = (suggestion.label.signature || '').replace(/\n.*$/m, '');
|
||||||
data.qualifierLabel.textContent = (suggestion.label.qualifier || '').replace(/\n.*$/m, '');
|
data.qualifierLabel.textContent = (suggestion.label.qualifier || '').replace(/\n.*$/m, '');
|
||||||
data.detailsLabel.textContent = (suggestion.label.type || '').replace(/\n.*$/m, '');
|
data.detailsLabel.textContent = (suggestion.label.type || '').replace(/\n.*$/m, '');
|
||||||
addClass(data.right, 'always-show-details');
|
removeClass(data.root, 'string-label');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canExpandCompletionItem(element)) {
|
if (canExpandCompletionItem(element)) {
|
||||||
|
|||||||
118
src/vs/editor/contrib/suggest/test/wordDistance.test.ts
Normal file
118
src/vs/editor/contrib/suggest/test/wordDistance.test.ts
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as assert from 'assert';
|
||||||
|
import { EditorSimpleWorker } from 'vs/editor/common/services/editorSimpleWorker';
|
||||||
|
import { mock } from 'vs/editor/contrib/suggest/test/suggestModel.test';
|
||||||
|
import { EditorWorkerHost, EditorWorkerServiceImpl } from 'vs/editor/common/services/editorWorkerServiceImpl';
|
||||||
|
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||||
|
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||||
|
import { NullLogService } from 'vs/platform/log/common/log';
|
||||||
|
import { WordDistance } from 'vs/editor/contrib/suggest/wordDistance';
|
||||||
|
import { createTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
|
||||||
|
import { IRange } from 'vs/editor/common/core/range';
|
||||||
|
import { DEFAULT_WORD_REGEXP } from 'vs/editor/common/model/wordHelper';
|
||||||
|
import { Event } from 'vs/base/common/event';
|
||||||
|
import { CompletionItem } from 'vs/editor/contrib/suggest/suggest';
|
||||||
|
import { IPosition } from 'vs/editor/common/core/position';
|
||||||
|
import * as modes from 'vs/editor/common/modes';
|
||||||
|
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
|
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||||
|
import { MockMode } from 'vs/editor/test/common/mocks/mockMode';
|
||||||
|
|
||||||
|
suite('suggest, word distance', function () {
|
||||||
|
|
||||||
|
class BracketMode extends MockMode {
|
||||||
|
|
||||||
|
private static readonly _id = new modes.LanguageIdentifier('bracketMode', 3);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(BracketMode._id);
|
||||||
|
this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {
|
||||||
|
brackets: [
|
||||||
|
['{', '}'],
|
||||||
|
['[', ']'],
|
||||||
|
['(', ')'],
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let distance: WordDistance;
|
||||||
|
let disposables = new DisposableStore();
|
||||||
|
|
||||||
|
setup(async function () {
|
||||||
|
|
||||||
|
disposables.clear();
|
||||||
|
let mode = new BracketMode();
|
||||||
|
let model = TextModel.createFromString('function abc(aa, ab){\na\n}', undefined, mode.getLanguageIdentifier(), URI.parse('test:///some.path'));
|
||||||
|
let editor = createTestCodeEditor({ model: model });
|
||||||
|
editor.updateOptions({ suggest: { localityBonus: true } });
|
||||||
|
editor.setPosition({ lineNumber: 2, column: 2 });
|
||||||
|
|
||||||
|
let modelService = new class extends mock<IModelService>() {
|
||||||
|
onModelRemoved = Event.None;
|
||||||
|
getModel(uri: URI) {
|
||||||
|
return uri.toString() === model.uri.toString() ? model : null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let service = new class extends EditorWorkerServiceImpl {
|
||||||
|
|
||||||
|
private _worker = new EditorSimpleWorker(new class extends mock<EditorWorkerHost>() { }, null);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(modelService, new class extends mock<ITextResourceConfigurationService>() { }, new NullLogService());
|
||||||
|
this._worker.acceptNewModel({
|
||||||
|
url: model.uri.toString(),
|
||||||
|
lines: model.getLinesContent(),
|
||||||
|
EOL: model.getEOL(),
|
||||||
|
versionId: model.getVersionId()
|
||||||
|
});
|
||||||
|
model.onDidChangeContent(e => this._worker.acceptModelChanged(model.uri.toString(), e));
|
||||||
|
}
|
||||||
|
computeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] } | null> {
|
||||||
|
return this._worker.computeWordRanges(resource.toString(), range, DEFAULT_WORD_REGEXP.source, DEFAULT_WORD_REGEXP.flags);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
distance = await WordDistance.create(service, editor);
|
||||||
|
|
||||||
|
disposables.add(mode);
|
||||||
|
disposables.add(model);
|
||||||
|
disposables.add(editor);
|
||||||
|
});
|
||||||
|
|
||||||
|
function createSuggestItem(label: string, overwriteBefore: number, position: IPosition): CompletionItem {
|
||||||
|
const suggestion: modes.CompletionItem = {
|
||||||
|
label,
|
||||||
|
range: { startLineNumber: position.lineNumber, startColumn: position.column - overwriteBefore, endLineNumber: position.lineNumber, endColumn: position.column },
|
||||||
|
insertText: label,
|
||||||
|
kind: 0
|
||||||
|
};
|
||||||
|
const container: modes.CompletionList = {
|
||||||
|
suggestions: [suggestion]
|
||||||
|
};
|
||||||
|
const provider: modes.CompletionItemProvider = {
|
||||||
|
provideCompletionItems(): any {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return new CompletionItem(position, suggestion, container, provider, undefined!);
|
||||||
|
}
|
||||||
|
|
||||||
|
test('Suggest locality bonus can boost current word #90515', function () {
|
||||||
|
this.skip();
|
||||||
|
|
||||||
|
const pos = { lineNumber: 2, column: 2 };
|
||||||
|
const d1 = distance.distance(pos, createSuggestItem('a', 1, pos).completion);
|
||||||
|
const d2 = distance.distance(pos, createSuggestItem('aa', 1, pos).completion);
|
||||||
|
const d3 = distance.distance(pos, createSuggestItem('ab', 1, pos).completion);
|
||||||
|
|
||||||
|
assert.ok(d1 > d2);
|
||||||
|
assert.ok(d2 === d3);
|
||||||
|
});
|
||||||
|
});
|
||||||
11
src/vs/monaco.d.ts
vendored
11
src/vs/monaco.d.ts
vendored
@@ -54,12 +54,19 @@ declare namespace monaco {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CancellationToken {
|
export interface CancellationToken {
|
||||||
|
/**
|
||||||
|
* A flag signalling is cancellation has been requested.
|
||||||
|
*/
|
||||||
readonly isCancellationRequested: boolean;
|
readonly isCancellationRequested: boolean;
|
||||||
/**
|
/**
|
||||||
* An event emitted when cancellation is requested
|
* An event which fires when cancellation is requested. This event
|
||||||
|
* only ever fires `once` as cancellation can only happen once. Listeners
|
||||||
|
* that are registered after cancellation will be called (next event loop run),
|
||||||
|
* but also only once.
|
||||||
|
*
|
||||||
* @event
|
* @event
|
||||||
*/
|
*/
|
||||||
readonly onCancellationRequested: IEvent<any>;
|
readonly onCancellationRequested: (listener: (e: any) => any, thisArgs?: any, disposables?: IDisposable[]) => IDisposable;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Uniform Resource Identifier (Uri) http://tools.ietf.org/html/rfc3986.
|
* Uniform Resource Identifier (Uri) http://tools.ietf.org/html/rfc3986.
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ import { OVERRIDE_PROPERTY_PATTERN, ConfigurationScope, IConfigurationRegistry,
|
|||||||
import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfigurationModel, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, removeFromValueTree, toOverrides, IConfigurationValue, ConfigurationTarget, compare, IConfigurationChangeEvent, IConfigurationChange } from 'vs/platform/configuration/common/configuration';
|
import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfigurationModel, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, removeFromValueTree, toOverrides, IConfigurationValue, ConfigurationTarget, compare, IConfigurationChangeEvent, IConfigurationChange } from 'vs/platform/configuration/common/configuration';
|
||||||
import { Workspace } from 'vs/platform/workspace/common/workspace';
|
import { Workspace } from 'vs/platform/workspace/common/workspace';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
|
import { dirname } from 'vs/base/common/resources';
|
||||||
|
|
||||||
export class ConfigurationModel implements IConfigurationModel {
|
export class ConfigurationModel implements IConfigurationModel {
|
||||||
|
|
||||||
@@ -335,6 +339,40 @@ export class ConfigurationModelParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class UserSettings extends Disposable {
|
||||||
|
|
||||||
|
private readonly parser: ConfigurationModelParser;
|
||||||
|
protected readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
|
||||||
|
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly userSettingsResource: URI,
|
||||||
|
private readonly scopes: ConfigurationScope[] | undefined,
|
||||||
|
private readonly fileService: IFileService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this.parser = new ConfigurationModelParser(this.userSettingsResource.toString(), this.scopes);
|
||||||
|
this._register(this.fileService.watch(dirname(this.userSettingsResource)));
|
||||||
|
this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.userSettingsResource))(() => this._onDidChange.fire()));
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadConfiguration(): Promise<ConfigurationModel> {
|
||||||
|
try {
|
||||||
|
const content = await this.fileService.readFile(this.userSettingsResource);
|
||||||
|
this.parser.parseContent(content.value.toString() || '{}');
|
||||||
|
return this.parser.configurationModel;
|
||||||
|
} catch (e) {
|
||||||
|
return new ConfigurationModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reprocess(): ConfigurationModel {
|
||||||
|
this.parser.parse();
|
||||||
|
return this.parser.configurationModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export class Configuration {
|
export class Configuration {
|
||||||
|
|
||||||
private _workspaceConsolidatedConfiguration: ConfigurationModel | null = null;
|
private _workspaceConsolidatedConfiguration: ConfigurationModel | null = null;
|
||||||
|
|||||||
@@ -7,54 +7,39 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
|||||||
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
|
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, isConfigurationOverrides, IConfigurationData, IConfigurationValue, IConfigurationChange } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, isConfigurationOverrides, IConfigurationData, IConfigurationValue, IConfigurationChange } from 'vs/platform/configuration/common/configuration';
|
||||||
import { DefaultConfigurationModel, Configuration, ConfigurationModel, ConfigurationModelParser, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels';
|
import { DefaultConfigurationModel, Configuration, ConfigurationModel, ConfigurationChangeEvent, UserSettings } from 'vs/platform/configuration/common/configurationModels';
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
|
||||||
import { ConfigWatcher } from 'vs/base/node/config';
|
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
|
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||||
|
|
||||||
export class ConfigurationService extends Disposable implements IConfigurationService, IDisposable {
|
export class ConfigurationService extends Disposable implements IConfigurationService, IDisposable {
|
||||||
|
|
||||||
_serviceBrand: undefined;
|
_serviceBrand: undefined;
|
||||||
|
|
||||||
private configuration: Configuration;
|
private configuration: Configuration;
|
||||||
private userConfigModelWatcher: ConfigWatcher<ConfigurationModelParser> | undefined;
|
private userConfiguration: UserSettings;
|
||||||
|
private readonly reloadConfigurationScheduler: RunOnceScheduler;
|
||||||
|
|
||||||
private readonly _onDidChangeConfiguration: Emitter<IConfigurationChangeEvent> = this._register(new Emitter<IConfigurationChangeEvent>());
|
private readonly _onDidChangeConfiguration: Emitter<IConfigurationChangeEvent> = this._register(new Emitter<IConfigurationChangeEvent>());
|
||||||
readonly onDidChangeConfiguration: Event<IConfigurationChangeEvent> = this._onDidChangeConfiguration.event;
|
readonly onDidChangeConfiguration: Event<IConfigurationChangeEvent> = this._onDidChangeConfiguration.event;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly settingsResource: URI
|
private readonly settingsResource: URI,
|
||||||
|
fileService: IFileService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
this.userConfiguration = this._register(new UserSettings(this.settingsResource, undefined, fileService));
|
||||||
this.configuration = new Configuration(new DefaultConfigurationModel(), new ConfigurationModel());
|
this.configuration = new Configuration(new DefaultConfigurationModel(), new ConfigurationModel());
|
||||||
|
|
||||||
|
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reloadConfiguration(), 50));
|
||||||
this._register(Registry.as<IConfigurationRegistry>(Extensions.Configuration).onDidUpdateConfiguration(configurationProperties => this.onDidDefaultConfigurationChange(configurationProperties)));
|
this._register(Registry.as<IConfigurationRegistry>(Extensions.Configuration).onDidUpdateConfiguration(configurationProperties => this.onDidDefaultConfigurationChange(configurationProperties)));
|
||||||
|
this._register(this.userConfiguration.onDidChange(() => this.reloadConfigurationScheduler.schedule()));
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize(): Promise<void> {
|
async initialize(): Promise<void> {
|
||||||
if (this.userConfigModelWatcher) {
|
const userConfiguration = await this.userConfiguration.loadConfiguration();
|
||||||
this.userConfigModelWatcher.dispose();
|
this.configuration = new Configuration(new DefaultConfigurationModel(), userConfiguration);
|
||||||
}
|
|
||||||
|
|
||||||
if (this.settingsResource.scheme !== Schemas.file) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
return new Promise<void>((c, e) => {
|
|
||||||
this.userConfigModelWatcher = this._register(new ConfigWatcher(this.settingsResource.fsPath, {
|
|
||||||
changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new ConfigurationModelParser(this.settingsResource.fsPath), parse: (content: string, parseErrors: any[]) => {
|
|
||||||
const userConfigModelParser = new ConfigurationModelParser(this.settingsResource.fsPath);
|
|
||||||
userConfigModelParser.parseContent(content);
|
|
||||||
parseErrors = [...userConfigModelParser.errors];
|
|
||||||
return userConfigModelParser;
|
|
||||||
}, initCallback: () => {
|
|
||||||
this.configuration = new Configuration(new DefaultConfigurationModel(), this.userConfigModelWatcher!.getConfig().configurationModel);
|
|
||||||
this._register(this.userConfigModelWatcher!.onDidUpdateConfiguration(() => this.onDidChangeUserConfiguration(this.userConfigModelWatcher!.getConfig().configurationModel)));
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getConfigurationData(): IConfigurationData {
|
getConfigurationData(): IConfigurationData {
|
||||||
@@ -92,14 +77,9 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
|
|||||||
return this.configuration.keys(undefined);
|
return this.configuration.keys(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadConfiguration(folder?: IWorkspaceFolder): Promise<void> {
|
async reloadConfiguration(): Promise<void> {
|
||||||
if (this.userConfigModelWatcher) {
|
const configurationModel = await this.userConfiguration.loadConfiguration();
|
||||||
return new Promise<void>(c => this.userConfigModelWatcher!.reload(userConfigModelParser => {
|
this.onDidChangeUserConfiguration(configurationModel);
|
||||||
this.onDidChangeUserConfiguration(userConfigModelParser.configurationModel);
|
|
||||||
c();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return this.initialize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private onDidChangeUserConfiguration(userConfigurationModel: ConfigurationModel): void {
|
private onDidChangeUserConfiguration(userConfigurationModel: ConfigurationModel): void {
|
||||||
|
|||||||
@@ -16,14 +16,32 @@ import { testFile } from 'vs/base/test/node/utils';
|
|||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
|
import { NullLogService } from 'vs/platform/log/common/log';
|
||||||
|
import { FileService } from 'vs/platform/files/common/fileService';
|
||||||
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
|
|
||||||
suite('ConfigurationService - Node', () => {
|
suite('ConfigurationService - Node', () => {
|
||||||
|
|
||||||
|
let fileService: IFileService;
|
||||||
|
const disposables: IDisposable[] = [];
|
||||||
|
|
||||||
|
setup(() => {
|
||||||
|
const logService = new NullLogService();
|
||||||
|
fileService = new FileService(logService);
|
||||||
|
disposables.push(fileService);
|
||||||
|
const diskFileSystemProvider = new DiskFileSystemProvider(logService);
|
||||||
|
disposables.push(diskFileSystemProvider);
|
||||||
|
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
|
||||||
|
});
|
||||||
|
|
||||||
test('simple', async () => {
|
test('simple', async () => {
|
||||||
const res = await testFile('config', 'config.json');
|
const res = await testFile('config', 'config.json');
|
||||||
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
|
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
|
||||||
|
|
||||||
const service = new ConfigurationService(URI.file(res.testFile));
|
const service = new ConfigurationService(URI.file(res.testFile), fileService);
|
||||||
await service.initialize();
|
await service.initialize();
|
||||||
const config = service.getValue<{
|
const config = service.getValue<{
|
||||||
foo: string;
|
foo: string;
|
||||||
@@ -41,7 +59,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
|
|
||||||
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
|
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
|
||||||
|
|
||||||
const service = new ConfigurationService(URI.file(res.testFile));
|
const service = new ConfigurationService(URI.file(res.testFile), fileService);
|
||||||
await service.initialize();
|
await service.initialize();
|
||||||
const config = service.getValue<{
|
const config = service.getValue<{
|
||||||
testworkbench: {
|
testworkbench: {
|
||||||
@@ -64,7 +82,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
|
|
||||||
fs.writeFileSync(res.testFile, ',,,,');
|
fs.writeFileSync(res.testFile, ',,,,');
|
||||||
|
|
||||||
const service = new ConfigurationService(URI.file(res.testFile));
|
const service = new ConfigurationService(URI.file(res.testFile), fileService);
|
||||||
await service.initialize();
|
await service.initialize();
|
||||||
const config = service.getValue<{
|
const config = service.getValue<{
|
||||||
foo: string;
|
foo: string;
|
||||||
@@ -81,7 +99,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
const newDir = path.join(parentDir, 'config', id);
|
const newDir = path.join(parentDir, 'config', id);
|
||||||
const testFile = path.join(newDir, 'config.json');
|
const testFile = path.join(newDir, 'config.json');
|
||||||
|
|
||||||
const service = new ConfigurationService(URI.file(testFile));
|
const service = new ConfigurationService(URI.file(testFile), fileService);
|
||||||
await service.initialize();
|
await service.initialize();
|
||||||
|
|
||||||
const config = service.getValue<{ foo: string }>();
|
const config = service.getValue<{ foo: string }>();
|
||||||
@@ -90,10 +108,10 @@ suite('ConfigurationService - Node', () => {
|
|||||||
service.dispose();
|
service.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('trigger configuration change event', async () => {
|
test('trigger configuration change event when file does not exist', async () => {
|
||||||
const res = await testFile('config', 'config.json');
|
const res = await testFile('config', 'config.json');
|
||||||
|
|
||||||
const service = new ConfigurationService(URI.file(res.testFile));
|
const service = new ConfigurationService(URI.file(res.testFile), fileService);
|
||||||
await service.initialize();
|
await service.initialize();
|
||||||
return new Promise((c, e) => {
|
return new Promise((c, e) => {
|
||||||
const disposable = Event.filter(service.onDidChangeConfiguration, e => e.source === ConfigurationTarget.USER)(async (e) => {
|
const disposable = Event.filter(service.onDidChangeConfiguration, e => e.source === ConfigurationTarget.USER)(async (e) => {
|
||||||
@@ -108,12 +126,31 @@ suite('ConfigurationService - Node', () => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('trigger configuration change event when file exists', async () => {
|
||||||
|
const res = await testFile('config', 'config.json');
|
||||||
|
|
||||||
|
const service = new ConfigurationService(URI.file(res.testFile), fileService);
|
||||||
|
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
|
||||||
|
await service.initialize();
|
||||||
|
return new Promise((c, e) => {
|
||||||
|
const disposable = Event.filter(service.onDidChangeConfiguration, e => e.source === ConfigurationTarget.USER)(async (e) => {
|
||||||
|
disposable.dispose();
|
||||||
|
assert.equal(service.getValue('foo'), 'barz');
|
||||||
|
service.dispose();
|
||||||
|
await res.cleanUp();
|
||||||
|
c();
|
||||||
|
});
|
||||||
|
fs.writeFileSync(res.testFile, '{ "foo": "barz" }');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
test('reloadConfiguration', async () => {
|
test('reloadConfiguration', async () => {
|
||||||
const res = await testFile('config', 'config.json');
|
const res = await testFile('config', 'config.json');
|
||||||
|
|
||||||
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
|
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
|
||||||
|
|
||||||
const service = new ConfigurationService(URI.file(res.testFile));
|
const service = new ConfigurationService(URI.file(res.testFile), fileService);
|
||||||
await service.initialize();
|
await service.initialize();
|
||||||
let config = service.getValue<{
|
let config = service.getValue<{
|
||||||
foo: string;
|
foo: string;
|
||||||
@@ -162,7 +199,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let serviceWithoutFile = new ConfigurationService(URI.file('__testFile'));
|
let serviceWithoutFile = new ConfigurationService(URI.file('__testFile'), fileService);
|
||||||
await serviceWithoutFile.initialize();
|
await serviceWithoutFile.initialize();
|
||||||
let setting = serviceWithoutFile.getValue<ITestSetting>();
|
let setting = serviceWithoutFile.getValue<ITestSetting>();
|
||||||
|
|
||||||
@@ -172,7 +209,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
return testFile('config', 'config.json').then(async res => {
|
return testFile('config', 'config.json').then(async res => {
|
||||||
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
|
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
|
||||||
|
|
||||||
const service = new ConfigurationService(URI.file(res.testFile));
|
const service = new ConfigurationService(URI.file(res.testFile), fileService);
|
||||||
|
|
||||||
let setting = service.getValue<ITestSetting>();
|
let setting = service.getValue<ITestSetting>();
|
||||||
|
|
||||||
@@ -205,7 +242,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const r = await testFile('config', 'config.json');
|
const r = await testFile('config', 'config.json');
|
||||||
const service = new ConfigurationService(URI.file(r.testFile));
|
const service = new ConfigurationService(URI.file(r.testFile), fileService);
|
||||||
service.initialize();
|
service.initialize();
|
||||||
|
|
||||||
let res = service.inspect('something.missing');
|
let res = service.inspect('something.missing');
|
||||||
@@ -243,7 +280,7 @@ suite('ConfigurationService - Node', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const r = await testFile('config', 'config.json');
|
const r = await testFile('config', 'config.json');
|
||||||
const service = new ConfigurationService(URI.file(r.testFile));
|
const service = new ConfigurationService(URI.file(r.testFile), fileService);
|
||||||
service.initialize();
|
service.initialize();
|
||||||
|
|
||||||
let res = service.inspect('lookup.service.testNullSetting');
|
let res = service.inspect('lookup.service.testNullSetting');
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ipcMain as ipc, app } from 'electron';
|
import { ipcMain as ipc, app, BrowserWindow } from 'electron';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IStateService } from 'vs/platform/state/node/state';
|
import { IStateService } from 'vs/platform/state/node/state';
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
@@ -12,7 +12,7 @@ import { ICodeWindow } from 'vs/platform/windows/electron-main/windows';
|
|||||||
import { handleVetos } from 'vs/platform/lifecycle/common/lifecycle';
|
import { handleVetos } from 'vs/platform/lifecycle/common/lifecycle';
|
||||||
import { isMacintosh, isWindows } from 'vs/base/common/platform';
|
import { isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { Barrier } from 'vs/base/common/async';
|
import { Barrier, timeout } from 'vs/base/common/async';
|
||||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||||
|
|
||||||
export const ILifecycleMainService = createDecorator<ILifecycleMainService>('lifecycleMainService');
|
export const ILifecycleMainService = createDecorator<ILifecycleMainService>('lifecycleMainService');
|
||||||
@@ -106,7 +106,7 @@ export interface ILifecycleMainService {
|
|||||||
/**
|
/**
|
||||||
* Forcefully shutdown the application. No livecycle event handlers are triggered.
|
* Forcefully shutdown the application. No livecycle event handlers are triggered.
|
||||||
*/
|
*/
|
||||||
kill(code?: number): void;
|
kill(code?: number): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a promise that resolves when a certain lifecycle phase
|
* Returns a promise that resolves when a certain lifecycle phase
|
||||||
@@ -550,9 +550,45 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe
|
|||||||
this.quit().then(veto => quitVetoed = veto);
|
this.quit().then(veto => quitVetoed = veto);
|
||||||
}
|
}
|
||||||
|
|
||||||
kill(code?: number): void {
|
async kill(code?: number): Promise<void> {
|
||||||
this.logService.trace('Lifecycle#kill()');
|
this.logService.trace('Lifecycle#kill()');
|
||||||
|
|
||||||
|
// The kill() method is only used in 2 situations:
|
||||||
|
// - when an instance fails to start at all
|
||||||
|
// - when extension tests run from CLI to report proper exit code
|
||||||
|
//
|
||||||
|
// From extension tests we have seen issues where calling app.exit()
|
||||||
|
// with an opened window can lead to native crashes (Linux) when webviews
|
||||||
|
// are involved. As such, we should make sure to destroy any opened
|
||||||
|
// window before calling app.exit().
|
||||||
|
//
|
||||||
|
// Note: Electron implements a similar logic here:
|
||||||
|
// https://github.com/electron/electron/blob/fe5318d753637c3903e23fc1ed1b263025887b6a/spec-main/window-helpers.ts#L5
|
||||||
|
|
||||||
|
await Promise.race([
|
||||||
|
|
||||||
|
// still do not block more than 1s
|
||||||
|
timeout(1000),
|
||||||
|
|
||||||
|
// destroy any opened window
|
||||||
|
(async () => {
|
||||||
|
for (const window of BrowserWindow.getAllWindows()) {
|
||||||
|
if (window && !window.isDestroyed()) {
|
||||||
|
let whenWindowClosed: Promise<void>;
|
||||||
|
if (window.webContents && !window.webContents.isDestroyed()) {
|
||||||
|
whenWindowClosed = new Promise(c => window.once('closed', c));
|
||||||
|
} else {
|
||||||
|
whenWindowClosed = Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.destroy();
|
||||||
|
await whenWindowClosed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Now exit either after 1s or all windows destroyed
|
||||||
app.exit(code);
|
app.exit(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,11 +243,13 @@ export class WorkbenchList<T> extends List<T> {
|
|||||||
|
|
||||||
readonly contextKeyService: IContextKeyService;
|
readonly contextKeyService: IContextKeyService;
|
||||||
private readonly configurationService: IConfigurationService;
|
private readonly configurationService: IConfigurationService;
|
||||||
|
private readonly themeService: IThemeService;
|
||||||
|
|
||||||
private listHasSelectionOrFocus: IContextKey<boolean>;
|
private listHasSelectionOrFocus: IContextKey<boolean>;
|
||||||
private listDoubleSelection: IContextKey<boolean>;
|
private listDoubleSelection: IContextKey<boolean>;
|
||||||
private listMultiSelection: IContextKey<boolean>;
|
private listMultiSelection: IContextKey<boolean>;
|
||||||
|
|
||||||
|
private _styler: IDisposable | undefined;
|
||||||
private _useAltAsMultipleSelectionModifier: boolean;
|
private _useAltAsMultipleSelectionModifier: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -278,6 +280,7 @@ export class WorkbenchList<T> extends List<T> {
|
|||||||
|
|
||||||
this.contextKeyService = createScopedContextKeyService(contextKeyService, this);
|
this.contextKeyService = createScopedContextKeyService(contextKeyService, this);
|
||||||
this.configurationService = configurationService;
|
this.configurationService = configurationService;
|
||||||
|
this.themeService = themeService;
|
||||||
|
|
||||||
const listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);
|
const listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);
|
||||||
listSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));
|
listSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));
|
||||||
@@ -292,7 +295,7 @@ export class WorkbenchList<T> extends List<T> {
|
|||||||
this.disposables.add((listService as ListService).register(this));
|
this.disposables.add((listService as ListService).register(this));
|
||||||
|
|
||||||
if (options.overrideStyles) {
|
if (options.overrideStyles) {
|
||||||
this.disposables.add(attachListStyler(this, themeService, options.overrideStyles));
|
this.updateStyles(options.overrideStyles);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.disposables.add(this.onSelectionChange(() => {
|
this.disposables.add(this.onSelectionChange(() => {
|
||||||
@@ -313,6 +316,29 @@ export class WorkbenchList<T> extends List<T> {
|
|||||||
this.registerListeners();
|
this.registerListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateOptions(options: IWorkbenchListOptions<T>): void {
|
||||||
|
super.updateOptions(options);
|
||||||
|
|
||||||
|
if (options.overrideStyles) {
|
||||||
|
this.updateStyles(options.overrideStyles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void {
|
||||||
|
super.dispose();
|
||||||
|
if (this._styler) {
|
||||||
|
this._styler.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateStyles(styles: IColorMapping): void {
|
||||||
|
if (this._styler) {
|
||||||
|
this._styler.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._styler = attachListStyler(this, this.themeService, styles);
|
||||||
|
}
|
||||||
|
|
||||||
private registerListeners(): void {
|
private registerListeners(): void {
|
||||||
this.disposables.add(this.configurationService.onDidChangeConfiguration(e => {
|
this.disposables.add(this.configurationService.onDidChangeConfiguration(e => {
|
||||||
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {
|
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {
|
||||||
@@ -738,7 +764,7 @@ export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void>
|
|||||||
@IKeybindingService keybindingService: IKeybindingService,
|
@IKeybindingService keybindingService: IKeybindingService,
|
||||||
@IAccessibilityService accessibilityService: IAccessibilityService
|
@IAccessibilityService accessibilityService: IAccessibilityService
|
||||||
) {
|
) {
|
||||||
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
|
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble<T, TFilterData, IWorkbenchObjectTreeOptions<T, TFilterData>>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
|
||||||
super(user, container, delegate, renderers, treeOptions);
|
super(user, container, delegate, renderers, treeOptions);
|
||||||
this.disposables.add(disposable);
|
this.disposables.add(disposable);
|
||||||
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
||||||
@@ -769,12 +795,20 @@ export class WorkbenchCompressibleObjectTree<T extends NonNullable<any>, TFilter
|
|||||||
@IKeybindingService keybindingService: IKeybindingService,
|
@IKeybindingService keybindingService: IKeybindingService,
|
||||||
@IAccessibilityService accessibilityService: IAccessibilityService
|
@IAccessibilityService accessibilityService: IAccessibilityService
|
||||||
) {
|
) {
|
||||||
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
|
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble<T, TFilterData, IWorkbenchCompressibleObjectTreeOptions<T, TFilterData>>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
|
||||||
super(user, container, delegate, renderers, treeOptions);
|
super(user, container, delegate, renderers, treeOptions);
|
||||||
this.disposables.add(disposable);
|
this.disposables.add(disposable);
|
||||||
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
||||||
this.disposables.add(this.internals);
|
this.disposables.add(this.internals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateOptions(options: IWorkbenchAsyncDataTreeOptions<T, TFilterData> = {}): void {
|
||||||
|
super.updateOptions(options);
|
||||||
|
|
||||||
|
if (options.overrideStyles) {
|
||||||
|
this.internals.updateStyleOverrides(options.overrideStyles);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IWorkbenchDataTreeOptions<T, TFilterData> extends IDataTreeOptions<T, TFilterData> {
|
export interface IWorkbenchDataTreeOptions<T, TFilterData> extends IDataTreeOptions<T, TFilterData> {
|
||||||
@@ -801,7 +835,7 @@ export class WorkbenchDataTree<TInput, T, TFilterData = void> extends DataTree<T
|
|||||||
@IKeybindingService keybindingService: IKeybindingService,
|
@IKeybindingService keybindingService: IKeybindingService,
|
||||||
@IAccessibilityService accessibilityService: IAccessibilityService
|
@IAccessibilityService accessibilityService: IAccessibilityService
|
||||||
) {
|
) {
|
||||||
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
|
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble<T, TFilterData, IWorkbenchDataTreeOptions<T, TFilterData>>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
|
||||||
super(user, container, delegate, renderers, dataSource, treeOptions);
|
super(user, container, delegate, renderers, dataSource, treeOptions);
|
||||||
this.disposables.add(disposable);
|
this.disposables.add(disposable);
|
||||||
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
||||||
@@ -841,7 +875,7 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
|
|||||||
@IKeybindingService keybindingService: IKeybindingService,
|
@IKeybindingService keybindingService: IKeybindingService,
|
||||||
@IAccessibilityService accessibilityService: IAccessibilityService
|
@IAccessibilityService accessibilityService: IAccessibilityService
|
||||||
) {
|
) {
|
||||||
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
|
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble<T, TFilterData, IWorkbenchAsyncDataTreeOptions<T, TFilterData>>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
|
||||||
super(user, container, delegate, renderers, dataSource, treeOptions);
|
super(user, container, delegate, renderers, dataSource, treeOptions);
|
||||||
this.disposables.add(disposable);
|
this.disposables.add(disposable);
|
||||||
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
||||||
@@ -882,7 +916,7 @@ export class WorkbenchCompressibleAsyncDataTree<TInput, T, TFilterData = void> e
|
|||||||
@IKeybindingService keybindingService: IKeybindingService,
|
@IKeybindingService keybindingService: IKeybindingService,
|
||||||
@IAccessibilityService accessibilityService: IAccessibilityService
|
@IAccessibilityService accessibilityService: IAccessibilityService
|
||||||
) {
|
) {
|
||||||
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
|
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble<T, TFilterData, IWorkbenchCompressibleAsyncDataTreeOptions<T, TFilterData>>(container, options, contextKeyService, configurationService, keybindingService, accessibilityService);
|
||||||
super(user, container, virtualDelegate, compressionDelegate, renderers, dataSource, treeOptions);
|
super(user, container, virtualDelegate, compressionDelegate, renderers, dataSource, treeOptions);
|
||||||
this.disposables.add(disposable);
|
this.disposables.add(disposable);
|
||||||
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class MarkerStats implements MarkerStatistics {
|
|||||||
this._data = undefined;
|
this._data = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _update(resources: URI[]): void {
|
private _update(resources: readonly URI[]): void {
|
||||||
if (!this._data) {
|
if (!this._data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -343,7 +343,7 @@ export class MarkerService implements IMarkerService {
|
|||||||
|
|
||||||
private static _dedupeMap: { [uri: string]: boolean };
|
private static _dedupeMap: { [uri: string]: boolean };
|
||||||
|
|
||||||
private static _debouncer(last: URI[], event: URI[]): URI[] {
|
private static _debouncer(last: URI[] | undefined, event: readonly URI[]): URI[] {
|
||||||
if (!last) {
|
if (!last) {
|
||||||
MarkerService._dedupeMap = Object.create(null);
|
MarkerService._dedupeMap = Object.create(null);
|
||||||
last = [];
|
last = [];
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user