{View, $$, $$$} = require 'space-pen' Range = require 'range' $ = require 'jquery' _ = require 'underscore' module.exports = class Gutter extends View @content: -> @div class: 'gutter', => @div outlet: 'lineNumbers', class: 'line-numbers' firstScreenRow: Infinity lastScreenRow: -1 highestNumberWidth: null afterAttach: (onDom) -> return if @attached or not onDom @attached = true highlightLines = => @highlightLines() @getEditor().on 'cursor:moved', highlightLines @getEditor().on 'selection:changed', highlightLines @on 'mousedown', (e) => @handleMouseEvents(e) getEditor: -> @parentView beforeRemove: -> $(document).off(".gutter-#{@getEditor().id}") handleMouseEvents: (e) -> editor = @getEditor() startRow = editor.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 = editor.screenPositionFromMouseEvent(e).row if end > start then end++ else start++ editor.getSelection().setScreenRange([[start, 0], [end, 0]]) $(document).on "mousemove.gutter-#{@getEditor().id}", moveHandler $(document).one "mouseup.gutter-#{@getEditor().id}", => $(document).off 'mousemove', moveHandler setShowLineNumbers: (showLineNumbers) -> if showLineNumbers then @lineNumbers.show() else @lineNumbers.hide() updateLineNumbers: (changes, renderFrom, renderTo) -> if renderFrom < @firstScreenRow or renderTo > @lastScreenRow performUpdate = true else if @getEditor().getLastScreenRow() < @lastScreenRow performUpdate = true else for change in changes if change.delta != 0 or (change.bufferDelta? and change.bufferDelta != 0) performUpdate = true break @renderLineNumbers(renderFrom, renderTo) if performUpdate renderLineNumbers: (startScreenRow, endScreenRow) -> editor = @getEditor() maxDigits = editor.getLineCount().toString().length rows = editor.bufferRowsForScreenRows(startScreenRow, endScreenRow) cursorScreenRow = editor.getCursorScreenPosition().row @lineNumbers[0].innerHTML = $$$ -> for row in rows if row == lastScreenRow rowValue = '•' else rowValue = (row + 1).toString() classes = ['line-number'] classes.push('fold') if editor.isFoldedAtBufferRow(row) @div lineNumber: row, class: classes.join(' '), => rowValuePadding = _.multiplyString(' ', maxDigits - rowValue.length) @raw("#{rowValuePadding}#{rowValue}") lastScreenRow = row @firstScreenRow = startScreenRow @lastScreenRow = endScreenRow @highlightedRows = null @highlightLines() 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: -> if @getEditor().getSelection().isEmpty() row = @getEditor().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 = @getEditor().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