From 94fab7acee537dc30739a5d3685ab05d65aa09f0 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Wed, 18 Feb 2026 21:43:50 -0600 Subject: [PATCH] Working on Editing --- app/screen_home.go | 87 ++++++++++++++++++--------------- widgets/json_content.go | 106 ++++++++++++++++++++++++++++++---------- 2 files changed, 128 insertions(+), 65 deletions(-) diff --git a/app/screen_home.go b/app/screen_home.go index fb43d2f..ab0691e 100644 --- a/app/screen_home.go +++ b/app/screen_home.go @@ -261,6 +261,7 @@ func (s *ScreenHome) initMenu() { s.menuLayout.AddMenuItems( s.menuLayout.CreateMenuItem("file", "File", nil, 'f', 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.exit", "Exit", s.menuExit, 'x'), ), @@ -292,11 +293,16 @@ func (s *ScreenHome) update() { } recNmInf.SetLabel(fmt.Sprintf("%s Infer Record Names", wrk)) + miAuth := s.menuLayout.FindItem("file.authpds") miReload := s.menuLayout.FindItem("file.reloadpds") if s.activePds == nil { + miAuth.SetDisabled(true) + miAuth.SetStyle(s.style.Foreground(tcell.ColorGray)) miReload.SetDisabled(true) miReload.SetStyle(s.style.Foreground(tcell.ColorGray)) } else { + miAuth.SetDisabled(true) + miAuth.SetStyle(s.style.Foreground(tcell.ColorGray)) miReload.SetDisabled(false) miReload.SetStyle(s.style.Foreground(tcell.ColorLime)) } @@ -344,43 +350,7 @@ func (s *ScreenHome) cliGetPds(args ...string) bool { return true } -func (s *ScreenHome) cliAuthPds(args ...string) bool { - 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) cliAuthPds(args ...string) bool { return s.menuAuthPds() } func (s *ScreenHome) cliBackupPds(args ...string) bool { if s.activePds == nil { @@ -480,9 +450,9 @@ func (s *ScreenHome) changePdsList(tn *wd.TreeNode) bool { auth := s.r.Auth.HasAuth(s.activePds.Did) if auth { if tn.Depth() == 0 { - s.pdsListing.SetHintText("(A)dd New Record") + s.pdsListing.SetHintText("┤ Ctrl+A: Add New Record ├") } 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 } +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 { s.menuLayout.HideMenu() s.doOpen = true diff --git a/widgets/json_content.go b/widgets/json_content.go index caca3f8..d77fdd7 100644 --- a/widgets/json_content.go +++ b/widgets/json_content.go @@ -52,8 +52,19 @@ type JsonContent struct { vimMode bool cursor int + + editKey, editVal bool + editValType int } +const ( + JsonTpString = iota + JsonTpBool + JsonTpNumber + JsonTpObject + JsonTpArray +) + var _ wd.Widget = (*JsonContent)(nil) 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 h := w.h - brdSz ln := len(w.contents) - st, ed := 0, ln-1 + start, end := 0, ln-1 if ln == 0 { return } @@ -136,50 +147,93 @@ func (w *JsonContent) Draw(screen tcell.Screen) { mid := h / 2 if w.cursor < mid { // contents need to start at 0 - ed = h + 1 + end = h + 1 } else if w.cursor > ln-mid { // contents need to begin at ln-h - st = ln - h + 1 + start = ln - h + 1 } else { - st = w.cursor - mid - ed = st + h + 1 + start = w.cursor - mid + end = start + h + 1 } } // ed cannot be higher than ln-1 - if st < 0 { - st = 0 + if start < 0 { + start = 0 } - if ed > ln-1 { - ed = ln - 1 + if end > ln-1 { + end = 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) + for i := start; i <= end; i++ { + stl := w.style + dim := i != w.cursor + if dim { + stl = stl.Foreground(tcell.ColorGreen) } txt := w.contents[i] if len(txt) > w.w-brdSz && w.w-brdSz >= 0 { txt = txt[:(w.w - brdSz)] } - if w.editable { - var key, val string - 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) + w.drawEditableLine(screen, i, w.x, y, txt, stl, dim) } else { - wh.DrawText(w.x, y, txt, st.Dim(dim).Bold(!dim), screen) + w.drawReadOnlyLine(screen, i, w.x, y, txt, stl, dim) } 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) Active() bool { return w.active }