1
0

model.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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. model := EditorModel{
  28. Buffer: initialBuf,
  29. Viewport: vp,
  30. Keymap: Keymap{
  31. left: key.NewBinding(
  32. key.WithKeys("left"),
  33. ),
  34. right: key.NewBinding(
  35. key.WithKeys("right"),
  36. ),
  37. up: key.NewBinding(
  38. key.WithKeys("up"),
  39. ),
  40. down: key.NewBinding(
  41. key.WithKeys("down"),
  42. ),
  43. cursorUp: key.NewBinding(
  44. key.WithKeys("shift+up"),
  45. ),
  46. cursorDown: key.NewBinding(
  47. key.WithKeys("shift+down"),
  48. ),
  49. clearCursors: key.NewBinding(
  50. key.WithKeys("esc"),
  51. ),
  52. tab: key.NewBinding(
  53. key.WithKeys("tab"),
  54. ),
  55. backtab: key.NewBinding(
  56. key.WithKeys("shift+tab"),
  57. ),
  58. delete: key.NewBinding(
  59. key.WithKeys("backspace"),
  60. ),
  61. newline: key.NewBinding(
  62. key.WithKeys("enter"),
  63. ),
  64. quit: key.NewBinding(
  65. key.WithKeys("ctrl+c"),
  66. ),
  67. },
  68. }
  69. model.Viewport.SetContent(model.renderedContent())
  70. return model
  71. }
  72. func (m EditorModel) Init() tea.Cmd {
  73. return nil
  74. }
  75. func (m EditorModel) View() tea.View {
  76. v := tea.NewView(m.Viewport.View())
  77. v.AltScreen = true
  78. return v
  79. }
  80. func (m EditorModel) renderedContent() string {
  81. content := []rune(m.Buffer.String())
  82. cursorMap := make(map[int]bool)
  83. for _, cur := range m.Buffer.CM.Cursors {
  84. offset := cur.Offset
  85. if offset < 0 {
  86. offset = 0
  87. }
  88. if offset > len(content) {
  89. offset = len(content)
  90. }
  91. cursorMap[offset] = true
  92. }
  93. out := make([]rune, 0, len(content)+len(cursorMap))
  94. for i, r := range content {
  95. if cursorMap[i] {
  96. out = append(out, '█')
  97. if r == '\n' {
  98. out = append(out, r)
  99. }
  100. } else {
  101. out = append(out, r)
  102. }
  103. }
  104. if cursorMap[len(content)] {
  105. out = append(out, '█')
  106. }
  107. return string(out)
  108. }