buffer.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. package buffer
  2. import (
  3. "slices"
  4. "unicode/utf8"
  5. "github.com/zyedidia/rope"
  6. )
  7. type BufferManager struct {
  8. Buffers []Buffer
  9. CurrentIdx int
  10. PaletteBuffer Buffer
  11. }
  12. func (bm *BufferManager) Current() *Buffer {
  13. return &bm.Buffers[bm.CurrentIdx]
  14. }
  15. type Buffer struct {
  16. Rope *rope.Node
  17. LI *LineIndex
  18. CM CursorManager
  19. Path string
  20. TopLine int
  21. }
  22. func NewBuffer() Buffer {
  23. return Buffer{
  24. Rope: rope.New([]byte{}),
  25. LI: NewLineIndex(),
  26. CM: CursorManager{
  27. Cursors: []Cursor{{Offset: 0, Goal: 0}},
  28. PrimaryIdx: 0,
  29. },
  30. }
  31. }
  32. func (buf *Buffer) ensureRope() {
  33. if buf.Rope == nil {
  34. buf.Rope = rope.New([]byte{})
  35. }
  36. if buf.LI == nil {
  37. buf.LI = NewLineIndexFromRope(buf.Rope)
  38. }
  39. }
  40. func (buf *Buffer) Insert(content rune) {
  41. buf.ensureRope()
  42. buf.CM.DeduplicateAndSort()
  43. delta := 0
  44. data := []byte(string(content))
  45. shift := len(data)
  46. for i := range buf.CM.Cursors {
  47. cur := &buf.CM.Cursors[i]
  48. pos := cur.Offset + delta
  49. if pos < 0 {
  50. pos = 0
  51. }
  52. if pos > buf.Rope.Len() {
  53. pos = buf.Rope.Len()
  54. }
  55. buf.Rope.Insert(pos, data)
  56. buf.LI.InsertAt(pos, data)
  57. cur.Offset = pos + shift
  58. _, goal := LineCol(buf, cur.Offset)
  59. cur.Goal = goal
  60. delta += shift
  61. }
  62. }
  63. func (buf *Buffer) Paste(content string) {
  64. for _, r := range content {
  65. buf.Insert(r)
  66. }
  67. }
  68. func (buf *Buffer) Delete() {
  69. buf.ensureRope()
  70. buf.CM.DeduplicateAndSort()
  71. delta := 0
  72. for i := range buf.CM.Cursors {
  73. cur := &buf.CM.Cursors[i]
  74. pos := cur.Offset + delta
  75. if pos <= 0 {
  76. cur.Offset = 0
  77. continue
  78. }
  79. if pos > buf.Rope.Len() {
  80. pos = buf.Rope.Len()
  81. }
  82. left := buf.Rope.Slice(0, pos)
  83. _, size := utf8.DecodeLastRune(left)
  84. if size <= 0 {
  85. size = 1
  86. }
  87. start := pos - size
  88. if start < 0 {
  89. start = 0
  90. }
  91. buf.Rope.Remove(start, pos)
  92. buf.LI.RemoveAt(start, pos)
  93. deleted := pos - start
  94. delta -= deleted
  95. cur.Offset = start
  96. _, goal := LineCol(buf, cur.Offset)
  97. cur.Goal = goal
  98. }
  99. buf.CM.DeduplicateAndSort()
  100. }
  101. func (buf *Buffer) Clear() {
  102. buf.ensureRope()
  103. primaryCursor := &Cursor{
  104. Offset: 0,
  105. Goal: 0,
  106. }
  107. buf.CM.Cursors = buf.CM.Cursors[:0]
  108. buf.CM.Cursors = append(buf.CM.Cursors, *primaryCursor)
  109. buf.CM.PrimaryIdx = 0
  110. buf.Rope.Remove(0, buf.Rope.Len())
  111. buf.LI = NewLineIndex()
  112. }
  113. func (buf *Buffer) MoveHoriz(dir int) {
  114. buf.ensureRope()
  115. for i := range buf.CM.Cursors {
  116. cur := &buf.CM.Cursors[i]
  117. switch {
  118. case dir < 0:
  119. cur.Offset = prevRuneStart(buf.Rope, cur.Offset)
  120. case dir > 0:
  121. cur.Offset = nextRuneEnd(buf.Rope, cur.Offset)
  122. }
  123. _, goal := LineCol(buf, cur.Offset)
  124. cur.Goal = goal
  125. }
  126. buf.CM.DeduplicateAndSort()
  127. }
  128. func (buf *Buffer) MoveVert(dir int) {
  129. buf.ensureRope()
  130. for i := range buf.CM.Cursors {
  131. cur := &buf.CM.Cursors[i]
  132. line, _ := LineCol(buf, cur.Offset)
  133. targetLine := line + dir
  134. if targetLine < 0 || targetLine >= LineCount(buf) {
  135. continue
  136. }
  137. lineStart := OffsetForLine(buf, targetLine)
  138. lineEnd := lineContentEnd(buf, targetLine)
  139. lineLen := runeCount(buf.Rope, lineStart, lineEnd)
  140. goal := cur.Goal
  141. if goal > lineLen {
  142. goal = lineLen
  143. }
  144. cur.Offset = OffsetForLineCol(buf, targetLine, goal)
  145. }
  146. buf.CM.DeduplicateAndSort()
  147. }
  148. func (buf *Buffer) AddCursorVert(dir int) {
  149. buf.ensureRope()
  150. var newCursors []Cursor
  151. for i := range buf.CM.Cursors {
  152. cur := &buf.CM.Cursors[i]
  153. line, _ := LineCol(buf, cur.Offset)
  154. targetLine := line + dir
  155. if targetLine < 0 || targetLine >= LineCount(buf) {
  156. continue
  157. }
  158. lineStart := OffsetForLine(buf, targetLine)
  159. lineEnd := lineContentEnd(buf, targetLine)
  160. lineLen := runeCount(buf.Rope, lineStart, lineEnd)
  161. goal := cur.Goal
  162. if goal > lineLen {
  163. goal = lineLen
  164. }
  165. newCursors = append(newCursors, Cursor{
  166. Offset: OffsetForLineCol(buf, targetLine, goal),
  167. Goal: goal,
  168. })
  169. }
  170. buf.CM.Cursors = slices.Concat(buf.CM.Cursors, newCursors)
  171. buf.CM.DeduplicateAndSort()
  172. }
  173. func (buf *Buffer) ScrollToShow(line, maxHeight int) {
  174. if maxHeight <= 0 {
  175. return
  176. }
  177. if line < buf.TopLine {
  178. buf.TopLine = line
  179. } else if line >= buf.TopLine+maxHeight {
  180. buf.TopLine = line - maxHeight + 1
  181. }
  182. if buf.TopLine < 0 {
  183. buf.TopLine = 0
  184. }
  185. }
  186. func (buf *Buffer) ClearCursors() {
  187. primaryCursor := &Cursor{
  188. Offset: buf.CM.Cursors[buf.CM.PrimaryIdx].Offset,
  189. Goal: buf.CM.Cursors[buf.CM.PrimaryIdx].Goal,
  190. }
  191. buf.CM.Cursors = buf.CM.Cursors[:0]
  192. buf.CM.Cursors = append(buf.CM.Cursors, *primaryCursor)
  193. buf.CM.PrimaryIdx = 0
  194. }
  195. func LineCount(buf *Buffer) int {
  196. return buf.LI.Count()
  197. }
  198. func LineCol(buf *Buffer, offset int) (line, col int) {
  199. offset = normalizeOffset(buf.Rope, offset)
  200. if offset < 0 {
  201. offset = 0
  202. }
  203. if offset > buf.Rope.Len() {
  204. offset = buf.Rope.Len()
  205. }
  206. line = buf.LI.LineForOffset(offset)
  207. lineStart := buf.LI.OffsetForLine(line)
  208. col = runeCount(buf.Rope, lineStart, offset)
  209. return
  210. }
  211. func OffsetForLine(buf *Buffer, targetLine int) int {
  212. if targetLine <= 0 {
  213. return 0
  214. }
  215. if targetLine >= buf.LI.Count() {
  216. return buf.Rope.Len()
  217. }
  218. return buf.LI.OffsetForLine(targetLine)
  219. }
  220. func OffsetForLineCol(buf *Buffer, line int, col int) int {
  221. if col <= 0 {
  222. return OffsetForLine(buf, line)
  223. }
  224. start := OffsetForLine(buf, line)
  225. end := lineContentEnd(buf, line)
  226. i := start
  227. for n := 0; i < end && n < col; n++ {
  228. _, size := utf8.DecodeRune(buf.Rope.Slice(i, end))
  229. if size <= 0 {
  230. size = 1
  231. }
  232. i += size
  233. }
  234. if i > end {
  235. return end
  236. }
  237. return i
  238. }
  239. func lineContentEnd(buf *Buffer, line int) int {
  240. nextStart := OffsetForLine(buf, line+1)
  241. if nextStart > 0 && nextStart <= buf.Rope.Len() && buf.Rope.At(nextStart-1) == '\n' {
  242. return nextStart - 1
  243. }
  244. return nextStart
  245. }
  246. func runeCount(r *rope.Node, start, end int) int {
  247. if start < 0 {
  248. start = 0
  249. }
  250. if end < start {
  251. end = start
  252. }
  253. if end > r.Len() {
  254. end = r.Len()
  255. }
  256. return utf8.RuneCount(r.Slice(start, end))
  257. }
  258. func normalizeOffset(r *rope.Node, offset int) int {
  259. if offset < 0 {
  260. return 0
  261. }
  262. if offset > r.Len() {
  263. return r.Len()
  264. }
  265. for offset > 0 && offset < r.Len() && !utf8.RuneStart(r.At(offset)) {
  266. offset--
  267. }
  268. return offset
  269. }
  270. func prevRuneStart(r *rope.Node, offset int) int {
  271. offset = normalizeOffset(r, offset)
  272. if offset <= 0 {
  273. return 0
  274. }
  275. left := r.Slice(0, offset)
  276. _, size := utf8.DecodeLastRune(left)
  277. if size <= 0 {
  278. size = 1
  279. }
  280. start := offset - size
  281. if start < 0 {
  282. start = 0
  283. }
  284. return start
  285. }
  286. func nextRuneEnd(r *rope.Node, offset int) int {
  287. offset = normalizeOffset(r, offset)
  288. if offset >= r.Len() {
  289. return r.Len()
  290. }
  291. _, size := utf8.DecodeRune(r.Slice(offset, r.Len()))
  292. if size <= 0 {
  293. size = 1
  294. }
  295. end := offset + size
  296. if end > r.Len() {
  297. end = r.Len()
  298. }
  299. return end
  300. }
  301. func (buf Buffer) String() string {
  302. if buf.Rope == nil {
  303. return ""
  304. }
  305. return string(buf.Rope.Value())
  306. }