+17
-2
go.mod
+17
-2
go.mod
···
5
5
require (
6
6
ariga.io/atlas v0.38.0
7
7
github.com/adrg/xdg v0.5.3
8
+
github.com/charmbracelet/bubbles v0.21.0
8
9
github.com/charmbracelet/bubbletea v1.3.10
10
+
github.com/charmbracelet/glamour v0.10.0
9
11
github.com/pelletier/go-toml/v2 v2.2.4
10
12
github.com/tidwall/gjson v1.18.0
11
13
github.com/urfave/cli/v3 v3.6.1
···
15
17
16
18
require (
17
19
github.com/agext/levenshtein v1.2.1 // indirect
20
+
github.com/alecthomas/chroma/v2 v2.14.0 // indirect
18
21
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
19
22
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
20
23
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
24
+
github.com/aymerick/douceur v0.2.0 // indirect
21
25
github.com/bmatcuk/doublestar v1.3.4 // indirect
22
26
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
23
-
github.com/charmbracelet/lipgloss v1.1.0 // indirect
27
+
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 // indirect
24
28
github.com/charmbracelet/x/ansi v0.10.1 // indirect
25
-
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
29
+
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
30
+
github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf // indirect
26
31
github.com/charmbracelet/x/term v0.2.1 // indirect
32
+
github.com/dlclark/regexp2 v1.11.0 // indirect
27
33
github.com/dustin/go-humanize v1.0.1 // indirect
28
34
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
29
35
github.com/go-openapi/inflect v0.19.0 // indirect
30
36
github.com/google/go-cmp v0.7.0 // indirect
31
37
github.com/google/uuid v1.6.0 // indirect
38
+
github.com/gorilla/css v1.0.1 // indirect
32
39
github.com/hashicorp/hcl/v2 v2.13.0 // indirect
33
40
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
34
41
github.com/mattn/go-isatty v0.0.20 // indirect
35
42
github.com/mattn/go-localereader v0.0.1 // indirect
36
43
github.com/mattn/go-runewidth v0.0.16 // indirect
44
+
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
37
45
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
38
46
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
39
47
github.com/muesli/cancelreader v0.2.2 // indirect
48
+
github.com/muesli/reflow v0.3.0 // indirect
40
49
github.com/muesli/termenv v0.16.0 // indirect
41
50
github.com/ncruces/go-strftime v0.1.9 // indirect
42
51
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
43
52
github.com/rivo/uniseg v0.4.7 // indirect
53
+
github.com/sergi/go-diff v1.3.1 // indirect
44
54
github.com/tidwall/match v1.1.1 // indirect
45
55
github.com/tidwall/pretty v1.2.0 // indirect
46
56
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
57
+
github.com/yuin/goldmark v1.7.8 // indirect
58
+
github.com/yuin/goldmark-emoji v1.0.5 // indirect
47
59
github.com/zclconf/go-cty v1.14.4 // indirect
48
60
github.com/zclconf/go-cty-yaml v1.1.0 // indirect
49
61
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
62
+
golang.org/x/net v0.33.0 // indirect
50
63
golang.org/x/sys v0.36.0 // indirect
64
+
golang.org/x/term v0.31.0 // indirect
51
65
golang.org/x/text v0.28.0 // indirect
66
+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
52
67
gopkg.in/yaml.v3 v3.0.1 // indirect
53
68
modernc.org/libc v1.66.10 // indirect
54
69
modernc.org/mathutil v1.7.1 // indirect
+54
-7
go.sum
+54
-7
go.sum
···
6
6
github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
7
7
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
8
8
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
9
+
github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
10
+
github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
11
+
github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
12
+
github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
13
+
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
14
+
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
9
15
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
10
16
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
11
17
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
12
18
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
13
19
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
14
20
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
21
+
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
22
+
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
23
+
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
24
+
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
15
25
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
16
26
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
27
+
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
28
+
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
17
29
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
18
30
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
19
31
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
20
32
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
21
-
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
22
-
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
33
+
github.com/charmbracelet/glamour v0.10.0 h1:MtZvfwsYCx8jEPFJm3rIBFIMZUfUJ765oX8V6kXldcY=
34
+
github.com/charmbracelet/glamour v0.10.0/go.mod h1:f+uf+I/ChNmqo087elLnVdCiVgjSKWuXa/l6NU2ndYk=
35
+
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 h1:ZR7e0ro+SZZiIZD7msJyA+NjkCNNavuiPBLgerbOziE=
36
+
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834/go.mod h1:aKC/t2arECF6rNOnaKaVU6y4t4ZeHQzqfxedE/VkVhA=
23
37
github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ=
24
38
github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
25
-
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
26
-
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
39
+
github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k=
40
+
github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
41
+
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
42
+
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
43
+
github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf h1:rLG0Yb6MQSDKdB52aGX55JT1oi0P0Kuaj7wi1bLUpnI=
44
+
github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf/go.mod h1:B3UgsnsBZS/eX42BlaNiJkD1pPOUa+oF1IYC6Yd2CEU=
27
45
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
28
46
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
47
+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
29
48
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
30
49
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
50
+
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
51
+
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
31
52
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
32
53
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
33
54
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
···
42
63
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
43
64
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
44
65
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
66
+
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
67
+
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
45
68
github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc=
46
69
github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
70
+
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
71
+
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
47
72
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
48
73
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
74
+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
75
+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
49
76
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
50
77
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
51
78
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
···
56
83
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
57
84
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
58
85
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
86
+
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
59
87
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
60
88
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
89
+
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
90
+
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
61
91
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
62
92
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
63
93
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
64
94
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
65
95
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
66
96
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
97
+
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
98
+
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
67
99
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
68
100
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
69
101
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
···
74
106
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
75
107
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
76
108
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
109
+
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
77
110
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
78
111
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
79
112
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
80
-
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
81
-
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
113
+
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
114
+
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
115
+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
116
+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
82
117
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
83
118
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
84
119
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
···
91
126
github.com/urfave/cli/v3 v3.6.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
92
127
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
93
128
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
129
+
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
130
+
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
131
+
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
132
+
github.com/yuin/goldmark-emoji v1.0.5 h1:EMVWyCGPlXJfUXBXpuMu+ii3TIaxbVBnEX9uaDC4cIk=
133
+
github.com/yuin/goldmark-emoji v1.0.5/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
94
134
github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
95
135
github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
96
136
github.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0=
···
99
139
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
100
140
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
101
141
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
142
+
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
143
+
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
102
144
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
103
145
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
104
146
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
105
147
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
106
148
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
107
149
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
150
+
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
151
+
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
108
152
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
109
153
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
110
154
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
111
155
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
112
-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
113
156
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
157
+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
158
+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
159
+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
160
+
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
114
161
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
115
162
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
116
163
modernc.org/cc/v4 v4.26.5 h1:xM3bX7Mve6G8K8b+T11ReenJOT+BmVqQj0FY5T4+5Y4=
+45
internal/store/sqlite_articles.go
+45
internal/store/sqlite_articles.go
···
56
56
return err
57
57
}
58
58
59
+
type Article struct {
60
+
ID string
61
+
Title string
62
+
Href string
63
+
Content string
64
+
Author string
65
+
IsRead bool
66
+
IsStarred bool
67
+
FeedID string
68
+
FeedTitle string
69
+
PublishedAt int64
70
+
}
71
+
72
+
func (s *Sqlite) GetArticles(ctx context.Context) ([]Article, error) {
73
+
query := `--sql
74
+
select a.id, a.title, a.href, a.content, a.author, s.is_read, s.is_starred, a.feed_id, f.title feed_name, a.published_at
75
+
from articles a
76
+
join article_statuses s on a.id = s.article_id
77
+
join feeds f on f.id = a.feed_id
78
+
where s.is_read = false
79
+
order by a.published_at desc`
80
+
81
+
rows, err := s.db.QueryContext(ctx, query)
82
+
if err != nil {
83
+
return nil, err
84
+
}
85
+
defer rows.Close()
86
+
87
+
var res []Article
88
+
for rows.Next() {
89
+
var a Article
90
+
if serr := rows.Scan(&a.ID, &a.Title, &a.Href, &a.Content, &a.Author, &a.IsRead, &a.IsStarred, &a.FeedID, &a.FeedTitle, &a.PublishedAt); serr != nil {
91
+
return res, serr
92
+
}
93
+
94
+
res = append(res, a)
95
+
}
96
+
97
+
if err = rows.Err(); err != nil {
98
+
return res, err
99
+
}
100
+
101
+
return res, nil
102
+
}
103
+
59
104
func buildPlaceholdersAndArgs(in []string, prefixArgs ...any) (placeholders string, args []any) {
60
105
placeholders = strings.Repeat("?,", len(in))
61
106
placeholders = placeholders[:len(placeholders)-1] // trim trailing comma
+18
internal/tui/fetcher.go
+18
internal/tui/fetcher.go
···
1
+
package tui
2
+
3
+
import (
4
+
tea "github.com/charmbracelet/bubbletea"
5
+
"olexsmir.xyz/smutok/internal/store"
6
+
)
7
+
8
+
type fetchedArticles []store.Article
9
+
10
+
func (m *Model) fetchArticles() tea.Cmd {
11
+
return func() tea.Msg {
12
+
articles, err := m.store.GetArticles(m.ctx)
13
+
if err != nil {
14
+
return sendErr(err)
15
+
}
16
+
return fetchedArticles(articles)
17
+
}
18
+
}
+1
internal/tui/styles.go
+1
internal/tui/styles.go
···
1
+
package tui
+83
-6
internal/tui/tui.go
+83
-6
internal/tui/tui.go
···
2
2
3
3
import (
4
4
"context"
5
+
"log/slog"
5
6
7
+
"github.com/charmbracelet/bubbles/table"
8
+
"github.com/charmbracelet/bubbles/viewport"
6
9
tea "github.com/charmbracelet/bubbletea"
10
+
"github.com/charmbracelet/glamour"
7
11
"olexsmir.xyz/smutok/internal/store"
8
12
)
9
13
10
14
type Syncer interface {
11
15
Sync(ctx context.Context) error
12
16
}
17
+
18
+
type AppState int
19
+
20
+
const (
21
+
ArticlesView AppState = iota
22
+
FeedsView
23
+
ReadingView
24
+
)
13
25
14
26
type Model struct {
15
27
ctx context.Context
16
28
29
+
state AppState
17
30
isQutting bool
18
31
showErr bool
19
32
err error
20
33
21
34
syncer Syncer
22
35
store *store.Sqlite
36
+
37
+
articles []store.Article
38
+
39
+
glamur *glamour.TermRenderer
40
+
table table.Model // feeds, articles feed
41
+
viewport viewport.Model // article content reader
23
42
}
24
43
25
44
func NewModel(
···
27
46
syncer Syncer,
28
47
store *store.Sqlite,
29
48
) *Model {
49
+
tbl := table.New(table.WithFocused(true))
50
+
vp := viewport.New(0, 0)
51
+
30
52
return &Model{
31
-
ctx: ctx,
32
-
syncer: syncer,
33
-
store: store,
53
+
ctx: ctx,
54
+
syncer: syncer,
55
+
store: store,
56
+
glamur: &glamour.TermRenderer{},
57
+
table: tbl,
58
+
viewport: vp,
59
+
state: ArticlesView,
60
+
isQutting: false,
61
+
showErr: false,
62
+
err: nil,
63
+
articles: nil,
34
64
}
35
65
}
36
66
37
67
func (m *Model) Init() tea.Cmd {
38
-
return nil
68
+
return tea.Batch(
69
+
tea.SetWindowTitle("smutok"),
70
+
m.fetchArticles(),
71
+
)
39
72
}
40
73
41
74
func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
75
+
var cmd tea.Cmd
42
76
switch msg := msg.(type) {
43
77
case errMsg:
44
78
m.err = msg
···
46
80
return m, nil
47
81
48
82
case tea.WindowSizeMsg:
83
+
m.table.SetHeight(msg.Height)
84
+
m.table.SetWidth(msg.Width)
85
+
m.viewport.Height = msg.Height
86
+
m.viewport.Width = msg.Width
87
+
return m, nil
88
+
89
+
case fetchedArticles:
90
+
m.articles = msg
91
+
92
+
columns := []table.Column{
93
+
// {Title: "read", Width: 4},
94
+
// {Title: "stared", Width: 6},
95
+
{Title: "author", Width: 14},
96
+
{Title: "title", Width: m.table.Width() - 14},
97
+
}
98
+
99
+
rows := make([]table.Row, len(msg))
100
+
for i, article := range msg {
101
+
rows[i] = table.Row{article.Author, article.Title}
102
+
}
103
+
104
+
m.table.SetColumns(columns)
105
+
m.table.SetRows(rows)
106
+
107
+
slog.Debug("got articles")
108
+
return m, nil
49
109
50
110
case tea.KeyMsg:
111
+
// page specific keys
112
+
switch m.state {
113
+
case ArticlesView, FeedsView:
114
+
m.table, cmd = m.table.Update(msg)
115
+
case ReadingView:
116
+
m.viewport, cmd = m.viewport.Update(msg)
117
+
}
118
+
119
+
// global keys
51
120
switch msg.String() {
52
121
case "q":
53
122
m.isQutting = true
54
123
return m, tea.Quit
55
124
}
56
125
}
57
-
return m, nil
126
+
return m, cmd
58
127
}
59
128
60
129
func (m *Model) View() string {
61
130
if m.isQutting {
62
131
return ""
63
132
}
64
-
return "are you feeling smutok?"
133
+
134
+
var out string
135
+
switch m.state {
136
+
case ArticlesView, FeedsView:
137
+
out = m.table.View()
138
+
case ReadingView:
139
+
out = m.viewport.View()
140
+
}
141
+
return out
65
142
}