Working on Editing
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|||||||
Reference in New Issue
Block a user