mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-25 17:18:02 +01:00
checkpoint on completion
This commit is contained in:
parent
d225c988ed
commit
848f7164a3
@ -149,12 +149,9 @@ func setBracketArgs(argMap map[string]string, bracketStr string) error {
|
|||||||
strReader := strings.NewReader(bracketStr)
|
strReader := strings.NewReader(bracketStr)
|
||||||
parser := syntax.NewParser(syntax.Variant(syntax.LangBash))
|
parser := syntax.NewParser(syntax.Variant(syntax.LangBash))
|
||||||
var wordErr error
|
var wordErr error
|
||||||
|
var ectx shexec.SimpleExpandContext // do not set HomeDir (we don't expand ~ in bracket args)
|
||||||
err := parser.Words(strReader, func(w *syntax.Word) bool {
|
err := parser.Words(strReader, func(w *syntax.Word) bool {
|
||||||
litStr, err := shexec.QuotedLitToStr(w)
|
litStr := shexec.SimpleExpandWord(ectx, w, bracketStr)
|
||||||
if err != nil {
|
|
||||||
wordErr = fmt.Errorf("invalid expr in bracket args: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
eqIdx := strings.Index(litStr, "=")
|
eqIdx := strings.Index(litStr, "=")
|
||||||
var varName, varVal string
|
var varName, varVal string
|
||||||
if eqIdx == -1 {
|
if eqIdx == -1 {
|
||||||
@ -299,7 +296,7 @@ func EvalMetaCommand(ctx context.Context, origPk *scpacket.FeCommandPacketType)
|
|||||||
return rtnPk, nil
|
return rtnPk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseAliasStmt(stmt *syntax.Stmt) (string, string, error) {
|
func parseAliasStmt(stmt *syntax.Stmt, sourceStr string) (string, string, error) {
|
||||||
cmd := stmt.Cmd
|
cmd := stmt.Cmd
|
||||||
callExpr, ok := cmd.(*syntax.CallExpr)
|
callExpr, ok := cmd.(*syntax.CallExpr)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -313,10 +310,8 @@ func parseAliasStmt(stmt *syntax.Stmt) (string, string, error) {
|
|||||||
return "", "", fmt.Errorf("invalid alias cmd word (not 'alias')")
|
return "", "", fmt.Errorf("invalid alias cmd word (not 'alias')")
|
||||||
}
|
}
|
||||||
secondWord := callExpr.Args[1]
|
secondWord := callExpr.Args[1]
|
||||||
val, err := shexec.QuotedLitToStr(secondWord)
|
var ectx shexec.SimpleExpandContext // no homedir, do not want ~ expansion
|
||||||
if err != nil {
|
val := shexec.SimpleExpandWord(ectx, secondWord, sourceStr)
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
eqIdx := strings.Index(val, "=")
|
eqIdx := strings.Index(val, "=")
|
||||||
if eqIdx == -1 {
|
if eqIdx == -1 {
|
||||||
return "", "", fmt.Errorf("no '=' in alias definition")
|
return "", "", fmt.Errorf("no '=' in alias definition")
|
||||||
@ -333,7 +328,7 @@ func ParseAliases(aliases string) (map[string]string, error) {
|
|||||||
}
|
}
|
||||||
rtn := make(map[string]string)
|
rtn := make(map[string]string)
|
||||||
for _, stmt := range file.Stmts {
|
for _, stmt := range file.Stmts {
|
||||||
aliasName, aliasVal, err := parseAliasStmt(stmt)
|
aliasName, aliasVal, err := parseAliasStmt(stmt, aliases)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// fmt.Printf("stmt-err: %v\n", err)
|
// fmt.Printf("stmt-err: %v\n", err)
|
||||||
continue
|
continue
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/scripthaus-dev/mshell/pkg/packet"
|
"github.com/scripthaus-dev/mshell/pkg/packet"
|
||||||
|
"github.com/scripthaus-dev/mshell/pkg/shexec"
|
||||||
"github.com/scripthaus-dev/sh2-server/pkg/sstore"
|
"github.com/scripthaus-dev/sh2-server/pkg/sstore"
|
||||||
"mvdan.cc/sh/v3/syntax"
|
"mvdan.cc/sh/v3/syntax"
|
||||||
)
|
)
|
||||||
@ -23,7 +24,13 @@ const (
|
|||||||
SimpleCompGenTypeVariable = "variable"
|
SimpleCompGenTypeVariable = "variable"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SimpleCompGenFnType = func(ctx context.Context, point SimpleCompPoint, rptr sstore.RemotePtrType, state *packet.ShellState, args []interface{})
|
type CompContext struct {
|
||||||
|
RemotePtr sstore.RemotePtrType
|
||||||
|
State *packet.ShellState
|
||||||
|
ForDisplay bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type SimpleCompGenFnType = func(ctx context.Context, point SimpleCompPoint, compCtx CompContext, args []interface{}) (*CompReturn, error)
|
||||||
|
|
||||||
type SimpleCompPoint struct {
|
type SimpleCompPoint struct {
|
||||||
Word string
|
Word string
|
||||||
@ -31,12 +38,14 @@ type SimpleCompPoint struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ParsedWord struct {
|
type ParsedWord struct {
|
||||||
Offset int
|
Offset int
|
||||||
Word string
|
Word *syntax.Word
|
||||||
Prefix string
|
PartialWord string
|
||||||
|
Prefix string
|
||||||
}
|
}
|
||||||
|
|
||||||
type CompPoint struct {
|
type CompPoint struct {
|
||||||
|
StmtStr string
|
||||||
Words []ParsedWord
|
Words []ParsedWord
|
||||||
CompWord int
|
CompWord int
|
||||||
CompWordPos int
|
CompWordPos int
|
||||||
@ -44,6 +53,38 @@ type CompPoint struct {
|
|||||||
Suffix string
|
Suffix string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *CompPoint) wordAsStr(w ParsedWord) string {
|
||||||
|
if w.Word != nil {
|
||||||
|
return p.StmtStr[w.Word.Pos().Offset():w.Word.End().Offset()]
|
||||||
|
}
|
||||||
|
return w.PartialWord
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *CompPoint) simpleExpandWord(w ParsedWord) string {
|
||||||
|
ectx := shexec.SimpleExpandContext{}
|
||||||
|
if w.Word != nil {
|
||||||
|
return SimpleExpandWord(ectx, w.Word, p.StmtStr)
|
||||||
|
}
|
||||||
|
return SimpleExpandPartialWord(ectx, p.PartialWord, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *CompPoint) compPrefix() string {
|
||||||
|
pword := p.Words[p.CompWord]
|
||||||
|
if p.CompWordPos == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
wordStr := p.wordAsStr(pword)
|
||||||
|
if p.CompWordPos == len(wordStr) {
|
||||||
|
return p.simpleExpandWord(pword)
|
||||||
|
}
|
||||||
|
// TODO we can do better, if p.Word is not nil, we can look for which WordPart
|
||||||
|
// our pos is in. we can then do a normal word expand on the previous parts
|
||||||
|
// and a partial on just the current part. this is an uncommon case though
|
||||||
|
// and has very little upside (even bash does not expand multipart words correctly)
|
||||||
|
partialWordStr := wordStr[:p.CompWordPos]
|
||||||
|
return SimpleExpandPartialWord(shexec.SimpleExpandContext{}, partialWordStr, false)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *CompPoint) dump() {
|
func (p *CompPoint) dump() {
|
||||||
if p.Prefix != "" {
|
if p.Prefix != "" {
|
||||||
fmt.Printf("prefix: %s\n", p.Prefix)
|
fmt.Printf("prefix: %s\n", p.Prefix)
|
||||||
@ -55,9 +96,9 @@ func (p *CompPoint) dump() {
|
|||||||
fmt.Printf("{%s}", w.Prefix)
|
fmt.Printf("{%s}", w.Prefix)
|
||||||
}
|
}
|
||||||
if idx == p.CompWord {
|
if idx == p.CompWord {
|
||||||
fmt.Printf("%s\n", strWithCursor(w.Word, p.CompWordPos))
|
fmt.Printf("%s\n", strWithCursor(p.wordAsStr(w), p.CompWordPos))
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%s\n", w.Word)
|
fmt.Printf("%s\n", p.wordAsStr(w))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.Suffix != "" {
|
if p.Suffix != "" {
|
||||||
@ -66,8 +107,10 @@ func (p *CompPoint) dump() {
|
|||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// directories will have a trailing "/"
|
||||||
type CompEntry struct {
|
type CompEntry struct {
|
||||||
Word string
|
Word string
|
||||||
|
IsMetaCmd bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type CompReturn struct {
|
type CompReturn struct {
|
||||||
@ -154,6 +197,7 @@ func ParseCompPoint(fullCmdStr string, pos int) (*CompPoint, error) {
|
|||||||
// fmt.Printf("found: ((%s))%s((%s))\n", rtnPoint.Prefix, strWithCursor(stmtStr, stmtPos), rtnPoint.Suffix)
|
// fmt.Printf("found: ((%s))%s((%s))\n", rtnPoint.Prefix, strWithCursor(stmtStr, stmtPos), rtnPoint.Suffix)
|
||||||
|
|
||||||
// now, find the word that the pos appears in within the stmt above
|
// now, find the word that the pos appears in within the stmt above
|
||||||
|
rtnPoint.StmtStr = stmtStr
|
||||||
stmtReader := strings.NewReader(stmtStr)
|
stmtReader := strings.NewReader(stmtStr)
|
||||||
lastWordPos := 0
|
lastWordPos := 0
|
||||||
parser.Words(stmtReader, func(w *syntax.Word) bool {
|
parser.Words(stmtReader, func(w *syntax.Word) bool {
|
||||||
@ -162,21 +206,22 @@ func ParseCompPoint(fullCmdStr string, pos int) (*CompPoint, error) {
|
|||||||
if int(w.Pos().Offset()) > lastWordPos {
|
if int(w.Pos().Offset()) > lastWordPos {
|
||||||
pword.Prefix = stmtStr[lastWordPos:w.Pos().Offset()]
|
pword.Prefix = stmtStr[lastWordPos:w.Pos().Offset()]
|
||||||
}
|
}
|
||||||
pword.Word = stmtStr[w.Pos().Offset():w.End().Offset()]
|
pword.Word = w
|
||||||
rtnPoint.Words = append(rtnPoint.Words, pword)
|
rtnPoint.Words = append(rtnPoint.Words, pword)
|
||||||
lastWordPos = int(w.End().Offset())
|
lastWordPos = int(w.End().Offset())
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
if lastWordPos < len(stmtStr) {
|
if lastWordPos < len(stmtStr) {
|
||||||
pword := ParsedWord{Offset: lastWordPos}
|
pword := ParsedWord{Offset: lastWordPos}
|
||||||
pword.Prefix, pword.Word = splitInitialWhitespace(stmtStr[lastWordPos:])
|
pword.Prefix, pword.PartialWord = splitInitialWhitespace(stmtStr[lastWordPos:])
|
||||||
rtnPoint.Words = append(rtnPoint.Words, pword)
|
rtnPoint.Words = append(rtnPoint.Words, pword)
|
||||||
}
|
}
|
||||||
if len(rtnPoint.Words) == 0 {
|
if len(rtnPoint.Words) == 0 {
|
||||||
rtnPoint.Words = append(rtnPoint.Words, ParsedWord{})
|
rtnPoint.Words = append(rtnPoint.Words, ParsedWord{})
|
||||||
}
|
}
|
||||||
for idx, w := range rtnPoint.Words {
|
for idx, w := range rtnPoint.Words {
|
||||||
if stmtPos > w.Offset && stmtPos <= w.Offset+len(w.Prefix)+len(w.Word) {
|
wordLen := len(rtnPoint.wordAsStr(w))
|
||||||
|
if stmtPos > w.Offset && stmtPos <= w.Offset+len(w.Prefix)+wordLen {
|
||||||
rtnPoint.CompWord = idx
|
rtnPoint.CompWord = idx
|
||||||
rtnPoint.CompWordPos = stmtPos - w.Offset - len(w.Prefix)
|
rtnPoint.CompWordPos = stmtPos - w.Offset - len(w.Prefix)
|
||||||
if rtnPoint.CompWordPos < 0 {
|
if rtnPoint.CompWordPos < 0 {
|
||||||
@ -184,7 +229,7 @@ func ParseCompPoint(fullCmdStr string, pos int) (*CompPoint, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// rtnPoint.dump()
|
rtnPoint.dump()
|
||||||
return &rtnPoint, nil
|
return &rtnPoint, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,8 +237,8 @@ func splitCompWord(p *CompPoint) {
|
|||||||
w := p.Words[p.CompWord]
|
w := p.Words[p.CompWord]
|
||||||
prefixPos := p.CompWordPos + len(w.Prefix)
|
prefixPos := p.CompWordPos + len(w.Prefix)
|
||||||
|
|
||||||
w1 := ParsedWord{Offset: w.Offset, Prefix: w.Prefix[:prefixPos], Word: ""}
|
w1 := ParsedWord{Offset: w.Offset, Prefix: w.Prefix[:prefixPos]}
|
||||||
w2 := ParsedWord{Offset: w.Offset + prefixPos, Prefix: w.Prefix[prefixPos:], Word: w.Word}
|
w2 := ParsedWord{Offset: w.Offset + prefixPos, Prefix: w.Prefix[prefixPos:], Word: w.Word, PartialWord: w.PartialWord}
|
||||||
p.CompWord = p.CompWord // the same (w1)
|
p.CompWord = p.CompWord // the same (w1)
|
||||||
p.CompWordPos = 0 // will be at 0 since w1 has a word length of 0
|
p.CompWordPos = 0 // will be at 0 since w1 has a word length of 0
|
||||||
var newWords []ParsedWord
|
var newWords []ParsedWord
|
||||||
|
54
pkg/comp/simplecomp.go
Normal file
54
pkg/comp/simplecomp.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package comp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/scripthaus-dev/mshell/pkg/packet"
|
||||||
|
"github.com/scripthaus-dev/sh2-server/pkg/remote"
|
||||||
|
)
|
||||||
|
|
||||||
|
func compsToCompReturn(comps []string, hasMore bool) *CompReturn {
|
||||||
|
var rtn CompReturn
|
||||||
|
rtn.HasMore = hasMore
|
||||||
|
for _, comp := range comps {
|
||||||
|
rtn.Entries = append(rtn.Entries, CompEntry{Word: comp})
|
||||||
|
}
|
||||||
|
return &rtn
|
||||||
|
}
|
||||||
|
|
||||||
|
func doCompGen(ctx context.Context, compCtx CompContext, prefix string, compType string, forDisplay bool) (*CompReturn, error) {
|
||||||
|
if !packet.IsValidCompGenType(compType) {
|
||||||
|
return nil, false, fmt.Errorf("/compgen invalid type '%s'", compType)
|
||||||
|
}
|
||||||
|
msh := remote.GetRemoteById(compCtx.RemotePtr.RemoteId)
|
||||||
|
if msh == nil {
|
||||||
|
return nil, false, fmt.Errorf("invalid remote '%s', not found", compCtx.RemotePtr)
|
||||||
|
}
|
||||||
|
cgPacket := packet.MakeCompGenPacket()
|
||||||
|
cgPacket.ReqId = uuid.New().String()
|
||||||
|
cgPacket.CompType = compType
|
||||||
|
cgPacket.Prefix = prefix
|
||||||
|
cgPacket.Cwd = compCtx.State.Cwd
|
||||||
|
resp, err := msh.PacketRpc(ctx, cgPacket)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
if err = resp.Err(); err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
comps := getStrArr(resp.Data, "comps")
|
||||||
|
hasMore := getBool(resp.Data, "hasmore")
|
||||||
|
return compsToCompReturn(conmps, hasMore), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SimpleCompFile(ctx context.Context, point SimpleCompPoint, compCtx CompContext, args []interface{}) (*CompReturn, error) {
|
||||||
|
pword := point.Words[p.CompWord]
|
||||||
|
prefix := ""
|
||||||
|
crtn, err := doCompGen(ctx, prefix, "file")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return crtn, nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user