lineindex.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package buffer
  2. import (
  3. "sort"
  4. "github.com/zyedidia/rope"
  5. )
  6. type LineIndex struct {
  7. starts []int
  8. }
  9. func NewLineIndex() *LineIndex {
  10. return &LineIndex{starts: []int{0}}
  11. }
  12. func NewLineIndexFromRope(r *rope.Node) *LineIndex {
  13. li := NewLineIndex()
  14. li.Rebuild(r)
  15. return li
  16. }
  17. func (li *LineIndex) Rebuild(r *rope.Node) {
  18. starts := []int{0}
  19. if r != nil {
  20. data := r.Value()
  21. for i, b := range data {
  22. if b == '\n' {
  23. starts = append(starts, i+1)
  24. }
  25. }
  26. }
  27. li.starts = starts
  28. }
  29. func (li *LineIndex) Count() int {
  30. return len(li.starts)
  31. }
  32. func (li *LineIndex) LineForOffset(offset int) int {
  33. // first index whose start is > offset; the line we want is one before that.
  34. i := sort.Search(len(li.starts), func(i int) bool {
  35. return li.starts[i] > offset
  36. })
  37. if i == 0 {
  38. return 0
  39. }
  40. return i - 1
  41. }
  42. func (li *LineIndex) OffsetForLine(line int) int {
  43. if line < 0 {
  44. return li.starts[0]
  45. }
  46. if line >= len(li.starts) {
  47. return li.starts[len(li.starts)-1]
  48. }
  49. return li.starts[line]
  50. }
  51. func (li *LineIndex) InsertAt(pos int, data []byte) {
  52. shift := len(data)
  53. if shift == 0 {
  54. return
  55. }
  56. lowIdx := sort.Search(len(li.starts), func(i int) bool {
  57. return li.starts[i] > pos
  58. })
  59. var newStarts []int
  60. for j := range data {
  61. if data[j] == '\n' {
  62. newStarts = append(newStarts, pos+j+1)
  63. }
  64. }
  65. result := make([]int, 0, len(li.starts)+len(newStarts))
  66. result = append(result, li.starts[:lowIdx]...)
  67. result = append(result, newStarts...)
  68. for _, o := range li.starts[lowIdx:] {
  69. result = append(result, o+shift)
  70. }
  71. li.starts = result
  72. }
  73. func (li *LineIndex) RemoveAt(start, end int) {
  74. if end <= start {
  75. return
  76. }
  77. removed := end - start
  78. lowIdx := sort.Search(len(li.starts), func(i int) bool {
  79. return li.starts[i] > start
  80. })
  81. highIdx := sort.Search(len(li.starts), func(i int) bool {
  82. return li.starts[i] > end
  83. })
  84. result := make([]int, 0, lowIdx+(len(li.starts)-highIdx))
  85. result = append(result, li.starts[:lowIdx]...)
  86. for _, o := range li.starts[highIdx:] {
  87. result = append(result, o-removed)
  88. }
  89. li.starts = result
  90. }