model.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package tui
  2. import (
  3. "moose/internal/buffer"
  4. "charm.land/bubbles/v2/key"
  5. "charm.land/bubbles/v2/viewport"
  6. tea "charm.land/bubbletea/v2"
  7. )
  8. type Keymap = struct {
  9. left, right, up, down, cursorUp, cursorDown, clearCursors, tab, backtab, newline, delete, quit key.Binding
  10. }
  11. type EditorModel struct {
  12. Buffer buffer.Buffer
  13. Viewport viewport.Model
  14. Keymap Keymap
  15. Width int
  16. Height int
  17. }
  18. func NewEditorModel() EditorModel {
  19. initialBuf := buffer.Buffer{
  20. Rope: nil,
  21. CM: buffer.CursorManager{
  22. Cursors: []buffer.Cursor{{Offset: 0, Goal: 0}},
  23. PrimaryIdx: 0,
  24. },
  25. }
  26. vp := viewport.New()
  27. vp.MouseWheelEnabled = false
  28. model := EditorModel{
  29. Buffer: initialBuf,
  30. Viewport: vp,
  31. Keymap: Keymap{
  32. left: key.NewBinding(
  33. key.WithKeys("left"),
  34. ),
  35. right: key.NewBinding(
  36. key.WithKeys("right"),
  37. ),
  38. up: key.NewBinding(
  39. key.WithKeys("up"),
  40. ),
  41. down: key.NewBinding(
  42. key.WithKeys("down"),
  43. ),
  44. cursorUp: key.NewBinding(
  45. key.WithKeys("shift+up"),
  46. ),
  47. cursorDown: key.NewBinding(
  48. key.WithKeys("shift+down"),
  49. ),
  50. clearCursors: key.NewBinding(
  51. key.WithKeys("esc"),
  52. ),
  53. tab: key.NewBinding(
  54. key.WithKeys("tab"),
  55. ),
  56. backtab: key.NewBinding(
  57. key.WithKeys("shift+tab"),
  58. ),
  59. delete: key.NewBinding(
  60. key.WithKeys("backspace"),
  61. ),
  62. newline: key.NewBinding(
  63. key.WithKeys("enter"),
  64. ),
  65. quit: key.NewBinding(
  66. key.WithKeys("ctrl+c"),
  67. ),
  68. },
  69. }
  70. model.Viewport.SetContent(model.renderedContent())
  71. return model
  72. }
  73. func (m EditorModel) Init() tea.Cmd {
  74. return nil
  75. }
  76. func (m EditorModel) View() tea.View {
  77. v := tea.NewView(m.Viewport.View())
  78. v.AltScreen = true
  79. v.MouseMode = tea.MouseModeCellMotion
  80. return v
  81. }
  82. func (m EditorModel) renderedContent() string {
  83. content := []rune(m.Buffer.String())
  84. cursorMap := make(map[int]bool)
  85. for _, cur := range m.Buffer.CM.Cursors {
  86. offset := cur.Offset
  87. if offset < 0 {
  88. offset = 0
  89. }
  90. if offset > len(content) {
  91. offset = len(content)
  92. }
  93. cursorMap[offset] = true
  94. }
  95. out := make([]rune, 0, len(content)+len(cursorMap))
  96. for i, r := range content {
  97. if cursorMap[i] {
  98. out = append(out, '█')
  99. if r == '\n' {
  100. out = append(out, r)
  101. }
  102. } else {
  103. out = append(out, r)
  104. }
  105. }
  106. if cursorMap[len(content)] {
  107. out = append(out, '█')
  108. }
  109. return string(out)
  110. }