| /* |
| * 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); |
| } |
| }; |