package parsekit import "fmt" // Cursor represents the position of a cursor in various ways. type Cursor struct { Byte int // The cursor offset in bytes, relative to start of file Rune int // The cursor offset in UTF8 runes, relative to start of file Column int // The column at which the cursor is (0-indexed) Line int // The line at which the cursor is (0-indexed) } // String produces a string representation of the cursor position. func (c Cursor) String() string { if c.Line == 0 && c.Column == 0 { return fmt.Sprintf("start of file") } return fmt.Sprintf("line %d, column %d", c.Line+1, c.Column+1) } // Move updates the position of the cursor, based on the provided input string. // The input string represents the runes that has been skipped over. This // method will take newlines into account to keep track of line numbers and // column positions automatically. // // Note: when you are writing a parser using parsekit, it's unlikely // that you will use this method directly. The parsekit package takes care // of calling it at the correct time. func (c *Cursor) Move(input string) *Cursor { c.Byte += len(input) for _, r := range input { c.Rune++ if r == '\n' { c.Column = 0 c.Line++ } else { c.Column++ } } return c }