blob: 3ee065a6857e0f337da0991f4958dba7e9bf56db [file] [log] [blame]
/*
* Copyright (C) 2014 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @unrestricted
*/
Sources.EditingLocationHistoryManager = class {
/**
* @param {!Sources.SourcesView} sourcesView
* @param {function():?Sources.UISourceCodeFrame} currentSourceFrameCallback
*/
constructor(sourcesView, currentSourceFrameCallback) {
this._sourcesView = sourcesView;
this._historyManager = new Sources.SimpleHistoryManager(Sources.EditingLocationHistoryManager.HistoryDepth);
this._currentSourceFrameCallback = currentSourceFrameCallback;
}
/**
* @param {!Sources.UISourceCodeFrame} sourceFrame
*/
trackSourceFrameCursorJumps(sourceFrame) {
sourceFrame.textEditor.addEventListener(
SourceFrame.SourcesTextEditor.Events.JumpHappened, this._onJumpHappened.bind(this));
}
/**
* @param {!Common.Event} event
*/
_onJumpHappened(event) {
if (event.data.from) {
this._updateActiveState(event.data.from);
}
if (event.data.to) {
this._pushActiveState(event.data.to);
}
}
rollback() {
this._historyManager.rollback();
}
rollover() {
this._historyManager.rollover();
}
updateCurrentState() {
const sourceFrame = this._currentSourceFrameCallback();
if (!sourceFrame) {
return;
}
this._updateActiveState(sourceFrame.textEditor.selection());
}
pushNewState() {
const sourceFrame = this._currentSourceFrameCallback();
if (!sourceFrame) {
return;
}
this._pushActiveState(sourceFrame.textEditor.selection());
}
/**
* @param {!TextUtils.TextRange} selection
*/
_updateActiveState(selection) {
const active = this._historyManager.active();
if (!active) {
return;
}
const sourceFrame = this._currentSourceFrameCallback();
if (!sourceFrame) {
return;
}
const entry = new Sources.EditingLocationHistoryEntry(this._sourcesView, this, sourceFrame, selection);
active.merge(entry);
}
/**
* @param {!TextUtils.TextRange} selection
*/
_pushActiveState(selection) {
const sourceFrame = this._currentSourceFrameCallback();
if (!sourceFrame) {
return;
}
const entry = new Sources.EditingLocationHistoryEntry(this._sourcesView, this, sourceFrame, selection);
this._historyManager.push(entry);
}
/**
* @param {!Workspace.UISourceCode} uiSourceCode
*/
removeHistoryForSourceCode(uiSourceCode) {
function filterOut(entry) {
return entry._projectId === uiSourceCode.project().id() && entry._url === uiSourceCode.url();
}
this._historyManager.filterOut(filterOut);
}
};
Sources.EditingLocationHistoryManager.HistoryDepth = 20;
/**
* @implements {Sources.HistoryEntry}
* @unrestricted
*/
Sources.EditingLocationHistoryEntry = class {
/**
* @param {!Sources.SourcesView} sourcesView
* @param {!Sources.EditingLocationHistoryManager} editingLocationManager
* @param {!Sources.UISourceCodeFrame} sourceFrame
* @param {!TextUtils.TextRange} selection
*/
constructor(sourcesView, editingLocationManager, sourceFrame, selection) {
this._sourcesView = sourcesView;
this._editingLocationManager = editingLocationManager;
const uiSourceCode = sourceFrame.uiSourceCode();
this._projectId = uiSourceCode.project().id();
this._url = uiSourceCode.url();
const position = this._positionFromSelection(selection);
this._positionHandle = sourceFrame.textEditor.textEditorPositionHandle(position.lineNumber, position.columnNumber);
}
/**
* @param {!Sources.HistoryEntry} entry
*/
merge(entry) {
if (this._projectId !== entry._projectId || this._url !== entry._url) {
return;
}
this._positionHandle = entry._positionHandle;
}
/**
* @param {!TextUtils.TextRange} selection
* @return {!{lineNumber: number, columnNumber: number}}
*/
_positionFromSelection(selection) {
return {lineNumber: selection.endLine, columnNumber: selection.endColumn};
}
/**
* @override
* @return {boolean}
*/
valid() {
const position = this._positionHandle.resolve();
const uiSourceCode = Workspace.workspace.uiSourceCode(this._projectId, this._url);
return !!(position && uiSourceCode);
}
/**
* @override
*/
reveal() {
const position = this._positionHandle.resolve();
const uiSourceCode = Workspace.workspace.uiSourceCode(this._projectId, this._url);
if (!position || !uiSourceCode) {
return;
}
this._editingLocationManager.updateCurrentState();
this._sourcesView.showSourceLocation(uiSourceCode, position.lineNumber, position.columnNumber);
}
};