Johan Rong преди 1 месец
родител
ревизия
eea72c3d75
променени са 8 файла, в които са добавени 179 реда и са изтрити 2 реда
  1. 3 0
      Makefile
  2. 21 0
      go.mod
  3. 40 0
      go.sum
  4. 10 0
      internal/buffer/buffer.go
  5. 25 0
      internal/buffer/cursor.go
  6. 40 0
      internal/tui/model.go
  7. 26 0
      internal/tui/update.go
  8. 14 2
      main.go

+ 3 - 0
Makefile

@@ -1,3 +1,6 @@
 build:
 	@mkdir -p build
 	go build -o build/moose .
+
+run:
+	go run .

+ 21 - 0
go.mod

@@ -1,3 +1,24 @@
 module moose
 
 go 1.26.4
+
+require charm.land/bubbletea/v2 v2.0.8
+
+require (
+	github.com/charmbracelet/colorprofile v0.4.3 // indirect
+	github.com/charmbracelet/ultraviolet v0.0.0-20260703014108-f5a850f9c2b7 // indirect
+	github.com/charmbracelet/x/ansi v0.11.7 // indirect
+	github.com/charmbracelet/x/term v0.2.2 // indirect
+	github.com/charmbracelet/x/termios v0.1.1 // indirect
+	github.com/charmbracelet/x/windows v0.2.2 // indirect
+	github.com/clipperhouse/displaywidth v0.11.0 // indirect
+	github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
+	github.com/gboncoffee/gopiecetable v1.0.0 // indirect
+	github.com/lucasb-eyer/go-colorful v1.4.0 // indirect
+	github.com/mattn/go-runewidth v0.0.23 // indirect
+	github.com/muesli/cancelreader v0.2.2 // indirect
+	github.com/rivo/uniseg v0.4.7 // indirect
+	github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
+	golang.org/x/sync v0.21.0 // indirect
+	golang.org/x/sys v0.46.0 // indirect
+)

+ 40 - 0
go.sum

@@ -0,0 +1,40 @@
+charm.land/bubbletea/v2 v2.0.8 h1:SxTJMhCAI3lbPmy4SgX5LWZ24AdINr4I6UEqzZvYJuY=
+charm.land/bubbletea/v2 v2.0.8/go.mod h1:2SkdgoTXluXJHOUwAoRlRXF/28vklb1rFl6GcgV1/ss=
+github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
+github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
+github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q=
+github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q=
+github.com/charmbracelet/ultraviolet v0.0.0-20260703014108-f5a850f9c2b7 h1:3FmWoGNWK4STvqg0O0Aeav2T7rodWJAPeF0QpH+8gFw=
+github.com/charmbracelet/ultraviolet v0.0.0-20260703014108-f5a850f9c2b7/go.mod h1:f/jRa757WUmaOZrbPspXymbg/GnbF+rwe4OLsG7aXYo=
+github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI=
+github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ=
+github.com/charmbracelet/x/exp/golden v0.0.0-20241212170349-ad4b7ae0f25f h1:UytXHv0UxnsDFmL/7Z9Q5SBYPwSuRLXHbwx+6LycZ2w=
+github.com/charmbracelet/x/exp/golden v0.0.0-20241212170349-ad4b7ae0f25f/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
+github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
+github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
+github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=
+github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=
+github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM=
+github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k=
+github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
+github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
+github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
+github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
+github.com/gboncoffee/gopiecetable v1.0.0 h1:24bQsimO5Cs3fTbgk7Bjn/dzgXXGKFzZi7cmJHBQZDU=
+github.com/gboncoffee/gopiecetable v1.0.0/go.mod h1:qsEeMiN4MVggYC0IF+I/addQ66+0oiFnAuwk21ibBlY=
+github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4=
+github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw=
+github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
+github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
+golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
+golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
+golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=

+ 10 - 0
internal/buffer/buffer.go

@@ -0,0 +1,10 @@
+package buffer
+
+import (
+    "github.com/gboncoffee/gopiecetable"
+)
+
+type Document struct {
+	Table *gopiecetable.PieceTable[rune]
+	CM CursorManager
+}

+ 25 - 0
internal/buffer/cursor.go

@@ -0,0 +1,25 @@
+package buffer
+
+import (
+	"os"
+	"fmt"
+)
+
+type Cursor struct {
+    Offset int
+}
+
+type CursorManager struct {
+	Cursors []Cursor
+	PrimaryIdx int
+}
+
+func (cm *CursorManager) AddCursor(cur Cursor) {
+    cm.Cursors = append(cm.Cursors, cur)
+    cm.DeduplicateAndSort()
+}
+
+func (cm *CursorManager) DeduplicateAndSort() {
+    fmt.Printf("moose: todo: implement DeduplicateAndSort()")
+	os.Exit(1)
+}

+ 40 - 0
internal/tui/model.go

@@ -0,0 +1,40 @@
+package tui
+
+import (
+    "moose/internal/buffer"
+
+	"github.com/gboncoffee/gopiecetable"
+	tea "charm.land/bubbletea/v2"
+)
+
+type EditorModel struct {
+    Document buffer.Document
+    Viewport viewport.Model
+    Width int
+    Height int
+}
+
+func NewEditorModel() EditorModel {
+	initialDoc := buffer.Document{
+		Table: gopiecetable.FromString("Welcome to your modular multi-cursor editor.\nPress Ctrl+A to spawn cursors.\nType freely to modify text blocks."),
+		CM: buffer.CursorManager{
+			Cursors: []buffer.Cursor{{Offset: 0}},
+			PrimaryIdx: 0,
+		},
+	}
+
+	vp := viewport.New(0, 0)
+
+	return EditorModel{
+		Document: initialDoc,
+		Viewport: vp,
+	}
+}
+
+func (m EditorModel) Init() tea.Cmd {
+    return nil
+}
+
+func (m EditorModel) View() tea.View {
+    return tea.NewView(gopiecetable.String(m.Document.Table))
+}

+ 26 - 0
internal/tui/update.go

@@ -0,0 +1,26 @@
+package tui
+
+import (
+    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.Width = msg.Width
+        m.Viewport.Height = msg.Height - 2 // Space for footer status bar
+        return m, nil
+
+    case tea.KeyMsg:
+        switch msg.String() {
+        case "ctrl+c":
+            return m, tea.Quit
+        default:
+            m.Document.Table.Insert(msg.String(), m.Document.Table.Size())
+            m.Viewport.SetContent(m.RenderBufferToString())
+        }
+    }
+    return m, nil
+}

+ 14 - 2
main.go

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