diff --git a/src/language-mode.coffee b/src/language-mode.coffee index 34dad3dc5..b7a52280b 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -2,6 +2,7 @@ _ = require 'underscore-plus' {OnigRegExp} = require 'oniguruma' {Emitter, Subscriber} = require 'emissary' +ScopeDescriptor = require './scope-descriptor' module.exports = class LanguageMode @@ -228,11 +229,20 @@ class LanguageMode # # Returns a {Number}. suggestedIndentForBufferRow: (bufferRow, options) -> + tokenizedLine = @editor.displayBuffer.tokenizedBuffer.tokenizedLineForRow(bufferRow) + @suggestedIndentForTokenizedLineAtBufferRow(bufferRow, tokenizedLine, options) + + suggestedIndentForLineAtBufferRow: (bufferRow, line, options) -> + tokenizedLine = @editor.displayBuffer.tokenizedBuffer.buildTokenizedLineForRowWithText(bufferRow, line) + @suggestedIndentForTokenizedLineAtBufferRow(bufferRow, tokenizedLine, options) + + suggestedIndentForTokenizedLineAtBufferRow: (bufferRow, tokenizedLine, options) -> + scopes = tokenizedLine.tokens[0].scopes + scopeDescriptor = new ScopeDescriptor({scopes}) + currentIndentLevel = @editor.indentationForBufferRow(bufferRow) - scopeDescriptor = @editor.scopeDescriptorForBufferPosition([bufferRow, 0]) return currentIndentLevel unless increaseIndentRegex = @increaseIndentRegexForScopeDescriptor(scopeDescriptor) - currentLine = @buffer.lineForRow(bufferRow) if options?.skipBlankLines ? true precedingRow = @buffer.previousNonBlankRow(bufferRow) return 0 unless precedingRow? @@ -245,7 +255,7 @@ class LanguageMode desiredIndentLevel += 1 if increaseIndentRegex.testSync(precedingLine) and not @editor.isBufferRowCommented(precedingRow) return desiredIndentLevel unless decreaseIndentRegex = @decreaseIndentRegexForScopeDescriptor(scopeDescriptor) - desiredIndentLevel -= 1 if decreaseIndentRegex.testSync(currentLine) + desiredIndentLevel -= 1 if decreaseIndentRegex.testSync(tokenizedLine.text) Math.max(desiredIndentLevel, 0) diff --git a/src/selection.coffee b/src/selection.coffee index 6e190d119..7c7fad10d 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -359,11 +359,24 @@ class Selection extends Model @clear() @cursor.needsAutoscroll = @cursor.isLastCursor() + autoIndentFirstLine = false precedingText = @editor.getTextInRange([[oldBufferRange.start.row, 0], oldBufferRange.start]) - startLevel = @editor.indentLevelForLine(precedingText) + remainingLines = text.split('\n') + firstInsertedLine = remainingLines.shift() if options.indentBasis? - text = @adjustIndent(text, startLevel - options.indentBasis) + indentAdjustment = @editor.indentLevelForLine(precedingText) - options.indentBasis + @adjustIndent(remainingLines, indentAdjustment) + + if options.autoIndent and not NonWhitespaceRegExp.test(precedingText) + autoIndentFirstLine = true + firstLine = precedingText + firstInsertedLine + desiredIndentLevel = @editor.languageMode.suggestedIndentForLineAtBufferRow(oldBufferRange.start.row, firstLine) + indentAdjustment = desiredIndentLevel - @editor.indentLevelForLine(firstLine) + @adjustIndent(remainingLines, indentAdjustment) + + text = firstInsertedLine + text += '\n' + remainingLines.join('\n') if remainingLines.length > 0 newBufferRange = @editor.buffer.setTextInRange(oldBufferRange, text, pick(options, 'undo', 'normalizeLineEndings')) @@ -372,20 +385,10 @@ class Selection extends Model else @cursor.setBufferPosition(newBufferRange.end, skipAtomicTokens: true) if wasReversed - if options.autoIndent - precedingText = @editor.getTextInBufferRange([[newBufferRange.start.row, 0], newBufferRange.start]) - unless NonWhitespaceRegExp.test(precedingText) - rowsToIndent = newBufferRange.getRows() - firstRow = rowsToIndent.shift() - rowsToIndent.pop() if text.endsWith("\n") - suggestedIndent = @editor.suggestedIndentForBufferRow(firstRow) - actualIndent = @editor.indentationForBufferRow(firstRow) - @editor.setIndentationForBufferRow(firstRow, suggestedIndent) - indentChange = suggestedIndent - actualIndent - for row in rowsToIndent - newIndent = @editor.indentationForBufferRow(row) + indentChange - @editor.setIndentationForBufferRow(row, newIndent) - else if options.autoIndentNewline and text == '\n' + if autoIndentFirstLine + @editor.setIndentationForBufferRow(oldBufferRange.start.row, desiredIndentLevel) + + if options.autoIndentNewline and text == '\n' currentIndentation = @editor.indentationForBufferRow(newBufferRange.start.row) @editor.autoIndentBufferRow(newBufferRange.end.row, preserveLeadingWhitespace: true, skipBlankLines: false) if @editor.indentationForBufferRow(newBufferRange.end.row) < currentIndentation @@ -605,18 +608,16 @@ class Selection extends Model # Private: Increase the indentation level of the given text by given number # of levels. Leaves the first line unchanged. - adjustIndent: (text, indentIncrease) -> - lines = text.split('\n') - for line, i in lines when i > 0 - if indentIncrease == 0 or line is '' + adjustIndent: (lines, indentAdjustment) -> + for line, i in lines + if indentAdjustment == 0 or line is '' continue - else if indentIncrease > 0 - lines[i] = @editor.buildIndentString(indentIncrease) + line + else if indentAdjustment > 0 + lines[i] = @editor.buildIndentString(indentAdjustment) + line else currentIndentLevel = @editor.indentLevelForLine(lines[i]) - indentLevel = Math.max(0, currentIndentLevel + indentIncrease) + indentLevel = Math.max(0, currentIndentLevel + indentAdjustment) lines[i] = line.replace(/^[\t ]+/, @editor.buildIndentString(indentLevel)) - lines.join('\n') # Indent the current line(s). # diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index eea600b97..67e4deb87 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -302,7 +302,9 @@ class TokenizedBuffer extends Model new TokenizedLine({tokens, tabLength, indentLevel, @invisibles, lineEnding}) buildTokenizedLineForRow: (row, ruleStack) -> - line = @buffer.lineForRow(row) + @buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack) + + buildTokenizedLineForRowWithText: (row, line, ruleStack = @stackForRow(row - 1)) -> lineEnding = @buffer.lineEndingForRow(row) tabLength = @getTabLength() indentLevel = @indentLevelForRow(row)