From b6d099ac7823f4d52500d521eb948b999a2b4925 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 29 Jun 2015 17:05:28 -0500 Subject: [PATCH] Consider tabs or spaces mutually exclusively as indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, we allowed a mix of tabs and spaces to be counted toward the indentation of a line. This caused problems when auto-indenting lines in a hard-tabbed file that contained “alignment spaces”, such as occurs in aligned comment blocks. For this case, it makes more sense to assume that the line is indented via tabs only, and consider the subsequent alignment space as part of the line’s content. Since it’s hard to imagine actual source code in which a mixed treatment of tabs and spaces is desirable, I’m going with this over any more complex approach. --- spec/text-editor-spec.coffee | 25 ++++++++++++++++++++----- src/selection.coffee | 2 +- src/tokenized-buffer.coffee | 9 ++++----- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 128fa5235..f20184e01 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -2943,6 +2943,20 @@ describe "TextEditor", -> expect(editor.lineTextForBufferRow(7)).toBe " c(x);" expect(editor.lineTextForBufferRow(8)).toBe " current = items.shift();" + it "auto-indents lines with a mix of hard tabs and spaces without removing spaces", -> + editor.setSoftTabs(false) + expect(editor.indentationForBufferRow(5)).toBe(3) + + atom.clipboard.write("/**\n\t * testing\n\t * indent\n\t **/\n", indentBasis: 1) + editor.setCursorBufferPosition([5, 0]) + editor.pasteText() + + # Do not lose the alignment spaces + expect(editor.lineTextForBufferRow(5)).toBe("\t\t\t/**") + expect(editor.lineTextForBufferRow(6)).toBe("\t\t\t * testing") + expect(editor.lineTextForBufferRow(7)).toBe("\t\t\t * indent") + expect(editor.lineTextForBufferRow(8)).toBe("\t\t\t **/") + describe "when pasting a single line of text", -> it "does not auto-indent the text", -> atom.clipboard.write("a(x);", indentBasis: 0) @@ -3692,11 +3706,12 @@ describe "TextEditor", -> it "returns the indent level when the line has only leading tabs", -> expect(editor.indentLevelForLine("\t\thello")).toBe(2) - it "returns the indent level when the line has mixed leading whitespace and tabs", -> - expect(editor.indentLevelForLine("\t hello")).toBe(2) - expect(editor.indentLevelForLine(" \thello")).toBe(2) - expect(editor.indentLevelForLine(" \t hello")).toBe(2.5) - expect(editor.indentLevelForLine(" \t \thello")).toBe(3.5) + it "returns the indent level based on the character starting the line when the leading whitespace contains both spaces and tabs", -> + expect(editor.indentLevelForLine("\t hello")).toBe(1) + expect(editor.indentLevelForLine(" \thello")).toBe(1) + expect(editor.indentLevelForLine(" \t hello")).toBe(1) + expect(editor.indentLevelForLine(" \t \thello")).toBe(2) + expect(editor.indentLevelForLine(" \t \thello")).toBe(2.5) describe "when the buffer is reloaded", -> it "preserves the current cursor position", -> diff --git a/src/selection.coffee b/src/selection.coffee index 6a4d4726f..3f7878195 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -622,7 +622,7 @@ class Selection extends Model else currentIndentLevel = @editor.indentLevelForLine(lines[i]) indentLevel = Math.max(0, currentIndentLevel + indentAdjustment) - lines[i] = line.replace(/^[\t ]+/, @editor.buildIndentString(indentLevel)) + lines[i] = line.replace(/^(\t+| +)/, @editor.buildIndentString(indentLevel)) return # Indent the current line(s). diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 7fb21937d..c764c1a1f 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -411,11 +411,10 @@ class TokenizedBuffer extends Model @indentLevelForLine(line) indentLevelForLine: (line) -> - if match = line.match(/^[\t ]+/) - leadingWhitespace = match[0] - tabCount = leadingWhitespace.match(/\t/g)?.length ? 0 - spaceCount = leadingWhitespace.match(/[ ]/g)?.length ? 0 - tabCount + (spaceCount / @getTabLength()) + if match = line.match(/^\t+/) + match[0].length + else if match = line.match(/^ +/) + match[0].length / @getTabLength() else 0