history - introduce and use new JUMP source

This commit is contained in:
Benjamin Pasero
2022-02-10 10:21:34 +01:00
parent c7647ef43b
commit e98deca874
9 changed files with 83 additions and 37 deletions
@@ -32,7 +32,7 @@ import * as nls from 'vs/nls';
import { ISubmenuItem, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor';
import { TextEditorSelectionRevealType, TextEditorSelectionSource } from 'vs/platform/editor/common/editor';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -202,7 +202,8 @@ export abstract class SymbolNavigationAction extends EditorAction {
resource: reference.uri,
options: {
selection: Range.collapseToStart(range),
selectionRevealType: TextEditorSelectionRevealType.NearTopIfOutsideViewport
selectionRevealType: TextEditorSelectionRevealType.NearTopIfOutsideViewport,
selectionSource: TextEditorSelectionSource.JUMP
}
}, editor, sideBySide);
@@ -19,6 +19,7 @@ import * as nls from 'vs/nls';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { TextEditorSelectionSource } from 'vs/platform/editor/common/editor';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IListService, WorkbenchListFocusContextKey, WorkbenchTreeElementCanCollapse, WorkbenchTreeElementCanExpand } from 'vs/platform/list/browser/listService';
@@ -246,7 +247,7 @@ export abstract class ReferencesController implements IEditorContribution {
return this._editorService.openCodeEditor({
resource: ref.uri,
options: { selection: range }
options: { selection: range, selectionSource: TextEditorSelectionSource.JUMP }
}, this._editor).then(openedEditor => {
this._ignoreModelChangeEvent = false;
@@ -292,7 +293,7 @@ export abstract class ReferencesController implements IEditorContribution {
const { uri, range } = ref;
this._editorService.openCodeEditor({
resource: uri,
options: { selection: range, pinned }
options: { selection: range, selectionSource: TextEditorSelectionSource.JUMP, pinned }
}, this._editor, sideBySide);
}
}
+19 -5
View File
@@ -328,16 +328,25 @@ export const enum TextEditorSelectionSource {
/**
* Programmatic source indicates a selection change that
* was not triggered by the user via keyboard or mouse.
* was not triggered by the user via keyboard or mouse
* but through text editor APIs.
*/
PROGRAMMATIC = 'api',
/**
* Navigation source indicates a change that was caused
* by navigating in the text editor from commands such
* as "Go to definition"
* Navigation source indicates a selection change that
* was caused via some command or UI component such as
* an outline tree.
*/
NAVIGATION = 'code.navigation'
NAVIGATION = 'code.navigation',
/**
* Jump source indicates a selection change that
* was caused from within the text editor to another
* location in the same or different text editor such
* as "Go to definition".
*/
JUMP = 'code.jump'
}
export interface ITextEditorOptions extends IEditorOptions {
@@ -352,4 +361,9 @@ export interface ITextEditorOptions extends IEditorOptions {
* Defaults to TextEditorSelectionRevealType.Center
*/
selectionRevealType?: TextEditorSelectionRevealType;
/**
* Source of the call that caused the selection.
*/
selectionSource?: TextEditorSelectionSource | string;
}
@@ -153,6 +153,7 @@ export abstract class BaseTextEditor<T extends IEditorViewState> extends Abstrac
switch (e.source) {
case TextEditorSelectionSource.PROGRAMMATIC: return EditorPaneSelectionChangeReason.PROGRAMMATIC;
case TextEditorSelectionSource.NAVIGATION: return EditorPaneSelectionChangeReason.NAVIGATION;
case TextEditorSelectionSource.JUMP: return EditorPaneSelectionChangeReason.JUMP;
default: return EditorPaneSelectionChangeReason.USER;
}
}
+12 -3
View File
@@ -223,10 +223,19 @@ export const enum EditorPaneSelectionChangeReason {
* The selection was changed as a result of a navigation
* action.
*
* For a text editor pane, this for example can be invoking
* "Go to definition" on a symbol.
* For a text editor pane, this for example can be a result
* of selecting an entry from a text outline view.
*/
NAVIGATION
NAVIGATION,
/**
* The selection was changed as a result of a jump action
* from within the editor pane.
*
* For a text editor pane, this for example can be a result
* of invoking "Go to definition" from a symbol.
*/
JUMP
}
export interface IEditorPaneSelection {
@@ -25,10 +25,11 @@ export function applyTextEditorOptions(options: ITextEditorOptions, editor: IEdi
endColumn: options.selection.endColumn ?? options.selection.startColumn
};
// Apply selection and give it a `TextEditorSelectionSource`
// so that listeners can distinguish this selection change
// from others.
editor.setSelection(range, TextEditorSelectionSource.NAVIGATION);
// Apply selection with a source so that listeners can
// distinguish this selection change from others.
// If no source is provided, set a default source to
// signal this navigation.
editor.setSelection(range, options.selectionSource ?? TextEditorSelectionSource.NAVIGATION);
// Reveal selection
if (options.selectionRevealType === TextEditorSelectionRevealType.NearTop) {
@@ -310,6 +310,7 @@ export class HistoryService extends Disposable implements IHistoryService {
}
private handleActiveEditorSelectionChangeEventInNavigationStacks(editorPane: IEditorPaneWithSelection, event: IEditorPaneSelectionChangeEvent): void {
const previous = this.globalDefaultEditorNavigationStack.current;
// Always send to global navigation stack
this.globalDefaultEditorNavigationStack.notifyNavigation(editorPane, event);
@@ -324,15 +325,17 @@ export class HistoryService extends Disposable implements IHistoryService {
// Note: ignore if global navigation stack is navigating because
// in that case we do not want to receive repeated entries in
// the navigation stack.
else if (event.reason === EditorPaneSelectionChangeReason.NAVIGATION && !this.globalDefaultEditorNavigationStack.isNavigating()) {
else if (
(event.reason === EditorPaneSelectionChangeReason.NAVIGATION || event.reason === EditorPaneSelectionChangeReason.JUMP) &&
!this.globalDefaultEditorNavigationStack.isNavigating()
) {
// A navigation selection change always has a source and target
// As such, we add the previous entry of the global navigation
// stack so that our navigation stack receives both entries
// unless the user is currently navigating.
// A "JUMP" navigation selection change always has a source and
// target. As such, we add the previous entry of the global
// navigation stack so that our navigation stack receives both
// entries unless the user is currently navigating.
if (!this.globalNavigationsEditorNavigationStack.isNavigating()) {
const previous = this.globalDefaultEditorNavigationStack.previous;
if (event.reason === EditorPaneSelectionChangeReason.JUMP && !this.globalNavigationsEditorNavigationStack.isNavigating()) {
if (previous) {
this.globalNavigationsEditorNavigationStack.addOrReplace(previous.groupId, previous.editor, previous.selection);
}
@@ -1035,7 +1038,7 @@ export class EditorNavigationStack extends Disposable {
private currentSelectionState: EditorSelectionState | undefined = undefined;
private get current(): IEditorNavigationStackEntry | undefined {
get current(): IEditorNavigationStackEntry | undefined {
return this.stack[this.index];
}
@@ -1045,10 +1048,6 @@ export class EditorNavigationStack extends Disposable {
}
}
get previous(): IEditorNavigationStackEntry | undefined {
return this.stack[this.index - 1];
}
constructor(
private readonly kind: GoFilter,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@@ -1120,6 +1119,7 @@ ${entryLabels.join('\n')}
switch (event.reason) {
case EditorPaneSelectionChangeReason.EDIT: return 'edit';
case EditorPaneSelectionChangeReason.NAVIGATION: return 'navigation';
case EditorPaneSelectionChangeReason.JUMP: return 'jump';
case EditorPaneSelectionChangeReason.PROGRAMMATIC: return 'programmatic';
case EditorPaneSelectionChangeReason.USER: return 'user';
}
@@ -171,6 +171,33 @@ suite('HistoryService', function () {
await historyService.goBack(GoFilter.NAVIGATION);
assertTextSelection(new Selection(5, 3, 5, 20), pane);
await historyService.goBack(GoFilter.NAVIGATION);
assertTextSelection(new Selection(5, 3, 5, 20), pane);
await historyService.goForward(GoFilter.NAVIGATION);
assertTextSelection(new Selection(120, 8, 120, 18), pane);
await historyService.goPrevious(GoFilter.NAVIGATION);
assertTextSelection(new Selection(5, 3, 5, 20), pane);
await historyService.goPrevious(GoFilter.NAVIGATION);
assertTextSelection(new Selection(120, 8, 120, 18), pane);
});
test('back / forward: in-editor text selection changes (jump)', async function () {
const [, historyService, editorService] = await createServices();
const resource = toResource.call(this, '/path/index.txt');
const pane = await editorService.openEditor({ resource, options: { pinned: true } }) as TestTextFileEditor;
await setTextSelection(historyService, pane, new Selection(2, 2, 2, 10), EditorPaneSelectionChangeReason.USER);
await setTextSelection(historyService, pane, new Selection(5, 3, 5, 20), EditorPaneSelectionChangeReason.JUMP);
await setTextSelection(historyService, pane, new Selection(120, 8, 120, 18), EditorPaneSelectionChangeReason.JUMP);
await historyService.goBack(GoFilter.NAVIGATION);
assertTextSelection(new Selection(5, 3, 5, 20), pane);
await historyService.goBack(GoFilter.NAVIGATION);
assertTextSelection(new Selection(2, 2, 2, 10), pane);
@@ -186,16 +186,8 @@ export class TestTextFileEditor extends TextFileEditor {
return this.instantiationService.createInstance(TestCodeEditor, parent, configuration, {});
}
fireSelectionChangeEvent(reason: EditorPaneSelectionChangeReason) {
this._onDidChangeSelection.fire({ reason });
}
setSelection(selection: Selection | undefined, reason: EditorPaneSelectionChangeReason): void {
if (selection) {
this.setOptions({ selection });
} else {
this.setOptions(undefined);
}
this._options = selection ? { selection } as IEditorOptions : undefined;
this._onDidChangeSelection.fire({ reason });
}