Quote none of the line in the unclosed-quote refusal: a refusal is kept on the bus as the call's answer (hq issue 294)
This commit is contained in:
@@ -1405,7 +1405,7 @@ func splitCommandLine(line string) ([]string, error) {
|
||||
}
|
||||
}
|
||||
if quote != 0 {
|
||||
return nil, unclosedQuote(runes, quote, opened)
|
||||
return nil, unclosedQuote(quote, opened)
|
||||
}
|
||||
if inWord {
|
||||
words = append(words, cur.String())
|
||||
@@ -1415,18 +1415,13 @@ func splitCommandLine(line string) ([]string, error) {
|
||||
|
||||
// unclosedQuote is the refusal of a line whose quote is never closed. Most often an apostrophe inside
|
||||
// a single-quoted value ended that quote early and a later quote was left open, so the refusal says
|
||||
// where the open quote is, shows the line from there, and says how a quote is written inside a quoted
|
||||
// value — the shell's own two ways, which this splitter already reads (novox/hq issue 294).
|
||||
func unclosedQuote(runes []rune, quote rune, opened int) error {
|
||||
const shown = 40
|
||||
from := runes[opened:]
|
||||
excerpt := string(from)
|
||||
if len(from) > shown {
|
||||
excerpt = string(from[:shown]) + "…"
|
||||
}
|
||||
return fmt.Errorf("command has an unclosed %c quote, opened at character %d: %s — an apostrophe "+
|
||||
// where the open quote is and how a quote is written inside a quoted value — the shell's own two
|
||||
// ways, which this splitter already reads (novox/hq issue 294). It quotes none of the line: a refusal
|
||||
// is kept on the bus as the call's answer, and the line may carry a setting's value.
|
||||
func unclosedQuote(quote rune, opened int) error {
|
||||
return fmt.Errorf("command has an unclosed %c quote, opened at character %d — an apostrophe "+
|
||||
"inside a single-quoted value ends it; write a ' inside single quotes as '\\'' (it'\\''s), or use "+
|
||||
"double quotes and write \\\" for a \" and \\\\ for a \\ inside them", quote, opened+1, excerpt)
|
||||
"double quotes and write \\\" for a \" and \\\\ for a \\ inside them", quote, opened+1)
|
||||
}
|
||||
|
||||
// seatAnnouncement is what the controller says it serves on the bus (novox/hq ADR 0197): the
|
||||
|
||||
@@ -417,7 +417,7 @@ func TestNoVerbSetsTheOperatorsKeyOrRevealsASecret(t *testing.T) {
|
||||
}
|
||||
|
||||
// A value with a quote in it can be said on a `command` line, as in a shell, and a line whose quote
|
||||
// is left open is refused naming where it opened and how a quote is written (novox/hq issue 294: an
|
||||
// is left open is refused naming where it opened and how a quote is written, quoting none of it (novox/hq issue 294: an
|
||||
// apostrophe inside a single-quoted JSON value cut the line, and the refusal named no cause).
|
||||
func TestAQuotedValueCanHoldAQuote(t *testing.T) {
|
||||
for _, c := range []struct{ line, want string }{
|
||||
@@ -436,11 +436,14 @@ func TestAQuotedValueCanHoldAQuote(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Fatal("an apostrophe that leaves a quote open was accepted")
|
||||
}
|
||||
for _, want := range []string{"character 57", `"}' --node g14`, `'\''`, `\"`} {
|
||||
for _, want := range []string{"character 57", `'\''`, `\"`} {
|
||||
if !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("the refusal does not say %q: %v", want, err)
|
||||
}
|
||||
}
|
||||
if strings.Contains(err.Error(), "laptop") || strings.Contains(err.Error(), "g14") {
|
||||
t.Errorf("the refusal quotes the line, which may carry a setting's value: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Every value reads back as it was when written the way the refusal says: single-quoted with '\”
|
||||
|
||||
Reference in New Issue
Block a user