Johan Rong 1 месяц назад
Родитель
Сommit
8205eec9c6

+ 40 - 40
internal/buffer/buffer.go

@@ -1,15 +1,15 @@
 package buffer
 
 import (
-	"unicode/utf8"
 	"slices"
+	"unicode/utf8"
 
 	"github.com/zyedidia/rope"
 )
 
 type Buffer struct {
 	Rope *rope.Node
-	CM CursorManager
+	CM   CursorManager
 }
 
 func (buf *Buffer) ensureRope() {
@@ -93,7 +93,7 @@ func (buf *Buffer) MoveHoriz(dir int) {
 
 	for i := range buf.CM.Cursors {
 		cur := &buf.CM.Cursors[i]
-		if cur.Offset + dir < 0 || cur.Offset + dir > buf.Rope.Len() {
+		if cur.Offset+dir < 0 || cur.Offset+dir > buf.Rope.Len() {
 			continue
 		}
 
@@ -138,7 +138,7 @@ func (buf *Buffer) MoveVert(dir int) {
 func (buf *Buffer) AddCursorVert(dir int) {
 	buf.ensureRope()
 
-	var newCursors []Cursor 
+	var newCursors []Cursor
 
 	for i := range buf.CM.Cursors {
 		cur := &buf.CM.Cursors[i]
@@ -164,7 +164,7 @@ func (buf *Buffer) AddCursorVert(dir int) {
 
 		newCursors = append(newCursors, Cursor{
 			Offset: lineStart + goal,
-			Goal: goal,
+			Goal:   goal,
 		})
 	}
 
@@ -176,7 +176,7 @@ func (buf *Buffer) AddCursorVert(dir int) {
 func (buf *Buffer) ClearCursors() {
 	primaryCursor := &Cursor{
 		Offset: buf.CM.Cursors[buf.CM.PrimaryIdx].Offset,
-		Goal: buf.CM.Cursors[buf.CM.PrimaryIdx].Goal,
+		Goal:   buf.CM.Cursors[buf.CM.PrimaryIdx].Goal,
 	}
 
 	buf.CM.Cursors = buf.CM.Cursors[:0]
@@ -189,43 +189,43 @@ func LineCount(r *rope.Node) int {
 }
 
 func LineCol(r *rope.Node, offset int) (line, col int) {
-    if offset < 0 {
-        offset = 0
-    }
-    if offset > r.Len() {
-        offset = r.Len()
-    }
-
-    line = r.Count(0, offset, []byte{'\n'})
-
-    lineStart := 0
-    for i := offset - 1; i >= 0; i-- {
-        if r.At(i) == '\n' {
-            lineStart = i + 1
-            break
-        }
-    }
-
-    col = offset - lineStart
-    return
+	if offset < 0 {
+		offset = 0
+	}
+	if offset > r.Len() {
+		offset = r.Len()
+	}
+
+	line = r.Count(0, offset, []byte{'\n'})
+
+	lineStart := 0
+	for i := offset - 1; i >= 0; i-- {
+		if r.At(i) == '\n' {
+			lineStart = i + 1
+			break
+		}
+	}
+
+	col = offset - lineStart
+	return
 }
 
 func OffsetForLine(r *rope.Node, targetLine int) int {
-    if targetLine <= 0 {
-        return 0
-    }
-
-    line := 0
-    for i := 0; i < r.Len(); i++ {
-        if r.At(i) == '\n' {
-            line++
-            if line == targetLine {
-                return i + 1
-            }
-        }
-    }
-
-    return r.Len()
+	if targetLine <= 0 {
+		return 0
+	}
+
+	line := 0
+	for i := 0; i < r.Len(); i++ {
+		if r.At(i) == '\n' {
+			line++
+			if line == targetLine {
+				return i + 1
+			}
+		}
+	}
+
+	return r.Len()
 }
 
 func (buf Buffer) String() string {

+ 7 - 7
internal/buffer/cursor.go

@@ -1,23 +1,23 @@
 package buffer
 
 import (
-	"slices"
 	"cmp"
+	"slices"
 )
 
 type Cursor struct {
-    Offset int
-	Goal int
+	Offset int
+	Goal   int
 }
 
 type CursorManager struct {
-	Cursors []Cursor
+	Cursors    []Cursor
 	PrimaryIdx int
 }
 
 func (cm *CursorManager) AddCursor(cur Cursor) {
-    cm.Cursors = append(cm.Cursors, cur)
-    cm.DeduplicateAndSort()
+	cm.Cursors = append(cm.Cursors, cur)
+	cm.DeduplicateAndSort()
 }
 
 func (cm *CursorManager) DeduplicateAndSort() {
@@ -41,4 +41,4 @@ func (cm *CursorManager) DeduplicateAndSort() {
 			break
 		}
 	}
-}
+}

+ 153 - 0
internal/editor/action.go

@@ -0,0 +1,153 @@
+package editor
+
+import (
+	"charm.land/bubbles/v2/key"
+	tea "charm.land/bubbletea/v2"
+)
+
+type Action = struct {
+	Binding  key.Binding
+	Command  string
+	HasArgs  bool
+	Callback func(Model, []string) tea.Cmd
+}
+
+//type Actionmap = struct {
+//	Left, Right, Up, Down, CursorUp, CursorDown, ClearCursors, Tab, Backtab, Newline, Delete, Quit Action
+//}
+
+func DefaultActions() []Action {
+	return []Action{
+		Action{
+			Binding: key.NewBinding(
+				key.WithKeys("left"),
+			),
+			Command: "TODO:",
+			HasArgs: false,
+			Callback: func(m Model, args []string) tea.Cmd {
+				m.Buffer.MoveHoriz(-1)	
+				return nil
+			},
+		},
+		Action{
+			Binding: key.NewBinding(
+				key.WithKeys("right"),
+			),
+			Command: "TODO:",
+			HasArgs: false,
+			Callback: func(m Model, args []string) tea.Cmd {
+				m.Buffer.MoveHoriz(1)
+				return nil
+			},
+		},
+		Action{
+			Binding: key.NewBinding(
+				key.WithKeys("up"),
+			),
+			Command: "TODO:",
+			HasArgs: false,
+			Callback: func(m Model, args []string) tea.Cmd {
+				m.Buffer.MoveVert(-1)
+				return nil
+			},
+		},
+		Action{
+			Binding: key.NewBinding(
+				key.WithKeys("down"),
+			),
+			Command: "TODO:",
+			HasArgs: false,
+			Callback: func(m Model, args []string) tea.Cmd {
+				m.Buffer.MoveVert(-1)
+				return nil
+			},
+		},
+		Action{
+			Binding: key.NewBinding(
+				key.WithKeys("shift+up"),
+			),
+			Command: "TODO:",
+			HasArgs: false,
+			Callback: func(m Model, args []string) tea.Cmd {
+				m.Buffer.AddCursorVert(-1)
+				return nil
+			},
+		},
+		Action{
+			Binding: key.NewBinding(
+				key.WithKeys("shift+down"),
+			),
+			Command: "TODO:",
+			HasArgs: false,
+			Callback: func(m Model, args []string) tea.Cmd {
+				m.Buffer.AddCursorVert(1)
+				return nil
+			},
+		},
+		Action{
+			Binding: key.NewBinding(
+				key.WithKeys("esc"),
+			),
+			Command: "TODO:",
+			HasArgs: false,
+			Callback: func(m Model, args []string) tea.Cmd {
+				m.Buffer.ClearCursors()
+				return nil
+			},
+		},
+		Action{
+			Binding: key.NewBinding(
+				key.WithKeys("tab"),
+			),
+			Command: "TODO:",
+			HasArgs: false,
+			Callback: func(m Model, args []string) tea.Cmd {
+				//TODO: implement m.Buffer.
+				return nil
+			},
+		},
+		Action{
+			Binding: key.NewBinding(
+				key.WithKeys("shift+tab"),
+			),
+			Command: "TODO:",
+			HasArgs: false,
+			Callback: func(m Model, args []string) tea.Cmd {
+				// TODO: implement m.Buffer.
+				return nil
+			},
+		},
+		Action{
+			Binding: key.NewBinding(
+				key.WithKeys("backspace"),
+			),
+			Command: "TODO:",
+			HasArgs: false,
+			Callback: func(m Model, args []string) tea.Cmd {
+				m.Buffer.Delete()
+				return nil
+			},
+		},
+		Action{
+			Binding: key.NewBinding(
+				key.WithKeys("enter"),
+			),
+			Command: "TODO:",
+			HasArgs: false,
+			Callback: func(m Model, args []string) tea.Cmd {
+				m.Buffer.Insert('\n')
+				return nil
+			},
+		},
+		Action{
+			Binding: key.NewBinding(
+				key.WithKeys("ctrl+c"),
+			),
+			Command: "q",
+			HasArgs: false,
+			Callback: func(m Model, args []string) tea.Cmd {
+				return tea.Quit
+			},
+		},
+	}
+}

+ 86 - 0
internal/editor/model.go

@@ -0,0 +1,86 @@
+package editor
+
+import (
+	"moose/internal/buffer"
+
+	"charm.land/bubbles/v2/viewport"
+	tea "charm.land/bubbletea/v2"
+)
+
+type Model struct {
+	Buffer        buffer.Buffer
+	CommandBuffer buffer.Buffer
+	Viewport      viewport.Model
+	Actions       []Action
+	Width         int
+	Height        int
+}
+
+func NewModel() Model {
+	initialBuf := buffer.Buffer{
+		Rope: nil,
+		CM: buffer.CursorManager{
+			Cursors:    []buffer.Cursor{{Offset: 0, Goal: 0}},
+			PrimaryIdx: 0,
+		},
+	}
+
+	vp := viewport.New()
+	vp.MouseWheelEnabled = false
+
+	model := Model{
+		Buffer:   initialBuf,
+		Viewport: vp,
+		Actions: DefaultActions(),
+	}
+
+	model.Viewport.SetContent(model.renderedContent())
+	return model
+}
+
+func (m Model) Init() tea.Cmd {
+	return nil
+}
+
+func (m Model) View() tea.View {
+	v := tea.NewView(m.Viewport.View())
+	v.AltScreen = true
+	v.MouseMode = tea.MouseModeCellMotion
+	return v
+}
+
+func (m Model) renderedContent() string {
+	content := []rune(m.Buffer.String())
+
+	cursorMap := make(map[int]bool)
+	for _, cur := range m.Buffer.CM.Cursors {
+		offset := cur.Offset
+		if offset < 0 {
+			offset = 0
+		}
+		if offset > len(content) {
+			offset = len(content)
+		}
+		cursorMap[offset] = true
+	}
+
+	out := make([]rune, 0, len(content)+len(cursorMap))
+
+	for i, r := range content {
+		if cursorMap[i] {
+			out = append(out, '█')
+
+			if r == '\n' {
+				out = append(out, r)
+			}
+		} else {
+			out = append(out, r)
+		}
+	}
+
+	if cursorMap[len(content)] {
+		out = append(out, '█')
+	}
+
+	return string(out)
+}

+ 56 - 0
internal/editor/update.go

@@ -0,0 +1,56 @@
+package editor
+
+import (
+	"charm.land/bubbles/v2/key"
+	tea "charm.land/bubbletea/v2"
+)
+
+func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+	switch msg := msg.(type) {
+	case tea.WindowSizeMsg:
+		m.Width = msg.Width
+		m.Height = msg.Height
+		m.Viewport.SetWidth(msg.Width)
+
+		h := msg.Height - 2
+		if h < 0 {
+			h = 0
+		}
+		m.Viewport.SetHeight(h)
+		return m, nil
+	case tea.MouseWheelMsg:
+		return m, nil
+	case tea.KeyPressMsg:
+		found := false
+
+		for i := range m.Actions {
+			action := m.Actions[i]
+
+			if key.Matches(msg, action.Binding) {
+				found = true
+				cmd := action.Callback(m, []string{})
+
+				if cmd != nil {
+					m.Viewport.SetContent(m.renderedContent())
+					return m, cmd
+				}
+
+				break
+			}
+		}
+
+		if !found {
+			key := msg.Key()
+			if key.Text != "" {
+				for _, r := range key.Text {
+					m.Buffer.Insert(r)
+				}
+			}
+		}
+
+		m.Viewport.SetContent(m.renderedContent())
+		return m, nil
+	}
+
+	return m, nil
+}

+ 0 - 127
internal/tui/model.go

@@ -1,127 +0,0 @@
-package tui
-
-import (
-	"moose/internal/buffer"
-
-	"charm.land/bubbles/v2/key"
-	"charm.land/bubbles/v2/viewport"
-	tea "charm.land/bubbletea/v2"
-)
-
-type Keymap = struct {
-	left, right, up, down, cursorUp, cursorDown, clearCursors, tab, backtab, newline, delete, quit key.Binding
-}
-
-type EditorModel struct {
-	Buffer buffer.Buffer
-	Viewport viewport.Model
-	Keymap Keymap
-	Width int
-	Height int
-}
-
-func NewEditorModel() EditorModel {
-	initialBuf := buffer.Buffer{
-		Rope: nil,
-		CM: buffer.CursorManager{
-			Cursors: []buffer.Cursor{{Offset: 0, Goal: 0}},
-			PrimaryIdx: 0,
-		},
-	}
-
-	vp := viewport.New()
-	vp.MouseWheelEnabled = false
-
-	model := EditorModel{
-		Buffer:   initialBuf,
-		Viewport: vp,
-		Keymap: Keymap{
-			left: key.NewBinding(
-				key.WithKeys("left"),
-			),
-			right: key.NewBinding(
-				key.WithKeys("right"),
-			),
-			up: key.NewBinding(
-				key.WithKeys("up"),
-			),
-			down: key.NewBinding(
-				key.WithKeys("down"),
-			),
-			cursorUp: key.NewBinding(
-				key.WithKeys("shift+up"),
-			),
-			cursorDown: key.NewBinding(
-				key.WithKeys("shift+down"),
-			),
-			clearCursors: key.NewBinding(
-				key.WithKeys("esc"),
-			),
-			tab: key.NewBinding(
-				key.WithKeys("tab"),
-			),
-			backtab: key.NewBinding(
-				key.WithKeys("shift+tab"),
-			),
-			delete: key.NewBinding(
-				key.WithKeys("backspace"),
-			),
-			newline: key.NewBinding(
-				key.WithKeys("enter"),
-			),
-			quit: key.NewBinding(
-				key.WithKeys("ctrl+c"),
-			),
-		},
-	}
-
-	model.Viewport.SetContent(model.renderedContent())
-	return model
-}
-
-func (m EditorModel) Init() tea.Cmd {
-	return nil
-}
-
-func (m EditorModel) View() tea.View {
-	v := tea.NewView(m.Viewport.View())
-	v.AltScreen = true
-	v.MouseMode = tea.MouseModeCellMotion
-	return v
-}
-
-func (m EditorModel) renderedContent() string {
-    content := []rune(m.Buffer.String())
-
-    cursorMap := make(map[int]bool)
-    for _, cur := range m.Buffer.CM.Cursors {
-        offset := cur.Offset
-        if offset < 0 {
-            offset = 0
-        }
-        if offset > len(content) {
-            offset = len(content)
-        }
-        cursorMap[offset] = true
-    }
-
-	out := make([]rune, 0, len(content)+len(cursorMap))
-
-    for i, r := range content {
-        if cursorMap[i] {
-            out = append(out, '█')
-            
-            if r == '\n' {
-                out = append(out, r)
-            }
-        } else {
-            out = append(out, r)
-        }
-    }
-
-    if cursorMap[len(content)] {
-        out = append(out, '█')
-    }
-
-    return string(out)
-}

+ 0 - 59
internal/tui/update.go

@@ -1,59 +0,0 @@
-package tui
-
-import (
-	"charm.land/bubbles/v2/key"
-	tea "charm.land/bubbletea/v2"
-)
-
-func (m EditorModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
-	switch msg := msg.(type) {
-	case tea.WindowSizeMsg:
-		m.Width = msg.Width
-		m.Height = msg.Height
-		m.Viewport.SetWidth(msg.Width)
-
-		h := msg.Height - 2
-		if h < 0 {
-			h = 0
-		}
-		m.Viewport.SetHeight(h)
-		return m, nil
-	case tea.MouseWheelMsg:
-		return m, nil
-	case tea.KeyPressMsg:
-		switch {
-		case key.Matches(msg, m.Keymap.quit):
-			return m, tea.Quit
-		case key.Matches(msg, m.Keymap.left):
-			m.Buffer.MoveHoriz(-1)
-		case key.Matches(msg, m.Keymap.right):
-			m.Buffer.MoveHoriz(1)
-		case key.Matches(msg, m.Keymap.down):
-			m.Buffer.MoveVert(1)
-		case key.Matches(msg, m.Keymap.up):
-			m.Buffer.MoveVert(-1)
-		case key.Matches(msg, m.Keymap.cursorUp):
-			m.Buffer.AddCursorVert(-1)
-		case key.Matches(msg, m.Keymap.cursorDown):
-			m.Buffer.AddCursorVert(1)
-		case key.Matches(msg, m.Keymap.clearCursors):
-			m.Buffer.ClearCursors()
-		case key.Matches(msg, m.Keymap.newline):
-			m.Buffer.Insert('\n')
-		case key.Matches(msg, m.Keymap.delete):
-			m.Buffer.Delete()
-		default:
-			key := msg.Key()
-			if key.Text != "" {
-				for _, r := range key.Text {
-					m.Buffer.Insert(r)
-				}
-			}
-		}
-
-		m.Viewport.SetContent(m.renderedContent())
-		return m, nil
-	}
-
-	return m, nil
-}

+ 11 - 10
main.go

@@ -1,19 +1,20 @@
 package main
 
 import (
-    "os"
-    "fmt"
+	"fmt"
+	"os"
 
-    "moose/internal/tui"
-    tea "charm.land/bubbletea/v2"
+	"moose/internal/editor"
+
+	tea "charm.land/bubbletea/v2"
 )
 
 func main() {
-    model := tui.NewEditorModel()
+	model := editor.NewModel()
 
-    p := tea.NewProgram(model)
-    if _, err := p.Run(); err != nil {
-        fmt.Printf("moose: error: %v", err)
-        os.Exit(1)
-    }
+	p := tea.NewProgram(model)
+	if _, err := p.Run(); err != nil {
+		fmt.Printf("moose: error: %v", err)
+		os.Exit(1)
+	}
 }