1
0

buffer.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. package buffer
  2. import (
  3. "unicode/utf8"
  4. "slices"
  5. "github.com/zyedidia/rope"
  6. )
  7. type Buffer struct {
  8. Rope *rope.Node
  9. CM CursorManager
  10. }
  11. func (buf *Buffer) ensureRope() {
  12. if buf.Rope == nil {
  13. buf.Rope = rope.New([]byte{})
  14. }
  15. }
  16. func (buf *Buffer) Insert(content rune) {
  17. buf.ensureRope()
  18. buf.CM.DeduplicateAndSort()
  19. delta := 0
  20. data := []byte(string(content))
  21. shift := len(data)
  22. for i := range buf.CM.Cursors {
  23. cur := &buf.CM.Cursors[i]
  24. pos := cur.Offset + delta
  25. if pos < 0 {
  26. pos = 0
  27. }
  28. if pos > buf.Rope.Len() {
  29. pos = buf.Rope.Len()
  30. }
  31. buf.Rope.Insert(pos, data)
  32. cur.Offset = pos + shift
  33. delta += shift
  34. }
  35. }
  36. func (buf *Buffer) Delete() {
  37. buf.ensureRope()
  38. buf.CM.DeduplicateAndSort()
  39. delta := 0
  40. for i := range buf.CM.Cursors {
  41. cur := &buf.CM.Cursors[i]
  42. pos := cur.Offset + delta
  43. if pos <= 0 {
  44. cur.Offset = 0
  45. continue
  46. }
  47. if pos > buf.Rope.Len() {
  48. pos = buf.Rope.Len()
  49. }
  50. left := buf.Rope.Slice(0, pos)
  51. _, size := utf8.DecodeLastRune(left)
  52. if size <= 0 {
  53. size = 1
  54. }
  55. start := pos - size
  56. if start < 0 {
  57. start = 0
  58. }
  59. buf.Rope.Remove(start, pos)
  60. deleted := pos - start
  61. delta -= deleted
  62. cur.Offset = start
  63. }
  64. buf.CM.DeduplicateAndSort()
  65. }
  66. func (buf *Buffer) MoveHoriz(dir int) {
  67. buf.ensureRope()
  68. for i := range buf.CM.Cursors {
  69. cur := &buf.CM.Cursors[i]
  70. if cur.Offset + dir < 0 || cur.Offset + dir > buf.Rope.Len() {
  71. continue
  72. }
  73. cur.Offset += dir
  74. _, goal := LineCol(buf.Rope, cur.Offset)
  75. cur.Goal = goal
  76. }
  77. buf.CM.DeduplicateAndSort()
  78. }
  79. func (buf *Buffer) MoveVert(dir int) {
  80. buf.ensureRope()
  81. for i := range buf.CM.Cursors {
  82. cur := &buf.CM.Cursors[i]
  83. line, _ := LineCol(buf.Rope, cur.Offset)
  84. targetLine := line + dir
  85. if targetLine < 0 || targetLine >= LineCount(buf.Rope) {
  86. continue
  87. }
  88. lineStart := OffsetForLine(buf.Rope, targetLine)
  89. lineEnd := OffsetForLine(buf.Rope, targetLine+1)
  90. lineLen := lineEnd - lineStart
  91. if lineLen < 0 {
  92. lineLen = 0
  93. }
  94. goal := cur.Goal
  95. if goal > lineLen {
  96. goal = lineLen
  97. }
  98. cur.Offset = lineStart + goal
  99. }
  100. buf.CM.DeduplicateAndSort()
  101. }
  102. func (buf *Buffer) AddCursorVert(dir int) {
  103. buf.ensureRope()
  104. var newCursors []Cursor
  105. for i := range buf.CM.Cursors {
  106. cur := &buf.CM.Cursors[i]
  107. line, _ := LineCol(buf.Rope, cur.Offset)
  108. targetLine := line + dir
  109. if targetLine < 0 || targetLine >= LineCount(buf.Rope) {
  110. continue
  111. }
  112. lineStart := OffsetForLine(buf.Rope, targetLine)
  113. lineEnd := OffsetForLine(buf.Rope, targetLine+1)
  114. lineLen := lineEnd - lineStart
  115. if lineLen < 0 {
  116. lineLen = 0
  117. }
  118. goal := cur.Goal
  119. if goal > lineLen {
  120. goal = lineLen
  121. }
  122. newCursors = append(newCursors, Cursor{
  123. Offset: lineStart + goal,
  124. Goal: goal,
  125. })
  126. }
  127. buf.CM.Cursors = slices.Concat(buf.CM.Cursors, newCursors)
  128. buf.CM.DeduplicateAndSort()
  129. }
  130. func (buf *Buffer) ClearCursors() {
  131. primaryCursor := &Cursor{
  132. Offset: buf.CM.Cursors[buf.CM.PrimaryIdx].Offset,
  133. Goal: buf.CM.Cursors[buf.CM.PrimaryIdx].Goal,
  134. }
  135. buf.CM.Cursors = buf.CM.Cursors[:0]
  136. buf.CM.Cursors = append(buf.CM.Cursors, *primaryCursor)
  137. buf.CM.PrimaryIdx = 0
  138. }
  139. func LineCount(r *rope.Node) int {
  140. return r.Count(0, r.Len(), []byte{'\n'}) + 1
  141. }
  142. func LineCol(r *rope.Node, offset int) (line, col int) {
  143. if offset < 0 {
  144. offset = 0
  145. }
  146. if offset > r.Len() {
  147. offset = r.Len()
  148. }
  149. line = r.Count(0, offset, []byte{'\n'})
  150. lineStart := 0
  151. for i := offset - 1; i >= 0; i-- {
  152. if r.At(i) == '\n' {
  153. lineStart = i + 1
  154. break
  155. }
  156. }
  157. col = offset - lineStart
  158. return
  159. }
  160. func OffsetForLine(r *rope.Node, targetLine int) int {
  161. if targetLine <= 0 {
  162. return 0
  163. }
  164. line := 0
  165. for i := 0; i < r.Len(); i++ {
  166. if r.At(i) == '\n' {
  167. line++
  168. if line == targetLine {
  169. return i + 1
  170. }
  171. }
  172. }
  173. return r.Len()
  174. }
  175. func (buf Buffer) String() string {
  176. if buf.Rope == nil {
  177. return ""
  178. }
  179. return string(buf.Rope.Value())
  180. }