mirror of
https://github.com/diamondburned/arikawa.git
synced 2025-03-23 10:29:30 +00:00
Shellwords: Simpler error and implementation
This commit is contained in:
parent
3e2814748f
commit
e0f051b4c6
|
@ -1,48 +1,35 @@
|
||||||
package shellwords
|
package shellwords
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WordOffset is the offset from the position cursor to print on the error.
|
|
||||||
const WordOffset = 7
|
|
||||||
|
|
||||||
var escaper = strings.NewReplacer(
|
var escaper = strings.NewReplacer(
|
||||||
"`", "\\`",
|
"__", "\\_\\_",
|
||||||
"@", "\\@",
|
|
||||||
"\\", "\\\\",
|
"\\", "\\\\",
|
||||||
)
|
)
|
||||||
|
|
||||||
type ErrParse struct {
|
// ErrMissingClose is returned when the parsed line is missing a closing quote.
|
||||||
|
type ErrMissingClose struct {
|
||||||
Position int
|
Position int
|
||||||
Words string // joined
|
Words string // joined
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e ErrParse) Error() string {
|
func (e ErrMissingClose) Error() string {
|
||||||
// Magic number 5.
|
// Underline 7 characters around.
|
||||||
var a = max(0, e.Position-WordOffset)
|
var start = e.Position
|
||||||
var b = min(len(e.Words), e.Position+WordOffset)
|
|
||||||
var word = e.Words[a:b]
|
|
||||||
var uidx = e.Position - a
|
|
||||||
|
|
||||||
errstr := strings.Builder{}
|
errstr := strings.Builder{}
|
||||||
errstr.WriteString("Unexpected quote or escape")
|
errstr.WriteString("missing quote close")
|
||||||
|
|
||||||
// Do a bound check.
|
if e.Words[start:] != "" {
|
||||||
if uidx+1 > len(word) {
|
errstr.WriteString(": ")
|
||||||
// Invalid.
|
errstr.WriteString(escaper.Replace(e.Words[:start]))
|
||||||
errstr.WriteString(".")
|
errstr.WriteString("__")
|
||||||
return errstr.String()
|
errstr.WriteString(escaper.Replace(e.Words[start:]))
|
||||||
|
errstr.WriteString("__")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the pre-underline part.
|
|
||||||
fmt.Fprintf(
|
|
||||||
&errstr, ": %s__%s__",
|
|
||||||
escaper.Replace(word[:uidx]),
|
|
||||||
escaper.Replace(string(word[uidx:])),
|
|
||||||
)
|
|
||||||
|
|
||||||
return errstr.String()
|
return errstr.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +104,7 @@ func Parse(line string) ([]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if escaped || singleQuoted || doubleQuoted {
|
if escaped || singleQuoted || doubleQuoted {
|
||||||
return args, &ErrParse{
|
return args, ErrMissingClose{
|
||||||
Position: cursor + buf.Len(),
|
Position: cursor + buf.Len(),
|
||||||
Words: strings.Join(args, " "),
|
Words: strings.Join(args, " "),
|
||||||
}
|
}
|
||||||
|
@ -133,17 +120,3 @@ func isSpace(r rune) bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func min(i, j int) int {
|
|
||||||
if i < j {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func max(i, j int) int {
|
|
||||||
if i < j {
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,7 +14,17 @@ type wordsTest struct {
|
||||||
func TestParse(t *testing.T) {
|
func TestParse(t *testing.T) {
|
||||||
var tests = []wordsTest{
|
var tests = []wordsTest{
|
||||||
{
|
{
|
||||||
`this is a "test"`,
|
"",
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"'",
|
||||||
|
nil,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`this is a "te""st"`,
|
||||||
[]string{"this", "is", "a", "test"},
|
[]string{"this", "is", "a", "test"},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue