Consider tabs or spaces mutually exclusively as indentation

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.
This commit is contained in:
Nathan Sobo 2015-06-29 17:05:28 -05:00
parent 375cf27574
commit b6d099ac78
3 changed files with 25 additions and 11 deletions

View File

@ -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", ->

View File

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

View File

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