package textobject import ( "git.gophernest.net/azpect/TextEditor/internal/action" "git.gophernest.net/azpect/TextEditor/internal/core" ) // Word implements text object for words (iw/aw) type Word struct{} func (to Word) GetRange(m action.Model, cursor core.Position, modifier string) (core.Position, core.Position, core.MotionType) { buf := m.ActiveBuffer() line := buf.Line(cursor.Line) // Find word boundaries start := findWordStart(line, cursor.Col) end := findWordEnd(line, cursor.Col, modifier == "a") // Word object's don't span lines start.Line = cursor.Line end.Line = cursor.Line return start, end, core.CharwiseInclusive } // Word implements text object for WORDs (iW/aW) type WORD struct{} func (to WORD) GetRange(m action.Model, cursor core.Position, modifier string) (core.Position, core.Position, core.MotionType) { buf := m.ActiveBuffer() line := buf.Line(cursor.Line) // Find word boundaries start := findWORDStart(line, cursor.Col) end := findWORDEnd(line, cursor.Col, modifier == "a") // Word object's don't span lines start.Line = cursor.Line end.Line = cursor.Line return start, end, core.CharwiseInclusive } // isWordChar: Returns true if the character is a word character (alphanumeric // or underscore). COPIED FROM internal/motion/word.go func isWordChar(c byte) bool { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' } func findWordStart(line string, col int) core.Position { if col >= len(line) || col < 0 { return core.Position{Line: 0, Col: 0} } curChar := line[col] // Don't start on whitespace (shouldn't happen for text objects) if curChar == ' ' || curChar == '\t' { return core.Position{Line: 0, Col: col} } // Determine if we're on word char or punctuation onWordChar := isWordChar(curChar) // Move backwards while in the same character class i := col for i > 0 { prevChar := line[i-1] // Stop at whitespace if prevChar == ' ' || prevChar == '\t' { break } // Stop if character class changes if isWordChar(prevChar) != onWordChar { break } i-- } return core.Position{Line: 0, Col: i} } func findWordEnd(line string, col int, includeWhitespace bool) core.Position { if col >= len(line) || col < 0 { return core.Position{Line: 0, Col: 0} } curChar := line[col] // Don't start on whitespace if curChar == ' ' || curChar == '\t' { return core.Position{Line: 0, Col: col} } // Determine if we're on word char or punctuation onWordChar := isWordChar(curChar) // Move forward while in the same character class i := col for i < len(line) { c := line[i] // Stop at whitespace if c == ' ' || c == '\t' { break } // Stop if character class changes if isWordChar(c) != onWordChar { break } i++ } // i is now one past the end, so back up i-- // If including whitespace, skip trailing spaces/tabs if includeWhitespace { i++ // Move forward to whitespace for i < len(line) && (line[i] == ' ' || line[i] == '\t') { i++ } i-- // Back to last whitespace } return core.Position{Line: 0, Col: i} } func findWORDStart(line string, col int) core.Position { if col >= len(line) || col < 0 { return core.Position{Line: 0, Col: 0} } curChar := line[col] // Don't start on whitespace (shouldn't happen for text objects) if curChar == ' ' || curChar == '\t' { return core.Position{Line: 0, Col: col} } // For WORD, all non-whitespace is one class // Just move backwards until we hit whitespace or start of line i := col for i > 0 { prevChar := line[i-1] // Stop at whitespace if prevChar == ' ' || prevChar == '\t' { break } i-- } return core.Position{Line: 0, Col: i} } func findWORDEnd(line string, col int, includeWhitespace bool) core.Position { if col >= len(line) || col < 0 { return core.Position{Line: 0, Col: 0} } curChar := line[col] // Don't start on whitespace if curChar == ' ' || curChar == '\t' { return core.Position{Line: 0, Col: col} } // For WORD, all non-whitespace is one class // Move forward until we hit whitespace or end of line i := col for i < len(line) { c := line[i] // Stop at whitespace if c == ' ' || c == '\t' { break } i++ } // i is now one past the end, so back up i-- // If including whitespace, skip trailing spaces/tabs if includeWhitespace { i++ // Move forward to whitespace for i < len(line) && (line[i] == ' ' || line[i] == '\t') { i++ } i-- // Back to last whitespace } return core.Position{Line: 0, Col: i} }