Merge from vscode 313ede61cbad8f9dc748907b3384e059ddddb79a (#7436)

* Merge from vscode 313ede61cbad8f9dc748907b3384e059ddddb79a

* fix strict null checks
This commit is contained in:
Anthony Dresser
2019-09-30 23:35:45 -07:00
committed by GitHub
parent 6ab03053a0
commit 084524cd2d
196 changed files with 2927 additions and 2547 deletions

View File

@@ -1,3 +1,3 @@
disturl "https://atom.io/download/electron"
target "6.0.9"
target "4.2.10"
runtime "electron"

View File

@@ -48,7 +48,7 @@ declare namespace monaco.editor {
#include(vs/editor/standalone/common/standaloneThemeService): BuiltinTheme, IStandaloneThemeData, IColors
#include(vs/editor/common/modes/supports/tokenization): ITokenThemeRule
#include(vs/editor/common/services/webWorker): MonacoWebWorker, IWebWorkerOptions
#include(vs/editor/standalone/browser/standaloneCodeEditor): IActionDescriptor, IEditorConstructionOptions, IDiffEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor
#include(vs/editor/standalone/browser/standaloneCodeEditor): IActionDescriptor, IStandaloneEditorConstructionOptions, IDiffEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor
export interface ICommandHandler {
(...args: any[]): void;
}

View File

@@ -6,7 +6,7 @@
"git": {
"name": "chromium",
"repositoryUrl": "https://chromium.googlesource.com/chromium/src",
"commitHash": "91f08db83c2ce8c722ddf0911ead8f7c473bedfa"
"commitHash": "c6a08e5368de4352903e702cde750b33239a50ab"
}
},
"licenseDetail": [
@@ -40,7 +40,7 @@
"SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
],
"isOnlyProductionDependency": true,
"version": "76.0.3809.146"
"version": "69.0.3497.128"
},
{
"component": {
@@ -48,11 +48,11 @@
"git": {
"name": "nodejs",
"repositoryUrl": "https://github.com/nodejs/node",
"commitHash": "64219741218aa87e259cf8257596073b8e747f0a"
"commitHash": "8c70b2084ce5f76ea1e3b3c4ccdeee4483fe338b"
}
},
"isOnlyProductionDependency": true,
"version": "12.4.0"
"version": "10.11.0"
},
{
"component": {
@@ -60,12 +60,12 @@
"git": {
"name": "electron",
"repositoryUrl": "https://github.com/electron/electron",
"commitHash": "407747b48c47cdeed156a73dde1c47609470c95a"
"commitHash": "4e4c7527c63fcf27dffaeb58bde996b8d859c0ed"
}
},
"isOnlyProductionDependency": true,
"license": "MIT",
"version": "6.0.9"
"version": "4.2.10"
},
{
"component": {
@@ -98,11 +98,11 @@
"git": {
"name": "vscode-octicons-font",
"repositoryUrl": "https://github.com/Microsoft/vscode-octicons-font",
"commitHash": "415cd5b42ab699b6b46c0bf011ada0a2ae50bfb4"
"commitHash": "4cbf2bd35cf0084eabd47d322cc58339fd7743cf"
}
},
"license": "MIT",
"version": "1.3.1"
"version": "1.3.2"
},
{
"component": {

View File

@@ -1268,7 +1268,7 @@ export class CommandCenter {
if (pick === saveAndCommit) {
await Promise.all(documents.map(d => d.save()));
await repository.add(documents.map(d => d.uri));
await repository.add([]);
} else if (pick !== commit) {
return false; // do not commit on cancel
}

View File

@@ -10,8 +10,8 @@ import { xhr, XHRResponse, getErrorStatusDescription } from 'request-light';
const localize = nls.loadMessageBundle();
import { workspace, window, languages, commands, ExtensionContext, extensions, Uri, LanguageConfiguration, Diagnostic, StatusBarAlignment, TextEditor } from 'vscode';
import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification, HandleDiagnosticsSignature, ResponseError } from 'vscode-languageclient';
import { workspace, window, languages, commands, ExtensionContext, extensions, Uri, LanguageConfiguration, Diagnostic, StatusBarAlignment, TextEditor, TextDocument, FormattingOptions, CancellationToken, ProviderResult, TextEdit, Range, Disposable } from 'vscode';
import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification, HandleDiagnosticsSignature, ResponseError, DocumentRangeFormattingParams, DocumentRangeFormattingRequest } from 'vscode-languageclient';
import TelemetryReporter from 'vscode-extension-telemetry';
import { hash } from './utils/hash';
@@ -65,6 +65,8 @@ export function activate(context: ExtensionContext) {
let toDispose = context.subscriptions;
let rangeFormatting: Disposable | undefined = undefined;
let packageInfo = getPackageInfo(context);
telemetryReporter = packageInfo && new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
@@ -101,7 +103,8 @@ export function activate(context: ExtensionContext) {
// Register the server for json documents
documentSelector,
initializationOptions: {
handledSchemaProtocols: ['file'] // language server only loads file-URI. Fetching schemas with other protocols ('http'...) are made on the client.
handledSchemaProtocols: ['file'], // language server only loads file-URI. Fetching schemas with other protocols ('http'...) are made on the client.
provideFormatter: false // tell the server to not provide formatting capability and ignore the `json.format.enable` setting.
},
synchronize: {
// Synchronize the setting section 'json' to the server
@@ -224,10 +227,13 @@ export function activate(context: ExtensionContext) {
extensions.onDidChange(_ => {
client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociation(context));
});
// manually register / deregister format provider based on the `html.format.enable` setting avoiding issues with late registration. See #71652.
updateFormatterRegistration();
toDispose.push({ dispose: () => rangeFormatting && rangeFormatting.dispose() });
toDispose.push(workspace.onDidChangeConfiguration(e => e.affectsConfiguration('html.format.enable') && updateFormatterRegistration()));
});
let languageConfiguration: LanguageConfiguration = {
wordPattern: /("(?:[^\\\"]*(?:\\.)?)*"?)|[^\s{}\[\],:]+/,
indentationRules: {
@@ -237,8 +243,35 @@ export function activate(context: ExtensionContext) {
};
languages.setLanguageConfiguration('json', languageConfiguration);
languages.setLanguageConfiguration('jsonc', languageConfiguration);
function updateFormatterRegistration() {
const formatEnabled = workspace.getConfiguration().get('json.format.enable');
if (!formatEnabled && rangeFormatting) {
rangeFormatting.dispose();
rangeFormatting = undefined;
} else if (formatEnabled && !rangeFormatting) {
rangeFormatting = languages.registerDocumentRangeFormattingEditProvider(documentSelector, {
provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult<TextEdit[]> {
let params: DocumentRangeFormattingParams = {
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
range: client.code2ProtocolConverter.asRange(range),
options: client.code2ProtocolConverter.asFormattingOptions(options)
};
return client.sendRequest(DocumentRangeFormattingRequest.type, params, token).then(
client.protocol2CodeConverter.asTextEdits,
(error) => {
client.logFailedRequest(DocumentRangeFormattingRequest.type, error);
return Promise.resolve([]);
}
);
}
});
}
}
}
export function deactivate(): Promise<any> {
return telemetryReporter ? telemetryReporter.dispose() : Promise.resolve(null);
}
@@ -286,7 +319,6 @@ function getSettings(): Settings {
proxyStrictSSL: httpSettings.get('proxyStrictSSL')
},
json: {
format: workspace.getConfiguration('json').get('format'),
schemas: [],
}
};

View File

@@ -104,7 +104,7 @@
"dependencies": {
"request-light": "^0.2.4",
"vscode-extension-telemetry": "0.1.1",
"vscode-languageclient": "^5.3.0-next.6",
"vscode-languageclient": "^6.0.0-next.1",
"vscode-nls": "^4.1.1"
},
"devDependencies": {

View File

@@ -12,7 +12,7 @@ The JSON Language server provides language-specific smarts for editing, validati
The JSON language server supports requests on documents of language id `json` and `jsonc`.
- `json` documents are parsed and validated following the [JSON specification](https://tools.ietf.org/html/rfc7159).
- `jsonc` documents additionally accept single line (`//`) and multi-line comments (`/* ... */`) and accepts trailing commas. JSONC is a VSCode specific file format, intended for VSCode configuration files, without any aspirations to define a new common file format.
- `jsonc` documents additionally accept single line (`//`) and multi-line comments (`/* ... */`). JSONC is a VSCode specific file format, intended for VSCode configuration files, without any aspirations to define a new common file format.
The server implements the following capabilities of the language server protocol:
@@ -40,6 +40,13 @@ The JSON language server has the following dependencies on the client's capabili
## Configuration
### Initialization options
The client can send the following initialization options to the server:
- `provideFormatter: boolean | undefined`. If defined, the value defines wheter the server provides the `documentRangeFormattingProvider` capability on initialization. If undefined, the setting `json.format.enable` is used to determined wheter formatting is provided. The formatter will then be registered through dynamic registration. If the client does not support dynamic registration, no formatter will be available.
- `handledSchemaProtocols`: The URI schemas handles by the server. See section `Schema configuration` below.
### Settings
Clients may send a `workspace/didChangeConfiguration` notification to notify the server of settings changes.
@@ -51,7 +58,7 @@ The server supports the following settings:
- json
- `format`
- `enable`: Whether the server should register the formatting support. This option is only applicable if the client supports *dynamicRegistration* for *rangeFormatting*
- `enable`: Whether the server should register the formatting support. This option is only applicable if the client supports *dynamicRegistration* for *rangeFormatting* and `initializationOptions.provideFormatter` is not defined.
- `schema`: Configures association of file names to schema URL or schemas and/or associations of schema URL to schema content.
- `fileMatch`: an array or file names or paths (separated by `/`). `*` can be used as a wildcard.
- `url`: The URL of the schema, optional when also a schema is provided.

View File

@@ -14,8 +14,8 @@
"dependencies": {
"jsonc-parser": "^2.1.1",
"request-light": "^0.2.4",
"vscode-json-languageservice": "^3.3.4",
"vscode-languageserver": "^5.3.0-next.8",
"vscode-json-languageservice": "^3.3.5",
"vscode-languageserver": "^6.0.0-next.1",
"vscode-nls": "^4.1.1",
"vscode-uri": "^2.0.3"
},

View File

@@ -114,7 +114,7 @@ const documents: TextDocuments = new TextDocuments();
documents.listen(connection);
let clientSnippetSupport = false;
let clientDynamicRegisterSupport = false;
let dynamicFormatterRegistration = false;
let foldingRangeLimit = Number.MAX_VALUE;
let hierarchicalDocumentSymbolSupport = false;
@@ -144,7 +144,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
}
clientSnippetSupport = getClientCapability('textDocument.completion.completionItem.snippetSupport', false);
clientDynamicRegisterSupport = getClientCapability('workspace.symbol.dynamicRegistration', false);
dynamicFormatterRegistration = getClientCapability('textDocument.rangeFormatting.dynamicRegistration', false) && (params.initializationOptions.provideFormatter === undefined);
foldingRangeLimit = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE);
hierarchicalDocumentSymbolSupport = getClientCapability('textDocument.documentSymbol.hierarchicalDocumentSymbolSupport', false);
const capabilities: ServerCapabilities = {
@@ -156,7 +156,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
documentRangeFormattingProvider: false,
colorProvider: {},
foldingRangeProvider: true,
selectionRangeProvider: true
selectionRangeProvider: true,
documentFormattingProvider: params.initializationOptions.provideFormatter === true
};
return { capabilities };
@@ -195,7 +196,7 @@ connection.onDidChangeConfiguration((change) => {
updateConfiguration();
// dynamically enable & disable the formatter
if (clientDynamicRegisterSupport) {
if (dynamicFormatterRegistration) {
const enableFormatter = settings && settings.json && settings.json.format && settings.json.format.enable;
if (enableFormatter) {
if (!formatterRegistration) {

View File

@@ -73,42 +73,41 @@ request-light@^0.2.4:
https-proxy-agent "^2.2.1"
vscode-nls "^4.0.0"
vscode-json-languageservice@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.3.4.tgz#4ff67580491d3a5dc469f4a78643f20adff0278d"
integrity sha512-/nuI4uDBfxyVyeGtBdYwP/tIaXYKOoymUOSozYKLzsmrDmu555gZpzc11LrARa96z92wSaa5hfjTtNMAoM2mxw==
vscode-json-languageservice@^3.3.5:
version "3.3.5"
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.3.5.tgz#e222e8391beeb23cfa40cf17fd57d1594d295fc7"
integrity sha512-Le6SG5aRdrRc5jVeVMRkYbGH9rrVaZHCW0Oa8zCFQ0T8viUud9qdZ29lSv5NPNLwTB8mn4pYucFyyEPM2YWvLA==
dependencies:
jsonc-parser "^2.1.1"
vscode-languageserver-types "^3.15.0-next.2"
vscode-languageserver-types "^3.15.0-next.5"
vscode-nls "^4.1.1"
vscode-uri "^2.0.3"
vscode-jsonrpc@^4.1.0-next.2:
version "4.1.0-next.2"
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.1.0-next.2.tgz#3bd318910a48e631742b290975386e3dae685be3"
integrity sha512-GsBLjP9DxQ42yl1mW9GEIlnSc0+R8mfzhaebwmmTPEJjezD5SPoAo3DFrIAFZha9yvQ1nzZfZlhtVpGQmgxtXg==
vscode-jsonrpc@^5.0.0-next.2:
version "5.0.0-next.2"
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.2.tgz#a44bc03f67069e53f8d8beb88b96c0cacbfefbca"
integrity sha512-Q3/jabZUNviCG9hhF6hHWjhrABevPF9mv0aiE2j8BYCAP2k+aHTpjMyk+04MzaAqWYwXdQuZkLSbcYCCqbzJLg==
vscode-languageserver-protocol@^3.15.0-next.6:
version "3.15.0-next.6"
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.6.tgz#a8aeb7e7dd65da8216b386db59494cdfd3215d92"
integrity sha512-/yDpYlWyNs26mM23mT73xmOFsh1iRfgZfBdHmfAxwDKwpQKLoOSqVidtYfxlK/pD3IEKGcAVnT4WXTsguxxAMQ==
vscode-languageserver-protocol@^3.15.0-next.9:
version "3.15.0-next.9"
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.9.tgz#e768256bd5b580b25bfbc8099bc03bc4c42ebf30"
integrity sha512-b9PAxouMmtsLEe8ZjbIMPb7wRWPhckGfgjwZLmp/dWnaAuRPYtY3lGO0/rNbLc3jKIqCVlnEyYVFKalzDAzj0g==
dependencies:
vscode-jsonrpc "^4.1.0-next.2"
vscode-languageserver-types "^3.15.0-next.2"
vscode-jsonrpc "^5.0.0-next.2"
vscode-languageserver-types "^3.15.0-next.5"
vscode-languageserver-types@^3.15.0-next.2:
version "3.15.0-next.2"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.2.tgz#a0601332cdaafac21931f497bb080cfb8d73f254"
integrity sha512-2JkrMWWUi2rlVLSo9OFR2PIGUzdiowEM8NgNYiwLKnXTjpwpjjIrJbNNxDik7Rv4oo9KtikcFQZKXbrKilL/MQ==
vscode-languageserver-types@^3.15.0-next.5:
version "3.15.0-next.5"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.5.tgz#863d711bf47b338ff5e63ae19fb20d4fcd4d713b"
integrity sha512-7hrELhTeWieUgex3+6692KjCkcmO/+V/bFItM5MHGcBotzwmjEuXjapLLYTYhIspuJ1ibRSik5MhX5YwLpsPiw==
vscode-languageserver@^5.3.0-next.8:
version "5.3.0-next.8"
resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-5.3.0-next.8.tgz#12a4adf60374dbb93e153e08bdca5525f9b2029f"
integrity sha512-6vUb96wsRfrFqndril3gct/FBCSc24OxFZ2iz7kuEuXvLaIcEVOcSZIqQK8oFN7PdbAIaa9nnIpKSy4Yd15cIw==
vscode-languageserver@^6.0.0-next.1:
version "6.0.0-next.1"
resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-6.0.0-next.1.tgz#4d71886d4a17d22eafc61b3a5fbf84e8e27c191f"
integrity sha512-LSF6bXoFeXfMPRNyqzI3yFX/kD2DzXBemqvyj1kDWNVraiWttm4xKF4YXsvJ7Z3s9sVt/Dpu3CFU3w61PGNZMg==
dependencies:
vscode-languageserver-protocol "^3.15.0-next.6"
vscode-languageserver-protocol "^3.15.0-next.9"
vscode-textbuffer "^1.0.0"
vscode-uri "^1.0.6"
vscode-nls@^4.0.0:
version "4.0.0"
@@ -125,11 +124,6 @@ vscode-textbuffer@^1.0.0:
resolved "https://registry.yarnpkg.com/vscode-textbuffer/-/vscode-textbuffer-1.0.0.tgz#1faee638c8e0e4131c8d5c353993a1874acda086"
integrity sha512-zPaHo4urgpwsm+PrJWfNakolRpryNja18SUip/qIIsfhuEqEIPEXMxHOlFPjvDC4JgTaimkncNW7UMXRJTY6ow==
vscode-uri@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d"
integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww==
vscode-uri@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.3.tgz#25e5f37f552fbee3cec7e5f80cef8469cefc6543"

View File

@@ -101,10 +101,10 @@ semver@^5.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==
semver@^5.5.0:
version "5.5.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477"
integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==
semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
vscode-extension-telemetry@0.1.1:
version "0.1.1"
@@ -113,31 +113,31 @@ vscode-extension-telemetry@0.1.1:
dependencies:
applicationinsights "1.0.8"
vscode-jsonrpc@^4.1.0-next.2:
version "4.1.0-next.2"
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.1.0-next.2.tgz#3bd318910a48e631742b290975386e3dae685be3"
integrity sha512-GsBLjP9DxQ42yl1mW9GEIlnSc0+R8mfzhaebwmmTPEJjezD5SPoAo3DFrIAFZha9yvQ1nzZfZlhtVpGQmgxtXg==
vscode-jsonrpc@^5.0.0-next.2:
version "5.0.0-next.2"
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.2.tgz#a44bc03f67069e53f8d8beb88b96c0cacbfefbca"
integrity sha512-Q3/jabZUNviCG9hhF6hHWjhrABevPF9mv0aiE2j8BYCAP2k+aHTpjMyk+04MzaAqWYwXdQuZkLSbcYCCqbzJLg==
vscode-languageclient@^5.3.0-next.6:
version "5.3.0-next.6"
resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-5.3.0-next.6.tgz#35e74882781158e8b111911c0953869d3df08777"
integrity sha512-DxT8+gkenjCjJV6ArcP75/AQfx6HP6m6kHIbacPCpffMeoE1YMLKj6ZixA9J87yr0fMtBmqumLmDeGe7MIF2bw==
vscode-languageclient@^6.0.0-next.1:
version "6.0.0-next.1"
resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-6.0.0-next.1.tgz#deca1743afd20da092e04e40ef73cedbbd978455"
integrity sha512-eJ9VjLFNINArgRzLbQ11YlWry7dM93GEODkQBXTRfrSypksiO9qSGr4SHhWgxxP26p4FRSpzc/17+N+Egnnchg==
dependencies:
semver "^5.5.0"
vscode-languageserver-protocol "^3.15.0-next.6"
semver "^6.3.0"
vscode-languageserver-protocol "^3.15.0-next.9"
vscode-languageserver-protocol@^3.15.0-next.6:
version "3.15.0-next.6"
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.6.tgz#a8aeb7e7dd65da8216b386db59494cdfd3215d92"
integrity sha512-/yDpYlWyNs26mM23mT73xmOFsh1iRfgZfBdHmfAxwDKwpQKLoOSqVidtYfxlK/pD3IEKGcAVnT4WXTsguxxAMQ==
vscode-languageserver-protocol@^3.15.0-next.9:
version "3.15.0-next.9"
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.9.tgz#e768256bd5b580b25bfbc8099bc03bc4c42ebf30"
integrity sha512-b9PAxouMmtsLEe8ZjbIMPb7wRWPhckGfgjwZLmp/dWnaAuRPYtY3lGO0/rNbLc3jKIqCVlnEyYVFKalzDAzj0g==
dependencies:
vscode-jsonrpc "^4.1.0-next.2"
vscode-languageserver-types "^3.15.0-next.2"
vscode-jsonrpc "^5.0.0-next.2"
vscode-languageserver-types "^3.15.0-next.5"
vscode-languageserver-types@^3.15.0-next.2:
version "3.15.0-next.2"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.2.tgz#a0601332cdaafac21931f497bb080cfb8d73f254"
integrity sha512-2JkrMWWUi2rlVLSo9OFR2PIGUzdiowEM8NgNYiwLKnXTjpwpjjIrJbNNxDik7Rv4oo9KtikcFQZKXbrKilL/MQ==
vscode-languageserver-types@^3.15.0-next.5:
version "3.15.0-next.5"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.5.tgz#863d711bf47b338ff5e63ae19fb20d4fcd4d713b"
integrity sha512-7hrELhTeWieUgex3+6692KjCkcmO/+V/bFItM5MHGcBotzwmjEuXjapLLYTYhIspuJ1ibRSik5MhX5YwLpsPiw==
vscode-nls@^4.0.0:
version "4.0.0"

View File

@@ -171,8 +171,7 @@
},
{
"scope": [
"meta.preprocessor",
"keyword.control.directive"
"meta.preprocessor"
],
"settings": {
"foreground": "#569cd6"

View File

@@ -169,8 +169,7 @@
},
{
"scope": [
"meta.preprocessor",
"keyword.control.directive"
"meta.preprocessor"
],
"settings": {
"foreground": "#0000ff"

View File

@@ -1,3 +1,3 @@
disturl "http://nodejs.org/dist"
target "12.4.0"
target "10.11.0"
runtime "node"

View File

@@ -2,7 +2,7 @@
Name=@@NAME_LONG@@ - URL Handler
Comment=Azure Data Studio
GenericName=Text Editor
Exec=@@EXEC@@ --no-sandbox --open-url %U
Exec=@@EXEC@@ --open-url %U
Icon=@@ICON@@
Type=Application
NoDisplay=true

View File

@@ -2,7 +2,7 @@
Name=@@NAME_LONG@@
Comment=Data Management Tool that enables you to work with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux.
GenericName=Text Editor
Exec=@@EXEC@@ --no-sandbox --unity-launch %F
Exec=@@EXEC@@ --unity-launch %F
Icon=@@ICON@@
Type=Application
StartupNotify=false
@@ -14,5 +14,5 @@ Keywords=azuredatastudio;
[Desktop Action new-empty-window]
Name=New Empty Window
Exec=@@EXEC@@ --no-sandbox --new-window %F
Exec=@@EXEC@@ --new-window %F
Icon=@@ICON@@

View File

@@ -8,7 +8,7 @@ if [[ "$OSTYPE" == "darwin"* ]]; then
else
ROOT=$(dirname $(dirname $(readlink -f $0)))
VSCODEUSERDATADIR=`mktemp -d 2>/dev/null`
LINUX_NO_SANDBOX="--no-sandbox" # Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox.
LINUX_NO_SANDBOX=""
fi
cd $ROOT

View File

@@ -34,5 +34,5 @@ else
cd $ROOT ; \
ELECTRON_ENABLE_LOGGING=1 \
"$CODE" \
test/electron/index.js --no-sandbox "$@" # Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox.
test/electron/index.js "$@"
fi

18
src/bootstrap.js vendored
View File

@@ -21,7 +21,6 @@ process.on('SIGPIPE', () => {
//#endregion
//#region Add support for redirecting the loading of node modules
exports.injectNodeModuleLookupPath = function (injectPath) {
if (!injectPath) {
throw new Error('Missing injectPath');
@@ -37,8 +36,10 @@ exports.injectNodeModuleLookupPath = function (injectPath) {
const originalResolveLookupPaths = Module._resolveLookupPaths;
// @ts-ignore
Module._resolveLookupPaths = function (moduleName, parent) {
const paths = originalResolveLookupPaths(moduleName, parent);
Module._resolveLookupPaths = function (moduleName, parent, newReturn) {
const result = originalResolveLookupPaths(moduleName, parent, newReturn);
const paths = newReturn ? result : result[1];
for (let i = 0, len = paths.length; i < len; i++) {
if (paths[i] === nodeModulesPath) {
paths.splice(i, 0, injectPath);
@@ -46,7 +47,7 @@ exports.injectNodeModuleLookupPath = function (injectPath) {
}
}
return paths;
return result;
};
};
//#endregion
@@ -70,10 +71,11 @@ exports.enableASARSupport = function (nodeModulesPath) {
// @ts-ignore
const originalResolveLookupPaths = Module._resolveLookupPaths;
// @ts-ignore
Module._resolveLookupPaths = function (request, parent) {
const paths = originalResolveLookupPaths(request, parent);
Module._resolveLookupPaths = function (request, parent, newReturn) {
const result = originalResolveLookupPaths(request, parent, newReturn);
const paths = newReturn ? result : result[1];
for (let i = 0, len = paths.length; i < len; i++) {
if (paths[i] === NODE_MODULES_PATH) {
paths.splice(i, 0, NODE_MODULES_ASAR_PATH);
@@ -81,7 +83,7 @@ exports.enableASARSupport = function (nodeModulesPath) {
}
}
return paths;
return result;
};
};
//#endregion

View File

@@ -17,7 +17,7 @@ const paths = require('./paths');
// @ts-ignore
const product = require('../product.json');
// @ts-ignore
const { app, protocol } = require('electron');
const app = require('electron').app;
// Enable portable support
const portable = bootstrap.configurePortable();
@@ -33,11 +33,6 @@ app.setPath('userData', userDataPath);
// Update cwd based on environment and platform
setCurrentWorkingDirectory();
// Register custom schemes with privileges
protocol.registerSchemesAsPrivileged([
{ scheme: 'vscode-resource', privileges: { secure: true, supportFetchAPI: true, corsEnabled: true } }
]);
// Global app listeners
registerListeners();

View File

@@ -0,0 +1,12 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { AbstractEnablePreviewFeatures } from 'sql/workbench/common/enablePreviewFeatures';
export class BrowserEnablePreviewFeatures extends AbstractEnablePreviewFeatures {
protected async getWindowCount(): Promise<number> {
return 1;
}
}

View File

@@ -11,7 +11,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IHostService } from 'vs/workbench/services/host/browser/host';
export class EnablePreviewFeatures implements IWorkbenchContribution {
export abstract class AbstractEnablePreviewFeatures implements IWorkbenchContribution {
private static ENABLE_PREVIEW_FEATURES_SHOWN = 'workbench.enablePreviewFeaturesShown';
@@ -22,12 +22,12 @@ export class EnablePreviewFeatures implements IWorkbenchContribution {
@IConfigurationService configurationService: IConfigurationService
) {
let previewFeaturesEnabled = configurationService.getValue('workbench')['enablePreviewFeatures'];
if (previewFeaturesEnabled || storageService.get(EnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, StorageScope.GLOBAL)) {
if (previewFeaturesEnabled || storageService.get(AbstractEnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, StorageScope.GLOBAL)) {
return;
}
Promise.all([
hostService.hasFocus,
hostService.windowCount
this.getWindowCount()
]).then(([focused, count]) => {
if (!focused && count > 1) {
return null;
@@ -42,7 +42,7 @@ export class EnablePreviewFeatures implements IWorkbenchContribution {
label: localize('enablePreviewFeatures.yes', "Yes"),
run: () => {
configurationService.updateValue('workbench.enablePreviewFeatures', true);
storageService.store(EnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true, StorageScope.GLOBAL);
storageService.store(AbstractEnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true, StorageScope.GLOBAL);
}
}, {
label: localize('enablePreviewFeatures.no', "No"),
@@ -53,7 +53,7 @@ export class EnablePreviewFeatures implements IWorkbenchContribution {
label: localize('enablePreviewFeatures.never', "No, don't show again"),
run: () => {
configurationService.updateValue('workbench.enablePreviewFeatures', false);
storageService.store(EnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true, StorageScope.GLOBAL);
storageService.store(AbstractEnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true, StorageScope.GLOBAL);
},
isSecondary: true
}]
@@ -61,4 +61,6 @@ export class EnablePreviewFeatures implements IWorkbenchContribution {
})
.then(null, onUnexpectedError);
}
protected abstract getWindowCount(): Promise<number>;
}

View File

@@ -0,0 +1,27 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { AbstractEnablePreviewFeatures } from 'sql/workbench/common/enablePreviewFeatures';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IElectronService } from 'vs/platform/electron/node/electron';
export class NativeEnablePreviewFeatures extends AbstractEnablePreviewFeatures {
constructor(
@IStorageService storageService: IStorageService,
@INotificationService notificationService: INotificationService,
@IHostService hostService: IHostService,
@IConfigurationService configurationService: IConfigurationService,
@IElectronService private readonly electronService: IElectronService
) {
super(storageService, notificationService, hostService, configurationService);
}
protected getWindowCount(): Promise<number> {
return this.electronService.getWindowCount();
}
}

View File

@@ -138,7 +138,7 @@ registerAction({
await workspaceEditingService.addFolders(folders.map(folder => ({ uri: folder })));
await viewletService.openViewlet(viewletService.getDefaultViewletId(), true);
if (options.forceNewWindow) {
return hostService.openInWindow([{ folderUri: folders[0] }], { forceNewWindow: options.forceNewWindow });
return hostService.openWindow([{ folderUri: folders[0] }], { forceNewWindow: options.forceNewWindow });
}
else {
return hostService.reload();

View File

@@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import { Registry } from 'vs/platform/registry/common/platform';
import { OpenWelcomePageInBrowser } from './openWebsite';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { BrowserEnablePreviewFeatures } from 'sql/workbench/browser/enablePreviewFeatures';
Registry
.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(OpenWelcomePageInBrowser, LifecyclePhase.Restored);
.registerWorkbenchContribution(BrowserEnablePreviewFeatures, LifecyclePhase.Eventually);

View File

@@ -0,0 +1,13 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { NativeEnablePreviewFeatures } from 'sql/workbench/electron-browser/enablePreviewFeatures';
Registry
.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(NativeEnablePreviewFeatures, LifecyclePhase.Eventually);

View File

@@ -14,7 +14,7 @@
"./sql/azdata.d.ts",
"./sql/azdata.proposed.d.ts",
"./vs/base/**/*.ts",
"./vs/platform/**/*.ts",
// "./vs/platform/**/*.ts",
"./sql/base/**/*.ts",
"./sql/editor/**/*.ts",
"./sql/platform/angularEventing/**/*.ts",

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
import { IMarkdownString, parseHrefAndDimensions, removeMarkdownEscapes } from 'vs/base/common/htmlContent';
import { defaultGenerator } from 'vs/base/common/idGenerator';
import * as marked from 'vs/base/common/marked/marked';
import * as insane from 'vs/base/common/insane/insane';
import { insane } from 'vs/base/common/insane/insane';
import { parse } from 'vs/base/common/marshalling';
import { cloneAndChange } from 'vs/base/common/objects';
import { escape } from 'vs/base/common/strings';

View File

@@ -152,34 +152,48 @@ export class StandardWheelEvent {
this.deltaX = deltaX;
if (e) {
let e1 = <IWebKitMouseWheelEvent><any>e;
let e2 = <IGeckoMouseWheelEvent><any>e;
if (e.type === 'wheel') {
// vertical delta scroll
if (typeof e1.wheelDeltaY !== 'undefined') {
this.deltaY = e1.wheelDeltaY / 120;
} else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) {
this.deltaY = -e2.detail / 3;
} else {
this.deltaY = -e.deltaY / 40;
}
// Modern wheel event
// https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent
const ev = <WheelEvent><unknown>e;
// horizontal delta scroll
if (typeof e1.wheelDeltaX !== 'undefined') {
if (browser.isSafari && platform.isWindows) {
this.deltaX = - (e1.wheelDeltaX / 120);
if (ev.deltaMode === ev.DOM_DELTA_LINE) {
// the deltas are expressed in lines
this.deltaY = -e.deltaY;
this.deltaX = -e.deltaX;
} else {
this.deltaX = e1.wheelDeltaX / 120;
this.deltaY = -e.deltaY / 40;
this.deltaX = -e.deltaX / 40;
}
} else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) {
this.deltaX = -e.detail / 3;
} else {
this.deltaX = -e.deltaX / 40;
}
// Assume a vertical scroll if nothing else worked
if (this.deltaY === 0 && this.deltaX === 0 && e.wheelDelta) {
this.deltaY = e.wheelDelta / 120;
} else {
// Old (deprecated) wheel events
let e1 = <IWebKitMouseWheelEvent><any>e;
let e2 = <IGeckoMouseWheelEvent><any>e;
// vertical delta scroll
if (typeof e1.wheelDeltaY !== 'undefined') {
this.deltaY = e1.wheelDeltaY / 120;
} else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) {
this.deltaY = -e2.detail / 3;
}
// horizontal delta scroll
if (typeof e1.wheelDeltaX !== 'undefined') {
if (browser.isSafari && platform.isWindows) {
this.deltaX = - (e1.wheelDeltaX / 120);
} else {
this.deltaX = e1.wheelDeltaX / 120;
}
} else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) {
this.deltaX = -e.detail / 3;
}
// Assume a vertical scroll if nothing else worked
if (this.deltaY === 0 && this.deltaX === 0 && e.wheelDelta) {
this.deltaY = e.wheelDelta / 120;
}
}
}
}

View File

@@ -86,15 +86,21 @@ export class Gesture extends Disposable {
this._register(DomUtils.addDisposableListener(document, 'touchmove', (e: TouchEvent) => this.onTouchMove(e)));
}
public static addTarget(element: HTMLElement): void {
public static addTarget(element: HTMLElement): IDisposable {
if (!Gesture.isTouchDevice()) {
return;
return Disposable.None;
}
if (!Gesture.INSTANCE) {
Gesture.INSTANCE = new Gesture();
}
Gesture.INSTANCE.targets.push(element);
return {
dispose: () => {
Gesture.INSTANCE.targets = Gesture.INSTANCE.targets.filter(t => t !== element);
}
};
}
@memoize

View File

@@ -103,7 +103,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
render(container: HTMLElement): void {
this.element = container;
Gesture.addTarget(container);
this._register(Gesture.addTarget(container));
const enableDragging = this.options && this.options.draggable;
if (enableDragging) {

View File

@@ -63,7 +63,7 @@ export class Button extends Disposable {
container.appendChild(this._element);
Gesture.addTarget(this._element);
this._register(Gesture.addTarget(this._element));
[DOM.EventType.CLICK, EventType.Tap].forEach(eventType => {
this._register(DOM.addDisposableListener(this._element, eventType, e => {

View File

@@ -83,7 +83,7 @@ export class BaseDropdown extends ActionRunner {
this._register(cleanupFn);
}
Gesture.addTarget(this._label);
this._register(Gesture.addTarget(this._label));
}
get element(): HTMLElement {

View File

@@ -236,7 +236,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
this.rowsContainer = document.createElement('div');
this.rowsContainer.className = 'monaco-list-rows';
Gesture.addTarget(this.rowsContainer);
this.disposables.add(Gesture.addTarget(this.rowsContainer));
this.scrollableElement = this.disposables.add(new ScrollableElement(this.rowsContainer, {
alwaysConsumeMouseWheel: true,

View File

@@ -542,7 +542,7 @@ export class MouseController<T> implements IDisposable {
list.onContextMenu(this.onContextMenu, this, this.disposables);
list.onMouseDblClick(this.onDoubleClick, this, this.disposables);
list.onTouchStart(this.onMouseDown, this, this.disposables);
Gesture.addTarget(list.getHTMLElement());
this.disposables.add(Gesture.addTarget(list.getHTMLElement()));
}
list.onMouseClick(this.onPointer, this, this.disposables);

View File

@@ -398,7 +398,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
EventHelper.stop(e, true);
this.onClick(e);
}));
}, 50);
}, 100);
this._register(this.runOnceToEnableMouseUp);
}

View File

@@ -238,7 +238,7 @@ export class MenuBar extends Disposable {
}
}));
Gesture.addTarget(buttonElement);
this._register(Gesture.addTarget(buttonElement));
this._register(DOM.addDisposableListener(buttonElement, EventType.Tap, (e: GestureEvent) => {
// Ignore this touch if the menu is touched
if (this.isOpen && this.focusedMenu && this.focusedMenu.holder && DOM.isAncestor(e.initialTarget as HTMLElement, this.focusedMenu.holder)) {
@@ -322,7 +322,7 @@ export class MenuBar extends Disposable {
}
}));
Gesture.addTarget(buttonElement);
this._register(Gesture.addTarget(buttonElement));
this._register(DOM.addDisposableListener(buttonElement, EventType.Tap, (e: GestureEvent) => {
// Ignore this touch if the menu is touched
if (this.isOpen && this.focusedMenu && this.focusedMenu.holder && DOM.isAncestor(e.initialTarget as HTMLElement, this.focusedMenu.holder)) {

View File

@@ -1,6 +1,6 @@
@font-face {
font-family: "octicons";
src: url("./octicons.ttf?628f71ee09945d25ba5fceb0c17f7b0f") format("truetype");
src: url("./octicons.ttf?1829db8570ee0fa5a4bef3bb41d5f62e") format("truetype");
}
.octicon, .mega-octicon {

View File

@@ -139,7 +139,7 @@ export class Sash extends Disposable {
this._register(domEvent(this.el, 'mousedown')(this.onMouseDown, this));
this._register(domEvent(this.el, 'dblclick')(this.onMouseDoubleClick, this));
Gesture.addTarget(this.el);
this._register(Gesture.addTarget(this.el));
this._register(domEvent(this.el, EventType.Start)(this.onTouchStart, this));
if (isIPad) {

View File

@@ -23,7 +23,10 @@ export class MarkdownString implements IMarkdownString {
appendText(value: string): MarkdownString {
// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
this.value += value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&');
this.value += value
.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
.replace('\n', '\n\n');
return this;
}

View File

@@ -3,11 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export as namespace insane;
export = insane;
declare function insane(
export function insane(
html: string,
options?: {
readonly allowedSchemes?: readonly string[],
@@ -16,5 +12,3 @@ declare function insane(
},
strict?: boolean,
): string;
declare namespace insane { }

View File

@@ -21,11 +21,7 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// ESM-comment-begin
let __insane_exports;
// ESM-comment-end
let __insane_func;
(function () { function r(e, n, t) { function o(i, f) { if (!n[i]) { if (!e[i]) { var c = "function" == typeof require && require; if (!f && c) return c(i, !0); if (u) return u(i, !0); var a = new Error("Cannot find module '" + i + "'"); throw a.code = "MODULE_NOT_FOUND", a } var p = n[i] = { exports: {} }; e[i][0].call(p.exports, function (r) { var n = e[i][1][r]; return o(n || r) }, p, p.exports, r, e, n, t) } return n[i].exports } for (var u = "function" == typeof require && require, i = 0; i < t.length; i++)o(t[i]); return o } return r })()({
1: [function (require, module, exports) {
@@ -92,7 +88,7 @@ let __insane_exports;
insane.defaults = defaults;
module.exports = insane;
__insane_exports = insane;
__insane_func = insane;
}, { "./defaults": 2, "./parser": 7, "./sanitizer": 8, "assignment": 6, "he": 9 }], 5: [function (require, module, exports) {
'use strict';
@@ -469,10 +465,10 @@ let __insane_exports;
}, {}]
}, {}, [4]);
// BEGIN MONACOCHANGE
// __marked_exports = marked;
// }).call(this);
// ESM-comment-begin
define(function() { return __insane_exports; });
define(function() { return { insane: __insane_func }; });
// ESM-comment-end
// ESM-uncomment-begin
// export var insane = __insane_func;
// ESM-uncomment-end

View File

@@ -92,7 +92,10 @@ class RemoteAuthoritiesImpl {
return this._delegate(uri);
}
const authority = uri.authority;
const host = this._hosts[authority];
let host = this._hosts[authority];
if (host.indexOf(':') !== -1) {
host = `[${host}]`;
}
const port = this._ports[authority];
const connectionToken = this._connectionTokens[authority];
return URI.from({

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Menu, MenuItem, BrowserWindow, ipcMain, IpcMainEvent } from 'electron';
import { Menu, MenuItem, BrowserWindow, ipcMain, Event as IpcMainEvent } from 'electron';
import { ISerializableContextMenuItem, CONTEXT_MENU_CLOSE_CHANNEL, CONTEXT_MENU_CHANNEL, IPopupOptions } from 'vs/base/parts/contextmenu/common/contextmenu';
export function registerContextMenuListener(): void {

View File

@@ -437,6 +437,7 @@ export class TreeView extends HeightMap {
private shouldInvalidateDropReaction: boolean;
private currentDropTargets: ViewItem[] | null = null;
private currentDropDisposable: Lifecycle.IDisposable = Lifecycle.Disposable.None;
private gestureDisposable: Lifecycle.IDisposable = Lifecycle.Disposable.None;
private dragAndDropScrollInterval: number | null = null;
private dragAndDropScrollTimeout: number | null = null;
private dragAndDropMouseY: number | null = null;
@@ -523,7 +524,7 @@ export class TreeView extends HeightMap {
this.wrapper.style.msTouchAction = 'none';
this.wrapper.style.msContentZooming = 'none';
} else {
Touch.Gesture.addTarget(this.wrapper);
this.gestureDisposable = Touch.Gesture.addTarget(this.wrapper);
}
this.rowsContainer = document.createElement('div');
@@ -1681,6 +1682,7 @@ export class TreeView extends HeightMap {
if (this.context.cache) {
this.context.cache.dispose();
}
this.gestureDisposable.dispose();
super.dispose();
}

View File

@@ -0,0 +1,19 @@
/*---------------------------------------------------------------------------------------------
* 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 { MarkdownString } from 'vs/base/common/htmlContent';
suite('markdownString', () => {
test('escape', () => {
const mds = new MarkdownString();
mds.appendText('# foo\n*bar*');
assert.equal(mds.value, '\\# foo\n\n\\*bar\\*');
});
});

View File

@@ -27,6 +27,7 @@ function getWorker(workerId: string, label: string): Worker | Promise<Worker> {
throw new Error(`You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker`);
}
// ESM-comment-begin
export function getWorkerBootstrapUrl(scriptPath: string, label: string): string {
if (/^(http:)|(https:)|(file:)/.test(scriptPath)) {
const currentUrl = String(window.location);
@@ -43,6 +44,7 @@ export function getWorkerBootstrapUrl(scriptPath: string, label: string): string
}
return scriptPath + '#' + label;
}
// ESM-comment-end
function isPromiseLike<T>(obj: any): obj is PromiseLike<T> {
if (typeof obj.then === 'function') {

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { app, ipcMain as ipc, systemPreferences, shell, Event, contentTracing, protocol, powerMonitor, IpcMainEvent } from 'electron';
import { app, ipcMain as ipc, systemPreferences, shell, Event, contentTracing, protocol, powerMonitor, Event as IpcMainEvent, BrowserWindow } from 'electron';
import { IProcessEnvironment, isWindows, isMacintosh } from 'vs/base/common/platform';
import { WindowsManager } from 'vs/code/electron-main/windows';
import { OpenContext, IWindowOpenable } from 'vs/platform/windows/common/windows';
@@ -78,6 +78,8 @@ import { IElectronService } from 'vs/platform/electron/node/electron';
import { ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService';
import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService';
import { assign } from 'vs/base/common/objects';
import { IDialogMainService, DialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
import { withNullAsUndefined } from 'vs/base/common/types';
export class CodeApplication extends Disposable {
@@ -85,6 +87,7 @@ export class CodeApplication extends Disposable {
private static readonly TRUE_MACHINE_ID_KEY = 'telemetry.trueMachineId';
private windowsMainService: IWindowsMainService | undefined;
private dialogMainService: IDialogMainService | undefined;
constructor(
private readonly mainIpcServer: Server,
@@ -381,8 +384,7 @@ export class CodeApplication extends Disposable {
}
// Setup Auth Handler
const authHandler = appInstantiationService.createInstance(ProxyAuthHandler);
this._register(authHandler);
this._register(new ProxyAuthHandler());
// Open Windows
const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient));
@@ -449,6 +451,7 @@ export class CodeApplication extends Disposable {
}
services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId, this.userEnv]));
services.set(IDialogMainService, new SyncDescriptor(DialogMainService));
services.set(ISharedProcessMainService, new SyncDescriptor(SharedProcessMainService, [sharedProcess]));
services.set(ILaunchMainService, new SyncDescriptor(LaunchMainService));
@@ -503,13 +506,13 @@ export class CodeApplication extends Disposable {
contentTracing.stopRecording(join(homedir(), `${product.applicationName}-${Math.random().toString(16).slice(-4)}.trace.txt`), path => {
if (!timeout) {
if (this.windowsMainService) {
this.windowsMainService.showMessageBox({
if (this.dialogMainService) {
this.dialogMainService.showMessageBox({
type: 'info',
message: localize('trace.message', "Successfully created trace."),
detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path),
buttons: [localize('trace.ok', "Ok")]
}, this.windowsMainService.getLastActiveWindow());
}, withNullAsUndefined(BrowserWindow.getFocusedWindow()));
}
} else {
this.logService.info(`Tracing: data recorded (after 30s timeout) to ${path}`);
@@ -580,6 +583,7 @@ export class CodeApplication extends Disposable {
// Propagate to clients
const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService);
this.dialogMainService = accessor.get(IDialogMainService);
// Create a URL handler to open file URIs in the active window
const environmentService = accessor.get(IEnvironmentService);

View File

@@ -4,8 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import { Disposable } from 'vs/base/common/lifecycle';
import { Event } from 'vs/base/common/event';
import { BrowserWindow, app, AuthInfo, WebContents, Event as ElectronEvent } from 'electron';
@@ -22,18 +21,21 @@ type Credentials = {
password: string;
};
export class ProxyAuthHandler {
export class ProxyAuthHandler extends Disposable {
_serviceBrand: undefined;
private retryCount = 0;
private disposables: IDisposable[] = [];
constructor(
@IWindowsMainService private readonly windowsMainService: IWindowsMainService
) {
constructor() {
super();
this.registerListeners();
}
private registerListeners(): void {
const onLogin = Event.fromNodeEventEmitter<LoginEvent>(app, 'login', (event, webContents, req, authInfo, cb) => ({ event, webContents, req, authInfo, cb }));
onLogin(this.onLogin, this, this.disposables);
this._register(onLogin(this.onLogin, this));
}
private onLogin({ event, authInfo, cb }: LoginEvent): void {
@@ -61,10 +63,9 @@ export class ProxyAuthHandler {
}
};
const focusedWindow = this.windowsMainService.getFocusedWindow();
const focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow) {
opts.parent = focusedWindow.win;
opts.parent = focusedWindow;
opts.modal = true;
}
@@ -89,8 +90,4 @@ export class ProxyAuthHandler {
win.close();
});
}
dispose(): void {
this.disposables = dispose(this.disposables);
}
}

View File

@@ -7,7 +7,7 @@ import { assign } from 'vs/base/common/objects';
import { memoize } from 'vs/base/common/decorators';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { BrowserWindow, ipcMain } from 'electron';
import { ISharedProcess } from 'vs/platform/windows/electron-main/windows';
import { ISharedProcess } from 'vs/platform/ipc/electron-main/sharedProcessMainService';
import { Barrier } from 'vs/base/common/async';
import { ILogService } from 'vs/platform/log/common/log';
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';

View File

@@ -561,7 +561,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
autoDetectHighContrast = false;
}
windowConfiguration.highContrast = isWindows && autoDetectHighContrast && systemPreferences.isInvertedColorScheme();
windowConfiguration.accessibilitySupport = app.accessibilitySupportEnabled;
windowConfiguration.accessibilitySupport = app.isAccessibilitySupportEnabled();
// Title style related
windowConfiguration.maximized = this._win.isMaximized();

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as fs from 'fs';
import { basename, normalize, join, dirname } from 'vs/base/common/path';
import { basename, normalize, join, } from 'vs/base/common/path';
import { localize } from 'vs/nls';
import * as arrays from 'vs/base/common/arrays';
import { assign, mixin } from 'vs/base/common/objects';
@@ -13,34 +13,36 @@ import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { IStateService } from 'vs/platform/state/node/state';
import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window';
import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter, shell, MessageBoxReturnValue, MessageBoxOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, Display } from 'electron';
import { ipcMain as ipc, screen, BrowserWindow, systemPreferences, MessageBoxOptions, Display } from 'electron';
import { parseLineAndColumnAware } from 'vs/code/node/paths';
import { ILifecycleMainService, UnloadReason, LifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/platform/log/common/log';
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, IPathsToWaitFor, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows';
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, IPathsToWaitFor, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions, IAddFoldersRequest } from 'vs/platform/windows/common/windows';
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs';
import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/code/node/windowsFinder';
import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/platform/windows/node/window';
import { Event as CommonEvent, Emitter } from 'vs/base/common/event';
import product from 'vs/platform/product/common/product';
import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent, ICodeWindow, IWindowState as ISingleWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows';
import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService';
import { IProcessEnvironment, isMacintosh, isWindows } from 'vs/base/common/platform';
import { IWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension, IEnterWorkspaceResult, IRecent } from 'vs/platform/workspaces/common/workspaces';
import { IWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension, IRecent } from 'vs/platform/workspaces/common/workspaces';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { Schemas } from 'vs/base/common/network';
import { normalizeNFC } from 'vs/base/common/normalization';
import { URI } from 'vs/base/common/uri';
import { Queue } from 'vs/base/common/async';
import { exists, dirExists } from 'vs/base/node/pfs';
import { getComparisonKey, isEqual, normalizePath, basename as resourcesBasename, originalFSPath, hasTrailingPathSeparator, removeTrailingPathSeparator } from 'vs/base/common/resources';
import { dirExists } from 'vs/base/node/pfs';
import { getComparisonKey, isEqual, normalizePath, originalFSPath, hasTrailingPathSeparator, removeTrailingPathSeparator } from 'vs/base/common/resources';
import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
import { restoreWindowsState, WindowsStateStorageData, getWindowsStateStoreData } from 'vs/code/electron-main/windowsStateStorage';
import { getWorkspaceIdentifier, IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService';
import { once } from 'vs/base/common/functional';
import { Disposable } from 'vs/base/common/lifecycle';
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
import { withNullAsUndefined } from 'vs/base/common/types';
import { isWindowsDriveLetter, toSlashes } from 'vs/base/common/extpath';
import { CharCode } from 'vs/base/common/charCode';
const enum WindowError {
UNRESPONSIVE = 1,
@@ -167,9 +169,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
private readonly windowsState: IWindowsState;
private lastClosedWindowState?: IWindowState;
private readonly dialogs: Dialogs;
private readonly workspacesManager: WorkspacesManager;
private readonly _onWindowReady = this._register(new Emitter<ICodeWindow>());
readonly onWindowReady: CommonEvent<ICodeWindow> = this._onWindowReady.event;
@@ -194,7 +193,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
@IConfigurationService private readonly configurationService: IConfigurationService,
@IWorkspacesHistoryMainService private readonly workspacesHistoryMainService: IWorkspacesHistoryMainService,
@IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService,
@IInstantiationService private readonly instantiationService: IInstantiationService
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IDialogMainService private readonly dialogMainService: IDialogMainService
) {
super();
@@ -203,9 +203,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
this.windowsState.openedWindows = [];
}
this.dialogs = new Dialogs(stateService, this);
this.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this);
this.lifecycleMainService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners());
this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.installWindowsMutex());
}
@@ -260,6 +257,11 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
this.lastClosedWindowState = undefined;
}
});
// Signal a window is ready after having entered a workspace
this._register(this.workspacesMainService.onWorkspaceEntered(event => {
this._onWindowReady.fire(event.window);
}));
}
// Note that onBeforeShutdown() and onBeforeWindowClose() are fired in different order depending on the OS:
@@ -380,12 +382,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
};
}
async openExternal(url: string): Promise<boolean> {
shell.openExternal(url);
return true;
}
open(openConfig: IOpenConfiguration): ICodeWindow[] {
this.logService.trace('windowsManager#open');
openConfig = this.validateOpenConfig(openConfig);
@@ -776,7 +772,9 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
private doAddFoldersToExistingWindow(window: ICodeWindow, foldersToAdd: URI[]): ICodeWindow {
window.focus(); // make sure window has focus
window.sendWhenReady('vscode:addFolders', { foldersToAdd });
const request: IAddFoldersRequest = { foldersToAdd };
window.sendWhenReady('vscode:addFolders', request);
return window;
}
@@ -862,7 +860,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
path.label = pathToOpen.label;
pathsToOpen.push(path);
} else {
const uri = resourceFromURIToOpen(pathToOpen);
const uri = this.resourceFromURIToOpen(pathToOpen);
// Warn about the invalid URI or path
let message, detail;
if (uri.scheme === Schemas.file) {
@@ -881,7 +880,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
noLink: true
};
this.dialogs.showMessageBox(options, this.getFocusedWindow());
this.dialogMainService.showMessageBox(options, withNullAsUndefined(BrowserWindow.getFocusedWindow()));
}
}
return pathsToOpen;
@@ -1011,10 +1010,12 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
this.logService.error(`Invalid URI input string, scheme missing: ${arg}`);
return undefined;
}
return uri;
} catch (e) {
this.logService.error(`Invalid URI input string: ${arg}, ${e.message}`);
}
return undefined;
}
@@ -1023,7 +1024,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
return undefined;
}
let uri = resourceFromURIToOpen(toOpen);
let uri = this.resourceFromURIToOpen(toOpen);
if (uri.scheme === Schemas.file) {
return this.parsePath(uri.fsPath, options, isFileToOpen(toOpen));
}
@@ -1050,6 +1051,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
remoteAuthority
};
}
return {
fileUri: uri,
remoteAuthority
@@ -1071,6 +1073,18 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
};
}
private resourceFromURIToOpen(openable: IWindowOpenable): URI {
if (isWorkspaceToOpen(openable)) {
return openable.workspaceUri;
}
if (isFolderToOpen(openable)) {
return openable.folderUri;
}
return openable.fileUri;
}
private parsePath(anyPath: string, options: IPathParseOptions, forceOpenWorkspaceAsFile?: boolean): IPathToOpen | undefined {
if (!anyPath) {
return undefined;
@@ -1086,11 +1100,36 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
anyPath = parsedPath.path;
}
// open remote if either specified in the cli even if it is a local file. TODO@aeschli: Future idea: resolve in remote host context.
// open remote if either specified in the cli even if it is a local file.
const remoteAuthority = options.remoteAuthority;
const candidate = normalize(anyPath);
if (remoteAuthority) {
// assume it's a folder or workspace file
const first = anyPath.charCodeAt(0);
// make absolute
if (first !== CharCode.Slash) {
if (isWindowsDriveLetter(first) && anyPath.charCodeAt(anyPath.charCodeAt(1)) === CharCode.Colon) {
anyPath = toSlashes(anyPath);
}
anyPath = '/' + anyPath;
}
const uri = URI.from({ scheme: Schemas.vscodeRemote, authority: remoteAuthority, path: anyPath });
if (hasWorkspaceFileExtension(anyPath)) {
if (forceOpenWorkspaceAsFile) {
return { fileUri: uri, remoteAuthority };
}
return { workspace: getWorkspaceIdentifier(uri), remoteAuthority };
}
return { folderUri: uri, remoteAuthority };
}
let candidate = normalize(anyPath);
try {
const candidateStat = fs.statSync(candidate);
if (candidateStat.isFile()) {
@@ -1185,7 +1224,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
return { openFolderInNewWindow: !!openFolderInNewWindow, openFilesInNewWindow };
}
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): void {
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): ICodeWindow[] {
// Reload an existing extension development host window on the same path
// We currently do not allow more than one extension development window
@@ -1195,7 +1234,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
this.reload(existingWindow, openConfig.cli);
existingWindow.focus(); // make sure it gets focus and is restored
return;
return [existingWindow];
}
let folderUris = openConfig.cli['folder-uri'] || [];
let fileUris = openConfig.cli['file-uri'] || [];
@@ -1286,7 +1325,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
noRecentEntry: true,
waitMarkerFileURI: openConfig.waitMarkerFileURI
};
this.open(openArgs);
return this.open(openArgs);
}
private openInBrowserWindow(options: IOpenBrowserWindowOptions): ICodeWindow {
@@ -1580,23 +1620,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
});
}
async enterWorkspace(win: ICodeWindow, path: URI): Promise<IEnterWorkspaceResult | undefined> {
const result = await this.workspacesManager.enterWorkspace(win, path);
return result ? this.doEnterWorkspace(win, result) : undefined;
}
private doEnterWorkspace(win: ICodeWindow, result: IEnterWorkspaceResult): IEnterWorkspaceResult {
// Mark as recently opened
this.workspacesHistoryMainService.addRecentlyOpened([{ workspace: result.workspace }]);
// Trigger Eevent to indicate load of workspace into window
this._onWindowReady.fire(win);
return result;
}
focusLastActive(cli: ParsedArgs, context: OpenContext): ICodeWindow {
const lastActive = this.getLastActiveWindow();
if (lastActive) {
@@ -1613,7 +1636,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
return getLastActiveWindow(WindowsManager.WINDOWS);
}
getLastActiveWindowForAuthority(remoteAuthority: string | undefined): ICodeWindow | undefined {
private getLastActiveWindowForAuthority(remoteAuthority: string | undefined): ICodeWindow | undefined {
return getLastActiveWindow(WindowsManager.WINDOWS.filter(window => window.remoteAuthority === remoteAuthority));
}
@@ -1623,13 +1646,11 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
if (cli && (cli.remote !== remote)) {
cli = { ...cli, remote };
}
const forceReuseWindow = options && options.reuse;
const forceNewWindow = !forceReuseWindow;
return this.open({ context, cli, forceEmpty: true, forceNewWindow, forceReuseWindow });
}
openNewTabbedWindow(context: OpenContext): ICodeWindow[] {
return this.open({ context, cli: this.environmentService.args, forceNewTabbedWindow: true, forceEmpty: true });
const forceReuseWindow = options && options.forceReuseWindow;
const forceNewWindow = !forceReuseWindow;
return this.open({ context, cli, forceEmpty: true, forceNewWindow, forceReuseWindow });
}
waitForWindowCloseOrLoad(windowId: number): Promise<void> {
@@ -1666,7 +1687,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
}
getFocusedWindow(): ICodeWindow | undefined {
private getFocusedWindow(): ICodeWindow | undefined {
const win = BrowserWindow.getFocusedWindow();
if (win) {
return this.getWindowById(win.id);
@@ -1710,14 +1731,14 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
// Show Dialog
this.dialogs.showMessageBox({
this.dialogMainService.showMessageBox({
title: product.nameLong,
type: 'warning',
buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'wait', comment: ['&& denotes a mnemonic'] }, "&&Keep Waiting")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))],
message: localize('appStalled', "The window is no longer responding"),
detail: localize('appStalledDetail', "You can reopen or close the window or keep waiting."),
noLink: true
}, window).then(result => {
}, window.win).then(result => {
if (!window.win) {
return; // Return early if the window has been going down already
}
@@ -1733,14 +1754,14 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
// Crashed
else {
this.dialogs.showMessageBox({
this.dialogMainService.showMessageBox({
title: product.nameLong,
type: 'warning',
buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))],
message: localize('appCrashed', "The window has crashed"),
detail: localize('appCrashedDetail', "We are sorry for the inconvenience! You can reopen the window to continue where you left off."),
noLink: true
}, window).then(result => {
}, window.win).then(result => {
if (!window.win) {
return; // Return early if the window has been going down already
}
@@ -1770,8 +1791,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
async pickFileFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
const title = localize('open', "Open");
const paths = await this.dialogs.pick({ ...options, pickFolders: true, pickFiles: true, title });
const paths = await this.dialogMainService.pickFileFolder(options);
if (paths) {
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFileFolder', options.telemetryExtraData);
const urisToOpen = await Promise.all(paths.map(async path => {
@@ -1790,8 +1810,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
async pickFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
const title = localize('openFolder', "Open Folder");
const paths = await this.dialogs.pick({ ...options, pickFolders: true, title });
const paths = await this.dialogMainService.pickFolder(options);
if (paths) {
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFolder', options.telemetryExtraData);
this.open({
@@ -1805,8 +1824,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
async pickFileAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
const title = localize('openFile', "Open File");
const paths = await this.dialogs.pick({ ...options, pickFiles: true, title });
const paths = await this.dialogMainService.pickFile(options);
if (paths) {
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFile', options.telemetryExtraData);
this.open({
@@ -1820,10 +1838,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
async pickWorkspaceAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
const title = localize('openWorkspaceTitle', "Open Workspace");
const buttonLabel = mnemonicButtonLabel(localize({ key: 'openWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open"));
const filters = WORKSPACE_FILTER;
const paths = await this.dialogs.pick({ ...options, pickFiles: true, title, filters, buttonLabel });
const paths = await this.dialogMainService.pickWorkspace(options);
if (paths) {
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openWorkspace', options.telemetryExtraData);
this.open({
@@ -1838,7 +1853,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
private sendPickerTelemetry(paths: string[], telemetryEventName: string, telemetryExtraData?: ITelemetryData) {
const numberOfPaths = paths ? paths.length : 0;
// Telemetry
@@ -1850,18 +1864,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
});
}
showMessageBox(options: MessageBoxOptions, win?: ICodeWindow): Promise<MessageBoxReturnValue> {
return this.dialogs.showMessageBox(options, win);
}
showSaveDialog(options: SaveDialogOptions, win?: ICodeWindow): Promise<SaveDialogReturnValue> {
return this.dialogs.showSaveDialog(options, win);
}
showOpenDialog(options: OpenDialogOptions, win?: ICodeWindow): Promise<OpenDialogReturnValue> {
return this.dialogs.showOpenDialog(options, win);
}
quit(): void {
// If the user selected to exit from an extension development host window, do not quit, but just
@@ -1879,240 +1881,3 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
}
}
interface IInternalNativeOpenDialogOptions extends INativeOpenDialogOptions {
pickFolders?: boolean;
pickFiles?: boolean;
title: string;
buttonLabel?: string;
filters?: FileFilter[];
}
class Dialogs {
private static readonly workingDirPickerStorageKey = 'pickerWorkingDir';
private readonly mapWindowToDialogQueue: Map<number, Queue<void>>;
private readonly noWindowDialogQueue: Queue<void>;
constructor(
private readonly stateService: IStateService,
private readonly windowsMainService: IWindowsMainService
) {
this.mapWindowToDialogQueue = new Map<number, Queue<void>>();
this.noWindowDialogQueue = new Queue<void>();
}
async pick(options: IInternalNativeOpenDialogOptions, win?: ICodeWindow): Promise<string[] | undefined> {
// Ensure dialog options
const dialogOptions: OpenDialogOptions = {
title: options.title,
buttonLabel: options.buttonLabel,
filters: options.filters
};
// Ensure defaultPath
dialogOptions.defaultPath = options.defaultPath || this.stateService.getItem<string>(Dialogs.workingDirPickerStorageKey);
// Ensure properties
if (typeof options.pickFiles === 'boolean' || typeof options.pickFolders === 'boolean') {
dialogOptions.properties = undefined; // let it override based on the booleans
if (options.pickFiles && options.pickFolders) {
dialogOptions.properties = ['multiSelections', 'openDirectory', 'openFile', 'createDirectory'];
}
}
if (!dialogOptions.properties) {
dialogOptions.properties = ['multiSelections', options.pickFolders ? 'openDirectory' : 'openFile', 'createDirectory'];
}
if (isMacintosh) {
dialogOptions.properties.push('treatPackageAsDirectory'); // always drill into .app files
}
// Show Dialog
const windowToUse = win || this.windowsMainService.getFocusedWindow();
const result = await this.showOpenDialog(dialogOptions, windowToUse);
if (result && result.filePaths && result.filePaths.length > 0) {
// Remember path in storage for next time
this.stateService.setItem(Dialogs.workingDirPickerStorageKey, dirname(result.filePaths[0]));
return result.filePaths;
}
return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check
}
private getDialogQueue(window?: ICodeWindow): Queue<any> {
if (!window) {
return this.noWindowDialogQueue;
}
let windowDialogQueue = this.mapWindowToDialogQueue.get(window.id);
if (!windowDialogQueue) {
windowDialogQueue = new Queue<any>();
this.mapWindowToDialogQueue.set(window.id, windowDialogQueue);
}
return windowDialogQueue;
}
showMessageBox(options: MessageBoxOptions, window?: ICodeWindow): Promise<MessageBoxReturnValue> {
return this.getDialogQueue(window).queue(async () => {
if (window) {
return dialog.showMessageBox(window.win, options);
}
return dialog.showMessageBox(options);
});
}
showSaveDialog(options: SaveDialogOptions, window?: ICodeWindow): Promise<SaveDialogReturnValue> {
function normalizePath(path: string | undefined): string | undefined {
if (path && isMacintosh) {
path = normalizeNFC(path); // normalize paths returned from the OS
}
return path;
}
return this.getDialogQueue(window).queue(async () => {
let result: SaveDialogReturnValue;
if (window) {
result = await dialog.showSaveDialog(window.win, options);
} else {
result = await dialog.showSaveDialog(options);
}
result.filePath = normalizePath(result.filePath);
return result;
});
}
showOpenDialog(options: OpenDialogOptions, window?: ICodeWindow): Promise<OpenDialogReturnValue> {
function normalizePaths(paths: string[] | undefined): string[] | undefined {
if (paths && paths.length > 0 && isMacintosh) {
paths = paths.map(path => normalizeNFC(path)); // normalize paths returned from the OS
}
return paths;
}
return this.getDialogQueue(window).queue(async () => {
// Ensure the path exists (if provided)
if (options.defaultPath) {
const pathExists = await exists(options.defaultPath);
if (!pathExists) {
options.defaultPath = undefined;
}
}
// Show dialog
let result: OpenDialogReturnValue;
if (window) {
result = await dialog.showOpenDialog(window.win, options);
} else {
result = await dialog.showOpenDialog(options);
}
result.filePaths = normalizePaths(result.filePaths);
return result;
});
}
}
class WorkspacesManager {
constructor(
private readonly workspacesMainService: IWorkspacesMainService,
private readonly backupMainService: IBackupMainService,
private readonly windowsMainService: IWindowsMainService,
) { }
async enterWorkspace(window: ICodeWindow, path: URI): Promise<IEnterWorkspaceResult | null> {
if (!window || !window.win || !window.isReady) {
return null; // return early if the window is not ready or disposed
}
const isValid = await this.isValidTargetWorkspacePath(window, path);
if (!isValid) {
return null; // return early if the workspace is not valid
}
return this.doOpenWorkspace(window, getWorkspaceIdentifier(path));
}
private async isValidTargetWorkspacePath(window: ICodeWindow, path?: URI): Promise<boolean> {
if (!path) {
return true;
}
if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, path)) {
return false; // window is already opened on a workspace with that path
}
// Prevent overwriting a workspace that is currently opened in another window
if (findWindowOnWorkspace(this.windowsMainService.getWindows(), getWorkspaceIdentifier(path))) {
const options: MessageBoxOptions = {
title: product.nameLong,
type: 'info',
buttons: [localize('ok', "OK")],
message: localize('workspaceOpenedMessage', "Unable to save workspace '{0}'", resourcesBasename(path)),
detail: localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again."),
noLink: true
};
await this.windowsMainService.showMessageBox(options, this.windowsMainService.getFocusedWindow());
return false;
}
return true; // OK
}
private doOpenWorkspace(window: ICodeWindow, workspace: IWorkspaceIdentifier): IEnterWorkspaceResult {
window.focus();
// Register window for backups and migrate current backups over
let backupPath: string | undefined;
if (!window.config.extensionDevelopmentPath) {
backupPath = this.backupMainService.registerWorkspaceBackupSync({ workspace, remoteAuthority: window.remoteAuthority }, window.config.backupPath);
}
// if the window was opened on an untitled workspace, delete it.
if (window.openedWorkspace && this.workspacesMainService.isUntitledWorkspace(window.openedWorkspace)) {
this.workspacesMainService.deleteUntitledWorkspaceSync(window.openedWorkspace);
}
// Update window configuration properly based on transition to workspace
window.config.folderUri = undefined;
window.config.workspace = workspace;
window.config.backupPath = backupPath;
return { workspace, backupPath };
}
}
function resourceFromURIToOpen(openable: IWindowOpenable): URI {
if (isWorkspaceToOpen(openable)) {
return openable.workspaceUri;
}
if (isFolderToOpen(openable)) {
return openable.folderUri;
}
return openable.fileUri;
}

View File

@@ -35,12 +35,15 @@ export function restoreWindowsState(data: WindowsStateStorageData | undefined):
if (windowsState.lastActiveWindow) {
result.lastActiveWindow = restoreWindowState(windowsState.lastActiveWindow);
}
if (windowsState.lastPluginDevelopmentHostWindow) {
result.lastPluginDevelopmentHostWindow = restoreWindowState(windowsState.lastPluginDevelopmentHostWindow);
}
if (Array.isArray(windowsState.openedWindows)) {
result.openedWindows = windowsState.openedWindows.map(windowState => restoreWindowState(windowState));
}
return result;
}
@@ -49,9 +52,11 @@ function restoreWindowState(windowState: ISerializedWindowState): IWindowState {
if (windowState.backupPath) {
result.backupPath = windowState.backupPath;
}
if (windowState.remoteAuthority) {
result.remoteAuthority = windowState.remoteAuthority;
}
if (windowState.folder) {
result.folderUri = URI.parse(windowState.folder);
} else if (windowState.folderUri) {
@@ -59,11 +64,13 @@ function restoreWindowState(windowState: ISerializedWindowState): IWindowState {
} else if (windowState.folderPath) {
result.folderUri = URI.file(windowState.folderPath);
}
if (windowState.workspaceIdentifier) {
result.workspace = { id: windowState.workspaceIdentifier.id, configPath: URI.parse(windowState.workspaceIdentifier.configURIPath) };
} else if (windowState.workspace) {
result.workspace = { id: windowState.workspace.id, configPath: URI.file(windowState.workspace.configPath) };
}
return result;
}

View File

@@ -3,19 +3,18 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as os from 'os';
import * as fs from 'fs';
import { spawn, ChildProcess, SpawnOptions } from 'child_process';
import { buildHelpMessage, buildVersionMessage, addArg, createWaitMarkerFile, OPTIONS } from 'vs/platform/environment/node/argv';
import { parseCLIProcessArgv } from 'vs/platform/environment/node/argvHelper';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import product from 'vs/platform/product/common/product';
import * as paths from 'vs/base/common/path';
import * as os from 'os';
import * as fs from 'fs';
import { whenDeleted, writeFileSync } from 'vs/base/node/pfs';
import { findFreePort, randomPort } from 'vs/base/node/ports';
import { resolveTerminalEncoding } from 'vs/base/node/encoding';
import * as iconv from 'iconv-lite';
import { isWindows, isLinux } from 'vs/base/common/platform';
import { isWindows } from 'vs/base/common/platform';
import { ProfilingSession, Target } from 'v8-inspect-profiler';
import { isString } from 'vs/base/common/types';
@@ -179,7 +178,8 @@ export async function main(argv: string[]): Promise<any> {
if (!stdinFileError) {
// Pipe into tmp file using terminals encoding
resolveTerminalEncoding(verbose).then(encoding => {
resolveTerminalEncoding(verbose).then(async encoding => {
const iconv = await import('iconv-lite');
const converterStream = iconv.decodeStream(encoding);
process.stdin.pipe(converterStream).pipe(stdinFileStream);
});
@@ -360,10 +360,6 @@ export async function main(argv: string[]): Promise<any> {
options['stdio'] = 'ignore';
}
if (isLinux) {
addArg(argv, '--no-sandbox'); // Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox
}
const child = spawn(process.execPath, argv.slice(2), options);
if (args.wait && waitMarkerFilePath) {

View File

@@ -1,131 +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 platform from 'vs/base/common/platform';
import * as extpath from 'vs/base/common/extpath';
import { OpenContext } from 'vs/platform/windows/common/windows';
import { IWorkspaceIdentifier, IResolvedWorkspace, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { URI } from 'vs/base/common/uri';
import { isEqual, isEqualOrParent } from 'vs/base/common/resources';
export interface ISimpleWindow {
openedWorkspace?: IWorkspaceIdentifier;
openedFolderUri?: URI;
extensionDevelopmentPath?: string[];
lastFocusTime: number;
}
export interface IBestWindowOrFolderOptions<W extends ISimpleWindow> {
windows: W[];
newWindow: boolean;
context: OpenContext;
fileUri?: URI;
userHome?: string;
codeSettingsFolder?: string;
localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null;
}
export function findBestWindowOrFolderForFile<W extends ISimpleWindow>({ windows, newWindow, context, fileUri, localWorkspaceResolver: workspaceResolver }: IBestWindowOrFolderOptions<W>): W | undefined {
if (!newWindow && fileUri && (context === OpenContext.DESKTOP || context === OpenContext.CLI || context === OpenContext.DOCK)) {
const windowOnFilePath = findWindowOnFilePath(windows, fileUri, workspaceResolver);
if (windowOnFilePath) {
return windowOnFilePath;
}
}
return !newWindow ? getLastActiveWindow(windows) : undefined;
}
function findWindowOnFilePath<W extends ISimpleWindow>(windows: W[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null): W | null {
// First check for windows with workspaces that have a parent folder of the provided path opened
for (const window of windows) {
const workspace = window.openedWorkspace;
if (workspace) {
const resolvedWorkspace = localWorkspaceResolver(workspace);
if (resolvedWorkspace) {
// workspace could be resolved: It's in the local file system
if (resolvedWorkspace.folders.some(folder => isEqualOrParent(fileUri, folder.uri))) {
return window;
}
} else {
// use the config path instead
if (isEqualOrParent(fileUri, workspace.configPath)) {
return window;
}
}
}
}
// Then go with single folder windows that are parent of the provided file path
const singleFolderWindowsOnFilePath = windows.filter(window => window.openedFolderUri && isEqualOrParent(fileUri, window.openedFolderUri));
if (singleFolderWindowsOnFilePath.length) {
return singleFolderWindowsOnFilePath.sort((a, b) => -(a.openedFolderUri!.path.length - b.openedFolderUri!.path.length))[0];
}
return null;
}
export function getLastActiveWindow<W extends ISimpleWindow>(windows: W[]): W | undefined {
const lastFocusedDate = Math.max.apply(Math, windows.map(window => window.lastFocusTime));
return windows.filter(window => window.lastFocusTime === lastFocusedDate)[0];
}
export function findWindowOnWorkspace<W extends ISimpleWindow>(windows: W[], workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)): W | null {
if (isSingleFolderWorkspaceIdentifier(workspace)) {
for (const window of windows) {
// match on folder
if (isSingleFolderWorkspaceIdentifier(workspace)) {
if (window.openedFolderUri && isEqual(window.openedFolderUri, workspace)) {
return window;
}
}
}
} else if (isWorkspaceIdentifier(workspace)) {
for (const window of windows) {
// match on workspace
if (window.openedWorkspace && window.openedWorkspace.id === workspace.id) {
return window;
}
}
}
return null;
}
export function findWindowOnExtensionDevelopmentPath<W extends ISimpleWindow>(windows: W[], extensionDevelopmentPaths: string[]): W | null {
const matches = (uriString: string): boolean => {
return extensionDevelopmentPaths.some(p => extpath.isEqual(p, uriString, !platform.isLinux /* ignorecase */));
};
for (const window of windows) {
// match on extension development path. The path can be one or more paths or uri strings, using paths.isEqual is not 100% correct but good enough
const currPaths = window.extensionDevelopmentPath;
if (currPaths && currPaths.some(p => matches(p))) {
return window;
}
}
return null;
}
export function findWindowOnWorkspaceOrFolderUri<W extends ISimpleWindow>(windows: W[], uri: URI | undefined): W | null {
if (!uri) {
return null;
}
for (const window of windows) {
// check for workspace config path
if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, uri)) {
return window;
}
// check for folder path
if (window.openedFolderUri && isEqual(window.openedFolderUri, uri)) {
return window;
}
}
return null;
}

View File

@@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform';
import { CharWidthRequest, CharWidthRequestType, readCharWidths } from 'vs/editor/browser/config/charWidthReader';
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
import { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig';
import { IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions';
import { EditorOption, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions';
import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo';
import { IDimension } from 'vs/editor/common/editorCommon';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
@@ -310,13 +310,13 @@ export class Configuration extends CommonEditorConfiguration {
constructor(
isSimpleWidget: boolean,
options: IEditorOptions,
options: IEditorConstructionOptions,
referenceDomElement: HTMLElement | null = null,
private readonly accessibilityService: IAccessibilityService
) {
super(isSimpleWidget, options);
this._elementSizeObserver = this._register(new ElementSizeObserver(referenceDomElement, () => this._onReferenceDomElementSizeChanged()));
this._elementSizeObserver = this._register(new ElementSizeObserver(referenceDomElement, options.dimension, () => this._onReferenceDomElementSizeChanged()));
this._register(CSSBasedConfiguration.INSTANCE.onDidChange(() => this._onCSSBasedConfigurationChanged()));

View File

@@ -14,14 +14,14 @@ export class ElementSizeObserver extends Disposable {
private width: number;
private height: number;
constructor(referenceDomElement: HTMLElement | null, changeCallback: () => void) {
constructor(referenceDomElement: HTMLElement | null, dimension: IDimension | undefined, changeCallback: () => void) {
super();
this.referenceDomElement = referenceDomElement;
this.changeCallback = changeCallback;
this.measureReferenceDomElementToken = -1;
this.width = -1;
this.height = -1;
this.measureReferenceDomElement(false);
this.measureReferenceDomElement(false, dimension);
}
public dispose(): void {
@@ -75,4 +75,4 @@ export class ElementSizeObserver extends Disposable {
}
}
}
}

View File

@@ -190,7 +190,7 @@ class TouchHandler extends MouseHandler {
constructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {
super(context, viewController, viewHelper);
Gesture.addTarget(this.viewHelper.linesContentDomNode);
this._register(Gesture.addTarget(this.viewHelper.linesContentDomNode));
this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Tap, (e) => this.onTap(e)));
this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Change, (e) => this.onChange(e)));

View File

@@ -152,6 +152,10 @@ export class TextAreaHandler extends ViewPart {
this.textArea.setAttribute('aria-haspopup', 'false');
this.textArea.setAttribute('aria-autocomplete', 'both');
if (platform.isWeb && options.get(EditorOption.readOnly)) {
this.textArea.setAttribute('readonly', 'true');
}
this.textAreaCover = createFastDomNode(document.createElement('div'));
this.textAreaCover.setPosition('absolute');
@@ -395,6 +399,14 @@ export class TextAreaHandler extends ViewPart {
this._copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting);
this.textArea.setAttribute('aria-label', this._getAriaLabel(options));
if (platform.isWeb && e.hasChanged(EditorOption.readOnly)) {
if (options.get(EditorOption.readOnly)) {
this.textArea.setAttribute('readonly', 'true');
} else {
this.textArea.removeAttribute('readonly');
}
}
if (e.hasChanged(EditorOption.accessibilitySupport)) {
this._textAreaInput.writeScreenReaderContent('strategy changed');
}

View File

@@ -29,6 +29,7 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic
import { ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel';
import { Selection } from 'vs/editor/common/core/selection';
import { Color } from 'vs/base/common/color';
import { GestureEvent, EventType, Gesture } from 'vs/base/browser/touch';
function getMinimapLineHeight(renderMinimap: RenderMinimap): number {
if (renderMinimap === RenderMinimap.Large) {
@@ -208,6 +209,10 @@ class MinimapLayout {
return Math.round(desiredSliderPosition / this._computedSliderRatio);
}
public getDesiredScrollTopFromTouchLocation(pageY: number): number {
return Math.round((pageY - this.sliderHeight / 2) / this._computedSliderRatio);
}
public static create(
options: MinimapOptions,
viewportStartLineNumber: number,
@@ -451,12 +456,17 @@ export class Minimap extends ViewPart {
private readonly _mouseDownListener: IDisposable;
private readonly _sliderMouseMoveMonitor: GlobalMouseMoveMonitor<IStandardMouseMoveEventData>;
private readonly _sliderMouseDownListener: IDisposable;
private readonly _gestureDisposable: IDisposable;
private readonly _sliderTouchStartListener: IDisposable;
private readonly _sliderTouchMoveListener: IDisposable;
private readonly _sliderTouchEndListener: IDisposable;
private _options: MinimapOptions;
private _lastRenderData: RenderData | null;
private _selections: Selection[] = [];
private _selectionColor: Color | undefined;
private _renderDecorations: boolean = false;
private _gestureInProgress: boolean = false;
private _buffers: MinimapBuffers | null;
constructor(context: ViewContext) {
@@ -566,12 +576,50 @@ export class Minimap extends ViewPart {
);
}
});
this._gestureDisposable = Gesture.addTarget(this._domNode.domNode);
this._sliderTouchStartListener = dom.addDisposableListener(this._domNode.domNode, EventType.Start, (e: GestureEvent) => {
e.preventDefault();
e.stopPropagation();
if (this._lastRenderData) {
this._slider.toggleClassName('active', true);
this._gestureInProgress = true;
this.scrollDueToTouchEvent(e);
}
});
this._sliderTouchMoveListener = dom.addStandardDisposableListener(this._domNode.domNode, EventType.Change, (e: GestureEvent) => {
e.preventDefault();
e.stopPropagation();
if (this._lastRenderData && this._gestureInProgress) {
this.scrollDueToTouchEvent(e);
}
});
this._sliderTouchEndListener = dom.addStandardDisposableListener(this._domNode.domNode, EventType.End, (e: GestureEvent) => {
e.preventDefault();
e.stopPropagation();
this._gestureInProgress = false;
this._slider.toggleClassName('active', false);
});
}
private scrollDueToTouchEvent(touch: GestureEvent) {
const startY = this._domNode.domNode.getBoundingClientRect().top;
const scrollTop = this._lastRenderData!.renderedLayout.getDesiredScrollTopFromTouchLocation(touch.pageY - startY);
this._context.viewLayout.setScrollPositionNow({
scrollTop: scrollTop
});
}
public dispose(): void {
this._mouseDownListener.dispose();
this._sliderMouseMoveMonitor.dispose();
this._sliderMouseDownListener.dispose();
this._gestureDisposable.dispose();
this._sliderTouchStartListener.dispose();
this._sliderTouchMoveListener.dispose();
this._sliderTouchEndListener.dispose();
super.dispose();
}

View File

@@ -23,7 +23,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService
import { ICommandDelegate } from 'vs/editor/browser/view/viewController';
import { IContentWidgetData, IOverlayWidgetData, View } from 'vs/editor/browser/view/viewImpl';
import { ViewOutgoingEvents } from 'vs/editor/browser/view/viewOutgoingEvents';
import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById } from 'vs/editor/common/config/editorOptions';
import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions';
import { Cursor, CursorStateChangedEvent } from 'vs/editor/common/controller/cursor';
import { CursorColumns, ICursors } from 'vs/editor/common/controller/cursorCommon';
import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
@@ -236,7 +236,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
constructor(
domElement: HTMLElement,
options: IEditorOptions,
options: IEditorConstructionOptions,
codeEditorWidgetOptions: ICodeEditorWidgetOptions,
@IInstantiationService instantiationService: IInstantiationService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@@ -329,7 +329,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
this._codeEditorService.addCodeEditor(this);
}
protected _createConfiguration(options: IEditorOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration {
protected _createConfiguration(options: IEditorConstructionOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration {
return new Configuration(this.isSimpleWidget, options, this._domElement, accessibilityService);
}

View File

@@ -12,6 +12,7 @@ import { USUAL_WORD_SEPARATORS } from 'vs/editor/common/model/wordHelper';
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { isObject } from 'vs/base/common/types';
import { IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
import { IDimension } from 'vs/editor/common/editorCommon';
//#region typed options
@@ -516,6 +517,13 @@ export interface IEditorOptions {
showUnused?: boolean;
}
export interface IEditorConstructionOptions extends IEditorOptions {
/**
* The initial editor dimension (to avoid measuring the container).
*/
dimension?: IDimension;
}
/**
* Configuration options for the diff editor.
*/

View File

@@ -280,6 +280,8 @@ export interface IEditor {
/**
* Instructs the editor to remeasure its container. This method should
* be called when the container of the editor gets resized.
*
* If a dimension is passed in, the passed in value will be used.
*/
layout(dimension?: IDimension): void;

View File

@@ -922,7 +922,7 @@ export interface DocumentSymbol {
/**
* The document symbol provider interface defines the contract between extensions and
* the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_goto-symbol)-feature.
* the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature.
*/
export interface DocumentSymbolProvider {

View File

@@ -14,7 +14,7 @@ import { ScrollType, IEditorContribution } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, registerInstantiatedEditorAction } from 'vs/editor/browser/editorExtensions';
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateForType } from 'vs/editor/contrib/folding/foldingModel';
import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateForType, toggleCollapseState } from 'vs/editor/contrib/folding/foldingModel';
import { FoldingDecorationProvider } from './foldingDecorations';
import { FoldingRegions, FoldingRegion } from './foldingRanges';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
@@ -656,6 +656,30 @@ class FoldAction extends FoldingAction<FoldingArguments> {
}
}
class ToggleFoldAction extends FoldingAction<void> {
constructor() {
super({
id: 'editor.toggleFold',
label: nls.localize('toggleFoldAction.label', "Toggle Fold"),
alias: 'Toggle Fold',
precondition: CONTEXT_FOLDING_ENABLED,
kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus,
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_K),
weight: KeybindingWeight.EditorContrib
}
});
}
invoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {
let selectedLines = this.getSelectedLines(editor);
toggleCollapseState(foldingModel, 1, selectedLines);
}
}
class FoldRecursivelyAction extends FoldingAction<void> {
constructor() {
@@ -842,6 +866,7 @@ registerEditorAction(UnfoldAllAction);
registerEditorAction(FoldAllBlockCommentsAction);
registerEditorAction(FoldAllRegionsAction);
registerEditorAction(UnfoldAllRegionsAction);
registerEditorAction(ToggleFoldAction);
for (let i = 1; i <= 7; i++) {
registerInstantiatedEditorAction(

View File

@@ -242,6 +242,26 @@ export class FoldingModel {
}
/**
* Collapse or expand the regions at the given locations
* @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels.
* @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model.
*/
export function toggleCollapseState(foldingModel: FoldingModel, levels: number, lineNumbers: number[]) {
let toToggle: FoldingRegion[] = [];
for (let lineNumber of lineNumbers) {
let region = foldingModel.getRegionAtLine(lineNumber);
if (region) {
const doCollapse = !region.isCollapsed;
toToggle.push(region);
if (levels > 1) {
let regionsInside = foldingModel.getRegionsInside(region, (r, level: number) => r.isCollapsed !== doCollapse && level < levels);
toToggle.push(...regionsInside);
}
}
}
foldingModel.toggleCollapseState(toToggle);
}
/**

View File

@@ -37,7 +37,7 @@
margin: 8px 0;
}
.monaco-editor-hover p > code {
.monaco-editor-hover code {
font-family: var(--monaco-monospace-font);
}

View File

@@ -53,7 +53,7 @@
padding-left: 20px;
}
.monaco-editor .suggest-widget > .details p > code {
.monaco-editor .suggest-widget > .details p code {
font-family: var(--monaco-monospace-font);
}

View File

@@ -21,7 +21,7 @@ import { Selection } from 'vs/editor/common/core/selection';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { ToggleTabFocusModeAction } from 'vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode';
import { IEditorConstructionOptions } from 'vs/editor/standalone/browser/standaloneCodeEditor';
import { IStandaloneEditorConstructionOptions } from 'vs/editor/standalone/browser/standaloneCodeEditor';
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -164,7 +164,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget {
if (e.equals(KeyMod.CtrlCmd | KeyCode.KEY_H)) {
alert(AccessibilityHelpNLS.openingDocs);
let url = (<IEditorConstructionOptions>this._editor.getRawOptions()).accessibilityHelpUrl;
let url = (<IStandaloneEditorConstructionOptions>this._editor.getRawOptions()).accessibilityHelpUrl;
if (typeof url === 'undefined') {
url = 'https://go.microsoft.com/fwlink/?linkid=852450';
}

View File

@@ -10,7 +10,7 @@ import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget';
import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { IDiffEditorOptions, IEditorOptions, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions';
import { InternalEditorAction } from 'vs/editor/common/editorAction';
import { IModelChangedEvent } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
@@ -79,7 +79,7 @@ export interface IActionDescriptor {
/**
* The options to create an editor.
*/
export interface IEditorConstructionOptions extends IEditorOptions {
export interface IStandaloneEditorConstructionOptions extends IEditorConstructionOptions {
/**
* The initial model associated with this code editor.
*/
@@ -158,7 +158,7 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon
constructor(
domElement: HTMLElement,
options: IEditorConstructionOptions,
options: IStandaloneEditorConstructionOptions,
@IInstantiationService instantiationService: IInstantiationService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@ICommandService commandService: ICommandService,
@@ -287,7 +287,7 @@ export class StandaloneEditor extends StandaloneCodeEditor implements IStandalon
constructor(
domElement: HTMLElement,
options: IEditorConstructionOptions | undefined,
options: IStandaloneEditorConstructionOptions | undefined,
toDispose: IDisposable,
@IInstantiationService instantiationService: IInstantiationService,
@ICodeEditorService codeEditorService: ICodeEditorService,

View File

@@ -24,7 +24,7 @@ import { IWebWorkerOptions, MonacoWebWorker, createWebWorker as actualCreateWebW
import * as standaloneEnums from 'vs/editor/common/standalone/standaloneEnums';
import { Colorizer, IColorizerElementOptions, IColorizerOptions } from 'vs/editor/standalone/browser/colorizer';
import { SimpleEditorModelResolverService } from 'vs/editor/standalone/browser/simpleServices';
import { IDiffEditorConstructionOptions, IEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor, StandaloneDiffEditor, StandaloneEditor } from 'vs/editor/standalone/browser/standaloneCodeEditor';
import { IDiffEditorConstructionOptions, IStandaloneEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor, StandaloneDiffEditor, StandaloneEditor } from 'vs/editor/standalone/browser/standaloneCodeEditor';
import { DynamicStandaloneServices, IEditorOverrideServices, StaticServices } from 'vs/editor/standalone/browser/standaloneServices';
import { IStandaloneThemeData, IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService';
import { ICommandService } from 'vs/platform/commands/common/commands';
@@ -68,7 +68,7 @@ function withAllStandaloneServices<T extends editorCommon.IEditor>(domElement: H
* `domElement` should be empty (not contain other dom nodes).
* The editor will read the size of `domElement`.
*/
export function create(domElement: HTMLElement, options?: IEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor {
export function create(domElement: HTMLElement, options?: IStandaloneEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor {
return withAllStandaloneServices(domElement, override || {}, (services) => {
return new StandaloneEditor(
domElement,

View File

@@ -29,7 +29,7 @@ import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService
export class TestCodeEditor extends CodeEditorWidget implements editorBrowser.ICodeEditor {
//#region testing overrides
protected _createConfiguration(options: editorOptions.IEditorOptions): editorCommon.IConfiguration {
protected _createConfiguration(options: editorOptions.IEditorConstructionOptions): editorCommon.IConfiguration {
return new TestConfiguration(options);
}
protected _createView(viewModel: ViewModel, cursor: Cursor): [View, boolean] {

15
src/vs/monaco.d.ts vendored
View File

@@ -813,7 +813,7 @@ declare namespace monaco.editor {
* `domElement` should be empty (not contain other dom nodes).
* The editor will read the size of `domElement`.
*/
export function create(domElement: HTMLElement, options?: IEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor;
export function create(domElement: HTMLElement, options?: IStandaloneEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor;
/**
* Emitted when an editor is created.
@@ -1051,7 +1051,7 @@ declare namespace monaco.editor {
/**
* The options to create an editor.
*/
export interface IEditorConstructionOptions extends IEditorOptions {
export interface IStandaloneEditorConstructionOptions extends IEditorConstructionOptions {
/**
* The initial model associated with this code editor.
*/
@@ -2061,6 +2061,8 @@ declare namespace monaco.editor {
/**
* Instructs the editor to remeasure its container. This method should
* be called when the container of the editor gets resized.
*
* If a dimension is passed in, the passed in value will be used.
*/
layout(dimension?: IDimension): void;
/**
@@ -2918,6 +2920,13 @@ declare namespace monaco.editor {
showUnused?: boolean;
}
export interface IEditorConstructionOptions extends IEditorOptions {
/**
* The initial editor dimension (to avoid measuring the container).
*/
dimension?: IDimension;
}
/**
* Configuration options for the diff editor.
*/
@@ -5131,7 +5140,7 @@ declare namespace monaco.languages {
/**
* The document symbol provider interface defines the contract between extensions and
* the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_goto-symbol)-feature.
* the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature.
*/
export interface DocumentSymbolProvider {
displayName?: string;

View File

@@ -8,6 +8,7 @@ import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
import { Disposable } from 'vs/base/common/lifecycle';
import { IProductService } from 'vs/platform/product/common/productService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
const SERVICE_NAME = 'VS Code';
const ACCOUNT = 'MyAccount';
@@ -23,9 +24,10 @@ export class AuthTokenService extends Disposable implements IAuthTokenService {
constructor(
@ICredentialsService private readonly credentialsService: ICredentialsService,
@IProductService productService: IProductService,
@IConfigurationService configurationService: IConfigurationService,
) {
super();
if (productService.settingsSyncStoreUrl) {
if (productService.settingsSyncStoreUrl && configurationService.getValue('configurationSync.enableAuth')) {
this._status = AuthTokenStatus.Inactive;
this.getToken().then(token => {
if (token) {

View File

@@ -0,0 +1,211 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { MessageBoxOptions, SaveDialogOptions, OpenDialogOptions, dialog, FileFilter, BrowserWindow } from 'electron';
import { Queue } from 'vs/base/common/async';
import { IStateService } from 'vs/platform/state/node/state';
import { isMacintosh } from 'vs/base/common/platform';
import { dirname } from 'vs/base/common/path';
import { normalizeNFC } from 'vs/base/common/normalization';
import { exists } from 'vs/base/node/pfs';
import { INativeOpenDialogOptions, MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue } from 'vs/platform/dialogs/node/dialogs';
import { withNullAsUndefined } from 'vs/base/common/types';
import { localize } from 'vs/nls';
import { WORKSPACE_FILTER } from 'vs/platform/workspaces/common/workspaces';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
export const IDialogMainService = createDecorator<IDialogMainService>('dialogMainService');
export interface IDialogMainService {
_serviceBrand: undefined;
pickFileFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined>;
pickFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined>;
pickFile(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined>;
pickWorkspace(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined>;
showMessageBox(options: MessageBoxOptions, window?: BrowserWindow): Promise<MessageBoxReturnValue>;
showSaveDialog(options: SaveDialogOptions, window?: BrowserWindow): Promise<SaveDialogReturnValue>;
showOpenDialog(options: OpenDialogOptions, window?: BrowserWindow): Promise<OpenDialogReturnValue>;
}
interface IInternalNativeOpenDialogOptions extends INativeOpenDialogOptions {
pickFolders?: boolean;
pickFiles?: boolean;
title: string;
buttonLabel?: string;
filters?: FileFilter[];
}
export class DialogMainService implements IDialogMainService {
_serviceBrand: undefined;
private static readonly workingDirPickerStorageKey = 'pickerWorkingDir';
private readonly mapWindowToDialogQueue: Map<number, Queue<void>>;
private readonly noWindowDialogQueue: Queue<void>;
constructor(
@IStateService private readonly stateService: IStateService
) {
this.mapWindowToDialogQueue = new Map<number, Queue<void>>();
this.noWindowDialogQueue = new Queue<void>();
}
pickFileFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined> {
return this.doPick({ ...options, pickFolders: true, pickFiles: true, title: localize('open', "Open") }, window);
}
pickFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined> {
return this.doPick({ ...options, pickFolders: true, title: localize('openFolder', "Open Folder") }, window);
}
pickFile(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined> {
return this.doPick({ ...options, pickFiles: true, title: localize('openFile', "Open File") }, window);
}
pickWorkspace(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined> {
const title = localize('openWorkspaceTitle', "Open Workspace");
const buttonLabel = mnemonicButtonLabel(localize({ key: 'openWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open"));
const filters = WORKSPACE_FILTER;
return this.doPick({ ...options, pickFiles: true, title, filters, buttonLabel }, window);
}
private async doPick(options: IInternalNativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined> {
// Ensure dialog options
const dialogOptions: OpenDialogOptions = {
title: options.title,
buttonLabel: options.buttonLabel,
filters: options.filters
};
// Ensure defaultPath
dialogOptions.defaultPath = options.defaultPath || this.stateService.getItem<string>(DialogMainService.workingDirPickerStorageKey);
// Ensure properties
if (typeof options.pickFiles === 'boolean' || typeof options.pickFolders === 'boolean') {
dialogOptions.properties = undefined; // let it override based on the booleans
if (options.pickFiles && options.pickFolders) {
dialogOptions.properties = ['multiSelections', 'openDirectory', 'openFile', 'createDirectory'];
}
}
if (!dialogOptions.properties) {
dialogOptions.properties = ['multiSelections', options.pickFolders ? 'openDirectory' : 'openFile', 'createDirectory'];
}
if (isMacintosh) {
dialogOptions.properties.push('treatPackageAsDirectory'); // always drill into .app files
}
// Show Dialog
const windowToUse = window || BrowserWindow.getFocusedWindow();
const result = await this.showOpenDialog(dialogOptions, withNullAsUndefined(windowToUse));
if (result && result.filePaths && result.filePaths.length > 0) {
// Remember path in storage for next time
this.stateService.setItem(DialogMainService.workingDirPickerStorageKey, dirname(result.filePaths[0]));
return result.filePaths;
}
return undefined; // {{SQL CARBON EDIT}} strict-null-check
}
private getDialogQueue(window?: BrowserWindow): Queue<any> {
if (!window) {
return this.noWindowDialogQueue;
}
let windowDialogQueue = this.mapWindowToDialogQueue.get(window.id);
if (!windowDialogQueue) {
windowDialogQueue = new Queue<any>();
this.mapWindowToDialogQueue.set(window.id, windowDialogQueue);
}
return windowDialogQueue;
}
showMessageBox(options: MessageBoxOptions, window?: BrowserWindow): Promise<MessageBoxReturnValue> {
return this.getDialogQueue(window).queue(async () => {
return new Promise(resolve => {
if (window) {
return dialog.showMessageBox(window, options, (response, checkboxChecked) => resolve({ response, checkboxChecked }));
}
return dialog.showMessageBox(options);
});
});
}
showSaveDialog(options: SaveDialogOptions, window?: BrowserWindow): Promise<SaveDialogReturnValue> {
function normalizePath(path: string | undefined): string | undefined {
if (path && isMacintosh) {
path = normalizeNFC(path); // normalize paths returned from the OS
}
return path;
}
return this.getDialogQueue(window).queue(async () => {
return new Promise<SaveDialogReturnValue>(resolve => {
if (window) {
dialog.showSaveDialog(window, options, filePath => resolve({ filePath }));
} else {
dialog.showSaveDialog(options, filePath => resolve({ filePath }));
}
}).then(result => {
result.filePath = normalizePath(result.filePath);
return result;
});
});
}
showOpenDialog(options: OpenDialogOptions, window?: BrowserWindow): Promise<OpenDialogReturnValue> {
function normalizePaths(paths: string[] | undefined): string[] | undefined {
if (paths && paths.length > 0 && isMacintosh) {
paths = paths.map(path => normalizeNFC(path)); // normalize paths returned from the OS
}
return paths;
}
return this.getDialogQueue(window).queue(async () => {
// Ensure the path exists (if provided)
if (options.defaultPath) {
const pathExists = await exists(options.defaultPath);
if (!pathExists) {
options.defaultPath = undefined;
}
}
// Show dialog
return new Promise<OpenDialogReturnValue>(resolve => {
if (window) {
dialog.showOpenDialog(window, options, filePaths => resolve({ filePaths }));
} else {
dialog.showOpenDialog(options, filePaths => resolve({ filePaths }));
}
}).then(result => {
result.filePaths = normalizePaths(result.filePaths);
return result;
});
});
}
}

View File

@@ -13,3 +13,16 @@ export interface INativeOpenDialogOptions {
telemetryEventName?: string;
telemetryExtraData?: ITelemetryData;
}
export interface MessageBoxReturnValue {
response: number;
checkboxChecked: boolean;
}
export interface SaveDialogReturnValue {
filePath?: string;
}
export interface OpenDialogReturnValue {
filePaths?: string[];
}

View File

@@ -5,16 +5,17 @@
import { Event } from 'vs/base/common/event';
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import { MessageBoxOptions, MessageBoxReturnValue, shell, OpenDevToolsOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, CrashReporterStartOptions, crashReporter, Menu, BrowserWindow, app } from 'electron';
import { INativeOpenInWindowOptions } from 'vs/platform/windows/node/window';
import { MessageBoxOptions, shell, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, CrashReporterStartOptions, crashReporter, Menu, BrowserWindow, app } from 'electron';
import { INativeOpenWindowOptions } from 'vs/platform/windows/node/window';
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { IOpenedWindow, OpenContext, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows';
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs';
import { INativeOpenDialogOptions, MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue } from 'vs/platform/dialogs/node/dialogs';
import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform';
import { IElectronService } from 'vs/platform/electron/node/electron';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { AddFirstParameterToFunctions } from 'vs/base/common/types';
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
export class ElectronMainService implements AddFirstParameterToFunctions<IElectronService, Promise<any> /* only methods, not events */, number /* window ID */> {
@@ -22,6 +23,7 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
constructor(
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
@IDialogMainService private readonly dialogMainService: IDialogMainService,
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
@IEnvironmentService private readonly environmentService: IEnvironmentService
) {
@@ -61,7 +63,7 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
}
async getActiveWindowId(windowId: number): Promise<number | undefined> {
const activeWindow = this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow();
const activeWindow = BrowserWindow.getFocusedWindow() || this.windowsMainService.getLastActiveWindow();
if (activeWindow) {
return activeWindow.id;
}
@@ -69,11 +71,17 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
return undefined;
}
async openEmptyWindow(windowId: number, options?: IOpenEmptyWindowOptions): Promise<void> {
this.windowsMainService.openEmptyWindow(OpenContext.API, options);
openWindow(windowId: number, options?: IOpenEmptyWindowOptions): Promise<void>;
openWindow(windowId: number, toOpen: IWindowOpenable[], options?: INativeOpenWindowOptions): Promise<void>;
openWindow(windowId: number, arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: INativeOpenWindowOptions): Promise<void> {
if (Array.isArray(arg1)) {
return this.doOpenWindow(windowId, arg1, arg2);
}
return this.doOpenEmptyWindow(windowId, arg1);
}
async openInWindow(windowId: number, toOpen: IWindowOpenable[], options: INativeOpenInWindowOptions = Object.create(null)): Promise<void> {
private async doOpenWindow(windowId: number, toOpen: IWindowOpenable[], options: INativeOpenWindowOptions = Object.create(null)): Promise<void> {
if (toOpen.length > 0) {
this.windowsMainService.open({
context: OpenContext.API,
@@ -91,6 +99,10 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
}
}
private async doOpenEmptyWindow(windowId: number, options?: IOpenEmptyWindowOptions): Promise<void> {
this.windowsMainService.openEmptyWindow(OpenContext.API, options);
}
async toggleFullScreen(windowId: number): Promise<void> {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
@@ -164,15 +176,24 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
//#region Dialog
async showMessageBox(windowId: number, options: MessageBoxOptions): Promise<MessageBoxReturnValue> {
return this.windowsMainService.showMessageBox(options, this.windowsMainService.getWindowById(windowId));
return this.dialogMainService.showMessageBox(options, this.toBrowserWindow(windowId));
}
async showSaveDialog(windowId: number, options: SaveDialogOptions): Promise<SaveDialogReturnValue> {
return this.windowsMainService.showSaveDialog(options, this.windowsMainService.getWindowById(windowId));
return this.dialogMainService.showSaveDialog(options, this.toBrowserWindow(windowId));
}
async showOpenDialog(windowId: number, options: OpenDialogOptions): Promise<OpenDialogReturnValue> {
return this.windowsMainService.showOpenDialog(options, this.windowsMainService.getWindowById(windowId));
return this.dialogMainService.showOpenDialog(options, this.toBrowserWindow(windowId));
}
private toBrowserWindow(windowId: number): BrowserWindow | undefined {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
return window.win;
}
return undefined;
}
async pickFileFolderAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
@@ -214,7 +235,9 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
}
async openExternal(windowId: number, url: string): Promise<boolean> {
return this.windowsMainService.openExternal(url);
shell.openExternal(url);
return true;
}
async updateTouchBar(windowId: number, items: ISerializableCommandAction[][]): Promise<void> {
@@ -229,7 +252,7 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
//#region macOS Touchbar
async newWindowTab(): Promise<void> {
this.windowsMainService.openNewTabbedWindow(OpenContext.API);
this.windowsMainService.open({ context: OpenContext.API, cli: this.environmentService.args, forceNewTabbedWindow: true, forceEmpty: true });
}
async showPreviousWindowTab(): Promise<void> {
@@ -267,7 +290,7 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
}
}
async closeWorkpsace(windowId: number): Promise<void> {
async closeWorkspace(windowId: number): Promise<void> {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
return this.windowsMainService.closeWorkspace(window);

View File

@@ -4,14 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { MessageBoxOptions, MessageBoxReturnValue, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, OpenDialogReturnValue, SaveDialogReturnValue, CrashReporterStartOptions } from 'electron';
import { MessageBoxOptions, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, CrashReporterStartOptions } from 'electron';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IWindowOpenable, IOpenEmptyWindowOptions, IOpenedWindow } from 'vs/platform/windows/common/windows';
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs';
import { INativeOpenDialogOptions, MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue } from 'vs/platform/dialogs/node/dialogs';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { ParsedArgs } from 'vscode-minimist';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { INativeOpenInWindowOptions } from 'vs/platform/windows/node/window';
import { INativeOpenWindowOptions } from 'vs/platform/windows/node/window';
export const IElectronService = createDecorator<IElectronService>('electronService');
@@ -33,8 +33,8 @@ export interface IElectronService {
getWindowCount(): Promise<number>;
getActiveWindowId(): Promise<number | undefined>;
openEmptyWindow(options?: IOpenEmptyWindowOptions): Promise<void>;
openInWindow(toOpen: IWindowOpenable[], options?: INativeOpenInWindowOptions): Promise<void>;
openWindow(options?: IOpenEmptyWindowOptions): Promise<void>;
openWindow(toOpen: IWindowOpenable[], options?: INativeOpenWindowOptions): Promise<void>;
toggleFullScreen(): Promise<void>;
@@ -76,7 +76,7 @@ export interface IElectronService {
// Lifecycle
relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): Promise<void>;
reload(): Promise<void>;
closeWorkpsace(): Promise<void>;
closeWorkspace(): Promise<void>;
closeWindow(): Promise<void>;
quit(): Promise<void>;

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ISharedProcess } from 'vs/platform/windows/electron-main/windows';
export const ISharedProcessMainService = createDecorator<ISharedProcessMainService>('sharedProcessMainService');
@@ -15,6 +14,12 @@ export interface ISharedProcessMainService {
whenSharedProcessReady(): Promise<void>;
toggleSharedProcessWindow(): Promise<void>;
}
export interface ISharedProcess {
whenReady(): Promise<void>;
toggle(): void;
}
export class SharedProcessMainService implements ISharedProcessMainService {
_serviceBrand: undefined;

View File

@@ -7,15 +7,16 @@ import { localize } from 'vs/nls';
import * as objects from 'vs/base/common/objects';
import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv';
import { IIssueService, IssueReporterData, IssueReporterFeatures, ProcessExplorerData } from 'vs/platform/issue/node/issue';
import { BrowserWindow, ipcMain, screen, dialog, IpcMainEvent, Display } from 'electron';
import { BrowserWindow, ipcMain, screen, Event as IpcMainEvent, Display, shell } from 'electron';
import { ILaunchMainService } from 'vs/platform/launch/electron-main/launchMainService';
import { PerformanceInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics';
import { IDiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform';
import { ILogService } from 'vs/platform/log/common/log';
import { IWindowState, IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import { IWindowState } from 'vs/platform/windows/electron-main/windows';
import { listProcesses } from 'vs/base/node/ps';
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
const DEFAULT_BACKGROUND_COLOR = '#1E1E1E';
@@ -33,7 +34,7 @@ export class IssueMainService implements IIssueService {
@ILaunchMainService private readonly launchMainService: ILaunchMainService,
@ILogService private readonly logService: ILogService,
@IDiagnosticsService private readonly diagnosticsService: IDiagnosticsService,
@IWindowsMainService private readonly windowsMainService: IWindowsMainService
@IDialogMainService private readonly dialogMainService: IDialogMainService
) {
this.registerListeners();
}
@@ -89,7 +90,7 @@ export class IssueMainService implements IIssueService {
};
if (this._issueWindow) {
dialog.showMessageBox(this._issueWindow, messageOptions)
this.dialogMainService.showMessageBox(messageOptions, this._issueWindow)
.then(result => {
event.sender.send('vscode:issueReporterClipboardResponse', result.response === 0);
});
@@ -113,7 +114,7 @@ export class IssueMainService implements IIssueService {
};
if (this._issueWindow) {
dialog.showMessageBox(this._issueWindow, messageOptions)
this.dialogMainService.showMessageBox(messageOptions, this._issueWindow)
.then(result => {
if (result.response === 0) {
if (this._issueWindow) {
@@ -146,7 +147,7 @@ export class IssueMainService implements IIssueService {
});
ipcMain.on('vscode:openExternal', (_: unknown, arg: string) => {
this.windowsMainService.openExternal(arg);
shell.openExternal(arg);
});
ipcMain.on('vscode:closeIssueReporter', (event: IpcMainEvent) => {

View File

@@ -141,6 +141,7 @@ export class LaunchMainService implements ILaunchMainService {
}
}
// Open new Window
if (openNewWindow) {
usedWindows = this.windowsMainService.open({
context,
@@ -150,8 +151,18 @@ export class LaunchMainService implements ILaunchMainService {
forceEmpty: true,
waitMarkerFileURI
});
} else {
usedWindows = [this.windowsMainService.focusLastActive(args, context)];
}
// Focus existing window or open if none opened
else {
const lastActive = this.windowsMainService.getLastActiveWindow();
if (lastActive) {
lastActive.focus();
usedWindows = [lastActive];
} else {
usedWindows = this.windowsMainService.open({ context, cli: args, forceEmpty: true });
}
}
}
@@ -216,7 +227,7 @@ export class LaunchMainService implements ILaunchMainService {
mainPID: process.pid,
mainArguments: process.argv.slice(1),
windows,
screenReader: !!app.accessibilitySupportEnabled,
screenReader: !!app.isAccessibilitySupportEnabled(),
gpuFeatureStatus: app.getGPUFeatureStatus()
});
}

View File

@@ -87,4 +87,10 @@ export class BufferLogService extends AbstractLogService implements ILogService
this._logger.dispose();
}
}
flush(): void {
if (this._logger) {
this._logger.flush();
}
}
}

View File

@@ -78,8 +78,7 @@ export class FileLogService extends AbstractLogService implements ILogService {
}
}
flush(): Promise<void> {
return this.queue.queue(() => Promise.resolve());
flush(): void {
}
log(level: LogLevel, args: any[]): void {

View File

@@ -41,6 +41,11 @@ export interface ILogger extends IDisposable {
warn(message: string, ...args: any[]): void;
error(message: string | Error, ...args: any[]): void;
critical(message: string | Error, ...args: any[]): void;
/**
* An operation to flush the contents. Can be synchronous.
*/
flush(): void;
}
export interface ILogService extends ILogger {
@@ -69,6 +74,7 @@ export abstract class AbstractLogService extends Disposable {
getLevel(): LogLevel {
return this.level;
}
}
export class ConsoleLogMainService extends AbstractLogService implements ILogService {
@@ -145,6 +151,11 @@ export class ConsoleLogMainService extends AbstractLogService implements ILogSer
dispose(): void {
// noop
}
flush(): void {
// noop
}
}
export class ConsoleLogService extends AbstractLogService implements ILogService {
@@ -192,7 +203,13 @@ export class ConsoleLogService extends AbstractLogService implements ILogService
}
}
dispose(): void { }
dispose(): void {
// noop
}
flush(): void {
// noop
}
}
export class ConsoleLogInMainService extends AbstractLogService implements ILogService {
@@ -240,7 +257,13 @@ export class ConsoleLogInMainService extends AbstractLogService implements ILogS
}
}
dispose(): void { }
dispose(): void {
// noop
}
flush(): void {
// noop
}
}
export class MultiplexLogService extends AbstractLogService implements ILogService {
@@ -296,6 +319,12 @@ export class MultiplexLogService extends AbstractLogService implements ILogServi
}
}
flush(): void {
for (const logService of this.logServices) {
logService.flush();
}
}
dispose(): void {
for (const logService of this.logServices) {
logService.dispose();
@@ -346,6 +375,10 @@ export class DelegatedLogService extends Disposable implements ILogService {
critical(message: string | Error, ...args: any[]): void {
this.logService.critical(message, ...args);
}
flush(): void {
this.logService.flush();
}
}
export class NullLogService implements ILogService {
@@ -360,6 +393,7 @@ export class NullLogService implements ILogService {
error(message: string | Error, ...args: any[]): void { }
critical(message: string | Error, ...args: any[]): void { }
dispose(): void { }
flush(): void { }
}
export function getLogLevel(environmentService: IEnvironmentService): LogLevel {

View File

@@ -32,7 +32,7 @@ export class LoggerService extends Disposable implements ILoggerService {
if (resource.scheme === Schemas.file) {
const baseName = basename(resource);
const ext = extname(resource);
logger = new SpdLogService(baseName.substring(0, baseName.length - ext.length), dirname(resource).path, this.logService.getLevel());
logger = new SpdLogService(baseName.substring(0, baseName.length - ext.length), dirname(resource).fsPath, this.logService.getLevel());
} else {
logger = this.instantiationService.createInstance(FileLogService, basename(resource), resource, this.logService.getLevel());
}

View File

@@ -30,7 +30,7 @@ interface ILog {
message: string;
}
function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string, sync: boolean): void {
function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string): void {
switch (level) {
case LogLevel.Trace: logger.trace(message); break;
case LogLevel.Debug: logger.debug(message); break;
@@ -40,9 +40,6 @@ function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string, sy
case LogLevel.Critical: logger.critical(message); break;
default: throw new Error('Invalid log level');
}
if (sync) {
logger.flush();
}
}
export class SpdLogService extends AbstractLogService implements ILogService {
@@ -53,7 +50,7 @@ export class SpdLogService extends AbstractLogService implements ILogService {
private _loggerCreationPromise: Promise<void> | undefined = undefined;
private _logger: spdlog.RotatingLogger | undefined;
constructor(private readonly name: string, private readonly logsFolder: string, level: LogLevel, private readonly sync: boolean = false) {
constructor(private readonly name: string, private readonly logsFolder: string, level: LogLevel) {
super();
this.setLevel(level);
this._createSpdLogLogger();
@@ -72,7 +69,7 @@ export class SpdLogService extends AbstractLogService implements ILogService {
this._logger = logger;
this._logger.setLevel(this.getLevel());
for (const { level, message } of this.buffer) {
log(this._logger, level, message, this.sync);
log(this._logger, level, message);
}
this.buffer = [];
}
@@ -83,7 +80,7 @@ export class SpdLogService extends AbstractLogService implements ILogService {
private _log(level: LogLevel, message: string): void {
if (this._logger) {
log(this._logger, level, message, this.sync);
log(this._logger, level, message);
} else if (this.getLevel() <= level) {
this.buffer.push({ level, message });
}
@@ -132,6 +129,14 @@ export class SpdLogService extends AbstractLogService implements ILogService {
}
}
flush(): void {
if (this._logger) {
this._logger.flush();
} else if (this._loggerCreationPromise) {
this._loggerCreationPromise.then(() => this.flush());
}
}
dispose(): void {
if (this._logger) {
this.disposeLogger();

View File

@@ -6,7 +6,7 @@
import * as nls from 'vs/nls';
import { isMacintosh, language } from 'vs/base/common/platform';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { app, shell, Menu, MenuItem, BrowserWindow, MenuItemConstructorOptions, WebContents, Event, KeyboardEvent } from 'electron';
import { app, shell, Menu, MenuItem, BrowserWindow, MenuItemConstructorOptions, WebContents, Event, Event as KeyboardEvent } from 'electron';
import { OpenContext, IRunActionInWindowRequest, getTitleBarStyle, IRunKeybindingInWindowRequest, IWindowOpenable } from 'vs/platform/windows/common/windows';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@@ -368,13 +368,13 @@ export class Menubar {
const servicesMenu = new Menu();
const services = new MenuItem({ label: nls.localize('mServices', "Services"), role: 'services', submenu: servicesMenu });
const hide = new MenuItem({ label: nls.localize('mHide', "Hide {0}", product.nameLong), role: 'hide', accelerator: 'Command+H' });
const hideOthers = new MenuItem({ label: nls.localize('mHideOthers', "Hide Others"), role: 'hideOthers', accelerator: 'Command+Alt+H' });
const hideOthers = new MenuItem({ label: nls.localize('mHideOthers', "Hide Others"), role: 'hideothers', accelerator: 'Command+Alt+H' });
const showAll = new MenuItem({ label: nls.localize('mShowAll', "Show All"), role: 'unhide' });
const quit = new MenuItem(this.likeAction('workbench.action.quit', {
label: nls.localize('miQuit', "Quit {0}", product.nameLong), click: () => {
if (
this.windowsMainService.getWindowCount() === 0 || // allow to quit when no more windows are open
!!this.windowsMainService.getFocusedWindow() || // allow to quit when window has focus (fix for https://github.com/Microsoft/vscode/issues/39191)
this.windowsMainService.getWindowCount() === 0 || // allow to quit when no more windows are open
!!BrowserWindow.getFocusedWindow() || // allow to quit when window has focus (fix for https://github.com/Microsoft/vscode/issues/39191)
this.windowsMainService.getLastActiveWindow()!.isMinimized() // allow to quit when window has no focus but is minimized (https://github.com/Microsoft/vscode/issues/63000)
) {
this.windowsMainService.quit();
@@ -557,7 +557,7 @@ export class Menubar {
label: this.mnemonicLabel(nls.localize('miCheckForUpdates', "Check for &&Updates...")), click: () => setTimeout(() => {
this.reportMenuActionTelemetry('CheckForUpdate');
const focusedWindow = this.windowsMainService.getFocusedWindow();
const focusedWindow = BrowserWindow.getFocusedWindow();
const context = focusedWindow ? { windowId: focusedWindow.id } : null;
this.updateService.checkForUpdates(context);
}, 0)
@@ -697,15 +697,16 @@ export class Menubar {
private makeContextAwareClickHandler(click: () => void, contextSpecificHandlers: IMenuItemClickHandler): () => void {
return () => {
// No Active Window
const activeWindow = this.windowsMainService.getFocusedWindow();
const activeWindow = BrowserWindow.getFocusedWindow();
if (!activeWindow) {
return contextSpecificHandlers.inNoWindow();
}
// DevTools focused
if (activeWindow.win.webContents.isDevToolsFocused()) {
return contextSpecificHandlers.inDevTools(activeWindow.win.webContents.devToolsWebContents);
if (activeWindow.webContents.isDevToolsFocused()) {
return contextSpecificHandlers.inDevTools(activeWindow.webContents.devToolsWebContents);
}
// Finally execute command in Window
@@ -719,14 +720,15 @@ export class Menubar {
// https://github.com/Microsoft/vscode/issues/11928
// Still allow to run when the last active window is minimized though for
// https://github.com/Microsoft/vscode/issues/63000
let activeWindow = this.windowsMainService.getFocusedWindow();
if (!activeWindow) {
let activeBrowserWindow = BrowserWindow.getFocusedWindow();
if (!activeBrowserWindow) {
const lastActiveWindow = this.windowsMainService.getLastActiveWindow();
if (lastActiveWindow && lastActiveWindow.isMinimized()) {
activeWindow = lastActiveWindow;
activeBrowserWindow = lastActiveWindow.win;
}
}
const activeWindow = activeBrowserWindow ? this.windowsMainService.getWindowById(activeBrowserWindow.id) : undefined;
if (activeWindow) {
this.logService.trace('menubar#runActionInRenderer', invocation);

View File

@@ -27,7 +27,7 @@ export function extractLocalHostUriMetaDataForPortMapping(uri: URI): { address:
if (uri.scheme !== 'http' && uri.scheme !== 'https') {
return undefined;
}
const localhostMatch = /^(localhost|127\.0\.0\.1):(\d+)$/.exec(uri.authority);
const localhostMatch = /^(localhost|127\.0\.0\.1|0\.0\.0\.0):(\d+)$/.exec(uri.authority);
if (!localhostMatch) {
return undefined;
}

View File

@@ -70,6 +70,7 @@ class TestableLogService extends AbstractLogService implements ILogService {
}
dispose(): void { }
flush(): void { }
}
suite('AIAdapter', () => {
@@ -198,4 +199,4 @@ suite('AIAdapter', () => {
}
}]));
});
});
});

View File

@@ -63,6 +63,12 @@ export function registerConfiguration(): IDisposable {
$ref: ignoredSettingsSchemaId,
additionalProperties: true,
uniqueItems: true
},
'configurationSync.enableAuth': {
'type': 'boolean',
description: localize('configurationSync.enableAuth', "Enables authentication and requires VS Code restart when changed"),
'default': false,
'scope': ConfigurationScope.APPLICATION
}
}
});

View File

@@ -44,4 +44,8 @@ export class UserDataSyncLogService extends AbstractLogService implements IUserD
this.logger.critical(message, ...args);
}
flush(): void {
this.logger.flush();
}
}

View File

@@ -131,27 +131,32 @@ export class UserDataAutoSync extends Disposable {
@IAuthTokenService private readonly authTokenService: IAuthTokenService,
) {
super();
this.updateEnablement();
this.sync(true);
this._register(Event.any<any>(authTokenService.onDidChangeStatus, userDataSyncService.onDidChangeStatus)(() => this.updateEnablement()));
this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('configurationSync.enable'))(() => this.updateEnablement()));
this.updateEnablement(false);
this._register(Event.any<any>(authTokenService.onDidChangeStatus, userDataSyncService.onDidChangeStatus)(() => this.updateEnablement(true)));
this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('configurationSync.enable'))(() => this.updateEnablement(true)));
// Sync immediately if there is a local change.
this._register(Event.debounce(this.userDataSyncService.onDidChangeLocal, () => undefined, 500)(() => this.sync(false)));
}
private updateEnablement(): void {
private updateEnablement(stopIfDisabled: boolean): void {
const enabled = this.isSyncEnabled();
if (this.enabled !== enabled) {
this.enabled = enabled;
if (this.enabled) {
this.userDataSyncLogService.info('Syncing configuration started');
this.sync(true);
} else {
if (this.enabled === enabled) {
return;
}
this.enabled = enabled;
if (this.enabled) {
this.userDataSyncLogService.info('Syncing configuration started');
this.sync(true);
return;
} else {
if (stopIfDisabled) {
this.userDataSyncService.stop();
this.userDataSyncLogService.info('Syncing configuration stopped.');
}
}
}
private async sync(loop: boolean): Promise<void> {

Some files were not shown because too many files have changed in this diff Show More