| 59 | } |
| 60 | |
| 61 | func (sc *RangeScanner) Scan() bool { |
| 62 | if sc.pos.Byte >= len(sc.b) || sc.err != nil { |
| 63 | // All done |
| 64 | return false |
| 65 | } |
| 66 | |
| 67 | // Since we're operating on an in-memory buffer, we always pass the whole |
| 68 | // remainder of the buffer to our SplitFunc and set isEOF to let it know |
| 69 | // that it has the whole thing. |
| 70 | advance, token, err := sc.cb(sc.b[sc.pos.Byte:], true) |
| 71 | |
| 72 | // Since we are setting isEOF to true this should never happen, but |
| 73 | // if it does we will just abort and assume the SplitFunc is misbehaving. |
| 74 | if advance == 0 && token == nil && err == nil { |
| 75 | return false |
| 76 | } |
| 77 | |
| 78 | if err != nil { |
| 79 | sc.err = err |
| 80 | sc.cur = Range{ |
| 81 | Filename: sc.filename, |
| 82 | Start: sc.pos, |
| 83 | End: sc.pos, |
| 84 | } |
| 85 | sc.tok = nil |
| 86 | return false |
| 87 | } |
| 88 | |
| 89 | sc.tok = token |
| 90 | start := sc.pos |
| 91 | end := sc.pos |
| 92 | new := sc.pos |
| 93 | |
| 94 | // adv is similar to token but it also includes any subsequent characters |
| 95 | // we're being asked to skip over by the SplitFunc. |
| 96 | // adv is a slice covering any additional bytes we are skipping over, based |
| 97 | // on what the SplitFunc told us to do with advance. |
| 98 | adv := sc.b[sc.pos.Byte : sc.pos.Byte+advance] |
| 99 | |
| 100 | // We now need to scan over our token to count the grapheme clusters |
| 101 | // so we can correctly advance Column, and count the newlines so we |
| 102 | // can correctly advance Line. |
| 103 | advR := bytes.NewReader(adv) |
| 104 | gsc := bufio.NewScanner(advR) |
| 105 | advanced := 0 |
| 106 | gsc.Split(textseg.ScanGraphemeClusters) |
| 107 | for gsc.Scan() { |
| 108 | gr := gsc.Bytes() |
| 109 | new.Byte += len(gr) |
| 110 | new.Column++ |
| 111 | |
| 112 | // We rely here on the fact that \r\n is considered a grapheme cluster |
| 113 | // and so we don't need to worry about miscounting additional lines |
| 114 | // on files with Windows-style line endings. |
| 115 | if len(gr) != 0 && (gr[0] == '\r' || gr[0] == '\n') { |
| 116 | new.Column = 1 |
| 117 | new.Line++ |
| 118 | } |