Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f347d8342 |
@@ -32,6 +32,7 @@ import (
|
|||||||
"github.com/bluesky-social/indigo/atproto/syntax"
|
"github.com/bluesky-social/indigo/atproto/syntax"
|
||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
"golang.design/x/clipboard"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ScreenHome struct {
|
type ScreenHome struct {
|
||||||
@@ -107,12 +108,24 @@ func (s *ScreenHome) Init(a *App) {
|
|||||||
s.pdsListing.SetVimMode(viper.GetBool(data.KeyVimMode))
|
s.pdsListing.SetVimMode(viper.GetBool(data.KeyVimMode))
|
||||||
|
|
||||||
s.jsonContent = wd.NewJsonContent("jsoncontent", s.style)
|
s.jsonContent = wd.NewJsonContent("jsoncontent", s.style)
|
||||||
brd := w.NewBorderedWidget("jsoncontentbrd", s.style, s.jsonContent)
|
km := s.jsonContent.GetKeyMap()
|
||||||
brd.SetBorder(
|
km.Add(
|
||||||
|
w.NewKey(w.BuildEK(tcell.KeyEnter), func(ev *tcell.EventKey) bool {
|
||||||
|
// Init returns an error if the package is not ready for use.
|
||||||
|
err := clipboard.Init()
|
||||||
|
if err != nil {
|
||||||
|
s.Log("Error initializing clipboard: %s", err.Error())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
clipboard.Write(clipboard.FmtText, []byte(s.jsonContent.GetSelectedValue()))
|
||||||
|
return true
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
s.jsonContent.SetKeyMap(km)
|
||||||
|
s.jsonContent.SetBorder(
|
||||||
[]rune{'─', '┐', '│', '┘', '─', '─', ' ', '─', '├', '─', '┤', '┬', '│', '┴', '┼'},
|
[]rune{'─', '┐', '│', '┘', '─', '─', ' ', '─', '├', '─', '┤', '┬', '│', '┴', '┼'},
|
||||||
)
|
)
|
||||||
|
s.columns.AddAll(s.pdsListing, s.jsonContent)
|
||||||
s.columns.AddAll(s.pdsListing, brd)
|
|
||||||
|
|
||||||
s.layout.AddAll(s.columns)
|
s.layout.AddAll(s.columns)
|
||||||
s.layout.SetWeight(s.columns, 4)
|
s.layout.SetWeight(s.columns, 4)
|
||||||
@@ -131,6 +144,10 @@ func (s *ScreenHome) HandleKey(ev *tcell.EventKey) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if s.doOpen {
|
if s.doOpen {
|
||||||
|
if ev.Key() == tcell.KeyEscape {
|
||||||
|
s.doOpen = false
|
||||||
|
return true
|
||||||
|
}
|
||||||
if ev.Key() == tcell.KeyCtrlU {
|
if ev.Key() == tcell.KeyCtrlU {
|
||||||
s.openPdsEntry.SetValue("")
|
s.openPdsEntry.SetValue("")
|
||||||
return true
|
return true
|
||||||
@@ -328,8 +345,7 @@ func (s *ScreenHome) selectPdsListingEntry(idx int, nm string) bool {
|
|||||||
return true
|
return true
|
||||||
|
|
||||||
case models.TypeRecord:
|
case models.TypeRecord:
|
||||||
// If signed in and we can edit this, activate jsonContent in 'editable' mode
|
// If signed in and we can edit this, activate jsonContent
|
||||||
s.jsonContent.SetEditable(true)
|
|
||||||
s.columns.ActivateWidget(s.jsonContent)
|
s.columns.ActivateWidget(s.jsonContent)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -10,6 +10,7 @@ require (
|
|||||||
github.com/muesli/go-app-paths v0.2.2
|
github.com/muesli/go-app-paths v0.2.2
|
||||||
github.com/spf13/cobra v1.10.2
|
github.com/spf13/cobra v1.10.2
|
||||||
github.com/spf13/viper v1.21.0
|
github.com/spf13/viper v1.21.0
|
||||||
|
golang.design/x/clipboard v0.7.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -90,6 +91,9 @@ require (
|
|||||||
go.uber.org/zap v1.26.0 // indirect
|
go.uber.org/zap v1.26.0 // indirect
|
||||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
golang.org/x/crypto v0.21.0 // indirect
|
golang.org/x/crypto v0.21.0 // indirect
|
||||||
|
golang.org/x/exp/shiny v0.0.0-20250606033433-dcc06ee1d476 // indirect
|
||||||
|
golang.org/x/image v0.28.0 // indirect
|
||||||
|
golang.org/x/mobile v0.0.0-20250606033058-a2a15c67f36f // indirect
|
||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/text v0.33.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
|
|||||||
9
go.sum
9
go.sum
@@ -226,6 +226,8 @@ go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
|||||||
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
|
golang.design/x/clipboard v0.7.1 h1:OEG3CmcYRBNnRwpDp7+uWLiZi3hrMRJpE9JkkkYtz2c=
|
||||||
|
golang.design/x/clipboard v0.7.1/go.mod h1:i5SiIqj0wLFw9P/1D7vfILFK0KHMk7ydE72HRrUIgkg=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
@@ -233,7 +235,14 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
|
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
|
||||||
|
golang.org/x/exp/shiny v0.0.0-20250606033433-dcc06ee1d476 h1:Wdx0vgH5Wgsw+lF//LJKmWOJBLWX6nprsMqnf99rYDE=
|
||||||
|
golang.org/x/exp/shiny v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:ygj7T6vSGhhm/9yTpOQQNvuAUFziTH7RUiH74EoE2C8=
|
||||||
|
golang.org/x/image v0.28.0 h1:gdem5JW1OLS4FbkWgLO+7ZeFzYtL3xClb97GaUzYMFE=
|
||||||
|
golang.org/x/image v0.28.0/go.mod h1:GUJYXtnGKEUgggyzh+Vxt+AviiCcyiwpsl8iQ8MvwGY=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mobile v0.0.0-20250606033058-a2a15c67f36f h1:/n+PL2HlfqeSiDCuhdBbRNlGS/g2fM4OHufalHaTVG8=
|
||||||
|
golang.org/x/mobile v0.0.0-20250606033058-a2a15c67f36f/go.mod h1:ESkJ836Z6LpG6mTVAhA48LpfW/8fNR0ifStlH2axyfg=
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import (
|
|||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Format contents as json. For now this is a duplice of the Text widget
|
|
||||||
type JsonContent struct {
|
type JsonContent struct {
|
||||||
id string
|
id string
|
||||||
|
|
||||||
@@ -40,6 +39,8 @@ type JsonContent struct {
|
|||||||
style tcell.Style
|
style tcell.Style
|
||||||
x, y int
|
x, y int
|
||||||
w, h int
|
w, h int
|
||||||
|
|
||||||
|
border []rune
|
||||||
visible bool
|
visible bool
|
||||||
active bool
|
active bool
|
||||||
focusable bool
|
focusable bool
|
||||||
@@ -49,6 +50,9 @@ type JsonContent struct {
|
|||||||
value any
|
value any
|
||||||
|
|
||||||
activeNode []string
|
activeNode []string
|
||||||
|
|
||||||
|
vimMode bool
|
||||||
|
cursor int
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ wd.Widget = (*JsonContent)(nil)
|
var _ wd.Widget = (*JsonContent)(nil)
|
||||||
@@ -64,7 +68,45 @@ func (w *JsonContent) Init(id string, style tcell.Style) {
|
|||||||
w.style = style
|
w.style = style
|
||||||
w.visible = true
|
w.visible = true
|
||||||
w.focusable = false
|
w.focusable = false
|
||||||
w.keyMap = wd.BlankKeyMap()
|
w.keyMap = wd.NewKeyMap(
|
||||||
|
wd.NewKey(wd.BuildEK(tcell.KeyUp), func(_ *tcell.EventKey) bool { return w.MoveUp() }),
|
||||||
|
wd.NewKey(wd.BuildEK(tcell.KeyDown), func(_ *tcell.EventKey) bool { return w.MoveDown() }),
|
||||||
|
wd.NewKey(wd.BuildEK(tcell.KeyEnter), func(ev *tcell.EventKey) bool {
|
||||||
|
return false
|
||||||
|
}),
|
||||||
|
wd.NewKey(wd.BuildEK(tcell.KeyPgDn), func(_ *tcell.EventKey) bool { return w.PageDn() }),
|
||||||
|
wd.NewKey(wd.BuildEK(tcell.KeyPgUp), func(_ *tcell.EventKey) bool { return w.PageUp() }),
|
||||||
|
wd.NewKey(wd.BuildEKr('j'), func(ev *tcell.EventKey) bool {
|
||||||
|
if !w.vimMode {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return w.MoveDown()
|
||||||
|
}),
|
||||||
|
wd.NewKey(wd.BuildEKr('k'), func(ev *tcell.EventKey) bool {
|
||||||
|
if !w.vimMode {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return w.MoveUp()
|
||||||
|
}),
|
||||||
|
wd.NewKey(wd.BuildEKr('b'), func(ev *tcell.EventKey) bool {
|
||||||
|
if !w.vimMode {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if ev.Modifiers()&tcell.ModCtrl != 0 {
|
||||||
|
return w.PageUp()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}),
|
||||||
|
wd.NewKey(wd.BuildEKr('f'), func(ev *tcell.EventKey) bool {
|
||||||
|
if !w.vimMode {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if ev.Modifiers()&tcell.ModCtrl != 0 {
|
||||||
|
return w.PageDn()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *JsonContent) Id() string { return w.id }
|
func (w *JsonContent) Id() string { return w.id }
|
||||||
@@ -73,15 +115,61 @@ func (w *JsonContent) HandleResize(ev *tcell.EventResize) { w.w, w.h = ev.Size()
|
|||||||
func (w *JsonContent) GetKeyMap() *wd.KeyMap { return w.keyMap }
|
func (w *JsonContent) GetKeyMap() *wd.KeyMap { return w.keyMap }
|
||||||
func (w *JsonContent) SetKeyMap(km *wd.KeyMap) { w.keyMap = km }
|
func (w *JsonContent) SetKeyMap(km *wd.KeyMap) { w.keyMap = km }
|
||||||
|
|
||||||
func (w *JsonContent) HandleKey(ev *tcell.EventKey) bool { return w.keyMap.Handle(ev) }
|
func (w *JsonContent) HandleKey(ev *tcell.EventKey) bool {
|
||||||
|
return w.keyMap.Handle(ev)
|
||||||
|
}
|
||||||
func (w *JsonContent) HandleTime(ev *tcell.EventTime) {}
|
func (w *JsonContent) HandleTime(ev *tcell.EventTime) {}
|
||||||
func (w *JsonContent) Draw(screen tcell.Screen) {
|
func (w *JsonContent) Draw(screen tcell.Screen) {
|
||||||
if !w.visible {
|
if !w.visible {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
y := w.y
|
x, y := w.x, w.y
|
||||||
for i := range w.contents {
|
brdSz := 0
|
||||||
wh.DrawText(w.x, y, w.contents[i], w.style, screen)
|
if len(w.border) > 0 {
|
||||||
|
brdSz = 2
|
||||||
|
wh.BorderFilled(x, y, x+w.w, y+w.h, w.border, w.style, screen)
|
||||||
|
}
|
||||||
|
x, y = x+1, y+1
|
||||||
|
h := w.h - brdSz
|
||||||
|
ln := len(w.contents)
|
||||||
|
st, ed := 0, ln-1
|
||||||
|
if ln == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ln > w.h-2 {
|
||||||
|
mid := h / 2
|
||||||
|
if w.cursor < mid {
|
||||||
|
// contents need to start at 0
|
||||||
|
ed = h + 1
|
||||||
|
} else if w.cursor > ln-mid {
|
||||||
|
// contents need to begin at ln-h
|
||||||
|
st = ln - h + 1
|
||||||
|
} else {
|
||||||
|
st = w.cursor - mid
|
||||||
|
ed = st + h + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ed cannot be higher than ln-1
|
||||||
|
if st < 0 {
|
||||||
|
st = 0
|
||||||
|
}
|
||||||
|
if ed > ln-1 {
|
||||||
|
ed = ln - 1
|
||||||
|
}
|
||||||
|
for i := st; i <= ed; i++ {
|
||||||
|
st := w.style
|
||||||
|
dim := true
|
||||||
|
if i == w.cursor {
|
||||||
|
dim = false
|
||||||
|
} else {
|
||||||
|
st = st.Foreground(tcell.ColorGreen)
|
||||||
|
}
|
||||||
|
txt := w.contents[i]
|
||||||
|
if len(txt) > w.w-brdSz && w.w-brdSz >= 0 {
|
||||||
|
txt = txt[:(w.w - brdSz)]
|
||||||
|
}
|
||||||
|
|
||||||
|
wh.DrawText(w.x, y, txt, st.Dim(dim).Bold(!dim), screen)
|
||||||
y++
|
y++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,6 +208,13 @@ func (w *JsonContent) SetValue(v any) error {
|
|||||||
w.contents = strings.Split(w.valueString, "\n")
|
w.contents = strings.Split(w.valueString, "\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
func (w *JsonContent) SetBorder(brd []rune) {
|
||||||
|
if len(brd) == 0 {
|
||||||
|
w.border = wh.BRD_SIMPLE
|
||||||
|
} else {
|
||||||
|
w.border = wh.ValidateBorder(brd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (w *JsonContent) SetEditable(v bool) { w.editable = v }
|
func (w *JsonContent) SetEditable(v bool) { w.editable = v }
|
||||||
|
|
||||||
@@ -136,3 +231,44 @@ func (w *JsonContent) SetEditable(v bool) { w.editable = v }
|
|||||||
func (w *JsonContent) GetJsonContent() string { return w.text }
|
func (w *JsonContent) GetJsonContent() string { return w.text }
|
||||||
func (w *JsonContent) GetContents() []string { return w.contents }
|
func (w *JsonContent) GetContents() []string { return w.contents }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
func (w *JsonContent) SetVimMode(b bool) { w.vimMode = b }
|
||||||
|
func (w *JsonContent) MoveUp() bool {
|
||||||
|
w.cursor--
|
||||||
|
if w.cursor < 0 {
|
||||||
|
w.cursor = 0
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
func (w *JsonContent) MoveDown() bool {
|
||||||
|
w.cursor++
|
||||||
|
if w.cursor >= len(w.contents) {
|
||||||
|
w.cursor = len(w.contents) - 1
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
func (w *JsonContent) PageUp() bool {
|
||||||
|
w.cursor -= w.h
|
||||||
|
if w.cursor < 0 {
|
||||||
|
w.cursor = 0
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
func (w *JsonContent) PageDn() bool {
|
||||||
|
w.cursor += w.h
|
||||||
|
if w.cursor > len(w.contents)-1 {
|
||||||
|
w.cursor = len(w.contents) - 1
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *JsonContent) GetSelectedValue() string {
|
||||||
|
if w.cursor >= len(w.contents) {
|
||||||
|
w.cursor = len(w.contents) - 1
|
||||||
|
}
|
||||||
|
var ret string
|
||||||
|
ret = w.contents[w.cursor]
|
||||||
|
ret = ret[strings.Index(ret, "\": \"")+3:]
|
||||||
|
ret = ret[1 : len(ret)-1]
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user