diff --git a/src/cursor-view.coffee b/src/cursor-view.coffee deleted file mode 100644 index a3d67264b..000000000 --- a/src/cursor-view.coffee +++ /dev/null @@ -1,113 +0,0 @@ -{View} = require './space-pen-extensions' -_ = require 'underscore-plus' - -module.exports = -class CursorView extends View - @content: -> - @div class: 'cursor idle', => @raw ' ' - - @blinkPeriod: 800 - - @blinkCursors: -> - element.classList.toggle('blink-off') for [element] in @cursorViews - - @startBlinking: (cursorView) -> - @cursorViews ?= [] - @cursorViews.push(cursorView) - if @cursorViews.length is 1 - @blinkInterval = setInterval(@blinkCursors.bind(this), @blinkPeriod / 2) - - @stopBlinking: (cursorView) -> - cursorView[0].classList.remove('blink-off') - _.remove(@cursorViews, cursorView) - clearInterval(@blinkInterval) if @cursorViews.length is 0 - - blinking: false - visible: true - needsUpdate: true - needsRemoval: false - shouldPauseBlinking: false - - initialize: (@cursor, @editorView) -> - @subscribe @cursor, 'moved', => - @needsUpdate = true - @shouldPauseBlinking = true - - @subscribe @cursor, 'visibility-changed', => - @needsUpdate = true - - @subscribe @cursor, 'autoscrolled', => - @editorView.requestDisplayUpdate() - - @subscribe @cursor, 'destroyed', => - @needsRemoval = true - - beforeRemove: -> - @editorView.removeCursorView(this) - @stopBlinking() - - updateDisplay: -> - screenPosition = @getScreenPosition() - pixelPosition = @getPixelPosition() - - unless _.isEqual(@lastPixelPosition, pixelPosition) - @lastPixelPosition = pixelPosition - @css(pixelPosition) - @trigger 'cursor:moved' - - if @shouldPauseBlinking - @resetBlinking() - else if !@startBlinkingTimeout - @startBlinking() - - @setVisible(@cursor.isVisible() and not @editorView.getEditor().isFoldedAtScreenRow(screenPosition.row)) - - # Override for speed. The base function checks the computedStyle - isHidden: -> - this[0].style.display is 'none' or not @isOnDom() - - needsAutoscroll: -> - @cursor.needsAutoscroll - - clearAutoscroll: -> - @cursor.clearAutoscroll() - - getPixelPosition: -> - @editorView.pixelPositionForScreenPosition(@getScreenPosition()) - - setVisible: (visible) -> - unless @visible is visible - @visible = visible - hiddenCursor = 'hidden-cursor' - if visible - @removeClass hiddenCursor - else - @addClass hiddenCursor - - stopBlinking: -> - @constructor.stopBlinking(this) if @blinking - @blinking = false - - startBlinking: -> - @constructor.startBlinking(this) unless @blinking - @blinking = true - - resetBlinking: -> - @stopBlinking() - @startBlinking() - - getBufferPosition: -> - @cursor.getBufferPosition() - - getScreenPosition: -> - @cursor.getScreenPosition() - - removeIdleClassTemporarily: -> - @removeClass 'idle' - window.clearTimeout(@idleTimeout) if @idleTimeout - @idleTimeout = window.setTimeout (=> @addClass 'idle'), 200 - - resetCursorAnimation: -> - window.clearTimeout(@idleTimeout) if @idleTimeout - @removeClass 'idle' - _.defer => @addClass 'idle' diff --git a/src/gutter-view.coffee b/src/gutter-view.coffee deleted file mode 100644 index 088d3740f..000000000 --- a/src/gutter-view.coffee +++ /dev/null @@ -1,275 +0,0 @@ -{View, $, $$, $$$} = require './space-pen-extensions' -{Range} = require 'text-buffer' -_ = require 'underscore-plus' - -# Represents the portion of the {EditorView} containing row numbers. -# -# The gutter also indicates if rows are folded. -module.exports = -class GutterView extends View - @content: -> - @div class: 'gutter', => - @div outlet: 'lineNumbers', class: 'line-numbers' - - firstScreenRow: null - lastScreenRow: null - - initialize: -> - @elementBuilder = document.createElement('div') - - afterAttach: (onDom) -> - return if @attached or not onDom - @attached = true - - highlightLines = => @highlightLines() - @getEditorView().on 'cursor:moved', highlightLines - @getEditorView().on 'selection:changed', highlightLines - @on 'mousedown', (e) => @handleMouseEvents(e) - - beforeRemove: -> - $(document).off(".gutter-#{@getEditorView().id}") - - handleMouseEvents: (e) -> - editorView = @getEditorView() - editor = @getEditor() - startRow = editorView.screenPositionFromMouseEvent(e).row - if e.shiftKey - editor.selectToScreenPosition([startRow + 1, 0]) - return - else - editor.getSelection().setScreenRange([[startRow, 0], [startRow, 0]]) - - moveHandler = (e) -> - start = startRow - end = editorView.screenPositionFromMouseEvent(e).row - if end > start then end++ else start++ - editor.getSelection().setScreenRange([[start, 0], [end, 0]]) - - $(document).on "mousemove.gutter-#{editorView.id}", moveHandler - $(document).one "mouseup.gutter-#{editorView.id}", -> $(document).off 'mousemove', moveHandler - - # Retrieves the containing {EditorView}. - # - # Returns an {EditorView}. - getEditorView: -> - @parentView - - getEditor: -> - @getEditorView().getEditor() - - # Defines whether to show the gutter or not. - # - # showLineNumbers - A {Boolean} which, if `false`, hides the gutter - setShowLineNumbers: (showLineNumbers) -> - if showLineNumbers then @lineNumbers.show() else @lineNumbers.hide() - - # Get all the line-number divs. - # - # Returns a list of {HTMLElement}s. - getLineNumberElements: -> - @lineNumbers[0].children - - # Get all the line-number divs. - # - # Returns a list of {HTMLElement}s. - getLineNumberElementsForClass: (klass) -> - @lineNumbers[0].getElementsByClassName(klass) - - # Get a single line-number div. - # - # * bufferRow: 0 based line number - # - # Returns a list of {HTMLElement}s that correspond to the bufferRow. More than - # one in the list indicates a wrapped line. - getLineNumberElement: (bufferRow) -> - @getLineNumberElementsForClass("line-number-#{bufferRow}") - - # Add a class to all line-number divs. - # - # * klass: string class name - # - # Returns true if the class was added to any lines - addClassToAllLines: (klass) -> - elements = @getLineNumberElements() - el.classList.add(klass) for el in elements - !!elements.length - - # Remove a class from all line-number divs. - # - # * klass: string class name. Can only be one class name. i.e. 'my-class' - # - # Returns true if the class was removed from any lines - removeClassFromAllLines: (klass) -> - # This is faster than calling $.removeClass on all lines, and faster than - # making a new array and iterating through it. - elements = @getLineNumberElementsForClass(klass) - willRemoveClasses = !!elements.length - elements[0].classList.remove(klass) while elements.length > 0 - willRemoveClasses - - # Add a class to a single line-number div - # - # * bufferRow: 0 based line number - # * klass: string class name - # - # Returns true if there were lines the class was added to - addClassToLine: (bufferRow, klass) -> - elements = @getLineNumberElement(bufferRow) - el.classList.add(klass) for el in elements - !!elements.length - - # Remove a class from a single line-number div - # - # * bufferRow: 0 based line number - # * klass: string class name - # - # Returns true if there were lines the class was removed from - removeClassFromLine: (bufferRow, klass) -> - classesRemoved = false - elements = @getLineNumberElement(bufferRow) - for el in elements - hasClass = el.classList.contains(klass) - classesRemoved |= hasClass - el.classList.remove(klass) if hasClass - classesRemoved - - updateLineNumbers: (changes, startScreenRow, endScreenRow) -> - # Check if we have something already rendered that overlaps the requested range - updateAllLines = not (startScreenRow? and endScreenRow?) - updateAllLines |= endScreenRow <= @firstScreenRow or startScreenRow >= @lastScreenRow - - unless updateAllLines - for change in changes - if change.screenDelta or change.bufferDelta - updateAllLines = true - break - - # Rebuild the entire gutter if a change added or removed lines - if updateAllLines - @lineNumbers[0].innerHTML = @buildLineElementsHtml(startScreenRow, endScreenRow) - - # Handle changes that didn't add/remove lines more optimally - else - if startScreenRow < @firstScreenRow - @prependLineElements(@buildLineElements(startScreenRow, @firstScreenRow-1)) - else if startScreenRow != @firstScreenRow - @removeLineElements(startScreenRow - @firstScreenRow) - - if endScreenRow > @lastScreenRow - @appendLineElements(@buildLineElements(@lastScreenRow+1, endScreenRow)) - else if endScreenRow != @lastScreenRow - @removeLineElements(endScreenRow - @lastScreenRow) - - @updateFoldableClasses(changes) - - @firstScreenRow = startScreenRow - @lastScreenRow = endScreenRow - @highlightedRows = null - @highlightLines() - - prependLineElements: (lineElements) -> - anchor = @lineNumbers[0].children[0] - return appendLineElements(lineElements) unless anchor? - @lineNumbers[0].insertBefore(lineElements[0], anchor) while lineElements.length > 0 - null # defeat coffeescript array return - - appendLineElements: (lineElements) -> - @lineNumbers[0].appendChild(lineElements[0]) while lineElements.length > 0 - null # defeat coffeescript array return - - removeLineElements: (numberOfElements) -> - children = @getLineNumberElements() - - # children is a live NodeList, so remove from the desired end {numberOfElements} times - if numberOfElements < 0 - @lineNumbers[0].removeChild(children[children.length-1]) while numberOfElements++ - else if numberOfElements > 0 - @lineNumbers[0].removeChild(children[0]) while numberOfElements-- - - null # defeat coffeescript array return - - buildLineElements: (startScreenRow, endScreenRow) -> - @elementBuilder.innerHTML = @buildLineElementsHtml(startScreenRow, endScreenRow) - @elementBuilder.children - - buildLineElementsHtml: (startScreenRow, endScreenRow) => - editor = @getEditor() - maxDigits = editor.getLineCount().toString().length - rows = editor.bufferRowsForScreenRows(startScreenRow, endScreenRow) - - html = '' - for row in rows - if row is lastRow - rowValue = '•' - else - rowValue = (row + 1).toString() - - classes = "line-number line-number-#{row}" - classes += ' foldable' if row isnt lastRow and editor.isFoldableAtBufferRow(row) - classes += ' folded' if editor.isFoldedAtBufferRow(row) - - rowValuePadding = _.multiplyString(' ', maxDigits - rowValue.length) - - html += """
#{rowValuePadding}#{rowValue}
""" - - lastRow = row - - html - - # Called to update the 'foldable' class of line numbers when there's - # a change to the display buffer that doesn't regenerate all the line numbers - # anyway. - updateFoldableClasses: (changes) -> - editor = @getEditor() - for {start, end} in changes when start <= @lastScreenRow and end >= @firstScreenRow - startScreenRow = Math.max(start - 1, @firstScreenRow) - endScreenRow = Math.min(end + 1, @lastScreenRow) - lastBufferRow = null - for bufferRow in editor.bufferRowsForScreenRows(startScreenRow, endScreenRow) when bufferRow isnt lastBufferRow - lastBufferRow = bufferRow - if lineNumberElement = @getLineNumberElement(bufferRow)[0] - if editor.isFoldableAtBufferRow(bufferRow) - lineNumberElement.classList.add('foldable') - else - lineNumberElement.classList.remove('foldable') - - removeLineHighlights: -> - return unless @highlightedLineNumbers - for line in @highlightedLineNumbers - line.classList.remove('cursor-line') - line.classList.remove('cursor-line-no-selection') - @highlightedLineNumbers = null - - addLineHighlight: (row, emptySelection) -> - return if row < @firstScreenRow or row > @lastScreenRow - @highlightedLineNumbers ?= [] - if highlightedLineNumber = @lineNumbers[0].children[row - @firstScreenRow] - highlightedLineNumber.classList.add('cursor-line') - highlightedLineNumber.classList.add('cursor-line-no-selection') if emptySelection - @highlightedLineNumbers.push(highlightedLineNumber) - - highlightLines: -> - editor = @getEditor() - return unless editor?.isAlive() - - if editor.getSelection().isEmpty() - row = editor.getCursorScreenPosition().row - rowRange = new Range([row, 0], [row, 0]) - return if @selectionEmpty and @highlightedRows?.isEqual(rowRange) - - @removeLineHighlights() - @addLineHighlight(row, true) - @highlightedRows = rowRange - @selectionEmpty = true - else - selectedRows = editor.getSelection().getScreenRange() - endRow = selectedRows.end.row - endRow-- if selectedRows.end.column is 0 - selectedRows = new Range([selectedRows.start.row, 0], [endRow, 0]) - return if not @selectionEmpty and @highlightedRows?.isEqual(selectedRows) - - @removeLineHighlights() - for row in [selectedRows.start.row..selectedRows.end.row] - @addLineHighlight(row, false) - @highlightedRows = selectedRows - @selectionEmpty = false diff --git a/src/selection-view.coffee b/src/selection-view.coffee deleted file mode 100644 index e0413b30c..000000000 --- a/src/selection-view.coffee +++ /dev/null @@ -1,85 +0,0 @@ -{Point, Range} = require 'text-buffer' -{View, $$} = require './space-pen-extensions' - -module.exports = -class SelectionView extends View - - @content: -> - @div class: 'selection' - - regions: null - needsRemoval: false - - initialize: ({@editorView, @selection} = {}) -> - @regions = [] - @selection.on 'screen-range-changed', => @editorView.requestDisplayUpdate() - @selection.on 'destroyed', => - @needsRemoval = true - @editorView.requestDisplayUpdate() - - updateDisplay: -> - @clearRegions() - range = @getScreenRange() - - @trigger 'selection:changed' - @editorView.highlightFoldsContainingBufferRange(@getBufferRange()) - return if range.isEmpty() - - rowSpan = range.end.row - range.start.row - - if rowSpan == 0 - @appendRegion(1, range.start, range.end) - else - @appendRegion(1, range.start, null) - if rowSpan > 1 - @appendRegion(rowSpan - 1, { row: range.start.row + 1, column: 0}, null) - @appendRegion(1, { row: range.end.row, column: 0 }, range.end) - - appendRegion: (rows, start, end) -> - { lineHeight, charWidth } = @editorView - css = @editorView.pixelPositionForScreenPosition(start) - css.height = lineHeight * rows - if end - css.width = @editorView.pixelPositionForScreenPosition(end).left - css.left - else - css.right = 0 - - region = ($$ -> @div class: 'region').css(css) - @append(region) - @regions.push(region) - - getCenterPixelPosition: -> - { start, end } = @getScreenRange() - startRow = start.row - endRow = end.row - endRow-- if end.column == 0 - @editorView.pixelPositionForScreenPosition([((startRow + endRow + 1) / 2), start.column]) - - clearRegions: -> - region.remove() for region in @regions - @regions = [] - - getScreenRange: -> - @selection.getScreenRange() - - getBufferRange: -> - @selection.getBufferRange() - - needsAutoscroll: -> - @selection.needsAutoscroll - - clearAutoscroll: -> - @selection.clearAutoscroll() - - highlight: -> - @unhighlight() - @addClass('highlighted') - clearTimeout(@unhighlightTimeout) - @unhighlightTimeout = setTimeout((=> @unhighlight()), 1000) - - unhighlight: -> - @removeClass('highlighted') - - remove: -> - @editorView.removeSelectionView(this) - super