commands for line selection, updated resolver to allow 'S' and 'E'

This commit is contained in:
sawka
2022-10-07 01:08:03 -07:00
parent 2d089b98fb
commit 43cf55b25e
3 changed files with 107 additions and 22 deletions
+20 -1
View File
@@ -43,7 +43,7 @@ var hostNameRe = regexp.MustCompile("^[a-z][a-z0-9.-]*$")
var userHostRe = regexp.MustCompile("^(sudo@)?([a-z][a-z0-9-]*)@([a-z][a-z0-9.-]*)(?::([0-9]+))?$")
var remoteAliasRe = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9_-]*$")
var genericNameRe = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9_ .()<>,/\"'\\[\\]{}=+$@!*-]*$")
var positionRe = regexp.MustCompile("^((\\+|-)?[0-9]+|(\\+|-))$")
var positionRe = regexp.MustCompile("^((S?\\+|E?-)?[0-9]+|(\\+|-|S|E))$")
var wsRe = regexp.MustCompile("\\s+")
type contextType string
@@ -439,6 +439,25 @@ func SwSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore
}
updateMap[sstore.SWField_ScrollTop] = stVal
}
if pk.Kwargs["line"] != "" {
sw, err := sstore.GetScreenWindowByIds(ctx, ids.SessionId, ids.ScreenId, ids.WindowId)
if err != nil {
return nil, fmt.Errorf("/sw:set cannot get screen-window: %v", err)
}
var selectedLineStr string
if sw.SelectedLine > 0 {
selectedLineStr = strconv.Itoa(sw.SelectedLine)
}
ritem, err := resolveLine(ctx, ids.SessionId, ids.WindowId, pk.Kwargs["line"], selectedLineStr)
if err != nil {
return nil, fmt.Errorf("/sw:set error resolving line: %v", err)
}
if ritem == nil {
return nil, fmt.Errorf("/sw:set could not resolve line %q", pk.Kwargs["line"])
}
setNonST = true
updateMap[sstore.SWField_SelectedLine] = ritem.Num
}
if len(updateMap) == 0 {
return nil, fmt.Errorf("/sw:set no updates, can set %s", formatStrs([]string{"line", "scrolltop"}, "or", false))
}
+64 -20
View File
@@ -95,26 +95,40 @@ func boundInt(ival int, maxVal int, wrap bool) int {
}
type posArgType struct {
Pos int
IsWrap bool
IsRelative bool
Pos int
IsWrap bool
IsRelative bool
StartAnchor bool
EndAnchor bool
}
func parsePosArg(posStr string) *posArgType {
if !positionRe.MatchString(posStr) {
return nil
}
rtn := &posArgType{}
rtn.IsRelative = strings.HasPrefix(posStr, "+") || strings.HasPrefix(posStr, "-")
rtn.IsWrap = posStr == "+" || posStr == "-"
if rtn.IsWrap && posStr == "+" {
rtn.Pos = 1
} else if rtn.IsWrap && posStr == "-" {
rtn.Pos = -1
} else {
rtn.Pos, _ = strconv.Atoi(posStr) // don't need to check error because of positionRe.Match
if posStr == "+" {
return &posArgType{Pos: 1, IsWrap: true, IsRelative: true}
} else if posStr == "-" {
return &posArgType{Pos: -1, IsWrap: true, IsRelative: true}
} else if posStr == "S" {
return &posArgType{Pos: 0, IsRelative: true, StartAnchor: true}
} else if posStr == "E" {
return &posArgType{Pos: 0, IsRelative: true, EndAnchor: true}
}
return rtn
if strings.HasPrefix(posStr, "S+") {
pos, _ := strconv.Atoi(posStr[2:])
return &posArgType{Pos: pos, IsRelative: true, StartAnchor: true}
}
if strings.HasPrefix(posStr, "E-") {
pos, _ := strconv.Atoi(posStr[1:])
return &posArgType{Pos: pos, IsRelative: true, EndAnchor: true}
}
if strings.HasPrefix(posStr, "+") || strings.HasPrefix(posStr, "-") {
pos, _ := strconv.Atoi(posStr)
return &posArgType{Pos: pos, IsRelative: true}
}
pos, _ := strconv.Atoi(posStr)
return &posArgType{Pos: pos}
}
func resolveByPosition(isNumeric bool, items []ResolveItem, curId string, posStr string) *ResolveItem {
@@ -127,15 +141,31 @@ func resolveByPosition(isNumeric bool, items []ResolveItem, curId string, posStr
}
var finalPos int
if posArg.IsRelative {
curIdx := 1 // if no match, curIdx will be first item
for idx, item := range items {
if item.Id == curId {
curIdx = idx + 1
break
var curIdx int
if posArg.StartAnchor {
curIdx = 1
} else if posArg.EndAnchor {
curIdx = len(items)
} else {
curIdx = 1 // if no match, curIdx will be first item
for idx, item := range items {
if item.Id == curId {
curIdx = idx + 1
break
}
}
}
finalPos = curIdx + posArg.Pos
} else if isNumeric {
// these resolve items have a "Num" set that should be used to look up non-relative positions
for _, item := range items {
if item.Num == posArg.Pos {
return &item
}
}
return nil
} else {
// non-numeric means position is just the index
finalPos = posArg.Pos
}
finalPos = boundInt(finalPos, len(items), posArg.IsWrap)
@@ -243,12 +273,20 @@ func resolveUiIds(ctx context.Context, pk *scpacket.FeCommandPacketType, rtype i
func resolveSessionScreen(ctx context.Context, sessionId string, screenArg string, curScreenArg string) (*ResolveItem, error) {
screens, err := sstore.GetSessionScreens(ctx, sessionId)
if err != nil {
return nil, fmt.Errorf("could not retreive screens for session=%s", sessionId)
return nil, fmt.Errorf("could not retreive screens for session=%s: %v", sessionId, err)
}
ritems := screensToResolveItems(screens)
return genericResolve(screenArg, curScreenArg, ritems, false, "screen")
}
func resolveLine(ctx context.Context, sessionId string, windowId string, lineArg string, curLineArg string) (*ResolveItem, error) {
lines, err := sstore.GetLineResolveItems(ctx, sessionId, windowId)
if err != nil {
return nil, fmt.Errorf("could not get lines: %v", err)
}
return genericResolve(lineArg, curLineArg, lines, true, "line")
}
func getSessionIds(sarr []*sstore.SessionType) []string {
rtn := make([]string, len(sarr))
for idx, s := range sarr {
@@ -263,6 +301,11 @@ func isPartialUUID(s string) bool {
return partialUUIDRe.MatchString(s)
}
func isUUID(s string) bool {
_, err := uuid.Parse(s)
return err == nil
}
func getResolveItemById(id string, items []ResolveItem) *ResolveItem {
if id == "" {
return nil
@@ -290,10 +333,11 @@ func genericResolve(arg string, curArg string, items []ResolveItem, isNumeric bo
if rtnItem != nil {
return rtnItem, nil
}
isUuid := isUUID(arg)
tryPuid := isPartialUUID(arg)
var prefixMatches []ResolveItem
for _, item := range items {
if item.Id == arg || (tryPuid && strings.HasPrefix(item.Id, arg)) {
if (isUuid && item.Id == arg) || (tryPuid && strings.HasPrefix(item.Id, arg)) {
return &item, nil
}
if item.Name != "" {
+23 -1
View File
@@ -1105,7 +1105,8 @@ func UpdateRemote(ctx context.Context, remoteId string, editMap map[string]inter
}
const (
SWField_ScrollTop = "scrolltop" // int
SWField_ScrollTop = "scrolltop" // int
SWField_SelectedLine = "selectedline" // int
)
func UpdateScreenWindow(ctx context.Context, sessionId string, screenId string, windowId string, editMap map[string]interface{}) (*ScreenWindowType, error) {
@@ -1119,6 +1120,10 @@ func UpdateScreenWindow(ctx context.Context, sessionId string, screenId string,
query = `UPDATE screen_window SET scrolltop = ? WHERE sessionid = ? AND screenid = ? AND windowid = ?`
tx.ExecWrap(query, stVal, sessionId, screenId, windowId)
}
if sline, found := editMap[SWField_SelectedLine]; found {
query = `UPDATE screen_window SET selectedline = ? WHERE sessionid = ? AND screenid = ? AND windowid = ?`
tx.ExecWrap(query, sline, sessionId, screenId, windowId)
}
var sw ScreenWindowType
query = `SELECT * FROM screen_window WHERE sessionid = ? AND screenid = ? AND windowid = ?`
found := tx.GetWrap(&sw, query, sessionId, screenId, windowId)
@@ -1133,6 +1138,23 @@ func UpdateScreenWindow(ctx context.Context, sessionId string, screenId string,
return rtn, nil
}
func GetScreenWindowByIds(ctx context.Context, sessionId string, screenId string, windowId string) (*ScreenWindowType, error) {
var rtn *ScreenWindowType
txErr := WithTx(ctx, func(tx *TxWrap) error {
var sw ScreenWindowType
query := `SELECT * FROM screen_window WHERE sessionid = ? AND screenid = ? AND windowid = ?`
found := tx.GetWrap(&sw, query, sessionId, screenId, windowId)
if found {
rtn = &sw
}
return nil
})
if txErr != nil {
return nil, txErr
}
return rtn, nil
}
func GetLineResolveItems(ctx context.Context, sessionId string, windowId string) ([]ResolveItem, error) {
var rtn []ResolveItem
txErr := WithTx(ctx, func(tx *TxWrap) error {