// Move cursor forward to beginning of the previous word. // Skips the rest of the current word, if any, unless is located at its // first character. Returns true if the move was successful, false if EOF reached. func (c *Cursor) PrevWord() bool { isNotSpace := func(r rune) bool { return !unicode.IsSpace(r) } for { // Skip space until we find a word character. // Re-try if we reached beginning-of-line. if !c.PrevRuneFunc(isNotSpace) { return false } if !c.BOL() { break } } r, _ := c.RuneBefore() if isNotSpace(r) { // Lowercase word motion differentiates words consisting of // (A-Z0-9_) and any other non-whitespace character. Skip until // we find either the other word type or whitespace. if utils.IsWord(r) { c.PrevRuneFunc(func(r rune) bool { return !utils.IsWord(r) || unicode.IsSpace(r) }) } else { c.PrevRuneFunc(func(r rune) bool { return utils.IsWord(r) || unicode.IsSpace(r) }) } } return !c.BOL() }
func (c *Cursor) WordUnderCursor() []byte { end, beg := *c, *c var ( r rune rlen int ) r, _ = beg.RuneUnder() if unicode.IsSpace(r) { return nil } if !beg.BOL() { r, rlen = beg.RuneBefore() if r == utf8.RuneError { return nil } // move the `beg` cursor back to the start of the word for utils.IsWord(r) && !beg.BOL() { beg.Boffset -= rlen r, rlen = beg.RuneBefore() } } // set the end cursor to the same position as the start cursor end.Boffset = beg.Boffset // check if the word is just a single character r, rlen = end.RuneAfter() if !utils.IsWord(r) { return c.Line.Data[end.Boffset : end.Boffset+1] } // move to the the rune after the end of the word for utils.IsWord(r) && !end.EOL() { end.Boffset += rlen r, rlen = end.RuneAfter() } end.NextRune(false) if beg.Boffset == end.Boffset { return nil } return c.Line.Data[beg.Boffset:end.Boffset] }
// Move cursor forward to beginning of next word. // Skips the rest of the current word, if any. Returns true if // the move was successful, false if EOF reached. func (c *Cursor) NextWord() bool { isNotSpace := func(r rune) bool { return !unicode.IsSpace(r) } r, _ := c.RuneUnder() if isNotSpace(r) { // Lowercase word motion differentiates words consisting of // (A-Z0-9_) and any other non-whitespace character. Skip until // we find either the other word type or whitespace. if utils.IsWord(r) { c.NextRuneFunc(func(r rune) bool { return !utils.IsWord(r) || unicode.IsSpace(r) }) } else { c.NextRuneFunc(func(r rune) bool { return utils.IsWord(r) || unicode.IsSpace(r) }) } } // Skip remaining whitespace until next word of any type. return c.NextRuneFunc(isNotSpace) }
// EndWord moves cursor to the end of current word or seeks to the // beginning of next word, if character under cursor is a whitespace. func (c *Cursor) EndWord() bool { if !c.NextRune(true) { return false } // Skip spaces until beginning of next word r, _ := c.RuneUnder() if c.EOL() || unicode.IsSpace(r) { c.NextWord() } // Skip to after the word. r, _ = c.RuneUnder() var f func(r rune) bool if utils.IsWord(r) { f = func(r rune) bool { return !utils.IsWord(r) || unicode.IsSpace(r) } } else { f = func(r rune) bool { return utils.IsWord(r) || unicode.IsSpace(r) } } // This can go back to end of buffer but can be ignored, // since we're going to backtrack one character. c.NextRuneFunc(f) c.PrevRune(true) // Keep going back until BOF if we end up at EOL. This // can happen on empty lines. for c.EOL() && !(c.BOL() && c.FirstLine()) { c.PrevRune(true) } return true }
func (c *Cursor) WordUnderCursor() []byte { end, beg := *c, *c r, rlen := beg.RuneBefore() if r == utf8.RuneError { return nil } for utils.IsWord(r) && !beg.BOL() { beg.Boffset -= rlen r, rlen = beg.RuneBefore() } if beg.Boffset == end.Boffset { return nil } return c.Line.Data[beg.Boffset:end.Boffset] }