From fc3d88aadae4b44232737374d7fe4e4265b9602b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 12 Feb 2015 16:21:45 -0700 Subject: [PATCH] :racehorse: Auto-indent lines prior to inserting in buffer Needs cleanup Signed-off-by: Max Brunsfeld --- src/language-mode.coffee | 21 ++++++++++++++++ src/selection.coffee | 49 +++++++++++++++++++------------------ src/tokenized-buffer.coffee | 8 ++++++ 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/src/language-mode.coffee b/src/language-mode.coffee index 34dad3dc5..f09983f10 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 @@ -249,6 +250,26 @@ class LanguageMode Math.max(desiredIndentLevel, 0) + suggestedIndentForLineAtBufferRow: (bufferRow, line) -> + currentIndentLevel = @editor.indentationForBufferRow(bufferRow) + + scopes = @editor.displayBuffer.tokenizedBuffer.buildTokenizedLineForRowWithText(bufferRow, line).tokens[0].scopes + scopeDescriptor = new ScopeDescriptor({scopes}) + + return currentIndentLevel unless increaseIndentRegex = @increaseIndentRegexForScopeDescriptor(scopeDescriptor) + + precedingRow = @buffer.previousNonBlankRow(bufferRow) + return 0 unless precedingRow? + + precedingLine = @buffer.lineForRow(precedingRow) + desiredIndentLevel = @editor.indentationForBufferRow(precedingRow) + desiredIndentLevel += 1 if increaseIndentRegex.testSync(precedingLine) and not @editor.isBufferRowCommented(precedingRow) + + return desiredIndentLevel unless decreaseIndentRegex = @decreaseIndentRegexForScopeDescriptor(scopeDescriptor) + desiredIndentLevel -= 1 if decreaseIndentRegex.testSync(line) + + Math.max(desiredIndentLevel, 0) + # Calculate a minimum indent level for a range of lines excluding empty lines. # # startRow - The row {Number} to start at 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..0cc3c3981 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -309,6 +309,14 @@ class TokenizedBuffer extends Model {tokens, ruleStack} = @grammar.tokenizeLine(line, ruleStack, row is 0) new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel, @invisibles}) + buildTokenizedLineForRowWithText: (row, line) -> + ruleStack = @stackForRow(row - 1) + lineEnding = @buffer.lineEndingForRow(row) + tabLength = @getTabLength() + indentLevel = @indentLevelForRow(row) + {tokens, ruleStack} = @grammar.tokenizeLine(line, ruleStack, row is 0) + new TokenizedLine({tokens, ruleStack, tabLength, lineEnding, indentLevel, @invisibles}) + tokenizedLineForRow: (bufferRow) -> @tokenizedLines[bufferRow]