From dbcdf83ed8aca3f0b84d67b944fff2f3a8bc7769 Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Wed, 8 Jun 2016 12:17:38 +0200 Subject: [PATCH] console: ignore round and curly brackets in strings when determining indentation level --- console/console.go | 47 +++++++++++++++++++++++++++++++++++++++-- console/console_test.go | 46 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/console/console.go b/console/console.go index baa9cf545..9cff8c876 100644 --- a/console/console.go +++ b/console/console.go @@ -330,11 +330,11 @@ func (c *Console) Interactive() { // Append the line to the input and check for multi-line interpretation input += line + "\n" - indents = strings.Count(input, "{") + strings.Count(input, "(") - strings.Count(input, "}") - strings.Count(input, ")") + indents = countIndents(input) if indents <= 0 { prompt = c.prompt } else { - prompt = strings.Repeat("..", indents*2) + " " + prompt = strings.Repeat(".", indents*3) + " " } // If all the needed lines are present, save the command and run if indents <= 0 { @@ -353,6 +353,49 @@ func (c *Console) Interactive() { } } +// countIndents returns the number of identations for the given input. +// In case of invalid input such as var a = } the result can be negative. +func countIndents(input string) int { + var ( + indents = 0 + inString = false + strOpenChar = ' ' // keep track of the string open char to allow var str = "I'm ...."; + charEscaped = false // keep track if the previous char was the '\' char, allow var str = "abc\"def"; + ) + + for _, c := range input { + switch c { + case '\\': + // indicate next char as escaped when in string and previous char isn't escaping this backslash + if !charEscaped && inString { + charEscaped = true + } + case '\'', '"': + if inString && !charEscaped && strOpenChar == c { // end string + inString = false + } else if !inString && !charEscaped { // begin string + inString = true + strOpenChar = c + } + charEscaped = false + case '{', '(': + if !inString { // ignore brackets when in string, allow var str = "a{"; without indenting + indents++ + } + charEscaped = false + case '}', ')': + if !inString { + indents-- + } + charEscaped = false + default: + charEscaped = false + } + } + + return indents +} + // Execute runs the JavaScript file specified as the argument. func (c *Console) Execute(path string) error { return c.jsre.Exec(path) diff --git a/console/console_test.go b/console/console_test.go index 911087824..7738d0c44 100644 --- a/console/console_test.go +++ b/console/console_test.go @@ -294,3 +294,49 @@ func TestPrettyError(t *testing.T) { t.Fatalf("pretty error mismatch: have %s, want %s", output, want) } } + +// Tests that tests if the number of indents for JS input is calculated correct. +func TestIndenting(t *testing.T) { + testCases := []struct { + input string + expectedIndentCount int + }{ + {`var a = 1;`, 0}, + {`"some string"`, 0}, + {`"some string with (parentesis`, 0}, + {`"some string with newline + ("`, 0}, + {`function v(a,b) {}`, 0}, + {`function f(a,b) { var str = "asd("; };`, 0}, + {`function f(a) {`, 1}, + {`function f(a, function(b) {`, 2}, + {`function f(a, function(b) { + var str = "a)}"; + });`, 0}, + {`function f(a,b) { + var str = "a{b(" + a, ", " + b; + }`, 0}, + {`var str = "\"{"`, 0}, + {`var str = "'("`, 0}, + {`var str = "\\{"`, 0}, + {`var str = "\\\\{"`, 0}, + {`var str = 'a"{`, 0}, + {`var obj = {`, 1}, + {`var obj = { {a:1`, 2}, + {`var obj = { {a:1}`, 1}, + {`var obj = { {a:1}, b:2}`, 0}, + {`var obj = {}`, 0}, + {`var obj = { + a: 1, b: 2 + }`, 0}, + {`var test = }`, -1}, + {`var str = "a\""; var obj = {`, 1}, + } + + for i, tt := range testCases { + counted := countIndents(tt.input) + if counted != tt.expectedIndentCount { + t.Errorf("test %d: invalid indenting: have %d, want %d", i, counted, tt.expectedIndentCount) + } + } +}