Merge pull request #5534 from atom/ns-mb-optimize-auto-indent-on-paste

Optimize auto-indent on paste
This commit is contained in:
Nathan Sobo
2015-02-12 17:06:23 -07:00
3 changed files with 41 additions and 28 deletions

View File

@@ -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)

View File

@@ -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).
#

View File

@@ -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)