diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml
index 175e3d0eb0..01f5420843 100644
--- a/build/azure-pipelines/darwin/product-build-darwin.yml
+++ b/build/azure-pipelines/darwin/product-build-darwin.yml
@@ -107,6 +107,16 @@ steps:
displayName: Run integration tests
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
+- script: |
+ set -e
+ cd test/smoke
+ yarn compile
+ cd -
+ yarn smoketest --web --headless
+ continueOnError: true
+ displayName: Run web smoke tests
+ condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
+
- script: |
set -e
cd test/smoke
diff --git a/extensions/package.json b/extensions/package.json
index 57d5f5da31..5c73fcbd3d 100644
--- a/extensions/package.json
+++ b/extensions/package.json
@@ -3,7 +3,7 @@
"version": "0.0.1",
"description": "Dependencies shared by all extensions",
"dependencies": {
- "typescript": "3.6.0-dev.20190810"
+ "typescript": "3.6.1-rc"
},
"scripts": {
"postinstall": "node ./postinstall"
diff --git a/extensions/theme-seti/build/update-icon-theme.js b/extensions/theme-seti/build/update-icon-theme.js
index 69d945693c..4bd77f37f3 100644
--- a/extensions/theme-seti/build/update-icon-theme.js
+++ b/extensions/theme-seti/build/update-icon-theme.js
@@ -32,7 +32,8 @@ let nonBuiltInLanguages = { // { fileNames, extensions }
"haml": { extensions: ['haml'] },
"stylus": { extensions: ['styl'] },
"vala": { extensions: ['vala'] },
- "todo": { fileNames: ['todo'] }
+ "todo": { fileNames: ['todo'] },
+ "jsonc": { extensions: ['json'] }
};
let FROM_DISK = true; // set to true to take content from a repo checked out next to the vscode repo
@@ -109,7 +110,7 @@ function downloadBinary(source, dest) {
return new Promise((c, e) => {
https.get(source, function (response) {
switch (response.statusCode) {
- case 200:
+ case 200: {
let file = fs.createWriteStream(dest);
response.on('data', function (chunk) {
file.write(chunk);
@@ -121,6 +122,7 @@ function downloadBinary(source, dest) {
e(err.message);
});
break;
+ }
case 301:
case 302:
case 303:
diff --git a/extensions/theme-seti/cgmanifest.json b/extensions/theme-seti/cgmanifest.json
index c742c019ea..1c86b8bcb2 100644
--- a/extensions/theme-seti/cgmanifest.json
+++ b/extensions/theme-seti/cgmanifest.json
@@ -6,7 +6,7 @@
"git": {
"name": "seti-ui",
"repositoryUrl": "https://github.com/jesseweed/seti-ui",
- "commitHash": "904c16acced1134a81b31d71d60293288c31334b"
+ "commitHash": "85a222708824c6f19bbecbec71633d2c97077dad"
}
},
"version": "0.1.0"
diff --git a/extensions/theme-seti/icons/vs-seti-icon-theme.json b/extensions/theme-seti/icons/vs-seti-icon-theme.json
index bdbbcb89ce..b339ff6092 100644
--- a/extensions/theme-seti/icons/vs-seti-icon-theme.json
+++ b/extensions/theme-seti/icons/vs-seti-icon-theme.json
@@ -1580,6 +1580,7 @@
"version.md": "_clock",
"version": "_clock",
"mvnw": "_maven",
+ "tsconfig.json": "_tsconfig",
"swagger.json": "_json_1",
"swagger.yml": "_json_1",
"swagger.yaml": "_json_1",
@@ -1589,6 +1590,8 @@
"docker-healthcheck": "_docker_2",
"docker-compose.yml": "_docker_3",
"docker-compose.yaml": "_docker_3",
+ "docker-compose.override.yml": "_docker_3",
+ "docker-compose.override.yaml": "_docker_3",
"firebase.json": "_firebase",
"geckodriver": "_firefox",
"gruntfile.js": "_grunt",
@@ -1968,6 +1971,7 @@
"version.md": "_clock_light",
"version": "_clock_light",
"mvnw": "_maven_light",
+ "tsconfig.json": "_tsconfig_light",
"swagger.json": "_json_1_light",
"swagger.yml": "_json_1_light",
"swagger.yaml": "_json_1_light",
@@ -1977,6 +1981,8 @@
"docker-healthcheck": "_docker_2_light",
"docker-compose.yml": "_docker_3_light",
"docker-compose.yaml": "_docker_3_light",
+ "docker-compose.override.yml": "_docker_3_light",
+ "docker-compose.override.yaml": "_docker_3_light",
"firebase.json": "_firebase_light",
"geckodriver": "_firefox_light",
"gruntfile.js": "_grunt_light",
@@ -2011,5 +2017,5 @@
"Schema Compare": "scmp"
}
},
- "version": "https://github.com/jesseweed/seti-ui/commit/904c16acced1134a81b31d71d60293288c31334b"
-}
+ "version": "https://github.com/jesseweed/seti-ui/commit/85a222708824c6f19bbecbec71633d2c97077dad"
+}
\ No newline at end of file
diff --git a/extensions/yarn.lock b/extensions/yarn.lock
index 233cf189e1..26979cdf9d 100644
--- a/extensions/yarn.lock
+++ b/extensions/yarn.lock
@@ -2,7 +2,7 @@
# yarn lockfile v1
-typescript@3.6.0-dev.20190810:
- version "3.6.0-dev.20190810"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.0-dev.20190810.tgz#dda80279480131eec9b05e3b78182a1ba1efe105"
- integrity sha512-gubcQ8Sn2G5AO1KhjvLpoFrutV7o/ZJ7wCDBC1IKgNI8R2vadIxTystJxAFqkb9boQ7tyRrZ6FwM5EL5ZYfJrg==
+typescript@3.6.1-rc:
+ version "3.6.1-rc"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.1-rc.tgz#9db650b25d8ef033d9e25b3057bdd1e102bb434b"
+ integrity sha512-u6AQN9AoocZKYSz8zcc1Qh/V/mbAO+BHc73fTiKlIdjzU60A8TesrK9/7kg3GM8o2RxNyCeOFpcevEtnfUyaLg==
diff --git a/package.json b/package.json
index 4c8595e3f9..79243939aa 100644
--- a/package.json
+++ b/package.json
@@ -78,7 +78,7 @@
"vscode-sqlite3": "4.0.8",
"vscode-textmate": "^4.2.2",
"xterm": "3.15.0-beta99",
- "xterm-addon-search": "0.2.0-beta3",
+ "xterm-addon-search": "0.2.0-beta5",
"xterm-addon-web-links": "0.1.0-beta10",
"yauzl": "^2.9.2",
"yazl": "^2.4.3",
diff --git a/remote/package.json b/remote/package.json
index ae754c1ae6..9bbc0f44c5 100644
--- a/remote/package.json
+++ b/remote/package.json
@@ -22,7 +22,7 @@
"vscode-ripgrep": "^1.5.6",
"vscode-textmate": "^4.2.2",
"xterm": "3.15.0-beta99",
- "xterm-addon-search": "0.2.0-beta3",
+ "xterm-addon-search": "0.2.0-beta5",
"xterm-addon-web-links": "0.1.0-beta10",
"yauzl": "^2.9.2",
"yazl": "^2.4.3"
diff --git a/remote/yarn.lock b/remote/yarn.lock
index 5d578d3130..54e0619915 100644
--- a/remote/yarn.lock
+++ b/remote/yarn.lock
@@ -1217,10 +1217,10 @@ vscode-windows-registry@1.0.1:
dependencies:
nan "^2.12.1"
-xterm-addon-search@0.2.0-beta3:
- version "0.2.0-beta3"
- resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta3.tgz#710ce14658e269c5a4791f5a9e2f520883a2e62b"
- integrity sha512-KzVdkEtGbKJe9ER2TmrI7XjF/wUq1lir9U63vPJi0t2ymQvIECl1V63f9QtOp1vvpdhbZiXBxO+vGTj+y0tRow==
+xterm-addon-search@0.2.0-beta5:
+ version "0.2.0-beta5"
+ resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta5.tgz#258d7cb1511d9060cd4520f0f82e408000fd4f53"
+ integrity sha512-Tg+d8scch0rYOVmzBbX35Y1GXtq+eu/YlzbXznmTo/yD83j3BQlXOhgECu/Yv8EX5JwFmzbfVRWC+JWnfigwGg==
xterm-addon-web-links@0.1.0-beta10:
version "0.1.0-beta10"
diff --git a/src/buildfile.js b/src/buildfile.js
index fc52d8acb5..5e578b6da3 100644
--- a/src/buildfile.js
+++ b/src/buildfile.js
@@ -26,7 +26,7 @@ exports.serviceWorker = [{
exports.workerExtensionHost = [{
name: 'vs/workbench/services/extensions/worker/extensionHostWorker',
// include: [],
- prepend: ['vs/loader.js'],
+ prepend: ['vs/loader.js', 'vs/nls.js'],
append: ['vs/workbench/services/extensions/worker/extensionHostWorkerMain'],
dest: 'vs/workbench/services/extensions/worker/extensionHostWorkerMain.js'
}];
diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts
index d390282a78..2851c07421 100644
--- a/src/vs/base/browser/dom.ts
+++ b/src/vs/base/browser/dom.ts
@@ -15,7 +15,7 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'
import * as platform from 'vs/base/common/platform';
import { coalesce } from 'vs/base/common/arrays';
import { URI } from 'vs/base/common/uri';
-import { Schemas } from 'vs/base/common/network';
+import { Schemas, RemoteAuthorities } from 'vs/base/common/network';
export function clearNode(node: HTMLElement): void {
while (node.firstChild) {
@@ -1193,14 +1193,21 @@ export function asDomUri(uri: URI): URI {
if (!uri) {
return uri;
}
- if (!platform.isWeb) {
- //todo@joh remove this once we have sw in electron going
- return uri;
- }
if (Schemas.vscodeRemote === uri.scheme) {
- // rewrite vscode-remote-uris to uris of the window location
- // so that they can be intercepted by the service worker
- return _location.with({ path: '/vscode-remote', query: JSON.stringify(uri) });
+ if (platform.isWeb) {
+ // rewrite vscode-remote-uris to uris of the window location
+ // so that they can be intercepted by the service worker
+ return _location.with({ path: '/vscode-remote', query: JSON.stringify(uri) });
+ } else {
+ return RemoteAuthorities.rewrite(uri.authority, uri.path);
+ }
}
return uri;
}
+
+/**
+ * returns url('...')
+ */
+export function asCSSUrl(uri: URI): string {
+ return `url('${asDomUri(uri).toString(true).replace(/'/g, '%27')}')`;
+}
diff --git a/src/vs/base/browser/markdownRenderer.ts b/src/vs/base/browser/markdownRenderer.ts
index 2878142f0b..07d282c874 100644
--- a/src/vs/base/browser/markdownRenderer.ts
+++ b/src/vs/base/browser/markdownRenderer.ts
@@ -157,8 +157,9 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
};
}
- if (options.actionHandler) {
- options.actionHandler.disposeables.add(DOM.addStandardDisposableListener(element, 'click', event => {
+ const actionHandler = options.actionHandler;
+ if (actionHandler) {
+ actionHandler.disposeables.add(DOM.addStandardDisposableListener(element, 'click', event => {
let target: HTMLElement | null = event.target;
if (target.tagName !== 'A') {
target = target.parentElement;
@@ -169,7 +170,7 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
try {
const href = target.dataset['href'];
if (href) {
- options.actionHandler!.callback(href, event);
+ actionHandler.callback(href, event);
}
} catch (err) {
onUnexpectedError(err);
diff --git a/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts b/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts
index 0332245db3..f43ac7bd68 100644
--- a/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts
+++ b/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts
@@ -4,6 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./octicons/octicons';
+import 'vs/css!./octicons/octicons2';
+import 'vs/css!./octicons/octicons-main';
import 'vs/css!./octicons/octicons-animations';
import { escape } from 'vs/base/common/strings';
@@ -30,4 +32,4 @@ export class OcticonLabel {
set title(title: string) {
this._container.title = title;
}
-}
\ No newline at end of file
+}
diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons-main.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons-main.css
new file mode 100644
index 0000000000..841e5e575c
--- /dev/null
+++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons-main.css
@@ -0,0 +1,21 @@
+body[data-octicons-update="enabled"] {
+ --version: octicons2;
+}
+
+body {
+ --version: octicons;
+}
+
+.octicon, .mega-octicon {
+ font-family: var(--version) !important;
+}
+
+body[data-octicons-update="enabled"] .monaco-workbench .part.statusbar > .items-container > .statusbar-item span.octicon {
+ font-size: 16px;
+}
+
+body[data-octicons-update="enabled"] .monaco-workbench .part.statusbar > .items-container > .statusbar-item > a {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css
index d9cc1b7a4f..29ed93db1b 100644
--- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css
+++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css
@@ -1,7 +1,7 @@
@font-face {
font-family: "octicons";
- src: url("./octicons.ttf?1b0f2a9535896866c74dd24eedeb4374") format("truetype"),
-url("./octicons.svg?1b0f2a9535896866c74dd24eedeb4374#octicons") format("svg");
+ src: url("./octicons.ttf?dda6b6d46f87b1fa91a76fc0389eeb1d") format("truetype"),
+url("./octicons.svg?dda6b6d46f87b1fa91a76fc0389eeb1d#octicons") format("svg");
}
.octicon, .mega-octicon {
@@ -169,7 +169,7 @@ url("./octicons.svg?1b0f2a9535896866c74dd24eedeb4374#octicons") format("svg");
.octicon-person-outline:before { content: "\f018" }
.octicon-pin:before { content: "\f041" }
.octicon-plug:before { content: "\f0d4" }
-.octicon-plus-small:before { content: "\f28a" }
+.octicon-plus-small:before { content: "\f05d" }
.octicon-plus:before { content: "\f05d" }
.octicon-primitive-dot:before { content: "\f052" }
.octicon-primitive-square:before { content: "\f053" }
@@ -233,16 +233,19 @@ url("./octicons.svg?1b0f2a9535896866c74dd24eedeb4374#octicons") format("svg");
.octicon-watch:before { content: "\f0e0" }
.octicon-x:before { content: "\f081" }
.octicon-zap:before { content: "\26a1" }
+.octicon-error:before { content: "\26a2" }
+.octicon-eye-closed:before { content: "\26a3" }
+.octicon-fold-down:before { content: "\26a4" }
+.octicon-fold-up:before { content: "\26a5" }
+.octicon-github-action:before { content: "\26a6" }
+.octicon-info-outline:before { content: "\26a7" }
+.octicon-play:before { content: "\26a8" }
+.octicon-remote:before { content: "\26a9" }
+.octicon-request-changes:before { content: "\26aa" }
+.octicon-smiley-outline:before { content: "\f27d" }
+.octicon-warning:before { content: "\f02d" }
+.octicon-controls:before { content: "\26ad" }
+.octicon-event:before { content: "\26ae" }
+.octicon-record-keys:before { content: "\26af" }
.octicon-archive:before { content: "\f101" }
.octicon-arrow-both:before { content: "\f102" }
-.octicon-error:before { content: "\f103" }
-.octicon-eye-closed:before { content: "\f104" }
-.octicon-fold-down:before { content: "\f105" }
-.octicon-fold-up:before { content: "\f106" }
-.octicon-github-action:before { content: "\f107" }
-.octicon-info-outline:before { content: "\f108" }
-.octicon-play:before { content: "\f109" }
-.octicon-remote:before { content: "\f10a" }
-.octicon-request-changes:before { content: "\f10b" }
-.octicon-smiley-outline:before { content: "\f10c" }
-.octicon-warning:before { content: "\f10d" }
diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg
index 3f4ab4f180..48f7d1b222 100644
--- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg
+++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg
@@ -167,10 +167,10 @@
unicode=""
horiz-adv-x="750" d=" M687.5 507.5H62.5C28.125 507.5 0 479.375 0 445V195C0 160.625 28.125 132.5 62.5 132.5H687.5C721.875 132.5 750 160.625 750 195V445C750 479.375 721.875 507.5 687.5 507.5zM250 257.5H125V382.5H250V257.5zM437.5 257.5H312.5V382.5H437.5V257.5zM625 257.5H500V382.5H625V257.5z" />
+
+
diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf
new file mode 100644
index 0000000000..654cfe9129
Binary files /dev/null and b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf differ
diff --git a/src/vs/base/common/errors.ts b/src/vs/base/common/errors.ts
index 99dfffcec4..4a04854bf8 100644
--- a/src/vs/base/common/errors.ts
+++ b/src/vs/base/common/errors.ts
@@ -194,3 +194,13 @@ export function getErrorMessage(err: any): string {
return String(err);
}
+
+
+export class NotImplementedError extends Error {
+ constructor(message?: string) {
+ super('NotImplemented');
+ if (message) {
+ this.message = message;
+ }
+ }
+}
diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts
index 3a599d62a5..cb865f2771 100644
--- a/src/vs/base/common/network.ts
+++ b/src/vs/base/common/network.ts
@@ -3,6 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
+import { URI } from 'vs/base/common/uri';
+
export namespace Schemas {
/**
@@ -62,13 +64,26 @@ class RemoteAuthoritiesImpl {
}
public set(authority: string, host: string, port: number): void {
- this._hosts[authority] = host;
+ this._hosts[authority] = (host === 'localhost' ? '127.0.0.1' : host);
this._ports[authority] = port;
}
public setConnectionToken(authority: string, connectionToken: string): void {
this._connectionTokens[authority] = connectionToken;
}
+
+ public rewrite(authority: string, path: string): URI {
+ const host = this._hosts[authority];
+ const port = this._ports[authority];
+ const connectionToken = this._connectionTokens[authority];
+ const scheme = (host === '127.0.0.1' ? Schemas.http : Schemas.vscodeRemote);
+ return URI.from({
+ scheme: scheme,
+ authority: `${host}:${port}`,
+ path: `/vscode-remote2`,
+ query: `path=${encodeURIComponent(path)}&tkn=${encodeURIComponent(connectionToken)}`
+ });
+ }
}
export const RemoteAuthorities = new RemoteAuthoritiesImpl();
diff --git a/src/vs/code/electron-browser/workbench/workbench.html b/src/vs/code/electron-browser/workbench/workbench.html
index a8e69a3aab..004dd3db57 100644
--- a/src/vs/code/electron-browser/workbench/workbench.html
+++ b/src/vs/code/electron-browser/workbench/workbench.html
@@ -4,7 +4,7 @@
-
+
diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts
index 1fef401f99..b64ef63fc6 100644
--- a/src/vs/code/electron-main/app.ts
+++ b/src/vs/code/electron-main/app.ts
@@ -39,7 +39,6 @@ import { ProxyAuthHandler } from 'vs/code/electron-main/auth';
import { Disposable } from 'vs/base/common/lifecycle';
import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows';
import { IHistoryMainService } from 'vs/platform/history/common/history';
-import { withUndefinedAsNull } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { WorkspacesChannel } from 'vs/platform/workspaces/node/workspacesIpc';
import { IWorkspacesMainService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
@@ -54,7 +53,6 @@ import { LogLevelSetterChannel } from 'vs/platform/log/common/logIpc';
import { setUnexpectedErrorHandler, onUnexpectedError } from 'vs/base/common/errors';
import { ElectronURLListener } from 'vs/platform/url/electron-main/electronUrlListener';
import { serve as serveDriver } from 'vs/platform/driver/electron-main/driver';
-import { connectRemoteAgentManagement, ManagementPersistentConnection, IConnectionOptions } from 'vs/platform/remote/common/remoteAgentConnection';
import { IMenubarService } from 'vs/platform/menubar/common/menubar';
import { MenubarService } from 'vs/platform/menubar/electron-main/menubarService';
import { MenubarChannel } from 'vs/platform/menubar/node/menubarIpc';
@@ -65,8 +63,6 @@ import { homedir } from 'os';
import { join, sep } from 'vs/base/common/path';
import { localize } from 'vs/nls';
import { Schemas } from 'vs/base/common/network';
-import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from 'vs/platform/remote/common/remoteAgentFileSystemChannel';
-import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { SnapUpdateService } from 'vs/platform/update/electron-main/updateService.snap';
import { IStorageMainService, StorageMainService } from 'vs/platform/storage/node/storageMainService';
import { GlobalStorageDatabaseChannel } from 'vs/platform/storage/node/storageIpc';
@@ -76,11 +72,7 @@ import { IBackupMainService } from 'vs/platform/backup/common/backup';
import { HistoryMainService } from 'vs/platform/history/electron-main/historyMainService';
import { URLService } from 'vs/platform/url/common/urlService';
import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService';
-import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment';
-import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory';
-import { VSBuffer } from 'vs/base/common/buffer';
import { statSync } from 'fs';
-import { ISignService } from 'vs/platform/sign/common/sign';
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc';
import { IDiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService';
import { FileService } from 'vs/platform/files/common/fileService';
@@ -103,8 +95,7 @@ export class CodeApplication extends Disposable {
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@ILifecycleService private readonly lifecycleService: ILifecycleService,
@IConfigurationService private readonly configurationService: IConfigurationService,
- @IStateService private readonly stateService: IStateService,
- @ISignService private readonly signService: ISignService
+ @IStateService private readonly stateService: IStateService
) {
super();
@@ -167,11 +158,13 @@ export class CodeApplication extends Disposable {
event.preventDefault();
});
app.on('remote-get-current-web-contents', event => {
- // The driver needs access to web contents
- if (!this.environmentService.args.driver) {
- this.logService.trace(`App#on(remote-get-current-web-contents): prevented`);
- event.preventDefault();
+ if (this.environmentService.args.driver) {
+ return; // the driver needs access to web contents
}
+
+ this.logService.trace(`App#on(remote-get-current-web-contents): prevented`);
+
+ event.preventDefault();
});
app.on('web-contents-created', (_event: Electron.Event, contents) => {
contents.on('will-attach-webview', (event: Electron.Event, webPreferences, params) => {
@@ -695,112 +688,11 @@ export class CodeApplication extends Disposable {
}
private handleRemoteAuthorities(): void {
- const connectionPool: Map = new Map();
-
- class ActiveConnection {
- private readonly _authority: string;
- private readonly _connection: Promise;
- private readonly _disposeRunner: RunOnceScheduler;
-
- constructor(authority: string, host: string, port: number, signService: ISignService) {
- this._authority = authority;
-
- const options: IConnectionOptions = {
- commit: product.commit,
- socketFactory: nodeSocketFactory,
- addressProvider: {
- getAddress: () => {
- return Promise.resolve({ host, port });
- }
- },
- signService
- };
-
- this._connection = connectRemoteAgentManagement(options, authority, `main`);
- this._disposeRunner = new RunOnceScheduler(() => this.dispose(), 5000);
- }
-
- dispose(): void {
- this._disposeRunner.dispose();
- connectionPool.delete(this._authority);
- this._connection.then(connection => connection.dispose());
- }
-
- async getClient(): Promise> {
- this._disposeRunner.schedule();
- const connection = await this._connection;
-
- return connection.client;
- }
- }
-
- const resolvedAuthorities = new Map();
- ipc.on('vscode:remoteAuthorityResolved', (event: Electron.Event, data: ResolvedAuthority) => {
- this.logService.info('Received resolved authority', data.authority);
-
- resolvedAuthorities.set(data.authority, data);
-
- // Make sure to close and remove any existing connections
- if (connectionPool.has(data.authority)) {
- connectionPool.get(data.authority)!.dispose();
- }
- });
-
- const resolveAuthority = (authority: string): ResolvedAuthority | null => {
- this.logService.info('Resolving authority', authority);
-
- if (authority.indexOf('+') >= 0) {
- if (resolvedAuthorities.has(authority)) {
- return withUndefinedAsNull(resolvedAuthorities.get(authority));
- }
-
- this.logService.info('Didnot find resolved authority for', authority);
-
- return null;
- } else {
- const [host, strPort] = authority.split(':');
- const port = parseInt(strPort, 10);
-
- return { authority, host, port };
- }
- };
-
- protocol.registerBufferProtocol(Schemas.vscodeRemote, async (request, callback) => {
- if (request.method !== 'GET') {
- return callback(undefined);
- }
-
- const uri = URI.parse(request.url);
-
- let activeConnection: ActiveConnection | undefined;
- if (connectionPool.has(uri.authority)) {
- activeConnection = connectionPool.get(uri.authority);
- } else {
- const resolvedAuthority = resolveAuthority(uri.authority);
- if (!resolvedAuthority) {
- callback(undefined);
- return;
- }
-
- activeConnection = new ActiveConnection(uri.authority, resolvedAuthority.host, resolvedAuthority.port, this.signService);
- connectionPool.set(uri.authority, activeConnection);
- }
-
- try {
- const rawClient = await activeConnection!.getClient();
- if (connectionPool.has(uri.authority)) { // not disposed in the meantime
- const channel = rawClient.getChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME);
-
- // TODO@alex don't use call directly, wrap it around a `RemoteExtensionsFileSystemProvider`
- const fileContents = await channel.call('readFile', [uri]);
- callback(fileContents.buffer);
- } else {
- callback(undefined);
- }
- } catch (err) {
- onUnexpectedError(err);
- callback(undefined);
- }
+ protocol.registerHttpProtocol(Schemas.vscodeRemote, (request, callback) => {
+ callback({
+ url: request.url.replace(/^vscode-remote:/, 'http:'),
+ method: request.method
+ });
});
}
}
diff --git a/src/vs/editor/browser/services/codeEditorServiceImpl.ts b/src/vs/editor/browser/services/codeEditorServiceImpl.ts
index 8f11c89704..1840d47596 100644
--- a/src/vs/editor/browser/services/codeEditorServiceImpl.ts
+++ b/src/vs/editor/browser/services/codeEditorServiceImpl.ts
@@ -229,11 +229,11 @@ const _CSS_MAP: { [prop: string]: string; } = {
cursor: 'cursor:{0};',
letterSpacing: 'letter-spacing:{0};',
- gutterIconPath: 'background:url(\'{0}\') center center no-repeat;',
+ gutterIconPath: 'background:{0} center center no-repeat;',
gutterIconSize: 'background-size:{0};',
contentText: 'content:\'{0}\';',
- contentIconPath: 'content:url(\'{0}\');',
+ contentIconPath: 'content:{0};',
margin: 'margin:{0};',
width: 'width:{0};',
height: 'height:{0};'
@@ -399,7 +399,7 @@ class DecorationCSSRules {
if (typeof opts !== 'undefined') {
this.collectBorderSettingsCSSText(opts, cssTextArr);
if (typeof opts.contentIconPath !== 'undefined') {
- cssTextArr.push(strings.format(_CSS_MAP.contentIconPath, dom.asDomUri(URI.revive(opts.contentIconPath)).toString(true).replace(/'/g, '%27')));
+ cssTextArr.push(strings.format(_CSS_MAP.contentIconPath, dom.asCSSUrl(URI.revive(opts.contentIconPath))));
}
if (typeof opts.contentText === 'string') {
const truncated = opts.contentText.match(/^.*$/m)![0]; // only take first line
@@ -426,7 +426,7 @@ class DecorationCSSRules {
const cssTextArr: string[] = [];
if (typeof opts.gutterIconPath !== 'undefined') {
- cssTextArr.push(strings.format(_CSS_MAP.gutterIconPath, dom.asDomUri(URI.revive(opts.gutterIconPath)).toString(true).replace(/'/g, '%27')));
+ cssTextArr.push(strings.format(_CSS_MAP.gutterIconPath, dom.asCSSUrl(URI.revive(opts.gutterIconPath))));
if (typeof opts.gutterIconSize !== 'undefined') {
cssTextArr.push(strings.format(_CSS_MAP.gutterIconSize, opts.gutterIconSize));
}
diff --git a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts
index c63c66611d..30cf954e2e 100644
--- a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts
+++ b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts
@@ -192,9 +192,6 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider {
}
public dispose(): void {
-
- this._disposables.dispose();
-
if (this._overlayWidget) {
this.editor.removeOverlayWidget(this._overlayWidget);
this._overlayWidget = null;
@@ -211,6 +208,8 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider {
this.editor.deltaDecorations(this._positionMarkerId, []);
this._positionMarkerId = [];
+
+ this._disposables.dispose();
}
public create(): void {
diff --git a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts
index c71ce227c4..a3753d92d5 100644
--- a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts
+++ b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts
@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import { addClasses, createCSSRule, removeClasses, asDomUri } from 'vs/base/browser/dom';
+import { addClasses, createCSSRule, removeClasses, asCSSUrl } from 'vs/base/browser/dom';
import { domEvent } from 'vs/base/browser/event';
import { ActionViewItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction } from 'vs/base/common/actions';
@@ -245,8 +245,8 @@ export class MenuEntryActionViewItem extends ActionViewItem {
iconClass = MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!;
} else {
iconClass = ids.nextId();
- createCSSRule(`.icon.${iconClass}`, `background-image: url("${asDomUri(item.iconLocation.light || item.iconLocation.dark).toString()}")`);
- createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: url("${asDomUri(item.iconLocation.dark).toString()}")`);
+ createCSSRule(`.icon.${iconClass}`, `background-image: ${asCSSUrl(item.iconLocation.light || item.iconLocation.dark)}`);
+ createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: ${asCSSUrl(item.iconLocation.dark)}`);
MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass);
}
diff --git a/src/vs/platform/notification/common/notification.ts b/src/vs/platform/notification/common/notification.ts
index 37624915fe..4a487dfaa0 100644
--- a/src/vs/platform/notification/common/notification.ts
+++ b/src/vs/platform/notification/common/notification.ts
@@ -37,6 +37,19 @@ export interface INotificationProperties {
neverShowAgain?: INeverShowAgainOptions;
}
+export enum NeverShowAgainScope {
+
+ /**
+ * Will never show this notification on the current workspace again.
+ */
+ WORKSPACE,
+
+ /**
+ * Will never show this notification on any workspace again.
+ */
+ GLOBAL
+}
+
export interface INeverShowAgainOptions {
/**
@@ -49,6 +62,12 @@ export interface INeverShowAgainOptions {
* make it a secondary action instead.
*/
isSecondary?: boolean;
+
+ /**
+ * Wether to persist the choice in the current workspace or for all workspaces. By
+ * default it will be persisted for all workspaces.
+ */
+ scope?: NeverShowAgainScope;
}
export interface INotification extends INotificationProperties {
diff --git a/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts
index b92262cef5..71c5538c75 100644
--- a/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts
+++ b/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts
@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { ResolvedAuthority, IRemoteAuthorityResolverService, ResolverResult, ResolvedOptions } from 'vs/platform/remote/common/remoteAuthorityResolver';
-import { ipcRenderer as ipc } from 'electron';
import * as errors from 'vs/base/common/errors';
import { RemoteAuthorities } from 'vs/base/common/network';
@@ -50,7 +49,6 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS
setResolvedAuthority(resolvedAuthority: ResolvedAuthority, options?: ResolvedOptions) {
if (this._resolveAuthorityRequests[resolvedAuthority.authority]) {
let request = this._resolveAuthorityRequests[resolvedAuthority.authority];
- ipc.send('vscode:remoteAuthorityResolved', resolvedAuthority);
RemoteAuthorities.set(resolvedAuthority.authority, resolvedAuthority.host, resolvedAuthority.port);
request.resolve({ authority: resolvedAuthority, options });
}
diff --git a/src/vs/platform/storage/browser/storageService.ts b/src/vs/platform/storage/browser/storageService.ts
index 560e93dca5..1d0241e76c 100644
--- a/src/vs/platform/storage/browser/storageService.ts
+++ b/src/vs/platform/storage/browser/storageService.ts
@@ -5,15 +5,17 @@
import { Disposable } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
-import { IWorkspaceStorageChangeEvent, IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason, logStorage, FileStorageDatabase } from 'vs/platform/storage/common/storage';
+import { IWorkspaceStorageChangeEvent, IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason, logStorage } from 'vs/platform/storage/common/storage';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
-import { IFileService } from 'vs/platform/files/common/files';
-import { IStorage, Storage } from 'vs/base/parts/storage/common/storage';
+import { IFileService, FileChangeType } from 'vs/platform/files/common/files';
+import { IStorage, Storage, IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage';
import { URI } from 'vs/base/common/uri';
import { joinPath } from 'vs/base/common/resources';
-import { runWhenIdle } from 'vs/base/common/async';
+import { runWhenIdle, RunOnceScheduler } from 'vs/base/common/async';
+import { serializableToMap, mapToSerializable } from 'vs/base/common/map';
+import { VSBuffer } from 'vs/base/common/buffer';
export class BrowserStorageService extends Disposable implements IStorageService {
@@ -35,6 +37,7 @@ export class BrowserStorageService extends Disposable implements IStorageService
private workspaceStorageFile: URI;
private initializePromise: Promise;
+ private periodicSaveScheduler = this._register(new RunOnceScheduler(() => this.saveState(), 5000));
get hasPendingUpdate(): boolean {
return this.globalStorageDatabase.hasPendingUpdate || this.workspaceStorageDatabase.hasPendingUpdate;
@@ -51,20 +54,23 @@ export class BrowserStorageService extends Disposable implements IStorageService
// long running operation.
// Instead, periodically ask customers to save save. The library will be clever enough
// to only save state that has actually changed.
- this.saveStatePeriodically();
+ this.periodicSaveScheduler.schedule();
}
- private saveStatePeriodically(): void {
- setTimeout(() => {
- runWhenIdle(() => {
+ private saveState(): void {
+ runWhenIdle(() => {
- // this event will potentially cause new state to be stored
+ // this event will potentially cause new state to be stored
+ // since new state will only be created while the document
+ // has focus, one optimization is to not run this when the
+ // document has no focus, assuming that state has not changed
+ if (document.hasFocus()) {
this._onWillSaveState.fire({ reason: WillSaveStateReason.NONE });
+ }
- // repeat
- this.saveStatePeriodically();
- });
- }, 5000);
+ // repeat
+ this.periodicSaveScheduler.schedule();
+ });
}
initialize(payload: IWorkspaceInitializationPayload): Promise {
@@ -83,14 +89,14 @@ export class BrowserStorageService extends Disposable implements IStorageService
// Workspace Storage
this.workspaceStorageFile = joinPath(stateRoot, `${payload.id}.json`);
- this.workspaceStorageDatabase = this._register(new FileStorageDatabase(this.workspaceStorageFile, this.fileService));
- this.workspaceStorage = new Storage(this.workspaceStorageDatabase);
+ this.workspaceStorageDatabase = this._register(new FileStorageDatabase(this.workspaceStorageFile, false /* do not watch for external changes */, this.fileService));
+ this.workspaceStorage = this._register(new Storage(this.workspaceStorageDatabase));
this._register(this.workspaceStorage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key, scope: StorageScope.WORKSPACE })));
// Global Storage
this.globalStorageFile = joinPath(stateRoot, 'global.json');
- this.globalStorageDatabase = this._register(new FileStorageDatabase(this.globalStorageFile, this.fileService));
- this.globalStorage = new Storage(this.globalStorageDatabase);
+ this.globalStorageDatabase = this._register(new FileStorageDatabase(this.globalStorageFile, true /* watch for external changes */, this.fileService));
+ this.globalStorage = this._register(new Storage(this.globalStorageDatabase));
this._register(this.globalStorage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key, scope: StorageScope.GLOBAL })));
// Init both
@@ -140,14 +146,125 @@ export class BrowserStorageService extends Disposable implements IStorageService
}
close(): void {
-
- // Signal as event so that clients can still store data
- this._onWillSaveState.fire({ reason: WillSaveStateReason.SHUTDOWN });
-
// We explicitly do not close our DBs because writing data onBeforeUnload()
// can result in unexpected results. Namely, it seems that - even though this
// operation is async - sometimes it is being triggered on unload and
// succeeds. Often though, the DBs turn out to be empty because the write
// never had a chance to complete.
+ //
+ // Instead we trigger dispose() to ensure that no timeouts or callbacks
+ // get triggered in this phase.
+ this.dispose();
+ }
+}
+
+export class FileStorageDatabase extends Disposable implements IStorageDatabase {
+
+ private readonly _onDidChangeItemsExternal: Emitter = this._register(new Emitter());
+ readonly onDidChangeItemsExternal: Event = this._onDidChangeItemsExternal.event;
+
+ private cache: Map | undefined;
+
+ private pendingUpdate: Promise = Promise.resolve();
+
+ private _hasPendingUpdate = false;
+ get hasPendingUpdate(): boolean {
+ return this._hasPendingUpdate;
+ }
+
+ private isWatching = false;
+
+ constructor(
+ private readonly file: URI,
+ private readonly watchForExternalChanges: boolean,
+ @IFileService private readonly fileService: IFileService
+ ) {
+ super();
+ }
+
+ private async ensureWatching(): Promise {
+ if (this.isWatching || !this.watchForExternalChanges) {
+ return;
+ }
+
+ const exists = await this.fileService.exists(this.file);
+ if (this.isWatching || !exists) {
+ return; // file must exist to be watched
+ }
+
+ this.isWatching = true;
+
+ this._register(this.fileService.watch(this.file));
+ this._register(this.fileService.onFileChanges(e => {
+ if (document.hasFocus()) {
+ return; // ignore changes from ourselves by checking for focus
+ }
+
+ if (!e.contains(this.file, FileChangeType.UPDATED)) {
+ return; // not our file
+ }
+
+ this.onDidStorageChangeExternal();
+ }));
+ }
+
+ private async onDidStorageChangeExternal(): Promise {
+ const items = await this.doGetItemsFromFile();
+
+ this.cache = items;
+
+ this._onDidChangeItemsExternal.fire({ items });
+ }
+
+ async getItems(): Promise