From d9daf68f2b19b9965b9e2b5e0b3b1dfe128e99ff Mon Sep 17 00:00:00 2001 From: shaoying Date: Sun, 3 Nov 2019 19:26:05 +0800 Subject: [PATCH] new web.code --- bin/boot.sh | 5 +- src/contexts/cli/cli.go | 36 ++++- src/contexts/cli/version.go | 2 +- src/contexts/ctx/cgi.go | 5 + src/contexts/ctx/type.go | 111 ++++++++++++- src/contexts/yac/yac.go | 22 +-- src/examples/code/code.go | 301 ++++++++++++++++++++++++++++++++++-- src/plugin/docker/index.css | 3 + src/plugin/docker/index.go | 36 +++++ src/plugin/docker/index.js | 3 + src/plugin/docker/index.shy | 49 ++++++ src/toolkit/misc.go | 40 +++++ usr/librarys/example.js | 85 ++++++++-- usr/librarys/toolkit.js | 11 +- 14 files changed, 651 insertions(+), 58 deletions(-) create mode 100644 src/plugin/docker/index.css create mode 100644 src/plugin/docker/index.go create mode 100644 src/plugin/docker/index.js create mode 100644 src/plugin/docker/index.shy diff --git a/bin/boot.sh b/bin/boot.sh index eb5d3fb0..a62d17e9 100755 --- a/bin/boot.sh +++ b/bin/boot.sh @@ -48,12 +48,13 @@ install() { echo echo - curl -o ${ctx_app} "$ctx_dev/publish/${ctx_app}?GOOS=$GOOS&GOARCH=$GOARCH" && chmod a+x ${ctx_app} || return + wget -O ${ctx_app} "$ctx_dev/publish/bench?GOOS=$GOOS&GOARCH=$GOARCH" && chmod a+x ${ctx_app} || return target=install && [ -n "$1" ] && target=$1 ${md5} ${ctx_app} && ./${ctx_app} upgrade ${target} || return - mv ${ctx_app} bin/${ctx_app} && bin/boot.sh + mv ${ctx_app} bin/${ctx_app} + # && bin/boot.sh } main() { trap HUP hup diff --git a/src/contexts/cli/cli.go b/src/contexts/cli/cli.go index 3a4d465d..74056345 100644 --- a/src/contexts/cli/cli.go +++ b/src/contexts/cli/cli.go @@ -69,18 +69,38 @@ func format(m *ctx.Message, out *bytes.Buffer) { } m.Table() case "cut": - c := byte(kit.Select(" ", m.Optionv("cmd_parse"), 2)[0]) + c := byte(kit.Select(" ", m.Optionv("cmd_parse"), 1)[0]) bio := bufio.NewScanner(out) + pos := []int{} heads := []string{} if h := kit.Select("", m.Optionv("cmd_parse"), 3); h != "" { heads = strings.Split(h, " ") } else if bio.Scan() { - heads = kit.Split(bio.Text(), c, kit.Int(kit.Select("-1", m.Optionv("cmd_parse"), 1))) + h := bio.Text() + v := kit.Trans(m.Optionv("cmd_headers")) + for i := 0; i < len(v)-1; i += 2 { + h = strings.Replace(h, v[i], v[i+1], 1) + } + + heads = kit.Split(h, c, kit.Int(kit.Select("-1", m.Optionv("cmd_parse"), 2))) + for _, v := range heads { + pos = append(pos, strings.Index(h, v)) + } } for bio.Scan() { + if len(pos) > 0 { + for i, v := range pos { + if i == len(pos)-1 { + m.Add("append", heads[i], bio.Text()[v:]) + } else { + m.Add("append", heads[i], bio.Text()[v:pos[i+1]]) + } + } + continue + } for i, v := range kit.Split(bio.Text(), c, len(heads)) { m.Add("append", heads[i], v) } @@ -306,12 +326,13 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", "cmd_timeout: 命令超时", "cmd_active(true/false): 是否交互", "cmd_daemon(true/false): 是否守护", - "cmd_dir: 工作目录", "cmd_env key value: 环境变量", + "cmd_dir: 工作目录", "cmd_log: 输出日志", - "cmd_temp arg...: 缓存结果", - "cmd_parse format|json|csv|cli|cut [count sep]: 解析结果", "cmd_error: 输出错误", + "cmd_temp arg...: 缓存结果", + "cmd_parse format|json|csv|cli|cut [count sep headers]: 解析结果", + "cmd_headers", }, Form: map[string]int{ "cmd_timeout": 1, "cmd_active": 1, @@ -323,6 +344,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", "cmd_parse": 4, "cmd_error": 0, "cmd_select": -1, + "cmd_headers": 2, "app_log": 1, }, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { // 管道参数 @@ -865,7 +887,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", if len(arg) == 1 { m.Cmdy("nfs.git", "sum", "-n", 20) } else { - m.Cmdy("nfs.git", "sum", "-n", arg[1:]) + m.Cmdy("nfs.git", "sum", "--reverse", "--since", arg[1:]) } case "trends": @@ -920,7 +942,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", // 编译项目 if m.Cmdy("cli.compile", ""); m.Has("bin") { - target := path.Join(kit.Select(os.Getenv("GOBIN"), ""), m.Conf("compile", "name")) + target := path.Join(kit.Select(os.Getenv("GOBIN"), ""), m.Conf("runtime", "boot.ctx_app")) os.Remove(target) m.Append("bin", m.Cmdx("nfs.copy", target, m.Append("bin"))) os.Chmod(target, 0777) diff --git a/src/contexts/cli/version.go b/src/contexts/cli/version.go index e58fba82..b9074099 100644 --- a/src/contexts/cli/version.go +++ b/src/contexts/cli/version.go @@ -7,5 +7,5 @@ var version = struct { self int }{ []string{"2017-11-01 01:02:03", "2019-07-13 18:02:21"}, - `2019-11-01 14:34:16`, `mac`, 657, + `2019-11-03 00:13:51`, `mac`, 659, } diff --git a/src/contexts/ctx/cgi.go b/src/contexts/ctx/cgi.go index ee5ddb60..96e79a98 100644 --- a/src/contexts/ctx/cgi.go +++ b/src/contexts/ctx/cgi.go @@ -109,3 +109,8 @@ func ExecuteFile(m *Message, w io.Writer, p string) error { tmpl.ParseGlob(p) return tmpl.ExecuteTemplate(w, path.Base(p), m) } +func ExecuteStr(m *Message, w io.Writer, p string) error { + tmpl := template.New("render").Funcs(CGI) + tmpl, _ = tmpl.Parse(p) + return tmpl.Execute(w, m) +} diff --git a/src/contexts/ctx/type.go b/src/contexts/ctx/type.go index 78f4cb82..790dc7df 100644 --- a/src/contexts/ctx/type.go +++ b/src/contexts/ctx/type.go @@ -250,8 +250,15 @@ func (m *Message) Push(str string, arg ...interface{}) *Message { } func (m *Message) Sort(key string, arg ...string) *Message { cmp := "str" - if len(arg) > 0 { + if len(arg) > 0 && arg[0] != "" { cmp = arg[0] + } else { + cmp = "int" + for _, v := range m.Meta[key] { + if _, e := strconv.Atoi(v); e != nil { + cmp = "str" + } + } } number := map[int]int{} @@ -274,7 +281,7 @@ func (m *Message) Sort(key string, arg ...string) *Message { for j := i + 1; j < len(table); j++ { result := false switch cmp { - case "str": + case "", "str": if table[i][key] > table[j][key] { result = true } @@ -306,6 +313,106 @@ func (m *Message) Sort(key string, arg ...string) *Message { } return m } +func (m *Message) Limit(offset, limit int) *Message { + l := len(m.Meta[m.Meta["append"][0]]) + if offset < 0 { + offset = 0 + } + if offset > l { + offset = l + } + if offset+limit > l { + limit = l - offset + } + for _, k := range m.Meta["append"] { + m.Meta[k] = m.Meta[k][offset : offset+limit] + } + return m +} +func (m *Message) Filter(value string) *Message { + + return m +} +func (m *Message) Group(method string, args ...string) *Message { + + nrow := len(m.Meta[m.Meta["append"][0]]) + + keys := map[string]bool{} + for _, v := range args { + keys[v] = true + } + + counts := []int{} + mis := map[int]bool{} + for i := 0; i < nrow; i++ { + counts = append(counts, 1) + if mis[i] { + continue + } + next: + for j := i + 1; j < nrow; j++ { + if mis[j] { + continue + } + for key := range keys { + if m.Meta[key][i] != m.Meta[key][j] { + continue next + } + } + for _, k := range m.Meta["append"] { + if !keys[k] { + switch method { + case "sum", "avg": + v1, e1 := strconv.Atoi(m.Meta[k][i]) + v2, e2 := strconv.Atoi(m.Meta[k][j]) + if e1 == nil && e2 == nil { + m.Meta[k][i] = fmt.Sprintf("%d", v1+v2) + } + } + } + } + mis[j] = true + counts[i]++ + } + } + + for i := 0; i < nrow; i++ { + for _, k := range m.Meta["append"] { + if !keys[k] { + switch method { + case "avg": + if v1, e1 := strconv.Atoi(m.Meta[k][i]); e1 == nil { + m.Meta[k][i] = strconv.Itoa(v1 / counts[i]) + } + } + } + } + } + for i := 0; i < nrow; i++ { + m.Push("_counts", counts[i]) + } + + for i := 0; i < nrow; i++ { + if mis[i] { + for j := i + 1; j < nrow; j++ { + if !mis[j] { + for _, k := range m.Meta["append"] { + m.Meta[k][i] = m.Meta[k][j] + } + mis[i], mis[j] = false, true + break + } + } + } + if mis[i] { + for _, k := range m.Meta["append"] { + m.Meta[k] = m.Meta[k][0:i] + } + break + } + } + return m +} func (m *Message) Table(cbs ...interface{}) *Message { if len(m.Meta["append"]) == 0 { return m diff --git a/src/contexts/yac/yac.go b/src/contexts/yac/yac.go index 2f60f17c..b527f852 100644 --- a/src/contexts/yac/yac.go +++ b/src/contexts/yac/yac.go @@ -1135,7 +1135,9 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心", } args := arg[i : j+1] if arg[i] == "feature" { - feature[arg[i+1]] = arg[i+2] + for k := 2; k < len(args); k++ { + feature[args[1]] = kit.Merge(feature[args[1]], args[k]) + } } else if arg[i] == "exports" { for k := 1; k < len(args); k += 1 { @@ -1147,14 +1149,7 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心", "value": kit.Select("", args, 1), } for k := 2; k < len(args)-1; k += 2 { - switch val := input[args[k]].(type) { - case nil: - input[args[k]] = args[k+1] - case string: - input[args[k]] = []interface{}{input[args[k]], args[k+1]} - case []interface{}: - input[args[k]] = append(val, args[k+1]) - } + input[args[k]] = kit.Merge(input[args[k]], args[k+1]) } inputs = append(inputs, input) } @@ -1170,6 +1165,13 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心", } } + ctx := m.Cap("module") + if strings.Contains(cmd, ".") { + cs := strings.Split(cmd, ".") + ctx = strings.Join(cs[:len(cs)-1], ".") + cmd = cs[len(cs)-1] + } + m.Confv("_index", []interface{}{-2}, map[string]interface{}{ "name": kit.Select("", arg, 1), "help": kit.Select("", arg, 2), @@ -1177,7 +1179,7 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心", "init": init, "type": right, - "ctx": m.Cap("module"), + "ctx": ctx, "cmd": cmd, "args": args, "inputs": inputs, diff --git a/src/examples/code/code.go b/src/examples/code/code.go index ab973cdf..c5e7e421 100644 --- a/src/examples/code/code.go +++ b/src/examples/code/code.go @@ -3,29 +3,302 @@ package code import ( "contexts/ctx" "contexts/web" + "path" + "regexp" + "strings" + "time" + "toolkit" ) var Index = &ctx.Context{Name: "code", Help: "代码中心", - Caches: map[string]*ctx.Cache{}, - Configs: map[string]*ctx.Config{}, + Caches: map[string]*ctx.Cache{}, + Configs: map[string]*ctx.Config{ + "docker": {Name: "docker", Help: "容器", Value: map[string]interface{}{ + "shy": ` +FROM {{options . "base"}} + +WORKDIR /home/{{options . "user"}}/context +Env ctx_dev {{options . "host"}} + +RUN wget -q -O - $ctx_dev/publish/boot.sh | sh -s install + +CMD sh bin/boot.sh + +`, + }}, + }, Commands: map[string]*ctx.Command{ - "zsh": &ctx.Command{Name: "zsh", Help: "终端", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - m.Echo("zsh") + "zsh": {Name: "zsh dir grep key [split reg fields] [filter reg fields] [order key method] [group keys method] [sort keys method]", + Form: map[string]int{"split": 2, "filter": 2, "order": 2, "group": 2, "sort": 2}, + Help: "终端", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + p, arg := kit.Select(".", arg[0]), arg[1:] + switch arg[0] { + case "install": + m.Cmd("cli.system", "apk", "add", arg[1]) + + case "list": + m.Cmdy("nfs.dir", p, "time", "size", "path") + + case "find": + m.Cmdy("cli.system", "find", p, "-name", arg[1]) + + case "grep": + if m.Options("split") { + re, _ := regexp.Compile(kit.Select("", m.Optionv("split"), 0)) + fields := map[string]bool{} + for _, v := range strings.Split(kit.Select("", m.Optionv("split"), 1), " ") { + if v != "" { + fields[v] = true + } + } + + m.Cmd("cli.system", "grep", "-rn", arg[1], p, "cmd_parse", "cut", ":", "3", "path line text").Table(func(index int, line map[string]string) { + if ls := re.FindAllStringSubmatch(line["text"], -1); len(ls) > 0 { + m.Push("path", line["path"]) + m.Push("line", line["line"]) + for _, v := range ls { + if len(fields) == 0 || fields[v[1]] { + m.Push(v[1], v[2]) + } + } + } + }) + m.Table() + } else { + m.Cmdy("cli.system", "grep", "-rn", arg[1], p, "cmd_parse", "cut", ":", "3", "path line text") + } + + if m.Has("filter") { + m.Filter(m.Option("filter")) + } + if m.Has("order") { + m.Sort(kit.Select("", m.Optionv("order"), 0), kit.Select("", m.Optionv("order"), 1)) + } + if m.Has("group") { + m.Group(kit.Select("sum", m.Optionv("group"), 1), strings.Split(kit.Select("", m.Option("group"), 0), " ")...) + } + if m.Has("sort") { + m.Sort(kit.Select("", m.Optionv("sort"), 0), kit.Select("", m.Optionv("sort"), 1)) + } + + case "tail": + m.Cmdy("cli.system", "tail", path.Join(p, arg[1])) + + } + return + }}, + "tmux": {Name: "tmux [session [window [pane cmd]]]", Help: "窗口", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + prefix := []string{"cli.system", "tmux"} + if len(arg) > 1 { + switch arg[1] { + case "modify": + switch arg[2] { + case "session": + m.Cmdy(prefix, "rename-session", "-t", arg[0], arg[3]) + case "window": + m.Cmdy(prefix, "rename-window", "-t", arg[0], arg[3]) + } + return + } + } + // 查看会话 + if m.Cmdy(prefix, "list-session", "-F", "#{session_id},#{session_name},#{session_windows},#{session_height},#{session_width}", + "cmd_parse", "cut", ",", "5", "id session windows height width"); len(arg) == 0 { + return + } + + // 创建会话 + if arg[0] != "" && !kit.Contains(m.Meta["session"], arg[0]) { + m.Cmdy(prefix, "new-session", "-ds", arg[0]) + } + m.Set("append").Set("result") + + // 查看窗口 + if m.Cmdy(prefix, "list-windows", "-t", arg[0], "-F", "#{window_id},#{window_name},#{window_panes},#{window_height},#{window_width}", + "cmd_parse", "cut", ",", "5", "id window panes height width"); len(arg) == 1 { + return + } + + // 创建窗口 + if arg[1] != "" && !kit.Contains(m.Meta["window"], arg[1]) { + m.Cmdy(prefix, "new-window", "-dt", arg[0], "-n", arg[1]) + } + m.Set("append").Set("result") + + // 查看面板 + if len(arg) == 2 { + m.Cmdy(prefix, "list-panes", "-t", arg[0]+":"+arg[1], "-F", "#{pane_id},#{pane_index},#{pane_tty},#{pane_height},#{pane_width}", + "cmd_parse", "cut", ",", "5", "id pane tty height width") + return + } + + // 执行命令 + target := arg[0] + ":" + arg[1] + "." + arg[2] + if len(arg) > 3 { + if len(arg) > 5 { + switch arg[5] { + case "modify": + switch arg[6] { + case "text": + m.Cmdy(prefix, "set-buffer", "-b", arg[4], arg[7]) + } + return + } + } + switch arg[3] { + case "buffer": + if len(arg) > 5 { + m.Cmdy(prefix, "set-buffer", "-b", arg[4], arg[5]) + } + if len(arg) > 4 { + m.Cmdy(prefix, "show-buffer", "-b", arg[4]) + return + } + m.Cmdy(prefix, "list-buffers", "cmd_parse", "cut", ": ", "3", "buffer size text") + for i, v := range m.Meta["text"] { + if i < 3 { + m.Meta["text"][i] = m.Cmdx(prefix, "show-buffer", "-b", m.Meta["buffer"][i]) + } else { + m.Meta["text"][i] = v[2 : len(v)-1] + } + } + return + case "layout": + default: + m.Cmdy(prefix, "send-keys", "-t", target, strings.Join(arg[3:], " "), "Enter") + time.Sleep(1 * time.Second) + } + } + + // 查看终端 + m.Echo(strings.TrimSpace(m.Cmdx(prefix, "capture-pane", "-pt", target))) return }}, - "tmux": &ctx.Command{Name: "tmux", Help: "窗口", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + "docker": {Name: "docker", Help: "容器", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + prefix := []string{"cli.system", "docker"} + switch arg[0] { + case "image": + prefix = append(prefix, "image") + pos := kit.Select("shy", arg, 1) + tag := kit.Select("2.1", arg, 2) + + // 查看镜像 + if m.Cmdy(prefix, "ls", "cmd_parse", "cut", "cmd_headers", "IMAGE ID", "IMAGE_ID"); len(arg) == 1 { + return + } else if i := kit.IndexOf(m.Meta["IMAGE_ID"], arg[1]); i > -1 { + arg, pos, tag = arg[2:], strings.TrimSpace(m.Meta["REPOSITORY"][i]), strings.TrimSpace(m.Meta["TAG"][i]) + } else { + arg = arg[3:] + } + + // 拉取镜像 + if len(arg) == 0 { + m.Cmdy(prefix, "pull", pos+":"+tag) + return + } + + switch arg[0] { + // 启动容器 + case "运行": + m.Set("append").Set("result") + m.Cmdy("cli.system", "docker", "run", "-dt", pos+":"+tag) + return + // 清理镜像 + case "清理": + m.Cmd(prefix, "prune", "-f") + + // 删除镜像 + case "delete": + m.Cmd(prefix, "rm", pos+":"+tag) + + // 创建镜像 + default: + m.Option("base", pos+":"+tag) + m.Option("name", arg[0]+":"+kit.Select("2.1", arg, 1)) + m.Option("host", "http://"+m.Conf("runtime", "boot.hostname")+".local:9095") + m.Option("user", kit.Select("shy", arg, 2)) + m.Option("file", "etc/Dockerfile") + + if f, _, e := kit.Create(m.Option("file")); m.Assert(e) { + defer f.Close() + if m.Assert(ctx.ExecuteStr(m, f, m.Conf("docker", arg[0]))) { + m.Cmdy("cli.system", "docker", "image", "build", "-f", m.Option("file"), "-t", m.Option("name"), ".") + } + } + } + + case "container": + prefix = append(prefix, "container") + if len(arg) > 1 { + switch arg[2] { + case "进入": + m.Cmdy("cli.system", "tmux", "new-window", "-dPF", "#{session_name}:#{window_name}.1", "docker exec -it "+arg[1]+" sh") + return + + case "停止": + m.Cmd(prefix, "stop", arg[1]) + + case "启动": + m.Cmd(prefix, "start", arg[1]) + + case "重启": + m.Cmd(prefix, "restart", arg[1]) + + case "清理": + m.Cmd(prefix, "prune", "-f") + + case "modify": + switch arg[3] { + case "NAMES": + m.Cmd(prefix, "rename", arg[1], arg[4:]) + } + + // 删除容器 + case "delete": + m.Cmd(prefix, "rm", arg[1]) + + default: + if len(arg) > 2 { + m.Cmdy(prefix, "exec", arg[1], arg[2:]) + } else { + m.Cmdy(prefix, "inspect", arg[1]) + } + return + } + } + m.Cmdy(prefix, "ls", "-a", "cmd_parse", "cut", "cmd_headers", "CONTAINER ID", "CONTAINER_ID") + + case "network": + if len(arg) == 1 { + m.Cmdy("cli.system", "docker", "network", "ls", "cmd_parse", "cut", "cmd_headers", "NETWORK ID", "NETWORK_ID") + break + } + + kit.Map(kit.Chain(kit.UnMarshal(m.Cmdx("cli.system", "docker", "network", "inspect", arg[1])), "0.Containers"), "", func(key string, value map[string]interface{}) { + m.Push("CONTAINER_ID", key[:12]) + m.Push("name", value["Name"]) + m.Push("IPv4", value["IPv4Address"]) + m.Push("IPv6", value["IPV4Address"]) + m.Push("Mac", value["MacAddress"]) + }) + m.Table() + + case "volume": + if len(arg) == 1 { + m.Cmdy("cli.system", "docker", "volume", "ls", "cmd_parse", "cut", "cmd_headers", "VOLUME NAME", "VOLUME_NAME") + break + } + + default: + m.Cmdy("cli.system", "docker", arg) + } + return + }}, + "git": {Name: "git", Help: "版本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { m.Echo("git") return }}, - "docker": &ctx.Command{Name: "docker", Help: "容器", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - m.Echo("docker") - return - }}, - "git": &ctx.Command{Name: "git", Help: "版本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - m.Echo("git") - return - }}, - "vim": &ctx.Command{Name: "vim", Help: "编辑器", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + "vim": {Name: "vim", Help: "编辑器", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { m.Echo("vim") return }}, diff --git a/src/plugin/docker/index.css b/src/plugin/docker/index.css new file mode 100644 index 00000000..928bca5f --- /dev/null +++ b/src/plugin/docker/index.css @@ -0,0 +1,3 @@ +fieldset.item.docker div.output { +} + diff --git a/src/plugin/docker/index.go b/src/plugin/docker/index.go new file mode 100644 index 00000000..0e326b29 --- /dev/null +++ b/src/plugin/docker/index.go @@ -0,0 +1,36 @@ +package main + +import ( + "contexts/cli" + "contexts/ctx" + "toolkit" + + "fmt" + "os" +) + +var Index = &ctx.Context{Name: `docker`, Help: `plugin`, + Caches: map[string]*ctx.Cache{}, + Configs: map[string]*ctx.Config{ + "_index": &ctx.Config{Name: "index", Value: []interface{}{ + map[string]interface{}{"name": "demo", "help": "demo", + "tmpl": "componet", "view": "", "init": "", + "type": "public", "ctx": "demo", "cmd": "demo", + "args": []interface{}{}, "inputs": []interface{}{ + map[string]interface{}{"type": "text", "name": "pod", "value": "hello world"}, + map[string]interface{}{"type": "button", "value": "执行"}, + }, + }, + }}, + }, + Commands: map[string]*ctx.Command{ + "demo": {Name: "demo", Help: "demo", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + m.Echo(kit.Select("hello world", arg, 0)) + return + }}, + }, +} + +func main() { + fmt.Print(cli.Index.Plugin(Index, os.Args[1:])) +} diff --git a/src/plugin/docker/index.js b/src/plugin/docker/index.js new file mode 100644 index 00000000..17b83ae2 --- /dev/null +++ b/src/plugin/docker/index.js @@ -0,0 +1,3 @@ +Script["docker/index.js"] = function(field, option, output) {return { +}} + diff --git a/src/plugin/docker/index.shy b/src/plugin/docker/index.shy new file mode 100644 index 00000000..7280bc31 --- /dev/null +++ b/src/plugin/docker/index.shy @@ -0,0 +1,49 @@ +kit shell "命令" private "web.code.zsh" \ + text "" name dir imports plugin_path action auto \ + select "" name cmd values list values find values grep values tail \ + exports path path \ + text "" name txt \ + feature display editor \ + button "搜索" \ + button "返回" cb Last + +kit clip "文本" private "web.code.tmux" "" "" "" "buffer" \ + text "" name tag imports plugin_buffer action auto \ + text "" name txt \ + exports buffer buffer \ + feature detail "复制" "下载" "修改" \ + button "查看" action auto \ + button "返回" cb Last + +kit tmux "终端" private "web.code.tmux" \ + text "context" name session imports plugin_session action auto \ + text "" name window imports plugin_window action auto \ + text "" name pane imports plugin_pane view char action auto \ + text "" name cmd \ + exports session session "" window window "" pane pane "" \ + feature detail "复制" "下载" "修改" \ + button "查看" action auto + +kit image "镜像" private "web.code.docker" "image" \ + text "" name pos imports plugin_REPOSITORY \ + text "" name tag imports plugin_TAG \ + exports IMAGE_ID IMAGE_ID "" REPOSITORY REPOSITORY "" TAG TAG "" \ + feature detail "运行" "删除" "清理" \ + button "查看" action auto + +kit container "容器" private "web.code.docker" "container" \ + text "" name arg imports plugin_CONTAINER_ID \ + exports CONTAINER_ID CONTAINER_ID \ + feature detail "进入" "停止" "启动" "重启" "修改" "删除" "清理" \ + button "查看" action auto + +kit network "网络" private "web.code.docker" "network" \ + text "" name arg imports plugin_NETWORK_ID action auto \ + exports NETWORK_ID NETWORK_ID \ + button "查看" action auto + +kit volume "存储" private "web.code.docker" "volume" \ + text "" name arg imports plugin_CONTAINER_ID \ + exports CONTAINER_ID CONTAINER_ID \ + button "查看" + diff --git a/src/toolkit/misc.go b/src/toolkit/misc.go index 2ac7c69c..bb3358ec 100644 --- a/src/toolkit/misc.go +++ b/src/toolkit/misc.go @@ -218,3 +218,43 @@ func List(arg interface{}, cb interface{}) { } } } + +func Merge(list interface{}, value string) interface{} { + switch val := list.(type) { + case nil: + return value + case string: + return []interface{}{val, value} + case []interface{}: + return append(val, value) + } + return list +} +func Contains(list interface{}, value string) bool { + switch val := list.(type) { + case nil: + case string: + case []string: + for _, v := range val { + if v == value { + return true + } + } + case []interface{}: + } + return false +} +func IndexOf(list interface{}, value string) int { + switch val := list.(type) { + case nil: + case string: + case []string: + for i, v := range val { + if strings.TrimSpace(v) == strings.TrimSpace(value) { + return i + } + } + case []interface{}: + } + return -1 +} diff --git a/usr/librarys/example.js b/usr/librarys/example.js index e37893bd..717ef075 100644 --- a/usr/librarys/example.js +++ b/usr/librarys/example.js @@ -1220,10 +1220,12 @@ function Plugin(page, pane, field, inits, runs) { var meta = arguments.callee.meta var list = arguments.callee.list - for (var i = 0; i < list.length; i += 3) { - (list[1] && line[list[1]] || list[i+1] && line[list[i+1]] || list[i+2]) && + for (var i = 0; i < list.length; i += 3) {if (list[i+1] == name) { + for (var i = 0; i < list.length; i += 3) { page.Sync("plugin_"+list[i]).set(meta[list[i+2]||""](list[i+1]? line[list[i+1]]: value, list[i+1]||name, line, list)) - } + } + break + }} }), onchoice: shy("菜单列表", { "返回": "Last", @@ -1232,7 +1234,7 @@ function Plugin(page, pane, field, inits, runs) { "减参": "Remove", "删除": "Delete", }, ["返回", "复制", "加参", "减参", "删除"], function(event, value, meta) { - kit._call(plugin, plugin[meta[value]]) + kit._call(plugin, plugin[meta[value]], [event]) return true }), onaction: shy("事件列表", { @@ -1290,7 +1292,7 @@ function Inputs(plugin, meta, item, target, option) { onimport: shy("导入数据", {}, [item.imports], function() { kit.List(arguments.callee.list, function(imports) { page.Sync(imports).change(function(value) { - plugin.History(target.value, target), target.value = value + plugin.History(target.value, target), target.value = value.trim() input.Event(event = document.createEvent("Event")) item.action == "auto" && plugin.Runs(event) }) @@ -1372,10 +1374,10 @@ function Inputs(plugin, meta, item, target, option) { return true }) + // Event入口 2.1 if (event.key == "Enter" && (event.ctrlKey || item.type == "text")) { - // Event入口 2.1 input.which.set(target.value) != undefined && plugin.History(target.value, target) - input.Event(event, {}) && plugin.Check(event, target) + input.Event(event, {}) && event.ctrlKey? plugin.Runs(event): plugin.Check(event, target) } }, onkeyup: function(event) { @@ -1409,11 +1411,27 @@ function Inputs(plugin, meta, item, target, option) { return plugin.Inputs[item.name] = target, target.Input = input } function Output(plugin, type, msg, cb, target, option) { - var exports = plugin.target.Meta.exports + var name = plugin.target.Meta.name+"."+type + var feature = JSON.parse(plugin.target.Meta.feature||'{}') + var exports = JSON.parse(plugin.target.Meta.exports||'{}') + var output = Meta(plugin.Zone(type), target, { _table: function() {plugin.onfigure("table")}, _canvas: function() {plugin.onfigure("canvas")}, clear: function() {target.innerHTML = ""}, + Format: function() { + var ext = ".csv", txt = kit.Selector(target, "tr", function(tr) { + return kit.Selector(tr, "td,th", function(td) { + return td.innerText + }).join(",") + }).join("\n"); + type == "editor" && msg.file && (ext = ".txt", txt = msg.result.join("\n")); + !txt && (ext = ".txt", txt = msg.result.join("")) + return [name, ext, txt] + }, + Copy: function(event) { + kit.CopyText(output.Format()[2]) + }, Jshy: function(event, args) { // 内部命令 @@ -1425,19 +1443,44 @@ function Output(plugin, type, msg, cb, target, option) { }, Download: function() { - var type = ".csv", text = kit.Selector(target, "tr", function(tr) { - return kit.Selector(tr, "td,th", function(td) { - return td.innerText - }).join(",") - }).join("\n") - !text && (type = ".txt", text = plugin.msg.result.join("")) + var ps = output.Format() - plugin.ontoast({text:''+name+type+'', title: "下载中...", width: 200}) + plugin.ontoast({text:''+ps[0]+ps[1]+'', title: "下载中...", width: 200}) kit.Selector(page.toast, "a", function(item) {item.click()}) }, onimport: shy("导入数据", { _table: function(msg, list) { - return list && list.length > 0 && kit.OrderTable(kit.AppendTable(kit.AppendChild(target, "table"), msg.Table(), list), "", output.onexport) + return list && list.length > 0 && kit.OrderTable(kit.AppendTable(kit.AppendChild(target, "table"), msg.Table(), list), "", output.onexport, function(event, value, name, line, index) { + var td = event.target + plugin.oncarte(event, shy("菜单列表", { + "修改": "modify", + "删除": "delete", + "下载": "Download", + "复制": function(event, text) {kit.CopyText(text), plugin.ontoast(text, "Copy to ClipBoard!")}, + }, feature.detail||["复制", "下载"], function(event, item, meta) { + var text = td.innerText.trim() + if (typeof meta[item] == "function") {meta[item](event, text); return} + + item == "修改"? (text = kit.AppendChilds(td, [{type: "input", value: text, data: {onkeydown: function(event) { + if (event.key == "Enter") { + var id = "" + for (var i = 0; i < exports.length-1; i += 3) { + id = (id || line[exports[i+1]] || "").trim() + } + plugin.Run(event, [id, meta[item], name, event.target.value], function(msg) { + td.innerHTML = event.target.value + plugin.ontoast("修改成功") + }, true) + return + } + }}}]).input, text.focus(), text.setSelectionRange(0, -1)): output[meta[item]]? output[meta[item]](event): plugin.Run(event, [line[exports[1]].trim(), meta[item]||item], function(msg) { + console.log(msg) + }) + + return true + }), + ) + }) }, _code: function(msg) { return msg.result && msg.result.length > 0 && kit.OrderCode(kit.AppendChild(target, [{view: ["code", "div", msg.Results()]}]).first) @@ -1489,13 +1532,21 @@ function Output(plugin, type, msg, cb, target, option) { page.output = target meta[type](msg, cb) }), + ondetail: shy("菜单列表", { + "删除": "_table", + "修改": "_canvas", + }, ["删除", "修改"], function(event, value, meta) { + kit._call(output, output[meta[value]], [event]) + return true + }), onchoice: shy("菜单列表", { "表格": "_table", "绘图": "_canvas", + "复制": "Copy", "下载": "Download", "返回": "Last", "清空": "clear", - }, ["表格", "绘图", "下载", "返回", "清空"], function(event, value, meta) { + }, ["表格", "绘图", "复制", "下载", "返回", "清空"], function(event, value, meta) { kit._call(output, output[meta[value]], [event]) return true }), diff --git a/usr/librarys/toolkit.js b/usr/librarys/toolkit.js index d7d451db..b519f938 100644 --- a/usr/librarys/toolkit.js +++ b/usr/librarys/toolkit.js @@ -303,7 +303,7 @@ kit = toolkit = (function() {var kit = {__proto__: document, var td = kit.AppendChild(tr, "td", kit.Color(row[key])) if (key == "when") {td.className = "when"} - if (row[key].startsWith("http")) { + if ((row[key]||"").startsWith("http")) { td.innerHTML = ""+row[key]+"" } @@ -353,8 +353,8 @@ kit = toolkit = (function() {var kit = {__proto__: document, tbody.appendChild(list[i]) } }, - OrderTable: function(table, field, cb) {if (!table) {return} - table.onclick = function(event) {var target = event.target + OrderTable: function(table, field, cb, cbs) {if (!table) {return} + table.oncontextmenu = table.onclick = function(event) {var target = event.target target.parentElement.childNodes.forEach(function(item, i) {if (item != target) {return} if (target.tagName == "TH") {var dataset = target.dataset dataset["sort_asc"] = (dataset["sort_asc"] == "1") ? 0: 1 @@ -362,7 +362,7 @@ kit = toolkit = (function() {var kit = {__proto__: document, } else if (target.tagName == "TD") {var index = 0 kit.Selector(table, "tr", function(item, i) {item == target.parentElement && (index = i)}) var name = target.parentElement.parentElement.querySelector("tr").childNodes[i].innerText - name.startsWith(field) && kit._call(cb, [event, item.innerText, name, item.parentNode.Meta, index]) + name.startsWith(field) && kit._call(event.type=="contextmenu"? cbs: cb, [event, item.innerText, name, item.parentNode.Meta, index]) } }) kit.CopyText() @@ -439,7 +439,7 @@ kit = toolkit = (function() {var kit = {__proto__: document, // HTML输入文本 CopyText: function(text) { if (text) { - var input = kit.AppendChild(document.body, [{type: "input", value: text}]).input + var input = kit.AppendChild(document.body, [{type: "textarea", inner: text}]).last input.focus(), input.setSelectionRange(0, text.length) } @@ -544,6 +544,7 @@ kit = toolkit = (function() {var kit = {__proto__: document, s = s.replace(/\033\[31m/g, "") s = s.replace(/\033\[0m/g, "") s = s.replace(/\033\[m/g, "") + s = s.replace(/\n/g, "
") return s }, Value: function() {