Files
atom/src/app/language-mode.coffee
Corey Johnson & Nathan Sobo 7fe6a05594 Folding no longer relies on Ace.
Indentation is used to determine foldable regions, if the last line matches TextMate's foldEndRegex it is included in the foldable region.
2012-08-08 17:42:11 -07:00

112 lines
3.9 KiB
CoffeeScript

AceAdaptor = require 'ace-adaptor'
Range = require 'range'
TextMateBundle = require 'text-mate-bundle'
_ = require 'underscore'
module.exports =
class LanguageMode
pairedCharacters:
'(': ')'
'[': ']'
'{': '}'
'"': '"'
"'": "'"
constructor: (@editSession) ->
@buffer = @editSession.buffer
@aceMode = @requireAceMode()
@grammar = TextMateBundle.grammarForFileName(@editSession.buffer.getBaseName())
@aceAdaptor = new AceAdaptor(@editSession)
_.adviseBefore @editSession, 'insertText', (text) =>
return true if @editSession.hasMultipleCursors()
cursorBufferPosition = @editSession.getCursorBufferPosition()
nextCharachter = @editSession.getTextInBufferRange([cursorBufferPosition, cursorBufferPosition.add([0, 1])])
if @isCloseBracket(text) and text == nextCharachter
@editSession.moveCursorRight()
false
else if pairedCharacter = @pairedCharacters[text]
@editSession.insertText text + pairedCharacter
@editSession.moveCursorLeft()
false
requireAceMode: (fileExtension) ->
modeName = switch @editSession.buffer.getExtension()
when 'js' then 'javascript'
when 'coffee' then 'coffee'
when 'rb', 'ru' then 'ruby'
when 'c', 'h', 'cpp' then 'c_cpp'
when 'html', 'htm' then 'html'
when 'css' then 'css'
when 'java' then 'java'
when 'xml' then 'xml'
else 'text'
new (require("ace/mode/#{modeName}").Mode)
isOpenBracket: (string) ->
@pairedCharacters[string]?
isCloseBracket: (string) ->
@getInvertedPairedCharacters()[string]?
getInvertedPairedCharacters: ->
return @invertedPairedCharacters if @invertedPairedCharacters
@invertedPairedCharacters = {}
for open, close of @pairedCharacters
@invertedPairedCharacters[close] = open
@invertedPairedCharacters
toggleLineCommentsInRange: (range) ->
range = Range.fromObject(range)
@aceMode.toggleCommentLines(@tokenizedBuffer.stackForRow(range.start.row), @aceAdaptor, range.start.row, range.end.row)
doesBufferRowStartFold: (bufferRow) ->
return false if @editSession.isBufferRowBlank(bufferRow)
nextNonEmptyRow = @editSession.nextNonBlankBufferRow(bufferRow)
return false unless nextNonEmptyRow?
@editSession.indentationForBufferRow(nextNonEmptyRow) > @editSession.indentationForBufferRow(bufferRow)
rowRangeForFoldAtBufferRow: (bufferRow) ->
return null unless @doesBufferRowStartFold(bufferRow)
startIndentation = @editSession.indentationForBufferRow(bufferRow)
for row in [(bufferRow + 1)..@editSession.getLastBufferRow()]
continue if @editSession.isBufferRowBlank(row)
indentation = @editSession.indentationForBufferRow(row)
if indentation <= startIndentation
includeRowInFold = indentation == startIndentation and @grammar.foldEndRegex.search(@editSession.lineForBufferRow(row))
foldEndRow = row if includeRowInFold
break
foldEndRow = row
[bufferRow, foldEndRow]
indentationForRow: (row) ->
for precedingRow in [row - 1..-1]
return if precedingRow < 0
precedingLine = @editSession.buffer.lineForRow(precedingRow)
break if /\S/.test(precedingLine)
scopes = @tokenizedBuffer.scopesForPosition([precedingRow, Infinity])
indentation = precedingLine.match(/^\s*/)[0]
increaseIndentPattern = TextMateBundle.getPreferenceInScope(scopes[0], 'increaseIndentPattern')
decreaseIndentPattern = TextMateBundle.getPreferenceInScope(scopes[0], 'decreaseIndentPattern')
if new OnigRegExp(increaseIndentPattern).search(precedingLine)
indentation += @editSession.tabText
line = @editSession.buffer.lineForRow(row)
if new OnigRegExp(decreaseIndentPattern).search(line)
indentation = indentation.replace(@editSession.tabText, "")
indentation
getLineTokens: (line, stack) ->
{tokens, stack} = @grammar.getLineTokens(line, stack)