Merge from vscode 1fbacccbc9
This commit is contained in:
Родитель
9af1f3b0eb
Коммит
73ea8b79b2
|
@ -22,6 +22,8 @@
|
|||
"i18n/**": true,
|
||||
"extensions/**/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
|
||||
},
|
||||
"lcov.path": [
|
||||
|
|
|
@ -8,5 +8,7 @@
|
|||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -120,17 +120,19 @@ steps:
|
|||
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \
|
||||
./resources/server/test/test-web-integration.sh --browser webkit
|
||||
displayName: Run integration tests (Browser)
|
||||
APP_ROOT=$(agent.builddirectory)/VSCode-darwin
|
||||
APP_NAME="`ls $APP_ROOT | head -n 1`"
|
||||
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'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \
|
||||
yarn smoketest --web --headless --browser webkit
|
||||
continueOnError: true
|
||||
displayName: Run smoke tests (Browser)
|
||||
./resources/server/test/test-web-integration.sh --browser webkit
|
||||
displayName: Run integration tests (Browser)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
|
|
|
@ -19,7 +19,9 @@ node build/azure-pipelines/common/createAsset.js \
|
|||
../vscode-server-darwin.zip
|
||||
|
||||
# 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
|
||||
yarn gulp upload-vscode-configuration
|
||||
|
|
|
@ -123,20 +123,21 @@ steps:
|
|||
displayName: Run integration tests (Electron)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
# Fails due to weird error: Protocol error (Target.getBrowserContexts): Target closed.
|
||||
# - script: |
|
||||
# set -e
|
||||
# VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-x64" \
|
||||
# DISPLAY=:10 ./resources/server/test/test-web-integration.sh --browser chromium
|
||||
# displayName: Run integration tests (Browser)
|
||||
# condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
- script: |
|
||||
set -e
|
||||
APP_ROOT=$(agent.builddirectory)/VSCode-linux-x64
|
||||
APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName")
|
||||
INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-linux-x64" \
|
||||
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: |
|
||||
set -e
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-x64" \
|
||||
yarn smoketest --web --headless --browser firefox
|
||||
continueOnError: true
|
||||
displayName: Run smoke tests (Firefox)
|
||||
DISPLAY=:10 ./resources/server/test/test-web-integration.sh --browser chromium
|
||||
displayName: Run integration tests (Browser)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- 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"
|
||||
|
||||
# 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
|
||||
PLATFORM_DEB="linux-deb-x64"
|
||||
|
|
|
@ -135,16 +135,18 @@ steps:
|
|||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$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 }
|
||||
displayName: Run integration tests (Browser)
|
||||
$AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)"
|
||||
$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'))
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)"; yarn smoketest --web --headless --browser chromium }
|
||||
continueOnError: true
|
||||
displayName: Run smoke tests (Browser)
|
||||
exec { $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)"; .\resources\server\test\test-web-integration.bat --browser firefox }
|
||||
displayName: Run integration tests (Browser)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- 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"
|
||||
$Zip = "$Repo\.build\win32-$Arch\archive\VSCode-win32-$Arch.zip"
|
||||
$LegacyServer = "$Root\vscode-reh-win32-$Arch"
|
||||
$ServerName = "vscode-server-win32-$Arch"
|
||||
$Server = "$Root\$ServerName"
|
||||
$Server = "$Root\vscode-server-win32-$Arch"
|
||||
$ServerZip = "$Repo\.build\vscode-server-win32-$Arch.zip"
|
||||
$Build = "$Root\VSCode-win32-$Arch"
|
||||
|
||||
# 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 }
|
||||
|
||||
# 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 "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
|
||||
$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 }
|
||||
# $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 }
|
||||
|
|
|
@ -110,6 +110,10 @@
|
|||
"name": "vs/workbench/contrib/output",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/openInDesktop",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/performance",
|
||||
"project": "vscode-workbench"
|
||||
|
|
|
@ -93,7 +93,7 @@ export class ApiWrapper {
|
|||
return vscode.workspace.asRelativePath(uri);
|
||||
}
|
||||
|
||||
public getWorkspaceFolders(): vscode.WorkspaceFolder[] {
|
||||
public getWorkspaceFolders(): readonly vscode.WorkspaceFolder[] {
|
||||
return vscode.workspace.workspaceFolders;
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,7 @@ export class ApiWrapper {
|
|||
return vscode.window.createStatusBarItem(alignment, priority);
|
||||
}
|
||||
|
||||
public get workspaceFolders(): vscode.WorkspaceFolder[] {
|
||||
public get workspaceFolders(): readonly vscode.WorkspaceFolder[] {
|
||||
return vscode.workspace.workspaceFolders;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ export class ApiWrapper {
|
|||
return vscode.workspace.asRelativePath(uri);
|
||||
}
|
||||
|
||||
public getWorkspaceFolders(): vscode.WorkspaceFolder[] {
|
||||
public getWorkspaceFolders(): readonly vscode.WorkspaceFolder[] {
|
||||
return vscode.workspace.workspaceFolders;
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ export class ApiWrapper {
|
|||
return vscode.window.createStatusBarItem(alignment, priority);
|
||||
}
|
||||
|
||||
public get workspaceFolders(): vscode.WorkspaceFolder[] {
|
||||
public get workspaceFolders(): readonly vscode.WorkspaceFolder[] {
|
||||
return vscode.workspace.workspaceFolders;
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ export class SettingsDocument {
|
|||
}));
|
||||
} else {
|
||||
// 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[]> {
|
||||
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 => {
|
||||
const completionItems = [];
|
||||
const configuration = vscode.workspace.getConfiguration();
|
||||
|
@ -182,7 +187,7 @@ export class SettingsDocument {
|
|||
let text = this.document.getText(range);
|
||||
if (text && text.trim().startsWith('[')) {
|
||||
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);
|
||||
|
@ -209,7 +214,7 @@ export class SettingsDocument {
|
|||
// Suggestion model word matching includes closed sqaure bracket and ending quote
|
||||
// Hence include them in the proposal to replace
|
||||
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([]);
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ export class ApiWrapper {
|
|||
return vscode.window.showTextDocument(document, options);
|
||||
}
|
||||
|
||||
public get workspaceFolders(): vscode.WorkspaceFolder[] {
|
||||
public get workspaceFolders(): readonly vscode.WorkspaceFolder[] {
|
||||
return vscode.workspace.workspaceFolders;
|
||||
}
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi
|
|||
return undefined;
|
||||
}
|
||||
|
||||
let workspaceFolders = vscode.workspace.workspaceFolders || [];
|
||||
let workspaceFolders = vscode.workspace.workspaceFolders?.slice() ?? [];
|
||||
const bookTreeViewProvider = new BookTreeViewProvider(workspaceFolders, extensionContext, false, BOOKS_VIEWID);
|
||||
await bookTreeViewProvider.initialized;
|
||||
const untitledBookTreeViewProvider = new BookTreeViewProvider([], extensionContext, true, READONLY_BOOKS_VIEWID);
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
// @ts-check
|
||||
// todo@jackson
|
||||
/* eslint code-no-unexternalized-strings: 0 */
|
||||
|
||||
const mappings = [
|
||||
['bat', 'source.batchfile'],
|
||||
|
@ -40,6 +38,7 @@ const mappings = [
|
|||
['perl', 'source.perl'],
|
||||
['php', 'source.php'],
|
||||
['pl', 'source.perl'],
|
||||
['pm', 'source.perl'],
|
||||
['ps1', 'source.powershell'],
|
||||
['pug', 'text.pug'],
|
||||
['py', 'source.python'],
|
||||
|
@ -104,43 +103,43 @@ mappings.forEach(([ext, scope, regexp]) =>
|
|||
repository[ext] = {
|
||||
name: scopes.resultBlock.meta,
|
||||
begin: `^(?!\\s)(.*?)([^\\\\\\/\\n]*${regexp || `\\.${ext}`})(:)$`,
|
||||
end: "^(?!\\s)",
|
||||
end: '^(?!\\s)',
|
||||
beginCaptures: {
|
||||
"0": { name: scopes.resultBlock.path.meta },
|
||||
"1": { name: scopes.resultBlock.path.dirname },
|
||||
"2": { name: scopes.resultBlock.path.basename },
|
||||
"3": { name: scopes.resultBlock.path.colon },
|
||||
'0': { name: scopes.resultBlock.path.meta },
|
||||
'1': { name: scopes.resultBlock.path.dirname },
|
||||
'2': { name: scopes.resultBlock.path.basename },
|
||||
'3': { name: scopes.resultBlock.path.colon },
|
||||
},
|
||||
patterns: [
|
||||
{
|
||||
name: [scopes.resultBlock.result.meta, scopes.resultBlock.result.metaMultiLine].join(' '),
|
||||
begin: "^ ((\\d+) )",
|
||||
while: "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
begin: '^ ((\\d+) )',
|
||||
while: '^ (?:((\\d+)(:))|((\\d+) ))',
|
||||
beginCaptures: {
|
||||
"0": { name: scopes.resultBlock.result.prefix.meta },
|
||||
"1": { name: scopes.resultBlock.result.prefix.metaContext },
|
||||
"2": { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||
'0': { name: scopes.resultBlock.result.prefix.meta },
|
||||
'1': { name: scopes.resultBlock.result.prefix.metaContext },
|
||||
'2': { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||
},
|
||||
whileCaptures: {
|
||||
"0": { name: scopes.resultBlock.result.prefix.meta },
|
||||
"1": { name: scopes.resultBlock.result.prefix.metaMatch },
|
||||
"2": { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||
"3": { name: scopes.resultBlock.result.prefix.colon },
|
||||
'0': { name: scopes.resultBlock.result.prefix.meta },
|
||||
'1': { name: scopes.resultBlock.result.prefix.metaMatch },
|
||||
'2': { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||
'3': { name: scopes.resultBlock.result.prefix.colon },
|
||||
|
||||
"4": { name: scopes.resultBlock.result.prefix.metaContext },
|
||||
"5": { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||
'4': { name: scopes.resultBlock.result.prefix.metaContext },
|
||||
'5': { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||
},
|
||||
patterns: [{ include: scope }]
|
||||
},
|
||||
{
|
||||
begin: "^ ((\\d+)(:))",
|
||||
while: "(?=not)possible",
|
||||
begin: '^ ((\\d+)(:))',
|
||||
while: '(?=not)possible',
|
||||
name: [scopes.resultBlock.result.meta, scopes.resultBlock.result.metaSingleLine].join(' '),
|
||||
beginCaptures: {
|
||||
"0": { name: scopes.resultBlock.result.prefix.meta },
|
||||
"1": { name: scopes.resultBlock.result.prefix.metaMatch },
|
||||
"2": { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||
"3": { name: scopes.resultBlock.result.prefix.colon },
|
||||
'0': { name: scopes.resultBlock.result.prefix.meta },
|
||||
'1': { name: scopes.resultBlock.result.prefix.metaMatch },
|
||||
'2': { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||
'3': { name: scopes.resultBlock.result.prefix.colon },
|
||||
},
|
||||
patterns: [{ include: scope }]
|
||||
}
|
||||
|
@ -149,10 +148,10 @@ mappings.forEach(([ext, scope, regexp]) =>
|
|||
|
||||
const header = [
|
||||
{
|
||||
begin: "^(# Query): ",
|
||||
end: "\n",
|
||||
begin: '^(# Query): ',
|
||||
end: '\n',
|
||||
name: scopes.header.meta,
|
||||
beginCaptures: { "1": { name: scopes.header.key }, },
|
||||
beginCaptures: { '1': { name: scopes.header.key }, },
|
||||
patterns: [
|
||||
{
|
||||
match: '(\\\\n)|(\\\\\\\\)',
|
||||
|
@ -169,10 +168,10 @@ const header = [
|
|||
]
|
||||
},
|
||||
{
|
||||
begin: "^(# Flags): ",
|
||||
end: "\n",
|
||||
begin: '^(# Flags): ',
|
||||
end: '\n',
|
||||
name: scopes.header.meta,
|
||||
beginCaptures: { "1": { name: scopes.header.key }, },
|
||||
beginCaptures: { '1': { name: scopes.header.key }, },
|
||||
patterns: [
|
||||
{
|
||||
match: '(RegExp|CaseSensitive|IgnoreExcludeSettings|WordMatch)',
|
||||
|
@ -182,10 +181,10 @@ const header = [
|
|||
]
|
||||
},
|
||||
{
|
||||
begin: "^(# ContextLines): ",
|
||||
end: "\n",
|
||||
begin: '^(# ContextLines): ',
|
||||
end: '\n',
|
||||
name: scopes.header.meta,
|
||||
beginCaptures: { "1": { name: scopes.header.key }, },
|
||||
beginCaptures: { '1': { name: scopes.header.key }, },
|
||||
patterns: [
|
||||
{
|
||||
match: '\\d',
|
||||
|
@ -195,42 +194,42 @@ const header = [
|
|||
]
|
||||
},
|
||||
{
|
||||
match: "^(# (?:Including|Excluding)): (.*)$",
|
||||
match: '^(# (?:Including|Excluding)): (.*)$',
|
||||
name: scopes.header.meta,
|
||||
captures: {
|
||||
"1": { name: scopes.header.key },
|
||||
"2": { name: scopes.header.value }
|
||||
'1': { name: scopes.header.key },
|
||||
'2': { name: scopes.header.value }
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const plainText = [
|
||||
{
|
||||
match: "^(?!\\s)(.*?)([^\\\\\\/\\n]*)(:)$",
|
||||
match: '^(?!\\s)(.*?)([^\\\\\\/\\n]*)(:)$',
|
||||
name: [scopes.resultBlock.meta, scopes.resultBlock.path.meta].join(' '),
|
||||
captures: {
|
||||
"1": { name: scopes.resultBlock.path.dirname },
|
||||
"2": { name: scopes.resultBlock.path.basename },
|
||||
"3": { name: scopes.resultBlock.path.colon }
|
||||
'1': { name: scopes.resultBlock.path.dirname },
|
||||
'2': { name: scopes.resultBlock.path.basename },
|
||||
'3': { name: scopes.resultBlock.path.colon }
|
||||
}
|
||||
},
|
||||
{
|
||||
match: "^ (?:((\\d+)(:))|((\\d+)( ))(.*))",
|
||||
match: '^ (?:((\\d+)(:))|((\\d+)( ))(.*))',
|
||||
name: [scopes.resultBlock.meta, scopes.resultBlock.result.meta].join(' '),
|
||||
captures: {
|
||||
"1": { name: [scopes.resultBlock.result.prefix.meta, scopes.resultBlock.result.prefix.metaMatch].join(' ') },
|
||||
"2": { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||
"3": { name: scopes.resultBlock.result.prefix.colon },
|
||||
'1': { name: [scopes.resultBlock.result.prefix.meta, scopes.resultBlock.result.prefix.metaMatch].join(' ') },
|
||||
'2': { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||
'3': { name: scopes.resultBlock.result.prefix.colon },
|
||||
|
||||
"4": { name: [scopes.resultBlock.result.prefix.meta, scopes.resultBlock.result.prefix.metaContext].join(' ') },
|
||||
"5": { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||
'4': { name: [scopes.resultBlock.result.prefix.meta, scopes.resultBlock.result.prefix.metaContext].join(' ') },
|
||||
'5': { name: scopes.resultBlock.result.prefix.lineNumber },
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const tmLanguage = {
|
||||
"information_for_contributors": "This file is generated from ./generateTMLanguage.js.",
|
||||
name: "Search Results",
|
||||
'information_for_contributors': 'This file is generated from ./generateTMLanguage.js.',
|
||||
name: 'Search Results',
|
||||
scopeName: scopes.root,
|
||||
patterns: [
|
||||
...header,
|
||||
|
|
|
@ -189,6 +189,9 @@
|
|||
{
|
||||
"include": "#pl"
|
||||
},
|
||||
{
|
||||
"include": "#pm"
|
||||
},
|
||||
{
|
||||
"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": {
|
||||
"name": "meta.resultBlock.search",
|
||||
"begin": "^(?!\\s)(.*?)([^\\\\\\/\\n]*\\.ps1)(:)$",
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
"vscode-ripgrep": "^1.5.8",
|
||||
"vscode-sqlite3": "4.0.9",
|
||||
"vscode-textmate": "4.4.0",
|
||||
"xterm": "4.4.0",
|
||||
"xterm": "4.5.0-beta.4",
|
||||
"xterm-addon-search": "0.5.0",
|
||||
"xterm-addon-unicode11": "0.1.1",
|
||||
"xterm-addon-web-links": "0.2.1",
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
"vscode-proxy-agent": "^0.5.2",
|
||||
"vscode-ripgrep": "^1.5.8",
|
||||
"vscode-textmate": "4.4.0",
|
||||
"xterm": "4.4.0",
|
||||
"xterm": "4.5.0-beta.4",
|
||||
"xterm-addon-search": "0.5.0",
|
||||
"xterm-addon-unicode11": "0.1.1",
|
||||
"xterm-addon-web-links": "0.2.1",
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"onigasm-umd": "2.2.5",
|
||||
"semver-umd": "^5.5.5",
|
||||
"vscode-textmate": "4.4.0",
|
||||
"xterm": "4.4.0",
|
||||
"xterm": "4.5.0-beta.4",
|
||||
"xterm-addon-search": "0.5.0",
|
||||
"xterm-addon-unicode11": "0.1.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"
|
||||
integrity sha512-hQrvabKCnwXFaEZ+YtoJM9Pm0CIBXL5KSwoU+RiGStU3KYTAcqYP2GsH3dWdvKX6kTWhWLS81dtDsGkfbOciuA==
|
||||
|
||||
xterm@4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.4.0.tgz#5915d3c4c8800fadbcf555a0a603c672ab9df589"
|
||||
integrity sha512-JGIpigWM3EBWvnS3rtBuefkiToIILSK1HYMXy4BCsUpO+O4UeeV+/U1AdAXgCB6qJrnPNb7yLgBsVCQUNMteig==
|
||||
xterm@4.5.0-beta.4:
|
||||
version "4.5.0-beta.4"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.5.0-beta.4.tgz#701f05553b643236d3fcd8bb7f14045bd4537c92"
|
||||
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"
|
||||
integrity sha512-hQrvabKCnwXFaEZ+YtoJM9Pm0CIBXL5KSwoU+RiGStU3KYTAcqYP2GsH3dWdvKX6kTWhWLS81dtDsGkfbOciuA==
|
||||
|
||||
xterm@4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.4.0.tgz#5915d3c4c8800fadbcf555a0a603c672ab9df589"
|
||||
integrity sha512-JGIpigWM3EBWvnS3rtBuefkiToIILSK1HYMXy4BCsUpO+O4UeeV+/U1AdAXgCB6qJrnPNb7yLgBsVCQUNMteig==
|
||||
xterm@4.5.0-beta.4:
|
||||
version "4.5.0-beta.4"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.5.0-beta.4.tgz#701f05553b643236d3fcd8bb7f14045bd4537c92"
|
||||
integrity sha512-Yv1Bf60LTLBMaig1rv033hPz8hQGXZN6VYW2oe/409t2NbJXPg5xZgf47qyaWFV7a5k1BFiwjayJCWaL2nYBew==
|
||||
|
||||
yauzl@^2.9.2:
|
||||
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
|
||||
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%
|
||||
|
||||
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
|
||||
|
||||
# Remote Integration Tests
|
||||
if [ -f ./resources/server/test/test-remote-integration.sh ]; then
|
||||
./resources/server/test/test-remote-integration.sh
|
||||
fi
|
||||
|
||||
# Tests in commonJS
|
||||
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
|
||||
|
|
|
@ -38,6 +38,7 @@ import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/commo
|
|||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
||||
|
||||
class MainThreadNotebookEditor extends Disposable {
|
||||
private _contentChangedEmitter = new Emitter<NotebookContentChange>();
|
||||
|
@ -458,12 +459,17 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
|||
};
|
||||
let isUntitled: boolean = uri.scheme === Schemas.untitled;
|
||||
|
||||
let fileInput;
|
||||
let fileInput: UntitledTextEditorInput | FileEditorInput;
|
||||
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 {
|
||||
fileInput = isUntitled ? this._untitledEditorService.create({ untitledResource: uri, mode: 'notebook', initialValue: options.initialContent }) :
|
||||
this._editorService.createInput({ resource: uri, mode: 'notebook' });
|
||||
if (isUntitled) {
|
||||
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;
|
||||
if (isUntitled) {
|
||||
|
@ -478,7 +484,7 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
|||
await untitledModel.load();
|
||||
input.untitledEditorModel = untitledModel;
|
||||
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));
|
||||
|
|
|
@ -36,6 +36,7 @@ import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/vie
|
|||
import { attachModalDialogStyler, attachPanelStyler } from 'sql/workbench/common/styler';
|
||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { ServiceOptionType } from 'sql/platform/connection/common/interfaces';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
|
||||
export class CategoryView extends ViewPane {
|
||||
|
||||
|
@ -48,9 +49,11 @@ export class CategoryView extends ViewPane {
|
|||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@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
|
||||
|
|
|
@ -24,6 +24,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
|||
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
|
||||
import { SimpleProgressIndicator } from 'sql/workbench/services/progress/browser/simpleProgressIndicator';
|
||||
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/platform/dashboard/browser/interfaces';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
@Component({
|
||||
template: '',
|
||||
|
@ -47,7 +48,8 @@ export default class EditorComponent extends ComponentBase implements IComponent
|
|||
@Inject(IInstantiationService) private _instantiationService: IInstantiationService,
|
||||
@Inject(IModelService) private _modelService: IModelService,
|
||||
@Inject(IModeService) private _modeService: IModeService,
|
||||
@Inject(ILogService) private _logService: ILogService
|
||||
@Inject(ILogService) private _logService: ILogService,
|
||||
@Inject(IEditorService) private readonly editorService: IEditorService
|
||||
) {
|
||||
super(changeRef, el);
|
||||
}
|
||||
|
@ -66,7 +68,7 @@ export default class EditorComponent extends ComponentBase implements IComponent
|
|||
this._editor.create(this._el.nativeElement);
|
||||
this._editor.setVisible(true);
|
||||
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);
|
||||
const model = await this._editorInput.resolve();
|
||||
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 { URI } from 'vs/base/common/uri';
|
||||
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 { WorkbenchAsyncDataTree, TreeResourceNavigator } from 'vs/platform/list/browser/listService';
|
||||
import { localize } from 'vs/nls';
|
||||
|
@ -63,9 +63,11 @@ export class CustomTreeViewPanel extends ViewPane {
|
|||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@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));
|
||||
this.treeView = treeView as ITreeView;
|
||||
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 { attachModalDialogStyler, attachPanelStyler } from 'sql/workbench/common/styler';
|
||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
|
||||
class AccountPanel extends ViewPane {
|
||||
public index: number;
|
||||
|
@ -48,12 +49,13 @@ class AccountPanel extends ViewPane {
|
|||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IThemeService private themeService: IThemeService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@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 {
|
||||
|
@ -130,7 +132,8 @@ export class AccountDialog extends Modal {
|
|||
@IClipboardService clipboardService: IClipboardService,
|
||||
@ILogService logService: ILogService,
|
||||
@IViewDescriptorService private viewDescriptorService: IViewDescriptorService,
|
||||
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService
|
||||
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService,
|
||||
@IOpenerService protected readonly openerService: IOpenerService
|
||||
) {
|
||||
super(
|
||||
localize('linkedAccounts', "Linked accounts"),
|
||||
|
@ -301,7 +304,8 @@ export class AccountDialog extends Modal {
|
|||
this._themeService,
|
||||
this.contextKeyService,
|
||||
this._instantiationService,
|
||||
this.viewDescriptorService
|
||||
this.viewDescriptorService,
|
||||
this.openerService
|
||||
);
|
||||
|
||||
attachPanelStyler(providerView, this._themeService);
|
||||
|
|
|
@ -86,7 +86,7 @@ function createInstantiationService(addAccountFailureEmitter?: Emitter<string>):
|
|||
.returns(() => undefined);
|
||||
|
||||
// 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);
|
||||
mockAccountDialog.setup(x => x.onAddAccountErrorEvent)
|
||||
.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 { assign } from 'vs/base/common/objects';
|
||||
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 {
|
||||
options: IInsightOptions;
|
||||
|
@ -35,7 +37,8 @@ export class CreateInsightAction extends Action {
|
|||
constructor(
|
||||
@IEditorService private editorService: IEditorService,
|
||||
@INotificationService private notificationService: INotificationService,
|
||||
@IUntitledTextEditorService private untitledEditorService: IUntitledTextEditorService
|
||||
@IUntitledTextEditorService private untitledEditorService: IUntitledTextEditorService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||
) {
|
||||
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) });
|
||||
|
||||
return this.editorService.openEditor(input, { pinned: true })
|
||||
return this.editorService.openEditor(this.instantiationService.createInstance(UntitledTextEditorInput, input), { pinned: true })
|
||||
.then(
|
||||
() => true,
|
||||
error => {
|
||||
|
|
|
@ -22,19 +22,18 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
|||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||
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 { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||
import { TestQueryModelService } from 'sql/workbench/services/query/test/common/testQueryModelService';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
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 { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||
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 {
|
||||
[arg: string]: any;
|
||||
|
@ -391,9 +390,11 @@ suite('commandLineService tests', () => {
|
|||
const querymodelService = TypeMoq.Mock.ofType<IQueryModelService>(TestQueryModelService, TypeMoq.MockBehavior.Strict);
|
||||
querymodelService.setup(c => c.onRunQueryStart).returns(() => Event.None);
|
||||
querymodelService.setup(c => c.onRunQueryComplete).returns(() => Event.None);
|
||||
const instantiationService = new TestInstantiationService();
|
||||
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);
|
||||
queryInput.state.connected = true;
|
||||
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 { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
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 {
|
||||
|
||||
|
@ -41,8 +43,10 @@ export class ConnectionViewletPanel extends ViewPane {
|
|||
@IObjectExplorerService private readonly objectExplorerService: IObjectExplorerService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@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,
|
||||
AddServerAction.ID,
|
||||
AddServerAction.LABEL);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* 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 { IQueryModelService } from 'sql/workbench/services/query/common/queryModel';
|
||||
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 { IEditorViewState } from 'vs/editor/common/editorCommon';
|
||||
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.
|
||||
|
@ -61,7 +63,7 @@ export class EditDataInput extends EditorInput implements IConnectableInput {
|
|||
// also set dirty status to false to prevent rerendering.
|
||||
if (this._sql) {
|
||||
this._register(this._sql.onDidChangeDirty(async () => {
|
||||
const model = await this._sql.resolve();
|
||||
const model = await this._sql.resolve() as UntitledTextEditorModel;
|
||||
model.setDirty(false);
|
||||
this._onDidChangeDirty.fire();
|
||||
}));
|
||||
|
@ -222,11 +224,10 @@ export class EditDataInput extends EditorInput implements IConnectableInput {
|
|||
return this._connectionManagementService.getTabColorForUri(this.uri);
|
||||
}
|
||||
|
||||
public get onDidModelChangeEncoding(): Event<void> { return this._sql.onDidModelChangeEncoding; }
|
||||
public resolve(refresh?: boolean): Promise<EditorModel> { return this._sql.resolve(); }
|
||||
public resolve(refresh?: boolean): Promise<IUntitledTextEditorModel & IResolvedTextEditorModel> { return this._sql.resolve(); }
|
||||
public getEncoding(): string { return this._sql.getEncoding(); }
|
||||
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 {
|
||||
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 { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
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);
|
||||
|
||||
|
@ -122,7 +123,10 @@ suite('Editor Replacer Contribution', () => {
|
|||
const instantiationService = workbenchInstantiationService();
|
||||
instantiationService.stub(IEditorService, editorService);
|
||||
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);
|
||||
assert(response?.override);
|
||||
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();
|
||||
instantiationService.stub(IEditorService, editorService);
|
||||
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 response = editorService.fireOpenEditor(input, undefined, undefined as IEditorGroup);
|
||||
assert(response === undefined);
|
||||
|
@ -150,7 +156,9 @@ suite('Editor Replacer Contribution', () => {
|
|||
const instantiationService = workbenchInstantiationService();
|
||||
instantiationService.stub(IEditorService, editorService);
|
||||
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);
|
||||
assert(response === undefined);
|
||||
|
||||
|
@ -254,3 +262,9 @@ class TestModeService implements IModeService {
|
|||
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 cellModelSource: string;
|
||||
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);
|
||||
this.setFocusAndScroll();
|
||||
|
||||
let untitledEditorModel: UntitledTextEditorModel = await this._editorInput.resolve();
|
||||
let untitledEditorModel = await this._editorInput.resolve() as UntitledTextEditorModel;
|
||||
this._editorModel = untitledEditorModel.textEditorModel;
|
||||
|
||||
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 { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||
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 { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
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 { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
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 { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
|
||||
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 _lastEditFullReplacement: boolean;
|
||||
constructor(public readonly notebookUri: URI,
|
||||
private textEditorModel: TextFileEditorModel | UntitledTextEditorModel | ResourceEditorModel,
|
||||
private textEditorModel: ITextFileEditorModel | IUntitledTextEditorModel | ResourceEditorModel,
|
||||
@INotebookService private notebookService: INotebookService,
|
||||
@ITextResourcePropertiesService private textResourcePropertiesService: ITextResourcePropertiesService
|
||||
) {
|
||||
|
@ -198,7 +198,7 @@ export abstract class NotebookInput extends EditorInput {
|
|||
private _parentContainer: HTMLElement;
|
||||
private readonly _layoutChanged: Emitter<void> = this._register(new Emitter<void>());
|
||||
private _model: NotebookEditorModel;
|
||||
private _untitledEditorModel: UntitledTextEditorModel;
|
||||
private _untitledEditorModel: IUntitledTextEditorModel;
|
||||
private _contentManager: IContentManager;
|
||||
private _providersLoaded: Promise<void>;
|
||||
private _dirtyListener: IDisposable;
|
||||
|
@ -328,11 +328,11 @@ export abstract class NotebookInput extends EditorInput {
|
|||
return this.resource;
|
||||
}
|
||||
|
||||
public get untitledEditorModel(): UntitledTextEditorModel {
|
||||
public get untitledEditorModel(): IUntitledTextEditorModel {
|
||||
return this._untitledEditorModel;
|
||||
}
|
||||
|
||||
public set untitledEditorModel(value: UntitledTextEditorModel) {
|
||||
public set untitledEditorModel(value: IUntitledTextEditorModel) {
|
||||
this._untitledEditorModel = value;
|
||||
}
|
||||
|
||||
|
@ -346,7 +346,7 @@ export abstract class NotebookInput extends EditorInput {
|
|||
if (this._model) {
|
||||
return Promise.resolve(this._model);
|
||||
} else {
|
||||
let textOrUntitledEditorModel: TextFileEditorModel | UntitledTextEditorModel | ResourceEditorModel;
|
||||
let textOrUntitledEditorModel: ITextFileEditorModel | IUntitledTextEditorModel | ResourceEditorModel;
|
||||
if (this.resource.scheme === Schemas.untitled) {
|
||||
if (this._untitledEditorModel) {
|
||||
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 { NotebookContentChange, INotebookModel } from 'sql/workbench/contrib/notebook/browser/models/modelInterfaces';
|
||||
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 { ITextEditorModel } from 'vs/workbench/common/editor';
|
||||
|
||||
export class NotebookTextFileModel {
|
||||
// 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);
|
||||
|
||||
// convert the range to leverage offsets in the json
|
||||
|
@ -109,7 +109,7 @@ export class NotebookTextFileModel {
|
|||
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) {
|
||||
let newOutput = JSON.stringify(contentChange.cells[0].outputs[contentChange.cells[0].outputs.length - 1], undefined, ' ');
|
||||
if (contentChange.cells[0].outputs.length > 1) {
|
||||
|
@ -136,7 +136,7 @@ export class NotebookTextFileModel {
|
|||
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);
|
||||
if (executionCountMatch && executionCountMatch.range) {
|
||||
// Execution count can be between 0 and n characters long
|
||||
|
@ -161,7 +161,7 @@ export class NotebookTextFileModel {
|
|||
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) {
|
||||
return false;
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ export class NotebookTextFileModel {
|
|||
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 model = textEditorModel.textEditorModel;
|
||||
let endLine = model.getLineCount();
|
||||
|
@ -190,7 +190,7 @@ export class NotebookTextFileModel {
|
|||
}
|
||||
|
||||
// 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) {
|
||||
return;
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ export class NotebookTextFileModel {
|
|||
}
|
||||
|
||||
// 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) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ export class NotebookTextFileModel {
|
|||
|
||||
// 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
|
||||
private getEndOfOutputs(textEditorModel: BaseTextEditorModel, cellGuid: string) {
|
||||
private getEndOfOutputs(textEditorModel: ITextEditorModel, cellGuid: string) {
|
||||
let outputsBegin;
|
||||
if (this._activeCellGuid === cellGuid) {
|
||||
outputsBegin = this._outputBeginRange;
|
||||
|
@ -272,7 +272,7 @@ export class NotebookTextFileModel {
|
|||
}
|
||||
|
||||
// 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);
|
||||
if (endOutputRange && endOutputRange.endLineNumber) {
|
||||
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
|
||||
// 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) {
|
||||
this.updateSourceBeginRange(textEditorModel, guid);
|
||||
}
|
||||
return this._sourceBeginRange;
|
||||
}
|
||||
|
||||
private getOutputNodeByGuid(textEditorModel: BaseTextEditorModel, guid: string) {
|
||||
private getOutputNodeByGuid(textEditorModel: ITextEditorModel, guid: string) {
|
||||
if (this._activeCellGuid !== 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;
|
||||
}
|
||||
|
||||
function findOrSetCellGuidMatch(textEditorModel: BaseTextEditorModel, cellGuid: string): FindMatch[] {
|
||||
function findOrSetCellGuidMatch(textEditorModel: ITextEditorModel, cellGuid: string): FindMatch[] {
|
||||
if (!textEditorModel || !cellGuid) {
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import * as TypeMoq from 'typemoq';
|
||||
import * as assert from 'assert';
|
||||
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 { URI } from 'vs/base/common/uri';
|
||||
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 { INotebookService, IProviderInfo } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
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 {
|
||||
const instantiationService = workbenchInstantiationService();
|
||||
|
@ -48,7 +48,9 @@ suite('Notebook Input', function (): void {
|
|||
let untitledNotebookInput: UntitledNotebookInput;
|
||||
|
||||
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(
|
||||
testTitle, untitledUri, untitledTextInput,
|
||||
undefined, instantiationService, mockNotebookService.object, mockExtensionService.object);
|
||||
|
@ -169,9 +171,17 @@ suite('Notebook Input', function (): void {
|
|||
assert.ok(untitledNotebookInput.matches(untitledNotebookInput), 'Input should match itself.');
|
||||
|
||||
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);
|
||||
|
||||
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 { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||
import { attachTabbedPanelStyler } from 'sql/workbench/common/styler';
|
||||
import { UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
||||
|
||||
class BasicView implements IView {
|
||||
public get element(): HTMLElement {
|
||||
|
@ -433,7 +434,8 @@ export class ProfilerEditor extends BaseEditor {
|
|||
editorContainer.className = 'profiler-editor';
|
||||
this._editor.create(editorContainer);
|
||||
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._editorInput.resolve().then(model => this._editorModel = model.textEditorModel);
|
||||
return editorContainer;
|
||||
|
|
|
@ -580,8 +580,7 @@ export abstract class GridTableBase<T> extends Disposable implements IView {
|
|||
let content = value.displayValue;
|
||||
|
||||
const input = this.untitledEditorService.create({ mode: column.isXml ? 'xml' : 'json', initialValue: content });
|
||||
const model = await input.resolve();
|
||||
await this.instantiationService.invokeFunction(formatDocumentWithSelectedProvider, model.textEditorModel, FormattingMode.Explicit, CancellationToken.None);
|
||||
await this.instantiationService.invokeFunction(formatDocumentWithSelectedProvider, input.textEditorModel, FormattingMode.Explicit, CancellationToken.None);
|
||||
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 { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
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 {
|
||||
|
||||
public static readonly ID = 'workbench.editorInput.untitledQueryInput';
|
||||
|
||||
public readonly onDidModelChangeEncoding = this.text.onDidModelChangeEncoding;
|
||||
|
||||
constructor(
|
||||
description: string,
|
||||
text: UntitledTextEditorInput,
|
||||
|
@ -31,7 +29,7 @@ export class UntitledQueryEditorInput extends QueryEditorInput implements IEncod
|
|||
super(description, text, results, connectionManagementService, queryModelService, configurationService);
|
||||
}
|
||||
|
||||
public resolve(): Promise<UntitledTextEditorModel & IResolvedTextEditorModel> {
|
||||
public resolve(): Promise<IUntitledTextEditorModel & IResolvedTextEditorModel> {
|
||||
return this.text.resolve();
|
||||
}
|
||||
|
||||
|
@ -40,7 +38,7 @@ export class UntitledQueryEditorInput extends QueryEditorInput implements IEncod
|
|||
}
|
||||
|
||||
public get hasAssociatedFilePath(): boolean {
|
||||
return this.text.hasAssociatedFilePath;
|
||||
return this.text.model.hasAssociatedFilePath;
|
||||
}
|
||||
|
||||
public setMode(mode: string): void {
|
||||
|
|
|
@ -23,17 +23,16 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
|||
|
||||
import * as TypeMoq from 'typemoq';
|
||||
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 { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||
import { TestQueryModelService } from 'sql/workbench/services/query/test/common/testQueryModelService';
|
||||
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 { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
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', () => {
|
||||
|
||||
|
@ -69,8 +68,10 @@ suite('SQL QueryAction Tests', () => {
|
|||
queryModelService.setup(q => q.onRunQueryComplete).returns(() => Event.None);
|
||||
connectionManagementService = TypeMoq.Mock.ofType<TestConnectionManagementService>(TestConnectionManagementService);
|
||||
connectionManagementService.setup(q => q.onDisconnect).returns(() => Event.None);
|
||||
const instantiationService = new TestInstantiationService();
|
||||
let fileInput = new UntitledTextEditorInput(URI.parse('file://testUri'), 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;
|
||||
let fileInput = workbenchinstantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: URI.parse('file://testUri') }));
|
||||
// Setup a reusable mock QueryInput
|
||||
testQueryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Strict, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
|
||||
testQueryInput.setup(x => x.uri).returns(() => testUri);
|
||||
|
@ -174,8 +175,10 @@ suite('SQL QueryAction Tests', () => {
|
|||
let queryModelService = TypeMoq.Mock.ofType(QueryModelService, TypeMoq.MockBehavior.Loose);
|
||||
queryModelService.setup(x => x.onRunQueryStart).returns(() => Event.None);
|
||||
queryModelService.setup(x => x.onRunQueryComplete).returns(() => Event.None);
|
||||
const instantiationService = new TestInstantiationService();
|
||||
let fileInput = new UntitledTextEditorInput(URI.parse('file://testUri'), 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;
|
||||
let fileInput = workbenchinstantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: URI.parse('file://testUri') }));
|
||||
|
||||
// ... Mock "isSelectionEmpty" in QueryEditor
|
||||
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 };
|
||||
|
||||
// ... Mock "getSelection" in QueryEditor
|
||||
const instantiationService = new TestInstantiationService();
|
||||
let fileInput = new UntitledTextEditorInput(URI.parse('file://testUri'), 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;
|
||||
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);
|
||||
queryInput.setup(x => x.uri).returns(() => testUri);
|
||||
|
@ -556,3 +561,9 @@ suite('SQL QueryAction Tests', () => {
|
|||
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 { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
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 { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||
import { TestQueryModelService } from 'sql/workbench/services/query/test/common/testQueryModelService';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { LabelService } from 'vs/workbench/services/label/common/labelService';
|
||||
import { TestCapabilitiesService } from 'sql/platform/capabilities/test/common/testCapabilitiesService';
|
||||
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||
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';
|
||||
|
||||
suite('SQL QueryEditor Tests', () => {
|
||||
|
@ -302,7 +302,10 @@ suite('SQL QueryEditor Tests', () => {
|
|||
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.setup(x => x.disposeQuery(TypeMoq.It.isAny()));
|
||||
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 { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||
|
||||
suite('Query Input Factory', () => {
|
||||
|
||||
|
@ -63,13 +64,22 @@ suite('Query Input Factory', () => {
|
|||
|
||||
});
|
||||
|
||||
class ServiceAccessor {
|
||||
constructor(
|
||||
@IUntitledTextEditorService public readonly untitledTextEditorService: IUntitledTextEditorService
|
||||
) { }
|
||||
}
|
||||
|
||||
class MockEditorService extends TestEditorService {
|
||||
public readonly activeEditor: IEditorInput | undefined = undefined;
|
||||
|
||||
constructor(instantiationService?: IInstantiationService) {
|
||||
super();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
|||
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
import { attachPanelStyler, attachModalDialogStyler } from 'sql/workbench/common/styler';
|
||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
|
||||
const labelDisplay = nls.localize("insights.item", "Item");
|
||||
const valueDisplay = nls.localize("insights.value", "Value");
|
||||
|
@ -66,9 +67,11 @@ class InsightTableView<T> extends ViewPane {
|
|||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@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 {
|
||||
|
|
|
@ -21,6 +21,8 @@ import { replaceConnection } from 'sql/workbench/browser/taskUtilities';
|
|||
import { EditDataResultsInput } from 'sql/workbench/contrib/editData/browser/editDataResultsInput';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
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
|
||||
|
@ -52,8 +54,8 @@ export class QueryEditorService implements IQueryEditorService {
|
|||
let docUri: URI = URI.from({ scheme: Schemas.untitled, path: filePath });
|
||||
|
||||
// Create a sql document pane with accoutrements
|
||||
const fileInput = this._untitledEditorService.create({ associatedResource: docUri, mode: 'sql' });
|
||||
let untitledEditorModel = await fileInput.resolve();
|
||||
const fileInput = this._editorService.createInput({ forceUntitled: true, resource: docUri, mode: 'sql' }) as UntitledTextEditorInput;
|
||||
let untitledEditorModel = await fileInput.resolve() as UntitledTextEditorModel;
|
||||
if (sqlContent) {
|
||||
untitledEditorModel.textEditorModel.setValue(sqlContent);
|
||||
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 });
|
||||
|
||||
// Create a sql document pane with accoutrements
|
||||
const fileInput = this._untitledEditorService.create({ associatedResource: docUri, mode: 'sql' });
|
||||
const m = await fileInput.resolve();
|
||||
const fileInput = this._editorService.createInput({ forceUntitled: true, resource: docUri, mode: 'sql' }) as UntitledTextEditorInput;
|
||||
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.
|
||||
m.setDirty(false);
|
||||
// Create an EditDataInput for editing
|
||||
|
|
|
@ -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';
|
||||
|
||||
export interface IButtonOptions extends IButtonStyles {
|
||||
title?: boolean;
|
||||
title?: boolean | string;
|
||||
}
|
||||
|
||||
export interface IButtonStyles {
|
||||
|
@ -151,10 +151,10 @@ export class Button extends Disposable {
|
|||
DOM.addClass(this._element, 'monaco-text-button');
|
||||
}
|
||||
this._element.textContent = value;
|
||||
//{{SQL CARBON EDIT}}
|
||||
this._element.setAttribute('aria-label', value);
|
||||
//{{END}}
|
||||
if (this.options.title) {
|
||||
this._element.setAttribute('aria-label', value); // {{SQL CARBON EDIT}}
|
||||
if (typeof this.options.title === 'string') {
|
||||
this._element.title = this.options.title;
|
||||
} else if (this.options.title) {
|
||||
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 { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { IBoundarySashes } from 'vs/base/browser/ui/grid/gridview';
|
||||
|
||||
export interface CenteredViewState {
|
||||
leftMarginRatio: number;
|
||||
|
@ -72,6 +73,19 @@ export class CenteredViewLayout implements IDisposable {
|
|||
get maximumHeight(): number { return this.view.maximumHeight; }
|
||||
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 {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
@ -119,6 +133,8 @@ export class CenteredViewLayout implements IDisposable {
|
|||
orientation: Orientation.HORIZONTAL,
|
||||
styles: this.style
|
||||
});
|
||||
this.splitView.orthogonalStartSash = this.boundarySashes.top;
|
||||
this.splitView.orthogonalEndSash = this.boundarySashes.bottom;
|
||||
|
||||
this.splitViewDisposables.add(this.splitView.onDidSashChange(() => {
|
||||
if (this.splitView) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
@font-face {
|
||||
font-family: "codicon";
|
||||
src: url("./codicon.ttf?be537a78617db0869caa4b4cc683a24a") format("truetype");
|
||||
src: url("./codicon.ttf?6caeeccc06315e827f3bff83885456fb") format("truetype");
|
||||
}
|
||||
|
||||
.codicon[class*='codicon-'] {
|
||||
|
@ -413,4 +413,5 @@
|
|||
.codicon-feedback:before { content: "\eb96" }
|
||||
.codicon-group-by-ref-type:before { content: "\eb97" }
|
||||
.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" }
|
||||
|
|
Двоичные данные
src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf
Двоичные данные
src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf
Двоичный файл не отображается.
|
@ -7,7 +7,7 @@ import 'vs/css!./gridview';
|
|||
import { Orientation } from 'vs/base/browser/ui/sash/sash';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
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';
|
||||
|
||||
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 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; }
|
||||
|
||||
private didLayout = false;
|
||||
|
|
|
@ -21,6 +21,20 @@ export interface IViewSize {
|
|||
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 {
|
||||
readonly element: HTMLElement;
|
||||
readonly minimumWidth: number;
|
||||
|
@ -32,6 +46,7 @@ export interface IView {
|
|||
readonly snap?: boolean;
|
||||
layout(width: number, height: number, top: number, left: number): void;
|
||||
setVisible?(visible: boolean): void;
|
||||
setBoundarySashes?(sashes: IBoundarySashes): void;
|
||||
}
|
||||
|
||||
export interface ISerializableView extends IView {
|
||||
|
@ -125,6 +140,22 @@ interface ILayoutContext {
|
|||
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 {
|
||||
|
||||
readonly element: HTMLElement;
|
||||
|
@ -217,10 +248,27 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
|
|||
private splitviewSashResetDisposable: IDisposable = Disposable.None;
|
||||
private childrenSashResetDisposable: IDisposable = Disposable.None;
|
||||
|
||||
get orthogonalStartSash(): Sash | undefined { return this.splitview.orthogonalStartSash; }
|
||||
set orthogonalStartSash(sash: Sash | undefined) { this.splitview.orthogonalStartSash = sash; }
|
||||
get orthogonalEndSash(): Sash | undefined { return this.splitview.orthogonalEndSash; }
|
||||
set orthogonalEndSash(sash: Sash | undefined) { this.splitview.orthogonalEndSash = sash; }
|
||||
private _boundarySashes: IRelativeBoundarySashes = {};
|
||||
get boundarySashes(): IRelativeBoundarySashes { return this._boundarySashes; }
|
||||
set boundarySashes(boundarySashes: IRelativeBoundarySashes) {
|
||||
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(
|
||||
readonly orientation: Orientation,
|
||||
|
@ -260,9 +308,15 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
|
|||
this.splitview = new SplitView(this.element, { ...options, descriptor });
|
||||
|
||||
this.children.forEach((node, index) => {
|
||||
// Set up orthogonal sashes for children
|
||||
node.orthogonalStartSash = this.splitview.sashes[index - 1];
|
||||
node.orthogonalEndSash = this.splitview.sashes[index];
|
||||
const first = index === 0;
|
||||
const last = index === this.children.length;
|
||||
|
||||
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 last = index === this.children.length;
|
||||
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) {
|
||||
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) {
|
||||
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);
|
||||
|
||||
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]
|
||||
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;
|
||||
|
@ -408,7 +479,12 @@ class BranchNode implements ISplitView<ILayoutContext>, IDisposable {
|
|||
to = clamp(to, 0, this.children.length);
|
||||
|
||||
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.onDidChildrenChange();
|
||||
|
@ -655,12 +731,14 @@ class LeafNode implements ISplitView<ILayoutContext>, IDisposable {
|
|||
return this.orientation === Orientation.HORIZONTAL ? this.maximumWidth : this.maximumHeight;
|
||||
}
|
||||
|
||||
set orthogonalStartSash(sash: Sash) {
|
||||
// noop
|
||||
}
|
||||
private _boundarySashes: IRelativeBoundarySashes = {};
|
||||
get boundarySashes(): IRelativeBoundarySashes { return this._boundarySashes; }
|
||||
set boundarySashes(boundarySashes: IRelativeBoundarySashes) {
|
||||
this._boundarySashes = boundarySashes;
|
||||
|
||||
set orthogonalEndSash(sash: Sash) {
|
||||
// noop
|
||||
if (this.view.setBoundarySashes) {
|
||||
this.view.setBoundarySashes(toAbsoluteBoundarySashes(boundarySashes, this.orientation));
|
||||
}
|
||||
}
|
||||
|
||||
layout(size: number, offset: number, ctx: ILayoutContext | undefined): void {
|
||||
|
@ -764,6 +842,7 @@ export class GridView implements IDisposable {
|
|||
const { size, orthogonalSize } = this._root;
|
||||
this.root = flipNode(this._root, orthogonalSize, size);
|
||||
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; }
|
||||
|
@ -777,6 +856,13 @@ export class GridView implements IDisposable {
|
|||
private _onDidChange = new Relay<IViewSize | undefined>();
|
||||
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
|
||||
* 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
|
||||
parent.removeChild(0);
|
||||
this.root = sibling;
|
||||
this.boundarySashes = this.boundarySashes;
|
||||
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 {
|
||||
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 {
|
||||
browserEvent: e.browserEvent,
|
||||
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 {
|
||||
browserEvent: e.browserEvent,
|
||||
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));
|
||||
}
|
||||
|
||||
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 (deep) {
|
||||
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>,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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');
|
||||
}
|
||||
|
||||
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 selection = this.getSelection().map(getId);
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ export class ObjectTree<T extends NonNullable<any>, TFilterData = void> extends
|
|||
renderers: ITreeRenderer<T, TFilterData, any>[],
|
||||
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 {
|
||||
|
@ -181,7 +181,7 @@ export class CompressibleObjectTree<T extends NonNullable<any>, TFilterData = vo
|
|||
) {
|
||||
const compressedTreeNodeProvider = () => this;
|
||||
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 {
|
||||
|
|
|
@ -79,35 +79,47 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
|||
const insertedElements = new Set<T | null>();
|
||||
const insertedElementIds = new Set<string>();
|
||||
|
||||
const _onDidCreateNode = (node: ITreeNode<T, TFilterData>) => {
|
||||
insertedElements.add(node.element);
|
||||
this.nodes.set(node.element, node);
|
||||
const _onDidCreateNode = (node: ITreeNode<T | null, TFilterData>) => {
|
||||
if (node.element === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tnode = node as ITreeNode<T, TFilterData>;
|
||||
|
||||
insertedElements.add(tnode.element);
|
||||
this.nodes.set(tnode.element, tnode);
|
||||
|
||||
if (this.identityProvider) {
|
||||
const id = this.identityProvider.getId(node.element).toString();
|
||||
const id = this.identityProvider.getId(tnode.element).toString();
|
||||
insertedElementIds.add(id);
|
||||
this.nodesByIdentity.set(id, node);
|
||||
this.nodesByIdentity.set(id, tnode);
|
||||
}
|
||||
|
||||
if (onDidCreateNode) {
|
||||
onDidCreateNode(node);
|
||||
onDidCreateNode(tnode);
|
||||
}
|
||||
};
|
||||
|
||||
const _onDidDeleteNode = (node: ITreeNode<T, TFilterData>) => {
|
||||
if (!insertedElements.has(node.element)) {
|
||||
this.nodes.delete(node.element);
|
||||
const _onDidDeleteNode = (node: ITreeNode<T | null, TFilterData>) => {
|
||||
if (node.element === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tnode = node as ITreeNode<T, TFilterData>;
|
||||
|
||||
if (!insertedElements.has(tnode.element)) {
|
||||
this.nodes.delete(tnode.element);
|
||||
}
|
||||
|
||||
if (this.identityProvider) {
|
||||
const id = this.identityProvider.getId(node.element).toString();
|
||||
const id = this.identityProvider.getId(tnode.element).toString();
|
||||
if (!insertedElementIds.has(id)) {
|
||||
this.nodesByIdentity.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
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';
|
||||
|
||||
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
|
||||
*/
|
||||
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);
|
||||
return { dispose() { clearTimeout(handle); } };
|
||||
} as Event<any>);
|
||||
});
|
||||
|
||||
export namespace CancellationToken {
|
||||
|
||||
|
|
|
@ -85,6 +85,8 @@ export namespace Event {
|
|||
* Given a collection of events, returns a single event which emits
|
||||
* 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> {
|
||||
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>;
|
||||
forEach(fn: (i: T) => void): 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>;
|
||||
latch(): 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));
|
||||
}
|
||||
|
||||
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> {
|
||||
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 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)) {
|
||||
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
|
||||
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 * as yazl from 'yazl';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
export interface IExtractOptions {
|
||||
overwrite?: boolean;
|
||||
|
@ -80,7 +79,7 @@ function extractEntry(stream: Readable, fileName: string, mode: number, targetPa
|
|||
|
||||
let istream: WriteStream;
|
||||
|
||||
Event.once(token.onCancellationRequested)(() => {
|
||||
token.onCancellationRequested(() => {
|
||||
if (istream) {
|
||||
istream.destroy();
|
||||
}
|
||||
|
@ -107,7 +106,7 @@ function extractZip(zipfile: ZipFile, targetPath: string, options: IOptions, tok
|
|||
let last = createCancelablePromise<void>(() => Promise.resolve());
|
||||
let extractedEntriesCount = 0;
|
||||
|
||||
Event.once(token.onCancellationRequested)(() => {
|
||||
token.onCancellationRequested(() => {
|
||||
last.cancel();
|
||||
zipfile.close();
|
||||
});
|
||||
|
|
|
@ -141,8 +141,8 @@ export class ItemRegistry {
|
|||
readonly onDidCollapseItem: Event<IItemCollapseEvent> = this._onDidCollapseItem.event;
|
||||
private _onDidAddTraitItem = new EventMultiplexer<IItemTraitEvent>();
|
||||
readonly onDidAddTraitItem: Event<IItemTraitEvent> = this._onDidAddTraitItem.event;
|
||||
private _onDidRemoveTraitItem = new EventMultiplexer<IItemCollapseEvent>();
|
||||
readonly onDidRemoveTraitItem: Event<IItemCollapseEvent> = this._onDidRemoveTraitItem.event;
|
||||
private _onDidRemoveTraitItem = new EventMultiplexer<IItemTraitEvent>();
|
||||
readonly onDidRemoveTraitItem: Event<IItemTraitEvent> = this._onDidRemoveTraitItem.event;
|
||||
private _onDidRefreshItem = new EventMultiplexer<Item>();
|
||||
readonly onDidRefreshItem: Event<Item> = this._onDidRefreshItem.event;
|
||||
private _onRefreshItemChildren = new EventMultiplexer<IItemChildrenRefreshEvent>();
|
||||
|
@ -273,8 +273,8 @@ export class Item {
|
|||
readonly onDidCollapse: Event<IItemCollapseEvent> = this._onDidCollapse.event;
|
||||
private readonly _onDidAddTrait = new Emitter<IItemTraitEvent>();
|
||||
readonly onDidAddTrait: Event<IItemTraitEvent> = this._onDidAddTrait.event;
|
||||
private readonly _onDidRemoveTrait = new Emitter<IItemCollapseEvent>();
|
||||
readonly onDidRemoveTrait: Event<IItemCollapseEvent> = this._onDidRemoveTrait.event;
|
||||
private readonly _onDidRemoveTrait = new Emitter<IItemTraitEvent>();
|
||||
readonly onDidRemoveTrait: Event<IItemTraitEvent> = this._onDidRemoveTrait.event;
|
||||
private readonly _onDidRefresh = new Emitter<Item>();
|
||||
readonly onDidRefresh: Event<Item> = this._onDidRefresh.event;
|
||||
private readonly _onRefreshChildren = new Emitter<IItemChildrenRefreshEvent>();
|
||||
|
@ -895,8 +895,8 @@ export class TreeModel {
|
|||
readonly onDidCollapseItem: Event<IItemCollapseEvent> = this._onDidCollapseItem.event;
|
||||
private _onDidAddTraitItem = new Relay<IItemTraitEvent>();
|
||||
readonly onDidAddTraitItem: Event<IItemTraitEvent> = this._onDidAddTraitItem.event;
|
||||
private _onDidRemoveTraitItem = new Relay<IItemCollapseEvent>();
|
||||
readonly onDidRemoveTraitItem: Event<IItemCollapseEvent> = this._onDidRemoveTraitItem.event;
|
||||
private _onDidRemoveTraitItem = new Relay<IItemTraitEvent>();
|
||||
readonly onDidRemoveTraitItem: Event<IItemTraitEvent> = this._onDidRemoveTraitItem.event;
|
||||
private _onDidRefreshItem = new Relay<Item>();
|
||||
readonly onDidRefreshItem: Event<Item> = this._onDidRefreshItem.event;
|
||||
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)));
|
||||
|
||||
// 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.preventDefault();
|
||||
|
||||
|
|
|
@ -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/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');
|
||||
|
|
|
@ -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.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
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 { CancellationToken } from 'vs/base/common/cancellation';
|
||||
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 { isEqual } from 'vs/base/common/resources';
|
||||
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 {
|
||||
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 () {
|
||||
|
||||
// Find config by checking for DOM
|
||||
|
@ -343,6 +380,7 @@ class WorkspaceProvider implements IWorkspaceProvider {
|
|||
...config,
|
||||
workspaceProvider: new WorkspaceProvider(workspace, payload),
|
||||
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);
|
||||
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);
|
||||
await configurationService.initialize();
|
||||
|
||||
// Storage
|
||||
const storageService = new NativeStorageService(new GlobalStorageDatabaseChannelClient(mainProcessService.getChannel('storage')), logService, environmentService);
|
||||
await storageService.initialize();
|
||||
services.set(IStorageService, storageService);
|
||||
|
@ -136,19 +146,9 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
|
|||
services.set(IRequestService, new SyncDescriptor(RequestService));
|
||||
services.set(ILoggerService, new SyncDescriptor(LoggerService));
|
||||
|
||||
|
||||
const electronService = createChannelSender<IElectronService>(mainProcessService.getChannel('electron'), { context: configuration.windowId });
|
||||
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));
|
||||
|
||||
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 { registerContextMenuListener } from 'vs/base/parts/contextmenu/electron-main/contextmenu';
|
||||
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 { Schemas } from 'vs/base/common/network';
|
||||
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 { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc';
|
||||
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 { IElectronMainService, ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService';
|
||||
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> {
|
||||
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) {
|
||||
case 'win32':
|
||||
services.set(IUpdateService, new SyncDescriptor(Win32UpdateService));
|
||||
|
@ -600,14 +591,42 @@ export class CodeApplication extends Disposable {
|
|||
urlService.registerHandler({
|
||||
async handleURL(uri: URI, options?: IOpenURLOptions): Promise<boolean> {
|
||||
|
||||
// Catch file URLs
|
||||
if (uri.authority === Schemas.file && !!uri.path) {
|
||||
// Catch file/remote URLs
|
||||
if ((uri.authority === Schemas.file || uri.authority === Schemas.vscodeRemote) && !!uri.path) {
|
||||
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;
|
||||
|
|
|
@ -42,6 +42,10 @@ import { once } from 'vs/base/common/functional';
|
|||
import { ISignService } from 'vs/platform/sign/common/sign';
|
||||
import { SignService } from 'vs/platform/sign/node/signService';
|
||||
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 {
|
||||
readonly isExpected = true;
|
||||
|
@ -118,12 +122,16 @@ class CodeMain {
|
|||
const environmentService = accessor.get(IEnvironmentService);
|
||||
const logService = accessor.get(ILogService);
|
||||
const lifecycleMainService = accessor.get(ILifecycleMainService);
|
||||
const fileService = accessor.get(IFileService);
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
|
||||
const mainIpcServer = await this.doStartup(logService, environmentService, lifecycleMainService, instantiationService, true);
|
||||
|
||||
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();
|
||||
});
|
||||
|
@ -143,7 +151,12 @@ class CodeMain {
|
|||
process.once('exit', () => logService.dispose());
|
||||
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(IStateService, new SyncDescriptor(StateService));
|
||||
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]
|
||||
.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
|
||||
const fileService = new FileService(logService);
|
||||
disposables.add(fileService);
|
||||
|
@ -325,6 +315,16 @@ export async function main(argv: ParsedArgs): Promise<void> {
|
|||
disposables.add(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);
|
||||
|
||||
return instantiationService.invokeFunction(async accessor => {
|
||||
|
|
|
@ -103,7 +103,15 @@ export class OpenerService implements IOpenerService {
|
|||
// Default external opener is going through window.open()
|
||||
this._externalOpener = {
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -118,7 +118,7 @@ export class View extends ViewEventHandler {
|
|||
this._context = new ViewContext(configuration, themeService.getTheme(), model, this.eventDispatcher);
|
||||
|
||||
this._register(themeService.onThemeChange(theme => {
|
||||
this._context.theme = theme;
|
||||
this._context.theme.update(theme);
|
||||
this.eventDispatcher.emit(new viewEvents.ViewThemeChangedEvent());
|
||||
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 { MinimapTokensColorTracker } from 'vs/editor/common/viewModel/minimapTokensColorTracker';
|
||||
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 { ViewLineData } from 'vs/editor/common/viewModel/viewModel';
|
||||
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 { Selection } from 'vs/editor/common/core/selection';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
|
@ -109,7 +109,7 @@ class MinimapOptions {
|
|||
|
||||
public readonly backgroundColor: RGBA8;
|
||||
|
||||
constructor(configuration: IConfiguration, theme: ITheme, tokensColorTracker: MinimapTokensColorTracker) {
|
||||
constructor(configuration: IConfiguration, theme: EditorTheme, tokensColorTracker: MinimapTokensColorTracker) {
|
||||
const options = configuration.options;
|
||||
const pixelRatio = options.get(EditorOption.pixelRatio);
|
||||
const layoutInfo = options.get(EditorOption.layoutInfo);
|
||||
|
@ -137,7 +137,7 @@ class MinimapOptions {
|
|||
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);
|
||||
if (themeColor) {
|
||||
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 { editorCursorForeground, editorOverviewRulerBorder } from 'vs/editor/common/view/editorColorRegistry';
|
||||
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 { ITheme } from 'vs/platform/theme/common/themeService';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
class Settings {
|
||||
|
@ -42,7 +41,7 @@ class Settings {
|
|||
public readonly x: number[];
|
||||
public readonly w: number[];
|
||||
|
||||
constructor(config: IConfiguration, theme: ITheme) {
|
||||
constructor(config: IConfiguration, theme: EditorTheme) {
|
||||
const options = config.options;
|
||||
this.lineHeight = options.get(EditorOption.lineHeight);
|
||||
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 { ignoreBracketsInToken } from 'vs/editor/common/modes/supports';
|
||||
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 { VSBufferReadableStream, VSBuffer } from 'vs/base/common/buffer';
|
||||
import { TokensStore, MultilineTokens, countEOL, MultilineTokens2, TokensStore2 } from 'vs/editor/common/model/tokensStore';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||
|
||||
function createTextBufferBuilder() {
|
||||
return new PieceTreeTextBufferBuilder();
|
||||
|
@ -2945,7 +2946,7 @@ export class ModelDecorationOverviewRulerOptions extends DecorationOptions {
|
|||
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 (theme.type !== 'light' && this.darkColor) {
|
||||
this._resolvedColor = this._resolveColor(this.darkColor, theme);
|
||||
|
@ -2960,7 +2961,7 @@ export class ModelDecorationOverviewRulerOptions extends DecorationOptions {
|
|||
this._resolvedColor = null;
|
||||
}
|
||||
|
||||
private _resolveColor(color: string | ThemeColor, theme: ITheme): string {
|
||||
private _resolveColor(color: string | ThemeColor, theme: EditorTheme): string {
|
||||
if (typeof color === 'string') {
|
||||
return color;
|
||||
}
|
||||
|
@ -2982,7 +2983,7 @@ export class ModelDecorationMinimapOptions extends DecorationOptions {
|
|||
this.position = options.position;
|
||||
}
|
||||
|
||||
public getColor(theme: ITheme): Color | undefined {
|
||||
public getColor(theme: EditorTheme): Color | undefined {
|
||||
if (!this._resolvedColor) {
|
||||
if (theme.type !== 'light' && this.darkColor) {
|
||||
this._resolvedColor = this._resolveColor(this.darkColor, theme);
|
||||
|
@ -2998,7 +2999,7 @@ export class ModelDecorationMinimapOptions extends DecorationOptions {
|
|||
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') {
|
||||
return Color.fromHex(color);
|
||||
}
|
||||
|
|
|
@ -615,7 +615,9 @@ export interface CodeActionProvider {
|
|||
/**
|
||||
* 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
|
||||
|
|
|
@ -7,7 +7,30 @@ import { IConfiguration } from 'vs/editor/common/editorCommon';
|
|||
import { ViewEventDispatcher } from 'vs/editor/common/view/viewEventDispatcher';
|
||||
import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';
|
||||
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 {
|
||||
|
||||
|
@ -15,8 +38,7 @@ export class ViewContext {
|
|||
public readonly model: IViewModel;
|
||||
public readonly viewLayout: IViewLayout;
|
||||
public readonly privateViewEventBus: ViewEventDispatcher;
|
||||
|
||||
public theme: ITheme; // will be updated
|
||||
public readonly theme: EditorTheme;
|
||||
|
||||
constructor(
|
||||
configuration: IConfiguration,
|
||||
|
@ -25,7 +47,7 @@ export class ViewContext {
|
|||
privateViewEventBus: ViewEventDispatcher
|
||||
) {
|
||||
this.configuration = configuration;
|
||||
this.theme = theme;
|
||||
this.theme = new EditorTheme(theme);
|
||||
this.model = model;
|
||||
this.viewLayout = model.viewLayout;
|
||||
this.privateViewEventBus = privateViewEventBus;
|
||||
|
|
|
@ -13,9 +13,9 @@ import { ModelDecorationOptions, ModelDecorationOverviewRulerOptions } from 'vs/
|
|||
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||
import { PrefixSumIndexOfResult } from 'vs/editor/common/viewModel/prefixSumComputer';
|
||||
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 { FontInfo } from 'vs/editor/common/config/fontInfo';
|
||||
import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||
|
||||
export class OutputPosition {
|
||||
outputLineIndex: number;
|
||||
|
@ -131,7 +131,7 @@ export interface IViewModelLinesCollection extends IDisposable {
|
|||
getViewLineData(viewLineNumber: number): ViewLineData;
|
||||
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[];
|
||||
}
|
||||
|
||||
|
@ -940,7 +940,7 @@ export class SplitLinesCollection implements IViewModelLinesCollection {
|
|||
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 result = new OverviewRulerDecorations();
|
||||
for (const decoration of decorations) {
|
||||
|
@ -1561,7 +1561,7 @@ export class IdentityLinesCollection implements IViewModelLinesCollection {
|
|||
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 result = new OverviewRulerDecorations();
|
||||
for (const decoration of decorations) {
|
||||
|
|
|
@ -14,7 +14,7 @@ import { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecorationOptions, T
|
|||
import { IViewEventListener } from 'vs/editor/common/view/viewEvents';
|
||||
import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
|
||||
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 {
|
||||
readonly id: string;
|
||||
|
@ -127,7 +127,7 @@ export interface IViewModel {
|
|||
getLineMaxColumn(lineNumber: number): number;
|
||||
getLineFirstNonWhitespaceColumn(lineNumber: number): number;
|
||||
getLineLastNonWhitespaceColumn(lineNumber: number): number;
|
||||
getAllOverviewRulerDecorations(theme: ITheme): IOverviewRulerDecorations;
|
||||
getAllOverviewRulerDecorations(theme: EditorTheme): IOverviewRulerDecorations;
|
||||
invalidateOverviewRulerColorCache(): void;
|
||||
invalidateMinimapColorCache(): void;
|
||||
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 { ICoordinatesConverter, IOverviewRulerDecorations, IViewModel, MinimapLinesRenderingData, ViewLineData, ViewLineRenderingData, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations';
|
||||
import { ITheme } from 'vs/platform/theme/common/themeService';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* 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 { illegalArgument, isPromiseCanceledError, onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
@ -27,6 +27,8 @@ export interface CodeActionSet extends IDisposable {
|
|||
readonly validActions: readonly modes.CodeAction[];
|
||||
readonly allActions: readonly modes.CodeAction[];
|
||||
readonly hasAutoFix: boolean;
|
||||
|
||||
readonly documentation: readonly modes.Command[];
|
||||
}
|
||||
|
||||
class ManagedCodeActionSet extends Disposable implements CodeActionSet {
|
||||
|
@ -48,7 +50,11 @@ class ManagedCodeActionSet extends Disposable implements CodeActionSet {
|
|||
public readonly validActions: 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();
|
||||
this._register(disposables);
|
||||
this.allActions = mergeSort([...actions], ManagedCodeActionSet.codeActionsComparator);
|
||||
|
@ -80,17 +86,23 @@ export function getCodeActions(
|
|||
const promises = providers.map(async provider => {
|
||||
try {
|
||||
const providedCodeActions = await provider.provideCodeActions(model, rangeOrSelection, codeActionContext, cts.token);
|
||||
if (cts.token.isCancellationRequested || !providedCodeActions) {
|
||||
return [];
|
||||
if (providedCodeActions) {
|
||||
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) {
|
||||
if (isPromiseCanceledError(err)) {
|
||||
throw err;
|
||||
}
|
||||
onUnexpectedExternalError(err);
|
||||
return [];
|
||||
return { actions: [] as modes.CodeAction[], documentation: undefined };
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -101,9 +113,11 @@ export function getCodeActions(
|
|||
}
|
||||
});
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(flatten)
|
||||
.then(actions => new ManagedCodeActionSet(actions, disposables))
|
||||
return Promise.all(promises).then(actions => {
|
||||
const allActions = flatten(actions.map(x => x.actions));
|
||||
const allDocumentation = coalesce(actions.map(x => x.documentation));
|
||||
return new ManagedCodeActionSet(allActions, allDocumentation, disposables);
|
||||
})
|
||||
.finally(() => {
|
||||
listener.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>> {
|
||||
const { resource, rangeOrSelection, kind } = args;
|
||||
if (!(resource instanceof URI)) {
|
||||
|
|
|
@ -14,9 +14,9 @@ import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
|||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
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 { 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 { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
|
||||
|
@ -84,7 +84,7 @@ export class CodeActionMenu extends Disposable {
|
|||
this._visible = true;
|
||||
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 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 result: IAction[] = actionsToShow
|
||||
.map(toCodeActionAction);
|
||||
|
||||
const allDocumentation: Command[] = [...documentation];
|
||||
|
||||
const model = this._editor.getModel();
|
||||
if (model && result.length) {
|
||||
for (const provider of CodeActionProviderRegistry.all(model)) {
|
||||
if (provider._getAdditionalMenuItems) {
|
||||
const items = 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,
|
||||
})));
|
||||
}
|
||||
allDocumentation.push(...provider._getAdditionalMenuItems({ trigger: trigger.type, only: trigger.filter?.include?.value }, actionsToShow));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allDocumentation.length) {
|
||||
result.push(new Separator(), ...allDocumentation.map(command => toCodeActionAction({
|
||||
title: command.title,
|
||||
command: command,
|
||||
})));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* 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 { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { registerModelAndPositionCommand } from 'vs/editor/browser/editorExtensions';
|
||||
|
@ -28,9 +27,18 @@ function getLocationLinks<T>(
|
|||
return undefined;
|
||||
});
|
||||
});
|
||||
return Promise.all(promises)
|
||||
.then(flatten)
|
||||
.then(coalesce);
|
||||
|
||||
return Promise.all(promises).then(values => {
|
||||
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;
|
||||
}
|
||||
|
||||
class ReferencesTree extends WorkbenchAsyncDataTree<ReferencesModel | FileReferences, TreeElement, FuzzyScore> { }
|
||||
|
||||
/**
|
||||
* ZoneWidget that is shown inside the editor
|
||||
*/
|
||||
|
@ -195,7 +197,7 @@ export class ReferenceWidget extends peekView.PeekViewWidget {
|
|||
private readonly _onDidSelectReference = new Emitter<SelectionEvent>();
|
||||
readonly onDidSelectReference = this._onDidSelectReference.event;
|
||||
|
||||
private _tree!: WorkbenchAsyncDataTree<ReferencesModel | FileReferences, TreeElement, FuzzyScore>;
|
||||
private _tree!: ReferencesTree;
|
||||
private _treeContainer!: HTMLElement;
|
||||
private _splitView!: SplitView;
|
||||
private _preview!: ICodeEditor;
|
||||
|
@ -316,8 +318,8 @@ export class ReferenceWidget extends peekView.PeekViewWidget {
|
|||
listBackground: peekView.peekViewResultsBackground
|
||||
}
|
||||
};
|
||||
this._tree = this._instantiationService.createInstance<typeof WorkbenchAsyncDataTree, WorkbenchAsyncDataTree<ReferencesModel | FileReferences, TreeElement, FuzzyScore>>(
|
||||
WorkbenchAsyncDataTree,
|
||||
this._tree = this._instantiationService.createInstance(
|
||||
ReferencesTree,
|
||||
'ReferencesWidget',
|
||||
this._treeContainer,
|
||||
new Delegate(),
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
.monaco-editor .parameter-hints-widget .monaco-scrollable-element,
|
||||
.monaco-editor .parameter-hints-widget .body {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
|
|
@ -137,8 +137,6 @@
|
|||
border-bottom-style: solid;
|
||||
|
||||
padding: 0 8px 0 4px;
|
||||
|
||||
box-shadow: 0 -.5px 3px #ddd;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget.list-right.docs-side > .suggest-status-bar {
|
||||
|
@ -177,6 +175,11 @@
|
|||
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 {
|
||||
margin-left: 4px;
|
||||
opacity: 0.4;
|
||||
|
@ -213,8 +216,8 @@
|
|||
|
||||
/** 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.docs-side .monaco-list .monaco-list-row.focused > .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:not(.string-label) > .contents > .main > .right > .details-label {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
|
@ -228,6 +231,12 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
.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) **/
|
||||
.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;
|
||||
}
|
||||
/** 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.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;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ export const Context = {
|
|||
MakesTextEdit: new RawContextKey('suggestionMakesTextEdit', true),
|
||||
AcceptSuggestionsOnEnter: new RawContextKey<boolean>('acceptSuggestionOnEnter', true),
|
||||
HasInsertAndReplaceRange: new RawContextKey('suggestionHasInsertAndReplaceRange', false),
|
||||
CanResolve: new RawContextKey('suggestionCanResolve', false),
|
||||
};
|
||||
|
||||
export const suggestWidgetStatusbarMenu = new MenuId('suggestWidgetStatusBar');
|
||||
|
@ -34,9 +35,12 @@ export class CompletionItem {
|
|||
|
||||
_brand!: 'ISuggestionItem';
|
||||
|
||||
private static readonly _defaultResolve = () => Promise.resolve();
|
||||
|
||||
readonly resolve: (token: CancellationToken) => Promise<void>;
|
||||
isResolved: boolean = false;
|
||||
|
||||
|
||||
//
|
||||
readonly editStart: IPosition;
|
||||
readonly editInsertEnd: IPosition;
|
||||
|
@ -87,13 +91,13 @@ export class CompletionItem {
|
|||
// create the suggestion resolver
|
||||
const { resolveCompletionItem } = provider;
|
||||
if (typeof resolveCompletionItem !== 'function') {
|
||||
this.resolve = () => Promise.resolve();
|
||||
this.resolve = CompletionItem._defaultResolve;
|
||||
this.isResolved = true;
|
||||
} else {
|
||||
let cached: Promise<void> | undefined;
|
||||
this.resolve = (token) => {
|
||||
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);
|
||||
this.isResolved = true;
|
||||
}, err => {
|
||||
|
|
|
@ -139,10 +139,12 @@ export class SuggestController implements IEditorContribution {
|
|||
// Wire up makes text edit context key
|
||||
const ctxMakesTextEdit = SuggestContext.MakesTextEdit.bindTo(this._contextKeyService);
|
||||
const ctxHasInsertAndReplace = SuggestContext.HasInsertAndReplaceRange.bindTo(this._contextKeyService);
|
||||
const ctxCanResolve = SuggestContext.CanResolve.bindTo(this._contextKeyService);
|
||||
|
||||
this._toDispose.add(toDisposable(() => {
|
||||
ctxMakesTextEdit.reset();
|
||||
ctxHasInsertAndReplace.reset();
|
||||
ctxCanResolve.reset();
|
||||
}));
|
||||
|
||||
this._toDispose.add(widget.onDidFocus(({ item }) => {
|
||||
|
@ -172,6 +174,9 @@ export class SuggestController implements IEditorContribution {
|
|||
|
||||
// (ctx: hasInsertAndReplaceRange)
|
||||
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 => {
|
||||
|
@ -695,13 +700,13 @@ registerEditorCommand(new SuggestCommand({
|
|||
menuId: suggestWidgetStatusbarMenu,
|
||||
group: 'right',
|
||||
order: 1,
|
||||
when: SuggestContext.DetailsVisible,
|
||||
when: ContextKeyExpr.and(SuggestContext.DetailsVisible, SuggestContext.CanResolve),
|
||||
title: nls.localize('detail.more', "show less")
|
||||
}, {
|
||||
menuId: suggestWidgetStatusbarMenu,
|
||||
group: 'right',
|
||||
order: 1,
|
||||
when: SuggestContext.DetailsVisible.toNegated(),
|
||||
when: ContextKeyExpr.and(SuggestContext.DetailsVisible.toNegated(), SuggestContext.CanResolve),
|
||||
title: nls.localize('detail.less', "show more")
|
||||
}]
|
||||
}));
|
||||
|
|
|
@ -244,12 +244,12 @@ class ItemRenderer implements IListRenderer<CompletionItem, ISuggestionTemplateD
|
|||
data.signatureLabel.textContent = '';
|
||||
data.qualifierLabel.textContent = '';
|
||||
data.detailsLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, '');
|
||||
removeClass(data.right, 'always-show-details');
|
||||
addClass(data.root, 'string-label');
|
||||
} else {
|
||||
data.signatureLabel.textContent = (suggestion.label.signature || '').replace(/\n.*$/m, '');
|
||||
data.qualifierLabel.textContent = (suggestion.label.qualifier || '').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)) {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
|
@ -54,12 +54,19 @@ declare namespace monaco {
|
|||
}
|
||||
|
||||
export interface CancellationToken {
|
||||
/**
|
||||
* A flag signalling is cancellation has been requested.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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.
|
||||
|
|
|
@ -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 { Workspace } from 'vs/platform/workspace/common/workspace';
|
||||
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 {
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
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 { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
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 { 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 { 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 {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
|
||||
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>());
|
||||
readonly onDidChangeConfiguration: Event<IConfigurationChangeEvent> = this._onDidChangeConfiguration.event;
|
||||
|
||||
constructor(
|
||||
private readonly settingsResource: URI
|
||||
private readonly settingsResource: URI,
|
||||
fileService: IFileService
|
||||
) {
|
||||
super();
|
||||
this.userConfiguration = this._register(new UserSettings(this.settingsResource, undefined, fileService));
|
||||
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(this.userConfiguration.onDidChange(() => this.reloadConfigurationScheduler.schedule()));
|
||||
}
|
||||
|
||||
initialize(): Promise<void> {
|
||||
if (this.userConfigModelWatcher) {
|
||||
this.userConfigModelWatcher.dispose();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}));
|
||||
});
|
||||
async initialize(): Promise<void> {
|
||||
const userConfiguration = await this.userConfiguration.loadConfiguration();
|
||||
this.configuration = new Configuration(new DefaultConfigurationModel(), userConfiguration);
|
||||
}
|
||||
|
||||
getConfigurationData(): IConfigurationData {
|
||||
|
@ -92,14 +77,9 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
|
|||
return this.configuration.keys(undefined);
|
||||
}
|
||||
|
||||
reloadConfiguration(folder?: IWorkspaceFolder): Promise<void> {
|
||||
if (this.userConfigModelWatcher) {
|
||||
return new Promise<void>(c => this.userConfigModelWatcher!.reload(userConfigModelParser => {
|
||||
this.onDidChangeUserConfiguration(userConfigModelParser.configurationModel);
|
||||
c();
|
||||
}));
|
||||
}
|
||||
return this.initialize();
|
||||
async reloadConfiguration(): Promise<void> {
|
||||
const configurationModel = await this.userConfiguration.loadConfiguration();
|
||||
this.onDidChangeUserConfiguration(configurationModel);
|
||||
}
|
||||
|
||||
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 { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
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', () => {
|
||||
|
||||
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 () => {
|
||||
const res = await testFile('config', 'config.json');
|
||||
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();
|
||||
const config = service.getValue<{
|
||||
foo: string;
|
||||
|
@ -41,7 +59,7 @@ suite('ConfigurationService - Node', () => {
|
|||
|
||||
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();
|
||||
const config = service.getValue<{
|
||||
testworkbench: {
|
||||
|
@ -64,7 +82,7 @@ suite('ConfigurationService - Node', () => {
|
|||
|
||||
fs.writeFileSync(res.testFile, ',,,,');
|
||||
|
||||
const service = new ConfigurationService(URI.file(res.testFile));
|
||||
const service = new ConfigurationService(URI.file(res.testFile), fileService);
|
||||
await service.initialize();
|
||||
const config = service.getValue<{
|
||||
foo: string;
|
||||
|
@ -81,7 +99,7 @@ suite('ConfigurationService - Node', () => {
|
|||
const newDir = path.join(parentDir, 'config', id);
|
||||
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();
|
||||
|
||||
const config = service.getValue<{ foo: string }>();
|
||||
|
@ -90,10 +108,10 @@ suite('ConfigurationService - Node', () => {
|
|||
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 service = new ConfigurationService(URI.file(res.testFile));
|
||||
const service = new ConfigurationService(URI.file(res.testFile), fileService);
|
||||
await service.initialize();
|
||||
return new Promise((c, 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 () => {
|
||||
const res = await testFile('config', 'config.json');
|
||||
|
||||
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();
|
||||
let config = service.getValue<{
|
||||
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();
|
||||
let setting = serviceWithoutFile.getValue<ITestSetting>();
|
||||
|
||||
|
@ -172,7 +209,7 @@ suite('ConfigurationService - Node', () => {
|
|||
return testFile('config', 'config.json').then(async res => {
|
||||
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>();
|
||||
|
||||
|
@ -205,7 +242,7 @@ suite('ConfigurationService - Node', () => {
|
|||
});
|
||||
|
||||
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();
|
||||
|
||||
let res = service.inspect('something.missing');
|
||||
|
@ -243,7 +280,7 @@ suite('ConfigurationService - Node', () => {
|
|||
});
|
||||
|
||||
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();
|
||||
|
||||
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.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ipcMain as ipc, app } from 'electron';
|
||||
import { ipcMain as ipc, app, BrowserWindow } from 'electron';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IStateService } from 'vs/platform/state/node/state';
|
||||
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 { isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||
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';
|
||||
|
||||
export const ILifecycleMainService = createDecorator<ILifecycleMainService>('lifecycleMainService');
|
||||
|
@ -106,7 +106,7 @@ export interface ILifecycleMainService {
|
|||
/**
|
||||
* 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
|
||||
|
@ -550,9 +550,45 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe
|
|||
this.quit().then(veto => quitVetoed = veto);
|
||||
}
|
||||
|
||||
kill(code?: number): void {
|
||||
async kill(code?: number): Promise<void> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -243,11 +243,13 @@ export class WorkbenchList<T> extends List<T> {
|
|||
|
||||
readonly contextKeyService: IContextKeyService;
|
||||
private readonly configurationService: IConfigurationService;
|
||||
private readonly themeService: IThemeService;
|
||||
|
||||
private listHasSelectionOrFocus: IContextKey<boolean>;
|
||||
private listDoubleSelection: IContextKey<boolean>;
|
||||
private listMultiSelection: IContextKey<boolean>;
|
||||
|
||||
private _styler: IDisposable | undefined;
|
||||
private _useAltAsMultipleSelectionModifier: boolean;
|
||||
|
||||
constructor(
|
||||
|
@ -278,6 +280,7 @@ export class WorkbenchList<T> extends List<T> {
|
|||
|
||||
this.contextKeyService = createScopedContextKeyService(contextKeyService, this);
|
||||
this.configurationService = configurationService;
|
||||
this.themeService = themeService;
|
||||
|
||||
const listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);
|
||||
listSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));
|
||||
|
@ -292,7 +295,7 @@ export class WorkbenchList<T> extends List<T> {
|
|||
this.disposables.add((listService as ListService).register(this));
|
||||
|
||||
if (options.overrideStyles) {
|
||||
this.disposables.add(attachListStyler(this, themeService, options.overrideStyles));
|
||||
this.updateStyles(options.overrideStyles);
|
||||
}
|
||||
|
||||
this.disposables.add(this.onSelectionChange(() => {
|
||||
|
@ -313,6 +316,29 @@ export class WorkbenchList<T> extends List<T> {
|
|||
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 {
|
||||
this.disposables.add(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {
|
||||
|
@ -738,7 +764,7 @@ export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void>
|
|||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@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);
|
||||
this.disposables.add(disposable);
|
||||
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,
|
||||
@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);
|
||||
this.disposables.add(disposable);
|
||||
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, options.overrideStyles, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
||||
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> {
|
||||
|
@ -801,7 +835,7 @@ export class WorkbenchDataTree<TInput, T, TFilterData = void> extends DataTree<T
|
|||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@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);
|
||||
this.disposables.add(disposable);
|
||||
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,
|
||||
@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);
|
||||
this.disposables.add(disposable);
|
||||
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,
|
||||
@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);
|
||||
this.disposables.add(disposable);
|
||||
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;
|
||||
}
|
||||
|
||||
private _update(resources: URI[]): void {
|
||||
private _update(resources: readonly URI[]): void {
|
||||
if (!this._data) {
|
||||
return;
|
||||
}
|
||||
|
@ -343,7 +343,7 @@ export class MarkerService implements IMarkerService {
|
|||
|
||||
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) {
|
||||
MarkerService._dedupeMap = Object.create(null);
|
||||
last = [];
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче