"bytes"
"os"
"path/filepath"
+ "reflect"
+ "runtime"
"strconv"
"strings"
"time"
return utf8.RuneCountInString(s)
}
-// NumOccurrences counts the number of occurences of a byte in a string
+// NumOccurrences counts the number of occurrences of a byte in a string
func NumOccurrences(s string, c byte) int {
var n int
for i := 0; i < len(s); i++ {
func IsWordChar(str string) bool {
if len(str) > 1 {
// Unicode
- return false
+ return true
}
c := str[0]
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '_')
return string([]rune(str)[:pos]) + value + string([]rune(str)[pos:])
}
+// MakeRelative will attempt to make a relative path between path and base
+func MakeRelative(path, base string) (string, error) {
+ if len(path) > 0 {
+ rel, err := filepath.Rel(base, path)
+ if err != nil {
+ return path, err
+ }
+ return rel, nil
+ }
+ return path, nil
+}
+
// GetLeadingWhitespace returns the leading whitespace of the given string
func GetLeadingWhitespace(str string) string {
ws := ""
// StringWidth returns the width of a string where tabs count as `tabsize` width
func StringWidth(str string, tabsize int) int {
sw := runewidth.StringWidth(str)
- sw += NumOccurrences(str, '\t') * (tabsize - 1)
+ lineIdx := 0
+ for _, ch := range str {
+ switch ch {
+ case '\t':
+ ts := tabsize - (lineIdx % tabsize)
+ sw += ts - 1
+ lineIdx += ts
+ case '\n':
+ lineIdx = 0
+ default:
+ lineIdx++
+ }
+ }
return sw
}
// that have a width larger than 1 (this also counts tabs as `tabsize` width)
func WidthOfLargeRunes(str string, tabsize int) int {
count := 0
+ lineIdx := 0
for _, ch := range str {
var w int
if ch == '\t' {
- w = tabsize
+ w = tabsize - (lineIdx % tabsize)
} else {
w = runewidth.RuneWidth(ch)
}
if w > 1 {
count += (w - 1)
}
+ if ch == '\n' {
+ lineIdx = 0
+ } else {
+ lineIdx += w
+ }
}
return count
}
return n
}
-// SplitCommandArgs seperates multiple command arguments which may be quoted.
+// FuncName returns the name of a given function object
+func FuncName(i interface{}) string {
+ return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
+}
+
+// SplitCommandArgs separates multiple command arguments which may be quoted.
// The returned slice contains at least one string
func SplitCommandArgs(input string) []string {
var result []string
+ var curQuote *bytes.Buffer
- inQuote := false
- escape := false
curArg := new(bytes.Buffer)
+ escape := false
+
+ finishQuote := func() {
+ if curQuote == nil {
+ return
+ }
+ str := curQuote.String()
+ if unquoted, err := strconv.Unquote(str); err == nil {
+ str = unquoted
+ }
+ curArg.WriteString(str)
+ curQuote = nil
+ }
+
+ appendResult := func() {
+ finishQuote()
+ escape = false
+
+ str := curArg.String()
+ result = append(result, str)
+ curArg.Reset()
+ }
+
for _, r := range input {
- if !escape {
- switch {
- case r == '\\' && inQuote:
- escape = true
- continue
- case r == '"' && inQuote:
- inQuote = false
- continue
- case r == '"' && !inQuote && curArg.Len() == 0:
- inQuote = true
- continue
- case r == ' ' && !inQuote:
- result = append(result, curArg.String())
- curArg.Reset()
- continue
+ if r == ' ' && curQuote == nil {
+ appendResult()
+ } else {
+ runeHandled := false
+ appendRuneToBuff := func() {
+ if curQuote != nil {
+ curQuote.WriteRune(r)
+ } else {
+ curArg.WriteRune(r)
+ }
+ runeHandled = true
+ }
+
+ if r == '"' && curQuote == nil {
+ curQuote = new(bytes.Buffer)
+ appendRuneToBuff()
+ } else {
+ if curQuote != nil && !escape {
+ if r == '"' {
+ appendRuneToBuff()
+ finishQuote()
+ } else if r == '\\' {
+ appendRuneToBuff()
+ escape = true
+ continue
+ }
+ }
+ }
+ if !runeHandled {
+ appendRuneToBuff()
}
}
+
escape = false
- curArg.WriteRune(r)
}
- result = append(result, curArg.String())
+ appendResult()
return result
}
} else {
buf.WriteRune(' ')
}
- if !strings.Contains(arg, " ") {
- buf.WriteString(arg)
+ quoted := strconv.Quote(arg)
+ if quoted[1:len(quoted)-1] != arg || strings.ContainsRune(arg, ' ') {
+ buf.WriteString(quoted)
} else {
- buf.WriteRune('"')
- for _, r := range arg {
- if r == '"' || r == '\\' {
- buf.WriteRune('\\')
- }
- buf.WriteRune(r)
- }
- buf.WriteRune('"')
+ buf.WriteString(arg)
}
}