buffer.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. package buffer
  2. import (
  3. "unicode/utf8"
  4. "github.com/zyedidia/rope"
  5. )
  6. type Buffer struct {
  7. Rope *rope.Node
  8. CM CursorManager
  9. }
  10. func (buf *Buffer) ensureRope() {
  11. if buf.Rope == nil {
  12. buf.Rope = rope.New([]byte{})
  13. }
  14. }
  15. func (buf *Buffer) Insert(content rune) {
  16. buf.ensureRope()
  17. data := []byte(string(content))
  18. shift := len(data)
  19. for i := range buf.CM.Cursors {
  20. cur := &buf.CM.Cursors[i]
  21. if cur.Offset < 0 {
  22. cur.Offset = 0
  23. }
  24. if cur.Offset > buf.Rope.Len() {
  25. cur.Offset = buf.Rope.Len()
  26. }
  27. buf.Rope.Insert(cur.Offset, data)
  28. cur.Offset += shift
  29. }
  30. buf.CM.DeduplicateAndSort()
  31. }
  32. func (buf *Buffer) Delete() {
  33. buf.ensureRope()
  34. for i := range buf.CM.Cursors {
  35. cur := &buf.CM.Cursors[i]
  36. if cur.Offset <= 0 {
  37. continue
  38. }
  39. if cur.Offset > buf.Rope.Len() {
  40. cur.Offset = buf.Rope.Len()
  41. }
  42. left := buf.Rope.Slice(0, cur.Offset)
  43. _, size := utf8.DecodeLastRune(left)
  44. if size <= 0 {
  45. size = 1
  46. }
  47. start := cur.Offset - size
  48. if start < 0 {
  49. start = 0
  50. }
  51. buf.Rope.Remove(start, cur.Offset)
  52. cur.Offset = start
  53. }
  54. buf.CM.DeduplicateAndSort()
  55. }
  56. func (buf *Buffer) MoveHoriz(dir int) {
  57. buf.ensureRope()
  58. for i := range buf.CM.Cursors {
  59. cur := &buf.CM.Cursors[i]
  60. if cur.Offset + dir < 0 || cur.Offset + dir > buf.Rope.Len() {
  61. continue
  62. }
  63. cur.Offset += dir
  64. _, goal := LineCol(buf.Rope, cur.Offset)
  65. cur.Goal = goal
  66. }
  67. }
  68. func (buf *Buffer) MoveVert(dir int) {
  69. buf.ensureRope()
  70. for i := range buf.CM.Cursors {
  71. cur := &buf.CM.Cursors[i]
  72. line, _ := LineCol(buf.Rope, cur.Offset)
  73. if line + dir < 0 || line + dir > LineCount(buf.Rope) {
  74. continue
  75. }
  76. line += dir
  77. cur.Offset = OffsetForLine(buf.Rope, line) + cur.Goal
  78. }
  79. }
  80. func LineCount(r *rope.Node) int {
  81. if r.Len() == 0 {
  82. return 0
  83. }
  84. lines := r.Count(0, r.Len(), []byte{'\n'})
  85. if r.At(r.Len()-1) != '\n' {
  86. lines++
  87. }
  88. return lines
  89. }
  90. func LineCol(r *rope.Node, offset int) (line, col int) {
  91. if offset < 0 {
  92. offset = 0
  93. }
  94. if offset > r.Len() {
  95. offset = r.Len()
  96. }
  97. line = r.Count(0, offset, []byte{'\n'})
  98. lineStart := 0
  99. for i := offset - 1; i >= 0; i-- {
  100. if r.At(i) == '\n' {
  101. lineStart = i + 1
  102. break
  103. }
  104. }
  105. col = offset - lineStart
  106. return
  107. }
  108. func OffsetForLine(r *rope.Node, targetLine int) int {
  109. if targetLine <= 0 {
  110. return 0
  111. }
  112. line := 0
  113. for i := 0; i < r.Len(); i++ {
  114. if r.At(i) == '\n' {
  115. line++
  116. if line == targetLine {
  117. return i + 1
  118. }
  119. }
  120. }
  121. return r.Len()
  122. }
  123. func (buf Buffer) String() string {
  124. if buf.Rope == nil {
  125. return ""
  126. }
  127. return string(buf.Rope.Value())
  128. }