提交 d1677286 编写于 作者: M Matt Bierner

Merge branch 'master' of https://github.com/Microsoft/vscode

......@@ -85,7 +85,6 @@ export class SelectBox extends Widget {
if (this.selected >= 0) {
this.select.selectedIndex = this.selected;
this.select.title = this.options[this.selected];
this._onDidSelect.fire(this.options[this.selected]);
}
}
......
......@@ -24,7 +24,7 @@ export class ArrayIterator<T> implements IIterator<T> {
}
public first(): T {
this.index = this.start - 1;
this.index = this.start;
return this.current();
}
......
......@@ -383,7 +383,7 @@ export class VSCodeMenu {
const closeWindow = new MenuItem(this.likeAction('workbench.action.closeWindow', { label: mnemonicLabel(nls.localize({ key: 'miCloseWindow', comment: ['&& denotes a mnemonic'] }, "Close &&Window")), click: () => this.windowsService.getLastActiveWindow().win.close(), enabled: this.windowsService.getWindowCount() > 0 }));
const closeFolder = this.createMenuItem(nls.localize({ key: 'miCloseFolder', comment: ['&& denotes a mnemonic'] }, "Close &&Folder"), 'workbench.action.closeFolder');
const closeEditor = this.createMenuItem(nls.localize({ key: 'miCloseEditor', comment: ['&& denotes a mnemonic'] }, "Close &&Editor"), 'workbench.action.closeActiveEditor');
const closeEditor = this.createMenuItem(nls.localize({ key: 'miCloseEditor', comment: ['&& denotes a mnemonic'] }, "&&Close Editor"), 'workbench.action.closeActiveEditor');
const exit = new MenuItem(this.likeAction('workbench.action.quit', { label: mnemonicLabel(nls.localize({ key: 'miExit', comment: ['&& denotes a mnemonic'] }, "E&&xit")), click: () => this.windowsService.quit() }));
......
......@@ -323,11 +323,11 @@ export class WindowsManager implements IWindowsMainService {
}
let foldersToOpen = arrays.distinct(iPathsToOpen.filter(iPath => iPath.workspacePath && !iPath.filePath).map(iPath => iPath.workspacePath), folder => platform.isLinux ? folder : folder.toLowerCase()); // prevent duplicates
let foldersToRestore = (openConfig.initialStartup && !openConfig.cli.extensionDevelopmentPath) ? this.backupService.workspaceBackupPaths : [];
let foldersToRestore = (openConfig.initialStartup && !openConfig.cli.extensionDevelopmentPath) ? this.backupService.getWorkspaceBackupPaths() : [];
let filesToOpen: IPath[] = [];
let filesToDiff: IPath[] = [];
let emptyToOpen = iPathsToOpen.filter(iPath => !iPath.workspacePath && !iPath.filePath);
let emptyToRestore = (openConfig.initialStartup && !openConfig.cli.extensionDevelopmentPath) ? this.backupService.emptyWorkspaceBackupPaths : [];
let emptyToRestore = (openConfig.initialStartup && !openConfig.cli.extensionDevelopmentPath) ? this.backupService.getEmptyWorkspaceBackupPaths() : [];
let filesToCreate = iPathsToOpen.filter(iPath => !!iPath.filePath && iPath.createFilePath);
// Diff mode needs special care
......
......@@ -17,8 +17,8 @@ export const IBackupService = createDecorator<IBackupService>('backupService');
export interface IBackupMainService extends IBackupService {
_serviceBrand: any;
workspaceBackupPaths: string[];
emptyWorkspaceBackupPaths: string[];
getWorkspaceBackupPaths(): string[];
getEmptyWorkspaceBackupPaths(): string[];
registerWindowForBackupsSync(windowId: number, isEmptyWorkspace: boolean, backupFolder?: string, workspacePath?: string): void;
}
......
......@@ -34,12 +34,12 @@ export class BackupMainService implements IBackupMainService {
this.loadSync();
}
public get workspaceBackupPaths(): string[] {
return this.backups.folderWorkspaces;
public getWorkspaceBackupPaths(): string[] {
return this.backups.folderWorkspaces.slice(0); // return a copy
}
public get emptyWorkspaceBackupPaths(): string[] {
return this.backups.emptyWorkspaces;
public getEmptyWorkspaceBackupPaths(): string[] {
return this.backups.emptyWorkspaces.slice(0); // return a copy
}
public getBackupPath(windowId: number): TPromise<string> {
......
......@@ -80,7 +80,7 @@ suite('BackupMainService', () => {
service.registerWindowForBackupsSync(1, false, null, fooFile.fsPath);
service.registerWindowForBackupsSync(2, false, null, barFile.fsPath);
service.loadSync();
assert.deepEqual(service.workspaceBackupPaths, []);
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
// 2) backup workspace path exists with empty contents within
fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
......@@ -88,7 +88,7 @@ suite('BackupMainService', () => {
service.registerWindowForBackupsSync(1, false, null, fooFile.fsPath);
service.registerWindowForBackupsSync(2, false, null, barFile.fsPath);
service.loadSync();
assert.deepEqual(service.workspaceBackupPaths, []);
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
assert.ok(!fs.exists(service.toBackupPath(fooFile.fsPath)));
assert.ok(!fs.exists(service.toBackupPath(barFile.fsPath)));
......@@ -100,7 +100,7 @@ suite('BackupMainService', () => {
service.registerWindowForBackupsSync(1, false, null, fooFile.fsPath);
service.registerWindowForBackupsSync(2, false, null, barFile.fsPath);
service.loadSync();
assert.deepEqual(service.workspaceBackupPaths, []);
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
assert.ok(!fs.exists(service.toBackupPath(fooFile.fsPath)));
assert.ok(!fs.exists(service.toBackupPath(barFile.fsPath)));
......@@ -111,101 +111,101 @@ suite('BackupMainService', () => {
fs.mkdirSync(service.toBackupPath(barFile.fsPath));
fs.mkdirSync(fileBackups);
service.registerWindowForBackupsSync(1, false, null, fooFile.fsPath);
assert.equal(service.workspaceBackupPaths.length, 1);
assert.equal(service.emptyWorkspaceBackupPaths.length, 0);
assert.equal(service.getWorkspaceBackupPaths().length, 1);
assert.equal(service.getEmptyWorkspaceBackupPaths().length, 0);
fs.writeFileSync(path.join(fileBackups, 'backup.txt'), '');
service.loadSync();
assert.equal(service.workspaceBackupPaths.length, 0);
assert.equal(service.emptyWorkspaceBackupPaths.length, 1);
assert.equal(service.getWorkspaceBackupPaths().length, 0);
assert.equal(service.getEmptyWorkspaceBackupPaths().length, 1);
done();
});
suite('loadSync', () => {
test('workspaceBackupPaths should return [] when workspaces.json doesn\'t exist', () => {
assert.deepEqual(service.workspaceBackupPaths, []);
test('getWorkspaceBackupPaths() should return [] when workspaces.json doesn\'t exist', () => {
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
});
test('workspaceBackupPaths should return [] when workspaces.json is not properly formed JSON', () => {
test('getWorkspaceBackupPaths() should return [] when workspaces.json is not properly formed JSON', () => {
fs.writeFileSync(backupWorkspacesPath, '');
service.loadSync();
assert.deepEqual(service.workspaceBackupPaths, []);
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{]');
service.loadSync();
assert.deepEqual(service.workspaceBackupPaths, []);
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, 'foo');
service.loadSync();
assert.deepEqual(service.workspaceBackupPaths, []);
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
});
test('workspaceBackupPaths should return [] when folderWorkspaces in workspaces.json is absent', () => {
test('getWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is absent', () => {
fs.writeFileSync(backupWorkspacesPath, '{}');
service.loadSync();
assert.deepEqual(service.workspaceBackupPaths, []);
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
});
test('workspaceBackupPaths should return [] when folderWorkspaces in workspaces.json is not a string array', () => {
test('getWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is not a string array', () => {
fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":{}}');
service.loadSync();
assert.deepEqual(service.workspaceBackupPaths, []);
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":{"foo": ["bar"]}}');
service.loadSync();
assert.deepEqual(service.workspaceBackupPaths, []);
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":{"foo": []}}');
service.loadSync();
assert.deepEqual(service.workspaceBackupPaths, []);
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":{"foo": "bar"}}');
service.loadSync();
assert.deepEqual(service.workspaceBackupPaths, []);
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":"foo"}');
service.loadSync();
assert.deepEqual(service.workspaceBackupPaths, []);
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":1}');
service.loadSync();
assert.deepEqual(service.workspaceBackupPaths, []);
assert.deepEqual(service.getWorkspaceBackupPaths(), []);
});
test('emptyWorkspaceBackupPaths should return [] when workspaces.json doesn\'t exist', () => {
assert.deepEqual(service.emptyWorkspaceBackupPaths, []);
test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json doesn\'t exist', () => {
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
});
test('emptyWorkspaceBackupPaths should return [] when workspaces.json is not properly formed JSON', () => {
test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json is not properly formed JSON', () => {
fs.writeFileSync(backupWorkspacesPath, '');
service.loadSync();
assert.deepEqual(service.emptyWorkspaceBackupPaths, []);
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{]');
service.loadSync();
assert.deepEqual(service.emptyWorkspaceBackupPaths, []);
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, 'foo');
service.loadSync();
assert.deepEqual(service.emptyWorkspaceBackupPaths, []);
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
});
test('emptyWorkspaceBackupPaths should return [] when folderWorkspaces in workspaces.json is absent', () => {
test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is absent', () => {
fs.writeFileSync(backupWorkspacesPath, '{}');
service.loadSync();
assert.deepEqual(service.emptyWorkspaceBackupPaths, []);
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
});
test('emptyWorkspaceBackupPaths should return [] when folderWorkspaces in workspaces.json is not a string array', () => {
test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is not a string array', () => {
fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{}}');
service.loadSync();
assert.deepEqual(service.emptyWorkspaceBackupPaths, []);
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": ["bar"]}}');
service.loadSync();
assert.deepEqual(service.emptyWorkspaceBackupPaths, []);
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": []}}');
service.loadSync();
assert.deepEqual(service.emptyWorkspaceBackupPaths, []);
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": "bar"}}');
service.loadSync();
assert.deepEqual(service.emptyWorkspaceBackupPaths, []);
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":"foo"}');
service.loadSync();
assert.deepEqual(service.emptyWorkspaceBackupPaths, []);
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":1}');
service.loadSync();
assert.deepEqual(service.emptyWorkspaceBackupPaths, []);
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
});
});
......@@ -232,10 +232,10 @@ suite('BackupMainService', () => {
});
suite('registerWindowForBackups', () => {
test('pushWorkspaceBackupPathsSync should persist paths to workspaces.json', () => {
test('pushgetWorkspaceBackupPaths()Sync should persist paths to workspaces.json', () => {
service.registerWindowForBackupsSync(1, false, null, fooFile.fsPath);
service.registerWindowForBackupsSync(2, false, null, barFile.fsPath);
assert.deepEqual(service.workspaceBackupPaths, [fooFile.fsPath, barFile.fsPath]);
assert.deepEqual(service.getWorkspaceBackupPaths(), [fooFile.fsPath, barFile.fsPath]);
pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath, barFile.fsPath]);
......
......@@ -284,6 +284,7 @@ export class WorkbenchShell {
// Telemetry: workspace tags
const workspaceStats: WorkspaceStats = <WorkspaceStats>this.workbench.getInstantiationService().createInstance(WorkspaceStats);
workspaceStats.reportWorkspaceTags(this.options);
workspaceStats.reportCloudStats();
if ((platform.isLinux || platform.isMacintosh) && process.getuid() === 0) {
this.messageService.show(Severity.Warning, nls.localize('runningAsRoot', "It is recommended not to run Code as 'root'."));
......
......@@ -37,6 +37,7 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem {
private registerListeners(): void {
this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => {
this.updateOptions();
this.nameContainer.textContent = this.debugService.getViewModel().selectedConfigurationName;
}));
this.toDispose.push(this.selectBox.onDidSelect(configurationName => {
this.debugService.getViewModel().setSelectedConfigurationName(configurationName);
......@@ -93,6 +94,8 @@ export class StartDebugActionItem extends EventEmitter implements IActionItem {
const selected = options.indexOf(this.debugService.getViewModel().selectedConfigurationName);
this.selectBox.setOptions(options, selected);
}
this.debugService.getViewModel().setSelectedConfigurationName(this.selectBox.getSelected());
}
}
......
......@@ -32,7 +32,9 @@ export class TreeExplorerViewlet extends Viewlet {
this.viewletState = new TreeExplorerViewletState();
this.viewletId = viewletId;
this.treeNodeProviderId = this.getTreeProviderName(viewletId);
const tokens = viewletId.split('.');
this.treeNodeProviderId = tokens[tokens.length - 1];
}
public getId(): string {
......@@ -63,19 +65,34 @@ export class TreeExplorerViewlet extends Viewlet {
}
private addTreeView(): void {
// Hide header (root node) by default
const headerSize = 0;
const headerSize = 0; // Hide header (root node) by default
this.view = this.instantiationService.createInstance(TreeExplorerView, this.viewletState, this.treeNodeProviderId, this.getActionRunner(), headerSize);
this.view.render(this.viewletContainer.getHTMLElement(), Orientation.VERTICAL);
}
private getTreeProviderName(viewletId: string): string {
const tokens = viewletId.split('.');
return tokens[tokens.length - 1];
public focus(): void {
super.focus();
if (this.view) {
this.view.focusBody();
}
}
public shutdown(): void {
if (this.view) {
this.view.shutdown();
}
super.shutdown();
}
public dispose(): void {
this.view = null;
if (this.view) {
this.view = null;
this.view.dispose();
}
super.dispose();
}
}
......@@ -72,6 +72,7 @@ export class TreeExplorerView extends CollapsibleViewletView {
public getActions(): IAction[] {
const refresh = this.instantiationService.createInstance(RefreshViewExplorerAction, this);
return [refresh];
}
......
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-fg{fill:#f0eff1}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-bg" d="M11 11v-1h2V2H7v2H6V1h8v10h-3zm-1-6v10H2V5h8zM9 6H3v8h6V6z" id="iconBg"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-bg" d="M11 11v-1h2V2H7v2H6V1h8v10h-3zm-1-6v10H2V5h8zM9 6H3v8h6V6z" id="iconBg"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{fill:#F6F6F6;} .icon-vs-bg{fill:#424242;}</style><path class="icon-canvas-transparent" d="M16 16h-16v-16h16v16z" id="canvas"/><path class="icon-vs-out" d="M16 4.28l-11.673 11.72h-4.327v-4.406l11.477-11.594h.308l4.215 4.237v.043z" id="outline" style="display: none;"/><path class="icon-vs-bg" d="M14.598 4.25l-1.688 1.75-3-3 1.688-1.75 3 3zm-5.688-.25l-7 7 3 3 7-7-3-3zm-7.91 8.09v2.91h2.91l-2.91-2.91z" id="iconBg"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#2d2d30;} .icon-vs-out{fill:#2d2d30;} .icon-vs-bg{fill:#c5c5c5;}</style><path class="icon-canvas-transparent" d="M16 16h-16v-16h16v16z" id="canvas"/><path class="icon-vs-out" d="M16 4.28l-11.673 11.72h-4.327v-4.406l11.477-11.594h.308l4.215 4.237v.043z" id="outline" style="display: none;"/><path class="icon-vs-bg" d="M14.598 4.25l-1.688 1.75-3-3 1.688-1.75 3 3zm-5.688-.25l-7 7 3 3 7-7-3-3zm-7.91 8.09v2.91h2.91l-2.91-2.91z" id="iconBg"/></svg>
\ No newline at end of file
......@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
.settings-header-widget {
display: flex;
border-bottom: 1px solid #efefef;
}
......@@ -13,7 +12,23 @@
}
.settings-header-widget > .settings-header-container {
margin: 8px 0px 12px 0;
margin-top: 8px;
padding-left: 28px;
padding-right: 32px;
}
.settings-header-widget > .settings-search-container {
padding-left: 28px;
padding-right: 32px;
padding-bottom: 11px;
padding-top: 11px;
}
.vs .settings-header-widget > .settings-search-container {
background: #efeff2;
}
.vs-dark .settings-header-widget > .settings-search-container {
background: #2d2d30;
}
.settings-header-widget > .settings-header-container > .settings-title-container {
......@@ -21,30 +36,48 @@
}
.settings-header-widget > .settings-header-container > .settings-title-container > .settings-info-container {
color: rgba(170, 170, 170, 1);
font-style: italic;
white-space: pre-wrap;
margin-bottom: 8px;
font-size: 12px;
}
.settings-header-widget > .settings-header-container > .settings-title-container > .settings-info-container span {
padding-right: 6px;
.vs .settings-header-widget > .settings-header-container > .settings-title-container > .settings-info-container {
color: #6f6f6f;
}
.vs-dark .settings-header-widget > .settings-header-container > .settings-title-container > .settings-info-container {
color: #bbbbbb;
}
.hc-black .settings-header-widget > .settings-header-container > .settings-title-container > .settings-info-container {
color: white;
}
.settings-header-widget > .settings-header-container > .settings-search-container > .settings-search-input {
.settings-header-widget > .settings-header-container > .settings-title-container > .settings-info-container .title-label {
text-transform: uppercase;
font-weight: bold;
}
.settings-header-widget > .settings-search-container > .settings-search-input {
vertical-align: middle;
}
.settings-header-widget > .settings-header-container > .settings-search-container > .settings-search-input > .monaco-inputbox {
.settings-header-widget > .settings-search-container > .settings-search-input > .monaco-inputbox {
height: 30px;
}
.vs .settings-header-widget > .settings-header-container > .settings-search-container > .settings-search-input > .monaco-inputbox {
.vs .settings-header-widget > .settings-search-container > .settings-search-input > .monaco-inputbox {
border: 1px solid #ddd;
}
.settings-header-widget > .settings-header-container > .settings-search-container > .settings-search-input > .monaco-inputbox .input {
.settings-header-widget > .settings-search-container > .settings-search-input > .monaco-inputbox .input {
font-size: 14px;
padding-left:30px;
background-image: url('search.svg');
background-repeat: no-repeat;
background-position: 8px 50%;
}
.settings-header-widget > .settings-search-container > .settings-search-input > .monaco-inputbox .input {
background-image: url('search_inverse.svg');
}
.monaco-editor .settings-group-title-widget {
......@@ -54,6 +87,17 @@
.monaco-editor .settings-group-title-widget .title-container {
width: 100%;
cursor: pointer;
font-weight: bold;
}
.vs .monaco-editor .settings-group-title-widget .title-container {
color: #6f6f6f;
}
.vs-dark .monaco-editor .settings-group-title-widget .title-container {
color: #bbbbbb;
}
.hc-black .monaco-editor .settings-group-title-widget .title-container {
color: white;
}
.monaco-editor .settings-group-title-widget .title-container > * {
......@@ -101,20 +145,20 @@
background: url(collapsed-dark.svg) 50% 50% no-repeat;
}
.monaco-editor .view-line:hover :not(.inline-folded).copySetting:after {
.monaco-editor .view-line:hover .copySetting:after {
cursor: pointer;
content:" ";
background: url('copy.svg') center center no-repeat;
background: url('edit.svg') center center no-repeat;
margin-left: 1em;
display:inline-block;
position: absolute;
height:16px;
height:100%;
width:16px;
}
.monaco-editor.hc-black .view-line:hover :not(.inline-folded).copySetting:after,
.monaco-editor.vs-dark .view-line:hover :not(.inline-folded).copySetting:after {
background: url('copy_inverse.svg') center center no-repeat;
.monaco-editor.hc-black .view-line:hover .copySetting:after,
.monaco-editor.vs-dark .view-line:hover .copySetting:after {
background: url('edit_inverse.svg') center center no-repeat;
}
.monaco-editor .floating-click-widget {
......
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#f6f6f6;fill-opacity:0;}.cls-2{fill:none;}.cls-3{fill:#424242;}</style></defs><title>Search_16x</title><path id="canvas" class="cls-1" d="M16,16H0V0H16Z"/><path id="outline" class="cls-2" d="M11.11,0a5.9,5.9,0,0,1-1,11.71,5.69,5.69,0,0,1-1.91-.33L3.57,16H2.68L0,13.36V12.2L4.51,7.72A5.68,5.68,0,0,1,4.2,5.81,5.91,5.91,0,0,1,9.09,0h2"/><path id="iconBg" class="cls-3" d="M1.32,13.07l1.61,1.61L7.75,9.86a3.82,3.82,0,0,0,2.42.8,4.83,4.83,0,1,0-4.8-4.83,3.48,3.48,0,0,0,.78,2.42ZM6.44,5.83a3.7,3.7,0,0,1,3.72-3.76,3.75,3.75,0,1,1,0,7.51A3.7,3.7,0,0,1,6.44,5.83"/><path id="iconFg" class="cls-2" d="M6.44,5.83a3.7,3.7,0,0,1,3.72-3.76,3.75,3.75,0,1,1,0,7.51A3.7,3.7,0,0,1,6.44,5.83"/></svg>
\ No newline at end of file
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#2d2d30;fill-opacity:0;}.cls-2{fill:none;}.cls-3{fill:#c5c5c5;}</style></defs><title>Search_16x</title><path id="canvas" class="cls-1" d="M16,16H0V0H16Z"/><path id="outline" class="cls-2" d="M11.11,0a5.9,5.9,0,0,1-1,11.71,5.69,5.69,0,0,1-1.91-.33L3.57,16H2.68L0,13.36V12.2L4.51,7.72A5.68,5.68,0,0,1,4.2,5.81,5.91,5.91,0,0,1,9.09,0h2"/><path id="iconBg" class="cls-3" d="M1.32,13.07l1.61,1.61L7.75,9.86a3.82,3.82,0,0,0,2.42.8,4.83,4.83,0,1,0-4.8-4.83,3.48,3.48,0,0,0,.78,2.42ZM6.44,5.83a3.7,3.7,0,0,1,3.72-3.76,3.75,3.75,0,1,1,0,7.51A3.7,3.7,0,0,1,6.44,5.83"/><path id="iconFg" class="cls-2" d="M6.44,5.83a3.7,3.7,0,0,1,3.72-3.76,3.75,3.75,0,1,1,0,7.51A3.7,3.7,0,0,1,6.44,5.83"/></svg>
\ No newline at end of file
......@@ -23,6 +23,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v
import * as editorCommon from 'vs/editor/common/editorCommon';
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
import { CodeEditor } from 'vs/editor/browser/codeEditor';
import { Range } from 'vs/editor/common/core/range';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import {
IPreferencesService, ISettingsGroup, ISetting, IPreferencesEditorModel, IFilterResult, CONTEXT_DEFAULT_SETTINGS_EDITOR,
......@@ -224,6 +225,7 @@ export class DefaultPreferencesEditor extends BaseTextEditor {
}
public clearInput(): void {
this.disposeModel();
this.saveState(<DefaultPreferencesEditorInput>this.input);
if (this.inputDisposeListener) {
this.inputDisposeListener.dispose();
......@@ -273,6 +275,13 @@ export class DefaultPreferencesEditor extends BaseTextEditor {
data['filter'] = filter;
this.telemetryService.publicLog('defaultSettings.filter', data);
}
private disposeModel(): void {
const model = this.defaultPreferencesEditor.getModel();
if (model) {
this.modelService.destroyModel(model.uri);
}
}
}
class DefaultPreferencesCodeEditor extends CodeEditor {
......@@ -429,7 +438,10 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR
}
public focusNextSetting(): void {
this.focusNextSettingRenderer.focusNext();
const setting = this.focusNextSettingRenderer.focusNext();
if (setting) {
this.settingsGroupTitleRenderer.showSetting(setting);
}
}
public collapseAll() {
......@@ -528,16 +540,25 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea
public showGroup(group: number) {
this.hiddenGroups = this.settingsGroups.filter((g, i) => i !== group - 1);
for (const groupTitleWidget of this.settingsGroupTitleWidgets.filter((g, i) => i !== group - 1)) {
groupTitleWidget.collapse();
groupTitleWidget.toggleCollapse(true);
}
this._onHiddenAreasChanged.fire();
}
public showSetting(setting: ISetting): void {
const settingsGroupTitleWidget = this.settingsGroupTitleWidgets.filter(widget => Range.containsRange(widget.settingsGroup.range, setting.range))[0];
if (settingsGroupTitleWidget && settingsGroupTitleWidget.isCollapsed()) {
settingsGroupTitleWidget.toggleCollapse(false);
this.hiddenGroups.splice(this.hiddenGroups.indexOf(settingsGroupTitleWidget.settingsGroup), 1);
this._onHiddenAreasChanged.fire();
}
}
public collapseAll() {
this.editor.setPosition({ lineNumber: 1, column: 1 });
this.hiddenGroups = this.settingsGroups.slice();
for (const groupTitleWidget of this.settingsGroupTitleWidgets) {
groupTitleWidget.collapse();
groupTitleWidget.toggleCollapse(true);
}
this._onHiddenAreasChanged.fire();
}
......@@ -711,7 +732,7 @@ export class FocusNextSettingRenderer extends Disposable {
super();
}
public focusNext(): void {
public focusNext(): ISetting {
this.clear();
let setting = this.iterator.next() || this.iterator.first();
if (setting) {
......@@ -731,7 +752,9 @@ export class FocusNextSettingRenderer extends Disposable {
}]);
});
this.editor.revealLinesInCenterIfOutsideViewport(setting.valueRange.startLineNumber, setting.valueRange.endLineNumber - 1);
return setting;
}
return null;
}
public render(filteredGroups: ISettingsGroup[]) {
......@@ -855,16 +878,12 @@ export class CopySettingActionRenderer extends Disposable {
if (setting) {
let jsonSchema: IJSONSchema = this.getConfigurationsMap()[setting.key];
const actions = this.getActions(setting, jsonSchema);
if (actions) {
let elementPosition = DOM.getDomNodePagePosition(<HTMLElement>e.target.element);
const anchor = { x: elementPosition.left, y: elementPosition.top + elementPosition.height + 10 };
this.contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => TPromise.wrap(actions)
});
return;
}
this.settingsService.copyConfiguration(setting);
let elementPosition = DOM.getDomNodePagePosition(<HTMLElement>e.target.element);
const anchor = { x: elementPosition.left, y: elementPosition.top + elementPosition.height + 10 };
this.contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => TPromise.wrap(actions)
});
}
}
......@@ -907,7 +926,12 @@ export class CopySettingActionRenderer extends Disposable {
};
});
}
return null;
return [<IAction>{
id: 'copyToSettings',
label: nls.localize('copyToSettings', "Copy to settings"),
enabled: true,
run: () => this.settingsService.copyConfiguration(setting)
}];
}
public dispose() {
......
......@@ -21,6 +21,7 @@ import { IEditorGroupService } from 'vs/workbench/services/group/common/groupSer
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IFileService, IFileOperationResult, FileOperationResult } from 'vs/platform/files/common/files';
import { IMessageService, Severity, IChoiceService } from 'vs/platform/message/common/message';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
......@@ -64,20 +65,23 @@ export class PreferencesService extends Disposable implements IPreferencesServic
@IEnvironmentService private environmentService: IEnvironmentService,
@ITelemetryService private telemetryService: ITelemetryService,
@ITextModelResolverService private textModelResolverService: ITextModelResolverService,
@IConfigurationEditingService private configurationEditingService: IConfigurationEditingService
@IConfigurationEditingService private configurationEditingService: IConfigurationEditingService,
@IExtensionService private extensionService: IExtensionService
) {
super();
this.defaultEditorModels = new Map<URI, IPreferencesEditorModel>();
}
createDefaultSettingsModel(): TPromise<IPreferencesEditorModel> {
return this.createDefaultPreferencesEditorModel(PreferencesService.DEFAULT_SETTINGS_URI);
}
createDefaultPreferencesEditorModel(uri: URI): TPromise<IPreferencesEditorModel> {
const editorModel = this.defaultEditorModels.get(uri);
if (editorModel) {
return TPromise.as(editorModel);
}
if (PreferencesService.DEFAULT_SETTINGS_URI.fsPath === uri.fsPath) {
return this.fetchMostCommonlyUsedSettings()
.then(mostCommonSettings => {
return TPromise.join<any>([this.extensionService.onReady(), this.fetchMostCommonlyUsedSettings()])
.then(result => {
const mostCommonSettings = result[1];
const model = this.instantiationService.createInstance(DefaultSettingsEditorModel, uri, mostCommonSettings);
this.defaultEditorModels.set(uri, model);
return model;
......
......@@ -79,8 +79,8 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone {
});
}
public collapse() {
DOM.addClass(this.titleContainer, 'collapsed');
public toggleCollapse(collapse: boolean) {
DOM.toggleClass(this.titleContainer, 'collapsed', collapse);
}
public toggleFocus(focus: boolean): void {
......@@ -89,7 +89,7 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone {
private layout(): void {
this.titleContainer.style.lineHeight = this.editor.getConfiguration().lineHeight + 3 + 'px';
this.titleContainer.style.fontSize = this.editor.getConfiguration().fontInfo.fontSize + 3 + 'px';
this.titleContainer.style.fontSize = this.editor.getConfiguration().fontInfo.fontSize + 'px';
const iconSize = this.getIconSize();
this.icon.style.height = `${iconSize}px`;
this.icon.style.width = `${iconSize}px`;
......@@ -189,15 +189,14 @@ export class DefaultSettingsHeaderWidget extends Widget {
private create(parent: HTMLElement) {
this.domNode = DOM.append(parent, DOM.$('div.settings-header-widget'));
this.headerContainer = DOM.append(this.domNode, DOM.$('div.settings-header-container'));
this.headerContainer.style.paddingLeft = '28px';
this.headerContainer.style.paddingRight = '32px';
const titleContainer = DOM.append(this.headerContainer, DOM.$('div.settings-title-container'));
this.createInfoContainer(DOM.append(titleContainer, DOM.$('div.settings-info-container')));
this.createSearchContainer(DOM.append(this.headerContainer, DOM.$('div.settings-search-container')));
this.createSearchContainer(DOM.append(this.domNode, DOM.$('div.settings-search-container')));
}
private createInfoContainer(infoContainer: HTMLElement) {
DOM.append(infoContainer, DOM.$('span')).textContent = localize('defaultSettingsInfo', "Overwrite settings by placing them into your settings file.");
DOM.append(infoContainer, DOM.$('span.title-label')).textContent = localize('defaultSettingsTitle', "Default Settings");
DOM.append(infoContainer, DOM.$('span')).textContent = localize('defaultSettingsInfo', " - Overwrite these by placing them into your settings file");
}
private createSearchContainer(searchContainer: HTMLElement) {
......@@ -220,7 +219,7 @@ export class DefaultSettingsHeaderWidget extends Widget {
}
public layout(dimension: Dimension): void {
this.inputBox.width = dimension.width - 65;
this.inputBox.width = dimension.width - 62;
}
private _onKeyUp(keyboardEvent: IKeyboardEvent): void {
......
......@@ -61,7 +61,6 @@ export interface IPreferencesService {
_serviceBrand: any;
createDefaultPreferencesEditorModel(uri: URI): TPromise<IPreferencesEditorModel>;
createDefaultSettingsModel(): TPromise<IPreferencesEditorModel>;
resolvePreferencesEditorModel(uri: URI): TPromise<IPreferencesEditorModel>;
openGlobalSettings(): TPromise<void>;
......
......@@ -8,12 +8,20 @@
import winjs = require('vs/base/common/winjs.base');
import errors = require('vs/base/common/errors');
import URI from 'vs/base/common/uri';
import { ArraySet } from 'vs/base/common/set';
import { IFileService } from 'vs/platform/files/common/files';
import product from 'vs/platform/product';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IOptions } from 'vs/workbench/common/options';
const SshProtocolMatcher = /^[^:]+@([^:]+):/;
const SecondLevelDomainMatcher = /[^.]+\.[^.]+$/;
const RemoteMatcher = /^\s*url\s*=\s*(.+\S)\s*$/mg;
type Tags = { [index: string]: boolean | number };
export class WorkspaceStats {
constructor(
@IFileService private fileService: IFileService,
......@@ -26,8 +34,8 @@ export class WorkspaceStats {
return arr.some(v => v.search(regEx) > -1) || undefined;
}
private getWorkspaceTags(workbenchOptions: IOptions): winjs.TPromise<{ [index: string]: boolean }> {
const tags: { [index: string]: boolean | number } = Object.create(null);
private getWorkspaceTags(workbenchOptions: IOptions): winjs.TPromise<Tags> {
const tags: Tags = Object.create(null);
const { filesToOpen, filesToCreate, filesToDiff } = workbenchOptions;
tags['workbench.filesToOpen'] = filesToOpen && filesToOpen.length || undefined;
......@@ -40,7 +48,7 @@ export class WorkspaceStats {
const folder = workspace ? workspace.resource : product.quality !== 'stable' && this.findFolder(workbenchOptions);
if (folder && this.fileService) {
return this.fileService.resolveFile(folder).then(stats => {
let names = stats.children.map(c => c.name);
let names = (stats.children || []).map(c => c.name);
tags['workspace.language.cs'] = this.searchArray(names, /^.+\.cs$/i);
tags['workspace.language.js'] = this.searchArray(names, /^.+\.js$/i);
......@@ -131,4 +139,102 @@ export class WorkspaceStats {
this.telemetryService.publicLog('workspce.tags', tags);
}, error => errors.onUnexpectedError(error));
}
private stripLowLevelDomains(domain: string): string {
let match = domain.match(SecondLevelDomainMatcher);
return match ? match[0] : null;
}
private extractDomain(url: string): string {
let match = url.match(SshProtocolMatcher);
if (match) {
return this.stripLowLevelDomains(match[1]);
}
try {
let uri = URI.parse(url);
if (uri.authority) {
return this.stripLowLevelDomains(uri.authority);
}
} catch (e) {
// ignore invalid URIs
}
return null;
}
private getDomainsOfRemotes(text): string[] {
let domains = new ArraySet<string>(), match;
while (match = RemoteMatcher.exec(text)) {
let domain = this.extractDomain(match[1]);
if (domain) {
domains.set(domain);
}
}
return domains.elements;
}
private reportRemotes(workspaceUri: URI): void {
let uri = workspaceUri.with({ path: `${workspaceUri.path}/.git/config` });
this.fileService.resolveContent(uri, { acceptTextOnly: true }).then(
content => {
let domains = this.getDomainsOfRemotes(content.value);
this.telemetryService.publicLog('workspace.remotes', { domains });
},
err => {
// ignore missing or binary file
}
).then(null, errors.onUnexpectedError);
}
private reportAzureNode(workspaceUri: URI, tags: Tags): winjs.TPromise<Tags> {
// TODO: should also work for `node_modules` folders several levels down
let uri = workspaceUri.with({ path: `${workspaceUri.path}/node_modules` });
return this.fileService.resolveFile(uri).then(
stats => {
let names = (stats.children || []).map(c => c.name);
let referencesAzure = this.searchArray(names, /azure/i);
if (referencesAzure) {
tags['node'] = true;
}
return tags;
},
err => {
return tags;
});
}
private reportAzureJava(workspaceUri: URI, tags: Tags): winjs.TPromise<Tags> {
let uri = workspaceUri.with({ path: `${workspaceUri.path}/pom.xml` });
return this.fileService.resolveContent(uri, { acceptTextOnly: true }).then(
content => {
let referencesAzure = content.value.match(/azure/i) !== null;
if (referencesAzure) {
tags['java'] = true;
}
return tags;
},
err => {
return tags;
}
);
}
private reportAzure(uri) {
const tags: Tags = Object.create(null);
this.reportAzureNode(uri, tags).then((tags) => {
return this.reportAzureJava(uri, tags);
}).then((tags) => {
if (Object.keys(tags).length) {
this.telemetryService.publicLog('workspace.azure', tags);
}
}).then(null, errors.onUnexpectedError);
}
public reportCloudStats(): void {
const workspace = this.contextService.getWorkspace();
let uri = workspace ? workspace.resource : null;
if (uri && this.fileService) {
this.reportRemotes(uri);
this.reportAzure(uri);
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册