mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-10 10:12:34 -05:00
Merge from vscode 313ede61cbad8f9dc748907b3384e059ddddb79a (#7436)
* Merge from vscode 313ede61cbad8f9dc748907b3384e059ddddb79a * fix strict null checks
This commit is contained in:
2
.yarnrc
2
.yarnrc
@@ -1,3 +1,3 @@
|
||||
disturl "https://atom.io/download/electron"
|
||||
target "6.0.9"
|
||||
target "4.2.10"
|
||||
runtime "electron"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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: [],
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -171,8 +171,7 @@
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"meta.preprocessor",
|
||||
"keyword.control.directive"
|
||||
"meta.preprocessor"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
|
||||
@@ -169,8 +169,7 @@
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"meta.preprocessor",
|
||||
"keyword.control.directive"
|
||||
"meta.preprocessor"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#0000ff"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
disturl "http://nodejs.org/dist"
|
||||
target "12.4.0"
|
||||
target "10.11.0"
|
||||
runtime "node"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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@@
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
18
src/bootstrap.js
vendored
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
12
src/sql/workbench/browser/enablePreviewFeatures.ts
Normal file
12
src/sql/workbench/browser/enablePreviewFeatures.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
27
src/sql/workbench/electron-browser/enablePreviewFeatures.ts
Normal file
27
src/sql/workbench/electron-browser/enablePreviewFeatures.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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",
|
||||
|
||||
1737
src/typings/electron.d.ts
vendored
1737
src/typings/electron.d.ts
vendored
File diff suppressed because it is too large
Load Diff
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -398,7 +398,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
EventHelper.stop(e, true);
|
||||
this.onClick(e);
|
||||
}));
|
||||
}, 50);
|
||||
}, 100);
|
||||
|
||||
this._register(this.runOnceToEnableMouseUp);
|
||||
}
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Binary file not shown.
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
8
src/vs/base/common/insane/insane.d.ts
vendored
8
src/vs/base/common/insane/insane.d.ts
vendored
@@ -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 { }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
19
src/vs/base/test/common/markdownString.test.ts
Normal file
19
src/vs/base/test/common/markdownString.test.ts
Normal 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\\*');
|
||||
});
|
||||
});
|
||||
@@ -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') {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -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()));
|
||||
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.monaco-editor-hover p > code {
|
||||
.monaco-editor-hover code {
|
||||
font-family: var(--monaco-monospace-font);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
15
src/vs/monaco.d.ts
vendored
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
211
src/vs/platform/dialogs/electron-main/dialogs.ts
Normal file
211
src/vs/platform/dialogs/electron-main/dialogs.ts
Normal 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;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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[];
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -87,4 +87,10 @@ export class BufferLogService extends AbstractLogService implements ILogService
|
||||
this._logger.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
if (this._logger) {
|
||||
this._logger.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ class TestableLogService extends AbstractLogService implements ILogService {
|
||||
}
|
||||
|
||||
dispose(): void { }
|
||||
flush(): void { }
|
||||
}
|
||||
|
||||
suite('AIAdapter', () => {
|
||||
@@ -198,4 +199,4 @@ suite('AIAdapter', () => {
|
||||
}
|
||||
}]));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -44,4 +44,8 @@ export class UserDataSyncLogService extends AbstractLogService implements IUserD
|
||||
this.logger.critical(message, ...args);
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
this.logger.flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user