1
0

buffer.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  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 string) {
  41. buf.ensureRope()
  42. buf.CM.DeduplicateAndSort()
  43. delta := 0
  44. data := []byte(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) Delete() {
  64. buf.ensureRope()
  65. buf.CM.DeduplicateAndSort()
  66. delta := 0
  67. for i := range buf.CM.Cursors {
  68. cur := &buf.CM.Cursors[i]
  69. pos := cur.Offset + delta
  70. if pos <= 0 {
  71. cur.Offset = 0
  72. continue
  73. }
  74. if pos > buf.Rope.Len() {
  75. pos = buf.Rope.Len()
  76. }
  77. left := buf.Rope.Slice(0, pos)
  78. _, size := utf8.DecodeLastRune(left)
  79. if size <= 0 {
  80. size = 1
  81. }
  82. start := pos - size
  83. if start < 0 {
  84. start = 0
  85. }
  86. buf.Rope.Remove(start, pos)
  87. buf.LI.RemoveAt(start, pos)
  88. deleted := pos - start
  89. delta -= deleted
  90. cur.Offset = start
  91. _, goal := LineCol(buf, cur.Offset)
  92. cur.Goal = goal
  93. }
  94. buf.CM.DeduplicateAndSort()
  95. }
  96. func (buf *Buffer) Clear() {
  97. buf.ensureRope()
  98. primaryCursor := &Cursor{
  99. Offset: 0,
  100. Goal: 0,
  101. }
  102. buf.CM.Cursors = buf.CM.Cursors[:0]
  103. buf.CM.Cursors = append(buf.CM.Cursors, *primaryCursor)
  104. buf.CM.PrimaryIdx = 0
  105. buf.Rope.Remove(0, buf.Rope.Len())
  106. buf.LI = NewLineIndex()
  107. }
  108. func (buf *Buffer) MoveHoriz(dir int) {
  109. buf.ensureRope()
  110. for i := range buf.CM.Cursors {
  111. cur := &buf.CM.Cursors[i]
  112. switch {
  113. case dir < 0:
  114. cur.Offset = prevRuneStart(buf.Rope, cur.Offset)
  115. case dir > 0:
  116. cur.Offset = nextRuneEnd(buf.Rope, cur.Offset)
  117. }
  118. _, goal := LineCol(buf, cur.Offset)
  119. cur.Goal = goal
  120. }
  121. buf.CM.DeduplicateAndSort()
  122. }
  123. func (buf *Buffer) MoveVert(dir int) {
  124. buf.ensureRope()
  125. for i := range buf.CM.Cursors {
  126. cur := &buf.CM.Cursors[i]
  127. line, _ := LineCol(buf, cur.Offset)
  128. targetLine := line + dir
  129. if targetLine < 0 || targetLine >= LineCount(buf) {
  130. continue
  131. }
  132. lineStart := OffsetForLine(buf, targetLine)
  133. lineEnd := lineContentEnd(buf, targetLine)
  134. lineLen := runeCount(buf.Rope, lineStart, lineEnd)
  135. goal := cur.Goal
  136. if goal > lineLen {
  137. goal = lineLen
  138. }
  139. cur.Offset = OffsetForLineCol(buf, targetLine, goal)
  140. }
  141. buf.CM.DeduplicateAndSort()
  142. }
  143. func (buf *Buffer) AddCursorVert(dir int) {
  144. buf.ensureRope()
  145. var newCursors []Cursor
  146. for i := range buf.CM.Cursors {
  147. cur := &buf.CM.Cursors[i]
  148. line, _ := LineCol(buf, cur.Offset)
  149. targetLine := line + dir
  150. if targetLine < 0 || targetLine >= LineCount(buf) {
  151. continue
  152. }
  153. lineStart := OffsetForLine(buf, targetLine)
  154. lineEnd := lineContentEnd(buf, targetLine)
  155. lineLen := runeCount(buf.Rope, lineStart, lineEnd)
  156. goal := cur.Goal
  157. if goal > lineLen {
  158. goal = lineLen
  159. }
  160. newCursors = append(newCursors, Cursor{
  161. Offset: OffsetForLineCol(buf, targetLine, goal),
  162. Goal: goal,
  163. })
  164. }
  165. buf.CM.Cursors = slices.Concat(buf.CM.Cursors, newCursors)
  166. buf.CM.DeduplicateAndSort()
  167. }
  168. func (buf *Buffer) ScrollToShow(line, maxHeight int) {
  169. if maxHeight <= 0 {
  170. return
  171. }
  172. if line < buf.TopLine {
  173. buf.TopLine = line
  174. } else if line >= buf.TopLine+maxHeight {
  175. buf.TopLine = line - maxHeight + 1
  176. }
  177. if buf.TopLine < 0 {
  178. buf.TopLine = 0
  179. }
  180. }
  181. func (buf *Buffer) ClearCursors() {
  182. primaryCursor := &Cursor{
  183. Offset: buf.CM.Cursors[buf.CM.PrimaryIdx].Offset,
  184. Goal: buf.CM.Cursors[buf.CM.PrimaryIdx].Goal,
  185. }
  186. buf.CM.Cursors = buf.CM.Cursors[:0]
  187. buf.CM.Cursors = append(buf.CM.Cursors, *primaryCursor)
  188. buf.CM.PrimaryIdx = 0
  189. }
  190. func LineCount(buf *Buffer) int {
  191. return buf.LI.Count()
  192. }
  193. func LineCol(buf *Buffer, offset int) (line, col int) {
  194. offset = normalizeOffset(buf.Rope, offset)
  195. if offset < 0 {
  196. offset = 0
  197. }
  198. if offset > buf.Rope.Len() {
  199. offset = buf.Rope.Len()
  200. }
  201. line = buf.LI.LineForOffset(offset)
  202. lineStart := buf.LI.OffsetForLine(line)
  203. col = runeCount(buf.Rope, lineStart, offset)
  204. return
  205. }
  206. func OffsetForLine(buf *Buffer, targetLine int) int {
  207. if targetLine <= 0 {
  208. return 0
  209. }
  210. if targetLine >= buf.LI.Count() {
  211. return buf.Rope.Len()
  212. }
  213. return buf.LI.OffsetForLine(targetLine)
  214. }
  215. func OffsetForLineCol(buf *Buffer, line int, col int) int {
  216. if col <= 0 {
  217. return OffsetForLine(buf, line)
  218. }
  219. start := OffsetForLine(buf, line)
  220. end := lineContentEnd(buf, line)
  221. i := start
  222. for n := 0; i < end && n < col; n++ {
  223. _, size := utf8.DecodeRune(buf.Rope.Slice(i, end))
  224. if size <= 0 {
  225. size = 1
  226. }
  227. i += size
  228. }
  229. if i > end {
  230. return end
  231. }
  232. return i
  233. }
  234. func LineText(buf *Buffer, line int) string {
  235. start := OffsetForLine(buf, line)
  236. end := lineContentEnd(buf, line)
  237. if end < start {
  238. end = start
  239. }
  240. return string(buf.Rope.Slice(start, end))
  241. }
  242. func lineContentEnd(buf *Buffer, line int) int {
  243. nextStart := OffsetForLine(buf, line+1)
  244. if nextStart > 0 && nextStart <= buf.Rope.Len() && buf.Rope.At(nextStart-1) == '\n' {
  245. return nextStart - 1
  246. }
  247. return nextStart
  248. }
  249. func runeCount(r *rope.Node, start, end int) int {
  250. if start < 0 {
  251. start = 0
  252. }
  253. if end < start {
  254. end = start
  255. }
  256. if end > r.Len() {
  257. end = r.Len()
  258. }
  259. return utf8.RuneCount(r.Slice(start, end))
  260. }
  261. func normalizeOffset(r *rope.Node, offset int) int {
  262. if offset < 0 {
  263. return 0
  264. }
  265. if offset > r.Len() {
  266. return r.Len()
  267. }
  268. for offset > 0 && offset < r.Len() && !utf8.RuneStart(r.At(offset)) {
  269. offset--
  270. }
  271. return offset
  272. }
  273. func prevRuneStart(r *rope.Node, offset int) int {
  274. offset = normalizeOffset(r, offset)
  275. if offset <= 0 {
  276. return 0
  277. }
  278. left := r.Slice(0, offset)
  279. _, size := utf8.DecodeLastRune(left)
  280. if size <= 0 {
  281. size = 1
  282. }
  283. start := offset - size
  284. if start < 0 {
  285. start = 0
  286. }
  287. return start
  288. }
  289. func nextRuneEnd(r *rope.Node, offset int) int {
  290. offset = normalizeOffset(r, offset)
  291. if offset >= r.Len() {
  292. return r.Len()
  293. }
  294. _, size := utf8.DecodeRune(r.Slice(offset, r.Len()))
  295. if size <= 0 {
  296. size = 1
  297. }
  298. end := offset + size
  299. if end > r.Len() {
  300. end = r.Len()
  301. }
  302. return end
  303. }
  304. func RuneAt(buf *Buffer, offset int) rune {
  305. if buf.Rope == nil || offset < 0 || offset >= buf.Rope.Len() {
  306. return ' '
  307. }
  308. r, size := utf8.DecodeRune(buf.Rope.Slice(offset, buf.Rope.Len()))
  309. if size <= 0 || r == '\n' || r == '\t' {
  310. return ' '
  311. }
  312. return r
  313. }
  314. func (buf Buffer) String() string {
  315. if buf.Rope == nil {
  316. return ""
  317. }
  318. return string(buf.Rope.Value())
  319. }