commit 5ca28cfb19e68eb0c5ef2dd8cd3c866aa585591a Author: Anish Lakhwara Date: Sat Aug 3 18:06:43 2024 -0700 init ;10u diff --git a/db/crsqlite.so b/db/crsqlite.so new file mode 100755 index 0000000..22c3157 Binary files /dev/null and b/db/crsqlite.so differ diff --git a/db/migrations.go b/db/migrations.go new file mode 100644 index 0000000..9fb5970 --- /dev/null +++ b/db/migrations.go @@ -0,0 +1,25 @@ +package main + +import ( + "database/sql" +) + +func RunMigrations(db *sql.DB) error { + // Load the cr-sqlite extension + _, err := db.Exec("SELECT load_extension('crsqlite.so')") + if err != nil { + return err + } + + // Create the todos table and initialize it as a CRDT + _, err = db.Exec(` + CREATE TABLE IF NOT EXISTS todos (id INTEGER PRIMARY KEY, content TEXT); + SELECT crsql_as_crr('todos'); + `) + if err != nil { + return err + } + + return nil +} + diff --git a/envrc b/envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/envrc @@ -0,0 +1 @@ +use flake diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..7035cfb --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1708407374, + "narHash": "sha256-EECzarm+uqnNDCwaGg/ppXCO11qibZ1iigORShkkDf0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "f33dd27a47ebdf11dc8a5eb05e7c8fbdaf89e73f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..f88de9f --- /dev/null +++ b/flake.nix @@ -0,0 +1,14 @@ +{ + description = "A basic flake with a shell"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + + outputs = { nixpkgs, ... }: + let + pkgs = nixpkgs.legacyPackages."x86_64-linux"; + in + { + devShells."x86_64-linux".default = pkgs.mkShell { + packages = [ pkgs.go ]; + }; + }; +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5218ef7 --- /dev/null +++ b/go.mod @@ -0,0 +1,22 @@ +module mast + +go 1.21.6 + +require ( + github.com/charmbracelet/bubbletea v0.26.6 // indirect + github.com/charmbracelet/x/ansi v0.1.2 // indirect + github.com/charmbracelet/x/input v0.1.0 // indirect + github.com/charmbracelet/x/term v0.1.1 // indirect + github.com/charmbracelet/x/windows v0.1.0 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // 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.7.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.3.8 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..5440193 --- /dev/null +++ b/go.sum @@ -0,0 +1,34 @@ +github.com/charmbracelet/bubbletea v0.26.6 h1:zTCWSuST+3yZYZnVSvbXwKOPRSNZceVeqpzOLN2zq1s= +github.com/charmbracelet/bubbletea v0.26.6/go.mod h1:dz8CWPlfCCGLFbBlTY4N7bjLiyOGDJEnd2Muu7pOWhk= +github.com/charmbracelet/x/ansi v0.1.2 h1:6+LR39uG8DE6zAmbu023YlqjJHkYXDF1z36ZwzO4xZY= +github.com/charmbracelet/x/ansi v0.1.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/input v0.1.0 h1:TEsGSfZYQyOtp+STIjyBq6tpRaorH0qpwZUj8DavAhQ= +github.com/charmbracelet/x/input v0.1.0/go.mod h1:ZZwaBxPF7IG8gWWzPUVqHEtWhc1+HXJPNuerJGRGZ28= +github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI= +github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw= +github.com/charmbracelet/x/windows v0.1.0 h1:gTaxdvzDM5oMa/I2ZNF7wN78X/atWemG9Wph7Ika2k4= +github.com/charmbracelet/x/windows v0.1.0/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +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.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +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/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= diff --git a/main.go b/main.go new file mode 100644 index 0000000..a245a7d --- /dev/null +++ b/main.go @@ -0,0 +1,98 @@ +package main + +import ( + "database/sql" + "fmt" + "os" + + tea "github.com/charmbracelet/bubbletea" + _ "github.com/mattn/go-sqlite3" + "git.sealight.xyz/aynish/mast/db" +) + +type model struct { + db *sql.DB + todos []string + cursor int +} + +func initialModel() model { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + + err = RunMigrations(db) + if err != nil { + panic(err) + } + + m := model{ + db: db, + todos: []string{}, + cursor: 0, + } + m.loadTodos() + return m +} + +func (m *model) addTodo(todo string) { + _, err := m.db.Exec("INSERT INTO todos (content) VALUES (?)", todo) + if err != nil { + panic(err) + } + m.loadTodos() +} + +func (m *model) loadTodos() { + rows, err := m.db.Query("SELECT content FROM todos") + if err != nil { + panic(err) + } + defer rows.Close() + + m.todos = []string{} + for rows.Next() { + var content string + if err := rows.Scan(&content); err != nil { + panic(err) + } + m.todos = append(m.todos, content) + } +} + +func (m model) Init() tea.Cmd { + return nil +} + +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "q": + return m, tea.Quit + } + } + return m, nil +} + +func (m model) View() string { + s := "Todo List:\n\n" + for i, todo := range m.todos { + cursor := " " + if m.cursor == i { + cursor = ">" + } + s += fmt.Sprintf("%s %s\n", cursor, todo) + } + s += "\nPress q to quit.\n" + return s +} + +func main() { + p := tea.NewProgram(initialModel()) + if _, err := p.Run(); err != nil { + fmt.Printf("Alas, there's been an error: %v", err) + os.Exit(1) + } +}