提交 379b3204 编写于 作者: J Johannes Rieken

first cut of #14783

上级 ee02bc3d
......@@ -17,12 +17,16 @@ import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { registerEditorAction, registerEditorContribution, ServicesAccessor, IActionOptions, EditorAction, EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { } from 'vs/platform/theme/common/colorRegistry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { MarkerNavigationWidget } from './gotoErrorWidget';
import { compare } from 'vs/base/common/strings';
import { binarySearch } from 'vs/base/common/arrays';
import { IEditorService } from 'vs/platform/editor/common/editor';
import { TPromise } from 'vs/base/common/winjs.base';
class MarkerModel {
......@@ -47,9 +51,13 @@ class MarkerModel {
// listen on editor
this._toUnbind.push(this._editor.onDidDispose(() => this.dispose()));
this._toUnbind.push(this._editor.onDidChangeCursorPosition(() => {
if (!this._ignoreSelectionChange) {
this._nextIdx = -1;
if (this._ignoreSelectionChange) {
return;
}
if (this.currentMarker && Range.containsPosition(this.currentMarker, this._editor.getPosition())) {
return;
}
this._nextIdx = -1;
}));
}
......@@ -62,13 +70,15 @@ class MarkerModel {
}
public setMarkers(markers: IMarker[]): void {
// assign
this._markers = markers || [];
// sort markers
this._markers.sort((left, right) => Severity.compare(left.severity, right.severity) || Range.compareRangesUsingStarts(left, right));
this._nextIdx = -1;
let oldMarker = this._nextIdx >= 0 ? this._markers[this._nextIdx] : undefined;
this._markers = markers || [];
this._markers.sort(MarkerNavigationAction.compareMarker);
if (!oldMarker) {
this._nextIdx = -1;
} else {
this._nextIdx = Math.max(-1, binarySearch(this._markers, oldMarker, MarkerNavigationAction.compareMarker));
}
this._onMarkerSetChanged.fire(this);
}
......@@ -95,7 +105,7 @@ class MarkerModel {
}
if (range.containsPosition(position) || position.isBeforeOrEqual(range.getStartPosition())) {
this._nextIdx = i + (fwd ? 0 : -1);
this._nextIdx = i;
found = true;
break;
}
......@@ -109,29 +119,43 @@ class MarkerModel {
}
}
public move(fwd: boolean, circle: boolean): boolean {
get currentMarker(): IMarker {
return this.canNavigate() ? this._markers[this._nextIdx] : undefined;
}
public move(fwd: boolean, inCircles: boolean): boolean {
if (!this.canNavigate()) {
this._onCurrentMarkerChanged.fire(undefined);
return false;
return !inCircles;
}
let old = this._nextIdx;
let oldIdx = this._nextIdx;
let atEdge = false;
if (this._nextIdx === -1) {
this._initIdx(fwd);
} else if (fwd) {
this._nextIdx = (this._nextIdx + 1) % this._markers.length;
} else {
this._nextIdx = (this._nextIdx - 1 + this._markers.length) % this._markers.length;
if (inCircles || this._nextIdx + 1 < this._markers.length) {
this._nextIdx = (this._nextIdx + 1) % this._markers.length;
} else {
atEdge = true;
}
} else if (!fwd) {
if (inCircles || this._nextIdx > 0) {
this._nextIdx = (this._nextIdx - 1 + this._markers.length) % this._markers.length;
} else {
atEdge = true;
}
}
if (circle || old === -1 || fwd && old < this._nextIdx || !fwd && old > this._nextIdx) {
if (oldIdx !== this._nextIdx) {
const marker = this._markers[this._nextIdx];
this._onCurrentMarkerChanged.fire(marker);
return false;
}
// we circled, didn't send an event, and return `true`
return true;
return atEdge;
}
public canNavigate(): boolean {
......@@ -160,26 +184,6 @@ class MarkerModel {
}
}
class MarkerNavigationAction extends EditorAction {
private _isNext: boolean;
constructor(next: boolean, opts: IActionOptions) {
super(opts);
this._isNext = next;
}
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
const controller = MarkerController.get(editor);
if (!controller) {
return;
}
const model = controller.getOrCreateModel();
model.move(this._isNext, true);
}
}
class MarkerController implements editorCommon.IEditorContribution {
private static readonly ID = 'editor.contrib.markerController';
......@@ -274,6 +278,79 @@ class MarkerController implements editorCommon.IEditorContribution {
}
}
class MarkerNavigationAction extends EditorAction {
private _isNext: boolean;
constructor(next: boolean, opts: IActionOptions) {
super(opts);
this._isNext = next;
}
public run(accessor: ServicesAccessor, editor: ICodeEditor): TPromise<void> {
const markerService = accessor.get(IMarkerService);
const editorService = accessor.get(IEditorService);
const controller = MarkerController.get(editor);
if (!controller) {
return undefined;
}
const model = controller.getOrCreateModel();
const atEdge = model.move(this._isNext, false);
if (!atEdge) {
return undefined;
}
// try with the next/prev file
let oldMarker = model.currentMarker || { resource: editor.getModel().uri, severity: Severity.Error, startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 };
let markers = markerService.read().sort(MarkerNavigationAction.compareMarker);
let idx = binarySearch(markers, oldMarker, MarkerNavigationAction.compareMarker);
if (idx < 0) {
// find best match...
idx = ~idx;
idx %= markers.length;
} else if (this._isNext) {
idx = (idx + 1) % markers.length;
} else {
idx = (idx + markers.length - 1) % markers.length;
}
let newMarker = markers[idx];
if (newMarker.resource.toString() === editor.getModel().uri.toString()) {
// the next `resource` is this resource which
// means we cycle within this file
model.move(this._isNext, true);
return undefined;
}
// close the widget for this editor-instance, open the resource
// for the next marker and re-start marker navigation in there
controller.closeMarkersNavigation();
return editorService.openEditor({
resource: newMarker.resource,
options: { pinned: false, revealIfOpened: true, revealInCenterIfOutsideViewport: true, selection: newMarker }
}).then(editor => {
if (!editor || !isCodeEditor(editor.getControl())) {
return undefined;
}
return (<ICodeEditor>editor.getControl()).getAction(this.id).run();
});
}
static compareMarker(a: IMarker, b: IMarker): number {
let res = compare(a.resource.toString(), b.resource.toString());
if (res === 0) {
res = Severity.compare(a.severity, b.severity);
}
if (res === 0) {
res = Range.compareRangesUsingStarts(a, b);
}
return res;
}
}
class NextMarkerAction extends MarkerNavigationAction {
constructor() {
super(true, {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册