| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import * as assert from '../../../base/common/assert.js';
- import { Emitter } from '../../../base/common/event.js';
- import { Disposable } from '../../../base/common/lifecycle.js';
- import * as objects from '../../../base/common/objects.js';
- import { Range } from '../../common/core/range.js';
- const defaultOptions = {
- followsCaret: true,
- ignoreCharChanges: true,
- alwaysRevealFirst: true
- };
- /**
- * Create a new diff navigator for the provided diff editor.
- */
- export class DiffNavigator extends Disposable {
- constructor(editor, options = {}) {
- super();
- this._onDidUpdate = this._register(new Emitter());
- this._editor = editor;
- this._options = objects.mixin(options, defaultOptions, false);
- this.disposed = false;
- this.nextIdx = -1;
- this.ranges = [];
- this.ignoreSelectionChange = false;
- this.revealFirst = Boolean(this._options.alwaysRevealFirst);
- // hook up to diff editor for diff, disposal, and caret move
- this._register(this._editor.onDidDispose(() => this.dispose()));
- this._register(this._editor.onDidUpdateDiff(() => this._onDiffUpdated()));
- if (this._options.followsCaret) {
- this._register(this._editor.getModifiedEditor().onDidChangeCursorPosition((e) => {
- if (this.ignoreSelectionChange) {
- return;
- }
- this.nextIdx = -1;
- }));
- }
- if (this._options.alwaysRevealFirst) {
- this._register(this._editor.getModifiedEditor().onDidChangeModel((e) => {
- this.revealFirst = true;
- }));
- }
- // init things
- this._init();
- }
- _init() {
- const changes = this._editor.getLineChanges();
- if (!changes) {
- return;
- }
- }
- _onDiffUpdated() {
- this._init();
- this._compute(this._editor.getLineChanges());
- if (this.revealFirst) {
- // Only reveal first on first non-null changes
- if (this._editor.getLineChanges() !== null) {
- this.revealFirst = false;
- this.nextIdx = -1;
- this.next(1 /* ScrollType.Immediate */);
- }
- }
- }
- _compute(lineChanges) {
- // new ranges
- this.ranges = [];
- if (lineChanges) {
- // create ranges from changes
- lineChanges.forEach((lineChange) => {
- if (!this._options.ignoreCharChanges && lineChange.charChanges) {
- lineChange.charChanges.forEach((charChange) => {
- this.ranges.push({
- rhs: true,
- range: new Range(charChange.modifiedStartLineNumber, charChange.modifiedStartColumn, charChange.modifiedEndLineNumber, charChange.modifiedEndColumn)
- });
- });
- }
- else {
- if (lineChange.modifiedEndLineNumber === 0) {
- // a deletion
- this.ranges.push({
- rhs: true,
- range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedStartLineNumber + 1, 1)
- });
- }
- else {
- // an insertion or modification
- this.ranges.push({
- rhs: true,
- range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber + 1, 1)
- });
- }
- }
- });
- }
- // sort
- this.ranges.sort((left, right) => Range.compareRangesUsingStarts(left.range, right.range));
- this._onDidUpdate.fire(this);
- }
- _initIdx(fwd) {
- let found = false;
- const position = this._editor.getPosition();
- if (!position) {
- this.nextIdx = 0;
- return;
- }
- for (let i = 0, len = this.ranges.length; i < len && !found; i++) {
- const range = this.ranges[i].range;
- if (position.isBeforeOrEqual(range.getStartPosition())) {
- this.nextIdx = i + (fwd ? 0 : -1);
- found = true;
- }
- }
- if (!found) {
- // after the last change
- this.nextIdx = fwd ? 0 : this.ranges.length - 1;
- }
- if (this.nextIdx < 0) {
- this.nextIdx = this.ranges.length - 1;
- }
- }
- _move(fwd, scrollType) {
- assert.ok(!this.disposed, 'Illegal State - diff navigator has been disposed');
- if (!this.canNavigate()) {
- return;
- }
- if (this.nextIdx === -1) {
- this._initIdx(fwd);
- }
- else if (fwd) {
- this.nextIdx += 1;
- if (this.nextIdx >= this.ranges.length) {
- this.nextIdx = 0;
- }
- }
- else {
- this.nextIdx -= 1;
- if (this.nextIdx < 0) {
- this.nextIdx = this.ranges.length - 1;
- }
- }
- const info = this.ranges[this.nextIdx];
- this.ignoreSelectionChange = true;
- try {
- const pos = info.range.getStartPosition();
- this._editor.setPosition(pos);
- this._editor.revealRangeInCenter(info.range, scrollType);
- }
- finally {
- this.ignoreSelectionChange = false;
- }
- }
- canNavigate() {
- return this.ranges && this.ranges.length > 0;
- }
- next(scrollType = 0 /* ScrollType.Smooth */) {
- this._move(true, scrollType);
- }
- previous(scrollType = 0 /* ScrollType.Smooth */) {
- this._move(false, scrollType);
- }
- dispose() {
- super.dispose();
- this.ranges = [];
- this.disposed = true;
- }
- }
|