From 4753646ff0b2c06a0ced819314c9626fdf7efe40 Mon Sep 17 00:00:00 2001 From: shaoying Date: Tue, 23 Jul 2019 09:31:43 +0800 Subject: [PATCH] add yac.fun --- etc/dotsfile/shy.vim | 2 +- src/contexts/cli/cli.go | 14 +- src/contexts/cli/version.go | 2 +- src/contexts/ctx/type.go | 12 +- src/contexts/mdb/mdb.go | 4 +- src/contexts/nfs/nfs.go | 55 ++---- src/contexts/yac/yac.go | 351 ++++++++++++++++++++++++++++++++---- src/examples/code/code.go | 46 +++++ src/toolkit/stmt.go | 27 ++- 9 files changed, 408 insertions(+), 105 deletions(-) diff --git a/etc/dotsfile/shy.vim b/etc/dotsfile/shy.vim index 1e431f56..6cc3013b 100644 --- a/etc/dotsfile/shy.vim +++ b/etc/dotsfile/shy.vim @@ -38,7 +38,7 @@ syn match shyCommand "\(^\|\t\| \|$(\)[a-zA-Z0-9_\.]\+\>" call Keys("Operator", ["new"]) call Keys("Statment", ["config", "cache"]) call Keys("Statment", ["return", "source"]) -call Keys("Statment", ["if", "for", "else", "else if", "end"]) +call Keys("Statment", ["if", "else", "else if", "for", "fun", "end"]) call Keys("Statment", ["let", "var"]) " context nfs call Keys("SubCommand", ["import", "export", "load", "save"]) diff --git a/src/contexts/cli/cli.go b/src/contexts/cli/cli.go index 3a6783d6..7face312 100644 --- a/src/contexts/cli/cli.go +++ b/src/contexts/cli/cli.go @@ -88,9 +88,6 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", "timer": &ctx.Config{Name: "timer", Value: map[string]interface{}{ "list": map[string]interface{}{}, "next": "", }, Help: "定时器"}, - "time": &ctx.Config{Name: "timer", Value: map[string]interface{}{ - "unit": 1000, "close": "open", - }, Help: "时间参数"}, "project": &ctx.Config{Name: "project", Value: map[string]interface{}{ "github": "https://github.com/shylinux/context", @@ -384,7 +381,7 @@ func main() { } else if e := cmd.Wait(); e != nil { m.Echo("error: ").Echo("%s\n", e) } - m.Conf("daemon", []string{h, "finish_time"}, time.Now().Format(m.Conf("time_format"))) + m.Conf("daemon", []string{h, "finish_time"}, time.Now().Format(m.Conf("time", "format"))) }) return e } @@ -547,7 +544,7 @@ func main() { if len(arg) == 0 { m.Confm("timer", "list", func(key string, timer map[string]interface{}) { m.Add("append", "key", key) - m.Add("append", "action_time", time.Unix(0, timer["action_time"].(int64)/int64(m.Confi("time", "unit"))*1000000000).Format(m.Conf("time_format"))) + m.Add("append", "action_time", time.Unix(0, timer["action_time"].(int64)/int64(m.Confi("time", "unit"))*1000000000).Format(m.Conf("time", "format"))) m.Add("append", "order", timer["order"]) m.Add("append", "time", timer["time"]) m.Add("append", "cmd", timer["cmd"]) @@ -649,11 +646,12 @@ func main() { Help: "查看时间, when: 输入的时间戳, 剩余参数是时间偏移", Form: map[string]int{"time_format": 1, "time_close": 1}, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + format := kit.Select(m.Conf("time", "format"), m.Option("time_format")) t, stamp := time.Now(), true if len(arg) > 0 { if i, e := strconv.ParseInt(arg[0], 10, 64); e == nil { t, stamp, arg = time.Unix(int64(i/int64(m.Confi("time", "unit"))), 0), false, arg[1:] - } else if n, e := time.ParseInLocation(m.Confx("time_format"), arg[0], time.Local); e == nil { + } else if n, e := time.ParseInLocation(format, arg[0], time.Local); e == nil { t, arg = n, arg[1:] } else { for _, v := range []string{"01-02", "2006-01-02", "15:04:05", "15:04"} { @@ -722,13 +720,13 @@ func main() { } } - m.Append("datetime", t.Format(m.Confx("time_format"))) + m.Append("datetime", t.Format(format)) m.Append("timestamp", t.Unix()*int64(m.Confi("time", "unit"))) if stamp { m.Echo("%d", t.Unix()*int64(m.Confi("time", "unit"))) } else { - m.Echo(t.Format(m.Confx("time_format"))) + m.Echo(t.Format(format)) } return }}, diff --git a/src/contexts/cli/version.go b/src/contexts/cli/version.go index f1aa710f..8f90a4e6 100644 --- a/src/contexts/cli/version.go +++ b/src/contexts/cli/version.go @@ -4,5 +4,5 @@ var version = struct { host string self int }{ - "2019-07-22 22:15:19", "ZYB-20190522USI", 199, + "2019-07-23 08:08:38", "com.mac_1", 209, } diff --git a/src/contexts/ctx/type.go b/src/contexts/ctx/type.go index eb021228..c7e50127 100644 --- a/src/contexts/ctx/type.go +++ b/src/contexts/ctx/type.go @@ -98,7 +98,7 @@ func (m *Message) Time(arg ...interface{}) string { } } - str := m.Conf("time_format") + str := m.Conf("time", "format") if len(arg) > 1 { str = fmt.Sprintf(arg[0].(string), arg[1:]...) } else if len(arg) > 0 { @@ -401,7 +401,7 @@ func (m *Message) Table(cbs ...interface{}) *Message { } //计算列宽 - space := m.Confx("table_space") + space := kit.Select(m.Conf("table", "space"), m.Option("table.space")) depth, width := 0, map[string]int{} for _, k := range m.Meta["append"] { if len(m.Meta[k]) > depth { @@ -420,9 +420,9 @@ func (m *Message) Table(cbs ...interface{}) *Message { if len(cbs) > 0 { cb = cbs[0].(func(maps map[string]string, list []string, line int) (goon bool)) } else { - row := m.Confx("table_row_sep") - col := m.Confx("table_col_sep") - compact := kit.Right(m.Confx("table_compact")) + row := kit.Select(m.Conf("table", "row_sep"), m.Option("table.row_sep")) + col := kit.Select(m.Conf("table", "col_sep"), m.Option("table.col_sep")) + compact := kit.Right(kit.Select(m.Conf("table", "compact"), m.Option("table.compact"))) cb = func(maps map[string]string, lists []string, line int) bool { for i, v := range lists { if k := m.Meta["append"][i]; compact { @@ -603,7 +603,7 @@ func (m *Message) Cmd(args ...interface{}) *Message { msg.Log("cmd", "%s %s %v %v", c.Name, key, arg, msg.Meta["option"]) msg.Hand = true x.Hand(msg, c, key, msg.Form(x, arg)...) - msg.Log("cmd", "%s %s %v %v", c.Name, key, len(msg.Meta["result"]), msg.Meta["append"]) + // msg.Log("cmd", "%s %s %v %v", c.Name, key, len(msg.Meta["result"]), msg.Meta["append"]) return target := msg.target diff --git a/src/contexts/mdb/mdb.go b/src/contexts/mdb/mdb.go index b692a018..7cc2b580 100644 --- a/src/contexts/mdb/mdb.go +++ b/src/contexts/mdb/mdb.go @@ -575,8 +575,8 @@ var Index = &ctx.Context{Name: "mdb", Help: "数据中心", }}, "note": &ctx.Command{Name: "note [model [name [type name]...]]|[index [name data...]]|[value name data...]|[name model data...]", Form: map[string]int{"eq": 2, "begin": 2, "offset": 1, "limit": 1}, Help: "记事", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - offset := kit.Int(kit.Select(m.Conf("page_offset"), m.Option("offset"))) - limit := kit.Int(kit.Select(m.Conf("page_limit"), m.Option("limit"))) + offset := kit.Int(kit.Select(m.Conf("table", "offset"), m.Option("table.offset"))) + limit := kit.Int(kit.Select(m.Conf("table", "limit"), m.Option("table.limit"))) // 节点列表 if len(arg) == 0 { diff --git a/src/contexts/nfs/nfs.go b/src/contexts/nfs/nfs.go index 67b0ed15..6d235851 100644 --- a/src/contexts/nfs/nfs.go +++ b/src/contexts/nfs/nfs.go @@ -921,9 +921,10 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { } // 语句堆栈 - stack := kit.Stack{} + stack := &kit.Stack{} stack.Push(m.Option("stack.key", "source"), m.Options("stack.run", true), m.Optioni("stack.pos", 0)) m.Optionv("bio.ctx", m.Target()) + m.Optionv("bio.stack", stack) line, bio := "", bufio.NewScanner(nfs) for nfs.prompt(); ; nfs.prompt() { @@ -948,27 +949,11 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { // 解析数据 for i := m.Capi("ninput") - 1; i < m.Capi("ninput"); i++ { line = m.Conf("input", []interface{}{i, "line"}) - - // 结束语句 - if strings.TrimSpace(line) == "end" { - m.Log("stack", "pop: %v", stack.Peek().String("/")) - if stack.Pop(); m.Options("stack.run") && m.Option("stack.key") == "for" { - i = m.Optioni("stack.pos") - 1 - } - frame := stack.Peek() - m.Options("stack.run", frame.Run) - m.Option("stack.key", frame.Key) - continue - } - - // 跳过语句 - if !m.Options("stack.run") && !strings.HasPrefix(strings.TrimSpace(line), "else") { - m.Log("stack", "skip %v", line) - continue - } + m.Optionv("input", m.Confv("input")) + m.Optioni("stack.pos", i) // 执行语句 - msg := m.Cmd("yac.parse", line+"\n").Set("option", "bio.pos", i) + msg := m.Cmd("yac.parse", line+"\n") nfs.print(m.Conf("prompt"), line) nfs.print(msg.Meta["result"]...) @@ -977,21 +962,6 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { m.Optionv("bio.ctx", v) } - // 压栈语句 - if msg.Has("stack.key") { - m.Log("stack", "push %v", stack.Push( - m.Option("stack.key", msg.Append("stack.key")), - m.Options("stack.run", msg.Appends("stack.run")), - m.Optioni("stack.pos", i), - ).String("\\")) - } - if msg.Has("stack.run") { - m.Log("stack", "set: run = %v", m.Options("stack.run", msg.Appends("stack.run"))) - } - if msg.Has("stack.else") { - m.Options("stack.else", msg.Appends("stack.else")) - } - // 跳转语句 if msg.Appends("bio.pos0") { i = int(msg.Appendi("bio.pos0")) - 1 @@ -1002,7 +972,8 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { if msg.Appends("bio.end") { m.Copy(msg, "append") m.Copy(msg, "result") - break + msg.Appends("bio.end", "") + return true } } line = "" @@ -1060,7 +1031,7 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { msg.Add(field, value) case "": - m.Log("recv", "time %v", time.Now().Format(m.Conf("time_format"))) + m.Log("recv", "time %v", time.Now().Format(m.Conf("time", "format"))) if head == "detail" { // 接收请求 msg.Detail(-1, "_route") msg.Option("remote_code", code) @@ -1210,7 +1181,7 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心", "commit": map[string]interface{}{"args": []interface{}{"commit", "-am"}}, "branch": map[string]interface{}{"args": []interface{}{"branch", "-v"}}, "status": map[string]interface{}{"args": []interface{}{"status", "-sb"}}, - "log": map[string]interface{}{"args": []interface{}{"log", "-n", "@page.limit", "--skip", "@page.offset", "pretty", "date"}}, + "log": map[string]interface{}{"args": []interface{}{"log", "-n", "@table.limit", "--skip", "@table.offset", "pretty", "date"}}, "trans": map[string]interface{}{ "date": "--date=format:%m/%d %H:%M", "pretty": "--pretty=format:%h %ad %an %s", @@ -1319,7 +1290,7 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心", if s.IsDir() { dir(m, p, 0, kit.Right(m.Has("dir_deep")), m.Confx("dir_type"), trip, rg, strings.Split(m.Confx("dir_fields", strings.Join(arg[1:], " ")), " "), - m.Conf("time_format")) + m.Conf("time", "format")) } else { if s.Size() < int64(m.Confi("buf_size")) { p0 := p + ".tmp0" @@ -1336,7 +1307,7 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心", } m.Append("file", p) m.Append("size", s.Size()) - m.Append("time", s.ModTime().Format(m.Conf("time_format"))) + m.Append("time", s.ModTime().Format(m.Conf("time", "format"))) } else { m.Append("directory", p) } @@ -1496,7 +1467,7 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心", n := 0 offset := kit.Int(value["offset"]) bio := bufio.NewScanner(f) - for i := 0; i < m.Optioni("page.limit") && bio.Scan(); i++ { + for i := 0; i < m.Optioni("table.limit") && bio.Scan(); i++ { text := bio.Text() if len(arg) == 0 || strings.Contains(text, arg[0]) { m.Add("append", "index", index) @@ -1689,7 +1660,7 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心", m.Option("filepath", p) m.Option("filename", s.Name()) m.Option("filesize", s.Size()) - m.Option("filetime", s.ModTime().Format(m.Conf("time_format"))) + m.Option("filetime", s.ModTime().Format(m.Conf("time", "format"))) switch { case strings.HasSuffix(arg[0], ".json"): diff --git a/src/contexts/yac/yac.go b/src/contexts/yac/yac.go index cdfc0c79..fe6e86cf 100644 --- a/src/contexts/yac/yac.go +++ b/src/contexts/yac/yac.go @@ -191,7 +191,7 @@ func (yac *YAC) train(m *ctx.Message, page, hash int, word []string, level int) m.Log("debug", "%s %s/%d word: %d point: %d end: %d", "train", strings.Repeat("#", level), level, len(word), len(points), len(ends)) return len(word), points, ends } -func (yac *YAC) parse(m *ctx.Message, msg *ctx.Message, page int, void int, line string, level int) (string, []string, int) { +func (yac *YAC) parse(m *ctx.Message, msg *ctx.Message, stack *kit.Stack, page int, void int, line string, level int) (string, []string, int) { m.Log("debug", "%s %s\\%d %s(%d): %s", "parse", strings.Repeat("#", level), level, yac.name(page), page, line) lex, hash, word := yac.lex, 0, []string{} @@ -223,7 +223,7 @@ func (yac *YAC) parse(m *ctx.Message, msg *ctx.Message, page int, void int, line if state == nil { for i := 0; i < m.Confi("meta", "ncell"); i++ { if x := yac.mat[s][byte(i)]; i < m.Confi("meta", "nlang") && x != nil { - if l, w, _ := yac.parse(m, msg, i, void, line, level+1); l != line { + if l, w, _ := yac.parse(m, msg, stack, i, void, line, level+1); l != line { line, word, state = l, append(word, w...), x break } @@ -242,19 +242,16 @@ func (yac *YAC) parse(m *ctx.Message, msg *ctx.Message, page int, void int, line if hash == 0 { word = word[:0] - } else if !m.Confs("exec", []string{yac.hand[hash], "disable"}) { - //执行命令 - cmd := msg.Spawn(m.Optionv("bio.ctx")) - if cmd.Cmd(yac.hand[hash], word); cmd.Hand { - word = cmd.Meta["result"] - } - //切换模块 - if v := cmd.Optionv("bio.ctx"); v != nil { - m.Optionv("bio.ctx", v) - } - for _, key := range []string{"stack.key", "stack.run", "stack.else"} { - if cmd.Has(key) { - msg.Appends(key, cmd.Appends(key)) + } else if !m.Confs("exec", []string{"disable", yac.hand[hash]}) { + if stack.Peek().Run || m.Confs("exec", []string{"always", yac.hand[hash]}) { + //执行命令 + cmd := msg.Spawn(m.Optionv("bio.ctx")) + if cmd.Cmd(yac.hand[hash], word); cmd.Hand { + word = cmd.Meta["result"] + } + //切换模块 + if v := cmd.Optionv("bio.ctx"); v != nil { + m.Optionv("bio.ctx", v) } } } @@ -336,6 +333,8 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心", map[string]interface{}{"page": "stm", "hash": "for", "word": []interface{}{"for", "rep{", "exp", "}"}}, map[string]interface{}{"page": "stm", "hash": "else", "word": []interface{}{"else", "opt{", "if", "exp", "}"}}, map[string]interface{}{"page": "stm", "hash": "end", "word": []interface{}{"end"}}, + + map[string]interface{}{"page": "stm", "hash": "fun", "word": []interface{}{"fun", "key", "rep{", "key", "}"}}, /* map[string]interface{}{"page": "op1", "hash": "op1", "word": []interface{}{"mul{", "-z", "-n", "}"}}, @@ -359,14 +358,37 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心", }, Help: "语法集合的最大数量"}, "exec": &ctx.Config{Name: "info", Value: map[string]interface{}{ - "void": map[string]interface{}{"disable": true}, - "num": map[string]interface{}{"disable": true}, - "key": map[string]interface{}{"disable": true}, - "op1": map[string]interface{}{"disable": true}, - "op2": map[string]interface{}{"disable": true}, - "word": map[string]interface{}{"disable": true}, - "line": map[string]interface{}{"disable": true}, + "disable": map[string]interface{}{ + "void": true, + "num": true, + "key": true, + "op1": true, + "op2": true, + "word": true, + "line": true, + }, + "always": map[string]interface{}{ + "if": true, + "else": true, + "end": true, + "for": true, + }, }, Help: "嵌套层级日志的标记"}, + + "alias": &ctx.Config{Name: "alias", Value: map[string]interface{}{ + "~": []string{"context"}, + "!": []string{"message"}, + ":": []string{"command"}, + "::": []string{"command", "list"}, + + "note": []string{"mdb.note"}, + "pwd": []string{"nfs.pwd"}, + "path": []string{"nfs.path"}, + "dir": []string{"nfs.dir"}, + "git": []string{"nfs.git"}, + "brow": []string{"web.brow"}, + "ifconfig": []string{"tcp.ifconfig"}, + }, Help: "启动脚本"}, }, Commands: map[string]*ctx.Command{ "_init": &ctx.Command{Name: "_init", Help: "添加语法规则, page: 语法集合, hash: 语句类型, word: 语法模板", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { @@ -398,10 +420,11 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心", }}, "parse": &ctx.Command{Name: "parse line", Help: "解析语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { if yac, ok := m.Target().Server.(*YAC); m.Assert(ok) { + stack := m.Optionv("bio.stack").(*kit.Stack) m.Optioni("yac.page", yac.page[m.Conf("nline")]) m.Optioni("yac.void", yac.page[m.Conf("nvoid")]) - _, word, _ := yac.parse(m, m, m.Optioni("yac.page"), m.Optioni("yac.void"), arg[0], 1) + _, word, _ := yac.parse(m, m, stack, m.Optioni("yac.page"), m.Optioni("yac.void"), arg[0], 1) m.Result(word) } return @@ -742,21 +765,282 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心", "com": &ctx.Command{Name: "com", Help: "解析注释", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { return }}, + "cmd": &ctx.Command{Name: "cmd word", Help: "解析命令", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + // 解析别名 + detail := []string{} + if alias, ok := m.Confv("alias", arg[0]).([]string); ok { + detail, arg = append(detail, alias...), arg[1:] + } + detail = append(detail, arg...) + + // 目标切换 + target := m.Optionv("bio.ctx") + if detail[0] != "context" { + defer func() { m.Optionv("bio.ctx", target) }() + } + + // 解析脚本 + msg := m + for k, v := range m.Confv("system", "script").(map[string]interface{}) { + if strings.HasSuffix(detail[0], "."+k) { + msg = m.Spawn(m.Optionv("bio.ctx")) + detail[0] = m.Cmdx("nfs.path", detail[0]) + detail = append([]string{v.(string)}, detail...) + break + } + } + + // 解析路由 + if msg == m { + if routes := strings.Split(detail[0], "."); len(routes) > 1 && !strings.Contains(detail[0], ":") { + route := strings.Join(routes[:len(routes)-1], ".") + if msg = m.Find(route, false); msg == nil { + msg = m.Find(route, true) + } + + if msg == nil { + m.Echo("%s not exist", route) + return + } + detail[0] = routes[len(routes)-1] + } else { + msg = m.Spawn(m.Optionv("bio.ctx")) + } + } + msg.Copy(m, "option").Copy(m, "append") + + // 解析命令 + args, rest := []string{}, []string{} + exports := []map[string]string{} + exec, execexec := true, false + for i := 0; i < len(detail); i++ { + switch detail[i] { + case "?": + if !kit.Right(detail[i+1]) { + return + } + i++ + case "??": + exec = false + execexec = execexec || kit.Right(detail[i+1]) + i++ + case "<": + m.Cmdy("nfs.import", detail[i+1]) + i++ + case ">": + exports = append(exports, map[string]string{"file": detail[i+1]}) + i++ + case ">$": + if i == len(detail)-2 { + exports = append(exports, map[string]string{"cache": detail[i+1], "index": "result"}) + i += 1 + break + } + exports = append(exports, map[string]string{"cache": detail[i+1], "index": detail[i+2]}) + i += 2 + case ">@": + if i == len(detail)-2 { + exports = append(exports, map[string]string{"config": detail[i+1], "index": "result"}) + i += 1 + break + } + exports = append(exports, map[string]string{"config": detail[i+1], "index": detail[i+2]}) + i += 2 + case "|": + detail, rest = detail[:i], detail[i+1:] + case "%": + rest = append(rest, "select") + detail, rest = detail[:i], append(rest, detail[i+1:]...) + default: + args = append(args, detail[i]) + } + } + if !exec && !execexec { + return + } + + // 执行命令 + if msg.Set("detail", args).Cmd(); !msg.Hand { + msg.Cmd("system", args) + } + if msg.Appends("bio.ctx1") { + target = msg.Target() + } + + // 管道命令 + if len(rest) > 0 { + pipe := msg.Spawn() + pipe.Copy(msg, "append").Copy(msg, "result").Cmd("cmd", rest) + msg.Set("append").Copy(pipe, "append") + msg.Set("result").Copy(pipe, "result") + } + + // 导出结果 + for _, v := range exports { + if v["file"] != "" { + m.Sess("nfs").Copy(msg, "option").Copy(msg, "append").Copy(msg, "result").Cmd("export", v["file"]) + msg.Set("result") + } + if v["cache"] != "" { + if v["index"] == "result" { + m.Cap(v["cache"], strings.Join(msg.Meta["result"], "")) + } else { + m.Cap(v["cache"], msg.Append(v["index"])) + } + } + if v["config"] != "" { + if v["index"] == "result" { + m.Conf(v["config"], strings.Join(msg.Meta["result"], "")) + } else { + m.Conf(v["config"], msg.Append(v["index"])) + } + } + } + + // 返回结果 + m.Optionv("bio.ctx", msg.Target()) + m.Set("append").Copy(msg, "append") + m.Set("result").Copy(msg, "result") + return + }}, + "alias": &ctx.Command{Name: "alias [short [long...]]|[delete short]|[import module [command [alias]]]", + Help: "查看、定义或删除命令别名, short: 命令别名, long: 命令原名, delete: 删除别名, import导入模块所有命令", + Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + switch len(arg) { + case 0: + m.Cmdy("ctx.config", "alias") + case 1: + m.Cmdy("ctx.config", "alias", arg[0]) + default: + switch arg[0] { + case "delete": + alias := m.Confm("alias") + m.Echo("delete: %s %v\n", arg[1], alias[arg[1]]) + delete(alias, arg[1]) + case "import": + msg := m.Find(arg[1], false) + if msg == nil { + msg = m.Find(arg[1], true) + } + if msg == nil { + m.Echo("%s not exist", arg[1]) + return + } + + module := msg.Cap("module") + for k, _ := range msg.Target().Commands { + if len(k) > 0 && k[0] == '/' { + continue + } + + if len(arg) == 2 { + m.Confv("alias", k, []string{module + "." + k}) + m.Log("info", "import %s.%s", module, k) + continue + } + + if key := k; k == arg[2] { + if len(arg) > 3 { + key = arg[3] + } + m.Confv("alias", key, []string{module + "." + k}) + m.Log("info", "import %s.%s as %s", module, k, key) + break + } + } + default: + m.Confv("alias", arg[0], arg[1:]) + m.Log("info", "%s: %v", arg[0], arg[1:]) + } + } + return + }}, "if": &ctx.Command{Name: "if exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - m.Appends("stack.else", true) - m.Push("stack.key", arg[0]) - m.Push("stack.run", m.Options("stack.run") && kit.Right(arg[1])) - if m.Appends("stack.run") { - m.Appends("stack.else", false) + stack := m.Optionv("bio.stack").(*kit.Stack) + p := stack.Push(arg[0], stack.Peek().Run && kit.Right(arg[1]), m.Optioni("stack.pos")) + m.Log("stack", "push %v", p.String("\\")) + if p.Run { + p.Done = true } return }}, + "else": &ctx.Command{Name: "else", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + p := m.Optionv("bio.stack").(*kit.Stack).Peek() + p.Run = !p.Done && !p.Run && (len(arg) == 1 || kit.Right(arg[2])) + m.Log("stack", "set: run = %v", p.Run) + if p.Run { + p.Done = true + } + return + }}, + "end": &ctx.Command{Name: "end", Help: "结束语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + p := m.Optionv("bio.stack").(*kit.Stack).Pop() + m.Log("stack", "pop: %v", p.String("/")) + switch p.Key { + case "for": + if p.Run { + m.Appendi("bio.pos0", p.Pos) + } + case "fun": + end := m.Optioni("stack.pos") + self := p.Data.(*ctx.Command) + help := []string{} + for i, v := range m.Optionv("input").([]interface{}) { + if p.Pos < i && i < end { + val := v.(map[string]interface{}) + help = append(help, val["line"].(string)) + } + } + self.Help = help + } + + return + }}, + "fun": &ctx.Command{Name: "fun", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + p := m.Optionv("bio.stack").(*kit.Stack).Push(arg[0], false, m.Optioni("stack.pos")) + m.Log("stack", "push %v", p.String("\\")) + + self := &ctx.Command{Name: strings.Join(arg[1:], " "), Help: []string{"pwd", "ls"}} + self.Hand = func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + stack := &kit.Stack{} + stack.Push("fun", true, 0) + m.Optionv("bio.stack", stack) + help := self.Help.([]string) + + // 解析数据 + for i := 0; i < len(help); i++ { + line := help[i] + m.Optioni("stack.pos", i) + + // 执行语句 + msg := m.Cmd("yac.parse", line+"\n") + + // 跳转语句 + if msg.Appends("bio.pos0") { + i = int(msg.Appendi("bio.pos0")) - 1 + msg.Append("bio.pos0", "") + } + + // 结束脚本 + if msg.Appends("bio.end") { + m.Copy(msg, "append") + m.Copy(msg, "result") + msg.Appends("bio.end", "") + break + } + } + return + } + m.Target().Commands[arg[1]] = self + p.Data = self + return + }}, "for": &ctx.Command{Name: "for [[express ;] condition]|[index message meta value]", Help: "循环语句, express: 每次循环运行的表达式, condition: 循环条件, index: 索引消息, message: 消息编号, meta: value: ", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - m.Push("stack.key", arg[0]) - m.Push("stack.run", m.Options("stack.run") && kit.Right(arg[1])) + stack := m.Optionv("bio.stack").(*kit.Stack) + m.Log("stack", "push %v", stack.Push(arg[0], stack.Peek().Run && kit.Right(arg[1]), m.Optioni("stack.pos")).String("\\")) /* if cli, ok := m.Target().Server.(*YAC); m.Assert(ok) { @@ -816,13 +1100,6 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心", */ return }}, - "else": &ctx.Command{Name: "else", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - m.Appends("stack.run", m.Options("stack.else") && !m.Options("stack.run") && (len(arg) == 1 || kit.Right(arg[2]))) - if m.Appends("stack.run") { - m.Appends("stack.else", false) - } - return - }}, "label": &ctx.Command{Name: "label name", Help: "记录当前脚本的位置, name: 位置名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { if cli, ok := m.Target().Server.(*YAC); m.Assert(ok) { diff --git a/src/examples/code/code.go b/src/examples/code/code.go index cb63b93b..3ea6ab86 100644 --- a/src/examples/code/code.go +++ b/src/examples/code/code.go @@ -525,6 +525,52 @@ var Index = &ctx.Context{Name: "code", Help: "代码中心", } return }}, + "tmux": &ctx.Command{Name: "tmux buffer", Help: "终端管理, buffer: 查看复制", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + switch arg[0] { + case "buffer": + bufs := strings.Split(m.Spawn().Cmd("system", "tmux", "list-buffers").Result(0), "\n") + + n := 3 + if m.Option("limit") != "" { + n = m.Optioni("limit") + } + + for i, b := range bufs { + if i >= n { + break + } + bs := strings.SplitN(b, ": ", 3) + if len(bs) > 1 { + m.Add("append", "buffer", bs[0][:len(bs[0])]) + m.Add("append", "length", bs[1][:len(bs[1])-6]) + m.Add("append", "strings", bs[2][1:len(bs[2])-1]) + } + } + + if m.Option("index") == "" { + m.Echo(m.Spawn().Cmd("system", "tmux", "show-buffer").Result(0)) + } else { + m.Echo(m.Spawn().Cmd("system", "tmux", "show-buffer", "-b", m.Option("index")).Result(0)) + } + } + return + }}, + "windows": &ctx.Command{Name: "windows", Help: "windows", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + m.Append("nclient", strings.Count(m.Spawn().Cmd("system", "tmux", "list-clients").Result(0), "\n")) + m.Append("nsession", strings.Count(m.Spawn().Cmd("system", "tmux", "list-sessions").Result(0), "\n")) + m.Append("nwindow", strings.Count(m.Spawn().Cmd("system", "tmux", "list-windows", "-a").Result(0), "\n")) + m.Append("npane", strings.Count(m.Spawn().Cmd("system", "tmux", "list-panes", "-a").Result(0), "\n")) + + m.Append("nbuf", strings.Count(m.Spawn().Cmd("system", "tmux", "list-buffers").Result(0), "\n")) + m.Append("ncmd", strings.Count(m.Spawn().Cmd("system", "tmux", "list-commands").Result(0), "\n")) + m.Append("nkey", strings.Count(m.Spawn().Cmd("system", "tmux", "list-keys").Result(0), "\n")) + m.Table() + return + }}, + "notice": &ctx.Command{Name: "notice", Help: "睡眠, time(ns/us/ms/s/m/h): 时间值(纳秒/微秒/毫秒/秒/分钟/小时)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + m.Cmd("cli.system", "osascript", "-e", fmt.Sprintf("display notification \"%s\"", kit.Select("", arg, 0))) + return + }}, }, } diff --git a/src/toolkit/stmt.go b/src/toolkit/stmt.go index 3e972e3e..3b577776 100644 --- a/src/toolkit/stmt.go +++ b/src/toolkit/stmt.go @@ -11,25 +11,36 @@ type Frame struct { Pos int deep int // list []string + Done bool + Data interface{} } func (f *Frame) String(meta string) string { return fmt.Sprintf("%s%s%d %s %t", strings.Repeat("#", f.deep), meta, f.deep, f.Key, f.Run) } +var bottom = &Frame{} + type Stack struct { - fs []*Frame + Target interface{} + fs []*Frame } +func (s *Stack) Push(key string, run bool, pos int) *Frame { + s.fs = append(s.fs, &Frame{Key: key, Run: run, Pos: pos, deep: len(s.fs)}) + return s.fs[len(s.fs)-1] +} +func (s *Stack) Peek() *Frame { + if len(s.fs) == 0 { + return bottom + } + return s.fs[len(s.fs)-1] +} func (s *Stack) Pop() *Frame { + if len(s.fs) == 0 { + return bottom + } f := s.fs[len(s.fs)-1] s.fs = s.fs[:len(s.fs)-1] return f } -func (s *Stack) Push(key string, run bool, pos int) *Frame { - s.fs = append(s.fs, &Frame{key, run, pos, len(s.fs)}) - return s.fs[len(s.fs)-1] -} -func (s *Stack) Peek() *Frame { - return s.fs[len(s.fs)-1] -}