buffer.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. package buffer
  2. import (
  3. "slices"
  4. "unicode"
  5. "unicode/utf8"
  6. "github.com/zyedidia/rope"
  7. )
  8. type BufferManager struct {
  9. Buffers []Buffer
  10. CurrentIdx int
  11. PaletteBuffer Buffer
  12. }
  13. func (bm *BufferManager) Current() *Buffer {
  14. return &bm.Buffers[bm.CurrentIdx]
  15. }
  16. type Buffer struct {
  17. Rope *rope.Node
  18. LI *LineIndex
  19. CM CursorManager
  20. Path string
  21. TopLine int
  22. History UndoStack
  23. }
  24. func NewBuffer() Buffer {
  25. return Buffer{
  26. Rope: rope.New([]byte{}),
  27. LI: NewLineIndex(),
  28. CM: CursorManager{
  29. Cursors: []Cursor{{Offset: 0, Goal: 0}},
  30. PrimaryIdx: 0,
  31. },
  32. }
  33. }
  34. func (buf *Buffer) ensureRope() {
  35. if buf.Rope == nil {
  36. buf.Rope = rope.New([]byte{})
  37. }
  38. if buf.LI == nil {
  39. buf.LI = NewLineIndexFromRope(buf.Rope)
  40. }
  41. }
  42. func (buf *Buffer) Insert(content string) {
  43. buf.ensureRope()
  44. buf.CM.DeduplicateAndSort()
  45. cursorsBefore, primaryBefore := buf.begin()
  46. delta := 0
  47. data := []byte(content)
  48. shift := len(data)
  49. edits := make([]Edit, 0, len(buf.CM.Cursors))
  50. for i := range buf.CM.Cursors {
  51. cur := &buf.CM.Cursors[i]
  52. pos := cur.Offset + delta
  53. if pos < 0 {
  54. pos = 0
  55. }
  56. if pos > buf.Rope.Len() {
  57. pos = buf.Rope.Len()
  58. }
  59. edit := Edit{Offset: pos, Inserted: data}
  60. buf.apply(edit)
  61. edits = append(edits, edit)
  62. cur.Offset = pos + shift
  63. _, goal := LineCol(buf, cur.Offset)
  64. cur.Goal = goal
  65. delta += shift
  66. }
  67. buf.commit(cursorsBefore, primaryBefore, edits)
  68. }
  69. func (buf *Buffer) Delete() {
  70. buf.ensureRope()
  71. buf.CM.DeduplicateAndSort()
  72. cursorsBefore, primaryBefore := buf.begin()
  73. delta := 0
  74. var edits []Edit
  75. for i := range buf.CM.Cursors {
  76. cur := &buf.CM.Cursors[i]
  77. pos := cur.Offset + delta
  78. if pos <= 0 {
  79. cur.Offset = 0
  80. continue
  81. }
  82. if pos > buf.Rope.Len() {
  83. pos = buf.Rope.Len()
  84. }
  85. left := buf.Rope.Slice(0, pos)
  86. _, size := utf8.DecodeLastRune(left)
  87. if size <= 0 {
  88. size = 1
  89. }
  90. start := pos - size
  91. if start < 0 {
  92. start = 0
  93. }
  94. deleted := append([]byte{}, buf.Rope.Slice(start, pos)...)
  95. edit := Edit{Offset: start, Deleted: deleted}
  96. buf.apply(edit)
  97. edits = append(edits, edit)
  98. delta -= len(deleted)
  99. cur.Offset = start
  100. _, goal := LineCol(buf, cur.Offset)
  101. cur.Goal = goal
  102. }
  103. buf.CM.DeduplicateAndSort()
  104. buf.commit(cursorsBefore, primaryBefore, edits)
  105. }
  106. func (buf *Buffer) DeleteLine() {
  107. buf.ensureRope()
  108. buf.CM.DeduplicateAndSort()
  109. if buf.Rope.Len() == 0 || len(buf.CM.Cursors) == 0 {
  110. return
  111. }
  112. cursorsBefore, primaryBefore := buf.begin()
  113. primary := buf.CM.Cursors[buf.CM.PrimaryIdx]
  114. line, _ := LineCol(buf, primary.Offset)
  115. start := OffsetForLine(buf, line)
  116. end := buf.Rope.Len()
  117. if line+1 < LineCount(buf) {
  118. end = OffsetForLine(buf, line+1)
  119. } else if line > 0 && start > 0 && buf.Rope.At(start-1) == '\n' {
  120. start--
  121. }
  122. if end <= start {
  123. return
  124. }
  125. deleted := append([]byte{}, buf.Rope.Slice(start, end)...)
  126. edit := Edit{Offset: start, Deleted: deleted}
  127. buf.apply(edit)
  128. newLine := line
  129. if newLine >= LineCount(buf) {
  130. newLine = LineCount(buf) - 1
  131. }
  132. if newLine < 0 {
  133. newLine = 0
  134. }
  135. newOffset := OffsetForLine(buf, newLine)
  136. for i := range buf.CM.Cursors {
  137. buf.CM.Cursors[i].Offset = newOffset
  138. buf.CM.Cursors[i].Goal = 0
  139. }
  140. buf.CM.DeduplicateAndSort()
  141. buf.commit(cursorsBefore, primaryBefore, []Edit{edit})
  142. }
  143. func (buf *Buffer) Clear() {
  144. buf.ensureRope()
  145. cursorsBefore, primaryBefore := buf.begin()
  146. primaryCursor := &Cursor{
  147. Offset: 0,
  148. Goal: 0,
  149. }
  150. buf.CM.Cursors = buf.CM.Cursors[:0]
  151. buf.CM.Cursors = append(buf.CM.Cursors, *primaryCursor)
  152. buf.CM.PrimaryIdx = 0
  153. var edits []Edit
  154. if buf.Rope.Len() > 0 {
  155. deleted := append([]byte{}, buf.Rope.Value()...)
  156. edit := Edit{Offset: 0, Deleted: deleted}
  157. buf.apply(edit)
  158. edits = append(edits, edit)
  159. }
  160. buf.commit(cursorsBefore, primaryBefore, edits)
  161. }
  162. func isWordRune(r rune) bool {
  163. return unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_'
  164. }
  165. func (buf *Buffer) MoveWordHoriz(dir int) {
  166. buf.ensureRope()
  167. for i := range buf.CM.Cursors {
  168. cur := &buf.CM.Cursors[i]
  169. pos := normalizeOffset(buf.Rope, cur.Offset)
  170. switch {
  171. case dir > 0:
  172. for pos < buf.Rope.Len() {
  173. r, size := utf8.DecodeRune(buf.Rope.Slice(pos, buf.Rope.Len()))
  174. if size <= 0 {
  175. size = 1
  176. }
  177. if !isWordRune(r) {
  178. break
  179. }
  180. pos += size
  181. }
  182. for pos < buf.Rope.Len() {
  183. r, size := utf8.DecodeRune(buf.Rope.Slice(pos, buf.Rope.Len()))
  184. if size <= 0 {
  185. size = 1
  186. }
  187. if isWordRune(r) {
  188. break
  189. }
  190. pos += size
  191. }
  192. case dir < 0:
  193. for pos > 0 {
  194. start := prevRuneStart(buf.Rope, pos)
  195. r, _ := utf8.DecodeRune(buf.Rope.Slice(start, pos))
  196. if isWordRune(r) {
  197. break
  198. }
  199. pos = start
  200. }
  201. for pos > 0 {
  202. start := prevRuneStart(buf.Rope, pos)
  203. r, _ := utf8.DecodeRune(buf.Rope.Slice(start, pos))
  204. if !isWordRune(r) {
  205. break
  206. }
  207. pos = start
  208. }
  209. }
  210. cur.Offset = pos
  211. _, goal := LineCol(buf, cur.Offset)
  212. cur.Goal = goal
  213. }
  214. buf.CM.DeduplicateAndSort()
  215. }
  216. func (buf *Buffer) MoveHoriz(dir int) {
  217. buf.ensureRope()
  218. for i := range buf.CM.Cursors {
  219. cur := &buf.CM.Cursors[i]
  220. switch {
  221. case dir < 0:
  222. cur.Offset = prevRuneStart(buf.Rope, cur.Offset)
  223. case dir > 0:
  224. cur.Offset = nextRuneEnd(buf.Rope, cur.Offset)
  225. }
  226. _, goal := LineCol(buf, cur.Offset)
  227. cur.Goal = goal
  228. }
  229. buf.CM.DeduplicateAndSort()
  230. }
  231. func (buf *Buffer) MoveVert(dir int) {
  232. buf.ensureRope()
  233. for i := range buf.CM.Cursors {
  234. cur := &buf.CM.Cursors[i]
  235. line, _ := LineCol(buf, cur.Offset)
  236. targetLine := line + dir
  237. if targetLine < 0 || targetLine >= LineCount(buf) {
  238. continue
  239. }
  240. lineStart := OffsetForLine(buf, targetLine)
  241. lineEnd := lineContentEnd(buf, targetLine)
  242. lineLen := runeCount(buf.Rope, lineStart, lineEnd)
  243. goal := cur.Goal
  244. if goal > lineLen {
  245. goal = lineLen
  246. }
  247. cur.Offset = OffsetForLineCol(buf, targetLine, goal)
  248. }
  249. buf.CM.DeduplicateAndSort()
  250. }
  251. func (buf *Buffer) AddCursorVert(dir int) {
  252. buf.ensureRope()
  253. var newCursors []Cursor
  254. for i := range buf.CM.Cursors {
  255. cur := &buf.CM.Cursors[i]
  256. line, _ := LineCol(buf, cur.Offset)
  257. targetLine := line + dir
  258. if targetLine < 0 || targetLine >= LineCount(buf) {
  259. continue
  260. }
  261. goal := buf.CM.Cursors[buf.CM.PrimaryIdx].Goal
  262. newCursors = append(newCursors, Cursor{
  263. Offset: OffsetForLineCol(buf, targetLine, goal),
  264. Goal: goal,
  265. })
  266. }
  267. buf.CM.Cursors = slices.Concat(buf.CM.Cursors, newCursors)
  268. buf.CM.DeduplicateAndSort()
  269. }
  270. func (buf *Buffer) ScrollToShow(line, maxHeight int) {
  271. if maxHeight <= 0 {
  272. return
  273. }
  274. if line < buf.TopLine {
  275. buf.TopLine = line
  276. } else if line >= buf.TopLine+maxHeight {
  277. buf.TopLine = line - maxHeight + 1
  278. }
  279. if buf.TopLine < 0 {
  280. buf.TopLine = 0
  281. }
  282. }
  283. func (buf *Buffer) ClearCursors() {
  284. primaryCursor := &Cursor{
  285. Offset: buf.CM.Cursors[buf.CM.PrimaryIdx].Offset,
  286. Goal: buf.CM.Cursors[buf.CM.PrimaryIdx].Goal,
  287. }
  288. buf.CM.Cursors = buf.CM.Cursors[:0]
  289. buf.CM.Cursors = append(buf.CM.Cursors, *primaryCursor)
  290. buf.CM.PrimaryIdx = 0
  291. }
  292. func LineCount(buf *Buffer) int {
  293. return buf.LI.Count()
  294. }
  295. func LineCol(buf *Buffer, offset int) (line, col int) {
  296. offset = normalizeOffset(buf.Rope, offset)
  297. if offset < 0 {
  298. offset = 0
  299. }
  300. if offset > buf.Rope.Len() {
  301. offset = buf.Rope.Len()
  302. }
  303. line = buf.LI.LineForOffset(offset)
  304. lineStart := buf.LI.OffsetForLine(line)
  305. col = runeCount(buf.Rope, lineStart, offset)
  306. return
  307. }
  308. func OffsetForLine(buf *Buffer, targetLine int) int {
  309. if targetLine <= 0 {
  310. return 0
  311. }
  312. if targetLine >= buf.LI.Count() {
  313. return buf.Rope.Len()
  314. }
  315. return buf.LI.OffsetForLine(targetLine)
  316. }
  317. func OffsetForLineCol(buf *Buffer, line int, col int) int {
  318. if col <= 0 {
  319. return OffsetForLine(buf, line)
  320. }
  321. start := OffsetForLine(buf, line)
  322. end := lineContentEnd(buf, line)
  323. i := start
  324. for n := 0; i < end && n < col; n++ {
  325. _, size := utf8.DecodeRune(buf.Rope.Slice(i, end))
  326. if size <= 0 {
  327. size = 1
  328. }
  329. i += size
  330. }
  331. if i > end {
  332. return end
  333. }
  334. return i
  335. }
  336. func LineText(buf *Buffer, line int) string {
  337. start := OffsetForLine(buf, line)
  338. end := lineContentEnd(buf, line)
  339. if end < start {
  340. end = start
  341. }
  342. return string(buf.Rope.Slice(start, end))
  343. }
  344. func lineContentEnd(buf *Buffer, line int) int {
  345. nextStart := OffsetForLine(buf, line+1)
  346. if nextStart > 0 && nextStart <= buf.Rope.Len() && buf.Rope.At(nextStart-1) == '\n' {
  347. return nextStart - 1
  348. }
  349. return nextStart
  350. }
  351. func runeCount(r *rope.Node, start, end int) int {
  352. if start < 0 {
  353. start = 0
  354. }
  355. if end < start {
  356. end = start
  357. }
  358. if end > r.Len() {
  359. end = r.Len()
  360. }
  361. return utf8.RuneCount(r.Slice(start, end))
  362. }
  363. func normalizeOffset(r *rope.Node, offset int) int {
  364. if offset < 0 {
  365. return 0
  366. }
  367. if offset > r.Len() {
  368. return r.Len()
  369. }
  370. for offset > 0 && offset < r.Len() && !utf8.RuneStart(r.At(offset)) {
  371. offset--
  372. }
  373. return offset
  374. }
  375. func prevRuneStart(r *rope.Node, offset int) int {
  376. offset = normalizeOffset(r, offset)
  377. if offset <= 0 {
  378. return 0
  379. }
  380. left := r.Slice(0, offset)
  381. _, size := utf8.DecodeLastRune(left)
  382. if size <= 0 {
  383. size = 1
  384. }
  385. start := offset - size
  386. if start < 0 {
  387. start = 0
  388. }
  389. return start
  390. }
  391. func nextRuneEnd(r *rope.Node, offset int) int {
  392. offset = normalizeOffset(r, offset)
  393. if offset >= r.Len() {
  394. return r.Len()
  395. }
  396. _, size := utf8.DecodeRune(r.Slice(offset, r.Len()))
  397. if size <= 0 {
  398. size = 1
  399. }
  400. end := offset + size
  401. if end > r.Len() {
  402. end = r.Len()
  403. }
  404. return end
  405. }
  406. func RuneAt(buf *Buffer, offset int) rune {
  407. if buf.Rope == nil || offset < 0 || offset >= buf.Rope.Len() {
  408. return ' '
  409. }
  410. r, size := utf8.DecodeRune(buf.Rope.Slice(offset, buf.Rope.Len()))
  411. if size <= 0 || r == '\n' || r == '\t' {
  412. return ' '
  413. }
  414. return r
  415. }
  416. func (buf Buffer) String() string {
  417. if buf.Rope == nil {
  418. return ""
  419. }
  420. return string(buf.Rope.Value())
  421. }