Archived
Merge from vscode e6a45f4242ebddb7aa9a229f85555e8a3bd987e2 (#9253)
* Merge from vscode e6a45f4242ebddb7aa9a229f85555e8a3bd987e2 * skip failing tests * remove github-authentication extensions * ignore github compile steps * ignore github compile steps * check in compiled files
This commit is contained in:
@@ -116,6 +116,11 @@ steps:
|
|||||||
yarn gulp minify-vscode-reh-web
|
yarn gulp minify-vscode-reh-web
|
||||||
displayName: Compile
|
displayName: Compile
|
||||||
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
|
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'))
|
||||||
|
env:
|
||||||
|
OSS_GITHUB_ID: "a5d3c261b032765a78de"
|
||||||
|
OSS_GITHUB_SECRET: $(oss-github-client-secret)
|
||||||
|
INSIDERS_GITHUB_ID: "31f02627809389d9f111"
|
||||||
|
INSIDERS_GITHUB_SECRET: $(insiders-github-client-secret)
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
set -e
|
set -e
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ function compileTask(src, out, build) {
|
|||||||
if (src === 'src') {
|
if (src === 'src') {
|
||||||
generator.execute();
|
generator.execute();
|
||||||
}
|
}
|
||||||
|
// generateGitHubAuthConfig();
|
||||||
return srcPipe
|
return srcPipe
|
||||||
.pipe(generator.stream)
|
.pipe(generator.stream)
|
||||||
.pipe(compile())
|
.pipe(compile())
|
||||||
@@ -96,6 +97,18 @@ function watchTask(out, build) {
|
|||||||
}
|
}
|
||||||
exports.watchTask = watchTask;
|
exports.watchTask = watchTask;
|
||||||
const REPO_SRC_FOLDER = path.join(__dirname, '../../src');
|
const REPO_SRC_FOLDER = path.join(__dirname, '../../src');
|
||||||
|
/*function generateGitHubAuthConfig() {
|
||||||
|
const schemes = ['OSS', 'INSIDERS'];
|
||||||
|
let content: { [key: string]: { id?: string, secret?: string }} = {};
|
||||||
|
schemes.forEach(scheme => {
|
||||||
|
content[scheme] = {
|
||||||
|
id: process.env[`${scheme}_GITHUB_ID`],
|
||||||
|
secret: process.env[`${scheme}_GITHUB_SECRET`]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFileSync(path.join(__dirname, '../../extensions/github-authentication/src/common/config.json'), JSON.stringify(content));
|
||||||
|
}*/
|
||||||
class MonacoGenerator {
|
class MonacoGenerator {
|
||||||
constructor(isWatch) {
|
constructor(isWatch) {
|
||||||
this._executeSoonTimer = null;
|
this._executeSoonTimer = null;
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ export function compileTask(src: string, out: string, build: boolean): () => Nod
|
|||||||
generator.execute();
|
generator.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generateGitHubAuthConfig();
|
||||||
|
|
||||||
return srcPipe
|
return srcPipe
|
||||||
.pipe(generator.stream)
|
.pipe(generator.stream)
|
||||||
.pipe(compile())
|
.pipe(compile())
|
||||||
@@ -115,6 +117,19 @@ export function watchTask(out: string, build: boolean): () => NodeJS.ReadWriteSt
|
|||||||
|
|
||||||
const REPO_SRC_FOLDER = path.join(__dirname, '../../src');
|
const REPO_SRC_FOLDER = path.join(__dirname, '../../src');
|
||||||
|
|
||||||
|
/*function generateGitHubAuthConfig() {
|
||||||
|
const schemes = ['OSS', 'INSIDERS'];
|
||||||
|
let content: { [key: string]: { id?: string, secret?: string }} = {};
|
||||||
|
schemes.forEach(scheme => {
|
||||||
|
content[scheme] = {
|
||||||
|
id: process.env[`${scheme}_GITHUB_ID`],
|
||||||
|
secret: process.env[`${scheme}_GITHUB_SECRET`]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFileSync(path.join(__dirname, '../../extensions/github-authentication/src/common/config.json'), JSON.stringify(content));
|
||||||
|
}*/
|
||||||
|
|
||||||
class MonacoGenerator {
|
class MonacoGenerator {
|
||||||
private readonly _isWatch: boolean;
|
private readonly _isWatch: boolean;
|
||||||
public readonly stream: NodeJS.ReadWriteStream;
|
public readonly stream: NodeJS.ReadWriteStream;
|
||||||
|
|||||||
@@ -302,6 +302,10 @@
|
|||||||
"name": "vs/workbench/services/textMate",
|
"name": "vs/workbench/services/textMate",
|
||||||
"project": "vscode-workbench"
|
"project": "vscode-workbench"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "vs/workbench/services/workingCopy",
|
||||||
|
"project": "vscode-workbench"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "vs/workbench/services/workspaces",
|
"name": "vs/workbench/services/workspaces",
|
||||||
"project": "vscode-workbench"
|
"project": "vscode-workbench"
|
||||||
|
|||||||
Vendored
+1
-1
@@ -232,7 +232,7 @@ function onUnexpectedError(error, enableDeveloperTools) {
|
|||||||
|
|
||||||
console.error('[uncaught exception]: ' + error);
|
console.error('[uncaught exception]: ' + error);
|
||||||
|
|
||||||
if (error.stack) {
|
if (error && error.stack) {
|
||||||
console.error(error.stack);
|
console.error(error.stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export class AdditionalKeyBindings<T> implements Slick.Plugin<T> {
|
|||||||
|
|
||||||
public init(grid: Slick.Grid<T>) {
|
public init(grid: Slick.Grid<T>) {
|
||||||
this.grid = grid;
|
this.grid = grid;
|
||||||
this.handler.subscribe(this.grid.onKeyDown, (e: KeyboardEvent, args) => this.handleKeyDown(e, args));
|
this.handler.subscribe(this.grid.onKeyDown, (e: DOMEvent, args) => this.handleKeyDown(e as KeyboardEvent, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ export class CellRangeSelector<T> implements ICellRangeSelector<T> {
|
|||||||
this.canvas = this.grid.getCanvasNode();
|
this.canvas = this.grid.getCanvasNode();
|
||||||
this.handler
|
this.handler
|
||||||
.subscribe(this.grid.onDragInit, e => this.handleDragInit(e))
|
.subscribe(this.grid.onDragInit, e => this.handleDragInit(e))
|
||||||
.subscribe(this.grid.onDragStart, (e: MouseEvent, dd) => this.handleDragStart(e, dd))
|
.subscribe(this.grid.onDragStart, (e: DOMEvent, dd) => this.handleDragStart(e as MouseEvent, dd))
|
||||||
.subscribe(this.grid.onDrag, (e: MouseEvent, dd) => this.handleDrag(e, dd))
|
.subscribe(this.grid.onDrag, (e: DOMEvent, dd) => this.handleDrag(e as MouseEvent, dd))
|
||||||
.subscribe(this.grid.onDragEnd, (e: MouseEvent, dd) => this.handleDragEnd(e, dd));
|
.subscribe(this.grid.onDragEnd, (e: DOMEvent, dd) => this.handleDragEnd(e as MouseEvent, dd));
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
|
|||||||
@@ -36,10 +36,10 @@ export class CellSelectionModel<T> implements Slick.SelectionModel<T, Array<Slic
|
|||||||
|
|
||||||
public init(grid: Slick.Grid<T>) {
|
public init(grid: Slick.Grid<T>) {
|
||||||
this.grid = grid;
|
this.grid = grid;
|
||||||
this._handler.subscribe(this.grid.onClick, (e: MouseEvent, args: Slick.OnActiveCellChangedEventArgs<T>) => this.handleActiveCellChange(e, args));
|
this._handler.subscribe(this.grid.onClick, (e: DOMEvent, args: Slick.OnActiveCellChangedEventArgs<T>) => this.handleActiveCellChange(e as MouseEvent, args));
|
||||||
this._handler.subscribe(this.grid.onKeyDown, (e: KeyboardEvent) => this.handleKeyDown(e));
|
this._handler.subscribe(this.grid.onKeyDown, (e: DOMEvent) => this.handleKeyDown(e as KeyboardEvent));
|
||||||
this._handler.subscribe(this.grid.onClick, (e: MouseEvent, args: Slick.OnClickEventArgs<T>) => this.handleIndividualCellSelection(e, args));
|
this._handler.subscribe(this.grid.onClick, (e: DOMEvent, args: Slick.OnClickEventArgs<T>) => this.handleIndividualCellSelection(e as MouseEvent, args));
|
||||||
this._handler.subscribe(this.grid.onHeaderClick, (e: MouseEvent, args: Slick.OnHeaderClickEventArgs<T>) => this.handleHeaderClick(e, args));
|
this._handler.subscribe(this.grid.onHeaderClick, (e: DOMEvent, args: Slick.OnHeaderClickEventArgs<T>) => this.handleHeaderClick(e as MouseEvent, args));
|
||||||
this.grid.registerPlugin(this.selector);
|
this.grid.registerPlugin(this.selector);
|
||||||
this._handler.subscribe(this.selector.onCellRangeSelected, (e: Event, range: Slick.Range) => this.handleCellRangeSelected(e, range, false));
|
this._handler.subscribe(this.selector.onCellRangeSelected, (e: Event, range: Slick.Range) => this.handleCellRangeSelected(e, range, false));
|
||||||
this._handler.subscribe(this.selector.onAppendCellRangeSelected, (e: Event, range: Slick.Range) => this.handleCellRangeSelected(e, range, true));
|
this._handler.subscribe(this.selector.onAppendCellRangeSelected, (e: Event, range: Slick.Range) => this.handleCellRangeSelected(e, range, true));
|
||||||
|
|||||||
@@ -66,9 +66,9 @@ export class CheckboxSelectColumn<T extends Slick.SlickData> implements Slick.Pl
|
|||||||
this._grid = grid;
|
this._grid = grid;
|
||||||
this._handler
|
this._handler
|
||||||
.subscribe(this._grid.onSelectedRowsChanged, (e: Event, args: Slick.OnSelectedRowsChangedEventArgs<T>) => this.handleSelectedRowsChanged(e, args))
|
.subscribe(this._grid.onSelectedRowsChanged, (e: Event, args: Slick.OnSelectedRowsChangedEventArgs<T>) => this.handleSelectedRowsChanged(e, args))
|
||||||
.subscribe(this._grid.onClick, (e: MouseEvent, args: Slick.OnClickEventArgs<T>) => this.handleClick(e, args))
|
.subscribe(this._grid.onClick, (e: DOMEvent, args: Slick.OnClickEventArgs<T>) => this.handleClick(e as MouseEvent, args))
|
||||||
.subscribe(this._grid.onHeaderClick, (e: MouseEvent, args: Slick.OnHeaderClickEventArgs<T>) => this.handleHeaderClick(e, args))
|
.subscribe(this._grid.onHeaderClick, (e: DOMEvent, args: Slick.OnHeaderClickEventArgs<T>) => this.handleHeaderClick(e as MouseEvent, args))
|
||||||
.subscribe(this._grid.onKeyDown, (e: KeyboardEvent, args: Slick.OnKeyDownEventArgs<T>) => this.handleKeyDown(e, args));
|
.subscribe(this._grid.onKeyDown, (e: DOMEvent, args: Slick.OnKeyDownEventArgs<T>) => this.handleKeyDown(e as KeyboardEvent, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy(): void {
|
public destroy(): void {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export class CopyKeybind<T> implements Slick.Plugin<T> {
|
|||||||
|
|
||||||
public init(grid: Slick.Grid<T>) {
|
public init(grid: Slick.Grid<T>) {
|
||||||
this.grid = grid;
|
this.grid = grid;
|
||||||
this.handler.subscribe(this.grid.onKeyDown, (e: KeyboardEvent, args: Slick.OnKeyDownEventArgs<T>) => this.handleKeyDown(e, args));
|
this.handler.subscribe(this.grid.onKeyDown, (e: DOMEvent, args: Slick.OnKeyDownEventArgs<T>) => this.handleKeyDown(e as KeyboardEvent, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ export class HeaderFilter<T extends Slick.SlickData> {
|
|||||||
this.grid = grid;
|
this.grid = grid;
|
||||||
this.handler.subscribe(this.grid.onHeaderCellRendered, (e: Event, args: Slick.OnHeaderCellRenderedEventArgs<T>) => this.handleHeaderCellRendered(e, args))
|
this.handler.subscribe(this.grid.onHeaderCellRendered, (e: Event, args: Slick.OnHeaderCellRenderedEventArgs<T>) => this.handleHeaderCellRendered(e, args))
|
||||||
.subscribe(this.grid.onBeforeHeaderCellDestroy, (e: Event, args: Slick.OnBeforeHeaderCellDestroyEventArgs<T>) => this.handleBeforeHeaderCellDestroy(e, args))
|
.subscribe(this.grid.onBeforeHeaderCellDestroy, (e: Event, args: Slick.OnBeforeHeaderCellDestroyEventArgs<T>) => this.handleBeforeHeaderCellDestroy(e, args))
|
||||||
.subscribe(this.grid.onClick, (e: MouseEvent) => this.handleBodyMouseDown(e))
|
.subscribe(this.grid.onClick, (e: DOMEvent) => this.handleBodyMouseDown(e as MouseEvent))
|
||||||
.subscribe(this.grid.onColumnsResized, () => this.columnsResized())
|
.subscribe(this.grid.onColumnsResized, () => this.columnsResized())
|
||||||
.subscribe(this.grid.onKeyDown, (e: KeyboardEvent) => this.handleKeyDown(e));
|
.subscribe(this.grid.onKeyDown, (e: DOMEvent) => this.handleKeyDown(e as KeyboardEvent));
|
||||||
this.grid.setColumns(this.grid.getColumns());
|
this.grid.setColumns(this.grid.getColumns());
|
||||||
|
|
||||||
this.disposableStore.add(addDisposableListener(document.body, 'mousedown', e => this.handleBodyMouseDown(e)));
|
this.disposableStore.add(addDisposableListener(document.body, 'mousedown', e => this.handleBodyMouseDown(e)));
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export class RowDetailView<T extends Slick.SlickData> {
|
|||||||
this._grid.getOptions().minRowBuffer = this._options.panelRows + 3;
|
this._grid.getOptions().minRowBuffer = this._options.panelRows + 3;
|
||||||
|
|
||||||
this._handler
|
this._handler
|
||||||
.subscribe(this._grid.onClick, (e: MouseEvent, args: Slick.OnClickEventArgs<T>) => this.handleClick(e, args))
|
.subscribe(this._grid.onClick, (e: DOMEvent, args: Slick.OnClickEventArgs<T>) => this.handleClick(e as MouseEvent, args))
|
||||||
.subscribe(this._grid.onSort, () => this.handleSort())
|
.subscribe(this._grid.onSort, () => this.handleSort())
|
||||||
.subscribe(this._grid.onScroll, () => this.handleScroll());
|
.subscribe(this._grid.onScroll, () => this.handleScroll());
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ export class RowNumberColumn<T> implements Slick.Plugin<T> {
|
|||||||
public init(grid: Slick.Grid<T>) {
|
public init(grid: Slick.Grid<T>) {
|
||||||
this.grid = grid;
|
this.grid = grid;
|
||||||
this.handler
|
this.handler
|
||||||
.subscribe(this.grid.onClick, (e: MouseEvent, args: Slick.OnClickEventArgs<T>) => this.handleClick(e, args))
|
.subscribe(this.grid.onClick, (e: DOMEvent, args: Slick.OnClickEventArgs<T>) => this.handleClick(e as MouseEvent, args))
|
||||||
.subscribe(this.grid.onHeaderClick, (e: MouseEvent, args: Slick.OnHeaderClickEventArgs<T>) => this.handleHeaderClick(e, args));
|
.subscribe(this.grid.onHeaderClick, (e: DOMEvent, args: Slick.OnHeaderClickEventArgs<T>) => this.handleHeaderClick(e as MouseEvent, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ export class RowSelectionModel<T extends Slick.SlickData> implements Slick.Selec
|
|||||||
this._grid = grid;
|
this._grid = grid;
|
||||||
this._handler
|
this._handler
|
||||||
.subscribe(this._grid.onActiveCellChanged, (e: Event, data: Slick.OnActiveCellChangedEventArgs<T>) => this.handleActiveCellChange(e, data))
|
.subscribe(this._grid.onActiveCellChanged, (e: Event, data: Slick.OnActiveCellChangedEventArgs<T>) => this.handleActiveCellChange(e, data))
|
||||||
.subscribe(this._grid.onKeyDown, (e: KeyboardEvent) => this.handleKeyDown(e))
|
.subscribe(this._grid.onKeyDown, (e: DOMEvent) => this.handleKeyDown(e as KeyboardEvent))
|
||||||
.subscribe(this._grid.onClick, (e: MouseEvent) => this.handleClick(e));
|
.subscribe(this._grid.onClick, (e: DOMEvent) => this.handleClick(e as MouseEvent));
|
||||||
}
|
}
|
||||||
|
|
||||||
private rangesToRows(ranges: Slick.Range[]): number[] {
|
private rangesToRows(ranges: Slick.Range[]): number[] {
|
||||||
|
|||||||
@@ -127,8 +127,8 @@ export class Table<T extends Slick.SlickData> extends Widget implements IDisposa
|
|||||||
}
|
}
|
||||||
|
|
||||||
private mapMouseEvent(slickEvent: Slick.Event<any>, emitter: Emitter<ITableMouseEvent>) {
|
private mapMouseEvent(slickEvent: Slick.Event<any>, emitter: Emitter<ITableMouseEvent>) {
|
||||||
slickEvent.subscribe((e: JQuery.Event) => {
|
slickEvent.subscribe((e: Slick.EventData) => {
|
||||||
const originalEvent = e.originalEvent;
|
const originalEvent = (e as JQuery.Event).originalEvent;
|
||||||
const cell = this._grid.getCellFromEvent(originalEvent);
|
const cell = this._grid.getCellFromEvent(originalEvent);
|
||||||
const anchor = originalEvent instanceof MouseEvent ? { x: originalEvent.x, y: originalEvent.y } : originalEvent.srcElement as HTMLElement;
|
const anchor = originalEvent instanceof MouseEvent ? { x: originalEvent.x, y: originalEvent.y } : originalEvent.srcElement as HTMLElement;
|
||||||
emitter.fire({ anchor, cell });
|
emitter.fire({ anchor, cell });
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import 'vs/css!./media/icons';
|
|||||||
|
|
||||||
import { ActionBar } from './actionbar';
|
import { ActionBar } from './actionbar';
|
||||||
|
|
||||||
import { Action, IActionRunner, IAction } from 'vs/base/common/actions';
|
import { IActionRunner, IAction } from 'vs/base/common/actions';
|
||||||
import { ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
import { ActionsOrientation, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||||
import { IToolBarOptions } from 'vs/base/browser/ui/toolbar/toolbar';
|
import { IToolBarOptions } from 'vs/base/browser/ui/toolbar/toolbar';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,7 +43,7 @@ export class Taskbar {
|
|||||||
this.actionBar = new ActionBar(element, {
|
this.actionBar = new ActionBar(element, {
|
||||||
orientation: options.orientation,
|
orientation: options.orientation,
|
||||||
ariaLabel: options.ariaLabel,
|
ariaLabel: options.ariaLabel,
|
||||||
actionViewItemProvider: (action: Action) => {
|
actionViewItemProvider: (action: IAction): IActionViewItem | undefined => {
|
||||||
return options.actionViewItemProvider ? options.actionViewItemProvider(action) : undefined;
|
return options.actionViewItemProvider ? options.actionViewItemProvider(action) : undefined;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import { ICapabilitiesService, ProviderFeatures } from 'sql/platform/capabilities/common/capabilitiesService';
|
import { ProviderFeatures } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||||
import { ConnectionConfig, ISaveGroupResult } from 'sql/platform/connection/common/connectionConfig';
|
import { ConnectionConfig, ISaveGroupResult } from 'sql/platform/connection/common/connectionConfig';
|
||||||
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||||
import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup';
|
import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup';
|
||||||
@@ -19,7 +19,7 @@ import { ConfigurationTarget } from 'vs/platform/configuration/common/configurat
|
|||||||
import { find } from 'vs/base/common/arrays';
|
import { find } from 'vs/base/common/arrays';
|
||||||
|
|
||||||
suite('ConnectionConfig', () => {
|
suite('ConnectionConfig', () => {
|
||||||
let capabilitiesService: TypeMoq.Mock<ICapabilitiesService>;
|
let capabilitiesService: TypeMoq.Mock<TestCapabilitiesService>;
|
||||||
let msSQLCapabilities: ProviderFeatures;
|
let msSQLCapabilities: ProviderFeatures;
|
||||||
let capabilities: ProviderFeatures[];
|
let capabilities: ProviderFeatures[];
|
||||||
let onCapabilitiesRegistered = new Emitter<ProviderFeatures>();
|
let onCapabilitiesRegistered = new Emitter<ProviderFeatures>();
|
||||||
|
|||||||
@@ -2,15 +2,10 @@
|
|||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"noImplicitAny": true,
|
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noImplicitThis": true,
|
"strict": true,
|
||||||
"alwaysStrict": true,
|
|
||||||
"strictBindCallApply": true,
|
|
||||||
"strictNullChecks": true,
|
|
||||||
"strictPropertyInitialization": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"skipLibCheck": true
|
"skipLibCheck": true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export interface MarkdownRenderOptions extends FormattedTextRenderOptions {
|
|||||||
/**
|
/**
|
||||||
* Create html nodes for the given content element.
|
* Create html nodes for the given content element.
|
||||||
*/
|
*/
|
||||||
export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRenderOptions = {}): HTMLElement {
|
export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRenderOptions = {}, markedOptions: marked.MarkedOptions = {}): HTMLElement {
|
||||||
const element = createElement(options);
|
const element = createElement(options);
|
||||||
|
|
||||||
const _uriMassage = function (part: string): string {
|
const _uriMassage = function (part: string): string {
|
||||||
@@ -183,10 +183,8 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const markedOptions: marked.MarkedOptions = {
|
markedOptions.sanitize = true;
|
||||||
sanitize: true,
|
markedOptions.renderer = renderer;
|
||||||
renderer
|
|
||||||
};
|
|
||||||
|
|
||||||
const allowedSchemes = [Schemas.http, Schemas.https, Schemas.mailto, Schemas.data, Schemas.file, Schemas.vscodeRemote, Schemas.vscodeRemoteResource];
|
const allowedSchemes = [Schemas.http, Schemas.https, Schemas.mailto, Schemas.data, Schemas.file, Schemas.vscodeRemote, Schemas.vscodeRemoteResource];
|
||||||
if (markdown.isTrusted) {
|
if (markdown.isTrusted) {
|
||||||
|
|||||||
@@ -197,6 +197,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
|||||||
get contentHeight(): number { return this.rangeMap.size; }
|
get contentHeight(): number { return this.rangeMap.size; }
|
||||||
|
|
||||||
get onDidScroll(): Event<ScrollEvent> { return this.scrollableElement.onScroll; }
|
get onDidScroll(): Event<ScrollEvent> { return this.scrollableElement.onScroll; }
|
||||||
|
get onWillScroll(): Event<ScrollEvent> { return this.scrollableElement.onWillScroll; }
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
|
|||||||
@@ -167,6 +167,9 @@ export abstract class AbstractScrollableElement extends Widget {
|
|||||||
private readonly _onScroll = this._register(new Emitter<ScrollEvent>());
|
private readonly _onScroll = this._register(new Emitter<ScrollEvent>());
|
||||||
public readonly onScroll: Event<ScrollEvent> = this._onScroll.event;
|
public readonly onScroll: Event<ScrollEvent> = this._onScroll.event;
|
||||||
|
|
||||||
|
private readonly _onWillScroll = this._register(new Emitter<ScrollEvent>());
|
||||||
|
public readonly onWillScroll: Event<ScrollEvent> = this._onWillScroll.event;
|
||||||
|
|
||||||
protected constructor(element: HTMLElement, options: ScrollableElementCreationOptions, scrollable: Scrollable) {
|
protected constructor(element: HTMLElement, options: ScrollableElementCreationOptions, scrollable: Scrollable) {
|
||||||
super();
|
super();
|
||||||
element.style.overflow = 'hidden';
|
element.style.overflow = 'hidden';
|
||||||
@@ -174,6 +177,7 @@ export abstract class AbstractScrollableElement extends Widget {
|
|||||||
this._scrollable = scrollable;
|
this._scrollable = scrollable;
|
||||||
|
|
||||||
this._register(this._scrollable.onScroll((e) => {
|
this._register(this._scrollable.onScroll((e) => {
|
||||||
|
this._onWillScroll.fire(e);
|
||||||
this._onDidScroll(e);
|
this._onDidScroll(e);
|
||||||
this._onScroll.fire(e);
|
this._onScroll.fire(e);
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -56,6 +56,20 @@ export function raceCancellation<T>(promise: Promise<T>, token: CancellationToke
|
|||||||
return Promise.race([promise, new Promise<T>(resolve => token.onCancellationRequested(() => resolve(defaultValue)))]);
|
return Promise.race([promise, new Promise<T>(resolve => token.onCancellationRequested(() => resolve(defaultValue)))]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function raceTimeout<T>(promise: Promise<T>, timeout: number, onTimeout?: () => void): Promise<T> {
|
||||||
|
let promiseResolve: (() => void) | undefined = undefined;
|
||||||
|
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
promiseResolve?.();
|
||||||
|
onTimeout?.();
|
||||||
|
}, timeout);
|
||||||
|
|
||||||
|
return Promise.race([
|
||||||
|
promise.finally(() => clearTimeout(timer)),
|
||||||
|
new Promise<T>(resolve => promiseResolve = resolve)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
export function asPromise<T>(callback: () => T | Thenable<T>): Promise<T> {
|
export function asPromise<T>(callback: () => T | Thenable<T>): Promise<T> {
|
||||||
return new Promise<T>((resolve, reject) => {
|
return new Promise<T>((resolve, reject) => {
|
||||||
const item = callback();
|
const item = callback();
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const month = day * 30;
|
|||||||
const year = day * 365;
|
const year = day * 365;
|
||||||
|
|
||||||
// TODO[ECA]: Localize strings
|
// TODO[ECA]: Localize strings
|
||||||
export function fromNow(date: number | Date) {
|
export function fromNow(date: number | Date, appendAgoLabel?: boolean): string {
|
||||||
if (typeof date !== 'number') {
|
if (typeof date !== 'number') {
|
||||||
date = date.getTime();
|
date = date.getTime();
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,7 @@ export function fromNow(date: number | Date) {
|
|||||||
unit = 'yr';
|
unit = 'yr';
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${value} ${unit}${value === 1 ? '' : 's'}`;
|
return `${value} ${unit}${value === 1 ? '' : 's'}${appendAgoLabel ? ' ago' : ''}`;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { IDragAndDropData } from 'vs/base/browser/dnd';
|
||||||
|
|
||||||
|
export class CompositeDragAndDropData implements IDragAndDropData {
|
||||||
|
constructor(private type: 'view' | 'composite', private id: string) { }
|
||||||
|
update(dataTransfer: DataTransfer): void {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
getData(): {
|
||||||
|
type: 'view' | 'composite';
|
||||||
|
id: string;
|
||||||
|
} {
|
||||||
|
return { type: this.type, id: this.id };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICompositeDragAndDrop {
|
||||||
|
drop(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent): void;
|
||||||
|
onDragOver(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent): boolean;
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import * as assert from 'assert';
|
|||||||
import * as async from 'vs/base/common/async';
|
import * as async from 'vs/base/common/async';
|
||||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||||
|
|
||||||
suite('Async', () => {
|
suite('Async', () => {
|
||||||
|
|
||||||
@@ -646,4 +647,45 @@ suite('Async', () => {
|
|||||||
|
|
||||||
assert.ok(pendingCancelled);
|
assert.ok(pendingCancelled);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('raceCancellation', async () => {
|
||||||
|
const cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
const p = async.raceCancellation(async.timeout(100), cts.token);
|
||||||
|
cts.cancel();
|
||||||
|
|
||||||
|
await p;
|
||||||
|
|
||||||
|
assert.ok(Date.now() - now < 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('raceTimeout', async () => {
|
||||||
|
const cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
// timeout wins
|
||||||
|
let now = Date.now();
|
||||||
|
let timedout = false;
|
||||||
|
|
||||||
|
const p1 = async.raceTimeout(async.timeout(100), 1, () => timedout = true);
|
||||||
|
cts.cancel();
|
||||||
|
|
||||||
|
await p1;
|
||||||
|
|
||||||
|
assert.ok(Date.now() - now < 100);
|
||||||
|
assert.equal(timedout, true);
|
||||||
|
|
||||||
|
// promise wins
|
||||||
|
now = Date.now();
|
||||||
|
timedout = false;
|
||||||
|
|
||||||
|
const p2 = async.raceTimeout(async.timeout(1), 100, () => timedout = true);
|
||||||
|
cts.cancel();
|
||||||
|
|
||||||
|
await p2;
|
||||||
|
|
||||||
|
assert.ok(Date.now() - now < 100);
|
||||||
|
assert.equal(timedout, false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -97,6 +97,23 @@ export class IssueReporter extends Disposable {
|
|||||||
this.previewButton = new Button(issueReporterElement);
|
this.previewButton = new Button(issueReporterElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const issueTitle = configuration.data.issueTitle;
|
||||||
|
if (issueTitle) {
|
||||||
|
const issueTitleElement = this.getElementById<HTMLInputElement>('issue-title');
|
||||||
|
if (issueTitleElement) {
|
||||||
|
issueTitleElement.value = issueTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const issueBody = configuration.data.issueBody;
|
||||||
|
if (issueBody) {
|
||||||
|
const description = this.getElementById<HTMLTextAreaElement>('description');
|
||||||
|
if (description) {
|
||||||
|
description.value = issueBody;
|
||||||
|
this.issueReporterModel.update({ issueDescription: issueBody });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ipcRenderer.on('vscode:issuePerformanceInfoResponse', (_: unknown, info: Partial<IssueReporterData>) => {
|
ipcRenderer.on('vscode:issuePerformanceInfoResponse', (_: unknown, info: Partial<IssueReporterData>) => {
|
||||||
this.logService.trace('issueReporter: Received performance data');
|
this.logService.trace('issueReporter: Received performance data');
|
||||||
this.issueReporterModel.update(info);
|
this.issueReporterModel.update(info);
|
||||||
@@ -1176,8 +1193,8 @@ export class IssueReporter extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getElementById(elementId: string): HTMLElement | undefined {
|
private getElementById<T extends HTMLElement = HTMLElement>(elementId: string): T | undefined {
|
||||||
const element = document.getElementById(elementId);
|
const element = document.getElementById(elementId) as T | undefined;
|
||||||
if (element) {
|
if (element) {
|
||||||
return element;
|
return element;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ import { IFileService } from 'vs/platform/files/common/files';
|
|||||||
import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider';
|
import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { IProductService } from 'vs/platform/product/common/productService';
|
import { IProductService } from 'vs/platform/product/common/productService';
|
||||||
import { IUserDataSyncService, IUserDataSyncStoreService, registerConfiguration, IUserDataSyncLogService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataAuthTokenService, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
|
import { IUserDataSyncService, IUserDataSyncStoreService, registerConfiguration, IUserDataSyncLogService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||||
import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService';
|
import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService';
|
||||||
import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService';
|
import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService';
|
||||||
import { UserDataSyncChannel, UserDataSyncUtilServiceClient, SettingsSyncChannel, UserDataAuthTokenServiceChannel, UserDataAutoSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc';
|
import { UserDataSyncChannel, UserDataSyncUtilServiceClient, SettingsSyncChannel, UserDataAutoSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc';
|
||||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||||
import { LoggerService } from 'vs/platform/log/node/loggerService';
|
import { LoggerService } from 'vs/platform/log/node/loggerService';
|
||||||
import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog';
|
import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog';
|
||||||
@@ -60,12 +60,13 @@ import { ICredentialsService } from 'vs/platform/credentials/common/credentials'
|
|||||||
import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService';
|
import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService';
|
||||||
import { UserDataAutoSyncService } from 'vs/platform/userDataSync/electron-browser/userDataAutoSyncService';
|
import { UserDataAutoSyncService } from 'vs/platform/userDataSync/electron-browser/userDataAutoSyncService';
|
||||||
import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync';
|
import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync';
|
||||||
import { UserDataAuthTokenService } from 'vs/platform/userDataSync/common/userDataAuthTokenService';
|
|
||||||
import { NativeStorageService } from 'vs/platform/storage/node/storageService';
|
import { NativeStorageService } from 'vs/platform/storage/node/storageService';
|
||||||
import { GlobalStorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc';
|
import { GlobalStorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc';
|
||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||||
import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService';
|
import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService';
|
||||||
import { UserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSyncEnablementService';
|
import { UserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSyncEnablementService';
|
||||||
|
import { IAuthenticationTokenService, AuthenticationTokenService } from 'vs/platform/authentication/common/authentication';
|
||||||
|
import { AuthenticationTokenServiceChannel } from 'vs/platform/authentication/common/authenticationIpc';
|
||||||
|
|
||||||
export interface ISharedProcessConfiguration {
|
export interface ISharedProcessConfiguration {
|
||||||
readonly machineId: string;
|
readonly machineId: string;
|
||||||
@@ -188,7 +189,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
|
|||||||
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
|
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
|
||||||
|
|
||||||
services.set(ICredentialsService, new SyncDescriptor(KeytarCredentialsService));
|
services.set(ICredentialsService, new SyncDescriptor(KeytarCredentialsService));
|
||||||
services.set(IUserDataAuthTokenService, new SyncDescriptor(UserDataAuthTokenService));
|
services.set(IAuthenticationTokenService, new SyncDescriptor(AuthenticationTokenService));
|
||||||
services.set(IUserDataSyncLogService, new SyncDescriptor(UserDataSyncLogService));
|
services.set(IUserDataSyncLogService, new SyncDescriptor(UserDataSyncLogService));
|
||||||
services.set(IUserDataSyncUtilService, new UserDataSyncUtilServiceClient(server.getChannel('userDataSyncUtil', client => client.ctx !== 'main')));
|
services.set(IUserDataSyncUtilService, new UserDataSyncUtilServiceClient(server.getChannel('userDataSyncUtil', client => client.ctx !== 'main')));
|
||||||
services.set(IGlobalExtensionEnablementService, new SyncDescriptor(GlobalExtensionEnablementService));
|
services.set(IGlobalExtensionEnablementService, new SyncDescriptor(GlobalExtensionEnablementService));
|
||||||
@@ -214,8 +215,8 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
|
|||||||
const diagnosticsChannel = new DiagnosticsChannel(diagnosticsService);
|
const diagnosticsChannel = new DiagnosticsChannel(diagnosticsService);
|
||||||
server.registerChannel('diagnostics', diagnosticsChannel);
|
server.registerChannel('diagnostics', diagnosticsChannel);
|
||||||
|
|
||||||
const authTokenService = accessor.get(IUserDataAuthTokenService);
|
const authTokenService = accessor.get(IAuthenticationTokenService);
|
||||||
const authTokenChannel = new UserDataAuthTokenServiceChannel(authTokenService);
|
const authTokenChannel = new AuthenticationTokenServiceChannel(authTokenService);
|
||||||
server.registerChannel('authToken', authTokenChannel);
|
server.registerChannel('authToken', authTokenChannel);
|
||||||
|
|
||||||
const settingsSyncService = accessor.get(ISettingsSyncService);
|
const settingsSyncService = accessor.get(ISettingsSyncService);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands
|
|||||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||||
|
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||||
|
|
||||||
const CORE_WEIGHT = KeybindingWeight.EditorCore;
|
const CORE_WEIGHT = KeybindingWeight.EditorCore;
|
||||||
|
|
||||||
@@ -1529,6 +1530,102 @@ export namespace CoreNavigationCommands {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A command that will:
|
||||||
|
* 1. invoke a command on the focused editor.
|
||||||
|
* 2. otherwise, invoke a browser built-in command on the `activeElement`.
|
||||||
|
* 3. otherwise, invoke a command on the workbench active editor.
|
||||||
|
*/
|
||||||
|
abstract class EditorOrNativeTextInputCommand extends Command {
|
||||||
|
|
||||||
|
public runCommand(accessor: ServicesAccessor, args: any): void {
|
||||||
|
|
||||||
|
const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
|
||||||
|
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||||
|
if (focusedEditor && focusedEditor.hasTextFocus()) {
|
||||||
|
return this.runEditorCommand(accessor, focusedEditor, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore this action when user is focused on an element that allows for entering text
|
||||||
|
const activeElement = <HTMLElement>document.activeElement;
|
||||||
|
if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) {
|
||||||
|
return this.runDOMCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirecting to active editor
|
||||||
|
const activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor();
|
||||||
|
if (activeEditor) {
|
||||||
|
activeEditor.focus();
|
||||||
|
return this.runEditorCommand(accessor, activeEditor, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract runDOMCommand(): void;
|
||||||
|
public abstract runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SelectAllCommand extends EditorOrNativeTextInputCommand {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
id: 'editor.action.selectAll',
|
||||||
|
precondition: EditorContextKeys.textInputFocus,
|
||||||
|
kbOpts: {
|
||||||
|
weight: CORE_WEIGHT,
|
||||||
|
kbExpr: null,
|
||||||
|
primary: KeyMod.CtrlCmd | KeyCode.KEY_A
|
||||||
|
},
|
||||||
|
menuOpts: [{
|
||||||
|
menuId: MenuId.MenubarEditMenu, // {{SQL CARBON EDIT}} - Put this in the edit menu since we disabled the selection menu
|
||||||
|
group: '4_find_global', // {{SQL CARBON EDIT}} - Put this in the edit menu since we disabled the selection menu
|
||||||
|
title: nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"),
|
||||||
|
order: 1
|
||||||
|
}, {
|
||||||
|
menuId: MenuId.CommandPalette,
|
||||||
|
group: '',
|
||||||
|
title: nls.localize('selectAll', "Select All"),
|
||||||
|
order: 1
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public runDOMCommand(): void {
|
||||||
|
document.execCommand('selectAll');
|
||||||
|
}
|
||||||
|
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
|
||||||
|
args = args || {};
|
||||||
|
args.source = 'keyboard';
|
||||||
|
CoreNavigationCommands.SelectAll.runEditorCommand(accessor, editor, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UndoCommand extends EditorOrNativeTextInputCommand {
|
||||||
|
public runDOMCommand(): void {
|
||||||
|
document.execCommand('undo');
|
||||||
|
}
|
||||||
|
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
|
||||||
|
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
editor.getModel().undo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RedoCommand extends EditorOrNativeTextInputCommand {
|
||||||
|
public runDOMCommand(): void {
|
||||||
|
document.execCommand('redo');
|
||||||
|
}
|
||||||
|
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
|
||||||
|
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
editor.getModel().redo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerCommand<T extends Command>(command: T): T {
|
||||||
|
command.register();
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
export namespace CoreEditingCommands {
|
export namespace CoreEditingCommands {
|
||||||
|
|
||||||
export abstract class CoreEditingCommand extends EditorCommand {
|
export abstract class CoreEditingCommand extends EditorCommand {
|
||||||
@@ -1659,62 +1756,53 @@ export namespace CoreEditingCommands {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
export const Undo: UndoCommand = registerCommand(new UndoCommand({
|
||||||
|
id: 'undo',
|
||||||
|
precondition: EditorContextKeys.writable,
|
||||||
|
kbOpts: {
|
||||||
|
weight: CORE_WEIGHT,
|
||||||
|
kbExpr: EditorContextKeys.textInputFocus,
|
||||||
|
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z
|
||||||
|
},
|
||||||
|
menuOpts: [{
|
||||||
|
menuId: MenuId.MenubarEditMenu,
|
||||||
|
group: '1_do',
|
||||||
|
title: nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"),
|
||||||
|
order: 1
|
||||||
|
}, {
|
||||||
|
menuId: MenuId.CommandPalette,
|
||||||
|
group: '',
|
||||||
|
title: nls.localize('undo', "Undo"),
|
||||||
|
order: 1
|
||||||
|
}]
|
||||||
|
}));
|
||||||
|
|
||||||
function registerCommand(command: Command) {
|
export const DefaultUndo: UndoCommand = registerCommand(new UndoCommand({ id: 'default:undo', precondition: EditorContextKeys.writable }));
|
||||||
command.register();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
export const Redo: RedoCommand = registerCommand(new RedoCommand({
|
||||||
* A command that will:
|
id: 'redo',
|
||||||
* 1. invoke a command on the focused editor.
|
precondition: EditorContextKeys.writable,
|
||||||
* 2. otherwise, invoke a browser built-in command on the `activeElement`.
|
kbOpts: {
|
||||||
* 3. otherwise, invoke a command on the workbench active editor.
|
weight: CORE_WEIGHT,
|
||||||
*/
|
kbExpr: EditorContextKeys.textInputFocus,
|
||||||
class EditorOrNativeTextInputCommand extends Command {
|
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
|
||||||
|
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
|
||||||
|
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }
|
||||||
|
},
|
||||||
|
menuOpts: [{
|
||||||
|
menuId: MenuId.MenubarEditMenu,
|
||||||
|
group: '1_do',
|
||||||
|
title: nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"),
|
||||||
|
order: 2
|
||||||
|
}, {
|
||||||
|
menuId: MenuId.CommandPalette,
|
||||||
|
group: '',
|
||||||
|
title: nls.localize('redo', "Redo"),
|
||||||
|
order: 1
|
||||||
|
}]
|
||||||
|
}));
|
||||||
|
|
||||||
private readonly _editorHandler: string | EditorCommand;
|
export const DefaultRedo: RedoCommand = registerCommand(new RedoCommand({ id: 'default:redo', precondition: EditorContextKeys.writable }));
|
||||||
private readonly _inputHandler: string;
|
|
||||||
|
|
||||||
constructor(opts: ICommandOptions & { editorHandler: string | EditorCommand; inputHandler: string; }) {
|
|
||||||
super(opts);
|
|
||||||
this._editorHandler = opts.editorHandler;
|
|
||||||
this._inputHandler = opts.inputHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public runCommand(accessor: ServicesAccessor, args: any): void {
|
|
||||||
|
|
||||||
const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
|
|
||||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
|
||||||
if (focusedEditor && focusedEditor.hasTextFocus()) {
|
|
||||||
return this._runEditorHandler(accessor, focusedEditor, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore this action when user is focused on an element that allows for entering text
|
|
||||||
const activeElement = <HTMLElement>document.activeElement;
|
|
||||||
if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) {
|
|
||||||
document.execCommand(this._inputHandler);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redirecting to active editor
|
|
||||||
const activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor();
|
|
||||||
if (activeEditor) {
|
|
||||||
activeEditor.focus();
|
|
||||||
return this._runEditorHandler(accessor, activeEditor, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _runEditorHandler(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
|
|
||||||
const HANDLER = this._editorHandler;
|
|
||||||
if (typeof HANDLER === 'string') {
|
|
||||||
editor.trigger('keyboard', HANDLER, args);
|
|
||||||
} else {
|
|
||||||
args = args || {};
|
|
||||||
args.source = 'keyboard';
|
|
||||||
HANDLER.runEditorCommand(accessor, editor, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1743,78 +1831,7 @@ class EditorHandlerCommand extends Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registerCommand(new EditorOrNativeTextInputCommand({
|
registerCommand(new SelectAllCommand());
|
||||||
editorHandler: CoreNavigationCommands.SelectAll,
|
|
||||||
inputHandler: 'selectAll',
|
|
||||||
id: 'editor.action.selectAll',
|
|
||||||
precondition: EditorContextKeys.textInputFocus,
|
|
||||||
kbOpts: {
|
|
||||||
weight: CORE_WEIGHT,
|
|
||||||
kbExpr: null,
|
|
||||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_A
|
|
||||||
},
|
|
||||||
menuOpts: [{
|
|
||||||
menuId: MenuId.MenubarEditMenu, // {{SQL CARBON EDIT}} - Put this in the edit menu since we disabled the selection menu
|
|
||||||
group: '4_find_global', // {{SQL CARBON EDIT}} - Put this in the edit menu since we disabled the selection menu
|
|
||||||
title: nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"),
|
|
||||||
order: 1
|
|
||||||
}, {
|
|
||||||
menuId: MenuId.CommandPalette,
|
|
||||||
group: '',
|
|
||||||
title: nls.localize('selectAll', "Select All"),
|
|
||||||
order: 1
|
|
||||||
}]
|
|
||||||
}));
|
|
||||||
|
|
||||||
registerCommand(new EditorOrNativeTextInputCommand({
|
|
||||||
editorHandler: Handler.Undo,
|
|
||||||
inputHandler: 'undo',
|
|
||||||
id: Handler.Undo,
|
|
||||||
precondition: EditorContextKeys.writable,
|
|
||||||
kbOpts: {
|
|
||||||
weight: CORE_WEIGHT,
|
|
||||||
kbExpr: EditorContextKeys.textInputFocus,
|
|
||||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z
|
|
||||||
},
|
|
||||||
menuOpts: [{
|
|
||||||
menuId: MenuId.MenubarEditMenu,
|
|
||||||
group: '1_do',
|
|
||||||
title: nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"),
|
|
||||||
order: 1
|
|
||||||
}, {
|
|
||||||
menuId: MenuId.CommandPalette,
|
|
||||||
group: '',
|
|
||||||
title: nls.localize('undo', "Undo"),
|
|
||||||
order: 1
|
|
||||||
}]
|
|
||||||
}));
|
|
||||||
registerCommand(new EditorHandlerCommand('default:' + Handler.Undo, Handler.Undo));
|
|
||||||
|
|
||||||
registerCommand(new EditorOrNativeTextInputCommand({
|
|
||||||
editorHandler: Handler.Redo,
|
|
||||||
inputHandler: 'redo',
|
|
||||||
id: Handler.Redo,
|
|
||||||
precondition: EditorContextKeys.writable,
|
|
||||||
kbOpts: {
|
|
||||||
weight: CORE_WEIGHT,
|
|
||||||
kbExpr: EditorContextKeys.textInputFocus,
|
|
||||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
|
|
||||||
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
|
|
||||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }
|
|
||||||
},
|
|
||||||
menuOpts: [{
|
|
||||||
menuId: MenuId.MenubarEditMenu,
|
|
||||||
group: '1_do',
|
|
||||||
title: nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"),
|
|
||||||
order: 2
|
|
||||||
}, {
|
|
||||||
menuId: MenuId.CommandPalette,
|
|
||||||
group: '',
|
|
||||||
title: nls.localize('redo', "Redo"),
|
|
||||||
order: 1
|
|
||||||
}]
|
|
||||||
}));
|
|
||||||
registerCommand(new EditorHandlerCommand('default:' + Handler.Redo, Handler.Redo));
|
|
||||||
|
|
||||||
function registerOverwritableCommand(handlerId: string, description?: ICommandHandlerDescription): void {
|
function registerOverwritableCommand(handlerId: string, description?: ICommandHandlerDescription): void {
|
||||||
registerCommand(new EditorHandlerCommand('default:' + handlerId, handlerId));
|
registerCommand(new EditorHandlerCommand('default:' + handlerId, handlerId));
|
||||||
|
|||||||
@@ -589,14 +589,19 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
|
|||||||
if (boxEndY - boxStartY > viewportHeight) {
|
if (boxEndY - boxStartY > viewportHeight) {
|
||||||
// the box is larger than the viewport ... scroll to its top
|
// the box is larger than the viewport ... scroll to its top
|
||||||
newScrollTop = boxStartY;
|
newScrollTop = boxStartY;
|
||||||
} else if (verticalType === viewEvents.VerticalRevealType.NearTop) {
|
} else if (verticalType === viewEvents.VerticalRevealType.NearTop || verticalType === viewEvents.VerticalRevealType.NearTopIfOutsideViewport) {
|
||||||
// We want a gap that is 20% of the viewport, but with a minimum of 5 lines
|
if (verticalType === viewEvents.VerticalRevealType.NearTopIfOutsideViewport && viewportStartY <= boxStartY && boxEndY <= viewportEndY) {
|
||||||
const desiredGapAbove = Math.max(5 * this._lineHeight, viewportHeight * 0.2);
|
// Box is already in the viewport... do nothing
|
||||||
// Try to scroll just above the box with the desired gap
|
newScrollTop = viewportStartY;
|
||||||
const desiredScrollTop = boxStartY - desiredGapAbove;
|
} else {
|
||||||
// But ensure that the box is not pushed out of viewport
|
// We want a gap that is 20% of the viewport, but with a minimum of 5 lines
|
||||||
const minScrollTop = boxEndY - viewportHeight;
|
const desiredGapAbove = Math.max(5 * this._lineHeight, viewportHeight * 0.2);
|
||||||
newScrollTop = Math.max(minScrollTop, desiredScrollTop);
|
// Try to scroll just above the box with the desired gap
|
||||||
|
const desiredScrollTop = boxStartY - desiredGapAbove;
|
||||||
|
// But ensure that the box is not pushed out of viewport
|
||||||
|
const minScrollTop = boxEndY - viewportHeight;
|
||||||
|
newScrollTop = Math.max(minScrollTop, desiredScrollTop);
|
||||||
|
}
|
||||||
} else if (verticalType === viewEvents.VerticalRevealType.Center || verticalType === viewEvents.VerticalRevealType.CenterIfOutsideViewport) {
|
} else if (verticalType === viewEvents.VerticalRevealType.Center || verticalType === viewEvents.VerticalRevealType.CenterIfOutsideViewport) {
|
||||||
if (verticalType === viewEvents.VerticalRevealType.CenterIfOutsideViewport && viewportStartY <= boxStartY && boxEndY <= viewportEndY) {
|
if (verticalType === viewEvents.VerticalRevealType.CenterIfOutsideViewport && viewportStartY <= boxStartY && boxEndY <= viewportEndY) {
|
||||||
// Box is already in the viewport... do nothing
|
// Box is already in the viewport... do nothing
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import * as platform from 'vs/base/common/platform';
|
|||||||
import * as strings from 'vs/base/common/strings';
|
import * as strings from 'vs/base/common/strings';
|
||||||
import { ILine, RenderedLinesCollection } from 'vs/editor/browser/view/viewLayer';
|
import { ILine, RenderedLinesCollection } from 'vs/editor/browser/view/viewLayer';
|
||||||
import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart';
|
import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart';
|
||||||
import { RenderMinimap, EditorOption, MINIMAP_GUTTER_WIDTH, EditorLayoutInfoComputer, IComputedEditorOptions } from 'vs/editor/common/config/editorOptions';
|
import { RenderMinimap, EditorOption, MINIMAP_GUTTER_WIDTH, EditorLayoutInfoComputer } from 'vs/editor/common/config/editorOptions';
|
||||||
import { Range } from 'vs/editor/common/core/range';
|
import { Range } from 'vs/editor/common/core/range';
|
||||||
import { RGBA8 } from 'vs/editor/common/core/rgba';
|
import { RGBA8 } from 'vs/editor/common/core/rgba';
|
||||||
import { IConfiguration, ScrollType } from 'vs/editor/common/editorCommon';
|
import { IConfiguration, ScrollType } from 'vs/editor/common/editorCommon';
|
||||||
@@ -91,6 +91,8 @@ class MinimapOptions {
|
|||||||
*/
|
*/
|
||||||
public readonly canvasOuterHeight: number;
|
public readonly canvasOuterHeight: number;
|
||||||
|
|
||||||
|
public readonly isSampling: boolean;
|
||||||
|
public readonly editorHeight: number;
|
||||||
public readonly fontScale: number;
|
public readonly fontScale: number;
|
||||||
public readonly minimapLineHeight: number;
|
public readonly minimapLineHeight: number;
|
||||||
public readonly minimapCharWidth: number;
|
public readonly minimapCharWidth: number;
|
||||||
@@ -122,6 +124,8 @@ class MinimapOptions {
|
|||||||
this.canvasOuterWidth = layoutInfo.minimapCanvasOuterWidth;
|
this.canvasOuterWidth = layoutInfo.minimapCanvasOuterWidth;
|
||||||
this.canvasOuterHeight = layoutInfo.minimapCanvasOuterHeight;
|
this.canvasOuterHeight = layoutInfo.minimapCanvasOuterHeight;
|
||||||
|
|
||||||
|
this.isSampling = layoutInfo.minimapIsSampling;
|
||||||
|
this.editorHeight = layoutInfo.height;
|
||||||
this.fontScale = layoutInfo.minimapScale;
|
this.fontScale = layoutInfo.minimapScale;
|
||||||
this.minimapLineHeight = layoutInfo.minimapLineHeight;
|
this.minimapLineHeight = layoutInfo.minimapLineHeight;
|
||||||
this.minimapCharWidth = Constants.BASE_CHAR_WIDTH * this.fontScale;
|
this.minimapCharWidth = Constants.BASE_CHAR_WIDTH * this.fontScale;
|
||||||
@@ -154,6 +158,8 @@ class MinimapOptions {
|
|||||||
&& this.canvasInnerHeight === other.canvasInnerHeight
|
&& this.canvasInnerHeight === other.canvasInnerHeight
|
||||||
&& this.canvasOuterWidth === other.canvasOuterWidth
|
&& this.canvasOuterWidth === other.canvasOuterWidth
|
||||||
&& this.canvasOuterHeight === other.canvasOuterHeight
|
&& this.canvasOuterHeight === other.canvasOuterHeight
|
||||||
|
&& this.isSampling === other.isSampling
|
||||||
|
&& this.editorHeight === other.editorHeight
|
||||||
&& this.fontScale === other.fontScale
|
&& this.fontScale === other.fontScale
|
||||||
&& this.minimapLineHeight === other.minimapLineHeight
|
&& this.minimapLineHeight === other.minimapLineHeight
|
||||||
&& this.minimapCharWidth === other.minimapCharWidth
|
&& this.minimapCharWidth === other.minimapCharWidth
|
||||||
@@ -527,26 +533,24 @@ type SamplingStateEvent = SamplingStateLinesInsertedEvent | SamplingStateLinesDe
|
|||||||
|
|
||||||
class MinimapSamplingState {
|
class MinimapSamplingState {
|
||||||
|
|
||||||
public static compute(options: IComputedEditorOptions, modelLineCount: number, oldSamplingState: MinimapSamplingState | null): [MinimapSamplingState | null, SamplingStateEvent[]] {
|
public static compute(options: MinimapOptions, viewLineCount: number, oldSamplingState: MinimapSamplingState | null): [MinimapSamplingState | null, SamplingStateEvent[]] {
|
||||||
const minimapOpts = options.get(EditorOption.minimap);
|
if (options.renderMinimap === RenderMinimap.None || !options.isSampling) {
|
||||||
const layoutInfo = options.get(EditorOption.layoutInfo);
|
|
||||||
if (!minimapOpts.enabled || !layoutInfo.minimapIsSampling) {
|
|
||||||
return [null, []];
|
return [null, []];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ratio is intentionally not part of the layout to avoid the layout changing all the time
|
// ratio is intentionally not part of the layout to avoid the layout changing all the time
|
||||||
// so we need to recompute it again...
|
// so we need to recompute it again...
|
||||||
const pixelRatio = options.get(EditorOption.pixelRatio);
|
const pixelRatio = options.pixelRatio;
|
||||||
const lineHeight = options.get(EditorOption.lineHeight);
|
const lineHeight = options.lineHeight;
|
||||||
const scrollBeyondLastLine = options.get(EditorOption.scrollBeyondLastLine);
|
const scrollBeyondLastLine = options.scrollBeyondLastLine;
|
||||||
const { minimapLineCount } = EditorLayoutInfoComputer.computeContainedMinimapLineCount({
|
const { minimapLineCount } = EditorLayoutInfoComputer.computeContainedMinimapLineCount({
|
||||||
modelLineCount: modelLineCount,
|
viewLineCount: viewLineCount,
|
||||||
scrollBeyondLastLine: scrollBeyondLastLine,
|
scrollBeyondLastLine: scrollBeyondLastLine,
|
||||||
height: layoutInfo.height,
|
height: options.editorHeight,
|
||||||
lineHeight: lineHeight,
|
lineHeight: lineHeight,
|
||||||
pixelRatio: pixelRatio
|
pixelRatio: pixelRatio
|
||||||
});
|
});
|
||||||
const ratio = modelLineCount / minimapLineCount;
|
const ratio = viewLineCount / minimapLineCount;
|
||||||
const halfRatio = ratio / 2;
|
const halfRatio = ratio / 2;
|
||||||
|
|
||||||
if (!oldSamplingState || oldSamplingState.minimapLines.length === 0) {
|
if (!oldSamplingState || oldSamplingState.minimapLines.length === 0) {
|
||||||
@@ -556,7 +560,7 @@ class MinimapSamplingState {
|
|||||||
for (let i = 0, lastIndex = minimapLineCount - 1; i < lastIndex; i++) {
|
for (let i = 0, lastIndex = minimapLineCount - 1; i < lastIndex; i++) {
|
||||||
result[i] = Math.round(i * ratio + halfRatio);
|
result[i] = Math.round(i * ratio + halfRatio);
|
||||||
}
|
}
|
||||||
result[minimapLineCount - 1] = modelLineCount;
|
result[minimapLineCount - 1] = viewLineCount;
|
||||||
}
|
}
|
||||||
return [new MinimapSamplingState(ratio, result), []];
|
return [new MinimapSamplingState(ratio, result), []];
|
||||||
}
|
}
|
||||||
@@ -566,15 +570,15 @@ class MinimapSamplingState {
|
|||||||
let result: number[] = [];
|
let result: number[] = [];
|
||||||
let oldIndex = 0;
|
let oldIndex = 0;
|
||||||
let oldDeltaLineCount = 0;
|
let oldDeltaLineCount = 0;
|
||||||
let minModelLineNumber = 1;
|
let minViewLineNumber = 1;
|
||||||
const MAX_EVENT_COUNT = 10; // generate at most 10 events, if there are more than 10 changes, just flush all previous data
|
const MAX_EVENT_COUNT = 10; // generate at most 10 events, if there are more than 10 changes, just flush all previous data
|
||||||
let events: SamplingStateEvent[] = [];
|
let events: SamplingStateEvent[] = [];
|
||||||
let lastEvent: SamplingStateEvent | null = null;
|
let lastEvent: SamplingStateEvent | null = null;
|
||||||
for (let i = 0; i < minimapLineCount; i++) {
|
for (let i = 0; i < minimapLineCount; i++) {
|
||||||
const fromModelLineNumber = Math.max(minModelLineNumber, Math.round(i * ratio));
|
const fromViewLineNumber = Math.max(minViewLineNumber, Math.round(i * ratio));
|
||||||
const toModelLineNumber = Math.max(fromModelLineNumber, Math.round((i + 1) * ratio));
|
const toViewLineNumber = Math.max(fromViewLineNumber, Math.round((i + 1) * ratio));
|
||||||
|
|
||||||
while (oldIndex < oldLength && oldMinimapLines[oldIndex] < fromModelLineNumber) {
|
while (oldIndex < oldLength && oldMinimapLines[oldIndex] < fromViewLineNumber) {
|
||||||
if (events.length < MAX_EVENT_COUNT) {
|
if (events.length < MAX_EVENT_COUNT) {
|
||||||
const oldMinimapLineNumber = oldIndex + 1 + oldDeltaLineCount;
|
const oldMinimapLineNumber = oldIndex + 1 + oldDeltaLineCount;
|
||||||
if (lastEvent && lastEvent.type === 'deleted' && lastEvent._oldIndex === oldIndex - 1) {
|
if (lastEvent && lastEvent.type === 'deleted' && lastEvent._oldIndex === oldIndex - 1) {
|
||||||
@@ -588,18 +592,18 @@ class MinimapSamplingState {
|
|||||||
oldIndex++;
|
oldIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
let selectedModelLineNumber: number;
|
let selectedViewLineNumber: number;
|
||||||
if (oldIndex < oldLength && oldMinimapLines[oldIndex] <= toModelLineNumber) {
|
if (oldIndex < oldLength && oldMinimapLines[oldIndex] <= toViewLineNumber) {
|
||||||
// reuse the old sampled line
|
// reuse the old sampled line
|
||||||
selectedModelLineNumber = oldMinimapLines[oldIndex];
|
selectedViewLineNumber = oldMinimapLines[oldIndex];
|
||||||
oldIndex++;
|
oldIndex++;
|
||||||
} else {
|
} else {
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
selectedModelLineNumber = 1;
|
selectedViewLineNumber = 1;
|
||||||
} else if (i + 1 === minimapLineCount) {
|
} else if (i + 1 === minimapLineCount) {
|
||||||
selectedModelLineNumber = modelLineCount;
|
selectedViewLineNumber = viewLineCount;
|
||||||
} else {
|
} else {
|
||||||
selectedModelLineNumber = Math.round(i * ratio + halfRatio);
|
selectedViewLineNumber = Math.round(i * ratio + halfRatio);
|
||||||
}
|
}
|
||||||
if (events.length < MAX_EVENT_COUNT) {
|
if (events.length < MAX_EVENT_COUNT) {
|
||||||
const oldMinimapLineNumber = oldIndex + 1 + oldDeltaLineCount;
|
const oldMinimapLineNumber = oldIndex + 1 + oldDeltaLineCount;
|
||||||
@@ -613,8 +617,8 @@ class MinimapSamplingState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result[i] = selectedModelLineNumber;
|
result[i] = selectedViewLineNumber;
|
||||||
minModelLineNumber = selectedModelLineNumber;
|
minViewLineNumber = selectedViewLineNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (events.length < MAX_EVENT_COUNT) {
|
if (events.length < MAX_EVENT_COUNT) {
|
||||||
@@ -743,7 +747,7 @@ export class Minimap extends ViewPart implements IMinimapModel {
|
|||||||
this._minimapSelections = null;
|
this._minimapSelections = null;
|
||||||
|
|
||||||
this.options = new MinimapOptions(this._context.configuration, this._context.theme, this.tokensColorTracker);
|
this.options = new MinimapOptions(this._context.configuration, this._context.theme, this.tokensColorTracker);
|
||||||
const [samplingState,] = MinimapSamplingState.compute(this._context.configuration.options, this._context.model.getLineCount(), null);
|
const [samplingState,] = MinimapSamplingState.compute(this.options, this._context.model.getLineCount(), null);
|
||||||
this._samplingState = samplingState;
|
this._samplingState = samplingState;
|
||||||
this._shouldCheckSampling = false;
|
this._shouldCheckSampling = false;
|
||||||
|
|
||||||
@@ -787,6 +791,9 @@ export class Minimap extends ViewPart implements IMinimapModel {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public onFlushed(e: viewEvents.ViewFlushedEvent): boolean {
|
public onFlushed(e: viewEvents.ViewFlushedEvent): boolean {
|
||||||
|
if (this._samplingState) {
|
||||||
|
this._shouldCheckSampling = true;
|
||||||
|
}
|
||||||
return this._actual.onFlushed();
|
return this._actual.onFlushed();
|
||||||
}
|
}
|
||||||
public onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {
|
public onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {
|
||||||
@@ -898,7 +905,7 @@ export class Minimap extends ViewPart implements IMinimapModel {
|
|||||||
this._minimapSelections = null;
|
this._minimapSelections = null;
|
||||||
|
|
||||||
const wasSampling = Boolean(this._samplingState);
|
const wasSampling = Boolean(this._samplingState);
|
||||||
const [samplingState, events] = MinimapSamplingState.compute(this._context.configuration.options, this._context.model.getLineCount(), this._samplingState);
|
const [samplingState, events] = MinimapSamplingState.compute(this.options, this._context.model.getLineCount(), this._samplingState);
|
||||||
this._samplingState = samplingState;
|
this._samplingState = samplingState;
|
||||||
|
|
||||||
if (wasSampling && this._samplingState) {
|
if (wasSampling && this._samplingState) {
|
||||||
|
|||||||
@@ -756,6 +756,15 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public revealRangeNearTopIfOutsideViewport(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
|
||||||
|
this._revealRange(
|
||||||
|
range,
|
||||||
|
VerticalRevealType.NearTopIfOutsideViewport,
|
||||||
|
true,
|
||||||
|
scrollType
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public revealRangeAtTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
|
public revealRangeAtTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
|
||||||
this._revealRange(
|
this._revealRange(
|
||||||
range,
|
range,
|
||||||
@@ -1534,11 +1543,18 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onDidChangeTextFocus = (textFocus: boolean) => {
|
||||||
|
if (this._modelData) {
|
||||||
|
this._modelData.cursor.setHasFocus(textFocus);
|
||||||
|
}
|
||||||
|
this._editorTextFocus.setValue(textFocus);
|
||||||
|
};
|
||||||
|
|
||||||
const viewOutgoingEvents = new ViewOutgoingEvents(viewModel);
|
const viewOutgoingEvents = new ViewOutgoingEvents(viewModel);
|
||||||
viewOutgoingEvents.onDidContentSizeChange = (e) => this._onDidContentSizeChange.fire(e);
|
viewOutgoingEvents.onDidContentSizeChange = (e) => this._onDidContentSizeChange.fire(e);
|
||||||
viewOutgoingEvents.onDidScroll = (e) => this._onDidScrollChange.fire(e);
|
viewOutgoingEvents.onDidScroll = (e) => this._onDidScrollChange.fire(e);
|
||||||
viewOutgoingEvents.onDidGainFocus = () => this._editorTextFocus.setValue(true);
|
viewOutgoingEvents.onDidGainFocus = () => onDidChangeTextFocus(true);
|
||||||
viewOutgoingEvents.onDidLoseFocus = () => this._editorTextFocus.setValue(false);
|
viewOutgoingEvents.onDidLoseFocus = () => onDidChangeTextFocus(false);
|
||||||
viewOutgoingEvents.onContextMenu = (e) => this._onContextMenu.fire(e);
|
viewOutgoingEvents.onContextMenu = (e) => this._onContextMenu.fire(e);
|
||||||
viewOutgoingEvents.onMouseDown = (e) => this._onMouseDown.fire(e);
|
viewOutgoingEvents.onMouseDown = (e) => this._onMouseDown.fire(e);
|
||||||
viewOutgoingEvents.onMouseUp = (e) => this._onMouseUp.fire(e);
|
viewOutgoingEvents.onMouseUp = (e) => this._onMouseUp.fire(e);
|
||||||
@@ -1579,7 +1595,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||||||
this._modelData = null;
|
this._modelData = null;
|
||||||
|
|
||||||
this._domElement.removeAttribute('data-mode-id');
|
this._domElement.removeAttribute('data-mode-id');
|
||||||
if (removeDomNode) {
|
if (removeDomNode && this._domElement.contains(removeDomNode)) {
|
||||||
this._domElement.removeChild(removeDomNode);
|
this._domElement.removeChild(removeDomNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -830,6 +830,10 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
|||||||
this.modifiedEditor.revealRangeNearTop(range, scrollType);
|
this.modifiedEditor.revealRangeNearTop(range, scrollType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public revealRangeNearTopIfOutsideViewport(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
|
||||||
|
this.modifiedEditor.revealRangeNearTopIfOutsideViewport(range, scrollType);
|
||||||
|
}
|
||||||
|
|
||||||
public revealRangeAtTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
|
public revealRangeAtTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
|
||||||
this.modifiedEditor.revealRangeAtTop(range, scrollType);
|
this.modifiedEditor.revealRangeAtTop(range, scrollType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
|
|||||||
public options!: ComputedEditorOptions;
|
public options!: ComputedEditorOptions;
|
||||||
|
|
||||||
private _isDominatedByLongLines: boolean;
|
private _isDominatedByLongLines: boolean;
|
||||||
private _maxLineNumber: number;
|
private _viewLineCount: number;
|
||||||
private _lineNumbersDigitCount: number;
|
private _lineNumbersDigitCount: number;
|
||||||
|
|
||||||
private _rawOptions: IEditorOptions;
|
private _rawOptions: IEditorOptions;
|
||||||
@@ -299,7 +299,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
|
|||||||
this.isSimpleWidget = isSimpleWidget;
|
this.isSimpleWidget = isSimpleWidget;
|
||||||
|
|
||||||
this._isDominatedByLongLines = false;
|
this._isDominatedByLongLines = false;
|
||||||
this._maxLineNumber = 1;
|
this._viewLineCount = 1;
|
||||||
this._lineNumbersDigitCount = 1;
|
this._lineNumbersDigitCount = 1;
|
||||||
|
|
||||||
this._rawOptions = deepCloneAndMigrateOptions(_options);
|
this._rawOptions = deepCloneAndMigrateOptions(_options);
|
||||||
@@ -349,7 +349,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
|
|||||||
fontInfo: this.readConfiguration(bareFontInfo),
|
fontInfo: this.readConfiguration(bareFontInfo),
|
||||||
extraEditorClassName: partialEnv.extraEditorClassName,
|
extraEditorClassName: partialEnv.extraEditorClassName,
|
||||||
isDominatedByLongLines: this._isDominatedByLongLines,
|
isDominatedByLongLines: this._isDominatedByLongLines,
|
||||||
maxLineNumber: this._maxLineNumber,
|
viewLineCount: this._viewLineCount,
|
||||||
lineNumbersDigitCount: this._lineNumbersDigitCount,
|
lineNumbersDigitCount: this._lineNumbersDigitCount,
|
||||||
emptySelectionClipboard: partialEnv.emptySelectionClipboard,
|
emptySelectionClipboard: partialEnv.emptySelectionClipboard,
|
||||||
pixelRatio: partialEnv.pixelRatio,
|
pixelRatio: partialEnv.pixelRatio,
|
||||||
@@ -408,11 +408,19 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
|
|||||||
}
|
}
|
||||||
|
|
||||||
public setMaxLineNumber(maxLineNumber: number): void {
|
public setMaxLineNumber(maxLineNumber: number): void {
|
||||||
if (this._maxLineNumber === maxLineNumber) {
|
const lineNumbersDigitCount = CommonEditorConfiguration._digitCount(maxLineNumber);
|
||||||
|
if (this._lineNumbersDigitCount === lineNumbersDigitCount) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._maxLineNumber = maxLineNumber;
|
this._lineNumbersDigitCount = lineNumbersDigitCount;
|
||||||
this._lineNumbersDigitCount = CommonEditorConfiguration._digitCount(maxLineNumber);
|
this._recomputeOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public setViewLineCount(viewLineCount: number): void {
|
||||||
|
if (this._viewLineCount === viewLineCount) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._viewLineCount = viewLineCount;
|
||||||
this._recomputeOptions();
|
this._recomputeOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -678,7 +678,7 @@ export interface IEnvironmentalOptions {
|
|||||||
readonly fontInfo: FontInfo;
|
readonly fontInfo: FontInfo;
|
||||||
readonly extraEditorClassName: string;
|
readonly extraEditorClassName: string;
|
||||||
readonly isDominatedByLongLines: boolean;
|
readonly isDominatedByLongLines: boolean;
|
||||||
readonly maxLineNumber: number;
|
readonly viewLineCount: number;
|
||||||
readonly lineNumbersDigitCount: number;
|
readonly lineNumbersDigitCount: number;
|
||||||
readonly emptySelectionClipboard: boolean;
|
readonly emptySelectionClipboard: boolean;
|
||||||
readonly pixelRatio: number;
|
readonly pixelRatio: number;
|
||||||
@@ -1733,7 +1733,7 @@ export interface EditorLayoutInfoComputerEnv {
|
|||||||
outerWidth: number;
|
outerWidth: number;
|
||||||
outerHeight: number;
|
outerHeight: number;
|
||||||
lineHeight: number;
|
lineHeight: number;
|
||||||
maxLineNumber: number;
|
viewLineCount: number;
|
||||||
lineNumbersDigitCount: number;
|
lineNumbersDigitCount: number;
|
||||||
typicalHalfwidthCharacterWidth: number;
|
typicalHalfwidthCharacterWidth: number;
|
||||||
maxDigitWidth: number;
|
maxDigitWidth: number;
|
||||||
@@ -1757,7 +1757,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
|
|||||||
outerWidth: env.outerWidth,
|
outerWidth: env.outerWidth,
|
||||||
outerHeight: env.outerHeight,
|
outerHeight: env.outerHeight,
|
||||||
lineHeight: env.fontInfo.lineHeight,
|
lineHeight: env.fontInfo.lineHeight,
|
||||||
maxLineNumber: env.maxLineNumber,
|
viewLineCount: env.viewLineCount,
|
||||||
lineNumbersDigitCount: env.lineNumbersDigitCount,
|
lineNumbersDigitCount: env.lineNumbersDigitCount,
|
||||||
typicalHalfwidthCharacterWidth: env.fontInfo.typicalHalfwidthCharacterWidth,
|
typicalHalfwidthCharacterWidth: env.fontInfo.typicalHalfwidthCharacterWidth,
|
||||||
maxDigitWidth: env.fontInfo.maxDigitWidth,
|
maxDigitWidth: env.fontInfo.maxDigitWidth,
|
||||||
@@ -1766,7 +1766,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static computeContainedMinimapLineCount(input: {
|
public static computeContainedMinimapLineCount(input: {
|
||||||
modelLineCount: number;
|
viewLineCount: number;
|
||||||
scrollBeyondLastLine: boolean;
|
scrollBeyondLastLine: boolean;
|
||||||
height: number;
|
height: number;
|
||||||
lineHeight: number;
|
lineHeight: number;
|
||||||
@@ -1774,8 +1774,8 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
|
|||||||
}): { typicalViewportLineCount: number; extraLinesBeyondLastLine: number; desiredRatio: number; minimapLineCount: number; } {
|
}): { typicalViewportLineCount: number; extraLinesBeyondLastLine: number; desiredRatio: number; minimapLineCount: number; } {
|
||||||
const typicalViewportLineCount = input.height / input.lineHeight;
|
const typicalViewportLineCount = input.height / input.lineHeight;
|
||||||
const extraLinesBeyondLastLine = input.scrollBeyondLastLine ? (typicalViewportLineCount - 1) : 0;
|
const extraLinesBeyondLastLine = input.scrollBeyondLastLine ? (typicalViewportLineCount - 1) : 0;
|
||||||
const desiredRatio = (input.modelLineCount + extraLinesBeyondLastLine) / (input.pixelRatio * input.height);
|
const desiredRatio = (input.viewLineCount + extraLinesBeyondLastLine) / (input.pixelRatio * input.height);
|
||||||
const minimapLineCount = Math.floor(input.modelLineCount / desiredRatio);
|
const minimapLineCount = Math.floor(input.viewLineCount / desiredRatio);
|
||||||
return { typicalViewportLineCount, extraLinesBeyondLastLine, desiredRatio, minimapLineCount };
|
return { typicalViewportLineCount, extraLinesBeyondLastLine, desiredRatio, minimapLineCount };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1863,9 +1863,9 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
|
|||||||
let minimapWidthMultiplier: number = 1;
|
let minimapWidthMultiplier: number = 1;
|
||||||
|
|
||||||
if (minimapMode === 'cover' || minimapMode === 'contain') {
|
if (minimapMode === 'cover' || minimapMode === 'contain') {
|
||||||
const modelLineCount = env.maxLineNumber;
|
const viewLineCount = env.viewLineCount;
|
||||||
const { typicalViewportLineCount, extraLinesBeyondLastLine, desiredRatio, minimapLineCount } = EditorLayoutInfoComputer.computeContainedMinimapLineCount({
|
const { typicalViewportLineCount, extraLinesBeyondLastLine, desiredRatio, minimapLineCount } = EditorLayoutInfoComputer.computeContainedMinimapLineCount({
|
||||||
modelLineCount: modelLineCount,
|
viewLineCount: viewLineCount,
|
||||||
scrollBeyondLastLine: scrollBeyondLastLine,
|
scrollBeyondLastLine: scrollBeyondLastLine,
|
||||||
height: outerHeight,
|
height: outerHeight,
|
||||||
lineHeight: lineHeight,
|
lineHeight: lineHeight,
|
||||||
@@ -1873,7 +1873,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
|
|||||||
});
|
});
|
||||||
// ratio is intentionally not part of the layout to avoid the layout changing all the time
|
// ratio is intentionally not part of the layout to avoid the layout changing all the time
|
||||||
// when doing sampling
|
// when doing sampling
|
||||||
const ratio = modelLineCount / minimapLineCount;
|
const ratio = viewLineCount / minimapLineCount;
|
||||||
|
|
||||||
if (ratio > 1) {
|
if (ratio > 1) {
|
||||||
minimapHeightIsEditorHeight = true;
|
minimapHeightIsEditorHeight = true;
|
||||||
@@ -1882,7 +1882,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
|
|||||||
minimapLineHeight = 1;
|
minimapLineHeight = 1;
|
||||||
minimapCharWidth = minimapScale / pixelRatio;
|
minimapCharWidth = minimapScale / pixelRatio;
|
||||||
} else {
|
} else {
|
||||||
const effectiveMinimapHeight = Math.ceil((modelLineCount + extraLinesBeyondLastLine) * minimapLineHeight);
|
const effectiveMinimapHeight = Math.ceil((viewLineCount + extraLinesBeyondLastLine) * minimapLineHeight);
|
||||||
if (minimapMode === 'cover' || effectiveMinimapHeight > minimapCanvasInnerHeight) {
|
if (minimapMode === 'cover' || effectiveMinimapHeight > minimapCanvasInnerHeight) {
|
||||||
minimapHeightIsEditorHeight = true;
|
minimapHeightIsEditorHeight = true;
|
||||||
const configuredFontScale = minimapScale;
|
const configuredFontScale = minimapScale;
|
||||||
@@ -1892,7 +1892,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
|
|||||||
minimapWidthMultiplier = Math.min(2, minimapScale / configuredFontScale);
|
minimapWidthMultiplier = Math.min(2, minimapScale / configuredFontScale);
|
||||||
}
|
}
|
||||||
minimapCharWidth = minimapScale / pixelRatio / minimapWidthMultiplier;
|
minimapCharWidth = minimapScale / pixelRatio / minimapWidthMultiplier;
|
||||||
minimapCanvasInnerHeight = Math.ceil((Math.max(typicalViewportLineCount, modelLineCount + extraLinesBeyondLastLine)) * minimapLineHeight);
|
minimapCanvasInnerHeight = Math.ceil((Math.max(typicalViewportLineCount, viewLineCount + extraLinesBeyondLastLine)) * minimapLineHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { Range, IRange } from 'vs/editor/common/core/range';
|
|||||||
import { ISelection, Selection, SelectionDirection } from 'vs/editor/common/core/selection';
|
import { ISelection, Selection, SelectionDirection } from 'vs/editor/common/core/selection';
|
||||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||||
import { ITextModel, TrackedRangeStickiness, IModelDeltaDecoration, ICursorStateComputer, IIdentifiedSingleEditOperation, IValidEditOperation } from 'vs/editor/common/model';
|
import { ITextModel, TrackedRangeStickiness, IModelDeltaDecoration, ICursorStateComputer, IIdentifiedSingleEditOperation, IValidEditOperation } from 'vs/editor/common/model';
|
||||||
import { RawContentChangedType } from 'vs/editor/common/model/textModelEvents';
|
import { RawContentChangedType, ModelRawContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||||
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||||
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
||||||
import { dispose } from 'vs/base/common/lifecycle';
|
import { dispose } from 'vs/base/common/lifecycle';
|
||||||
@@ -186,6 +186,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||||||
public context: CursorContext;
|
public context: CursorContext;
|
||||||
private _cursors: CursorCollection;
|
private _cursors: CursorCollection;
|
||||||
|
|
||||||
|
private _hasFocus: boolean;
|
||||||
private _isHandling: boolean;
|
private _isHandling: boolean;
|
||||||
private _isDoingComposition: boolean;
|
private _isDoingComposition: boolean;
|
||||||
private _selectionsWhenCompositionStarted: Selection[] | null;
|
private _selectionsWhenCompositionStarted: Selection[] | null;
|
||||||
@@ -202,6 +203,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||||||
this.context = new CursorContext(this._configuration, this._model, this._viewModel);
|
this.context = new CursorContext(this._configuration, this._model, this._viewModel);
|
||||||
this._cursors = new CursorCollection(this.context);
|
this._cursors = new CursorCollection(this.context);
|
||||||
|
|
||||||
|
this._hasFocus = false;
|
||||||
this._isHandling = false;
|
this._isHandling = false;
|
||||||
this._isDoingComposition = false;
|
this._isDoingComposition = false;
|
||||||
this._selectionsWhenCompositionStarted = null;
|
this._selectionsWhenCompositionStarted = null;
|
||||||
@@ -215,8 +217,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let hadFlushEvent = e.containsEvent(RawContentChangedType.Flush);
|
this._onModelContentChanged(e);
|
||||||
this._onModelContentChanged(hadFlushEvent);
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._register(viewModel.addEventListener((events: viewEvents.ViewEvent[]) => {
|
this._register(viewModel.addEventListener((events: viewEvents.ViewEvent[]) => {
|
||||||
@@ -264,6 +265,10 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setHasFocus(hasFocus: boolean): void {
|
||||||
|
this._hasFocus = hasFocus;
|
||||||
|
}
|
||||||
|
|
||||||
private _validateAutoClosedActions(): void {
|
private _validateAutoClosedActions(): void {
|
||||||
if (this._autoClosedActions.length > 0) {
|
if (this._autoClosedActions.length > 0) {
|
||||||
let selections: Range[] = this._cursors.getSelections();
|
let selections: Range[] = this._cursors.getSelections();
|
||||||
@@ -392,8 +397,9 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||||||
this.reveal('restoreState', true, RevealTarget.Primary, editorCommon.ScrollType.Immediate);
|
this.reveal('restoreState', true, RevealTarget.Primary, editorCommon.ScrollType.Immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onModelContentChanged(hadFlushEvent: boolean): void {
|
private _onModelContentChanged(e: ModelRawContentChangedEvent): void {
|
||||||
|
|
||||||
|
const hadFlushEvent = e.containsEvent(RawContentChangedType.Flush);
|
||||||
this._prevEditOperationType = EditOperationType.Other;
|
this._prevEditOperationType = EditOperationType.Other;
|
||||||
|
|
||||||
if (hadFlushEvent) {
|
if (hadFlushEvent) {
|
||||||
@@ -403,8 +409,13 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||||||
this._validateAutoClosedActions();
|
this._validateAutoClosedActions();
|
||||||
this._emitStateChangedIfNecessary('model', CursorChangeReason.ContentFlush, null);
|
this._emitStateChangedIfNecessary('model', CursorChangeReason.ContentFlush, null);
|
||||||
} else {
|
} else {
|
||||||
const selectionsFromMarkers = this._cursors.readSelectionFromMarkers();
|
if (this._hasFocus && e.resultingSelection && e.resultingSelection.length > 0) {
|
||||||
this.setStates('modelChange', CursorChangeReason.RecoverFromMarkers, CursorState.fromModelSelections(selectionsFromMarkers));
|
const cursorState = CursorState.fromModelSelections(e.resultingSelection);
|
||||||
|
this.setStates('modelChange', e.isUndoing ? CursorChangeReason.Undo : e.isRedoing ? CursorChangeReason.Redo : CursorChangeReason.RecoverFromMarkers, cursorState);
|
||||||
|
} else {
|
||||||
|
const selectionsFromMarkers = this._cursors.readSelectionFromMarkers();
|
||||||
|
this.setStates('modelChange', CursorChangeReason.RecoverFromMarkers, CursorState.fromModelSelections(selectionsFromMarkers));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -704,11 +715,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||||||
const oldState = new CursorModelState(this._model, this);
|
const oldState = new CursorModelState(this._model, this);
|
||||||
let cursorChangeReason = CursorChangeReason.NotSet;
|
let cursorChangeReason = CursorChangeReason.NotSet;
|
||||||
|
|
||||||
if (handlerId !== H.Undo && handlerId !== H.Redo) {
|
this._cursors.stopTrackingSelections();
|
||||||
// TODO@Alex: if the undo/redo stack contains non-null selections
|
|
||||||
// it would also be OK to stop tracking selections here
|
|
||||||
this._cursors.stopTrackingSelections();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure valid state on all cursors
|
// ensure valid state on all cursors
|
||||||
this._cursors.ensureValidState();
|
this._cursors.ensureValidState();
|
||||||
@@ -734,16 +741,6 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||||||
this._cut();
|
this._cut();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case H.Undo:
|
|
||||||
cursorChangeReason = CursorChangeReason.Undo;
|
|
||||||
this._interpretCommandResult(this._model.undo());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case H.Redo:
|
|
||||||
cursorChangeReason = CursorChangeReason.Redo;
|
|
||||||
this._interpretCommandResult(this._model.redo());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case H.ExecuteCommand:
|
case H.ExecuteCommand:
|
||||||
this._externalExecuteCommand(<editorCommon.ICommand>payload);
|
this._externalExecuteCommand(<editorCommon.ICommand>payload);
|
||||||
break;
|
break;
|
||||||
@@ -762,9 +759,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||||||
|
|
||||||
this._isHandling = false;
|
this._isHandling = false;
|
||||||
|
|
||||||
if (handlerId !== H.Undo && handlerId !== H.Redo) {
|
this._cursors.startTrackingSelections();
|
||||||
this._cursors.startTrackingSelections();
|
|
||||||
}
|
|
||||||
|
|
||||||
this._validateAutoClosedActions();
|
this._validateAutoClosedActions();
|
||||||
|
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ export interface IConfiguration extends IDisposable {
|
|||||||
readonly options: IComputedEditorOptions;
|
readonly options: IComputedEditorOptions;
|
||||||
|
|
||||||
setMaxLineNumber(maxLineNumber: number): void;
|
setMaxLineNumber(maxLineNumber: number): void;
|
||||||
|
setViewLineCount(viewLineCount: number): void;
|
||||||
updateOptions(newOptions: IEditorOptions): void;
|
updateOptions(newOptions: IEditorOptions): void;
|
||||||
getRawOptions(): IEditorOptions;
|
getRawOptions(): IEditorOptions;
|
||||||
observeReferenceElement(dimension?: IDimension): void;
|
observeReferenceElement(dimension?: IDimension): void;
|
||||||
@@ -466,6 +467,12 @@ export interface IEditor {
|
|||||||
*/
|
*/
|
||||||
revealRangeNearTop(range: IRange, scrollType?: ScrollType): void;
|
revealRangeNearTop(range: IRange, scrollType?: ScrollType): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport,
|
||||||
|
* optimized for viewing a code definition. Only if it lies outside the viewport.
|
||||||
|
*/
|
||||||
|
revealRangeNearTopIfOutsideViewport(range: IRange, scrollType?: ScrollType): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directly trigger a handler or an editor action.
|
* Directly trigger a handler or an editor action.
|
||||||
* @param source The source of the call.
|
* @param source The source of the call.
|
||||||
@@ -671,9 +678,5 @@ export const Handler = {
|
|||||||
CompositionStart: 'compositionStart',
|
CompositionStart: 'compositionStart',
|
||||||
CompositionEnd: 'compositionEnd',
|
CompositionEnd: 'compositionEnd',
|
||||||
Paste: 'paste',
|
Paste: 'paste',
|
||||||
|
|
||||||
Cut: 'cut',
|
Cut: 'cut',
|
||||||
|
|
||||||
Undo: 'undo',
|
|
||||||
Redo: 'redo',
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -379,6 +379,13 @@ export interface IValidEditOperation {
|
|||||||
forceMoveMarkers: boolean;
|
forceMoveMarkers: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export interface IValidEditOperations {
|
||||||
|
operations: IValidEditOperation[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback that can compute the cursor state after applying a series of edit operations.
|
* A callback that can compute the cursor state after applying a series of edit operations.
|
||||||
*/
|
*/
|
||||||
@@ -1086,18 +1093,28 @@ export interface ITextModel {
|
|||||||
*/
|
*/
|
||||||
applyEdits(operations: IIdentifiedSingleEditOperation[]): IValidEditOperation[];
|
applyEdits(operations: IIdentifiedSingleEditOperation[]): IValidEditOperation[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
_applyEdits(edits: IValidEditOperations[], isUndoing: boolean, isRedoing: boolean, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): IValidEditOperations[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the end of line sequence without recording in the undo stack.
|
* Change the end of line sequence without recording in the undo stack.
|
||||||
* This can have dire consequences on the undo stack! See @pushEOL for the preferred way.
|
* This can have dire consequences on the undo stack! See @pushEOL for the preferred way.
|
||||||
*/
|
*/
|
||||||
setEOL(eol: EndOfLineSequence): void;
|
setEOL(eol: EndOfLineSequence): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
_setEOL(eol: EndOfLineSequence, isUndoing: boolean, isRedoing: boolean, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Undo edit operations until the first previous stop point created by `pushStackElement`.
|
* Undo edit operations until the first previous stop point created by `pushStackElement`.
|
||||||
* The inverse edit operations will be pushed on the redo stack.
|
* The inverse edit operations will be pushed on the redo stack.
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
undo(): Selection[] | null;
|
undo(): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is there anything in the undo stack?
|
* Is there anything in the undo stack?
|
||||||
@@ -1110,7 +1127,7 @@ export interface ITextModel {
|
|||||||
* The inverse edit operations will be pushed on the undo stack.
|
* The inverse edit operations will be pushed on the undo stack.
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
redo(): Selection[] | null;
|
redo(): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is there anything in the redo stack?
|
* Is there anything in the redo stack?
|
||||||
|
|||||||
@@ -3,61 +3,72 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as nls from 'vs/nls';
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { Selection } from 'vs/editor/common/core/selection';
|
import { Selection } from 'vs/editor/common/core/selection';
|
||||||
import { EndOfLineSequence, ICursorStateComputer, IIdentifiedSingleEditOperation, IValidEditOperation } from 'vs/editor/common/model';
|
import { EndOfLineSequence, ICursorStateComputer, IIdentifiedSingleEditOperation, IValidEditOperation, ITextModel, IValidEditOperations } from 'vs/editor/common/model';
|
||||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||||
|
import { IUndoRedoService, IUndoRedoElement, IUndoRedoContext } from 'vs/platform/undoRedo/common/undoRedo';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
|
||||||
interface IEditOperation {
|
class EditStackElement implements IUndoRedoElement {
|
||||||
operations: IValidEditOperation[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IStackElement {
|
public readonly label: string;
|
||||||
readonly beforeVersionId: number;
|
private _isOpen: boolean;
|
||||||
readonly beforeCursorState: Selection[] | null;
|
private readonly _model: TextModel;
|
||||||
readonly afterCursorState: Selection[] | null;
|
private readonly _beforeVersionId: number;
|
||||||
readonly afterVersionId: number;
|
private readonly _beforeCursorState: Selection[];
|
||||||
|
private _afterVersionId: number;
|
||||||
|
private _afterCursorState: Selection[] | null;
|
||||||
|
private _edits: IValidEditOperations[];
|
||||||
|
|
||||||
undo(model: TextModel): void;
|
public get resources(): readonly URI[] {
|
||||||
redo(model: TextModel): void;
|
return [this._model.uri];
|
||||||
}
|
|
||||||
|
|
||||||
class EditStackElement implements IStackElement {
|
|
||||||
public readonly beforeVersionId: number;
|
|
||||||
public readonly beforeCursorState: Selection[];
|
|
||||||
public afterCursorState: Selection[] | null;
|
|
||||||
public afterVersionId: number;
|
|
||||||
|
|
||||||
public editOperations: IEditOperation[];
|
|
||||||
|
|
||||||
constructor(beforeVersionId: number, beforeCursorState: Selection[]) {
|
|
||||||
this.beforeVersionId = beforeVersionId;
|
|
||||||
this.beforeCursorState = beforeCursorState;
|
|
||||||
this.afterCursorState = null;
|
|
||||||
this.afterVersionId = -1;
|
|
||||||
this.editOperations = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public undo(model: TextModel): void {
|
constructor(model: TextModel, beforeVersionId: number, beforeCursorState: Selection[], afterVersionId: number, afterCursorState: Selection[] | null, operations: IValidEditOperation[]) {
|
||||||
// Apply all operations in reverse order
|
this.label = nls.localize('edit', "Typing");
|
||||||
for (let i = this.editOperations.length - 1; i >= 0; i--) {
|
this._isOpen = true;
|
||||||
this.editOperations[i] = {
|
this._model = model;
|
||||||
operations: model.applyEdits(this.editOperations[i].operations)
|
this._beforeVersionId = beforeVersionId;
|
||||||
};
|
this._beforeCursorState = beforeCursorState;
|
||||||
}
|
this._afterVersionId = afterVersionId;
|
||||||
|
this._afterCursorState = afterCursorState;
|
||||||
|
this._edits = [{ operations: operations }];
|
||||||
}
|
}
|
||||||
|
|
||||||
public redo(model: TextModel): void {
|
public isOpen(): boolean {
|
||||||
// Apply all operations
|
return this._isOpen;
|
||||||
for (let i = 0; i < this.editOperations.length; i++) {
|
}
|
||||||
this.editOperations[i] = {
|
|
||||||
operations: model.applyEdits(this.editOperations[i].operations)
|
public append(operations: IValidEditOperation[], afterVersionId: number, afterCursorState: Selection[] | null): void {
|
||||||
};
|
this._edits.push({ operations: operations });
|
||||||
}
|
this._afterVersionId = afterVersionId;
|
||||||
|
this._afterCursorState = afterCursorState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public close(): void {
|
||||||
|
this._isOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
undo(ctx: IUndoRedoContext): void {
|
||||||
|
this._isOpen = false;
|
||||||
|
this._edits.reverse();
|
||||||
|
this._edits = this._model._applyEdits(this._edits, true, false, this._beforeVersionId, this._beforeCursorState);
|
||||||
|
}
|
||||||
|
|
||||||
|
redo(ctx: IUndoRedoContext): void {
|
||||||
|
this._isOpen = false;
|
||||||
|
this._edits.reverse();
|
||||||
|
this._edits = this._model._applyEdits(this._edits, false, true, this._afterVersionId, this._afterCursorState);
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate(resource: URI): void {
|
||||||
|
// nothing to do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getModelEOL(model: TextModel): EndOfLineSequence {
|
function getModelEOL(model: ITextModel): EndOfLineSequence {
|
||||||
const eol = model.getEOL();
|
const eol = model.getEOL();
|
||||||
if (eol === '\n') {
|
if (eol === '\n') {
|
||||||
return EndOfLineSequence.LF;
|
return EndOfLineSequence.LF;
|
||||||
@@ -66,32 +77,40 @@ function getModelEOL(model: TextModel): EndOfLineSequence {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EOLStackElement implements IStackElement {
|
class EOLStackElement implements IUndoRedoElement {
|
||||||
public readonly beforeVersionId: number;
|
|
||||||
public readonly beforeCursorState: Selection[] | null;
|
|
||||||
public readonly afterCursorState: Selection[] | null;
|
|
||||||
public afterVersionId: number;
|
|
||||||
|
|
||||||
public eol: EndOfLineSequence;
|
public readonly label: string;
|
||||||
|
private readonly _model: TextModel;
|
||||||
|
private readonly _beforeVersionId: number;
|
||||||
|
private readonly _afterVersionId: number;
|
||||||
|
private _eol: EndOfLineSequence;
|
||||||
|
|
||||||
constructor(beforeVersionId: number, setEOL: EndOfLineSequence) {
|
public get resources(): readonly URI[] {
|
||||||
this.beforeVersionId = beforeVersionId;
|
return [this._model.uri];
|
||||||
this.beforeCursorState = null;
|
|
||||||
this.afterCursorState = null;
|
|
||||||
this.afterVersionId = -1;
|
|
||||||
this.eol = setEOL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public undo(model: TextModel): void {
|
constructor(model: TextModel, beforeVersionId: number, afterVersionId: number, eol: EndOfLineSequence) {
|
||||||
let redoEOL = getModelEOL(model);
|
this.label = nls.localize('eol', "Change End Of Line Sequence");
|
||||||
model.setEOL(this.eol);
|
this._model = model;
|
||||||
this.eol = redoEOL;
|
this._beforeVersionId = beforeVersionId;
|
||||||
|
this._afterVersionId = afterVersionId;
|
||||||
|
this._eol = eol;
|
||||||
}
|
}
|
||||||
|
|
||||||
public redo(model: TextModel): void {
|
undo(ctx: IUndoRedoContext): void {
|
||||||
let undoEOL = getModelEOL(model);
|
const redoEOL = getModelEOL(this._model);
|
||||||
model.setEOL(this.eol);
|
this._model._setEOL(this._eol, true, false, this._beforeVersionId, null);
|
||||||
this.eol = undoEOL;
|
this._eol = redoEOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
redo(ctx: IUndoRedoContext): void {
|
||||||
|
const undoEOL = getModelEOL(this._model);
|
||||||
|
this._model._setEOL(this._eol, false, true, this._afterVersionId, null);
|
||||||
|
this._eol = undoEOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate(resource: URI): void {
|
||||||
|
// nothing to do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,76 +121,52 @@ export interface IUndoRedoResult {
|
|||||||
|
|
||||||
export class EditStack {
|
export class EditStack {
|
||||||
|
|
||||||
private readonly model: TextModel;
|
private readonly _model: TextModel;
|
||||||
private currentOpenStackElement: IStackElement | null;
|
private readonly _undoRedoService: IUndoRedoService;
|
||||||
private past: IStackElement[];
|
|
||||||
private future: IStackElement[];
|
|
||||||
|
|
||||||
constructor(model: TextModel) {
|
constructor(model: TextModel, undoRedoService: IUndoRedoService) {
|
||||||
this.model = model;
|
this._model = model;
|
||||||
this.currentOpenStackElement = null;
|
this._undoRedoService = undoRedoService;
|
||||||
this.past = [];
|
|
||||||
this.future = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public pushStackElement(): void {
|
public pushStackElement(): void {
|
||||||
if (this.currentOpenStackElement !== null) {
|
const lastElement = this._undoRedoService.getLastElement(this._model.uri);
|
||||||
this.past.push(this.currentOpenStackElement);
|
if (lastElement && lastElement instanceof EditStackElement) {
|
||||||
this.currentOpenStackElement = null;
|
lastElement.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public clear(): void {
|
public clear(): void {
|
||||||
this.currentOpenStackElement = null;
|
this._undoRedoService.removeElements(this._model.uri);
|
||||||
this.past = [];
|
|
||||||
this.future = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public pushEOL(eol: EndOfLineSequence): void {
|
public pushEOL(eol: EndOfLineSequence): void {
|
||||||
// No support for parallel universes :(
|
const beforeVersionId = this._model.getAlternativeVersionId();
|
||||||
this.future = [];
|
const inverseEOL = getModelEOL(this._model);
|
||||||
|
this._model.setEOL(eol);
|
||||||
|
const afterVersionId = this._model.getAlternativeVersionId();
|
||||||
|
|
||||||
if (this.currentOpenStackElement) {
|
const lastElement = this._undoRedoService.getLastElement(this._model.uri);
|
||||||
this.pushStackElement();
|
if (lastElement && lastElement instanceof EditStackElement) {
|
||||||
|
lastElement.close();
|
||||||
}
|
}
|
||||||
|
this._undoRedoService.pushElement(new EOLStackElement(this._model, inverseEOL, beforeVersionId, afterVersionId));
|
||||||
const prevEOL = getModelEOL(this.model);
|
|
||||||
let stackElement = new EOLStackElement(this.model.getAlternativeVersionId(), prevEOL);
|
|
||||||
|
|
||||||
this.model.setEOL(eol);
|
|
||||||
|
|
||||||
stackElement.afterVersionId = this.model.getVersionId();
|
|
||||||
this.currentOpenStackElement = stackElement;
|
|
||||||
this.pushStackElement();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public pushEditOperation(beforeCursorState: Selection[], editOperations: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer | null): Selection[] | null {
|
public pushEditOperation(beforeCursorState: Selection[], editOperations: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer | null): Selection[] | null {
|
||||||
// No support for parallel universes :(
|
const beforeVersionId = this._model.getAlternativeVersionId();
|
||||||
this.future = [];
|
const inverseEditOperations = this._model.applyEdits(editOperations);
|
||||||
|
const afterVersionId = this._model.getAlternativeVersionId();
|
||||||
|
const afterCursorState = EditStack._computeCursorState(cursorStateComputer, inverseEditOperations);
|
||||||
|
|
||||||
let stackElement: EditStackElement | null = null;
|
const lastElement = this._undoRedoService.getLastElement(this._model.uri);
|
||||||
|
if (lastElement && lastElement instanceof EditStackElement && lastElement.isOpen()) {
|
||||||
if (this.currentOpenStackElement) {
|
lastElement.append(inverseEditOperations, afterVersionId, afterCursorState);
|
||||||
if (this.currentOpenStackElement instanceof EditStackElement) {
|
} else {
|
||||||
stackElement = this.currentOpenStackElement;
|
this._undoRedoService.pushElement(new EditStackElement(this._model, beforeVersionId, beforeCursorState, afterVersionId, afterCursorState, inverseEditOperations));
|
||||||
} else {
|
|
||||||
this.pushStackElement();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.currentOpenStackElement) {
|
return afterCursorState;
|
||||||
stackElement = new EditStackElement(this.model.getAlternativeVersionId(), beforeCursorState);
|
|
||||||
this.currentOpenStackElement = stackElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
const inverseEditOperation: IEditOperation = {
|
|
||||||
operations: this.model.applyEdits(editOperations)
|
|
||||||
};
|
|
||||||
|
|
||||||
stackElement!.editOperations.push(inverseEditOperation);
|
|
||||||
stackElement!.afterCursorState = EditStack._computeCursorState(cursorStateComputer, inverseEditOperation.operations);
|
|
||||||
stackElement!.afterVersionId = this.model.getVersionId();
|
|
||||||
return stackElement!.afterCursorState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _computeCursorState(cursorStateComputer: ICursorStateComputer | null, inverseEditOperations: IValidEditOperation[]): Selection[] | null {
|
private static _computeCursorState(cursorStateComputer: ICursorStateComputer | null, inverseEditOperations: IValidEditOperation[]): Selection[] | null {
|
||||||
@@ -182,62 +177,4 @@ export class EditStack {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public undo(): IUndoRedoResult | null {
|
|
||||||
|
|
||||||
this.pushStackElement();
|
|
||||||
|
|
||||||
if (this.past.length > 0) {
|
|
||||||
const pastStackElement = this.past.pop()!;
|
|
||||||
|
|
||||||
try {
|
|
||||||
pastStackElement.undo(this.model);
|
|
||||||
} catch (e) {
|
|
||||||
onUnexpectedError(e);
|
|
||||||
this.clear();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.future.push(pastStackElement);
|
|
||||||
|
|
||||||
return {
|
|
||||||
selections: pastStackElement.beforeCursorState,
|
|
||||||
recordedVersionId: pastStackElement.beforeVersionId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public canUndo(): boolean {
|
|
||||||
return (this.past.length > 0) || this.currentOpenStackElement !== null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public redo(): IUndoRedoResult | null {
|
|
||||||
|
|
||||||
if (this.future.length > 0) {
|
|
||||||
const futureStackElement = this.future.pop()!;
|
|
||||||
|
|
||||||
try {
|
|
||||||
futureStackElement.redo(this.model);
|
|
||||||
} catch (e) {
|
|
||||||
onUnexpectedError(e);
|
|
||||||
this.clear();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.past.push(futureStackElement);
|
|
||||||
|
|
||||||
return {
|
|
||||||
selections: futureStackElement.afterCursorState,
|
|
||||||
recordedVersionId: futureStackElement.afterVersionId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public canRedo(): boolean {
|
|
||||||
return (this.future.length > 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ import { TokensStore, MultilineTokens, countEOL, MultilineTokens2, TokensStore2
|
|||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
import { Constants } from 'vs/base/common/uint';
|
import { Constants } from 'vs/base/common/uint';
|
||||||
import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||||
|
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||||
|
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
|
||||||
|
|
||||||
function createTextBufferBuilder() {
|
function createTextBufferBuilder() {
|
||||||
return new PieceTreeTextBufferBuilder();
|
return new PieceTreeTextBufferBuilder();
|
||||||
@@ -188,7 +190,7 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public static createFromString(text: string, options: model.ITextModelCreationOptions = TextModel.DEFAULT_CREATION_OPTIONS, languageIdentifier: LanguageIdentifier | null = null, uri: URI | null = null): TextModel {
|
public static createFromString(text: string, options: model.ITextModelCreationOptions = TextModel.DEFAULT_CREATION_OPTIONS, languageIdentifier: LanguageIdentifier | null = null, uri: URI | null = null): TextModel {
|
||||||
return new TextModel(text, options, languageIdentifier, uri);
|
return new TextModel(text, options, languageIdentifier, uri, new UndoRedoService());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static resolveOptions(textBuffer: model.ITextBuffer, options: model.ITextModelCreationOptions): model.TextModelResolvedOptions {
|
public static resolveOptions(textBuffer: model.ITextBuffer, options: model.ITextModelCreationOptions): model.TextModelResolvedOptions {
|
||||||
@@ -253,6 +255,7 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||||||
public readonly id: string;
|
public readonly id: string;
|
||||||
public readonly isForSimpleWidget: boolean;
|
public readonly isForSimpleWidget: boolean;
|
||||||
private readonly _associatedResource: URI;
|
private readonly _associatedResource: URI;
|
||||||
|
private readonly _undoRedoService: IUndoRedoService;
|
||||||
private _attachedEditorCount: number;
|
private _attachedEditorCount: number;
|
||||||
private _buffer: model.ITextBuffer;
|
private _buffer: model.ITextBuffer;
|
||||||
private _options: model.TextModelResolvedOptions;
|
private _options: model.TextModelResolvedOptions;
|
||||||
@@ -268,7 +271,7 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||||||
private readonly _isTooLargeForTokenization: boolean;
|
private readonly _isTooLargeForTokenization: boolean;
|
||||||
|
|
||||||
//#region Editing
|
//#region Editing
|
||||||
private _commandManager: EditStack;
|
private readonly _commandManager: EditStack;
|
||||||
private _isUndoing: boolean;
|
private _isUndoing: boolean;
|
||||||
private _isRedoing: boolean;
|
private _isRedoing: boolean;
|
||||||
private _trimAutoWhitespaceLines: number[] | null;
|
private _trimAutoWhitespaceLines: number[] | null;
|
||||||
@@ -293,7 +296,13 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||||||
private readonly _tokenization: TextModelTokenization;
|
private readonly _tokenization: TextModelTokenization;
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
constructor(source: string | model.ITextBufferFactory, creationOptions: model.ITextModelCreationOptions, languageIdentifier: LanguageIdentifier | null, associatedResource: URI | null = null) {
|
constructor(
|
||||||
|
source: string | model.ITextBufferFactory,
|
||||||
|
creationOptions: model.ITextModelCreationOptions,
|
||||||
|
languageIdentifier: LanguageIdentifier | null,
|
||||||
|
associatedResource: URI | null = null,
|
||||||
|
undoRedoService: IUndoRedoService
|
||||||
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
// Generate a new unique model id
|
// Generate a new unique model id
|
||||||
@@ -305,6 +314,7 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||||||
} else {
|
} else {
|
||||||
this._associatedResource = associatedResource;
|
this._associatedResource = associatedResource;
|
||||||
}
|
}
|
||||||
|
this._undoRedoService = undoRedoService;
|
||||||
this._attachedEditorCount = 0;
|
this._attachedEditorCount = 0;
|
||||||
|
|
||||||
this._buffer = createTextBuffer(source, creationOptions.defaultEOL);
|
this._buffer = createTextBuffer(source, creationOptions.defaultEOL);
|
||||||
@@ -347,7 +357,7 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||||||
this._decorations = Object.create(null);
|
this._decorations = Object.create(null);
|
||||||
this._decorationsTree = new DecorationsTrees();
|
this._decorationsTree = new DecorationsTrees();
|
||||||
|
|
||||||
this._commandManager = new EditStack(this);
|
this._commandManager = new EditStack(this, undoRedoService);
|
||||||
this._isUndoing = false;
|
this._isUndoing = false;
|
||||||
this._isRedoing = false;
|
this._isRedoing = false;
|
||||||
this._trimAutoWhitespaceLines = null;
|
this._trimAutoWhitespaceLines = null;
|
||||||
@@ -362,6 +372,7 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||||||
this._onWillDispose.fire();
|
this._onWillDispose.fire();
|
||||||
this._languageRegistryListener.dispose();
|
this._languageRegistryListener.dispose();
|
||||||
this._tokenization.dispose();
|
this._tokenization.dispose();
|
||||||
|
this._undoRedoService.removeElements(this.uri);
|
||||||
this._isDisposed = true;
|
this._isDisposed = true;
|
||||||
super.dispose();
|
super.dispose();
|
||||||
this._isDisposing = false;
|
this._isDisposing = false;
|
||||||
@@ -436,7 +447,7 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||||||
this._decorationsTree = new DecorationsTrees();
|
this._decorationsTree = new DecorationsTrees();
|
||||||
|
|
||||||
// Destroy my edit history and settings
|
// Destroy my edit history and settings
|
||||||
this._commandManager = new EditStack(this);
|
this._commandManager.clear();
|
||||||
this._trimAutoWhitespaceLines = null;
|
this._trimAutoWhitespaceLines = null;
|
||||||
|
|
||||||
this._emitContentChangedEvent(
|
this._emitContentChangedEvent(
|
||||||
@@ -483,6 +494,21 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setEOL(eol: model.EndOfLineSequence, isUndoing: boolean, isRedoing: boolean, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void {
|
||||||
|
try {
|
||||||
|
this._onDidChangeDecorations.beginDeferredEmit();
|
||||||
|
this._eventEmitter.beginDeferredEmit();
|
||||||
|
this._isUndoing = isUndoing;
|
||||||
|
this._isRedoing = isRedoing;
|
||||||
|
this.setEOL(eol);
|
||||||
|
this._overwriteAlternativeVersionId(resultingAlternativeVersionId);
|
||||||
|
} finally {
|
||||||
|
this._isUndoing = false;
|
||||||
|
this._eventEmitter.endDeferredEmit(resultingSelection);
|
||||||
|
this._onDidChangeDecorations.endDeferredEmit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _onBeforeEOLChange(): void {
|
private _onBeforeEOLChange(): void {
|
||||||
// Ensure all decorations get their `range` set.
|
// Ensure all decorations get their `range` set.
|
||||||
const versionId = this.getVersionId();
|
const versionId = this.getVersionId();
|
||||||
@@ -1272,18 +1298,37 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||||||
return this._commandManager.pushEditOperation(beforeCursorState, editOperations, cursorStateComputer);
|
return this._commandManager.pushEditOperation(beforeCursorState, editOperations, cursorStateComputer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_applyEdits(edits: model.IValidEditOperations[], isUndoing: boolean, isRedoing: boolean, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): model.IValidEditOperations[] {
|
||||||
|
try {
|
||||||
|
this._onDidChangeDecorations.beginDeferredEmit();
|
||||||
|
this._eventEmitter.beginDeferredEmit();
|
||||||
|
this._isUndoing = isUndoing;
|
||||||
|
this._isRedoing = isRedoing;
|
||||||
|
let reverseEdits: model.IValidEditOperations[] = [];
|
||||||
|
for (let i = 0, len = edits.length; i < len; i++) {
|
||||||
|
reverseEdits[i] = { operations: this.applyEdits(edits[i].operations) };
|
||||||
|
}
|
||||||
|
this._overwriteAlternativeVersionId(resultingAlternativeVersionId);
|
||||||
|
return reverseEdits;
|
||||||
|
} finally {
|
||||||
|
this._isUndoing = false;
|
||||||
|
this._eventEmitter.endDeferredEmit(resultingSelection);
|
||||||
|
this._onDidChangeDecorations.endDeferredEmit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public applyEdits(rawOperations: model.IIdentifiedSingleEditOperation[]): model.IValidEditOperation[] {
|
public applyEdits(rawOperations: model.IIdentifiedSingleEditOperation[]): model.IValidEditOperation[] {
|
||||||
try {
|
try {
|
||||||
this._onDidChangeDecorations.beginDeferredEmit();
|
this._onDidChangeDecorations.beginDeferredEmit();
|
||||||
this._eventEmitter.beginDeferredEmit();
|
this._eventEmitter.beginDeferredEmit();
|
||||||
return this._applyEdits(this._validateEditOperations(rawOperations));
|
return this._doApplyEdits(this._validateEditOperations(rawOperations));
|
||||||
} finally {
|
} finally {
|
||||||
this._eventEmitter.endDeferredEmit();
|
this._eventEmitter.endDeferredEmit();
|
||||||
this._onDidChangeDecorations.endDeferredEmit();
|
this._onDidChangeDecorations.endDeferredEmit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _applyEdits(rawOperations: model.ValidAnnotatedEditOperation[]): model.IValidEditOperation[] {
|
private _doApplyEdits(rawOperations: model.ValidAnnotatedEditOperation[]): model.IValidEditOperation[] {
|
||||||
|
|
||||||
const oldLineCount = this._buffer.getLineCount();
|
const oldLineCount = this._buffer.getLineCount();
|
||||||
const result = this._buffer.applyEdits(rawOperations, this._options.trimAutoWhitespace);
|
const result = this._buffer.applyEdits(rawOperations, this._options.trimAutoWhitespace);
|
||||||
@@ -1364,62 +1409,20 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||||||
return result.reverseEdits;
|
return result.reverseEdits;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _undo(): Selection[] | null {
|
public undo(): void {
|
||||||
this._isUndoing = true;
|
this._undoRedoService.undo(this.uri);
|
||||||
let r = this._commandManager.undo();
|
|
||||||
this._isUndoing = false;
|
|
||||||
|
|
||||||
if (!r) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._overwriteAlternativeVersionId(r.recordedVersionId);
|
|
||||||
|
|
||||||
return r.selections;
|
|
||||||
}
|
|
||||||
|
|
||||||
public undo(): Selection[] | null {
|
|
||||||
try {
|
|
||||||
this._onDidChangeDecorations.beginDeferredEmit();
|
|
||||||
this._eventEmitter.beginDeferredEmit();
|
|
||||||
return this._undo();
|
|
||||||
} finally {
|
|
||||||
this._eventEmitter.endDeferredEmit();
|
|
||||||
this._onDidChangeDecorations.endDeferredEmit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public canUndo(): boolean {
|
public canUndo(): boolean {
|
||||||
return this._commandManager.canUndo();
|
return this._undoRedoService.canUndo(this.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _redo(): Selection[] | null {
|
public redo(): void {
|
||||||
this._isRedoing = true;
|
this._undoRedoService.redo(this.uri);
|
||||||
let r = this._commandManager.redo();
|
|
||||||
this._isRedoing = false;
|
|
||||||
|
|
||||||
if (!r) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._overwriteAlternativeVersionId(r.recordedVersionId);
|
|
||||||
|
|
||||||
return r.selections;
|
|
||||||
}
|
|
||||||
|
|
||||||
public redo(): Selection[] | null {
|
|
||||||
try {
|
|
||||||
this._onDidChangeDecorations.beginDeferredEmit();
|
|
||||||
this._eventEmitter.beginDeferredEmit();
|
|
||||||
return this._redo();
|
|
||||||
} finally {
|
|
||||||
this._eventEmitter.endDeferredEmit();
|
|
||||||
this._onDidChangeDecorations.endDeferredEmit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public canRedo(): boolean {
|
public canRedo(): boolean {
|
||||||
return this._commandManager.canRedo();
|
return this._undoRedoService.canRedo(this.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
@@ -3191,10 +3194,11 @@ export class DidChangeContentEmitter extends Disposable {
|
|||||||
this._deferredCnt++;
|
this._deferredCnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public endDeferredEmit(): void {
|
public endDeferredEmit(resultingSelection: Selection[] | null = null): void {
|
||||||
this._deferredCnt--;
|
this._deferredCnt--;
|
||||||
if (this._deferredCnt === 0) {
|
if (this._deferredCnt === 0) {
|
||||||
if (this._deferredEvent !== null) {
|
if (this._deferredEvent !== null) {
|
||||||
|
this._deferredEvent.rawContentChangedEvent.resultingSelection = resultingSelection;
|
||||||
const e = this._deferredEvent;
|
const e = this._deferredEvent;
|
||||||
this._deferredEvent = null;
|
this._deferredEvent = null;
|
||||||
this._fastEmitter.fire(e);
|
this._fastEmitter.fire(e);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
import { IRange } from 'vs/editor/common/core/range';
|
||||||
|
import { Selection } from 'vs/editor/common/core/selection';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event describing that the current mode associated with a model has changed.
|
* An event describing that the current mode associated with a model has changed.
|
||||||
@@ -225,11 +226,14 @@ export class ModelRawContentChangedEvent {
|
|||||||
*/
|
*/
|
||||||
public readonly isRedoing: boolean;
|
public readonly isRedoing: boolean;
|
||||||
|
|
||||||
|
public resultingSelection: Selection[] | null;
|
||||||
|
|
||||||
constructor(changes: ModelRawChange[], versionId: number, isUndoing: boolean, isRedoing: boolean) {
|
constructor(changes: ModelRawChange[], versionId: number, isUndoing: boolean, isRedoing: boolean) {
|
||||||
this.changes = changes;
|
this.changes = changes;
|
||||||
this.versionId = versionId;
|
this.versionId = versionId;
|
||||||
this.isUndoing = isUndoing;
|
this.isUndoing = isUndoing;
|
||||||
this.isRedoing = isRedoing;
|
this.isRedoing = isRedoing;
|
||||||
|
this.resultingSelection = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public containsEvent(type: RawContentChangedType): boolean {
|
public containsEvent(type: RawContentChangedType): boolean {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
|||||||
import { SparseEncodedTokens, MultilineTokens2 } from 'vs/editor/common/model/tokensStore';
|
import { SparseEncodedTokens, MultilineTokens2 } from 'vs/editor/common/model/tokensStore';
|
||||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||||
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
|
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
|
||||||
|
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||||
|
|
||||||
export interface IEditorSemanticHighlightingOptions {
|
export interface IEditorSemanticHighlightingOptions {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
@@ -103,6 +104,7 @@ export class ModelServiceImpl extends Disposable implements IModelService {
|
|||||||
private readonly _configurationService: IConfigurationService;
|
private readonly _configurationService: IConfigurationService;
|
||||||
private readonly _configurationServiceSubscription: IDisposable;
|
private readonly _configurationServiceSubscription: IDisposable;
|
||||||
private readonly _resourcePropertiesService: ITextResourcePropertiesService;
|
private readonly _resourcePropertiesService: ITextResourcePropertiesService;
|
||||||
|
private readonly _undoRedoService: IUndoRedoService;
|
||||||
|
|
||||||
private readonly _onModelAdded: Emitter<ITextModel> = this._register(new Emitter<ITextModel>());
|
private readonly _onModelAdded: Emitter<ITextModel> = this._register(new Emitter<ITextModel>());
|
||||||
public readonly onModelAdded: Event<ITextModel> = this._onModelAdded.event;
|
public readonly onModelAdded: Event<ITextModel> = this._onModelAdded.event;
|
||||||
@@ -126,11 +128,13 @@ export class ModelServiceImpl extends Disposable implements IModelService {
|
|||||||
@IConfigurationService configurationService: IConfigurationService,
|
@IConfigurationService configurationService: IConfigurationService,
|
||||||
@ITextResourcePropertiesService resourcePropertiesService: ITextResourcePropertiesService,
|
@ITextResourcePropertiesService resourcePropertiesService: ITextResourcePropertiesService,
|
||||||
@IThemeService themeService: IThemeService,
|
@IThemeService themeService: IThemeService,
|
||||||
@ILogService logService: ILogService
|
@ILogService logService: ILogService,
|
||||||
|
@IUndoRedoService undoRedoService: IUndoRedoService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this._configurationService = configurationService;
|
this._configurationService = configurationService;
|
||||||
this._resourcePropertiesService = resourcePropertiesService;
|
this._resourcePropertiesService = resourcePropertiesService;
|
||||||
|
this._undoRedoService = undoRedoService;
|
||||||
this._models = {};
|
this._models = {};
|
||||||
this._modelCreationOptionsByLanguageAndResource = Object.create(null);
|
this._modelCreationOptionsByLanguageAndResource = Object.create(null);
|
||||||
|
|
||||||
@@ -272,7 +276,7 @@ export class ModelServiceImpl extends Disposable implements IModelService {
|
|||||||
private _createModelData(value: string | ITextBufferFactory, languageIdentifier: LanguageIdentifier, resource: URI | undefined, isForSimpleWidget: boolean): ModelData {
|
private _createModelData(value: string | ITextBufferFactory, languageIdentifier: LanguageIdentifier, resource: URI | undefined, isForSimpleWidget: boolean): ModelData {
|
||||||
// create & save the model
|
// create & save the model
|
||||||
const options = this.getCreationOptions(languageIdentifier.language, resource, isForSimpleWidget);
|
const options = this.getCreationOptions(languageIdentifier.language, resource, isForSimpleWidget);
|
||||||
const model: TextModel = new TextModel(value, options, languageIdentifier, resource);
|
const model: TextModel = new TextModel(value, options, languageIdentifier, resource, this._undoRedoService);
|
||||||
const modelId = MODEL_ID(model.uri);
|
const modelId = MODEL_ID(model.uri);
|
||||||
|
|
||||||
if (this._models[modelId]) {
|
if (this._models[modelId]) {
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ export const enum VerticalRevealType {
|
|||||||
Top = 3,
|
Top = 3,
|
||||||
Bottom = 4,
|
Bottom = 4,
|
||||||
NearTop = 5,
|
NearTop = 5,
|
||||||
|
NearTopIfOutsideViewport = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ViewRevealRangeRequestEvent {
|
export class ViewRevealRangeRequestEvent {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||||||
private readonly configuration: IConfiguration;
|
private readonly configuration: IConfiguration;
|
||||||
private readonly model: ITextModel;
|
private readonly model: ITextModel;
|
||||||
private readonly _tokenizeViewportSoon: RunOnceScheduler;
|
private readonly _tokenizeViewportSoon: RunOnceScheduler;
|
||||||
|
private readonly _updateConfigurationViewLineCount: RunOnceScheduler;
|
||||||
private hasFocus: boolean;
|
private hasFocus: boolean;
|
||||||
private viewportStartLine: number;
|
private viewportStartLine: number;
|
||||||
private viewportStartLineTrackedRange: string | null;
|
private viewportStartLineTrackedRange: string | null;
|
||||||
@@ -56,6 +57,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this._tokenizeViewportSoon = this._register(new RunOnceScheduler(() => this.tokenizeViewport(), 50));
|
this._tokenizeViewportSoon = this._register(new RunOnceScheduler(() => this.tokenizeViewport(), 50));
|
||||||
|
this._updateConfigurationViewLineCount = this._register(new RunOnceScheduler(() => this._updateConfigurationViewLineCountNow(), 0));
|
||||||
this.hasFocus = false;
|
this.hasFocus = false;
|
||||||
this.viewportStartLine = -1;
|
this.viewportStartLine = -1;
|
||||||
this.viewportStartLineTrackedRange = null;
|
this.viewportStartLineTrackedRange = null;
|
||||||
@@ -130,6 +132,8 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||||||
this._endEmit();
|
this._endEmit();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this._updateConfigurationViewLineCountNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
@@ -142,6 +146,10 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||||||
this.viewportStartLineTrackedRange = this.model._setTrackedRange(this.viewportStartLineTrackedRange, null, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges);
|
this.viewportStartLineTrackedRange = this.model._setTrackedRange(this.viewportStartLineTrackedRange, null, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _updateConfigurationViewLineCountNow(): void {
|
||||||
|
this.configuration.setViewLineCount(this.lines.getViewLineCount());
|
||||||
|
}
|
||||||
|
|
||||||
public tokenizeViewport(): void {
|
public tokenizeViewport(): void {
|
||||||
const linesViewportData = this.viewLayout.getLinesViewportData();
|
const linesViewportData = this.viewLayout.getLinesViewportData();
|
||||||
const startPosition = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(linesViewportData.startLineNumber, 1));
|
const startPosition = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(linesViewportData.startLineNumber, 1));
|
||||||
@@ -180,6 +188,8 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||||||
// Never change the scroll position from 0 to something else...
|
// Never change the scroll position from 0 to something else...
|
||||||
restorePreviousViewportStart = true;
|
restorePreviousViewportStart = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._updateConfigurationViewLineCount.schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.hasChanged(EditorOption.readOnly)) {
|
if (e.hasChanged(EditorOption.readOnly)) {
|
||||||
@@ -301,6 +311,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||||||
// Update the configuration and reset the centered view line
|
// Update the configuration and reset the centered view line
|
||||||
this.viewportStartLine = -1;
|
this.viewportStartLine = -1;
|
||||||
this.configuration.setMaxLineNumber(this.model.getLineCount());
|
this.configuration.setMaxLineNumber(this.model.getLineCount());
|
||||||
|
this._updateConfigurationViewLineCountNow();
|
||||||
|
|
||||||
// Recover viewport
|
// Recover viewport
|
||||||
if (!this.hasFocus && this.model.getAttachedEditorCount() >= 2 && this.viewportStartLineTrackedRange) {
|
if (!this.hasFocus && this.model.getAttachedEditorCount() >= 2 && this.viewportStartLineTrackedRange) {
|
||||||
@@ -358,6 +369,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||||||
} finally {
|
} finally {
|
||||||
this._endEmit();
|
this._endEmit();
|
||||||
}
|
}
|
||||||
|
this._updateConfigurationViewLineCount.schedule();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -387,6 +399,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||||||
} finally {
|
} finally {
|
||||||
this._endEmit();
|
this._endEmit();
|
||||||
}
|
}
|
||||||
|
this._updateConfigurationViewLineCount.schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getVisibleRanges(): Range[] {
|
public getVisibleRanges(): Range[] {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { TextModel } from 'vs/editor/common/model/textModel';
|
|||||||
import { FindModelBoundToEditorModel } from 'vs/editor/contrib/find/findModel';
|
import { FindModelBoundToEditorModel } from 'vs/editor/contrib/find/findModel';
|
||||||
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
|
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||||
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
|
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
|
||||||
|
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
|
||||||
|
|
||||||
suite('FindModel', () => {
|
suite('FindModel', () => {
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ suite('FindModel', () => {
|
|||||||
const factory = ptBuilder.finish();
|
const factory = ptBuilder.finish();
|
||||||
withTestCodeEditor([],
|
withTestCodeEditor([],
|
||||||
{
|
{
|
||||||
model: new TextModel(factory, TextModel.DEFAULT_CREATION_OPTIONS, null, null)
|
model: new TextModel(factory, TextModel.DEFAULT_CREATION_OPTIONS, null, null, new UndoRedoService())
|
||||||
},
|
},
|
||||||
(editor, cursor) => callback(editor as unknown as IActiveCodeEditor, cursor)
|
(editor, cursor) => callback(editor as unknown as IActiveCodeEditor, cursor)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -885,7 +885,7 @@ for (let i = 1; i <= 7; i++) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const foldBackgroundBackground = registerColor('editor.foldBackground', { light: transparent(editorSelectionBackground, 0.3), dark: transparent(editorSelectionBackground, 0.3), hc: null }, nls.localize('foldBackgroundBackground', "Background color behind folded ranges."));
|
export const foldBackgroundBackground = registerColor('editor.foldBackground', { light: transparent(editorSelectionBackground, 0.3), dark: transparent(editorSelectionBackground, 0.3), hc: null }, nls.localize('foldBackgroundBackground', "Background color behind folded ranges. The color must not be opaque so as not to hide underlying decorations."), true);
|
||||||
|
|
||||||
registerThemingParticipant((theme, collector) => {
|
registerThemingParticipant((theme, collector) => {
|
||||||
const foldBackground = theme.getColor(foldBackgroundBackground);
|
const foldBackground = theme.getColor(foldBackgroundBackground);
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ abstract class SymbolNavigationAction extends EditorAction {
|
|||||||
resource: reference.uri,
|
resource: reference.uri,
|
||||||
options: {
|
options: {
|
||||||
selection: Range.collapseToStart(range),
|
selection: Range.collapseToStart(range),
|
||||||
selectionRevealType: TextEditorSelectionRevealType.CenterIfOutsideViewport
|
selectionRevealType: TextEditorSelectionRevealType.NearTopIfOutsideViewport
|
||||||
}
|
}
|
||||||
}, editor, sideBySide);
|
}, editor, sideBySide);
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ class SymbolNavigationService implements ISymbolNavigationService {
|
|||||||
resource: reference.uri,
|
resource: reference.uri,
|
||||||
options: {
|
options: {
|
||||||
selection: Range.collapseToStart(reference.range),
|
selection: Range.collapseToStart(reference.range),
|
||||||
selectionRevealType: TextEditorSelectionRevealType.CenterIfOutsideViewport
|
selectionRevealType: TextEditorSelectionRevealType.NearTopIfOutsideViewport
|
||||||
}
|
}
|
||||||
}, source).finally(() => {
|
}, source).finally(() => {
|
||||||
this._ignoreEditorChange = false;
|
this._ignoreEditorChange = false;
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ suite('Editor Contrib - Line Operations', () => {
|
|||||||
assert.equal(model.getLineContent(1), 'one');
|
assert.equal(model.getLineContent(1), 'one');
|
||||||
assert.deepEqual(editor.getSelection(), new Selection(1, 1, 1, 1));
|
assert.deepEqual(editor.getSelection(), new Selection(1, 1, 1, 1));
|
||||||
|
|
||||||
editor.trigger('keyboard', Handler.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'Typing some text here on line one');
|
assert.equal(model.getLineContent(1), 'Typing some text here on line one');
|
||||||
assert.deepEqual(editor.getSelection(), new Selection(1, 31, 1, 31));
|
assert.deepEqual(editor.getSelection(), new Selection(1, 31, 1, 31));
|
||||||
});
|
});
|
||||||
@@ -447,7 +447,7 @@ suite('Editor Contrib - Line Operations', () => {
|
|||||||
assert.equal(model.getLineContent(1), 'hello my dear world');
|
assert.equal(model.getLineContent(1), 'hello my dear world');
|
||||||
assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 14));
|
assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 14));
|
||||||
|
|
||||||
editor.trigger('keyboard', Handler.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'hello my dear');
|
assert.equal(model.getLineContent(1), 'hello my dear');
|
||||||
assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 14));
|
assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 14));
|
||||||
});
|
});
|
||||||
@@ -815,13 +815,13 @@ suite('Editor Contrib - Line Operations', () => {
|
|||||||
new Selection(2, 4, 2, 4)
|
new Selection(2, 4, 2, 4)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
editor.trigger('tests', Handler.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.deepEqual(editor.getSelections(), [
|
assert.deepEqual(editor.getSelections(), [
|
||||||
new Selection(1, 3, 1, 3),
|
new Selection(1, 3, 1, 3),
|
||||||
new Selection(1, 6, 1, 6),
|
new Selection(1, 6, 1, 6),
|
||||||
new Selection(3, 4, 3, 4)
|
new Selection(3, 4, 3, 4)
|
||||||
]);
|
]);
|
||||||
editor.trigger('tests', Handler.Redo, {});
|
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||||
assert.deepEqual(editor.getSelections(), [
|
assert.deepEqual(editor.getSelections(), [
|
||||||
new Selection(1, 3, 1, 3),
|
new Selection(1, 3, 1, 3),
|
||||||
new Selection(2, 4, 2, 4)
|
new Selection(2, 4, 2, 4)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { WordSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/wordSe
|
|||||||
import { TestTextResourcePropertiesService } from 'vs/editor/test/common/services/modelService.test';
|
import { TestTextResourcePropertiesService } from 'vs/editor/test/common/services/modelService.test';
|
||||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||||
import { NullLogService } from 'vs/platform/log/common/log';
|
import { NullLogService } from 'vs/platform/log/common/log';
|
||||||
|
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
|
||||||
|
|
||||||
class MockJSMode extends MockMode {
|
class MockJSMode extends MockMode {
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ suite('SmartSelect', () => {
|
|||||||
|
|
||||||
setup(() => {
|
setup(() => {
|
||||||
const configurationService = new TestConfigurationService();
|
const configurationService = new TestConfigurationService();
|
||||||
modelService = new ModelServiceImpl(configurationService, new TestTextResourcePropertiesService(configurationService), new TestThemeService(), new NullLogService());
|
modelService = new ModelServiceImpl(configurationService, new TestTextResourcePropertiesService(configurationService), new TestThemeService(), new NullLogService(), new UndoRedoService());
|
||||||
mode = new MockJSMode();
|
mode = new MockJSMode();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { IModelDeltaDecoration } from 'vs/editor/common/model';
|
|||||||
import { SuggestController } from 'vs/editor/contrib/suggest/suggestController';
|
import { SuggestController } from 'vs/editor/contrib/suggest/suggestController';
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
import { domEvent } from 'vs/base/browser/event';
|
import { domEvent } from 'vs/base/browser/event';
|
||||||
|
import { domContentLoaded } from 'vs/base/browser/dom';
|
||||||
|
|
||||||
export class SuggestRangeHighlighter {
|
export class SuggestRangeHighlighter {
|
||||||
|
|
||||||
@@ -101,10 +102,12 @@ const shiftKey = new class ShiftKey extends Emitter<boolean> {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this._subscriptions.add(domEvent(document.body, 'keydown')(e => this.isPressed = e.shiftKey));
|
domContentLoaded().then(() => {
|
||||||
this._subscriptions.add(domEvent(document.body, 'keyup')(() => this.isPressed = false));
|
this._subscriptions.add(domEvent(document.body, 'keydown')(e => this.isPressed = e.shiftKey));
|
||||||
this._subscriptions.add(domEvent(document.body, 'mouseleave')(() => this.isPressed = false));
|
this._subscriptions.add(domEvent(document.body, 'keyup')(() => this.isPressed = false));
|
||||||
this._subscriptions.add(domEvent(document.body, 'blur')(() => this.isPressed = false));
|
this._subscriptions.add(domEvent(document.body, 'mouseleave')(() => this.isPressed = false));
|
||||||
|
this._subscriptions.add(domEvent(document.body, 'blur')(() => this.isPressed = false));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get isPressed(): boolean {
|
get isPressed(): boolean {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { CursorWordEndLeft, CursorWordEndLeftSelect, CursorWordEndRight, CursorW
|
|||||||
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
|
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
|
||||||
import { Handler } from 'vs/editor/common/editorCommon';
|
import { Handler } from 'vs/editor/common/editorCommon';
|
||||||
import { Cursor } from 'vs/editor/common/controller/cursor';
|
import { Cursor } from 'vs/editor/common/controller/cursor';
|
||||||
|
import { CoreEditingCommands } from 'vs/editor/browser/controller/coreCommands';
|
||||||
|
|
||||||
suite('WordOperations', () => {
|
suite('WordOperations', () => {
|
||||||
|
|
||||||
@@ -216,7 +217,7 @@ suite('WordOperations', () => {
|
|||||||
|
|
||||||
assert.equal(editor.getValue(), 'foo qbar baz');
|
assert.equal(editor.getValue(), 'foo qbar baz');
|
||||||
|
|
||||||
cursorCommand(cursor, Handler.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(editor.getValue(), 'foo bar baz');
|
assert.equal(editor.getValue(), 'foo bar baz');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common
|
|||||||
import { AccessibilityService } from 'vs/platform/accessibility/common/accessibilityService';
|
import { AccessibilityService } from 'vs/platform/accessibility/common/accessibilityService';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import { BrowserClipboardService } from 'vs/platform/clipboard/browser/clipboardService';
|
import { BrowserClipboardService } from 'vs/platform/clipboard/browser/clipboardService';
|
||||||
|
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||||
|
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
|
||||||
|
|
||||||
export interface IEditorOverrideServices {
|
export interface IEditorOverrideServices {
|
||||||
[index: string]: any;
|
[index: string]: any;
|
||||||
@@ -150,7 +152,9 @@ export module StaticServices {
|
|||||||
|
|
||||||
export const logService = define(ILogService, () => new NullLogService());
|
export const logService = define(ILogService, () => new NullLogService());
|
||||||
|
|
||||||
export const modelService = define(IModelService, (o) => new ModelServiceImpl(configurationService.get(o), resourcePropertiesService.get(o), standaloneThemeService.get(o), logService.get(o)));
|
export const undoRedoService = define(IUndoRedoService, () => new UndoRedoService());
|
||||||
|
|
||||||
|
export const modelService = define(IModelService, (o) => new ModelServiceImpl(configurationService.get(o), resourcePropertiesService.get(o), standaloneThemeService.get(o), logService.get(o), undoRedoService.get(o)));
|
||||||
|
|
||||||
export const markerDecorationsService = define(IMarkerDecorationsService, (o) => new MarkerDecorationsService(modelService.get(o), markerService.get(o)));
|
export const markerDecorationsService = define(IMarkerDecorationsService, (o) => new MarkerDecorationsService(modelService.get(o), markerService.get(o)));
|
||||||
|
|
||||||
|
|||||||
@@ -1240,22 +1240,22 @@ suite('Editor Controller - Regression tests', () => {
|
|||||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert9');
|
assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert9');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\nx', 'assert10');
|
assert.equal(model.getValue(EndOfLinePreference.LF), '\nx', 'assert10');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\t\nx', 'assert11');
|
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\t\nx', 'assert11');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\t\n\tx', 'assert12');
|
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\t\n\tx', 'assert12');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Redo, {});
|
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\t\nx', 'assert13');
|
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\t\nx', 'assert13');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Redo, {});
|
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\nx', 'assert14');
|
assert.equal(model.getValue(EndOfLinePreference.LF), '\nx', 'assert14');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Redo, {});
|
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert15');
|
assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert15');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1263,12 +1263,12 @@ suite('Editor Controller - Regression tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('issue #23539: Setting model EOL isn\'t undoable', () => {
|
test('issue #23539: Setting model EOL isn\'t undoable', () => {
|
||||||
usingCursor({
|
withTestCodeEditor([
|
||||||
text: [
|
'Hello',
|
||||||
'Hello',
|
'world'
|
||||||
'world'
|
], {}, (editor, cursor) => {
|
||||||
]
|
const model = editor.getModel()!;
|
||||||
}, (model, cursor) => {
|
|
||||||
assertCursor(cursor, new Position(1, 1));
|
assertCursor(cursor, new Position(1, 1));
|
||||||
model.setEOL(EndOfLineSequence.LF);
|
model.setEOL(EndOfLineSequence.LF);
|
||||||
assert.equal(model.getValue(), 'Hello\nworld');
|
assert.equal(model.getValue(), 'Hello\nworld');
|
||||||
@@ -1276,7 +1276,7 @@ suite('Editor Controller - Regression tests', () => {
|
|||||||
model.pushEOL(EndOfLineSequence.CRLF);
|
model.pushEOL(EndOfLineSequence.CRLF);
|
||||||
assert.equal(model.getValue(), 'Hello\r\nworld');
|
assert.equal(model.getValue(), 'Hello\r\nworld');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo);
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(), 'Hello\nworld');
|
assert.equal(model.getValue(), 'Hello\nworld');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1301,7 +1301,7 @@ suite('Editor Controller - Regression tests', () => {
|
|||||||
cursorCommand(cursor, H.Type, { text: '%' }, 'keyboard');
|
cursorCommand(cursor, H.Type, { text: '%' }, 'keyboard');
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), '%\'%👁\'', 'assert1');
|
assert.equal(model.getValue(EndOfLinePreference.LF), '%\'%👁\'', 'assert1');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\'👁\'', 'assert2');
|
assert.equal(model.getValue(EndOfLinePreference.LF), '\'👁\'', 'assert2');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1327,39 +1327,39 @@ suite('Editor Controller - Regression tests', () => {
|
|||||||
assert.equal(model.getLineContent(1), 'Hello world');
|
assert.equal(model.getLineContent(1), 'Hello world');
|
||||||
assertCursor(cursor, new Position(1, 12));
|
assertCursor(cursor, new Position(1, 12));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'Hello world ');
|
assert.equal(model.getLineContent(1), 'Hello world ');
|
||||||
assertCursor(cursor, new Position(1, 13));
|
assertCursor(cursor, new Position(1, 13));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'Hello world');
|
assert.equal(model.getLineContent(1), 'Hello world');
|
||||||
assertCursor(cursor, new Position(1, 12));
|
assertCursor(cursor, new Position(1, 12));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'Hello');
|
assert.equal(model.getLineContent(1), 'Hello');
|
||||||
assertCursor(cursor, new Position(1, 6));
|
assertCursor(cursor, new Position(1, 6));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), '');
|
assert.equal(model.getLineContent(1), '');
|
||||||
assertCursor(cursor, new Position(1, 1));
|
assertCursor(cursor, new Position(1, 1));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Redo, {});
|
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'Hello');
|
assert.equal(model.getLineContent(1), 'Hello');
|
||||||
assertCursor(cursor, new Position(1, 6));
|
assertCursor(cursor, new Position(1, 6));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Redo, {});
|
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'Hello world');
|
assert.equal(model.getLineContent(1), 'Hello world');
|
||||||
assertCursor(cursor, new Position(1, 12));
|
assertCursor(cursor, new Position(1, 12));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Redo, {});
|
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'Hello world ');
|
assert.equal(model.getLineContent(1), 'Hello world ');
|
||||||
assertCursor(cursor, new Position(1, 13));
|
assertCursor(cursor, new Position(1, 13));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Redo, {});
|
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'Hello world');
|
assert.equal(model.getLineContent(1), 'Hello world');
|
||||||
assertCursor(cursor, new Position(1, 12));
|
assertCursor(cursor, new Position(1, 12));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Redo, {});
|
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'Hello world');
|
assert.equal(model.getLineContent(1), 'Hello world');
|
||||||
assertCursor(cursor, new Position(1, 12));
|
assertCursor(cursor, new Position(1, 12));
|
||||||
});
|
});
|
||||||
@@ -1735,21 +1735,21 @@ suite('Editor Controller - Regression tests', () => {
|
|||||||
'\t just some text'
|
'\t just some text'
|
||||||
].join('\n'), '001');
|
].join('\n'), '001');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo);
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(), [
|
assert.equal(model.getValue(), [
|
||||||
' some lines',
|
' some lines',
|
||||||
' and more lines',
|
' and more lines',
|
||||||
' just some text',
|
' just some text',
|
||||||
].join('\n'), '002');
|
].join('\n'), '002');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo);
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(), [
|
assert.equal(model.getValue(), [
|
||||||
'some lines',
|
'some lines',
|
||||||
'and more lines',
|
'and more lines',
|
||||||
'just some text',
|
'just some text',
|
||||||
].join('\n'), '003');
|
].join('\n'), '003');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo);
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(), [
|
assert.equal(model.getValue(), [
|
||||||
'some lines',
|
'some lines',
|
||||||
'and more lines',
|
'and more lines',
|
||||||
@@ -1935,10 +1935,8 @@ suite('Editor Controller - Regression tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('issue #9675: Undo/Redo adds a stop in between CHN Characters', () => {
|
test('issue #9675: Undo/Redo adds a stop in between CHN Characters', () => {
|
||||||
usingCursor({
|
withTestCodeEditor([], {}, (editor, cursor) => {
|
||||||
text: [
|
const model = editor.getModel()!;
|
||||||
]
|
|
||||||
}, (model, cursor) => {
|
|
||||||
assertCursor(cursor, new Position(1, 1));
|
assertCursor(cursor, new Position(1, 1));
|
||||||
|
|
||||||
// Typing sennsei in Japanese - Hiragana
|
// Typing sennsei in Japanese - Hiragana
|
||||||
@@ -1957,7 +1955,7 @@ suite('Editor Controller - Regression tests', () => {
|
|||||||
assert.equal(model.getLineContent(1), 'せんせい');
|
assert.equal(model.getLineContent(1), 'せんせい');
|
||||||
assertCursor(cursor, new Position(1, 5));
|
assertCursor(cursor, new Position(1, 5));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo);
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), '');
|
assert.equal(model.getLineContent(1), '');
|
||||||
assertCursor(cursor, new Position(1, 1));
|
assertCursor(cursor, new Position(1, 1));
|
||||||
});
|
});
|
||||||
@@ -2138,7 +2136,7 @@ suite('Editor Controller - Regression tests', () => {
|
|||||||
}], () => [new Selection(1, 1, 1, 1)]);
|
}], () => [new Selection(1, 1, 1, 1)]);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), 'Hello world!');
|
assert.equal(model.getValue(EndOfLinePreference.LF), 'Hello world!');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), 'Hello world!');
|
assert.equal(model.getValue(EndOfLinePreference.LF), 'Hello world!');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2229,12 +2227,12 @@ suite('Editor Controller - Regression tests', () => {
|
|||||||
new Selection(1, 5, 1, 5),
|
new Selection(1, 5, 1, 5),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, null, 'keyboard');
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assertCursor(cursor, [
|
assertCursor(cursor, [
|
||||||
new Selection(1, 4, 1, 4),
|
new Selection(1, 4, 1, 4),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
cursorCommand(cursor, H.Redo, null, 'keyboard');
|
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||||
assertCursor(cursor, [
|
assertCursor(cursor, [
|
||||||
new Selection(1, 5, 1, 5),
|
new Selection(1, 5, 1, 5),
|
||||||
]);
|
]);
|
||||||
@@ -2263,7 +2261,7 @@ suite('Editor Controller - Regression tests', () => {
|
|||||||
new Selection(1, 1, 1, 1),
|
new Selection(1, 1, 1, 1),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, null, 'keyboard');
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assertCursor(cursor, [
|
assertCursor(cursor, [
|
||||||
new Selection(1, 1, 1, 1),
|
new Selection(1, 1, 1, 1),
|
||||||
]);
|
]);
|
||||||
@@ -2378,49 +2376,49 @@ suite('Editor Controller - Cursor Configuration', () => {
|
|||||||
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 1) });
|
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 1) });
|
||||||
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), ' My Second Line123');
|
assert.equal(model.getLineContent(2), ' My Second Line123');
|
||||||
cursorCommand(cursor, H.Undo, null, 'keyboard');
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
|
|
||||||
// Tab on column 2
|
// Tab on column 2
|
||||||
assert.equal(model.getLineContent(2), 'My Second Line123');
|
assert.equal(model.getLineContent(2), 'My Second Line123');
|
||||||
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 2) });
|
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 2) });
|
||||||
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), 'M y Second Line123');
|
assert.equal(model.getLineContent(2), 'M y Second Line123');
|
||||||
cursorCommand(cursor, H.Undo, null, 'keyboard');
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
|
|
||||||
// Tab on column 3
|
// Tab on column 3
|
||||||
assert.equal(model.getLineContent(2), 'My Second Line123');
|
assert.equal(model.getLineContent(2), 'My Second Line123');
|
||||||
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 3) });
|
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 3) });
|
||||||
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), 'My Second Line123');
|
assert.equal(model.getLineContent(2), 'My Second Line123');
|
||||||
cursorCommand(cursor, H.Undo, null, 'keyboard');
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
|
|
||||||
// Tab on column 4
|
// Tab on column 4
|
||||||
assert.equal(model.getLineContent(2), 'My Second Line123');
|
assert.equal(model.getLineContent(2), 'My Second Line123');
|
||||||
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 4) });
|
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 4) });
|
||||||
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), 'My Second Line123');
|
assert.equal(model.getLineContent(2), 'My Second Line123');
|
||||||
cursorCommand(cursor, H.Undo, null, 'keyboard');
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
|
|
||||||
// Tab on column 5
|
// Tab on column 5
|
||||||
assert.equal(model.getLineContent(2), 'My Second Line123');
|
assert.equal(model.getLineContent(2), 'My Second Line123');
|
||||||
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 5) });
|
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 5) });
|
||||||
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), 'My S econd Line123');
|
assert.equal(model.getLineContent(2), 'My S econd Line123');
|
||||||
cursorCommand(cursor, H.Undo, null, 'keyboard');
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
|
|
||||||
// Tab on column 5
|
// Tab on column 5
|
||||||
assert.equal(model.getLineContent(2), 'My Second Line123');
|
assert.equal(model.getLineContent(2), 'My Second Line123');
|
||||||
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 5) });
|
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 5) });
|
||||||
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), 'My S econd Line123');
|
assert.equal(model.getLineContent(2), 'My S econd Line123');
|
||||||
cursorCommand(cursor, H.Undo, null, 'keyboard');
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
|
|
||||||
// Tab on column 13
|
// Tab on column 13
|
||||||
assert.equal(model.getLineContent(2), 'My Second Line123');
|
assert.equal(model.getLineContent(2), 'My Second Line123');
|
||||||
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 13) });
|
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursor, { position: new Position(2, 13) });
|
||||||
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
CoreEditingCommands.Tab.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), 'My Second Li ne123');
|
assert.equal(model.getLineContent(2), 'My Second Li ne123');
|
||||||
cursorCommand(cursor, H.Undo, null, 'keyboard');
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
|
|
||||||
// Tab on column 14
|
// Tab on column 14
|
||||||
assert.equal(model.getLineContent(2), 'My Second Line123');
|
assert.equal(model.getLineContent(2), 'My Second Line123');
|
||||||
@@ -2774,7 +2772,7 @@ suite('Editor Controller - Cursor Configuration', () => {
|
|||||||
assert.equal(model.getLineContent(2), 'a ');
|
assert.equal(model.getLineContent(2), 'a ');
|
||||||
|
|
||||||
// Undo DeleteLeft - get us back to original indentation
|
// Undo DeleteLeft - get us back to original indentation
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), ' a ');
|
assert.equal(model.getLineContent(2), ' a ');
|
||||||
|
|
||||||
// Nothing is broken when cursor is in (1,1)
|
// Nothing is broken when cursor is in (1,1)
|
||||||
@@ -2859,22 +2857,22 @@ suite('Editor Controller - Cursor Configuration', () => {
|
|||||||
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert10');
|
assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert10');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\nx', 'assert11');
|
assert.equal(model.getValue(EndOfLinePreference.LF), '\nx', 'assert11');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\nx', 'assert12');
|
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\nx', 'assert12');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\n\tx', 'assert13');
|
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\n\tx', 'assert13');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Redo, {});
|
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\nx', 'assert14');
|
assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\nx', 'assert14');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Redo, {});
|
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), '\nx', 'assert15');
|
assert.equal(model.getValue(EndOfLinePreference.LF), '\nx', 'assert15');
|
||||||
|
|
||||||
cursorCommand(cursor, H.Redo, {});
|
CoreEditingCommands.Redo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert16');
|
assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert16');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2895,7 +2893,7 @@ suite('Editor Controller - Cursor Configuration', () => {
|
|||||||
const beforeVersion = model.getVersionId();
|
const beforeVersion = model.getVersionId();
|
||||||
const beforeAltVersion = model.getAlternativeVersionId();
|
const beforeAltVersion = model.getAlternativeVersionId();
|
||||||
cursorCommand(cursor, H.Type, { text: 'Hello' }, 'keyboard');
|
cursorCommand(cursor, H.Type, { text: 'Hello' }, 'keyboard');
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
const afterVersion = model.getVersionId();
|
const afterVersion = model.getVersionId();
|
||||||
const afterAltVersion = model.getAlternativeVersionId();
|
const afterAltVersion = model.getAlternativeVersionId();
|
||||||
|
|
||||||
@@ -4263,7 +4261,7 @@ suite('autoClosingPairs', () => {
|
|||||||
moveTo(cursor, lineNumber, column);
|
moveTo(cursor, lineNumber, column);
|
||||||
cursorCommand(cursor, H.Type, { text: chr }, 'keyboard');
|
cursorCommand(cursor, H.Type, { text: chr }, 'keyboard');
|
||||||
assert.deepEqual(model.getLineContent(lineNumber), expected, message);
|
assert.deepEqual(model.getLineContent(lineNumber), expected, message);
|
||||||
cursorCommand(cursor, H.Undo);
|
model.undo();
|
||||||
}
|
}
|
||||||
|
|
||||||
test('open parens: default', () => {
|
test('open parens: default', () => {
|
||||||
@@ -5347,11 +5345,11 @@ suite('Undo stops', () => {
|
|||||||
assert.equal(model.getLineContent(1), 'A fir line');
|
assert.equal(model.getLineContent(1), 'A fir line');
|
||||||
assertCursor(cursor, new Selection(1, 6, 1, 6));
|
assertCursor(cursor, new Selection(1, 6, 1, 6));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'A first line');
|
assert.equal(model.getLineContent(1), 'A first line');
|
||||||
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'A line');
|
assert.equal(model.getLineContent(1), 'A line');
|
||||||
assertCursor(cursor, new Selection(1, 3, 1, 3));
|
assertCursor(cursor, new Selection(1, 3, 1, 3));
|
||||||
});
|
});
|
||||||
@@ -5376,11 +5374,11 @@ suite('Undo stops', () => {
|
|||||||
assert.equal(model.getLineContent(1), 'A firstine');
|
assert.equal(model.getLineContent(1), 'A firstine');
|
||||||
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'A first line');
|
assert.equal(model.getLineContent(1), 'A first line');
|
||||||
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'A line');
|
assert.equal(model.getLineContent(1), 'A line');
|
||||||
assertCursor(cursor, new Selection(1, 3, 1, 3));
|
assertCursor(cursor, new Selection(1, 3, 1, 3));
|
||||||
});
|
});
|
||||||
@@ -5410,11 +5408,11 @@ suite('Undo stops', () => {
|
|||||||
assert.equal(model.getLineContent(2), 'Second line');
|
assert.equal(model.getLineContent(2), 'Second line');
|
||||||
assertCursor(cursor, new Selection(2, 7, 2, 7));
|
assertCursor(cursor, new Selection(2, 7, 2, 7));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), ' line');
|
assert.equal(model.getLineContent(2), ' line');
|
||||||
assertCursor(cursor, new Selection(2, 1, 2, 1));
|
assertCursor(cursor, new Selection(2, 1, 2, 1));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), 'Another line');
|
assert.equal(model.getLineContent(2), 'Another line');
|
||||||
assertCursor(cursor, new Selection(2, 8, 2, 8));
|
assertCursor(cursor, new Selection(2, 8, 2, 8));
|
||||||
});
|
});
|
||||||
@@ -5448,11 +5446,11 @@ suite('Undo stops', () => {
|
|||||||
assert.equal(model.getLineContent(2), '');
|
assert.equal(model.getLineContent(2), '');
|
||||||
assertCursor(cursor, new Selection(2, 1, 2, 1));
|
assertCursor(cursor, new Selection(2, 1, 2, 1));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), ' line');
|
assert.equal(model.getLineContent(2), ' line');
|
||||||
assertCursor(cursor, new Selection(2, 1, 2, 1));
|
assertCursor(cursor, new Selection(2, 1, 2, 1));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), 'Another line');
|
assert.equal(model.getLineContent(2), 'Another line');
|
||||||
assertCursor(cursor, new Selection(2, 8, 2, 8));
|
assertCursor(cursor, new Selection(2, 8, 2, 8));
|
||||||
});
|
});
|
||||||
@@ -5479,11 +5477,11 @@ suite('Undo stops', () => {
|
|||||||
assert.equal(model.getLineContent(2), 'Another text');
|
assert.equal(model.getLineContent(2), 'Another text');
|
||||||
assertCursor(cursor, new Selection(2, 13, 2, 13));
|
assertCursor(cursor, new Selection(2, 13, 2, 13));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), 'Another ');
|
assert.equal(model.getLineContent(2), 'Another ');
|
||||||
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), 'Another line');
|
assert.equal(model.getLineContent(2), 'Another line');
|
||||||
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
||||||
});
|
});
|
||||||
@@ -5515,11 +5513,11 @@ suite('Undo stops', () => {
|
|||||||
assert.equal(model.getLineContent(2), 'An');
|
assert.equal(model.getLineContent(2), 'An');
|
||||||
assertCursor(cursor, new Selection(2, 3, 2, 3));
|
assertCursor(cursor, new Selection(2, 3, 2, 3));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), 'Another ');
|
assert.equal(model.getLineContent(2), 'Another ');
|
||||||
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(2), 'Another line');
|
assert.equal(model.getLineContent(2), 'Another line');
|
||||||
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
assertCursor(cursor, new Selection(2, 9, 2, 9));
|
||||||
});
|
});
|
||||||
@@ -5539,15 +5537,15 @@ suite('Undo stops', () => {
|
|||||||
assert.equal(model.getLineContent(1), 'A first and interesting line');
|
assert.equal(model.getLineContent(1), 'A first and interesting line');
|
||||||
assertCursor(cursor, new Selection(1, 24, 1, 24));
|
assertCursor(cursor, new Selection(1, 24, 1, 24));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'A first and line');
|
assert.equal(model.getLineContent(1), 'A first and line');
|
||||||
assertCursor(cursor, new Selection(1, 12, 1, 12));
|
assertCursor(cursor, new Selection(1, 12, 1, 12));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'A first line');
|
assert.equal(model.getLineContent(1), 'A first line');
|
||||||
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
assertCursor(cursor, new Selection(1, 8, 1, 8));
|
||||||
|
|
||||||
cursorCommand(cursor, H.Undo, {});
|
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||||
assert.equal(model.getLineContent(1), 'A line');
|
assert.equal(model.getLineContent(1), 'A line');
|
||||||
assertCursor(cursor, new Selection(1, 3, 1, 3));
|
assertCursor(cursor, new Selection(1, 3, 1, 3));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ export function withTestCodeEditor(text: string | string[] | null, options: Test
|
|||||||
}
|
}
|
||||||
|
|
||||||
let editor = <TestCodeEditor>createTestCodeEditor(options);
|
let editor = <TestCodeEditor>createTestCodeEditor(options);
|
||||||
|
editor.getCursor()!.setHasFocus(true);
|
||||||
callback(editor, editor.getCursor()!);
|
callback(editor, editor.getCursor()!);
|
||||||
|
|
||||||
editor.dispose();
|
editor.dispose();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvent
|
|||||||
import { assertSyncedModels, testApplyEditsWithSyncedModels } from 'vs/editor/test/common/model/editableTextModelTestUtils';
|
import { assertSyncedModels, testApplyEditsWithSyncedModels } from 'vs/editor/test/common/model/editableTextModelTestUtils';
|
||||||
|
|
||||||
function createEditableTextModelFromString(text: string): TextModel {
|
function createEditableTextModelFromString(text: string): TextModel {
|
||||||
return new TextModel(text, TextModel.DEFAULT_CREATION_OPTIONS, null);
|
return TextModel.createFromString(text, TextModel.DEFAULT_CREATION_OPTIONS, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
suite('EditorModel - EditableTextModel.applyEdits updates mightContainRTL', () => {
|
suite('EditorModel - EditableTextModel.applyEdits updates mightContainRTL', () => {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ function assertLineMapping(model: TextModel, msg: string): void {
|
|||||||
|
|
||||||
|
|
||||||
export function assertSyncedModels(text: string, callback: (model: TextModel, assertMirrorModels: () => void) => void, setup: ((model: TextModel) => void) | null = null): void {
|
export function assertSyncedModels(text: string, callback: (model: TextModel, assertMirrorModels: () => void) => void, setup: ((model: TextModel) => void) | null = null): void {
|
||||||
let model = new TextModel(text, TextModel.DEFAULT_CREATION_OPTIONS, null);
|
let model = TextModel.createFromString(text, TextModel.DEFAULT_CREATION_OPTIONS, null);
|
||||||
model.setEOL(EndOfLineSequence.LF);
|
model.setEOL(EndOfLineSequence.LF);
|
||||||
assertLineMapping(model, 'model');
|
assertLineMapping(model, 'model');
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ suite('ModelLinesTokens', () => {
|
|||||||
|
|
||||||
function testApplyEdits(initial: IBufferLineState[], edits: IEdit[], expected: IBufferLineState[]): void {
|
function testApplyEdits(initial: IBufferLineState[], edits: IEdit[], expected: IBufferLineState[]): void {
|
||||||
const initialText = initial.map(el => el.text).join('\n');
|
const initialText = initial.map(el => el.text).join('\n');
|
||||||
const model = new TextModel(initialText, TextModel.DEFAULT_CREATION_OPTIONS, new LanguageIdentifier('test', 0));
|
const model = TextModel.createFromString(initialText, TextModel.DEFAULT_CREATION_OPTIONS, new LanguageIdentifier('test', 0));
|
||||||
for (let lineIndex = 0; lineIndex < initial.length; lineIndex++) {
|
for (let lineIndex = 0; lineIndex < initial.length; lineIndex++) {
|
||||||
const lineTokens = initial[lineIndex].tokens;
|
const lineTokens = initial[lineIndex].tokens;
|
||||||
const lineTextLength = model.getLineMaxColumn(lineIndex + 1) - 1;
|
const lineTextLength = model.getLineMaxColumn(lineIndex + 1) - 1;
|
||||||
@@ -442,7 +442,7 @@ suite('ModelLinesTokens', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test('insertion on empty line', () => {
|
test('insertion on empty line', () => {
|
||||||
const model = new TextModel('some text', TextModel.DEFAULT_CREATION_OPTIONS, new LanguageIdentifier('test', 0));
|
const model = TextModel.createFromString('some text', TextModel.DEFAULT_CREATION_OPTIONS, new LanguageIdentifier('test', 0));
|
||||||
const tokens = TestToken.toTokens([new TestToken(0, 1)]);
|
const tokens = TestToken.toTokens([new TestToken(0, 1)]);
|
||||||
LineTokens.convertToEndOffset(tokens, model.getLineMaxColumn(1) - 1);
|
LineTokens.convertToEndOffset(tokens, model.getLineMaxColumn(1) - 1);
|
||||||
model.setLineTokens(1, tokens);
|
model.setLineTokens(1, tokens);
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ suite('TextModelWithTokens', () => {
|
|||||||
brackets: brackets
|
brackets: brackets
|
||||||
});
|
});
|
||||||
|
|
||||||
let model = new TextModel(
|
let model = TextModel.createFromString(
|
||||||
contents.join('\n'),
|
contents.join('\n'),
|
||||||
TextModel.DEFAULT_CREATION_OPTIONS,
|
TextModel.DEFAULT_CREATION_OPTIONS,
|
||||||
languageIdentifier
|
languageIdentifier
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
|||||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||||
import { NullLogService } from 'vs/platform/log/common/log';
|
import { NullLogService } from 'vs/platform/log/common/log';
|
||||||
|
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
|
||||||
|
|
||||||
const GENERATE_TESTS = false;
|
const GENERATE_TESTS = false;
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ suite('ModelService', () => {
|
|||||||
configService.setUserConfiguration('files', { 'eol': '\n' });
|
configService.setUserConfiguration('files', { 'eol': '\n' });
|
||||||
configService.setUserConfiguration('files', { 'eol': '\r\n' }, URI.file(platform.isWindows ? 'c:\\myroot' : '/myroot'));
|
configService.setUserConfiguration('files', { 'eol': '\r\n' }, URI.file(platform.isWindows ? 'c:\\myroot' : '/myroot'));
|
||||||
|
|
||||||
modelService = new ModelServiceImpl(configService, new TestTextResourcePropertiesService(configService), new TestThemeService(), new NullLogService());
|
modelService = new ModelServiceImpl(configService, new TestTextResourcePropertiesService(configService), new TestThemeService(), new NullLogService(), new UndoRedoService());
|
||||||
});
|
});
|
||||||
|
|
||||||
teardown(() => {
|
teardown(() => {
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
|
|||||||
outerWidth: input.outerWidth,
|
outerWidth: input.outerWidth,
|
||||||
outerHeight: input.outerHeight,
|
outerHeight: input.outerHeight,
|
||||||
lineHeight: input.lineHeight,
|
lineHeight: input.lineHeight,
|
||||||
maxLineNumber: input.maxLineNumber || Math.pow(10, input.lineNumbersDigitCount) - 1,
|
viewLineCount: input.maxLineNumber || Math.pow(10, input.lineNumbersDigitCount) - 1,
|
||||||
lineNumbersDigitCount: input.lineNumbersDigitCount,
|
lineNumbersDigitCount: input.lineNumbersDigitCount,
|
||||||
typicalHalfwidthCharacterWidth: input.typicalHalfwidthCharacterWidth,
|
typicalHalfwidthCharacterWidth: input.typicalHalfwidthCharacterWidth,
|
||||||
maxDigitWidth: input.maxDigitWidth,
|
maxDigitWidth: input.maxDigitWidth,
|
||||||
|
|||||||
+5
-1
@@ -923,7 +923,11 @@ var AMDLoader;
|
|||||||
var hashDataNow = _this._crypto.createHash('md5').update(scriptSource, 'utf8').digest();
|
var hashDataNow = _this._crypto.createHash('md5').update(scriptSource, 'utf8').digest();
|
||||||
if (!hashData.equals(hashDataNow)) {
|
if (!hashData.equals(hashDataNow)) {
|
||||||
moduleManager.getConfig().onError(new Error("FAILED TO VERIFY CACHED DATA, deleting stale '" + cachedDataPath + "' now, but a RESTART IS REQUIRED"));
|
moduleManager.getConfig().onError(new Error("FAILED TO VERIFY CACHED DATA, deleting stale '" + cachedDataPath + "' now, but a RESTART IS REQUIRED"));
|
||||||
_this._fs.unlink(cachedDataPath, function (err) { return moduleManager.getConfig().onError(err); });
|
_this._fs.unlink(cachedDataPath, function (err) {
|
||||||
|
if (err) {
|
||||||
|
moduleManager.getConfig().onError(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, Math.ceil(5000 * (1 + Math.random())));
|
}, Math.ceil(5000 * (1 + Math.random())));
|
||||||
};
|
};
|
||||||
|
|||||||
Vendored
+5
@@ -2307,6 +2307,11 @@ declare namespace monaco.editor {
|
|||||||
* optimized for viewing a code definition.
|
* optimized for viewing a code definition.
|
||||||
*/
|
*/
|
||||||
revealRangeNearTop(range: IRange, scrollType?: ScrollType): void;
|
revealRangeNearTop(range: IRange, scrollType?: ScrollType): void;
|
||||||
|
/**
|
||||||
|
* Scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport,
|
||||||
|
* optimized for viewing a code definition. Only if it lies outside the viewport.
|
||||||
|
*/
|
||||||
|
revealRangeNearTopIfOutsideViewport(range: IRange, scrollType?: ScrollType): void;
|
||||||
/**
|
/**
|
||||||
* Directly trigger a handler or an editor action.
|
* Directly trigger a handler or an editor action.
|
||||||
* @param source The source of the call.
|
* @param source The source of the call.
|
||||||
|
|||||||
+16
-2
@@ -3,11 +3,24 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { IUserDataAuthTokenService } from 'vs/platform/userDataSync/common/userDataSync';
|
|
||||||
|
|
||||||
export class UserDataAuthTokenService extends Disposable implements IUserDataAuthTokenService {
|
export const IAuthenticationTokenService = createDecorator<IAuthenticationTokenService>('IAuthenticationTokenService');
|
||||||
|
|
||||||
|
export interface IAuthenticationTokenService {
|
||||||
|
_serviceBrand: undefined;
|
||||||
|
|
||||||
|
readonly onDidChangeToken: Event<string | undefined>;
|
||||||
|
readonly onTokenFailed: Event<void>;
|
||||||
|
|
||||||
|
getToken(): Promise<string | undefined>;
|
||||||
|
setToken(accessToken: string | undefined): Promise<void>;
|
||||||
|
sendTokenFailed(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AuthenticationTokenService extends Disposable implements IAuthenticationTokenService {
|
||||||
|
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
|
|
||||||
@@ -38,3 +51,4 @@ export class UserDataAuthTokenService extends Disposable implements IUserDataAut
|
|||||||
this._onTokenFailed.fire();
|
this._onTokenFailed.fire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||||
|
import { Event } from 'vs/base/common/event';
|
||||||
|
import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication';
|
||||||
|
|
||||||
|
|
||||||
|
export class AuthenticationTokenServiceChannel implements IServerChannel {
|
||||||
|
constructor(private readonly service: IAuthenticationTokenService) { }
|
||||||
|
|
||||||
|
listen(_: unknown, event: string): Event<any> {
|
||||||
|
switch (event) {
|
||||||
|
case 'onDidChangeToken': return this.service.onDidChangeToken;
|
||||||
|
case 'onTokenFailed': return this.service.onTokenFailed;
|
||||||
|
}
|
||||||
|
throw new Error(`Event not found: ${event}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
call(context: any, command: string, args?: any): Promise<any> {
|
||||||
|
switch (command) {
|
||||||
|
case 'setToken': return this.service.setToken(args);
|
||||||
|
case 'getToken': return this.service.getToken();
|
||||||
|
}
|
||||||
|
throw new Error('Invalid call');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -113,6 +113,7 @@ export interface IConfigurationPropertySchema extends IJSONSchema {
|
|||||||
scope?: ConfigurationScope;
|
scope?: ConfigurationScope;
|
||||||
included?: boolean;
|
included?: boolean;
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
|
disallowSyncIgnore?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IConfigurationExtensionInfo {
|
export interface IConfigurationExtensionInfo {
|
||||||
|
|||||||
@@ -228,6 +228,11 @@ export const enum TextEditorSelectionRevealType {
|
|||||||
* Option to scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport, but not quite at the top.
|
* Option to scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport, but not quite at the top.
|
||||||
*/
|
*/
|
||||||
NearTop = 2,
|
NearTop = 2,
|
||||||
|
/**
|
||||||
|
* Option to scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport, but not quite at the top.
|
||||||
|
* Only if it lies outside the viewport
|
||||||
|
*/
|
||||||
|
NearTopIfOutsideViewport = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITextEditorOptions extends IEditorOptions {
|
export interface ITextEditorOptions extends IEditorOptions {
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ export interface IssueReporterData extends WindowData {
|
|||||||
enabledExtensions: IssueReporterExtensionData[];
|
enabledExtensions: IssueReporterExtensionData[];
|
||||||
issueType?: IssueType;
|
issueType?: IssueType;
|
||||||
extensionId?: string;
|
extensionId?: string;
|
||||||
|
readonly issueTitle?: string;
|
||||||
|
readonly issueBody?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISettingSearchResult {
|
export interface ISettingSearchResult {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export enum RemoteAuthorityResolverErrorCode {
|
|||||||
Unknown = 'Unknown',
|
Unknown = 'Unknown',
|
||||||
NotAvailable = 'NotAvailable',
|
NotAvailable = 'NotAvailable',
|
||||||
TemporarilyNotAvailable = 'TemporarilyNotAvailable',
|
TemporarilyNotAvailable = 'TemporarilyNotAvailable',
|
||||||
|
NoResolverFound = 'NoResolverFound'
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RemoteAuthorityResolverError extends Error {
|
export class RemoteAuthorityResolverError extends Error {
|
||||||
@@ -50,10 +51,11 @@ export class RemoteAuthorityResolverError extends Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static isTemporarilyNotAvailable(err: any): boolean {
|
public static isTemporarilyNotAvailable(err: any): boolean {
|
||||||
if (err instanceof RemoteAuthorityResolverError) {
|
return (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable;
|
||||||
return err._code === RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable;
|
}
|
||||||
}
|
|
||||||
return false;
|
public static isNoResolverFound(err: any): boolean {
|
||||||
|
return (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.NoResolverFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly _message: string | undefined;
|
public readonly _message: string | undefined;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export interface IUndoRedoElement {
|
|||||||
/**
|
/**
|
||||||
* None, one or multiple resources that this undo/redo element impacts.
|
* None, one or multiple resources that this undo/redo element impacts.
|
||||||
*/
|
*/
|
||||||
readonly resources: URI[];
|
readonly resources: readonly URI[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The label of the undo/redo element.
|
* The label of the undo/redo element.
|
||||||
@@ -43,7 +43,7 @@ export interface IUndoRedoElement {
|
|||||||
* Invalidate the edits concerning `resource`.
|
* Invalidate the edits concerning `resource`.
|
||||||
* i.e. the undo/redo stack for that particular resource has been destroyed.
|
* i.e. the undo/redo stack for that particular resource has been destroyed.
|
||||||
*/
|
*/
|
||||||
invalidate(resource: URI): boolean;
|
invalidate(resource: URI): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUndoRedoService {
|
export interface IUndoRedoService {
|
||||||
|
|||||||
@@ -7,11 +7,12 @@ import { IUndoRedoService, IUndoRedoElement } from 'vs/platform/undoRedo/common/
|
|||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { getComparisonKey as uriGetComparisonKey } from 'vs/base/common/resources';
|
import { getComparisonKey as uriGetComparisonKey } from 'vs/base/common/resources';
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
|
|
||||||
class StackElement {
|
class StackElement {
|
||||||
public readonly actual: IUndoRedoElement;
|
public readonly actual: IUndoRedoElement;
|
||||||
public readonly label: string;
|
public readonly label: string;
|
||||||
public readonly resources: URI[];
|
public readonly resources: readonly URI[];
|
||||||
public readonly strResources: string[];
|
public readonly strResources: string[];
|
||||||
|
|
||||||
constructor(actual: IUndoRedoElement) {
|
constructor(actual: IUndoRedoElement) {
|
||||||
@@ -179,7 +180,7 @@ export class UndoRedoService implements IUndoRedoService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
redo(resource: URI): void {
|
public redo(resource: URI): void {
|
||||||
const strResource = uriGetComparisonKey(resource);
|
const strResource = uriGetComparisonKey(resource);
|
||||||
if (!this._editStacks.has(strResource)) {
|
if (!this._editStacks.has(strResource)) {
|
||||||
return;
|
return;
|
||||||
@@ -239,3 +240,5 @@ export class UndoRedoService implements IUndoRedoService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerSingleton(IUndoRedoService, UndoRedoService);
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import { FormattingOptions } from 'vs/base/common/jsonFormatter';
|
|||||||
import { IStringDictionary } from 'vs/base/common/collections';
|
import { IStringDictionary } from 'vs/base/common/collections';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
|
|
||||||
|
const BACK_UP_MAX_AGE = 1000 * 60 * 60 * 24 * 30; /* 30 days */
|
||||||
|
|
||||||
type SyncSourceClassification = {
|
type SyncSourceClassification = {
|
||||||
source?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
|
source?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
|
||||||
};
|
};
|
||||||
@@ -68,6 +70,7 @@ export abstract class AbstractSynchroniser extends Disposable {
|
|||||||
this.syncFolder = joinPath(environmentService.userDataSyncHome, source);
|
this.syncFolder = joinPath(environmentService.userDataSyncHome, source);
|
||||||
this.lastSyncResource = joinPath(this.syncFolder, `.lastSync${source}.json`);
|
this.lastSyncResource = joinPath(this.syncFolder, `.lastSync${source}.json`);
|
||||||
this.cleanUpDelayer = new ThrottledDelayer(50);
|
this.cleanUpDelayer = new ThrottledDelayer(50);
|
||||||
|
this.cleanUpBackup();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected setStatus(status: SyncStatus): void {
|
protected setStatus(status: SyncStatus): void {
|
||||||
@@ -195,9 +198,24 @@ export abstract class AbstractSynchroniser extends Disposable {
|
|||||||
private async cleanUpBackup(): Promise<void> {
|
private async cleanUpBackup(): Promise<void> {
|
||||||
const stat = await this.fileService.resolve(this.syncFolder);
|
const stat = await this.fileService.resolve(this.syncFolder);
|
||||||
if (stat.children) {
|
if (stat.children) {
|
||||||
const all = stat.children.filter(stat => stat.isFile && /^\d{8}T\d{6}$/.test(stat.name)).sort();
|
const toDelete = stat.children.filter(stat => {
|
||||||
const toDelete = all.slice(0, Math.max(0, all.length - 9));
|
if (stat.isFile && /^\d{8}T\d{6}$/.test(stat.name)) {
|
||||||
await Promise.all(toDelete.map(stat => this.fileService.del(stat.resource)));
|
const ctime = stat.ctime || new Date(
|
||||||
|
parseInt(stat.name.substring(0, 4)),
|
||||||
|
parseInt(stat.name.substring(4, 6)) - 1,
|
||||||
|
parseInt(stat.name.substring(6, 8)),
|
||||||
|
parseInt(stat.name.substring(9, 11)),
|
||||||
|
parseInt(stat.name.substring(11, 13)),
|
||||||
|
parseInt(stat.name.substring(13, 15))
|
||||||
|
).getTime();
|
||||||
|
return Date.now() - ctime > BACK_UP_MAX_AGE;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
await Promise.all(toDelete.map(stat => {
|
||||||
|
this.logService.info('Deleting from backup', stat.resource.path);
|
||||||
|
this.fileService.del(stat.resource);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// massage incoming extension - add disabled property
|
||||||
|
const massageIncomingExtension = (extension: ISyncExtension): ISyncExtension => ({ ...extension, ...{ disabled: !!extension.disabled } });
|
||||||
|
localExtensions = localExtensions.map(massageIncomingExtension);
|
||||||
|
remoteExtensions = remoteExtensions.map(massageIncomingExtension);
|
||||||
|
lastSyncExtensions = lastSyncExtensions ? lastSyncExtensions.map(massageIncomingExtension) : null;
|
||||||
|
|
||||||
const uuids: Map<string, string> = new Map<string, string>();
|
const uuids: Map<string, string> = new Map<string, string>();
|
||||||
const addUUID = (identifier: IExtensionIdentifier) => { if (identifier.uuid) { uuids.set(identifier.id.toLowerCase(), identifier.uuid); } };
|
const addUUID = (identifier: IExtensionIdentifier) => { if (identifier.uuid) { uuids.set(identifier.id.toLowerCase(), identifier.uuid); } };
|
||||||
localExtensions.forEach(({ identifier }) => addUUID(identifier));
|
localExtensions.forEach(({ identifier }) => addUUID(identifier));
|
||||||
@@ -37,10 +43,12 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync
|
|||||||
lastSyncExtensions.forEach(({ identifier }) => addUUID(identifier));
|
lastSyncExtensions.forEach(({ identifier }) => addUUID(identifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
const addExtensionToMap = (map: Map<string, ISyncExtension>, extension: ISyncExtension) => {
|
const getKey = (extension: ISyncExtension): string => {
|
||||||
const uuid = extension.identifier.uuid || uuids.get(extension.identifier.id.toLowerCase());
|
const uuid = extension.identifier.uuid || uuids.get(extension.identifier.id.toLowerCase());
|
||||||
const key = uuid ? `uuid:${uuid}` : `id:${extension.identifier.id.toLowerCase()}`;
|
return uuid ? `uuid:${uuid}` : `id:${extension.identifier.id.toLowerCase()}`;
|
||||||
map.set(key, extension);
|
};
|
||||||
|
const addExtensionToMap = (map: Map<string, ISyncExtension>, extension: ISyncExtension) => {
|
||||||
|
map.set(getKey(extension), extension);
|
||||||
return map;
|
return map;
|
||||||
};
|
};
|
||||||
const localExtensionsMap = localExtensions.reduce(addExtensionToMap, new Map<string, ISyncExtension>());
|
const localExtensionsMap = localExtensions.reduce(addExtensionToMap, new Map<string, ISyncExtension>());
|
||||||
@@ -62,14 +70,17 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync
|
|||||||
const baseToLocal = compare(lastSyncExtensionsMap, localExtensionsMap, ignoredExtensionsSet);
|
const baseToLocal = compare(lastSyncExtensionsMap, localExtensionsMap, ignoredExtensionsSet);
|
||||||
const baseToRemote = compare(lastSyncExtensionsMap, remoteExtensionsMap, ignoredExtensionsSet);
|
const baseToRemote = compare(lastSyncExtensionsMap, remoteExtensionsMap, ignoredExtensionsSet);
|
||||||
|
|
||||||
const massageSyncExtension = (extension: ISyncExtension, key: string): ISyncExtension => {
|
// massage outgoing extension - remove disabled property
|
||||||
|
const massageOutgoingExtension = (extension: ISyncExtension, key: string): ISyncExtension => {
|
||||||
const massagedExtension: ISyncExtension = {
|
const massagedExtension: ISyncExtension = {
|
||||||
identifier: {
|
identifier: {
|
||||||
id: extension.identifier.id,
|
id: extension.identifier.id,
|
||||||
uuid: startsWith(key, 'uuid:') ? key.substring('uuid:'.length) : undefined
|
uuid: startsWith(key, 'uuid:') ? key.substring('uuid:'.length) : undefined
|
||||||
},
|
},
|
||||||
enabled: extension.enabled,
|
|
||||||
};
|
};
|
||||||
|
if (extension.disabled) {
|
||||||
|
massagedExtension.disabled = true;
|
||||||
|
}
|
||||||
if (extension.version) {
|
if (extension.version) {
|
||||||
massagedExtension.version = extension.version;
|
massagedExtension.version = extension.version;
|
||||||
}
|
}
|
||||||
@@ -90,25 +101,25 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync
|
|||||||
if (baseToLocal.added.has(key)) {
|
if (baseToLocal.added.has(key)) {
|
||||||
// Is different from local to remote
|
// Is different from local to remote
|
||||||
if (localToRemote.updated.has(key)) {
|
if (localToRemote.updated.has(key)) {
|
||||||
updated.push(massageSyncExtension(remoteExtensionsMap.get(key)!, key));
|
updated.push(massageOutgoingExtension(remoteExtensionsMap.get(key)!, key));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Add to local
|
// Add to local
|
||||||
added.push(massageSyncExtension(remoteExtensionsMap.get(key)!, key));
|
added.push(massageOutgoingExtension(remoteExtensionsMap.get(key)!, key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remotely updated extensions
|
// Remotely updated extensions
|
||||||
for (const key of values(baseToRemote.updated)) {
|
for (const key of values(baseToRemote.updated)) {
|
||||||
// Update in local always
|
// Update in local always
|
||||||
updated.push(massageSyncExtension(remoteExtensionsMap.get(key)!, key));
|
updated.push(massageOutgoingExtension(remoteExtensionsMap.get(key)!, key));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locally added extensions
|
// Locally added extensions
|
||||||
for (const key of values(baseToLocal.added)) {
|
for (const key of values(baseToLocal.added)) {
|
||||||
// Not there in remote
|
// Not there in remote
|
||||||
if (!baseToRemote.added.has(key)) {
|
if (!baseToRemote.added.has(key)) {
|
||||||
newRemoteExtensionsMap.set(key, massageSyncExtension(localExtensionsMap.get(key)!, key));
|
newRemoteExtensionsMap.set(key, localExtensionsMap.get(key)!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +132,7 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync
|
|||||||
|
|
||||||
// If not updated in remote
|
// If not updated in remote
|
||||||
if (!baseToRemote.updated.has(key)) {
|
if (!baseToRemote.updated.has(key)) {
|
||||||
newRemoteExtensionsMap.set(key, massageSyncExtension(localExtensionsMap.get(key)!, key));
|
newRemoteExtensionsMap.set(key, localExtensionsMap.get(key)!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,9 +144,13 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const remote: ISyncExtension[] = [];
|
||||||
const remoteChanges = compare(remoteExtensionsMap, newRemoteExtensionsMap, new Set<string>());
|
const remoteChanges = compare(remoteExtensionsMap, newRemoteExtensionsMap, new Set<string>());
|
||||||
const remote = remoteChanges.added.size > 0 || remoteChanges.updated.size > 0 || remoteChanges.removed.size > 0 ? values(newRemoteExtensionsMap) : null;
|
if (remoteChanges.added.size > 0 || remoteChanges.updated.size > 0 || remoteChanges.removed.size > 0) {
|
||||||
return { added, removed, updated, remote };
|
newRemoteExtensionsMap.forEach((value, key) => remote.push(massageOutgoingExtension(value, key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return { added, removed, updated, remote: remote.length ? remote : null };
|
||||||
}
|
}
|
||||||
|
|
||||||
function compare(from: Map<string, ISyncExtension> | null, to: Map<string, ISyncExtension>, ignoredExtensions: Set<string>): { added: Set<string>, removed: Set<string>, updated: Set<string> } {
|
function compare(from: Map<string, ISyncExtension> | null, to: Map<string, ISyncExtension>, ignoredExtensions: Set<string>): { added: Set<string>, removed: Set<string>, updated: Set<string> } {
|
||||||
@@ -152,7 +167,7 @@ function compare(from: Map<string, ISyncExtension> | null, to: Map<string, ISync
|
|||||||
const fromExtension = from!.get(key)!;
|
const fromExtension = from!.get(key)!;
|
||||||
const toExtension = to.get(key);
|
const toExtension = to.get(key);
|
||||||
if (!toExtension
|
if (!toExtension
|
||||||
|| fromExtension.enabled !== toExtension.enabled
|
|| fromExtension.disabled !== toExtension.disabled
|
||||||
|| fromExtension.version !== toExtension.version
|
|| fromExtension.version !== toExtension.version
|
||||||
) {
|
) {
|
||||||
updated.add(key);
|
updated.add(key);
|
||||||
|
|||||||
@@ -14,17 +14,19 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
|||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { merge } from 'vs/platform/userDataSync/common/extensionsMerge';
|
import { merge } from 'vs/platform/userDataSync/common/extensionsMerge';
|
||||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||||
import { AbstractSynchroniser, IRemoteUserData } from 'vs/platform/userDataSync/common/abstractSynchronizer';
|
import { AbstractSynchroniser, IRemoteUserData, ISyncData } from 'vs/platform/userDataSync/common/abstractSynchronizer';
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
|
|
||||||
interface ISyncPreviewResult {
|
interface ISyncPreviewResult {
|
||||||
|
readonly localExtensions: ISyncExtension[];
|
||||||
|
readonly remoteUserData: IRemoteUserData;
|
||||||
|
readonly lastSyncUserData: ILastSyncUserData | null;
|
||||||
readonly added: ISyncExtension[];
|
readonly added: ISyncExtension[];
|
||||||
readonly removed: IExtensionIdentifier[];
|
readonly removed: IExtensionIdentifier[];
|
||||||
readonly updated: ISyncExtension[];
|
readonly updated: ISyncExtension[];
|
||||||
readonly remote: ISyncExtension[] | null;
|
readonly remote: ISyncExtension[] | null;
|
||||||
readonly remoteUserData: IRemoteUserData;
|
|
||||||
readonly skippedExtensions: ISyncExtension[];
|
readonly skippedExtensions: ISyncExtension[];
|
||||||
readonly lastSyncUserData: ILastSyncUserData | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ILastSyncUserData extends IRemoteUserData {
|
interface ILastSyncUserData extends IRemoteUserData {
|
||||||
@@ -34,7 +36,7 @@ interface ILastSyncUserData extends IRemoteUserData {
|
|||||||
export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {
|
export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {
|
||||||
|
|
||||||
readonly resourceKey: ResourceKey = 'extensions';
|
readonly resourceKey: ResourceKey = 'extensions';
|
||||||
protected readonly version: number = 1;
|
protected readonly version: number = 2;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IEnvironmentService environmentService: IEnvironmentService,
|
@IEnvironmentService environmentService: IEnvironmentService,
|
||||||
@@ -75,9 +77,9 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
|||||||
|
|
||||||
if (remoteUserData.syncData !== null) {
|
if (remoteUserData.syncData !== null) {
|
||||||
const localExtensions = await this.getLocalExtensions();
|
const localExtensions = await this.getLocalExtensions();
|
||||||
const remoteExtensions: ISyncExtension[] = JSON.parse(remoteUserData.syncData.content);
|
const remoteExtensions = this.parseExtensions(remoteUserData.syncData);
|
||||||
const { added, updated, remote } = merge(localExtensions, remoteExtensions, [], [], this.getIgnoredExtensions());
|
const { added, updated, remote, removed } = merge(localExtensions, remoteExtensions, localExtensions, [], this.getIgnoredExtensions());
|
||||||
await this.apply({ added, removed: [], updated, remote, remoteUserData, skippedExtensions: [], lastSyncUserData });
|
await this.apply({ added, removed, updated, remote, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData });
|
||||||
}
|
}
|
||||||
|
|
||||||
// No remote exists to pull
|
// No remote exists to pull
|
||||||
@@ -107,7 +109,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
|||||||
const { added, removed, updated, remote } = merge(localExtensions, null, null, [], this.getIgnoredExtensions());
|
const { added, removed, updated, remote } = merge(localExtensions, null, null, [], this.getIgnoredExtensions());
|
||||||
const lastSyncUserData = await this.getLastSyncUserData<ILastSyncUserData>();
|
const lastSyncUserData = await this.getLastSyncUserData<ILastSyncUserData>();
|
||||||
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
|
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
|
||||||
await this.apply({ added, removed, updated, remote, remoteUserData, skippedExtensions: [], lastSyncUserData }, true);
|
await this.apply({ added, removed, updated, remote, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData }, true);
|
||||||
|
|
||||||
this.logService.info('Extensions: Finished pushing extensions.');
|
this.logService.info('Extensions: Finished pushing extensions.');
|
||||||
} finally {
|
} finally {
|
||||||
@@ -165,8 +167,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async getPreview(remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise<ISyncPreviewResult> {
|
private async getPreview(remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise<ISyncPreviewResult> {
|
||||||
const remoteExtensions: ISyncExtension[] = remoteUserData.syncData ? JSON.parse(remoteUserData.syncData.content) : null;
|
const remoteExtensions: ISyncExtension[] | null = remoteUserData.syncData ? this.parseExtensions(remoteUserData.syncData) : null;
|
||||||
const lastSyncExtensions: ISyncExtension[] | null = lastSyncUserData ? JSON.parse(lastSyncUserData.syncData!.content) : null;
|
const lastSyncExtensions: ISyncExtension[] | null = lastSyncUserData ? this.parseExtensions(lastSyncUserData.syncData!) : null;
|
||||||
const skippedExtensions: ISyncExtension[] = lastSyncUserData ? lastSyncUserData.skippedExtensions || [] : [];
|
const skippedExtensions: ISyncExtension[] = lastSyncUserData ? lastSyncUserData.skippedExtensions || [] : [];
|
||||||
|
|
||||||
const localExtensions = await this.getLocalExtensions();
|
const localExtensions = await this.getLocalExtensions();
|
||||||
@@ -179,14 +181,14 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
|||||||
|
|
||||||
const { added, removed, updated, remote } = merge(localExtensions, remoteExtensions, lastSyncExtensions, skippedExtensions, this.getIgnoredExtensions());
|
const { added, removed, updated, remote } = merge(localExtensions, remoteExtensions, lastSyncExtensions, skippedExtensions, this.getIgnoredExtensions());
|
||||||
|
|
||||||
return { added, removed, updated, remote, skippedExtensions, remoteUserData, lastSyncUserData };
|
return { added, removed, updated, remote, skippedExtensions, remoteUserData, localExtensions, lastSyncUserData };
|
||||||
}
|
}
|
||||||
|
|
||||||
private getIgnoredExtensions() {
|
private getIgnoredExtensions() {
|
||||||
return this.configurationService.getValue<string[]>('sync.ignoredExtensions') || [];
|
return this.configurationService.getValue<string[]>('sync.ignoredExtensions') || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private async apply({ added, removed, updated, remote, remoteUserData, skippedExtensions, lastSyncUserData }: ISyncPreviewResult, forcePush?: boolean): Promise<void> {
|
private async apply({ added, removed, updated, remote, remoteUserData, skippedExtensions, lastSyncUserData, localExtensions }: ISyncPreviewResult, forcePush?: boolean): Promise<void> {
|
||||||
|
|
||||||
const hasChanges = added.length || removed.length || updated.length || remote;
|
const hasChanges = added.length || removed.length || updated.length || remote;
|
||||||
|
|
||||||
@@ -195,6 +197,9 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (added.length || removed.length || updated.length) {
|
if (added.length || removed.length || updated.length) {
|
||||||
|
// back up all disabled or market place extensions
|
||||||
|
const backUpExtensions = localExtensions.filter(e => e.disabled || !!e.identifier.uuid);
|
||||||
|
await this.backupLocal(VSBuffer.fromString(JSON.stringify(backUpExtensions)));
|
||||||
skippedExtensions = await this.updateLocalExtensions(added, removed, updated, skippedExtensions);
|
skippedExtensions = await this.updateLocalExtensions(added, removed, updated, skippedExtensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,14 +241,14 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
|||||||
|
|
||||||
// Builtin Extension: Sync only enablement state
|
// Builtin Extension: Sync only enablement state
|
||||||
if (installedExtension && installedExtension.type === ExtensionType.System) {
|
if (installedExtension && installedExtension.type === ExtensionType.System) {
|
||||||
if (e.enabled) {
|
if (e.disabled) {
|
||||||
this.logService.trace('Extensions: Enabling extension...', e.identifier.id);
|
|
||||||
await this.extensionEnablementService.enableExtension(e.identifier);
|
|
||||||
this.logService.info('Extensions: Enabled extension', e.identifier.id);
|
|
||||||
} else {
|
|
||||||
this.logService.trace('Extensions: Disabling extension...', e.identifier.id);
|
this.logService.trace('Extensions: Disabling extension...', e.identifier.id);
|
||||||
await this.extensionEnablementService.disableExtension(e.identifier);
|
await this.extensionEnablementService.disableExtension(e.identifier);
|
||||||
this.logService.info('Extensions: Disabled extension', e.identifier.id);
|
this.logService.info('Extensions: Disabled extension', e.identifier.id);
|
||||||
|
} else {
|
||||||
|
this.logService.trace('Extensions: Enabling extension...', e.identifier.id);
|
||||||
|
await this.extensionEnablementService.enableExtension(e.identifier);
|
||||||
|
this.logService.info('Extensions: Enabled extension', e.identifier.id);
|
||||||
}
|
}
|
||||||
removeFromSkipped.push(e.identifier);
|
removeFromSkipped.push(e.identifier);
|
||||||
return;
|
return;
|
||||||
@@ -252,14 +257,14 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
|||||||
const extension = await this.extensionGalleryService.getCompatibleExtension(e.identifier, e.version);
|
const extension = await this.extensionGalleryService.getCompatibleExtension(e.identifier, e.version);
|
||||||
if (extension) {
|
if (extension) {
|
||||||
try {
|
try {
|
||||||
if (e.enabled) {
|
if (e.disabled) {
|
||||||
this.logService.trace('Extensions: Enabling extension...', e.identifier.id, extension.version);
|
|
||||||
await this.extensionEnablementService.enableExtension(extension.identifier);
|
|
||||||
this.logService.info('Extensions: Enabled extension', e.identifier.id, extension.version);
|
|
||||||
} else {
|
|
||||||
this.logService.trace('Extensions: Disabling extension...', e.identifier.id, extension.version);
|
this.logService.trace('Extensions: Disabling extension...', e.identifier.id, extension.version);
|
||||||
await this.extensionEnablementService.disableExtension(extension.identifier);
|
await this.extensionEnablementService.disableExtension(extension.identifier);
|
||||||
this.logService.info('Extensions: Disabled extension', e.identifier.id, extension.version);
|
this.logService.info('Extensions: Disabled extension', e.identifier.id, extension.version);
|
||||||
|
} else {
|
||||||
|
this.logService.trace('Extensions: Enabling extension...', e.identifier.id, extension.version);
|
||||||
|
await this.extensionEnablementService.enableExtension(extension.identifier);
|
||||||
|
this.logService.info('Extensions: Enabled extension', e.identifier.id, extension.version);
|
||||||
}
|
}
|
||||||
// Install only if the extension does not exist
|
// Install only if the extension does not exist
|
||||||
if (!installedExtension || installedExtension.manifest.version !== extension.version) {
|
if (!installedExtension || installedExtension.manifest.version !== extension.version) {
|
||||||
@@ -293,11 +298,33 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
|||||||
return newSkippedExtensions;
|
return newSkippedExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private parseExtensions(syncData: ISyncData): ISyncExtension[] {
|
||||||
|
let extensions: ISyncExtension[] = JSON.parse(syncData.content);
|
||||||
|
if (syncData.version !== this.version) {
|
||||||
|
extensions = extensions.map(e => {
|
||||||
|
// #region Migration from v1 (enabled -> disabled)
|
||||||
|
if (!(<any>e).enabled) {
|
||||||
|
e.disabled = true;
|
||||||
|
}
|
||||||
|
delete (<any>e).enabled;
|
||||||
|
// #endregion
|
||||||
|
return e;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
private async getLocalExtensions(): Promise<ISyncExtension[]> {
|
private async getLocalExtensions(): Promise<ISyncExtension[]> {
|
||||||
const installedExtensions = await this.extensionManagementService.getInstalled();
|
const installedExtensions = await this.extensionManagementService.getInstalled();
|
||||||
const disabledExtensions = await this.extensionEnablementService.getDisabledExtensions();
|
const disabledExtensions = this.extensionEnablementService.getDisabledExtensions();
|
||||||
return installedExtensions
|
return installedExtensions
|
||||||
.map(({ identifier }) => ({ identifier, enabled: !disabledExtensions.some(disabledExtension => areSameExtensions(disabledExtension, identifier)) }));
|
.map(({ identifier }) => {
|
||||||
|
const syncExntesion: ISyncExtension = { identifier };
|
||||||
|
if (disabledExtensions.some(disabledExtension => areSameExtensions(disabledExtension, identifier))) {
|
||||||
|
syncExntesion.disabled = true;
|
||||||
|
}
|
||||||
|
return syncExntesion;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const argvProperties: string[] = ['locale'];
|
|||||||
interface ISyncPreviewResult {
|
interface ISyncPreviewResult {
|
||||||
readonly local: IGlobalState | undefined;
|
readonly local: IGlobalState | undefined;
|
||||||
readonly remote: IGlobalState | undefined;
|
readonly remote: IGlobalState | undefined;
|
||||||
|
readonly localUserData: IGlobalState;
|
||||||
readonly remoteUserData: IRemoteUserData;
|
readonly remoteUserData: IRemoteUserData;
|
||||||
readonly lastSyncUserData: IRemoteUserData | null;
|
readonly lastSyncUserData: IRemoteUserData | null;
|
||||||
}
|
}
|
||||||
@@ -59,8 +60,9 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
|||||||
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
|
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
|
||||||
|
|
||||||
if (remoteUserData.syncData !== null) {
|
if (remoteUserData.syncData !== null) {
|
||||||
|
const localUserData = await this.getLocalGlobalState();
|
||||||
const local: IGlobalState = JSON.parse(remoteUserData.syncData.content);
|
const local: IGlobalState = JSON.parse(remoteUserData.syncData.content);
|
||||||
await this.apply({ local, remote: undefined, remoteUserData, lastSyncUserData });
|
await this.apply({ local, remote: undefined, remoteUserData, localUserData, lastSyncUserData });
|
||||||
}
|
}
|
||||||
|
|
||||||
// No remote exists to pull
|
// No remote exists to pull
|
||||||
@@ -86,10 +88,10 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
|||||||
this.logService.info('UI State: Started pushing UI State...');
|
this.logService.info('UI State: Started pushing UI State...');
|
||||||
this.setStatus(SyncStatus.Syncing);
|
this.setStatus(SyncStatus.Syncing);
|
||||||
|
|
||||||
const remote = await this.getLocalGlobalState();
|
const localUserData = await this.getLocalGlobalState();
|
||||||
const lastSyncUserData = await this.getLastSyncUserData();
|
const lastSyncUserData = await this.getLastSyncUserData();
|
||||||
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
|
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
|
||||||
await this.apply({ local: undefined, remote, remoteUserData, lastSyncUserData }, true);
|
await this.apply({ local: undefined, remote: localUserData, remoteUserData, localUserData, lastSyncUserData }, true);
|
||||||
|
|
||||||
this.logService.info('UI State: Finished pushing UI State.');
|
this.logService.info('UI State: Finished pushing UI State.');
|
||||||
} finally {
|
} finally {
|
||||||
@@ -152,10 +154,10 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
|||||||
|
|
||||||
const { local, remote } = merge(localGloablState, remoteGlobalState, lastSyncGlobalState);
|
const { local, remote } = merge(localGloablState, remoteGlobalState, lastSyncGlobalState);
|
||||||
|
|
||||||
return { local, remote, remoteUserData, lastSyncUserData };
|
return { local, remote, remoteUserData, localUserData: localGloablState, lastSyncUserData };
|
||||||
}
|
}
|
||||||
|
|
||||||
private async apply({ local, remote, remoteUserData, lastSyncUserData }: ISyncPreviewResult, forcePush?: boolean): Promise<void> {
|
private async apply({ local, remote, remoteUserData, lastSyncUserData, localUserData }: ISyncPreviewResult, forcePush?: boolean): Promise<void> {
|
||||||
|
|
||||||
const hasChanges = local || remote;
|
const hasChanges = local || remote;
|
||||||
|
|
||||||
@@ -166,6 +168,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
|||||||
if (local) {
|
if (local) {
|
||||||
// update local
|
// update local
|
||||||
this.logService.trace('UI State: Updating local ui state...');
|
this.logService.trace('UI State: Updating local ui state...');
|
||||||
|
await this.backupLocal(VSBuffer.fromString(JSON.stringify(localUserData)));
|
||||||
await this.writeLocalGlobalState(local);
|
await this.writeLocalGlobalState(local);
|
||||||
this.logService.info('UI State: Updated local ui state');
|
this.logService.info('UI State: Updated local ui state');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,9 +260,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
|
|||||||
|
|
||||||
if (content !== null) {
|
if (content !== null) {
|
||||||
|
|
||||||
if (this.hasErrors(content)) {
|
this.validateContent(content);
|
||||||
throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync settings as there are errors/warning in settings file."), UserDataSyncErrorCode.LocalInvalidContent, this.source);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasLocalChanged) {
|
if (hasLocalChanged) {
|
||||||
this.logService.trace('Settings: Updating local settings...');
|
this.logService.trace('Settings: Updating local settings...');
|
||||||
@@ -317,21 +315,14 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
|
|||||||
|
|
||||||
if (remoteSettingsSyncContent) {
|
if (remoteSettingsSyncContent) {
|
||||||
const localContent: string = fileContent ? fileContent.value.toString() : '{}';
|
const localContent: string = fileContent ? fileContent.value.toString() : '{}';
|
||||||
|
this.validateContent(localContent);
|
||||||
// No action when there are errors
|
this.logService.trace('Settings: Merging remote settings with local settings...');
|
||||||
if (this.hasErrors(localContent)) {
|
const result = merge(localContent, remoteSettingsSyncContent.settings, lastSettingsSyncContent ? lastSettingsSyncContent.settings : null, getIgnoredSettings(this.configurationService), resolvedConflicts, formattingOptions);
|
||||||
throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync settings as there are errors/warning in settings file."), UserDataSyncErrorCode.LocalInvalidContent, this.source);
|
content = result.localContent || result.remoteContent;
|
||||||
}
|
hasLocalChanged = result.localContent !== null;
|
||||||
|
hasRemoteChanged = result.remoteContent !== null;
|
||||||
else {
|
hasConflicts = result.hasConflicts;
|
||||||
this.logService.trace('Settings: Merging remote settings with local settings...');
|
conflictSettings = result.conflictsSettings;
|
||||||
const result = merge(localContent, remoteSettingsSyncContent.settings, lastSettingsSyncContent ? lastSettingsSyncContent.settings : null, getIgnoredSettings(this.configurationService), resolvedConflicts, formattingOptions);
|
|
||||||
content = result.localContent || result.remoteContent;
|
|
||||||
hasLocalChanged = result.localContent !== null;
|
|
||||||
hasRemoteChanged = result.remoteContent !== null;
|
|
||||||
hasConflicts = result.hasConflicts;
|
|
||||||
conflictSettings = result.conflictsSettings;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// First time syncing to remote
|
// First time syncing to remote
|
||||||
@@ -364,4 +355,10 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private validateContent(content: string): void {
|
||||||
|
if (this.hasErrors(content)) {
|
||||||
|
throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync settings as there are errors/warning in settings file."), UserDataSyncErrorCode.LocalInvalidContent, this.source);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
import { timeout, Delayer } from 'vs/base/common/async';
|
import { timeout, Delayer } from 'vs/base/common/async';
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { IUserDataSyncLogService, IUserDataSyncService, SyncStatus, IUserDataAuthTokenService, IUserDataAutoSyncService, UserDataSyncError, UserDataSyncErrorCode, SyncSource, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
|
import { IUserDataSyncLogService, IUserDataSyncService, SyncStatus, IUserDataAutoSyncService, UserDataSyncError, UserDataSyncErrorCode, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||||
|
import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication';
|
||||||
|
|
||||||
export class UserDataAutoSyncService extends Disposable implements IUserDataAutoSyncService {
|
export class UserDataAutoSyncService extends Disposable implements IUserDataAutoSyncService {
|
||||||
|
|
||||||
@@ -16,19 +17,19 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto
|
|||||||
private successiveFailures: number = 0;
|
private successiveFailures: number = 0;
|
||||||
private readonly syncDelayer: Delayer<void>;
|
private readonly syncDelayer: Delayer<void>;
|
||||||
|
|
||||||
private readonly _onError: Emitter<{ code: UserDataSyncErrorCode, source?: SyncSource }> = this._register(new Emitter<{ code: UserDataSyncErrorCode, source?: SyncSource }>());
|
private readonly _onError: Emitter<UserDataSyncError> = this._register(new Emitter<UserDataSyncError>());
|
||||||
readonly onError: Event<{ code: UserDataSyncErrorCode, source?: SyncSource }> = this._onError.event;
|
readonly onError: Event<UserDataSyncError> = this._onError.event;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IUserDataSyncEnablementService private readonly userDataSyncEnablementService: IUserDataSyncEnablementService,
|
@IUserDataSyncEnablementService private readonly userDataSyncEnablementService: IUserDataSyncEnablementService,
|
||||||
@IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService,
|
@IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService,
|
||||||
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
|
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
|
||||||
@IUserDataAuthTokenService private readonly userDataAuthTokenService: IUserDataAuthTokenService,
|
@IAuthenticationTokenService private readonly authTokenService: IAuthenticationTokenService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.updateEnablement(false, true);
|
this.updateEnablement(false, true);
|
||||||
this.syncDelayer = this._register(new Delayer<void>(0));
|
this.syncDelayer = this._register(new Delayer<void>(0));
|
||||||
this._register(Event.any<any>(userDataAuthTokenService.onDidChangeToken)(() => this.updateEnablement(true, true)));
|
this._register(Event.any<any>(authTokenService.onDidChangeToken)(() => this.updateEnablement(true, true)));
|
||||||
this._register(Event.any<any>(userDataSyncService.onDidChangeStatus)(() => this.updateEnablement(true, true)));
|
this._register(Event.any<any>(userDataSyncService.onDidChangeStatus)(() => this.updateEnablement(true, true)));
|
||||||
this._register(this.userDataSyncEnablementService.onDidChangeEnablement(() => this.updateEnablement(true, false)));
|
this._register(this.userDataSyncEnablementService.onDidChangeEnablement(() => this.updateEnablement(true, false)));
|
||||||
this._register(this.userDataSyncEnablementService.onDidChangeResourceEnablement(() => this.triggerAutoSync()));
|
this._register(this.userDataSyncEnablementService.onDidChangeResourceEnablement(() => this.triggerAutoSync()));
|
||||||
@@ -61,27 +62,23 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto
|
|||||||
await this.userDataSyncService.sync();
|
await this.userDataSyncService.sync();
|
||||||
this.resetFailures();
|
this.resetFailures();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.TurnedOff) {
|
const error = UserDataSyncError.toUserDataSyncError(e);
|
||||||
|
if (error.code === UserDataSyncErrorCode.TurnedOff || error.code === UserDataSyncErrorCode.SessionExpired) {
|
||||||
this.logService.info('Auto Sync: Sync is turned off in the cloud.');
|
this.logService.info('Auto Sync: Sync is turned off in the cloud.');
|
||||||
this.logService.info('Auto Sync: Resetting the local sync state.');
|
this.logService.info('Auto Sync: Resetting the local sync state.');
|
||||||
await this.userDataSyncService.resetLocal();
|
await this.userDataSyncService.resetLocal();
|
||||||
this.logService.info('Auto Sync: Completed resetting the local sync state.');
|
this.logService.info('Auto Sync: Completed resetting the local sync state.');
|
||||||
if (auto) {
|
if (auto) {
|
||||||
return this.userDataSyncEnablementService.setEnablement(false);
|
this.userDataSyncEnablementService.setEnablement(false);
|
||||||
|
this._onError.fire(error);
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
return this.sync(loop, auto);
|
return this.sync(loop, auto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.SessionExpired) {
|
this.logService.error(error);
|
||||||
this.logService.info('Auto Sync: Cloud has new session');
|
|
||||||
this.logService.info('Auto Sync: Resetting the local sync state.');
|
|
||||||
await this.userDataSyncService.resetLocal();
|
|
||||||
this.logService.info('Auto Sync: Completed resetting the local sync state.');
|
|
||||||
return this.sync(loop, auto);
|
|
||||||
}
|
|
||||||
this.logService.error(e);
|
|
||||||
this.successiveFailures++;
|
this.successiveFailures++;
|
||||||
this._onError.fire(e instanceof UserDataSyncError ? { code: e.code, source: e.source } : { code: UserDataSyncErrorCode.Unknown });
|
this._onError.fire(error);
|
||||||
}
|
}
|
||||||
if (loop) {
|
if (loop) {
|
||||||
await timeout(1000 * 60 * 5);
|
await timeout(1000 * 60 * 5);
|
||||||
@@ -95,7 +92,7 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto
|
|||||||
private async isAutoSyncEnabled(): Promise<boolean> {
|
private async isAutoSyncEnabled(): Promise<boolean> {
|
||||||
return this.userDataSyncEnablementService.isEnabled()
|
return this.userDataSyncEnablementService.isEnabled()
|
||||||
&& this.userDataSyncService.status !== SyncStatus.Uninitialized
|
&& this.userDataSyncService.status !== SyncStatus.Uninitialized
|
||||||
&& !!(await this.userDataAuthTokenService.getToken());
|
&& !!(await this.authTokenService.getToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
private resetFailures(): void {
|
private resetFailures(): void {
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export interface ISyncConfiguration {
|
|||||||
|
|
||||||
export function registerConfiguration(): IDisposable {
|
export function registerConfiguration(): IDisposable {
|
||||||
const ignoredSettingsSchemaId = 'vscode://schemas/ignoredSettings';
|
const ignoredSettingsSchemaId = 'vscode://schemas/ignoredSettings';
|
||||||
|
const ignoredExtensionsSchemaId = 'vscode://schemas/ignoredExtensions';
|
||||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
||||||
configurationRegistry.registerConfiguration({
|
configurationRegistry.registerConfiguration({
|
||||||
id: 'sync',
|
id: 'sync',
|
||||||
@@ -84,14 +85,11 @@ export function registerConfiguration(): IDisposable {
|
|||||||
'sync.ignoredExtensions': {
|
'sync.ignoredExtensions': {
|
||||||
'type': 'array',
|
'type': 'array',
|
||||||
'description': localize('sync.ignoredExtensions', "List of extensions to be ignored while synchronizing. The identifier of an extension is always ${publisher}.${name}. For example: vscode.csharp."),
|
'description': localize('sync.ignoredExtensions', "List of extensions to be ignored while synchronizing. The identifier of an extension is always ${publisher}.${name}. For example: vscode.csharp."),
|
||||||
items: {
|
$ref: ignoredExtensionsSchemaId,
|
||||||
type: 'string',
|
|
||||||
pattern: EXTENSION_IDENTIFIER_PATTERN,
|
|
||||||
errorMessage: localize('app.extension.identifier.errorMessage', "Expected format '${publisher}.${name}'. Example: 'vscode.csharp'.")
|
|
||||||
},
|
|
||||||
'default': [],
|
'default': [],
|
||||||
'scope': ConfigurationScope.APPLICATION,
|
'scope': ConfigurationScope.APPLICATION,
|
||||||
uniqueItems: true
|
uniqueItems: true,
|
||||||
|
disallowSyncIgnore: true
|
||||||
},
|
},
|
||||||
'sync.ignoredSettings': {
|
'sync.ignoredSettings': {
|
||||||
'type': 'array',
|
'type': 'array',
|
||||||
@@ -100,12 +98,13 @@ export function registerConfiguration(): IDisposable {
|
|||||||
'scope': ConfigurationScope.APPLICATION,
|
'scope': ConfigurationScope.APPLICATION,
|
||||||
$ref: ignoredSettingsSchemaId,
|
$ref: ignoredSettingsSchemaId,
|
||||||
additionalProperties: true,
|
additionalProperties: true,
|
||||||
uniqueItems: true
|
uniqueItems: true,
|
||||||
|
disallowSyncIgnore: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
||||||
const registerIgnoredSettingsSchema = () => {
|
const registerIgnoredSettingsSchema = () => {
|
||||||
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
|
||||||
const ignoredSettingsSchema: IJSONSchema = {
|
const ignoredSettingsSchema: IJSONSchema = {
|
||||||
items: {
|
items: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@@ -114,6 +113,11 @@ export function registerConfiguration(): IDisposable {
|
|||||||
};
|
};
|
||||||
jsonRegistry.registerSchema(ignoredSettingsSchemaId, ignoredSettingsSchema);
|
jsonRegistry.registerSchema(ignoredSettingsSchemaId, ignoredSettingsSchema);
|
||||||
};
|
};
|
||||||
|
jsonRegistry.registerSchema(ignoredExtensionsSchemaId, {
|
||||||
|
type: 'string',
|
||||||
|
pattern: EXTENSION_IDENTIFIER_PATTERN,
|
||||||
|
errorMessage: localize('app.extension.identifier.errorMessage', "Expected format '${publisher}.${name}'. Example: 'vscode.csharp'.")
|
||||||
|
});
|
||||||
return configurationRegistry.onDidUpdateConfiguration(() => registerIgnoredSettingsSchema());
|
return configurationRegistry.onDidUpdateConfiguration(() => registerIgnoredSettingsSchema());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +214,7 @@ export class UserDataSyncStoreError extends UserDataSyncError { }
|
|||||||
export interface ISyncExtension {
|
export interface ISyncExtension {
|
||||||
identifier: IExtensionIdentifier;
|
identifier: IExtensionIdentifier;
|
||||||
version?: string;
|
version?: string;
|
||||||
enabled: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGlobalState {
|
export interface IGlobalState {
|
||||||
@@ -283,6 +287,9 @@ export interface IUserDataSyncService {
|
|||||||
|
|
||||||
readonly onDidChangeLocal: Event<void>;
|
readonly onDidChangeLocal: Event<void>;
|
||||||
|
|
||||||
|
readonly lastSyncTime: number | undefined;
|
||||||
|
readonly onDidChangeLastSyncTime: Event<number>;
|
||||||
|
|
||||||
pull(): Promise<void>;
|
pull(): Promise<void>;
|
||||||
sync(): Promise<void>;
|
sync(): Promise<void>;
|
||||||
stop(): Promise<void>;
|
stop(): Promise<void>;
|
||||||
@@ -297,7 +304,7 @@ export interface IUserDataSyncService {
|
|||||||
export const IUserDataAutoSyncService = createDecorator<IUserDataAutoSyncService>('IUserDataAutoSyncService');
|
export const IUserDataAutoSyncService = createDecorator<IUserDataAutoSyncService>('IUserDataAutoSyncService');
|
||||||
export interface IUserDataAutoSyncService {
|
export interface IUserDataAutoSyncService {
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
readonly onError: Event<{ code: UserDataSyncErrorCode, source?: SyncSource }>;
|
readonly onError: Event<UserDataSyncError>;
|
||||||
triggerAutoSync(): Promise<void>;
|
triggerAutoSync(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,19 +315,6 @@ export interface IUserDataSyncUtilService {
|
|||||||
resolveFormattingOptions(resource: URI): Promise<FormattingOptions>;
|
resolveFormattingOptions(resource: URI): Promise<FormattingOptions>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const IUserDataAuthTokenService = createDecorator<IUserDataAuthTokenService>('IUserDataAuthTokenService');
|
|
||||||
|
|
||||||
export interface IUserDataAuthTokenService {
|
|
||||||
_serviceBrand: undefined;
|
|
||||||
|
|
||||||
readonly onDidChangeToken: Event<string | undefined>;
|
|
||||||
readonly onTokenFailed: Event<void>;
|
|
||||||
|
|
||||||
getToken(): Promise<string | undefined>;
|
|
||||||
setToken(accessToken: string | undefined): Promise<void>;
|
|
||||||
sendTokenFailed(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const IUserDataSyncLogService = createDecorator<IUserDataSyncLogService>('IUserDataSyncLogService');
|
export const IUserDataSyncLogService = createDecorator<IUserDataSyncLogService>('IUserDataSyncLogService');
|
||||||
export interface IUserDataSyncLogService extends ILogService { }
|
export interface IUserDataSyncLogService extends ILogService { }
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc';
|
import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { IUserDataSyncService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataAuthTokenService, IUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataSync';
|
import { IUserDataSyncService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { IStringDictionary } from 'vs/base/common/collections';
|
import { IStringDictionary } from 'vs/base/common/collections';
|
||||||
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
|
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
|
||||||
@@ -19,13 +19,14 @@ export class UserDataSyncChannel implements IServerChannel {
|
|||||||
case 'onDidChangeStatus': return this.service.onDidChangeStatus;
|
case 'onDidChangeStatus': return this.service.onDidChangeStatus;
|
||||||
case 'onDidChangeConflicts': return this.service.onDidChangeConflicts;
|
case 'onDidChangeConflicts': return this.service.onDidChangeConflicts;
|
||||||
case 'onDidChangeLocal': return this.service.onDidChangeLocal;
|
case 'onDidChangeLocal': return this.service.onDidChangeLocal;
|
||||||
|
case 'onDidChangeLastSyncTime': return this.service.onDidChangeLastSyncTime;
|
||||||
}
|
}
|
||||||
throw new Error(`Event not found: ${event}`);
|
throw new Error(`Event not found: ${event}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
call(context: any, command: string, args?: any): Promise<any> {
|
call(context: any, command: string, args?: any): Promise<any> {
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case '_getInitialData': return Promise.resolve([this.service.status, this.service.conflictsSources]);
|
case '_getInitialData': return Promise.resolve([this.service.status, this.service.conflictsSources, this.service.lastSyncTime]);
|
||||||
case 'sync': return this.service.sync();
|
case 'sync': return this.service.sync();
|
||||||
case 'accept': return this.service.accept(args[0], args[1]);
|
case 'accept': return this.service.accept(args[0], args[1]);
|
||||||
case 'pull': return this.service.pull();
|
case 'pull': return this.service.pull();
|
||||||
@@ -90,26 +91,6 @@ export class UserDataAutoSyncChannel implements IServerChannel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UserDataAuthTokenServiceChannel implements IServerChannel {
|
|
||||||
constructor(private readonly service: IUserDataAuthTokenService) { }
|
|
||||||
|
|
||||||
listen(_: unknown, event: string): Event<any> {
|
|
||||||
switch (event) {
|
|
||||||
case 'onDidChangeToken': return this.service.onDidChangeToken;
|
|
||||||
case 'onTokenFailed': return this.service.onTokenFailed;
|
|
||||||
}
|
|
||||||
throw new Error(`Event not found: ${event}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
call(context: any, command: string, args?: any): Promise<any> {
|
|
||||||
switch (command) {
|
|
||||||
case 'setToken': return this.service.setToken(args);
|
|
||||||
case 'getToken': return this.service.getToken();
|
|
||||||
}
|
|
||||||
throw new Error('Invalid call');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class UserDataSycnUtilServiceChannel implements IServerChannel {
|
export class UserDataSycnUtilServiceChannel implements IServerChannel {
|
||||||
|
|
||||||
constructor(private readonly service: IUserDataSyncUtilService) { }
|
constructor(private readonly service: IUserDataSyncUtilService) { }
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ type SyncErrorClassification = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const SESSION_ID_KEY = 'sync.sessionId';
|
const SESSION_ID_KEY = 'sync.sessionId';
|
||||||
|
const LAST_SYNC_TIME_KEY = 'sync.lastSyncTime';
|
||||||
|
|
||||||
export class UserDataSyncService extends Disposable implements IUserDataSyncService {
|
export class UserDataSyncService extends Disposable implements IUserDataSyncService {
|
||||||
|
|
||||||
@@ -40,6 +41,11 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
|||||||
private _onDidChangeConflicts: Emitter<SyncSource[]> = this._register(new Emitter<SyncSource[]>());
|
private _onDidChangeConflicts: Emitter<SyncSource[]> = this._register(new Emitter<SyncSource[]>());
|
||||||
readonly onDidChangeConflicts: Event<SyncSource[]> = this._onDidChangeConflicts.event;
|
readonly onDidChangeConflicts: Event<SyncSource[]> = this._onDidChangeConflicts.event;
|
||||||
|
|
||||||
|
private _lastSyncTime: number | undefined = undefined;
|
||||||
|
get lastSyncTime(): number | undefined { return this._lastSyncTime; }
|
||||||
|
private _onDidChangeLastSyncTime: Emitter<number> = this._register(new Emitter<number>());
|
||||||
|
readonly onDidChangeLastSyncTime: Event<number> = this._onDidChangeLastSyncTime.event;
|
||||||
|
|
||||||
private readonly keybindingsSynchroniser: KeybindingsSynchroniser;
|
private readonly keybindingsSynchroniser: KeybindingsSynchroniser;
|
||||||
private readonly extensionsSynchroniser: ExtensionsSynchroniser;
|
private readonly extensionsSynchroniser: ExtensionsSynchroniser;
|
||||||
private readonly globalStateSynchroniser: GlobalStateSynchroniser;
|
private readonly globalStateSynchroniser: GlobalStateSynchroniser;
|
||||||
@@ -63,6 +69,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
|||||||
this._register(Event.any(...this.synchronisers.map(s => Event.map(s.onDidChangeStatus, () => undefined)))(() => this.updateStatus()));
|
this._register(Event.any(...this.synchronisers.map(s => Event.map(s.onDidChangeStatus, () => undefined)))(() => this.updateStatus()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._lastSyncTime = this.storageService.getNumber(LAST_SYNC_TIME_KEY, StorageScope.GLOBAL, undefined);
|
||||||
this.onDidChangeLocal = Event.any(...this.synchronisers.map(s => s.onDidChangeLocal));
|
this.onDidChangeLocal = Event.any(...this.synchronisers.map(s => s.onDidChangeLocal));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +163,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
|||||||
async accept(source: SyncSource, content: string): Promise<void> {
|
async accept(source: SyncSource, content: string): Promise<void> {
|
||||||
await this.checkEnablement();
|
await this.checkEnablement();
|
||||||
const synchroniser = this.getSynchroniser(source);
|
const synchroniser = this.getSynchroniser(source);
|
||||||
return synchroniser.accept(content);
|
await synchroniser.accept(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRemoteContent(source: SyncSource, preview: boolean): Promise<string | null> {
|
async getRemoteContent(source: SyncSource, preview: boolean): Promise<string | null> {
|
||||||
@@ -189,6 +196,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
|||||||
async resetLocal(): Promise<void> {
|
async resetLocal(): Promise<void> {
|
||||||
await this.checkEnablement();
|
await this.checkEnablement();
|
||||||
this.storageService.remove(SESSION_ID_KEY, StorageScope.GLOBAL);
|
this.storageService.remove(SESSION_ID_KEY, StorageScope.GLOBAL);
|
||||||
|
this.storageService.remove(LAST_SYNC_TIME_KEY, StorageScope.GLOBAL);
|
||||||
for (const synchroniser of this.synchronisers) {
|
for (const synchroniser of this.synchronisers) {
|
||||||
try {
|
try {
|
||||||
synchroniser.resetLocal();
|
synchroniser.resetLocal();
|
||||||
@@ -227,9 +235,13 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setStatus(status: SyncStatus): void {
|
private setStatus(status: SyncStatus): void {
|
||||||
|
const oldStatus = this._status;
|
||||||
if (this._status !== status) {
|
if (this._status !== status) {
|
||||||
this._status = status;
|
this._status = status;
|
||||||
this._onDidChangeStatus.fire(status);
|
this._onDidChangeStatus.fire(status);
|
||||||
|
if (oldStatus !== SyncStatus.Uninitialized && this.status === SyncStatus.Idle) {
|
||||||
|
this.updateLastSyncTime(new Date().getTime());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,6 +268,14 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
|||||||
return SyncStatus.Idle;
|
return SyncStatus.Idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateLastSyncTime(lastSyncTime: number): void {
|
||||||
|
if (this._lastSyncTime !== lastSyncTime) {
|
||||||
|
this._lastSyncTime = lastSyncTime;
|
||||||
|
this.storageService.store(LAST_SYNC_TIME_KEY, lastSyncTime, StorageScope.GLOBAL);
|
||||||
|
this._onDidChangeLastSyncTime.fire(lastSyncTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private handleSyncError(e: Error, source: SyncSource): void {
|
private handleSyncError(e: Error, source: SyncSource): void {
|
||||||
if (e instanceof UserDataSyncStoreError) {
|
if (e instanceof UserDataSyncStoreError) {
|
||||||
switch (e.code) {
|
switch (e.code) {
|
||||||
|
|||||||
@@ -4,12 +4,13 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { Disposable, } from 'vs/base/common/lifecycle';
|
import { Disposable, } from 'vs/base/common/lifecycle';
|
||||||
import { IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, IUserDataSyncStore, getUserDataSyncStore, IUserDataAuthTokenService, SyncSource, UserDataSyncStoreError, IUserDataSyncLogService, IUserDataManifest } from 'vs/platform/userDataSync/common/userDataSync';
|
import { IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, IUserDataSyncStore, getUserDataSyncStore, SyncSource, UserDataSyncStoreError, IUserDataSyncLogService, IUserDataManifest } from 'vs/platform/userDataSync/common/userDataSync';
|
||||||
import { IRequestService, asText, isSuccess, asJson } from 'vs/platform/request/common/request';
|
import { IRequestService, asText, isSuccess, asJson } from 'vs/platform/request/common/request';
|
||||||
import { joinPath } from 'vs/base/common/resources';
|
import { joinPath } from 'vs/base/common/resources';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { IHeaders, IRequestOptions, IRequestContext } from 'vs/base/parts/request/common/request';
|
import { IHeaders, IRequestOptions, IRequestContext } from 'vs/base/parts/request/common/request';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication';
|
||||||
|
|
||||||
export class UserDataSyncStoreService extends Disposable implements IUserDataSyncStoreService {
|
export class UserDataSyncStoreService extends Disposable implements IUserDataSyncStoreService {
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn
|
|||||||
constructor(
|
constructor(
|
||||||
@IConfigurationService configurationService: IConfigurationService,
|
@IConfigurationService configurationService: IConfigurationService,
|
||||||
@IRequestService private readonly requestService: IRequestService,
|
@IRequestService private readonly requestService: IRequestService,
|
||||||
@IUserDataAuthTokenService private readonly authTokenService: IUserDataAuthTokenService,
|
@IAuthenticationTokenService private readonly authTokenService: IAuthenticationTokenService,
|
||||||
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
|
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IUserDataSyncService, IUserDataSyncLogService, IUserDataAuthTokenService, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
|
import { IUserDataSyncService, IUserDataSyncLogService, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||||
import { UserDataAutoSyncService as BaseUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataAutoSyncService';
|
import { UserDataAutoSyncService as BaseUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataAutoSyncService';
|
||||||
|
import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication';
|
||||||
|
|
||||||
export class UserDataAutoSyncService extends BaseUserDataAutoSyncService {
|
export class UserDataAutoSyncService extends BaseUserDataAutoSyncService {
|
||||||
|
|
||||||
@@ -15,7 +16,7 @@ export class UserDataAutoSyncService extends BaseUserDataAutoSyncService {
|
|||||||
@IUserDataSyncService userDataSyncService: IUserDataSyncService,
|
@IUserDataSyncService userDataSyncService: IUserDataSyncService,
|
||||||
@IElectronService electronService: IElectronService,
|
@IElectronService electronService: IElectronService,
|
||||||
@IUserDataSyncLogService logService: IUserDataSyncLogService,
|
@IUserDataSyncLogService logService: IUserDataSyncLogService,
|
||||||
@IUserDataAuthTokenService authTokenService: IUserDataAuthTokenService,
|
@IAuthenticationTokenService authTokenService: IAuthenticationTokenService,
|
||||||
) {
|
) {
|
||||||
super(userDataSyncEnablementService, userDataSyncService, logService, authTokenService);
|
super(userDataSyncEnablementService, userDataSyncService, logService, authTokenService);
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge returns local extension if remote does not exist', async () => {
|
test('merge returns local extension if remote does not exist', async () => {
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, null, null, [], []);
|
const actual = merge(localExtensions, null, null, [], []);
|
||||||
@@ -26,13 +26,13 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge returns local extension if remote does not exist with ignored extensions', async () => {
|
test('merge returns local extension if remote does not exist with ignored extensions', async () => {
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const expected: ISyncExtension[] = [
|
const expected: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, null, null, [], ['a']);
|
const actual = merge(localExtensions, null, null, [], ['a']);
|
||||||
@@ -45,13 +45,13 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge returns local extension if remote does not exist with ignored extensions (ignore case)', async () => {
|
test('merge returns local extension if remote does not exist with ignored extensions (ignore case)', async () => {
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const expected: ISyncExtension[] = [
|
const expected: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, null, null, [], ['A']);
|
const actual = merge(localExtensions, null, null, [], ['A']);
|
||||||
@@ -64,17 +64,17 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge returns local extension if remote does not exist with skipped extensions', async () => {
|
test('merge returns local extension if remote does not exist with skipped extensions', async () => {
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const skippedExtension: ISyncExtension[] = [
|
const skippedExtension: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
];
|
];
|
||||||
const expected: ISyncExtension[] = [
|
const expected: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, null, null, skippedExtension, []);
|
const actual = merge(localExtensions, null, null, skippedExtension, []);
|
||||||
@@ -87,16 +87,16 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge returns local extension if remote does not exist with skipped and ignored extensions', async () => {
|
test('merge returns local extension if remote does not exist with skipped and ignored extensions', async () => {
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const skippedExtension: ISyncExtension[] = [
|
const skippedExtension: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
];
|
];
|
||||||
const expected: ISyncExtension[] = [
|
const expected: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, null, null, skippedExtension, ['a']);
|
const actual = merge(localExtensions, null, null, skippedExtension, ['a']);
|
||||||
@@ -109,23 +109,23 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge local and remote extensions when there is no base', async () => {
|
test('merge local and remote extensions when there is no base', async () => {
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const expected: ISyncExtension[] = [
|
const expected: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, null, [], []);
|
const actual = merge(localExtensions, remoteExtensions, null, [], []);
|
||||||
|
|
||||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' }, enabled: true }, { identifier: { id: 'c', uuid: 'c' }, enabled: true }]);
|
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' } }, { identifier: { id: 'c', uuid: 'c' } }]);
|
||||||
assert.deepEqual(actual.removed, []);
|
assert.deepEqual(actual.removed, []);
|
||||||
assert.deepEqual(actual.updated, []);
|
assert.deepEqual(actual.updated, []);
|
||||||
assert.deepEqual(actual.remote, expected);
|
assert.deepEqual(actual.remote, expected);
|
||||||
@@ -133,22 +133,22 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge local and remote extensions when there is no base and with ignored extensions', async () => {
|
test('merge local and remote extensions when there is no base and with ignored extensions', async () => {
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const expected: ISyncExtension[] = [
|
const expected: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, null, [], ['a']);
|
const actual = merge(localExtensions, remoteExtensions, null, [], ['a']);
|
||||||
|
|
||||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' }, enabled: true }, { identifier: { id: 'c', uuid: 'c' }, enabled: true }]);
|
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' } }, { identifier: { id: 'c', uuid: 'c' } }]);
|
||||||
assert.deepEqual(actual.removed, []);
|
assert.deepEqual(actual.removed, []);
|
||||||
assert.deepEqual(actual.updated, []);
|
assert.deepEqual(actual.updated, []);
|
||||||
assert.deepEqual(actual.remote, expected);
|
assert.deepEqual(actual.remote, expected);
|
||||||
@@ -156,43 +156,66 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge local and remote extensions when remote is moved forwarded', async () => {
|
test('merge local and remote extensions when remote is moved forwarded', async () => {
|
||||||
const baseExtensions: ISyncExtension[] = [
|
const baseExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []);
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []);
|
||||||
|
|
||||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' }, enabled: true }, { identifier: { id: 'c', uuid: 'c' }, enabled: true }]);
|
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' } }, { identifier: { id: 'c', uuid: 'c' } }]);
|
||||||
assert.deepEqual(actual.removed, [{ id: 'a', uuid: 'a' }, { id: 'd', uuid: 'd' }]);
|
assert.deepEqual(actual.removed, [{ id: 'a', uuid: 'a' }, { id: 'd', uuid: 'd' }]);
|
||||||
assert.deepEqual(actual.updated, []);
|
assert.deepEqual(actual.updated, []);
|
||||||
assert.equal(actual.remote, null);
|
assert.equal(actual.remote, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('merge local and remote extensions when remote moved forwarded with ignored extensions', async () => {
|
test('merge local and remote extensions when remote is moved forwarded with disabled extension', async () => {
|
||||||
const baseExtensions: ISyncExtension[] = [
|
const baseExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
|
{ identifier: { id: 'd', uuid: 'd' }, disabled: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []);
|
||||||
|
|
||||||
|
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' } }, { identifier: { id: 'c', uuid: 'c' } }]);
|
||||||
|
assert.deepEqual(actual.removed, [{ id: 'a', uuid: 'a' }]);
|
||||||
|
assert.deepEqual(actual.updated, [{ identifier: { id: 'd', uuid: 'd' }, disabled: true }]);
|
||||||
|
assert.equal(actual.remote, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('merge local and remote extensions when remote moved forwarded with ignored extensions', async () => {
|
||||||
|
const baseExtensions: ISyncExtension[] = [
|
||||||
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
|
];
|
||||||
|
const localExtensions: ISyncExtension[] = [
|
||||||
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
|
];
|
||||||
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['a']);
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['a']);
|
||||||
|
|
||||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' }, enabled: true }, { identifier: { id: 'c', uuid: 'c' }, enabled: true }]);
|
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' } }, { identifier: { id: 'c', uuid: 'c' } }]);
|
||||||
assert.deepEqual(actual.removed, [{ id: 'd', uuid: 'd' }]);
|
assert.deepEqual(actual.removed, [{ id: 'd', uuid: 'd' }]);
|
||||||
assert.deepEqual(actual.updated, []);
|
assert.deepEqual(actual.updated, []);
|
||||||
assert.equal(actual.remote, null);
|
assert.equal(actual.remote, null);
|
||||||
@@ -200,23 +223,23 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge local and remote extensions when remote is moved forwarded with skipped extensions', async () => {
|
test('merge local and remote extensions when remote is moved forwarded with skipped extensions', async () => {
|
||||||
const baseExtensions: ISyncExtension[] = [
|
const baseExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const skippedExtensions: ISyncExtension[] = [
|
const skippedExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, []);
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, []);
|
||||||
|
|
||||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' }, enabled: true }, { identifier: { id: 'c', uuid: 'c' }, enabled: true }]);
|
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' } }, { identifier: { id: 'c', uuid: 'c' } }]);
|
||||||
assert.deepEqual(actual.removed, [{ id: 'd', uuid: 'd' }]);
|
assert.deepEqual(actual.removed, [{ id: 'd', uuid: 'd' }]);
|
||||||
assert.deepEqual(actual.updated, []);
|
assert.deepEqual(actual.updated, []);
|
||||||
assert.equal(actual.remote, null);
|
assert.equal(actual.remote, null);
|
||||||
@@ -224,23 +247,23 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge local and remote extensions when remote is moved forwarded with skipped and ignored extensions', async () => {
|
test('merge local and remote extensions when remote is moved forwarded with skipped and ignored extensions', async () => {
|
||||||
const baseExtensions: ISyncExtension[] = [
|
const baseExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const skippedExtensions: ISyncExtension[] = [
|
const skippedExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['b']);
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['b']);
|
||||||
|
|
||||||
assert.deepEqual(actual.added, [{ identifier: { id: 'c', uuid: 'c' }, enabled: true }]);
|
assert.deepEqual(actual.added, [{ identifier: { id: 'c', uuid: 'c' } }]);
|
||||||
assert.deepEqual(actual.removed, [{ id: 'd', uuid: 'd' }]);
|
assert.deepEqual(actual.removed, [{ id: 'd', uuid: 'd' }]);
|
||||||
assert.deepEqual(actual.updated, []);
|
assert.deepEqual(actual.updated, []);
|
||||||
assert.equal(actual.remote, null);
|
assert.equal(actual.remote, null);
|
||||||
@@ -248,16 +271,39 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge local and remote extensions when local is moved forwarded', async () => {
|
test('merge local and remote extensions when local is moved forwarded', async () => {
|
||||||
const baseExtensions: ISyncExtension[] = [
|
const baseExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
|
];
|
||||||
|
|
||||||
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []);
|
||||||
|
|
||||||
|
assert.deepEqual(actual.added, []);
|
||||||
|
assert.deepEqual(actual.removed, []);
|
||||||
|
assert.deepEqual(actual.updated, []);
|
||||||
|
assert.deepEqual(actual.remote, localExtensions);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('merge local and remote extensions when local is moved forwarded with disabled extensions', async () => {
|
||||||
|
const baseExtensions: ISyncExtension[] = [
|
||||||
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
|
];
|
||||||
|
const localExtensions: ISyncExtension[] = [
|
||||||
|
{ identifier: { id: 'a', uuid: 'a' }, disabled: true },
|
||||||
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
|
];
|
||||||
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []);
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []);
|
||||||
@@ -270,16 +316,16 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge local and remote extensions when local is moved forwarded with ignored settings', async () => {
|
test('merge local and remote extensions when local is moved forwarded with ignored settings', async () => {
|
||||||
const baseExtensions: ISyncExtension[] = [
|
const baseExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['b']);
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['b']);
|
||||||
@@ -288,30 +334,30 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
assert.deepEqual(actual.removed, []);
|
assert.deepEqual(actual.removed, []);
|
||||||
assert.deepEqual(actual.updated, []);
|
assert.deepEqual(actual.updated, []);
|
||||||
assert.deepEqual(actual.remote, [
|
assert.deepEqual(actual.remote, [
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('merge local and remote extensions when local is moved forwarded with skipped extensions', async () => {
|
test('merge local and remote extensions when local is moved forwarded with skipped extensions', async () => {
|
||||||
const baseExtensions: ISyncExtension[] = [
|
const baseExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const skippedExtensions: ISyncExtension[] = [
|
const skippedExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const expected: ISyncExtension[] = [
|
const expected: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, []);
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, []);
|
||||||
@@ -324,23 +370,23 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge local and remote extensions when local is moved forwarded with skipped and ignored extensions', async () => {
|
test('merge local and remote extensions when local is moved forwarded with skipped and ignored extensions', async () => {
|
||||||
const baseExtensions: ISyncExtension[] = [
|
const baseExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const skippedExtensions: ISyncExtension[] = [
|
const skippedExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const expected: ISyncExtension[] = [
|
const expected: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['c']);
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['c']);
|
||||||
@@ -353,28 +399,28 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge local and remote extensions when both moved forwarded', async () => {
|
test('merge local and remote extensions when both moved forwarded', async () => {
|
||||||
const baseExtensions: ISyncExtension[] = [
|
const baseExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
{ identifier: { id: 'e', uuid: 'e' } },
|
||||||
];
|
];
|
||||||
const expected: ISyncExtension[] = [
|
const expected: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
{ identifier: { id: 'e', uuid: 'e' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []);
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []);
|
||||||
|
|
||||||
assert.deepEqual(actual.added, [{ identifier: { id: 'e', uuid: 'e' }, enabled: true }]);
|
assert.deepEqual(actual.added, [{ identifier: { id: 'e', uuid: 'e' } }]);
|
||||||
assert.deepEqual(actual.removed, [{ id: 'a', uuid: 'a' }]);
|
assert.deepEqual(actual.removed, [{ id: 'a', uuid: 'a' }]);
|
||||||
assert.deepEqual(actual.updated, []);
|
assert.deepEqual(actual.updated, []);
|
||||||
assert.deepEqual(actual.remote, expected);
|
assert.deepEqual(actual.remote, expected);
|
||||||
@@ -382,23 +428,23 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge local and remote extensions when both moved forwarded with ignored extensions', async () => {
|
test('merge local and remote extensions when both moved forwarded with ignored extensions', async () => {
|
||||||
const baseExtensions: ISyncExtension[] = [
|
const baseExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
{ identifier: { id: 'e', uuid: 'e' } },
|
||||||
];
|
];
|
||||||
const expected: ISyncExtension[] = [
|
const expected: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
{ identifier: { id: 'e', uuid: 'e' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['a', 'e']);
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['a', 'e']);
|
||||||
@@ -411,30 +457,30 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge local and remote extensions when both moved forwarded with skipped extensions', async () => {
|
test('merge local and remote extensions when both moved forwarded with skipped extensions', async () => {
|
||||||
const baseExtensions: ISyncExtension[] = [
|
const baseExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const skippedExtensions: ISyncExtension[] = [
|
const skippedExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
];
|
];
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
{ identifier: { id: 'e', uuid: 'e' } },
|
||||||
];
|
];
|
||||||
const expected: ISyncExtension[] = [
|
const expected: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
{ identifier: { id: 'e', uuid: 'e' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, []);
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, []);
|
||||||
|
|
||||||
assert.deepEqual(actual.added, [{ identifier: { id: 'e', uuid: 'e' }, enabled: true }]);
|
assert.deepEqual(actual.added, [{ identifier: { id: 'e', uuid: 'e' } }]);
|
||||||
assert.deepEqual(actual.removed, []);
|
assert.deepEqual(actual.removed, []);
|
||||||
assert.deepEqual(actual.updated, []);
|
assert.deepEqual(actual.updated, []);
|
||||||
assert.deepEqual(actual.remote, expected);
|
assert.deepEqual(actual.remote, expected);
|
||||||
@@ -442,25 +488,25 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge local and remote extensions when both moved forwarded with skipped and ignoredextensions', async () => {
|
test('merge local and remote extensions when both moved forwarded with skipped and ignoredextensions', async () => {
|
||||||
const baseExtensions: ISyncExtension[] = [
|
const baseExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const skippedExtensions: ISyncExtension[] = [
|
const skippedExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
];
|
];
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
{ identifier: { id: 'e', uuid: 'e' } },
|
||||||
];
|
];
|
||||||
const expected: ISyncExtension[] = [
|
const expected: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
{ identifier: { id: 'e', uuid: 'e' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['e']);
|
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['e']);
|
||||||
@@ -473,24 +519,24 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
|||||||
|
|
||||||
test('merge when remote extension has no uuid and different extension id case', async () => {
|
test('merge when remote extension has no uuid and different extension id case', async () => {
|
||||||
const localExtensions: ISyncExtension[] = [
|
const localExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
{ identifier: { id: 'a', uuid: 'a' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
const remoteExtensions: ISyncExtension[] = [
|
const remoteExtensions: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'A' }, enabled: true },
|
{ identifier: { id: 'A' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
];
|
];
|
||||||
const expected: ISyncExtension[] = [
|
const expected: ISyncExtension[] = [
|
||||||
{ identifier: { id: 'A' }, enabled: true },
|
{ identifier: { id: 'A', uuid: 'a' } },
|
||||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
{ identifier: { id: 'd', uuid: 'd' } },
|
||||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
{ identifier: { id: 'b', uuid: 'b' } },
|
||||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
{ identifier: { id: 'c', uuid: 'c' } },
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = merge(localExtensions, remoteExtensions, null, [], []);
|
const actual = merge(localExtensions, remoteExtensions, null, [], []);
|
||||||
|
|
||||||
assert.deepEqual(actual.added, [{ identifier: { id: 'd', uuid: 'd' }, enabled: true }]);
|
assert.deepEqual(actual.added, [{ identifier: { id: 'd', uuid: 'd' } }]);
|
||||||
assert.deepEqual(actual.removed, []);
|
assert.deepEqual(actual.removed, []);
|
||||||
assert.deepEqual(actual.updated, []);
|
assert.deepEqual(actual.updated, []);
|
||||||
assert.deepEqual(actual.remote, expected);
|
assert.deepEqual(actual.remote, expected);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import { IRequestService } from 'vs/platform/request/common/request';
|
import { IRequestService } from 'vs/platform/request/common/request';
|
||||||
import { IRequestOptions, IRequestContext, IHeaders } from 'vs/base/parts/request/common/request';
|
import { IRequestOptions, IRequestContext, IHeaders } from 'vs/base/parts/request/common/request';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { IUserData, ResourceKey, IUserDataManifest, ALL_RESOURCE_KEYS, IUserDataAuthTokenService, IUserDataSyncLogService, IUserDataSyncStoreService, IUserDataSyncUtilService, IUserDataSyncEnablementService, ISettingsSyncService, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync';
|
import { IUserData, ResourceKey, IUserDataManifest, ALL_RESOURCE_KEYS, IUserDataSyncLogService, IUserDataSyncStoreService, IUserDataSyncUtilService, IUserDataSyncEnablementService, ISettingsSyncService, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||||
import { bufferToStream, VSBuffer } from 'vs/base/common/buffer';
|
import { bufferToStream, VSBuffer } from 'vs/base/common/buffer';
|
||||||
import { generateUuid } from 'vs/base/common/uuid';
|
import { generateUuid } from 'vs/base/common/uuid';
|
||||||
import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService';
|
import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService';
|
||||||
@@ -33,6 +33,7 @@ import { ConfigurationService } from 'vs/platform/configuration/common/configura
|
|||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync';
|
import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync';
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
|
import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication';
|
||||||
|
|
||||||
export class UserDataSyncClient extends Disposable {
|
export class UserDataSyncClient extends Disposable {
|
||||||
|
|
||||||
@@ -76,7 +77,7 @@ export class UserDataSyncClient extends Disposable {
|
|||||||
this.instantiationService.stub(IConfigurationService, configurationService);
|
this.instantiationService.stub(IConfigurationService, configurationService);
|
||||||
|
|
||||||
this.instantiationService.stub(IRequestService, this.testServer);
|
this.instantiationService.stub(IRequestService, this.testServer);
|
||||||
this.instantiationService.stub(IUserDataAuthTokenService, <Partial<IUserDataAuthTokenService>>{
|
this.instantiationService.stub(IAuthenticationTokenService, <Partial<IAuthenticationTokenService>>{
|
||||||
onDidChangeToken: new Emitter<string | undefined>().event,
|
onDidChangeToken: new Emitter<string | undefined>().event,
|
||||||
async getToken() { return 'token'; }
|
async getToken() { return 'token'; }
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { IFileService } from 'vs/platform/files/common/files';
|
|||||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
import { VSBuffer } from 'vs/base/common/buffer';
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
|
|
||||||
suite('UserDataSyncService', () => {
|
suite.skip('UserDataSyncService', () => { // {{SQL CARBON EDIT}} skip failing tests
|
||||||
|
|
||||||
const disposableStore = new DisposableStore();
|
const disposableStore = new DisposableStore();
|
||||||
|
|
||||||
|
|||||||
Vendored
+40
-6
@@ -2897,6 +2897,34 @@ declare module 'vscode' {
|
|||||||
constructor(range: Range, newText: string);
|
constructor(range: Range, newText: string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional data for entries of a workspace edit. Supports to label entries and marks entries
|
||||||
|
* as needing confirmation by the user. The editor groups edits with equal labels into tree nodes,
|
||||||
|
* for instance all edits labelled with "Changes in Strings" would be a tree node.
|
||||||
|
*/
|
||||||
|
export interface WorkspaceEditEntryMetadata {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flag which indicates that user confirmation is needed.
|
||||||
|
*/
|
||||||
|
needsConfirmation: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A human-readable string which is rendered prominent.
|
||||||
|
*/
|
||||||
|
label: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A human-readable string which is rendered less prominent on the same line.
|
||||||
|
*/
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The icon path or [ThemeIcon](#ThemeIcon) for the edit.
|
||||||
|
*/
|
||||||
|
iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A workspace edit is a collection of textual and files changes for
|
* A workspace edit is a collection of textual and files changes for
|
||||||
* multiple resources and documents.
|
* multiple resources and documents.
|
||||||
@@ -2916,8 +2944,9 @@ declare module 'vscode' {
|
|||||||
* @param uri A resource identifier.
|
* @param uri A resource identifier.
|
||||||
* @param range A range.
|
* @param range A range.
|
||||||
* @param newText A string.
|
* @param newText A string.
|
||||||
|
* @param metadata Optional metadata for the entry.
|
||||||
*/
|
*/
|
||||||
replace(uri: Uri, range: Range, newText: string): void;
|
replace(uri: Uri, range: Range, newText: string, metadata?: WorkspaceEditEntryMetadata): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert the given text at the given position.
|
* Insert the given text at the given position.
|
||||||
@@ -2925,16 +2954,18 @@ declare module 'vscode' {
|
|||||||
* @param uri A resource identifier.
|
* @param uri A resource identifier.
|
||||||
* @param position A position.
|
* @param position A position.
|
||||||
* @param newText A string.
|
* @param newText A string.
|
||||||
|
* @param metadata Optional metadata for the entry.
|
||||||
*/
|
*/
|
||||||
insert(uri: Uri, position: Position, newText: string): void;
|
insert(uri: Uri, position: Position, newText: string, metadata?: WorkspaceEditEntryMetadata): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the text at the given range.
|
* Delete the text at the given range.
|
||||||
*
|
*
|
||||||
* @param uri A resource identifier.
|
* @param uri A resource identifier.
|
||||||
* @param range A range.
|
* @param range A range.
|
||||||
|
* @param metadata Optional metadata for the entry.
|
||||||
*/
|
*/
|
||||||
delete(uri: Uri, range: Range): void;
|
delete(uri: Uri, range: Range, metadata?: WorkspaceEditEntryMetadata): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a text edit for a resource exists.
|
* Check if a text edit for a resource exists.
|
||||||
@@ -2966,15 +2997,17 @@ declare module 'vscode' {
|
|||||||
* @param uri Uri of the new file..
|
* @param uri Uri of the new file..
|
||||||
* @param options Defines if an existing file should be overwritten or be
|
* @param options Defines if an existing file should be overwritten or be
|
||||||
* ignored. When overwrite and ignoreIfExists are both set overwrite wins.
|
* ignored. When overwrite and ignoreIfExists are both set overwrite wins.
|
||||||
|
* @param metadata Optional metadata for the entry.
|
||||||
*/
|
*/
|
||||||
createFile(uri: Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean }): void;
|
createFile(uri: Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean }, metadata?: WorkspaceEditEntryMetadata): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a file or folder.
|
* Delete a file or folder.
|
||||||
*
|
*
|
||||||
* @param uri The uri of the file that is to be deleted.
|
* @param uri The uri of the file that is to be deleted.
|
||||||
|
* @param metadata Optional metadata for the entry.
|
||||||
*/
|
*/
|
||||||
deleteFile(uri: Uri, options?: { recursive?: boolean, ignoreIfNotExists?: boolean }): void;
|
deleteFile(uri: Uri, options?: { recursive?: boolean, ignoreIfNotExists?: boolean }, metadata?: WorkspaceEditEntryMetadata): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rename a file or folder.
|
* Rename a file or folder.
|
||||||
@@ -2983,8 +3016,9 @@ declare module 'vscode' {
|
|||||||
* @param newUri The new location.
|
* @param newUri The new location.
|
||||||
* @param options Defines if existing files should be overwritten or be
|
* @param options Defines if existing files should be overwritten or be
|
||||||
* ignored. When overwrite and ignoreIfExists are both set overwrite wins.
|
* ignored. When overwrite and ignoreIfExists are both set overwrite wins.
|
||||||
|
* @param metadata Optional metadata for the entry.
|
||||||
*/
|
*/
|
||||||
renameFile(oldUri: Uri, newUri: Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean }): void;
|
renameFile(oldUri: Uri, newUri: Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean }, metadata?: WorkspaceEditEntryMetadata): void;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Vendored
-43
@@ -1408,49 +1408,6 @@ declare module 'vscode' {
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
//#region https://github.com/microsoft/vscode/issues/77728
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Additional data for entries of a workspace edit. Supports to label entries and marks entries
|
|
||||||
* as needing confirmation by the user. The editor groups edits with equal labels into tree nodes,
|
|
||||||
* for instance all edits labelled with "Changes in Strings" would be a tree node.
|
|
||||||
*/
|
|
||||||
export interface WorkspaceEditMetadata {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flag which indicates that user confirmation is needed.
|
|
||||||
*/
|
|
||||||
needsConfirmation: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A human-readable string which is rendered prominent.
|
|
||||||
*/
|
|
||||||
label: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A human-readable string which is rendered less prominent on the same line.
|
|
||||||
*/
|
|
||||||
description?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The icon path or [ThemeIcon](#ThemeIcon) for the edit.
|
|
||||||
*/
|
|
||||||
iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WorkspaceEdit {
|
|
||||||
|
|
||||||
insert(uri: Uri, position: Position, newText: string, metadata?: WorkspaceEditMetadata): void;
|
|
||||||
delete(uri: Uri, range: Range, metadata?: WorkspaceEditMetadata): void;
|
|
||||||
replace(uri: Uri, range: Range, newText: string, metadata?: WorkspaceEditMetadata): void;
|
|
||||||
|
|
||||||
createFile(uri: Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean }, metadata?: WorkspaceEditMetadata): void;
|
|
||||||
deleteFile(uri: Uri, options?: { recursive?: boolean, ignoreIfNotExists?: boolean }, metadata?: WorkspaceEditMetadata): void;
|
|
||||||
renameFile(oldUri: Uri, newUri: Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean }, metadata?: WorkspaceEditMetadata): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region Diagnostic links https://github.com/microsoft/vscode/issues/11847
|
//#region Diagnostic links https://github.com/microsoft/vscode/issues/11847
|
||||||
|
|
||||||
export interface Diagnostic {
|
export interface Diagnostic {
|
||||||
|
|||||||
@@ -8,16 +8,13 @@ import { FileChangeType, IFileService, FileOperation } from 'vs/platform/files/c
|
|||||||
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||||
import { ExtHostContext, FileSystemEvents, IExtHostContext } from '../common/extHost.protocol';
|
import { ExtHostContext, FileSystemEvents, IExtHostContext } from '../common/extHost.protocol';
|
||||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
import { IProgressService } from 'vs/platform/progress/common/progress';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
|
||||||
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||||
import { URI } from 'vs/base/common/uri';
|
|
||||||
import { IWaitUntil } from 'vs/base/common/event';
|
|
||||||
|
|
||||||
@extHostCustomer
|
@extHostCustomer
|
||||||
export class MainThreadFileSystemEventService {
|
export class MainThreadFileSystemEventService {
|
||||||
@@ -65,43 +62,11 @@ export class MainThreadFileSystemEventService {
|
|||||||
|
|
||||||
|
|
||||||
// BEFORE file operation
|
// BEFORE file operation
|
||||||
const messages = new Map<FileOperation, string>();
|
workingCopyFileService.addFileOperationParticipant({
|
||||||
messages.set(FileOperation.CREATE, localize('msg-create', "Running 'File Create' participants..."));
|
participate: (target, source, operation, progress, timeout, token) => {
|
||||||
messages.set(FileOperation.DELETE, localize('msg-delete', "Running 'File Delete' participants..."));
|
return proxy.$onWillRunFileOperation(operation, target, source, timeout, token);
|
||||||
messages.set(FileOperation.MOVE, localize('msg-rename', "Running 'File Rename' participants..."));
|
|
||||||
|
|
||||||
function participateInFileOperation(e: IWaitUntil, operation: FileOperation, target: URI, source?: URI): void {
|
|
||||||
const timeout = configService.getValue<number>('files.participants.timeout');
|
|
||||||
if (timeout <= 0) {
|
|
||||||
return; // disabled
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
const p = progressService.withProgress({ location: ProgressLocation.Window }, progress => {
|
|
||||||
|
|
||||||
progress.report({ message: messages.get(operation) });
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
|
|
||||||
const cts = new CancellationTokenSource();
|
|
||||||
|
|
||||||
const timeoutHandle = setTimeout(() => {
|
|
||||||
logService.trace('CANCELLED file participants because of timeout', timeout, target, operation);
|
|
||||||
cts.cancel();
|
|
||||||
reject(new Error('timeout'));
|
|
||||||
}, timeout);
|
|
||||||
|
|
||||||
proxy.$onWillRunFileOperation(operation, target, source, timeout, cts.token)
|
|
||||||
.then(resolve, reject)
|
|
||||||
.finally(() => clearTimeout(timeoutHandle));
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
e.waitUntil(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._listener.add(textFileService.onWillCreateTextFile(e => participateInFileOperation(e, FileOperation.CREATE, e.resource)));
|
|
||||||
this._listener.add(workingCopyFileService.onBeforeWorkingCopyFileOperation(e => participateInFileOperation(e, e.operation, e.target, e.source)));
|
|
||||||
|
|
||||||
// AFTER file operation
|
// AFTER file operation
|
||||||
this._listener.add(textFileService.onDidCreateTextFile(e => proxy.$onDidRunFileOperation(FileOperation.CREATE, e.resource, undefined)));
|
this._listener.add(textFileService.onDidCreateTextFile(e => proxy.$onDidRunFileOperation(FileOperation.CREATE, e.resource, undefined)));
|
||||||
|
|||||||
@@ -174,10 +174,20 @@ export class RemoveFromRecentlyOpenedAPICommand {
|
|||||||
}
|
}
|
||||||
CommandsRegistry.registerCommand(RemoveFromRecentlyOpenedAPICommand.ID, adjustHandler(RemoveFromRecentlyOpenedAPICommand.execute));
|
CommandsRegistry.registerCommand(RemoveFromRecentlyOpenedAPICommand.ID, adjustHandler(RemoveFromRecentlyOpenedAPICommand.execute));
|
||||||
|
|
||||||
|
export interface OpenIssueReporterArgs {
|
||||||
|
readonly extensionId: string;
|
||||||
|
readonly issueTitle?: string;
|
||||||
|
readonly issueBody?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class OpenIssueReporter {
|
export class OpenIssueReporter {
|
||||||
public static readonly ID = 'vscode.openIssueReporter';
|
public static readonly ID = 'vscode.openIssueReporter';
|
||||||
public static execute(executor: ICommandsExecutor, extensionId: string): Promise<void> {
|
|
||||||
return executor.executeCommand('workbench.action.openIssueReporter', [extensionId]);
|
public static execute(executor: ICommandsExecutor, args: string | OpenIssueReporterArgs): Promise<void> {
|
||||||
|
const commandArgs = typeof args === 'string'
|
||||||
|
? { extensionId: args }
|
||||||
|
: args;
|
||||||
|
return executor.executeCommand('workbench.action.openIssueReporter', commandArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import * as search from 'vs/workbench/contrib/search/common/search';
|
|||||||
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||||
import { CustomCodeAction } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
import { CustomCodeAction } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||||
import { ICommandsExecutor, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand, OpenIssueReporter } from './apiCommands';
|
import { ICommandsExecutor, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand, OpenIssueReporter, OpenIssueReporterArgs } from './apiCommands';
|
||||||
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
|
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
import { IRange } from 'vs/editor/common/core/range';
|
||||||
@@ -364,7 +364,7 @@ export class ExtHostApiCommands {
|
|||||||
this._register(OpenIssueReporter.ID, adjustHandler(OpenIssueReporter.execute), {
|
this._register(OpenIssueReporter.ID, adjustHandler(OpenIssueReporter.execute), {
|
||||||
description: 'Opens the issue reporter with the provided extension id as the selected source',
|
description: 'Opens the issue reporter with the provided extension id as the selected source',
|
||||||
args: [
|
args: [
|
||||||
{ name: 'extensionId', description: 'extensionId to report an issue on', constraint: (value: any) => typeof value === 'string' }
|
{ name: 'extensionId', description: 'extensionId to report an issue on', constraint: (value: unknown) => typeof value === 'string' || (typeof value === 'object' && typeof (value as OpenIssueReporterArgs).extensionId === 'string') }
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { Schemas } from 'vs/base/common/network';
|
|||||||
import { VSBuffer } from 'vs/base/common/buffer';
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
|
import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
|
||||||
import { RemoteAuthorityResolverError } from 'vs/workbench/api/common/extHostTypes';
|
import { RemoteAuthorityResolverError } from 'vs/workbench/api/common/extHostTypes';
|
||||||
import { ResolvedAuthority, ResolvedOptions } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
import { ResolvedAuthority, ResolvedOptions, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||||
import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||||
@@ -641,7 +641,14 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
|||||||
|
|
||||||
const resolver = this._resolvers[authorityPrefix];
|
const resolver = this._resolvers[authorityPrefix];
|
||||||
if (!resolver) {
|
if (!resolver) {
|
||||||
throw new Error(`No remote extension installed to resolve ${authorityPrefix}.`);
|
return {
|
||||||
|
type: 'error',
|
||||||
|
error: {
|
||||||
|
code: RemoteAuthorityResolverErrorCode.NoResolverFound,
|
||||||
|
message: `No remote extension installed to resolve ${authorityPrefix}.`,
|
||||||
|
detail: undefined
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -576,14 +576,14 @@ export interface IFileOperation {
|
|||||||
from?: URI;
|
from?: URI;
|
||||||
to?: URI;
|
to?: URI;
|
||||||
options?: IFileOperationOptions;
|
options?: IFileOperationOptions;
|
||||||
metadata?: vscode.WorkspaceEditMetadata;
|
metadata?: vscode.WorkspaceEditEntryMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFileTextEdit {
|
export interface IFileTextEdit {
|
||||||
_type: 2;
|
_type: 2;
|
||||||
uri: URI;
|
uri: URI;
|
||||||
edit: TextEdit;
|
edit: TextEdit;
|
||||||
metadata?: vscode.WorkspaceEditMetadata;
|
metadata?: vscode.WorkspaceEditEntryMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
@es5ClassCompat
|
@es5ClassCompat
|
||||||
@@ -591,27 +591,27 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
|||||||
|
|
||||||
private _edits = new Array<IFileOperation | IFileTextEdit>();
|
private _edits = new Array<IFileOperation | IFileTextEdit>();
|
||||||
|
|
||||||
renameFile(from: vscode.Uri, to: vscode.Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean; }, metadata?: vscode.WorkspaceEditMetadata): void {
|
renameFile(from: vscode.Uri, to: vscode.Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean; }, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||||
this._edits.push({ _type: 1, from, to, options, metadata });
|
this._edits.push({ _type: 1, from, to, options, metadata });
|
||||||
}
|
}
|
||||||
|
|
||||||
createFile(uri: vscode.Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean; }, metadata?: vscode.WorkspaceEditMetadata): void {
|
createFile(uri: vscode.Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean; }, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||||
this._edits.push({ _type: 1, from: undefined, to: uri, options, metadata });
|
this._edits.push({ _type: 1, from: undefined, to: uri, options, metadata });
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteFile(uri: vscode.Uri, options?: { recursive?: boolean, ignoreIfNotExists?: boolean; }, metadata?: vscode.WorkspaceEditMetadata): void {
|
deleteFile(uri: vscode.Uri, options?: { recursive?: boolean, ignoreIfNotExists?: boolean; }, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||||
this._edits.push({ _type: 1, from: uri, to: undefined, options, metadata });
|
this._edits.push({ _type: 1, from: uri, to: undefined, options, metadata });
|
||||||
}
|
}
|
||||||
|
|
||||||
replace(uri: URI, range: Range, newText: string, metadata?: vscode.WorkspaceEditMetadata): void {
|
replace(uri: URI, range: Range, newText: string, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||||
this._edits.push({ _type: 2, uri, edit: new TextEdit(range, newText), metadata });
|
this._edits.push({ _type: 2, uri, edit: new TextEdit(range, newText), metadata });
|
||||||
}
|
}
|
||||||
|
|
||||||
insert(resource: URI, position: Position, newText: string, metadata?: vscode.WorkspaceEditMetadata): void {
|
insert(resource: URI, position: Position, newText: string, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||||
this.replace(resource, new Range(position, position), newText, metadata);
|
this.replace(resource, new Range(position, position), newText, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(resource: URI, range: Range, metadata?: vscode.WorkspaceEditMetadata): void {
|
delete(resource: URI, range: Range, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||||
this.replace(resource, range, '', metadata);
|
this.replace(resource, range, '', metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import * as nls from 'vs/nls';
|
|||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { Action } from 'vs/base/common/actions';
|
import { Action } from 'vs/base/common/actions';
|
||||||
import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
|
import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||||
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
|
import { IWorkbenchActionRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/actions';
|
||||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService';
|
import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService';
|
||||||
import { IEditorGroupsService, GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService';
|
import { IEditorGroupsService, GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||||
@@ -24,8 +24,9 @@ import { InEditorZenModeContext, IsCenteredLayoutContext, EditorAreaVisibleConte
|
|||||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { SideBarVisibleContext } from 'vs/workbench/common/viewlet';
|
import { SideBarVisibleContext } from 'vs/workbench/common/viewlet';
|
||||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
|
import { IViewDescriptorService, IViewContainersRegistry, Extensions as ViewContainerExtensions } from 'vs/workbench/common/views';
|
||||||
|
|
||||||
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
|
const registry = Registry.as<IWorkbenchActionRegistry>(WorkbenchExtensions.WorkbenchActions);
|
||||||
const viewCategory = nls.localize('view', "View");
|
const viewCategory = nls.localize('view', "View");
|
||||||
|
|
||||||
// --- Close Side Bar
|
// --- Close Side Bar
|
||||||
@@ -482,6 +483,42 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
|||||||
order: 0
|
order: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// --- Reset View Positions
|
||||||
|
|
||||||
|
export class ResetViewLocationsAction extends Action {
|
||||||
|
static readonly ID = 'workbench.action.resetViewLocations';
|
||||||
|
static readonly LABEL = nls.localize('resetViewLocations', "Reset View Locations");
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
id: string,
|
||||||
|
label: string,
|
||||||
|
@IViewDescriptorService private viewDescriptorService: IViewDescriptorService
|
||||||
|
) {
|
||||||
|
super(id, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
run(): Promise<void> {
|
||||||
|
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
|
||||||
|
viewContainerRegistry.all.forEach(viewContainer => {
|
||||||
|
const viewDescriptors = this.viewDescriptorService.getViewDescriptors(viewContainer);
|
||||||
|
|
||||||
|
viewDescriptors.allViewDescriptors.forEach(viewDescriptor => {
|
||||||
|
const defaultContainer = this.viewDescriptorService.getDefaultContainer(viewDescriptor.id);
|
||||||
|
const currentContainer = this.viewDescriptorService.getViewContainer(viewDescriptor.id);
|
||||||
|
|
||||||
|
if (defaultContainer && currentContainer !== defaultContainer) {
|
||||||
|
this.viewDescriptorService.moveViewsToContainer([viewDescriptor], defaultContainer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.registerWorkbenchAction(SyncActionDescriptor.create(ResetViewLocationsAction, ResetViewLocationsAction.ID, ResetViewLocationsAction.LABEL), 'View: Reset View Locations', viewCategory);
|
||||||
|
|
||||||
|
|
||||||
// --- Resize View
|
// --- Resize View
|
||||||
|
|
||||||
export abstract class BaseResizeViewAction extends Action {
|
export abstract class BaseResizeViewAction extends Action {
|
||||||
|
|||||||
@@ -1180,6 +1180,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||||||
} else {
|
} else {
|
||||||
this.setEditorHidden(false);
|
this.setEditorHidden(false);
|
||||||
this.workbenchGrid.resizeView(this.panelPartView, { width: this.state.panel.position === Position.BOTTOM ? size.width : this.state.panel.lastNonMaximizedWidth, height: this.state.panel.position === Position.BOTTOM ? this.state.panel.lastNonMaximizedHeight : size.height });
|
this.workbenchGrid.resizeView(this.panelPartView, { width: this.state.panel.position === Position.BOTTOM ? size.width : this.state.panel.lastNonMaximizedWidth, height: this.state.panel.position === Position.BOTTOM ? this.state.panel.lastNonMaximizedHeight : size.height });
|
||||||
|
this.editorGroupService.activeGroup.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ import { ToggleActivityBarVisibilityAction, ToggleMenuBarAction } from 'vs/workb
|
|||||||
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
||||||
import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND, ACTIVITY_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme';
|
import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND, ACTIVITY_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme';
|
||||||
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||||
import { CompositeBar, ICompositeBarItem } from 'vs/workbench/browser/parts/compositeBar';
|
import { CompositeBar, ICompositeBarItem, CompositeDragAndDrop } from 'vs/workbench/browser/parts/compositeBar';
|
||||||
import { Dimension, addClass, removeNode } from 'vs/base/browser/dom';
|
import { Dimension, addClass, removeNode } from 'vs/base/browser/dom';
|
||||||
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
import { ToggleCompositePinnedAction, ICompositeBarColors, ActivityAction, ICompositeActivity } from 'vs/workbench/browser/parts/compositeBarActions';
|
import { ToggleCompositePinnedAction, ICompositeBarColors, ActivityAction, ICompositeActivity } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||||
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
|
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
|
||||||
import { IViewDescriptorService, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainer, TEST_VIEW_CONTAINER_ID, IViewDescriptorCollection } from 'vs/workbench/common/views';
|
import { IViewDescriptorService, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainer, TEST_VIEW_CONTAINER_ID, IViewDescriptorCollection, ViewContainerLocation } from 'vs/workbench/common/views';
|
||||||
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { IViewlet } from 'vs/workbench/common/viewlet';
|
import { IViewlet } from 'vs/workbench/common/viewlet';
|
||||||
import { isUndefinedOrNull, assertIsDefined } from 'vs/base/common/types';
|
import { isUndefinedOrNull, assertIsDefined } from 'vs/base/common/types';
|
||||||
@@ -128,6 +128,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
|||||||
getContextMenuActionsForComposite: () => [],
|
getContextMenuActionsForComposite: () => [],
|
||||||
getDefaultCompositeId: () => this.viewletService.getDefaultViewletId(),
|
getDefaultCompositeId: () => this.viewletService.getDefaultViewletId(),
|
||||||
hidePart: () => this.layoutService.setSideBarHidden(true),
|
hidePart: () => this.layoutService.setSideBarHidden(true),
|
||||||
|
dndHandler: new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Sidebar,
|
||||||
|
(id: string, focus?: boolean) => this.viewletService.openViewlet(id, focus),
|
||||||
|
(from: string, to: string) => this.compositeBar.move(from, to),
|
||||||
|
() => this.getPinnedViewletIds()
|
||||||
|
),
|
||||||
compositeSize: 50,
|
compositeSize: 50,
|
||||||
colors: (theme: ITheme) => this.getActivitybarItemColors(theme),
|
colors: (theme: ITheme) => this.getActivitybarItemColors(theme),
|
||||||
overflowActionSize: ActivitybarPart.ACTION_HEIGHT
|
overflowActionSize: ActivitybarPart.ACTION_HEIGHT
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ import { isUndefinedOrNull } from 'vs/base/common/types';
|
|||||||
import { LocalSelectionTransfer } from 'vs/workbench/browser/dnd';
|
import { LocalSelectionTransfer } from 'vs/workbench/browser/dnd';
|
||||||
import { ITheme } from 'vs/platform/theme/common/themeService';
|
import { ITheme } from 'vs/platform/theme/common/themeService';
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
|
import { DraggedViewIdentifier } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||||
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
import { IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/common/views';
|
||||||
|
import { ICompositeDragAndDrop, CompositeDragAndDropData } from 'vs/base/parts/composite/browser/compositeDnd';
|
||||||
|
|
||||||
export interface ICompositeBarItem {
|
export interface ICompositeBarItem {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -29,12 +33,120 @@ export interface ICompositeBarItem {
|
|||||||
visible: boolean;
|
visible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class CompositeDragAndDrop implements ICompositeDragAndDrop {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private viewDescriptorService: IViewDescriptorService,
|
||||||
|
private targetContainerLocation: ViewContainerLocation,
|
||||||
|
private openComposite: (id: string, focus?: boolean) => void,
|
||||||
|
private moveComposite: (from: string, to: string) => void,
|
||||||
|
private getVisibleCompositeIds: () => string[]
|
||||||
|
) { }
|
||||||
|
drop(data: CompositeDragAndDropData, targetCompositeId: string | undefined, originalEvent: DragEvent): void {
|
||||||
|
const dragData = data.getData();
|
||||||
|
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
|
||||||
|
|
||||||
|
if (dragData.type === 'composite') {
|
||||||
|
const currentContainer = viewContainerRegistry.get(dragData.id)!;
|
||||||
|
const currentLocation = viewContainerRegistry.getViewContainerLocation(currentContainer);
|
||||||
|
if (targetCompositeId) {
|
||||||
|
if (currentLocation !== this.targetContainerLocation && this.targetContainerLocation !== ViewContainerLocation.Panel) {
|
||||||
|
const destinationContainer = viewContainerRegistry.get(targetCompositeId);
|
||||||
|
if (destinationContainer) {
|
||||||
|
this.viewDescriptorService.moveViewsToContainer(this.viewDescriptorService.getViewDescriptors(currentContainer)!.allViewDescriptors.filter(vd => vd.canMoveView), destinationContainer);
|
||||||
|
this.openComposite(targetCompositeId, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.moveComposite(dragData.id, targetCompositeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const viewDescriptor = this.viewDescriptorService.getViewDescriptor(dragData.id);
|
||||||
|
if (viewDescriptor && viewDescriptor.canMoveView) {
|
||||||
|
if (targetCompositeId) {
|
||||||
|
const destinationContainer = viewContainerRegistry.get(targetCompositeId);
|
||||||
|
if (destinationContainer) {
|
||||||
|
if (this.targetContainerLocation === ViewContainerLocation.Sidebar) {
|
||||||
|
this.viewDescriptorService.moveViewsToContainer([viewDescriptor], destinationContainer);
|
||||||
|
this.openComposite(targetCompositeId, true);
|
||||||
|
} else {
|
||||||
|
this.viewDescriptorService.moveViewToLocation(viewDescriptor, this.targetContainerLocation);
|
||||||
|
this.moveComposite(this.viewDescriptorService.getViewContainer(viewDescriptor.id)!.id, targetCompositeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.viewDescriptorService.moveViewToLocation(viewDescriptor, this.targetContainerLocation);
|
||||||
|
const newCompositeId = this.viewDescriptorService.getViewContainer(dragData.id)!.id;
|
||||||
|
const visibleItems = this.getVisibleCompositeIds();
|
||||||
|
const targetId = visibleItems.length ? visibleItems[visibleItems.length - 1] : undefined;
|
||||||
|
if (targetId && targetId !== newCompositeId) {
|
||||||
|
this.moveComposite(newCompositeId, targetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.openComposite(newCompositeId, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDragOver(data: CompositeDragAndDropData, targetCompositeId: string | undefined, originalEvent: DragEvent): boolean {
|
||||||
|
const dragData = data.getData();
|
||||||
|
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
|
||||||
|
|
||||||
|
if (dragData.type === 'composite') {
|
||||||
|
// Dragging a composite
|
||||||
|
const currentContainer = viewContainerRegistry.get(dragData.id)!;
|
||||||
|
const currentLocation = viewContainerRegistry.getViewContainerLocation(currentContainer);
|
||||||
|
|
||||||
|
// ... to the same location
|
||||||
|
if (currentLocation === this.targetContainerLocation) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... across view containers but without a destination composite
|
||||||
|
if (!targetCompositeId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... from panel to the sidebar
|
||||||
|
if (this.targetContainerLocation === ViewContainerLocation.Sidebar) {
|
||||||
|
const destinationContainer = viewContainerRegistry.get(targetCompositeId);
|
||||||
|
return !!destinationContainer &&
|
||||||
|
this.viewDescriptorService.getViewDescriptors(currentContainer)!.allViewDescriptors.some(vd => vd.canMoveView);
|
||||||
|
}
|
||||||
|
// ... from sidebar to the panel
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Dragging an individual view
|
||||||
|
const viewDescriptor = this.viewDescriptorService.getViewDescriptor(dragData.id);
|
||||||
|
|
||||||
|
// ... that cannot move
|
||||||
|
if (!viewDescriptor || !viewDescriptor.canMoveView) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... to create a view container
|
||||||
|
if (!targetCompositeId) {
|
||||||
|
return this.targetContainerLocation === ViewContainerLocation.Panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... into a destination
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface ICompositeBarOptions {
|
export interface ICompositeBarOptions {
|
||||||
readonly icon: boolean;
|
readonly icon: boolean;
|
||||||
readonly orientation: ActionsOrientation;
|
readonly orientation: ActionsOrientation;
|
||||||
readonly colors: (theme: ITheme) => ICompositeBarColors;
|
readonly colors: (theme: ITheme) => ICompositeBarColors;
|
||||||
readonly compositeSize: number;
|
readonly compositeSize: number;
|
||||||
readonly overflowActionSize: number;
|
readonly overflowActionSize: number;
|
||||||
|
readonly dndHandler: ICompositeDragAndDrop;
|
||||||
|
|
||||||
getActivityAction: (compositeId: string) => ActivityAction;
|
getActivityAction: (compositeId: string) => ActivityAction;
|
||||||
getCompositePinnedAction: (compositeId: string) => Action;
|
getCompositePinnedAction: (compositeId: string) => Action;
|
||||||
@@ -58,7 +170,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
|
|||||||
private visibleComposites: string[];
|
private visibleComposites: string[];
|
||||||
private compositeSizeInBar: Map<string, number>;
|
private compositeSizeInBar: Map<string, number>;
|
||||||
|
|
||||||
private compositeTransfer: LocalSelectionTransfer<DraggedCompositeIdentifier>;
|
private compositeTransfer: LocalSelectionTransfer<DraggedCompositeIdentifier | DraggedViewIdentifier>;
|
||||||
|
|
||||||
private readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
|
private readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
|
||||||
readonly onDidChange = this._onDidChange.event;
|
readonly onDidChange = this._onDidChange.event;
|
||||||
@@ -107,6 +219,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
|
|||||||
() => this.getContextMenuActions() as Action[],
|
() => this.getContextMenuActions() as Action[],
|
||||||
this.options.colors,
|
this.options.colors,
|
||||||
this.options.icon,
|
this.options.icon,
|
||||||
|
this.options.dndHandler,
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -134,6 +247,46 @@ export class CompositeBar extends Widget implements ICompositeBar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) {
|
||||||
|
const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype);
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
const draggedViewId = data[0].id;
|
||||||
|
this.compositeTransfer.clearData(DraggedViewIdentifier.prototype);
|
||||||
|
|
||||||
|
this.options.dndHandler.drop(new CompositeDragAndDropData('view', draggedViewId), undefined, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._register(addDisposableListener(parent, EventType.DRAG_OVER, (e: DragEvent) => {
|
||||||
|
if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) {
|
||||||
|
EventHelper.stop(e, true);
|
||||||
|
|
||||||
|
const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype);
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
const draggedCompositeId = data[0].id;
|
||||||
|
|
||||||
|
// Check if drop is allowed
|
||||||
|
if (e.dataTransfer && !this.options.dndHandler.onDragOver(new CompositeDragAndDropData('composite', draggedCompositeId), undefined, e)) {
|
||||||
|
e.dataTransfer.dropEffect = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) {
|
||||||
|
EventHelper.stop(e, true);
|
||||||
|
|
||||||
|
const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype);
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
const draggedViewId = data[0].id;
|
||||||
|
|
||||||
|
// Check if drop is allowed
|
||||||
|
if (e.dataTransfer && !this.options.dndHandler.onDragOver(new CompositeDragAndDropData('view', draggedViewId), undefined, e)) {
|
||||||
|
e.dataTransfer.dropEffect = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return actionBarDiv;
|
return actionBarDiv;
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
|||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
import { DragAndDropObserver, LocalSelectionTransfer } from 'vs/workbench/browser/dnd';
|
import { DragAndDropObserver, LocalSelectionTransfer } from 'vs/workbench/browser/dnd';
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
|
import { DraggedViewIdentifier } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||||
|
import { ICompositeDragAndDrop, CompositeDragAndDropData } from 'vs/base/parts/composite/browser/compositeDnd';
|
||||||
|
|
||||||
export interface ICompositeActivity {
|
export interface ICompositeActivity {
|
||||||
badge: IBadge;
|
badge: IBadge;
|
||||||
@@ -458,7 +460,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
|
|||||||
private static manageExtensionAction: ManageExtensionAction;
|
private static manageExtensionAction: ManageExtensionAction;
|
||||||
|
|
||||||
private compositeActivity: IActivity | undefined;
|
private compositeActivity: IActivity | undefined;
|
||||||
private compositeTransfer: LocalSelectionTransfer<DraggedCompositeIdentifier>;
|
private compositeTransfer: LocalSelectionTransfer<DraggedCompositeIdentifier | DraggedViewIdentifier>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private compositeActivityAction: ActivityAction,
|
private compositeActivityAction: ActivityAction,
|
||||||
@@ -467,6 +469,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
|
|||||||
private contextMenuActionsProvider: () => ReadonlyArray<Action>,
|
private contextMenuActionsProvider: () => ReadonlyArray<Action>,
|
||||||
colors: (theme: ITheme) => ICompositeBarColors,
|
colors: (theme: ITheme) => ICompositeBarColors,
|
||||||
icon: boolean,
|
icon: boolean,
|
||||||
|
private dndHandler: ICompositeDragAndDrop,
|
||||||
private compositeBar: ICompositeBar,
|
private compositeBar: ICompositeBar,
|
||||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||||
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||||
@@ -475,7 +478,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
|
|||||||
) {
|
) {
|
||||||
super(compositeActivityAction, { draggable: true, colors, icon }, themeService);
|
super(compositeActivityAction, { draggable: true, colors, icon }, themeService);
|
||||||
|
|
||||||
this.compositeTransfer = LocalSelectionTransfer.getInstance<DraggedCompositeIdentifier>();
|
this.compositeTransfer = LocalSelectionTransfer.getInstance<DraggedCompositeIdentifier | DraggedViewIdentifier>();
|
||||||
|
|
||||||
if (!CompositeActionViewItem.manageExtensionAction) {
|
if (!CompositeActionViewItem.manageExtensionAction) {
|
||||||
CompositeActionViewItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction);
|
CompositeActionViewItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction);
|
||||||
@@ -546,6 +549,31 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onDragOver: e => {
|
||||||
|
dom.EventHelper.stop(e, true);
|
||||||
|
if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) {
|
||||||
|
const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype);
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
const draggedCompositeId = data[0].id;
|
||||||
|
if (draggedCompositeId !== this.activity.id) {
|
||||||
|
if (e.dataTransfer && !this.dndHandler.onDragOver(new CompositeDragAndDropData('composite', draggedCompositeId), this.activity.id, e)) {
|
||||||
|
e.dataTransfer.dropEffect = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) {
|
||||||
|
const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype);
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
const draggedViewId = data[0].id;
|
||||||
|
if (e.dataTransfer && !this.dndHandler.onDragOver(new CompositeDragAndDropData('view', draggedViewId), this.activity.id, e)) {
|
||||||
|
e.dataTransfer.dropEffect = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onDragLeave: e => {
|
onDragLeave: e => {
|
||||||
if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) {
|
if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) {
|
||||||
this.updateFromDragging(container, false);
|
this.updateFromDragging(container, false);
|
||||||
@@ -571,16 +599,27 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
|
|||||||
this.updateFromDragging(container, false);
|
this.updateFromDragging(container, false);
|
||||||
this.compositeTransfer.clearData(DraggedCompositeIdentifier.prototype);
|
this.compositeTransfer.clearData(DraggedCompositeIdentifier.prototype);
|
||||||
|
|
||||||
this.compositeBar.move(draggedCompositeId, this.activity.id);
|
this.dndHandler.drop(new CompositeDragAndDropData('composite', draggedCompositeId), this.activity.id, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) {
|
||||||
|
const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype);
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
const draggedViewId = data[0].id;
|
||||||
|
|
||||||
|
this.dndHandler.drop(new CompositeDragAndDropData('view', draggedViewId), this.activity.id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Activate on drag over to reveal targets
|
// Activate on drag over to reveal targets
|
||||||
[this.badge, this.label].forEach(b => this._register(new DelayedDragHandler(b, () => {
|
[this.badge, this.label].forEach(b => this._register(new DelayedDragHandler(b, () => {
|
||||||
if (!this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype) && !this.getAction().checked) {
|
if (!(this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype) ||
|
||||||
|
this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) &&
|
||||||
|
!this.getAction().checked) {
|
||||||
this.getAction().run();
|
this.getAction().run();
|
||||||
}
|
}
|
||||||
})));
|
})));
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import { ClosePanelAction, PanelActivityAction, ToggleMaximizedPanelAction, Togg
|
|||||||
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||||
import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_DRAG_AND_DROP_BACKGROUND, PANEL_INPUT_BORDER } from 'vs/workbench/common/theme';
|
import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_DRAG_AND_DROP_BACKGROUND, PANEL_INPUT_BORDER } from 'vs/workbench/common/theme';
|
||||||
import { activeContrastBorder, focusBorder, contrastBorder, editorBackground, badgeBackground, badgeForeground } from 'vs/platform/theme/common/colorRegistry';
|
import { activeContrastBorder, focusBorder, contrastBorder, editorBackground, badgeBackground, badgeForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||||
import { CompositeBar, ICompositeBarItem } from 'vs/workbench/browser/parts/compositeBar';
|
import { CompositeBar, ICompositeBarItem, CompositeDragAndDrop } from 'vs/workbench/browser/parts/compositeBar';
|
||||||
import { ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
|
import { ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||||
import { IBadge } from 'vs/workbench/services/activity/common/activity';
|
import { IBadge } from 'vs/workbench/services/activity/common/activity';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
@@ -33,7 +33,7 @@ import { IContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/con
|
|||||||
import { isUndefinedOrNull, assertIsDefined } from 'vs/base/common/types';
|
import { isUndefinedOrNull, assertIsDefined } from 'vs/base/common/types';
|
||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, IViewDescriptorService, IViewDescriptorCollection } from 'vs/workbench/common/views';
|
import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, IViewDescriptorService, IViewDescriptorCollection, ViewContainerLocation } from 'vs/workbench/common/views';
|
||||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||||
import { ViewMenuActions } from 'vs/workbench/browser/parts/views/viewMenuActions';
|
import { ViewMenuActions } from 'vs/workbench/browser/parts/views/viewMenuActions';
|
||||||
|
|
||||||
@@ -142,6 +142,11 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
|||||||
getContextMenuActionsForComposite: (compositeId: string) => this.getContextMenuActionsForComposite(compositeId) as Action[],
|
getContextMenuActionsForComposite: (compositeId: string) => this.getContextMenuActionsForComposite(compositeId) as Action[],
|
||||||
getDefaultCompositeId: () => this.panelRegistry.getDefaultPanelId(),
|
getDefaultCompositeId: () => this.panelRegistry.getDefaultPanelId(),
|
||||||
hidePart: () => this.layoutService.setPanelHidden(true),
|
hidePart: () => this.layoutService.setPanelHidden(true),
|
||||||
|
dndHandler: new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Panel,
|
||||||
|
(id: string, focus?: boolean) => this.openPanel(id, focus),
|
||||||
|
(from: string, to: string) => this.compositeBar.move(from, to),
|
||||||
|
() => this.getPinnedPanels().map(p => p.id)
|
||||||
|
),
|
||||||
compositeSize: 0,
|
compositeSize: 0,
|
||||||
overflowActionSize: 44,
|
overflowActionSize: 44,
|
||||||
colors: (theme: ITheme) => ({
|
colors: (theme: ITheme) => ({
|
||||||
@@ -397,7 +402,17 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
|||||||
|
|
||||||
getPanels(): readonly PanelDescriptor[] {
|
getPanels(): readonly PanelDescriptor[] {
|
||||||
return this.panelRegistry.getPanels()
|
return this.panelRegistry.getPanels()
|
||||||
.sort((v1, v2) => typeof v1.order === 'number' && typeof v2.order === 'number' ? v1.order - v2.order : NaN);
|
.sort((v1, v2) => {
|
||||||
|
if (typeof v1.order !== 'number') {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof v2.order !== 'number') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v1.order - v2.order;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getPinnedPanels(): readonly PanelDescriptor[] {
|
getPinnedPanels(): readonly PanelDescriptor[] {
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import { parseLinkedText } from 'vs/base/common/linkedText';
|
|||||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
import { Button } from 'vs/base/browser/ui/button/button';
|
import { Button } from 'vs/base/browser/ui/button/button';
|
||||||
import { Link } from 'vs/platform/opener/browser/link';
|
import { Link } from 'vs/platform/opener/browser/link';
|
||||||
|
import { LocalSelectionTransfer } from 'vs/workbench/browser/dnd';
|
||||||
|
|
||||||
export interface IPaneColors extends IColorMapping {
|
export interface IPaneColors extends IColorMapping {
|
||||||
dropBackground?: ColorIdentifier;
|
dropBackground?: ColorIdentifier;
|
||||||
@@ -57,6 +58,15 @@ export interface IViewPaneOptions extends IPaneOptions {
|
|||||||
titleMenuId?: MenuId;
|
titleMenuId?: MenuId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class DraggedViewIdentifier {
|
||||||
|
constructor(private _viewId: string) { }
|
||||||
|
|
||||||
|
get id(): string {
|
||||||
|
return this._viewId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const viewsRegistry = Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry);
|
const viewsRegistry = Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry);
|
||||||
|
|
||||||
interface IItem {
|
interface IItem {
|
||||||
@@ -444,6 +454,8 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
|||||||
private paneItems: IViewPaneItem[] = [];
|
private paneItems: IViewPaneItem[] = [];
|
||||||
private paneview?: PaneView;
|
private paneview?: PaneView;
|
||||||
|
|
||||||
|
private static viewTransfer = LocalSelectionTransfer.getInstance<DraggedViewIdentifier>();
|
||||||
|
|
||||||
private visible: boolean = false;
|
private visible: boolean = false;
|
||||||
|
|
||||||
private areExtensionsReady: boolean = false;
|
private areExtensionsReady: boolean = false;
|
||||||
@@ -874,6 +886,22 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
|||||||
|
|
||||||
this.paneItems.splice(index, 0, paneItem);
|
this.paneItems.splice(index, 0, paneItem);
|
||||||
assertIsDefined(this.paneview).addPane(pane, size, index);
|
assertIsDefined(this.paneview).addPane(pane, size, index);
|
||||||
|
|
||||||
|
this._register(addDisposableListener(pane.draggableElement, EventType.DRAG_START, (e: DragEvent) => {
|
||||||
|
if (e.dataTransfer) {
|
||||||
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register as dragged to local transfer
|
||||||
|
ViewPaneContainer.viewTransfer.setData([new DraggedViewIdentifier(pane.id)], DraggedViewIdentifier.prototype);
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
this._register(addDisposableListener(pane.draggableElement, EventType.DRAG_END, (e: DragEvent) => {
|
||||||
|
if (ViewPaneContainer.viewTransfer.hasData(DraggedViewIdentifier.prototype)) {
|
||||||
|
ViewPaneContainer.viewTransfer.clearData(DraggedViewIdentifier.prototype);
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
removePanes(panes: ViewPane[]): void {
|
removePanes(panes: ViewPane[]): void {
|
||||||
@@ -952,7 +980,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
|||||||
}
|
}
|
||||||
if (!this.areExtensionsReady) {
|
if (!this.areExtensionsReady) {
|
||||||
if (this.visibleViewsCountFromCache === undefined) {
|
if (this.visibleViewsCountFromCache === undefined) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
// Check in cache so that view do not jump. See #29609
|
// Check in cache so that view do not jump. See #29609
|
||||||
return this.visibleViewsCountFromCache === 1;
|
return this.visibleViewsCountFromCache === 1;
|
||||||
|
|||||||
@@ -591,7 +591,7 @@ export class ViewsService extends Disposable implements IViewsService {
|
|||||||
}
|
}
|
||||||
run(accessor: ServicesAccessor): any {
|
run(accessor: ServicesAccessor): any {
|
||||||
accessor.get(IViewDescriptorService).moveViewToLocation(viewDescriptor, newLocation);
|
accessor.get(IViewDescriptorService).moveViewToLocation(viewDescriptor, newLocation);
|
||||||
accessor.get(IViewsService).openView(viewDescriptor.id);
|
accessor.get(IViewsService).openView(viewDescriptor.id, true);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import { IFileService, FileSystemProviderCapabilities } from 'vs/platform/files/
|
|||||||
import { IPathData } from 'vs/platform/windows/common/windows';
|
import { IPathData } from 'vs/platform/windows/common/windows';
|
||||||
import { coalesce, firstOrDefault } from 'vs/base/common/arrays';
|
import { coalesce, firstOrDefault } from 'vs/base/common/arrays';
|
||||||
import { ITextFileSaveOptions, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileSaveOptions, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { isEqual, dirname } from 'vs/base/common/resources';
|
import { isEqual, dirname } from 'vs/base/common/resources';
|
||||||
import { IPanel } from 'vs/workbench/common/panel';
|
import { IPanel } from 'vs/workbench/common/panel';
|
||||||
import { IRange } from 'vs/editor/common/core/range';
|
import { IRange } from 'vs/editor/common/core/range';
|
||||||
@@ -345,6 +345,11 @@ export interface IRevertOptions {
|
|||||||
readonly soft?: boolean;
|
readonly soft?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IMoveResult {
|
||||||
|
editor: IEditorInput | IResourceEditor;
|
||||||
|
options?: IEditorOptions;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IEditorInput extends IDisposable {
|
export interface IEditorInput extends IDisposable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -446,6 +451,16 @@ export interface IEditorInput extends IDisposable {
|
|||||||
*/
|
*/
|
||||||
revert(group: GroupIdentifier, options?: IRevertOptions): Promise<boolean>;
|
revert(group: GroupIdentifier, options?: IRevertOptions): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to determine how to handle a resource that is moved that matches
|
||||||
|
* the editors resource (or is a child of).
|
||||||
|
*
|
||||||
|
* Implementors are free to not implement this method to signal no intent
|
||||||
|
* to participate. If an editor is returned though, it will replace the
|
||||||
|
* current one with that editor and optional options.
|
||||||
|
*/
|
||||||
|
move(group: GroupIdentifier, target: URI): IMoveResult | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if the other object matches this input.
|
* Returns if the other object matches this input.
|
||||||
*/
|
*/
|
||||||
@@ -546,6 +561,10 @@ export abstract class EditorInput extends Disposable implements IEditorInput {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
move(group: GroupIdentifier, target: URI): IMoveResult | undefined {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclasses can set this to false if it does not make sense to split the editor input.
|
* Subclasses can set this to false if it does not make sense to split the editor input.
|
||||||
*/
|
*/
|
||||||
@@ -780,6 +799,11 @@ export interface IFileEditorInput extends IEditorInput, IEncodingSupport, IModeS
|
|||||||
* Forces this file input to open as binary instead of text.
|
* Forces this file input to open as binary instead of text.
|
||||||
*/
|
*/
|
||||||
setForceOpenAsBinary(): void;
|
setForceOpenAsBinary(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Figure out if the input has been resolved or not.
|
||||||
|
*/
|
||||||
|
isResolved(): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1209,6 +1233,8 @@ export class TextEditorOptions extends EditorOptions implements ITextEditorOptio
|
|||||||
|
|
||||||
if (this.selectionRevealType === TextEditorSelectionRevealType.NearTop) {
|
if (this.selectionRevealType === TextEditorSelectionRevealType.NearTop) {
|
||||||
editor.revealRangeNearTop(range, scrollType);
|
editor.revealRangeNearTop(range, scrollType);
|
||||||
|
} else if (this.selectionRevealType === TextEditorSelectionRevealType.NearTopIfOutsideViewport) {
|
||||||
|
editor.revealRangeNearTopIfOutsideViewport(range, scrollType);
|
||||||
} else if (this.selectionRevealType === TextEditorSelectionRevealType.CenterIfOutsideViewport) {
|
} else if (this.selectionRevealType === TextEditorSelectionRevealType.CenterIfOutsideViewport) {
|
||||||
editor.revealRangeInCenterIfOutsideViewport(range, scrollType);
|
editor.revealRangeInCenterIfOutsideViewport(range, scrollType);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user