Working on Editing

This commit is contained in:
2026-02-18 21:43:50 -06:00
parent 4066197ec1
commit 94fab7acee
2 changed files with 128 additions and 65 deletions

View File

@@ -261,6 +261,7 @@ func (s *ScreenHome) initMenu() {
s.menuLayout.AddMenuItems( s.menuLayout.AddMenuItems(
s.menuLayout.CreateMenuItem("file", "File", nil, 'f', s.menuLayout.CreateMenuItem("file", "File", nil, 'f',
s.menuLayout.CreateMenuItem("file.openpds", "Open PDS", s.menuOpenPds, 'o'), s.menuLayout.CreateMenuItem("file.openpds", "Open PDS", s.menuOpenPds, 'o'),
s.menuLayout.CreateMenuItem("file.authpds", "Authenticate PDS", s.menuAuthPds, 'a'),
s.menuLayout.CreateMenuItem("file.reloadpds", "Reload PDS", s.menuRefreshPds, 'r'), s.menuLayout.CreateMenuItem("file.reloadpds", "Reload PDS", s.menuRefreshPds, 'r'),
s.menuLayout.CreateMenuItem("file.exit", "Exit", s.menuExit, 'x'), s.menuLayout.CreateMenuItem("file.exit", "Exit", s.menuExit, 'x'),
), ),
@@ -292,11 +293,16 @@ func (s *ScreenHome) update() {
} }
recNmInf.SetLabel(fmt.Sprintf("%s Infer Record Names", wrk)) recNmInf.SetLabel(fmt.Sprintf("%s Infer Record Names", wrk))
miAuth := s.menuLayout.FindItem("file.authpds")
miReload := s.menuLayout.FindItem("file.reloadpds") miReload := s.menuLayout.FindItem("file.reloadpds")
if s.activePds == nil { if s.activePds == nil {
miAuth.SetDisabled(true)
miAuth.SetStyle(s.style.Foreground(tcell.ColorGray))
miReload.SetDisabled(true) miReload.SetDisabled(true)
miReload.SetStyle(s.style.Foreground(tcell.ColorGray)) miReload.SetStyle(s.style.Foreground(tcell.ColorGray))
} else { } else {
miAuth.SetDisabled(true)
miAuth.SetStyle(s.style.Foreground(tcell.ColorGray))
miReload.SetDisabled(false) miReload.SetDisabled(false)
miReload.SetStyle(s.style.Foreground(tcell.ColorLime)) miReload.SetStyle(s.style.Foreground(tcell.ColorLime))
} }
@@ -344,43 +350,7 @@ func (s *ScreenHome) cliGetPds(args ...string) bool {
return true return true
} }
func (s *ScreenHome) cliAuthPds(args ...string) bool { func (s *ScreenHome) cliAuthPds(args ...string) bool { return s.menuAuthPds() }
if s.activePds == nil {
s.Log("No active PDS.")
return true
}
s.isLoading = true
go func() {
defer func() { s.isLoading = false }()
// Check if we already have authentication.
if !s.r.Auth.HasAuth(s.activePds.Did) {
atid := s.activePds.AtId.String()
callbackRes := make(chan url.Values, 1)
listenPort, err := s.r.Auth.ListenForCallback(callbackRes)
if err != nil {
s.Log("Error Instantiating HTTP Server for Callback: %w", err)
return
}
s.Log("Listening on %d", listenPort)
_, err = s.r.Auth.StartAuthFlow(listenPort, atid, callbackRes)
if err != nil {
s.Log("Error starting auth flow: %w", err)
} else {
s.alert.SetTitle("Authentication Started")
s.alert.SetMessage(fmt.Sprintf("OAuth Process Started.\nIf a browser window didn't open, you can open this URL manually:\nhttp://localhost:%d/auth\nThis url will redirect to the PDS OAuth Page.", listenPort))
s.alert.SetVisible(true)
s.alert.SetActive(true)
go func() {
for s.isLoading {
time.Sleep(100)
}
s.alert.SetVisible(false)
}()
}
}
}()
return true
}
func (s *ScreenHome) cliBackupPds(args ...string) bool { func (s *ScreenHome) cliBackupPds(args ...string) bool {
if s.activePds == nil { if s.activePds == nil {
@@ -480,9 +450,9 @@ func (s *ScreenHome) changePdsList(tn *wd.TreeNode) bool {
auth := s.r.Auth.HasAuth(s.activePds.Did) auth := s.r.Auth.HasAuth(s.activePds.Did)
if auth { if auth {
if tn.Depth() == 0 { if tn.Depth() == 0 {
s.pdsListing.SetHintText("(A)dd New Record") s.pdsListing.SetHintText("┤ Ctrl+A: Add New Record")
} else { } else {
s.pdsListing.SetHintText("(A)dd New Record; (D)elete Record") s.pdsListing.SetHintText("┤ Ctrl+A: Add New Record │ Ctrl+D: Delete Record")
} }
} }
@@ -517,6 +487,45 @@ func (s *ScreenHome) updateJsonView(tn *wd.TreeNode) bool {
return true return true
} }
func (s *ScreenHome) menuAuthPds() bool {
s.menuLayout.HideMenu()
if s.activePds == nil {
s.Log("No active PDS.")
return true
}
s.isLoading = true
go func() {
defer func() { s.isLoading = false }()
// Check if we already have authentication.
if !s.r.Auth.HasAuth(s.activePds.Did) {
atid := s.activePds.AtId.String()
callbackRes := make(chan url.Values, 1)
listenPort, err := s.r.Auth.ListenForCallback(callbackRes)
if err != nil {
s.Log("Error Instantiating HTTP Server for Callback: %w", err)
return
}
s.Log("Listening on %d", listenPort)
_, err = s.r.Auth.StartAuthFlow(listenPort, atid, callbackRes)
if err != nil {
s.Log("Error starting auth flow: %w", err)
} else {
s.alert.SetTitle("Authentication Started")
s.alert.SetMessage(fmt.Sprintf("OAuth Process Started.\nIf a browser window didn't open, you can open this URL manually:\nhttp://localhost:%d/auth\nThis url will redirect to the PDS OAuth Page.", listenPort))
s.alert.SetVisible(true)
s.alert.SetActive(true)
go func() {
for s.isLoading {
time.Sleep(100)
}
s.alert.SetVisible(false)
}()
}
}
}()
return true
}
func (s *ScreenHome) menuOpenPds() bool { func (s *ScreenHome) menuOpenPds() bool {
s.menuLayout.HideMenu() s.menuLayout.HideMenu()
s.doOpen = true s.doOpen = true

View File

@@ -52,8 +52,19 @@ type JsonContent struct {
vimMode bool vimMode bool
cursor int cursor int
editKey, editVal bool
editValType int
} }
const (
JsonTpString = iota
JsonTpBool
JsonTpNumber
JsonTpObject
JsonTpArray
)
var _ wd.Widget = (*JsonContent)(nil) var _ wd.Widget = (*JsonContent)(nil)
func NewJsonContent(id string, style tcell.Style) *JsonContent { func NewJsonContent(id string, style tcell.Style) *JsonContent {
@@ -128,7 +139,7 @@ func (w *JsonContent) Draw(screen tcell.Screen) {
x, y = x+1, y+1 x, y = x+1, y+1
h := w.h - brdSz h := w.h - brdSz
ln := len(w.contents) ln := len(w.contents)
st, ed := 0, ln-1 start, end := 0, ln-1
if ln == 0 { if ln == 0 {
return return
} }
@@ -136,50 +147,93 @@ func (w *JsonContent) Draw(screen tcell.Screen) {
mid := h / 2 mid := h / 2
if w.cursor < mid { if w.cursor < mid {
// contents need to start at 0 // contents need to start at 0
ed = h + 1 end = h + 1
} else if w.cursor > ln-mid { } else if w.cursor > ln-mid {
// contents need to begin at ln-h // contents need to begin at ln-h
st = ln - h + 1 start = ln - h + 1
} else { } else {
st = w.cursor - mid start = w.cursor - mid
ed = st + h + 1 end = start + h + 1
} }
} }
// ed cannot be higher than ln-1 // ed cannot be higher than ln-1
if st < 0 { if start < 0 {
st = 0 start = 0
} }
if ed > ln-1 { if end > ln-1 {
ed = ln - 1 end = ln - 1
} }
for i := st; i <= ed; i++ { for i := start; i <= end; i++ {
st := w.style stl := w.style
dim := true dim := i != w.cursor
if i == w.cursor { if dim {
dim = false stl = stl.Foreground(tcell.ColorGreen)
} else {
st = st.Foreground(tcell.ColorGreen)
} }
txt := w.contents[i] txt := w.contents[i]
if len(txt) > w.w-brdSz && w.w-brdSz >= 0 { if len(txt) > w.w-brdSz && w.w-brdSz >= 0 {
txt = txt[:(w.w - brdSz)] txt = txt[:(w.w - brdSz)]
} }
if w.editable { if w.editable {
var key, val string w.drawEditableLine(screen, i, w.x, y, txt, stl, dim)
pts := strings.Split(txt, ":")
if len(pts) == 2 {
key, val = pts[0], pts[1]
}
wh.DrawText(w.x, y, key, st.Dim(dim).Bold(!dim), screen)
st = st.Reverse(true)
wh.DrawText(w.x, y, val, st.Dim(dim).Bold(!dim), screen)
} else { } else {
wh.DrawText(w.x, y, txt, st.Dim(dim).Bold(!dim), screen) w.drawReadOnlyLine(screen, i, w.x, y, txt, stl, dim)
} }
y++ y++
} }
} }
func (w *JsonContent) drawReadOnlyLine(screen tcell.Screen, idx, x, y int, txt string, stl tcell.Style, dim bool) {
wh.DrawText(x, y, txt, stl.Dim(dim).Bold(!dim), screen)
}
func (w *JsonContent) drawEditableLine(screen tcell.Screen, idx, x, y int, txt string, stl tcell.Style, dim bool) {
parseQuoted := func(txt string) (string, string) {
var v string
var slash bool
for i := range txt {
if txt[i] == '\\' {
slash = true
} else if slash {
slash = false
} else if txt[i] == '"' {
return v, txt[i+1:]
}
v = fmt.Sprintf("%s%c", v, txt[i])
}
// We didn't hit an ending quote
return v, ""
}
var key, val, wrk string
// The key should be a quoted value
for i := range txt {
if txt[i] == '"' && len(txt) > i {
key, wrk = parseQuoted(txt[i:])
break
}
}
txt = strings.Trim(wrk, ": ")
if len(txt) > 0 {
switch txt[0] {
case '"':
val, wrk = parseQuoted(txt[1:])
w.editValType = JsonTpString
case '{':
w.editValType = JsonTpObject
case '[':
w.editValType = JsonTpArray
default:
if txt == "true" || txt == "false" {
// Editing a boolean value
w.editValType = JsonTpBool
} else {
// Must be a number, right?
w.editValType = JsonTpNumber
}
}
}
keyStr := fmt.Sprintf("%s: ", key)
wh.DrawText(w.x, y, keyStr, stl.Dim(dim).Bold(!dim), screen)
wh.DrawText(w.x, y+len(keyStr), val, stl.Dim(dim).Bold(!dim), screen)
}
func (w *JsonContent) SetStyle(s tcell.Style) { w.style = s } func (w *JsonContent) SetStyle(s tcell.Style) { w.style = s }
func (w *JsonContent) Active() bool { return w.active } func (w *JsonContent) Active() bool { return w.active }