package shell import ( "io" "log" "regexp" "strings" ) func NewWord(wordS string) *Word { word := new(Word) for _, c := range wordS { word.AddToken(Char(c)) } return word } type Word struct { chars []Char consecutiveBackslashes int } func (w *Word) Tokens() []Token { return []Token{} } func (w *Word) AddToken(token Token) { if char, ok := token.(Char); ok { if rune(char) == '\\' { w.consecutiveBackslashes += 1 } else if w.consecutiveBackslashes%2 == 1 { if len(w.chars) > 0 { w.chars = w.chars[:len(w.chars)-1] } else { log.Println( "Parse error: funky shit is happening, a word with 0" + " chars was expected to contain a backslash", ) } w.consecutiveBackslashes = 0 } w.chars = append(w.chars, char) } } func (w *Word) Expand(_ State, _ io.Reader, _ io.Writer) ([]string, uint8) { var str string for _, char := range w.chars { str += string(char) } return []string{str}, 0 } func (w *Word) String() string { str, _ := w.Expand(nil, nil, nil) return strings.Join(str, "") } type WordParameters struct{} func (p *WordParameters) MakeToken() Token { return new(Word) } var wordRegexp = regexp.MustCompile("[0-9a-zA-Z_.~/:\\\\=-]") func (p *WordParameters) Supports(charsBefore []rune, r rune) bool { return wordRegexp.MatchString(string(r)) } func (p *WordParameters) ShouldLeave(charsBefore []rune, r rune) bool { if !p.Supports(charsBefore, r) { return countBackslashSuffixes(charsBefore)%2 == 0 } return false } func (p *WordParameters) Leave(i *CharIterator) error { return i.Previous() } func (p *WordParameters) SubParsers() []Parser { return []Parser{ &BaseParser{ parameters: &CharParserParameters{}, }, } } type Char rune func (c Char) Tokens() []Token { return nil } func (c Char) AddToken(_ Token) {} func (c Char) String() string { return string(c) } type CharParserParameters struct { currentRune rune } func (p *CharParserParameters) MakeToken() Token { return Char(p.currentRune) } func (p *CharParserParameters) Supports(charsBefore []rune, r rune) bool { p.currentRune = r return true } func (p *CharParserParameters) ShouldLeave(charsBefore []rune, r rune) bool { return true } func (p *CharParserParameters) SubParsers() []Parser { return nil }