switch from '/' to '@' as metacommand character

This commit is contained in:
sawka 2022-08-23 13:37:08 -07:00
parent 709920ad8e
commit 946f31988c

View File

@ -63,14 +63,14 @@ func SubMetaCmd(cmd string) string {
} }
var ValidCommands = []string{ var ValidCommands = []string{
"/run", "@run",
"/eval", "@eval",
"/screen", "/screen:open", "/screen:close", "@screen", "@screen:open", "@screen:close",
"/session", "/session:open", "/session:close", "@session", "@session:open", "@session:close",
"/comment", "@comment",
"/cd", "@cd",
"/compgen", "@compgen",
"/setenv", "/unset", "@setenv", "@unset",
} }
func HandleCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { func HandleCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
@ -106,7 +106,7 @@ func HandleCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
return UnSetCommand(ctx, pk) return UnSetCommand(ctx, pk)
default: default:
return nil, fmt.Errorf("invalid command '/%s', no handler", pk.MetaCmd) return nil, fmt.Errorf("invalid command '@%s', no handler", pk.MetaCmd)
} }
} }
@ -270,7 +270,7 @@ func resolveIds(ctx context.Context, pk *scpacket.FeCommandPacketType, rtype int
func RunCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { func RunCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote) ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote)
if err != nil { if err != nil {
return nil, fmt.Errorf("/run error: %w", err) return nil, fmt.Errorf("@run error: %w", err)
} }
cmdId := uuid.New().String() cmdId := uuid.New().String()
cmdStr := firstArg(pk) cmdStr := firstArg(pk)
@ -323,12 +323,12 @@ func addToHistory(ctx context.Context, pk *scpacket.FeCommandPacketType, update
func EvalCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { func EvalCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
if len(pk.Args) == 0 { if len(pk.Args) == 0 {
return nil, fmt.Errorf("usage: /eval [command], no command passed to eval") return nil, fmt.Errorf("usage: @eval [command], no command passed to eval")
} }
// parse metacmd // parse metacmd
commandStr := strings.TrimSpace(pk.Args[0]) commandStr := strings.TrimSpace(pk.Args[0])
if commandStr == "" { if commandStr == "" {
return nil, fmt.Errorf("/eval, invalid emtpty command") return nil, fmt.Errorf("@eval, invalid emtpty command")
} }
update, err := evalCommandInternal(ctx, pk) update, err := evalCommandInternal(ctx, pk)
if !resolveBool(pk.Kwargs["nohist"], false) { if !resolveBool(pk.Kwargs["nohist"], false) {
@ -360,7 +360,7 @@ func evalCommandInternal(ctx context.Context, pk *scpacket.FeCommandPacketType)
} else if commandStr == "unset" || strings.HasPrefix(commandStr, "unset ") { } else if commandStr == "unset" || strings.HasPrefix(commandStr, "unset ") {
metaCmd = "unset" metaCmd = "unset"
commandStr = strings.TrimSpace(commandStr[5:]) commandStr = strings.TrimSpace(commandStr[5:])
} else if commandStr[0] == '/' { } else if commandStr[0] == '@' {
spaceIdx := strings.Index(commandStr, " ") spaceIdx := strings.Index(commandStr, " ")
if spaceIdx == -1 { if spaceIdx == -1 {
metaCmd = commandStr[1:] metaCmd = commandStr[1:]
@ -374,7 +374,7 @@ func evalCommandInternal(ctx context.Context, pk *scpacket.FeCommandPacketType)
metaCmd, metaSubCmd = metaCmd[0:colonIdx], metaCmd[colonIdx+1:] metaCmd, metaSubCmd = metaCmd[0:colonIdx], metaCmd[colonIdx+1:]
} }
if metaCmd == "" { if metaCmd == "" {
return nil, fmt.Errorf("invalid command, got bare '/', with no command") return nil, fmt.Errorf("invalid command, got bare '@', with no command")
} }
} }
if metaCmd == "" { if metaCmd == "" {
@ -412,7 +412,7 @@ func ScreenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
if pk.MetaSubCmd == "close" { if pk.MetaSubCmd == "close" {
ids, err := resolveIds(ctx, pk, R_Session|R_Screen) ids, err := resolveIds(ctx, pk, R_Session|R_Screen)
if err != nil { if err != nil {
return nil, fmt.Errorf("/screen:close cannot close screen: %w", err) return nil, fmt.Errorf("@screen:close cannot close screen: %w", err)
} }
update, err := sstore.DeleteScreen(ctx, ids.SessionId, ids.ScreenId) update, err := sstore.DeleteScreen(ctx, ids.SessionId, ids.ScreenId)
if err != nil { if err != nil {
@ -423,7 +423,7 @@ func ScreenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
if pk.MetaSubCmd == "open" || pk.MetaSubCmd == "new" { if pk.MetaSubCmd == "open" || pk.MetaSubCmd == "new" {
ids, err := resolveIds(ctx, pk, R_Session) ids, err := resolveIds(ctx, pk, R_Session)
if err != nil { if err != nil {
return nil, fmt.Errorf("/screen:open cannot open screen: %w", err) return nil, fmt.Errorf("@screen:open cannot open screen: %w", err)
} }
activate := resolveBool(pk.Kwargs["activate"], true) activate := resolveBool(pk.Kwargs["activate"], true)
update, err := sstore.InsertScreen(ctx, ids.SessionId, pk.Kwargs["name"], activate) update, err := sstore.InsertScreen(ctx, ids.SessionId, pk.Kwargs["name"], activate)
@ -433,15 +433,15 @@ func ScreenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
return update, nil return update, nil
} }
if pk.MetaSubCmd != "" { if pk.MetaSubCmd != "" {
return nil, fmt.Errorf("invalid /screen subcommand '%s'", pk.MetaSubCmd) return nil, fmt.Errorf("invalid @screen subcommand '%s'", pk.MetaSubCmd)
} }
ids, err := resolveIds(ctx, pk, R_Session) ids, err := resolveIds(ctx, pk, R_Session)
if err != nil { if err != nil {
return nil, fmt.Errorf("/screen cannot switch to screen: %w", err) return nil, fmt.Errorf("@screen cannot switch to screen: %w", err)
} }
firstArg := firstArg(pk) firstArg := firstArg(pk)
if firstArg == "" { if firstArg == "" {
return nil, fmt.Errorf("usage /screen [screen-name|screen-index|screen-id], no param specified") return nil, fmt.Errorf("usage @screen [screen-name|screen-index|screen-id], no param specified")
} }
screenIdArg, err := resolveSessionScreen(ctx, ids.SessionId, firstArg) screenIdArg, err := resolveSessionScreen(ctx, ids.SessionId, firstArg)
if err != nil { if err != nil {
@ -456,7 +456,7 @@ func ScreenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
func UnSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { func UnSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
if pk.MetaSubCmd != "" { if pk.MetaSubCmd != "" {
return nil, fmt.Errorf("invalid /unset subcommand '%s'", pk.MetaSubCmd) return nil, fmt.Errorf("invalid @unset subcommand '%s'", pk.MetaSubCmd)
} }
ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote) ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote)
if err != nil { if err != nil {
@ -512,7 +512,7 @@ func makeSetVarsStr(setVars map[string]bool) string {
func SetEnvCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { func SetEnvCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
if pk.MetaSubCmd != "" { if pk.MetaSubCmd != "" {
return nil, fmt.Errorf("invalid /setenv subcommand '%s'", pk.MetaSubCmd) return nil, fmt.Errorf("invalid @setenv subcommand '%s'", pk.MetaSubCmd)
} }
ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote) ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote)
if err != nil { if err != nil {
@ -577,7 +577,7 @@ func SetEnvCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Window) ids, err := resolveIds(ctx, pk, R_Session|R_Window)
if err != nil { if err != nil {
return nil, fmt.Errorf("/cr error: %w", err) return nil, fmt.Errorf("@cr error: %w", err)
} }
newRemote := firstArg(pk) newRemote := firstArg(pk)
if newRemote == "" { if newRemote == "" {
@ -589,11 +589,11 @@ func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
return nil, err return nil, err
} }
if remoteId == "" { if remoteId == "" {
return nil, fmt.Errorf("/cr error: remote not found") return nil, fmt.Errorf("@cr error: remote not found")
} }
err = sstore.UpdateCurRemote(ctx, ids.SessionId, ids.WindowId, remoteName) err = sstore.UpdateCurRemote(ctx, ids.SessionId, ids.WindowId, remoteName)
if err != nil { if err != nil {
return nil, fmt.Errorf("/cr error: cannot update curremote: %w", err) return nil, fmt.Errorf("@cr error: cannot update curremote: %w", err)
} }
update := sstore.WindowUpdate{ update := sstore.WindowUpdate{
Window: sstore.WindowType{ Window: sstore.WindowType{
@ -612,7 +612,7 @@ func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
func CdCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { func CdCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote) ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote)
if err != nil { if err != nil {
return nil, fmt.Errorf("/cd error: %w", err) return nil, fmt.Errorf("@cd error: %w", err)
} }
newDir := firstArg(pk) newDir := firstArg(pk)
curRemote := remote.GetRemoteById(ids.RemoteId) curRemote := remote.GetRemoteById(ids.RemoteId)
@ -638,12 +638,12 @@ func CdCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
} }
if !strings.HasPrefix(newDir, "/") { if !strings.HasPrefix(newDir, "/") {
if ids.RemoteState == nil { if ids.RemoteState == nil {
return nil, fmt.Errorf("/cd error: cannot get current remote directory (can only cd with absolute path)") return nil, fmt.Errorf("@cd error: cannot get current remote directory (can only cd with absolute path)")
} }
newDir = path.Join(ids.RemoteState.Cwd, newDir) newDir = path.Join(ids.RemoteState.Cwd, newDir)
newDir, err = filepath.Abs(newDir) newDir, err = filepath.Abs(newDir)
if err != nil { if err != nil {
return nil, fmt.Errorf("/cd error: error canonicalizing new directory: %w", err) return nil, fmt.Errorf("@cd error: error canonicalizing new directory: %w", err)
} }
} }
cdPacket := packet.MakeCdPacket() cdPacket := packet.MakeCdPacket()
@ -722,6 +722,9 @@ func getBool(v interface{}, field string) bool {
func makeInfoFromComps(compType string, comps []string, hasMore bool) sstore.UpdatePacket { func makeInfoFromComps(compType string, comps []string, hasMore bool) sstore.UpdatePacket {
sort.Strings(comps) sort.Strings(comps)
if len(comps) == 0 {
comps = []string{"(no completions)"}
}
update := sstore.InfoUpdate{ update := sstore.InfoUpdate{
Info: &sstore.InfoMsgType{ Info: &sstore.InfoMsgType{
InfoTitle: fmt.Sprintf("%s completions", compType), InfoTitle: fmt.Sprintf("%s completions", compType),
@ -777,13 +780,16 @@ func longestPrefix(root string, comps []string) string {
var wsRe = regexp.MustCompile("\\s+") var wsRe = regexp.MustCompile("\\s+")
func doMetaCompGen(ctx context.Context, ids resolvedIds, prefix string) ([]string, bool, error) { func doMetaCompGen(ctx context.Context, ids resolvedIds, prefix string) ([]string, bool, error) {
var comps []string comps, hasMore, err := doCompGen(ctx, ids, prefix, "file")
if err != nil {
return nil, false, err
}
for _, cmd := range ValidCommands { for _, cmd := range ValidCommands {
if strings.HasPrefix(cmd, prefix) { if strings.HasPrefix(cmd, prefix) {
comps = append(comps, cmd) comps = append(comps, cmd)
} }
} }
return comps, false, nil return comps, hasMore, nil
} }
func doCompGen(ctx context.Context, ids resolvedIds, prefix string, compType string) ([]string, bool, error) { func doCompGen(ctx context.Context, ids resolvedIds, prefix string, compType string) ([]string, bool, error) {
@ -791,14 +797,14 @@ func doCompGen(ctx context.Context, ids resolvedIds, prefix string, compType str
return doMetaCompGen(ctx, ids, prefix) return doMetaCompGen(ctx, ids, prefix)
} }
if !packet.IsValidCompGenType(compType) { if !packet.IsValidCompGenType(compType) {
return nil, false, fmt.Errorf("/compgen invalid type '%s'", compType) return nil, false, fmt.Errorf("@compgen invalid type '%s'", compType)
} }
cgPacket := packet.MakeCompGenPacket() cgPacket := packet.MakeCompGenPacket()
cgPacket.ReqId = uuid.New().String() cgPacket.ReqId = uuid.New().String()
cgPacket.CompType = compType cgPacket.CompType = compType
cgPacket.Prefix = prefix cgPacket.Prefix = prefix
if ids.RemoteState == nil { if ids.RemoteState == nil {
return nil, false, fmt.Errorf("/compgen invalid remote state") return nil, false, fmt.Errorf("@compgen invalid remote state")
} }
cgPacket.Cwd = ids.RemoteState.Cwd cgPacket.Cwd = ids.RemoteState.Cwd
curRemote := remote.GetRemoteById(ids.RemoteId) curRemote := remote.GetRemoteById(ids.RemoteId)
@ -820,14 +826,14 @@ func doCompGen(ctx context.Context, ids resolvedIds, prefix string, compType str
func CompGenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { func CompGenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote) ids, err := resolveIds(ctx, pk, R_Session|R_Window|R_Remote)
if err != nil { if err != nil {
return nil, fmt.Errorf("/compgen error: %w", err) return nil, fmt.Errorf("@compgen error: %w", err)
} }
cmdLine := firstArg(pk) cmdLine := firstArg(pk)
pos := len(cmdLine) pos := len(cmdLine)
if pk.Kwargs["comppos"] != "" { if pk.Kwargs["comppos"] != "" {
posArg, err := strconv.Atoi(pk.Kwargs["comppos"]) posArg, err := strconv.Atoi(pk.Kwargs["comppos"])
if err != nil { if err != nil {
return nil, fmt.Errorf("/compgen invalid comppos '%s': %w", pk.Kwargs["comppos"], err) return nil, fmt.Errorf("@compgen invalid comppos '%s': %w", pk.Kwargs["comppos"], err)
} }
pos = posArg pos = posArg
} }
@ -841,9 +847,9 @@ func CompGenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
prefix := cmdLine[:pos] prefix := cmdLine[:pos]
parts := strings.Split(prefix, " ") parts := strings.Split(prefix, " ")
compType := "file" compType := "file"
if len(parts) > 0 && strings.HasPrefix(parts[0], "/") { if len(parts) > 0 && len(parts) < 2 && strings.HasPrefix(parts[0], "@") {
compType = "metacommand" compType = "metacommand"
} else if len(parts) == 2 && (parts[0] == "cd" || parts[0] == "/cd") { } else if len(parts) == 2 && (parts[0] == "cd" || parts[0] == "@cd") {
compType = "directory" compType = "directory"
} else if len(parts) <= 1 { } else if len(parts) <= 1 {
compType = "command" compType = "command"
@ -865,7 +871,7 @@ func CompGenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
func CommentCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) { func CommentCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
ids, err := resolveIds(ctx, pk, R_Session|R_Window) ids, err := resolveIds(ctx, pk, R_Session|R_Window)
if err != nil { if err != nil {
return nil, fmt.Errorf("/comment error: %w", err) return nil, fmt.Errorf("@comment error: %w", err)
} }
text := firstArg(pk) text := firstArg(pk)
if strings.TrimSpace(text) == "" { if strings.TrimSpace(text) == "" {
@ -888,11 +894,11 @@ func SessionCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
return update, nil return update, nil
} }
if pk.MetaSubCmd != "" { if pk.MetaSubCmd != "" {
return nil, fmt.Errorf("invalid /session subcommand '%s'", pk.MetaSubCmd) return nil, fmt.Errorf("invalid @session subcommand '%s'", pk.MetaSubCmd)
} }
firstArg := firstArg(pk) firstArg := firstArg(pk)
if firstArg == "" { if firstArg == "" {
return nil, fmt.Errorf("usage /session [session-name|session-id], no param specified") return nil, fmt.Errorf("usage @session [session-name|session-id], no param specified")
} }
sessionId, err := resolveSession(ctx, firstArg) sessionId, err := resolveSession(ctx, firstArg)
if err != nil { if err != nil {