From fc3d88aadae4b44232737374d7fe4e4265b9602b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 12 Feb 2015 16:21:45 -0700 Subject: [PATCH 1/3] :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] From 18826f414ca1c83c4e9bc6960b77c806f4c5e36e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 12 Feb 2015 16:33:42 -0700 Subject: [PATCH 2/3] :art: Dry up suggested indent methods in LanguageMode Signed-off-by: Max Brunsfeld --- src/language-mode.coffee | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/src/language-mode.coffee b/src/language-mode.coffee index f09983f10..b7a52280b 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -229,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? @@ -246,27 +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) - - 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) + desiredIndentLevel -= 1 if decreaseIndentRegex.testSync(tokenizedLine.text) Math.max(desiredIndentLevel, 0) From b2d322f5314beaeac881b329c08f297dbfc6d50b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 12 Feb 2015 16:40:18 -0700 Subject: [PATCH 3/3] :art: Dry up buildTokenizedLineForRow methods on TokenizedBuffer Signed-off-by: Max Brunsfeld --- src/tokenized-buffer.coffee | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 0cc3c3981..67e4deb87 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -302,15 +302,9 @@ class TokenizedBuffer extends Model new TokenizedLine({tokens, tabLength, indentLevel, @invisibles, lineEnding}) buildTokenizedLineForRow: (row, ruleStack) -> - line = @buffer.lineForRow(row) - 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}) + @buildTokenizedLineForRowWithText(row, @buffer.lineForRow(row), ruleStack) - buildTokenizedLineForRowWithText: (row, line) -> - ruleStack = @stackForRow(row - 1) + buildTokenizedLineForRowWithText: (row, line, ruleStack = @stackForRow(row - 1)) -> lineEnding = @buffer.lineEndingForRow(row) tabLength = @getTabLength() indentLevel = @indentLevelForRow(row)