From 9534d31a01cc1696300cc637774d9e9449507c74 Mon Sep 17 00:00:00 2001 From: Eelco Lempsink Date: Sat, 3 Sep 2016 00:08:03 +0200 Subject: [PATCH 1/2] Add failing test for mixing tabs / spaces --- test/formatting.coffee | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/formatting.coffee b/test/formatting.coffee index 31cc282840..b1dd522632 100644 --- a/test/formatting.coffee +++ b/test/formatting.coffee @@ -254,3 +254,11 @@ test "#1275: allow indentation before closing brackets", -> a = 1 ) eq 1, a + +test "allow mixing of spaces and tabs for indentation by passing a width for tabs to the lexer", -> + doesNotThrow -> CoffeeScript.compile ''' + new Layer + x: 0 + y: 1 + z: 2 + ''', tabSize: 2 From 164f61926b9b04f4ace3f400080ccb0ba4e7aa6a Mon Sep 17 00:00:00 2001 From: Eelco Lempsink Date: Sat, 3 Sep 2016 01:27:48 +0200 Subject: [PATCH 2/2] Add 'tabSize' option to pass the tab stop width and allow mixing of tabs and spaces for indentation. --- src/lexer.coffee | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/lexer.coffee b/src/lexer.coffee index 2e6090df61..dfb43b3adf 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -44,6 +44,8 @@ exports.Lexer = class Lexer @tokens = [] # Stream of parsed tokens in the form `['TYPE', value, location data]`. @seenFor = no # Used to recognize FORIN and FOROF tokens. + @tabSize = opts.tabSize or 1 # Width of tab stop + @chunkLine = opts.line or 0 # The start line for the current @chunk. @chunkColumn = @@ -318,31 +320,43 @@ exports.Lexer = class Lexer return 0 unless match = MULTI_DENT.exec @chunk indent = match[0] @seenFor = no - size = indent.length - 1 - indent.lastIndexOf '\n' + width = size = indent.length - 1 - indent.lastIndexOf '\n' + + if @tabSize > 1 + width = 0 + beforeStop = 0 + for i in [1..size] + if indent[i] isnt '\t' + beforeStop++ + if indent[i] is '\t' or beforeStop is @tabSize + width += @tabSize + beforeStop = 0 + width += beforeStop + noNewlines = @unfinished() - if size - @indebt is @indent + if width - @indebt is @indent if noNewlines then @suppressNewlines() else @newlineToken 0 return indent.length - if size > @indent + if width > @indent if noNewlines - @indebt = size - @indent + @indebt = width - @indent @suppressNewlines() return indent.length unless @tokens.length - @baseIndent = @indent = size + @baseIndent = @indent = width return indent.length - diff = size - @indent + @outdebt + diff = width - @indent + @outdebt @token 'INDENT', diff, indent.length - size, size @indents.push diff @ends.push {tag: 'OUTDENT'} @outdebt = @indebt = 0 - @indent = size - else if size < @baseIndent + @indent = width + else if width < @baseIndent @error 'missing indentation', offset: indent.length else @indebt = 0 - @outdentToken @indent - size, noNewlines, indent.length + @outdentToken @indent - width, noNewlines, indent.length indent.length # Record an outdent token or multiple tokens, if we happen to be moving back