From fbe652b9321ebca2faf816bd3e02c88741e9e884 Mon Sep 17 00:00:00 2001 From: sawka Date: Thu, 6 Oct 2022 18:33:54 -0700 Subject: [PATCH] add scrolltop and selectedline to screen_window --- db/migrations/000001_init.up.sql | 2 ++ pkg/cmdrunner/cmdrunner.go | 43 ++++++++++++++++++++++++++++++++ pkg/cmdrunner/resolver.go | 38 ++++++++++++++++++++++++++++ pkg/sstore/dbops.go | 35 +++++++++++++++++++++++--- pkg/sstore/sstore.go | 12 +++++---- pkg/sstore/updatebus.go | 23 +++++++++-------- 6 files changed, 134 insertions(+), 19 deletions(-) diff --git a/db/migrations/000001_init.up.sql b/db/migrations/000001_init.up.sql index 08029a1d..7d788502 100644 --- a/db/migrations/000001_init.up.sql +++ b/db/migrations/000001_init.up.sql @@ -50,6 +50,8 @@ CREATE TABLE screen_window ( windowid varchar(36) NOT NULL, name varchar(50) NOT NULL, layout json NOT NULL, + selectedline int NOT NULL, + scrolltop int NOT NULL, PRIMARY KEY (sessionid, screenid, windowid) ); diff --git a/pkg/cmdrunner/cmdrunner.go b/pkg/cmdrunner/cmdrunner.go index 60c04964..43a58986 100644 --- a/pkg/cmdrunner/cmdrunner.go +++ b/pkg/cmdrunner/cmdrunner.go @@ -99,6 +99,8 @@ func init() { registerCmdFn("remote:install", RemoteInstallCommand) registerCmdFn("remote:installcancel", RemoteInstallCancelCommand) + registerCmdFn("sw:set", SwSetCommand) + registerCmdFn("window:resize", WindowResizeCommand) registerCmdFn("line", LineCommand) @@ -200,6 +202,20 @@ func resolvePosInt(arg string, def int) (int, error) { return ival, nil } +func resolveNonNegInt(arg string, def int) (int, error) { + if arg == "" { + return def, nil + } + ival, err := strconv.Atoi(arg) + if err != nil { + return 0, err + } + if ival < 0 { + return 0, fmt.Errorf("cannot be negative") + } + return ival, nil +} + func RunCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_RemoteConnected) if err != nil { @@ -409,6 +425,33 @@ func ScreenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor return update, nil } +func SwSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { + ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window) + if err != nil { + return nil, fmt.Errorf("/sw:set cannot resolve current screen-window: %w", err) + } + var setNonST bool // scrolltop does not receive an update + updateMap := make(map[string]interface{}) + if pk.Kwargs["scrolltop"] != "" { + stVal, err := resolveNonNegInt(pk.Kwargs["scrolltop"], 0) + if err != nil { + return nil, fmt.Errorf("/sw:set invalid scrolltop argument: %v", err) + } + updateMap[sstore.SWField_ScrollTop] = stVal + } + if len(updateMap) == 0 { + return nil, fmt.Errorf("/sw:set no updates, can set %s", formatStrs([]string{"line", "scrolltop"}, "or", false)) + } + sw, err := sstore.UpdateScreenWindow(ctx, ids.SessionId, ids.ScreenId, ids.WindowId, updateMap) + if err != nil { + return nil, fmt.Errorf("/sw:set failed to update: %v", err) + } + if !setNonST { + return nil, nil + } + return sstore.ModelUpdate{ScreenWindow: sw}, nil +} + func UnSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_RemoteConnected) if err != nil { diff --git a/pkg/cmdrunner/resolver.go b/pkg/cmdrunner/resolver.go index 09a701a9..4fb1cf2c 100644 --- a/pkg/cmdrunner/resolver.go +++ b/pkg/cmdrunner/resolver.go @@ -143,6 +143,24 @@ func resolveUiIds(ctx context.Context, pk *scpacket.FeCommandPacketType, rtype i rtn.ScreenId = uictx.ScreenId rtn.WindowId = uictx.WindowId } + if pk.Kwargs["session"] != "" { + sessionId, err := resolveSessionArg(pk.Kwargs["session"]) + if err != nil { + return rtn, err + } + if sessionId != "" { + rtn.SessionId = sessionId + } + } + if pk.Kwargs["screen"] != "" { + screenId, err := resolveScreenArg(rtn.SessionId, pk.Kwargs["screen"]) + if err != nil { + return rtn, err + } + if screenId != "" { + rtn.ScreenId = screenId + } + } if pk.Kwargs["window"] != "" { windowId, err := resolveWindowArg(rtn.SessionId, rtn.ScreenId, pk.Kwargs["window"]) if err != nil { @@ -274,6 +292,26 @@ func resolveWindowArg(sessionId string, screenId string, windowArg string) (stri return windowArg, nil } +func resolveSessionArg(sessionArg string) (string, error) { + if sessionArg == "" { + return "", nil + } + if _, err := uuid.Parse(sessionArg); err != nil { + return "", fmt.Errorf("invalid session arg specified (must be sessionid) '%s'", sessionArg) + } + return sessionArg, nil +} + +func resolveScreenArg(sessionId string, screenArg string) (string, error) { + if screenArg == "" { + return "", nil + } + if _, err := uuid.Parse(screenArg); err != nil { + return "", fmt.Errorf("invalid screen arg specified (must be sessionid) '%s'", screenArg) + } + return screenArg, nil +} + func resolveScreenId(ctx context.Context, pk *scpacket.FeCommandPacketType, sessionId string) (string, error) { screenArg := pk.Kwargs["screen"] if screenArg == "" { diff --git a/pkg/sstore/dbops.go b/pkg/sstore/dbops.go index b1f8bf76..350eb2ea 100644 --- a/pkg/sstore/dbops.go +++ b/pkg/sstore/dbops.go @@ -498,8 +498,8 @@ func InsertScreen(ctx context.Context, sessionId string, origScreenName string, query = `INSERT INTO screen (sessionid, screenid, name, activewindowid, screenidx, screenopts, ownerid, sharemode) VALUES (?, ?, ?, ?, ?, ?, '', 'local')` tx.ExecWrap(query, sessionId, newScreenId, screenName, newWindowId, maxScreenIdx+1, ScreenOptsType{}) layout := LayoutType{Type: LayoutFull} - query = `INSERT INTO screen_window (sessionid, screenid, windowid, name, layout) VALUES (?, ?, ?, ?, ?)` - tx.ExecWrap(query, sessionId, newScreenId, newWindowId, DefaultScreenWindowName, layout) + query = `INSERT INTO screen_window (sessionid, screenid, windowid, name, layout, selectedline, scrolltop) VALUES (?, ?, ?, ?, ?, ?, ?)` + tx.ExecWrap(query, sessionId, newScreenId, newWindowId, DefaultScreenWindowName, layout, 0, 0) if activate { query = `UPDATE session SET activescreenid = ? WHERE sessionid = ?` tx.ExecWrap(query, newScreenId, sessionId) @@ -619,7 +619,6 @@ func InsertLine(ctx context.Context, line *LineType, cmd *CmdType) error { if line.LineNum != 0 { return fmt.Errorf("line should not hage linenum set") } - cmd.OrigTermOpts = cmd.TermOpts return WithTx(ctx, func(tx *TxWrap) error { query := `SELECT windowid FROM window WHERE sessionid = ? AND windowid = ?` if !tx.Exists(query, line.SessionId, line.WindowId) { @@ -634,6 +633,7 @@ func InsertLine(ctx context.Context, line *LineType, cmd *CmdType) error { query = `UPDATE window SET nextlinenum = ? WHERE sessionid = ? AND windowid = ?` tx.ExecWrap(query, nextLineNum+1, line.SessionId, line.WindowId) if cmd != nil { + cmd.OrigTermOpts = cmd.TermOpts cmdMap := cmd.ToMap() query = ` INSERT INTO cmd ( sessionid, cmdid, remoteownerid, remoteid, remotename, cmdstr, remotestate, termopts, origtermopts, status, startpk, donepk, runout, usedrows) @@ -1103,3 +1103,32 @@ func UpdateRemote(ctx context.Context, remoteId string, editMap map[string]inter } return rtn, nil } + +const ( + SWField_ScrollTop = "scrolltop" // int +) + +func UpdateScreenWindow(ctx context.Context, sessionId string, screenId string, windowId string, editMap map[string]interface{}) (*ScreenWindowType, error) { + var rtn *ScreenWindowType + txErr := WithTx(ctx, func(tx *TxWrap) error { + query := `SELECT sessionid FROM screen_window WHERE sessionid = ? AND screenid = ? AND windowid = ?` + if !tx.Exists(query, sessionId, screenId, windowId) { + return fmt.Errorf("screen-window not found") + } + if stVal, found := editMap[SWField_ScrollTop]; found { + query = `UPDATE screen_window SET scrolltop = ? WHERE sessionid = ? AND screenid = ? AND windowid = ?` + tx.ExecWrap(query, stVal, 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) + if found { + rtn = &sw + } + return nil + }) + if txErr != nil { + return nil, txErr + } + return rtn, nil +} diff --git a/pkg/sstore/sstore.go b/pkg/sstore/sstore.go index 2225ccdc..f18658bd 100644 --- a/pkg/sstore/sstore.go +++ b/pkg/sstore/sstore.go @@ -376,11 +376,13 @@ func (l LayoutType) Value() (driver.Value, error) { } type ScreenWindowType struct { - SessionId string `json:"sessionid"` - ScreenId string `json:"screenid"` - WindowId string `json:"windowid"` - Name string `json:"name"` - Layout LayoutType `json:"layout"` + SessionId string `json:"sessionid"` + ScreenId string `json:"screenid"` + WindowId string `json:"windowid"` + Name string `json:"name"` + Layout LayoutType `json:"layout"` + SelectedLine int `json:"selectedline"` + ScrollTop int `json:"scrolltop"` // only for updates Remove bool `json:"remove,omitempty"` diff --git a/pkg/sstore/updatebus.go b/pkg/sstore/updatebus.go index 9378722b..e73df343 100644 --- a/pkg/sstore/updatebus.go +++ b/pkg/sstore/updatebus.go @@ -29,17 +29,18 @@ func (PtyDataUpdate) UpdateType() string { } type ModelUpdate struct { - Sessions []*SessionType `json:"sessions,omitempty"` - ActiveSessionId string `json:"activesessionid,omitempty"` - Window *WindowType `json:"window,omitempty"` - Line *LineType `json:"line,omitempty"` - Cmd *CmdType `json:"cmd,omitempty"` - CmdLine *CmdLineType `json:"cmdline,omitempty"` - Info *InfoMsgType `json:"info,omitempty"` - Remotes []interface{} `json:"remotes,omitempty"` // []*remote.RemoteState - History *HistoryInfoType `json:"history,omitempty"` - Interactive bool `json:"interactive"` - Connect bool `json:"connect,omitempty"` + Sessions []*SessionType `json:"sessions,omitempty"` + ActiveSessionId string `json:"activesessionid,omitempty"` + Window *WindowType `json:"window,omitempty"` + ScreenWindow *ScreenWindowType `json:"screenwindow,omitempty"` + Line *LineType `json:"line,omitempty"` + Cmd *CmdType `json:"cmd,omitempty"` + CmdLine *CmdLineType `json:"cmdline,omitempty"` + Info *InfoMsgType `json:"info,omitempty"` + Remotes []interface{} `json:"remotes,omitempty"` // []*remote.RemoteState + History *HistoryInfoType `json:"history,omitempty"` + Interactive bool `json:"interactive"` + Connect bool `json:"connect,omitempty"` } func (ModelUpdate) UpdateType() string {