1
0
forked from x/icebergs
This commit is contained in:
shaoying 2020-06-22 20:31:46 +08:00
parent d4da81ce94
commit 11cff19070
14 changed files with 487 additions and 459 deletions

View File

@ -204,6 +204,9 @@ const (
PARSER = "parser"
ADVISE = "advise"
PLUGIN = "plugin"
ENGINE = "engine"
)
var Index = &ice.Context{Name: "mdb", Help: "数据模块",

View File

@ -232,6 +232,17 @@ const (
FILE = "file"
)
const (
DIR_ROOT = "dir_root"
DIR_TYPE = "dir_type"
DIR_DEEP = "dir_deep"
DIR_REG = "dir_reg"
)
const (
TYPE_ALL = "all"
TYPE_DIR = "dir"
TYPE_FILE = "file"
)
var Index = &ice.Context{Name: "nfs", Help: "存储模块",
Configs: map[string]*ice.Config{

View File

@ -277,7 +277,7 @@ func (f *Frame) Start(m *ice.Message, arg ...string) bool {
defer s.Close()
buf := bytes.NewBuffer(make([]byte, 0, 4096))
defer m.Echo(buf.String())
defer func() { m.Echo(buf.String()) }()
// 脚本解析
f.source = arg[0]
@ -380,4 +380,4 @@ var Index = &ice.Context{Name: "ssh", Help: "终端模块",
},
}
func init() { ice.Index.Register(Index, &Frame{}) }
func init() { ice.Index.Register(Index, &Frame{}, SOURCE, QRCODE) }

View File

@ -123,7 +123,7 @@ func _action_show(m *ice.Message, river, storm, index string, arg ...string) {
}
func _action_proxy(m *ice.Message) (proxy []string) {
if m.Option(POD) != "" {
proxy = append(proxy, web.PROXY, m.Option(POD))
proxy = append(proxy, web.SPACE, m.Option(POD))
m.Option(POD, "")
}
return proxy

View File

@ -10,10 +10,10 @@ func init() {
Commands: map[string]*ice.Command{
"/" + mdb.SEARCH: {Name: "/search", Help: "搜索引擎", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) > 2 {
m.Cmdy(mdb.RENDER, arg)
m.Cmdy(m.Space(m.Option("pod")), mdb.RENDER, arg)
return
}
m.Cmdy(mdb.SEARCH, arg)
m.Cmdy(m.Space(m.Option("pod")), mdb.SEARCH, arg)
}},
},
}, nil)

39
core/wiki/data.go Normal file
View File

@ -0,0 +1,39 @@
package wiki
import (
"github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/mdb"
"github.com/shylinux/icebergs/base/nfs"
"github.com/shylinux/toolkits"
)
func _data_show(m *ice.Message, name string, arg ...string) {
m.Cmdy(nfs.CAT, name)
m.CSV(m.Result())
}
const DATA = "data"
const (
DataPlugin = "/plugin/local/wiki/data.js"
)
func init() {
Index.Merge(&ice.Context{Name: "data", Help: "数据表格",
Configs: map[string]*ice.Config{
DATA: {Name: "data", Help: "数据表格", Value: kit.Data(
kit.MDB_SHORT, "name", "path", "", "regs", ".*\\.csv",
)},
},
Commands: map[string]*ice.Command{
DATA: {Name: "data path=auto auto", Help: "数据表格", Meta: kit.Dict(mdb.PLUGIN, DataPlugin), Action: map[string]*ice.Action{
nfs.SAVE: {Name: "save path text", Help: "保存", Hand: func(m *ice.Message, arg ...string) {
_wiki_save(m, DATA, arg[0], arg[1])
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if !_wiki_list(m, DATA, kit.Select("./", arg, 0)) {
_data_show(m, arg[0])
}
}},
},
}, nil)
}

View File

@ -2,13 +2,9 @@ package wiki
import (
"github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/mdb"
"github.com/shylinux/icebergs/base/nfs"
"github.com/shylinux/toolkits"
"path"
)
const (
DRAW = "draw"
)
func _draw_show(m *ice.Message, zone, kind, name, text string, arg ...string) {
@ -23,48 +19,34 @@ func _draw_plugin(m *ice.Message, arg ...string) {
})
}
const DRAW = "draw"
const (
DrawPlugin = "/plugin/local/wiki/draw.js"
)
func init() {
sub := &ice.Context{Name: "draw", Help: "思维导图",
Index.Register(&ice.Context{Name: "draw", Help: "思维导图",
Configs: map[string]*ice.Config{
DRAW: {Name: "draw", Help: "思维导图", Value: kit.Data(kit.MDB_SHORT, "name", "path", "", "regs", ".*\\.svg",
"prefix", `<svg vertion="1.1" xmlns="http://www.w3.org/2000/svg" width="%v" height="%v">`, "suffix", `</svg>`,
)},
},
Commands: map[string]*ice.Command{
DRAW: {Name: "draw path=自然/编程/hi.svg auto", Help: "思维导图", Meta: kit.Dict(
"display", "/plugin/local/wiki/draw.js",
), Action: map[string]*ice.Action{
"save": {Name: "save path text", Help: "保存", Hand: func(m *ice.Message, arg ...string) {
m.Cmd("nfs.save", path.Join(m.Conf(DRAW, "meta.path"), kit.Select("hi.svg", arg, 0)), kit.Select(m.Option("content"), arg, 1))
DRAW: {Name: "draw path=自然/编程/hi.svg auto", Help: "思维导图", Meta: kit.Dict(mdb.PLUGIN, DrawPlugin), Action: map[string]*ice.Action{
nfs.SAVE: {Name: "save path text", Help: "保存", Hand: func(m *ice.Message, arg ...string) {
_wiki_save(m, DATA, arg[0], arg[1])
}},
"run": {Name: "show path text", Help: "运行", Hand: func(m *ice.Message, arg ...string) {
_draw_show(m, arg[0], arg[1], arg[2], arg[3], arg[4:]...)
}},
"plugin": {Name: "plugin", Help: "插件", Hand: func(m *ice.Message, arg ...string) {
mdb.PLUGIN: {Name: "plugin", Help: "插件", Hand: func(m *ice.Message, arg ...string) {
_draw_plugin(m, arg...)
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
reply(m, cmd, arg...)
}},
},
}
sub.Register(&ice.Context{Name: "创业", Help: "创业",
Commands: map[string]*ice.Command{
"项目开发": {Name: "项目开发", Help: "项目开发", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
m.Echo("hello world")
}},
"项目测试": {Name: "项目测试", Help: "项目测试", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
}},
"改变世界": {Name: "改变世界", Help: "改变世界", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
m.Echo("hello world")
}},
"认识世界": {Name: "认识世界", Help: "认识世界", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
m.Echo("hello world")
if !_wiki_list(m, DRAW, kit.Select("./", arg, 0)) {
_wiki_show(m, DRAW, arg[0])
}
}},
},
}, nil)
Index.Register(sub, nil)
}

53
core/wiki/feel.go Normal file
View File

@ -0,0 +1,53 @@
package wiki
import (
"github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/mdb"
"github.com/shylinux/icebergs/base/web"
"github.com/shylinux/toolkits"
"os"
"path"
)
func _feel_show(m *ice.Message, name string, arg ...string) {
m.Echo(path.Join(m.Conf(FEEL, "meta.path"), name))
}
const FEEL = "feel"
const (
FeelPlugin = "/plugin/local/wiki/feel.js"
)
func init() {
Index.Merge(&ice.Context{Name: "feel", Help: "影音媒体",
Configs: map[string]*ice.Config{
FEEL: {Name: "feel", Help: "影音媒体", Value: kit.Data(
kit.MDB_SHORT, "name", "path", "", "regs", ".*.(qrc|png|jpg|JPG|MOV|m4v)",
)},
},
Commands: map[string]*ice.Command{
FEEL: {Name: "feel path=auto auto", Help: "影音媒体", Meta: kit.Dict(
mdb.PLUGIN, FeelPlugin, "detail", []string{"标签", "删除"},
), Action: map[string]*ice.Action{
mdb.CREATE: {Name: "create", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
m.Conf(FEEL, kit.Keys(path.Base(arg[2]), "-2"), arg[3])
p := path.Join(m.Conf(FEEL, "meta.path"), arg[2])
q := path.Join(m.Conf(FEEL, "meta.path"), arg[3])
os.MkdirAll(q, 0777)
m.Assert(os.Link(p, path.Join(q, path.Base(arg[2]))))
}},
mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
m.Assert(os.Remove(path.Join(m.Conf(FEEL, "meta.path"), m.Option("path"))))
}},
web.UPLOAD: {Name: "upload", Help: "上传", Hand: func(m *ice.Message, arg ...string) {
_wiki_upload(m, FEEL)
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if !_wiki_list(m, FEEL, kit.Select("./", arg, 0)) {
_feel_show(m, arg[0])
}
}},
},
}, nil)
}

View File

@ -1,22 +0,0 @@
package wiki
import (
ice "github.com/shylinux/icebergs"
)
func init() {
Index.Register(&ice.Context{Name: "jpg", Help: "图片",
Configs: map[string]*ice.Config{},
Commands: map[string]*ice.Command{
"list": {Name: "list name", Help: "列表", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Echo(arg[0])
}},
"save": {Name: "save name text", Help: "保存", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
}},
"show": {Name: "show name", Help: "渲染", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
}},
},
}, nil)
}

View File

@ -7,14 +7,13 @@ data-type="{{.Option "type"}}" data-name="{{.Option "name"}}" data-text="{{.Opti
{{range $index, $value := .Optionv "list"}}<li>{{index $value 0}}: <a href="{{index $value 1}}" target="_blank">{{index $value 1}}</a></li>{{end}}</ul>`
var spark = `<p class="story" data-type="{{.Option "type"}}" data-name="{{.Option "name"}}" data-text="{{.Option "text"}}">{{.Option "text"}}</p>`
var local = `<div class="story"
data-type="{{.Option "type"}}" data-name="{{.Option "name"}}" data-text="{{.Option "text"}}">
{{range $index, $value := .Optionv "input"}}{{$value}}{{end}}</div>`
var shell = `<code class="story" data-type="{{.Option "type"}}" data-name="{{.Option "name"}}" data-text="{{.Option "input"}}" data-dir="{{.Option "cmd_dir"}}">$ {{.Option "input"}} # {{.Option "name"}}
{{.Option "output"}}</code>
`
var chart = `<svg class="story" vertion="1.1" xmlns="http://www.w3.org/2000/svg" dominant-baseline="middle" text-anchor="middle"
data-type="{{.Option "type"}}" data-name="{{.Option "name"}}" data-text="{{.Option "text"}}"
width="{{.Option "width"}}" height="{{.Option "height"}}"
font-size="{{.Option "font-size"}}" stroke="{{.Option "stroke"}}" fill="{{.Option "fill"}}"
stroke-width="{{.Option "stroke-width"}}" font-family="{{.Option "font-family"}}"
style="{{.Option "style"}}"
>`
var field = `<fieldset class="story {{.Option "name"}}" data-type="{{.Option "type"}}" data-name="{{.Option "name"}}" data-text="{{.Option "text"}}" data-meta='{{.Optionv "meta"|Format}}'>
<legend>{{.Option "name"}}</legend>
<form class="option"></form>
@ -23,40 +22,13 @@ var field = `<fieldset class="story {{.Option "name"}}" data-type="{{.Option "ty
<div class="status"></div>
</fieldset>
`
var field0 = `<fieldset class="story" data-type="{{.Option "type"}}" data-name="{{.Option "name"}}" data-text="{{.Option "text"}}">
<legend>{{.Option "name"}} </legend>{{$meta := .Optionv "meta"}}
<form class="option">
{{if $meta}}
{{range $index, $value := index $meta "inputs"}}
{{$type := index $value "_input"}}
<div class="item input">
<input
{{if eq $type "text"}}class="args"{{end}}
type="{{index $value "_input"}}"
name="{{index $value "name"|Format}}"
value="{{index $value "value"|Format}}"
data-action="{{index $value "action"|Format}}"
>
</div>
{{end}}
{{end}}
</form>
<div class="action">
</div>
<div class="output">
{{if .Result}}
<div class="code">{{.Result}}</div>
{{else if .Appendv "append"}}
<table>{{$msg := .}}
<tr>{{range $index, $value := .Appendv "append"}}<th>{{$value}}</th>{{end}}</tr>
{{range $index, $_ := .Appendv "_index"}}<tr>{{range $_, $key := $msg.Appendv "append"}}{{$line := $msg.Appendv $key}}
<td>{{index $line $index}}</td>
{{end}}</tr>{{end}}
</table>
{{end}}
</div>
</fieldset>
var shell = `<code class="story" data-type="{{.Option "type"}}" data-name="{{.Option "name"}}" data-text="{{.Option "input"}}" data-dir="{{.Option "cmd_dir"}}">$ {{.Option "input"}} # {{.Option "name"}}
{{.Option "output"}}</code>
`
var local = `<div class="story"
data-type="{{.Option "type"}}" data-name="{{.Option "name"}}" data-text="{{.Option "text"}}">
{{range $index, $value := .Optionv "input"}}{{$value}}{{end}}</div>`
var order = `<ul class="story"
data-type="{{.Option "type"}}" data-name="{{.Option "name"}}" data-text="{{.Option "text"}}">
{{range $index, $value := .Optionv "list"}}<li>{{$value}}</li>{{end}}</ul>`
@ -72,14 +44,6 @@ data-type="{{.Option "type"}}" data-name="{{.Option "name"}}" data-text="{{.Opti
var stack = `<div class="story"
data-type="{{.Option "type"}}" data-name="{{.Option "name"}}" data-text="{{.Option "text"}}">`
var prefix = `<svg class="story" vertion="1.1" xmlns="http://www.w3.org/2000/svg" dominant-baseline="middle" text-anchor="middle"
data-type="{{.Option "type"}}" data-name="{{.Option "name"}}" data-text="{{.Option "text"}}"
width="{{.Option "width"}}" height="{{.Option "height"}}"
font-size="{{.Option "font-size"}}" stroke="{{.Option "stroke"}}" fill="{{.Option "fill"}}"
stroke-width="{{.Option "stroke-width"}}" font-family="{{.Option "font-family"}}"
style="{{.Option "style"}}"
>`
var premenu = `<ul class="story" data-type="premenu"></ul>`
var endmenu = `<ul class="story" data-type="endmenu">{{$menu := .Optionv "menu"}}{{range $index, $value := Value $menu "list"}}
<li>{{Value $value "prefix"}} {{Value $value "content"}}</li>{{end}}

View File

@ -3,15 +3,43 @@ package wiki
import (
ice "github.com/shylinux/icebergs"
_ "github.com/shylinux/icebergs/base"
"github.com/shylinux/icebergs/base/nfs"
"github.com/shylinux/icebergs/base/ssh"
"github.com/shylinux/icebergs/base/web"
kit "github.com/shylinux/toolkits"
"os"
"path"
"strings"
)
func _wiki_list(m *ice.Message, cmd, name string, arg ...string) bool {
if strings.HasSuffix(name, "/") {
m.Option(nfs.DIR_ROOT, m.Conf(cmd, "meta.path"))
m.Option(nfs.DIR_TYPE, nfs.TYPE_DIR)
m.Cmdy(nfs.DIR, name)
m.Option(nfs.DIR_TYPE, nfs.TYPE_FILE)
m.Option(nfs.DIR_REG, m.Conf(cmd, "meta.regs"))
m.Cmdy(nfs.DIR, name)
m.Option("_display", "table")
return true
}
return false
}
func _wiki_show(m *ice.Message, cmd, name string, arg ...string) {
m.Cmdy(nfs.CAT, path.Join(m.Conf(cmd, "meta.path"), name))
}
func _wiki_save(m *ice.Message, cmd, name, text string, arg ...string) {
m.Cmd(nfs.SAVE, path.Join(m.Conf(cmd, "meta.path"), name), text)
}
func _wiki_upload(m *ice.Message, cmd string) {
m.Option("request", m.R)
msg := m.Cmd(web.CACHE, "catch", "", "")
m.Cmd(web.CACHE, "watch", msg.Append("data"), path.Join(msg.Conf(cmd, "meta.path"),
path.Dir(m.Option("path")), msg.Append("name")))
}
func reply(m *ice.Message, cmd string, arg ...string) bool {
// 文件列表
m.Option("dir_root", m.Conf(cmd, "meta.path"))
@ -32,19 +60,7 @@ func reply(m *ice.Message, cmd string, arg ...string) bool {
var Index = &ice.Context{Name: "wiki", Help: "文档中心",
Configs: map[string]*ice.Config{
"brief": {Name: "brief", Help: "摘要", Value: kit.Data("template", brief)},
"refer": {Name: "refer", Help: "参考", Value: kit.Data("template", refer)},
"spark": {Name: "spark", Help: "段落", Value: kit.Data("template", spark)},
"local": {Name: "local", Help: "文件", Value: kit.Data("template", local)},
"order": {Name: "order", Help: "列表", Value: kit.Data("template", order)},
"table": {Name: "table", Help: "表格", Value: kit.Data("template", table)},
"stack": {Name: "stack", Help: "结构", Value: kit.Data("template", stack)},
"data": {Name: "data", Help: "数据表格", Value: kit.Data(kit.MDB_SHORT, "name", "path", "", "regs", ".*\\.csv")},
"walk": {Name: "walk", Help: "走遍世界", Value: kit.Data(kit.MDB_SHORT, "name", "path", "", "regs", ".*\\.csv")},
"feel": {Name: "feel", Help: "影音媒体", Value: kit.Data(kit.MDB_SHORT, "name", "path", "", "regs", ".*\\.(png|jpg|JPG|MOV|m4v)")},
},
Commands: map[string]*ice.Command{
ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
@ -54,194 +70,6 @@ var Index = &ice.Context{Name: "wiki", Help: "文档中心",
m.Save("feel")
}},
"brief": {Name: "brief name text", Help: "摘要", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 {
m.Echo(`<br class="story" data-type="brief">`)
return
}
if len(arg) == 1 {
arg = []string{"", arg[0]}
}
m.Option(kit.MDB_TYPE, cmd)
m.Option(kit.MDB_NAME, arg[0])
m.Option(kit.MDB_TEXT, arg[1])
m.Render(ice.RENDER_TEMPLATE, m.Conf(cmd, "meta.template"))
}},
"refer": {Name: "refer name text", Help: "参考", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Option(kit.MDB_TYPE, cmd)
m.Option(kit.MDB_NAME, arg[0])
m.Option(kit.MDB_TEXT, arg[1])
list := [][]string{}
for _, v := range kit.Split(strings.TrimSpace(arg[1]), "\n") {
list = append(list, kit.Split(v, " "))
}
m.Optionv("list", list)
m.Render(ice.RENDER_TEMPLATE, m.Conf(cmd, "meta.template"))
}},
"spark": {Name: "spark name text", Help: "感悟", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 {
m.Echo(`<br class="story" data-type="spark">`)
return
}
if len(arg) == 1 {
arg = []string{"", arg[0]}
}
m.Option(kit.MDB_TYPE, cmd)
m.Option(kit.MDB_NAME, arg[0])
m.Option(kit.MDB_TEXT, arg[1])
m.Optionv("list", kit.Split(arg[1], "\n"))
m.Render(ice.RENDER_TEMPLATE, m.Conf(cmd, "meta.template"))
}},
"local": {Name: "local name text", Help: "文件", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Option(kit.MDB_TYPE, cmd)
m.Option(kit.MDB_NAME, arg[0])
m.Option(kit.MDB_TEXT, arg[1])
m.Option("input", m.Cmdx("nfs.cat", arg[1]))
switch ls := strings.Split(arg[1], "."); ls[len(ls)-1] {
case "csv":
list := []string{"<table>"}
m.Spawn().CSV(m.Option("input")).Table(func(index int, value map[string]string, head []string) {
if index == 0 {
list = append(list, "<tr>")
for _, k := range head {
list = append(list, "<th>", k, "</th>")
}
list = append(list, "</tr>")
}
list = append(list, "<tr>")
for _, k := range head {
list = append(list, "<td>", value[k], "</td>")
}
list = append(list, "</tr>")
})
list = append(list, "</table>")
m.Optionv("input", list)
}
m.Render(ice.RENDER_TEMPLATE, m.Conf(cmd, "meta.template"))
}},
"order": {Name: "order name text", Help: "列表", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Option(kit.MDB_TYPE, cmd)
m.Option(kit.MDB_NAME, arg[0])
m.Option(kit.MDB_TEXT, arg[1])
m.Optionv("list", kit.Split(strings.TrimSpace(arg[1]), "\n"))
m.Render(ice.RENDER_TEMPLATE, m.Conf(cmd, "meta.template"))
}},
"table": {Name: "table name text", Help: "表格", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Option(kit.MDB_TYPE, cmd)
m.Option(kit.MDB_NAME, arg[0])
m.Option(kit.MDB_TEXT, arg[1])
head, list := []string{}, [][]string{}
for i, v := range kit.Split(strings.TrimSpace(arg[1]), "\n") {
if i == 0 {
head = kit.Split(v)
} else {
line := kit.Split(v)
for i, v := range line {
if ls := kit.Split(v); len(ls) > 1 {
style := []string{}
for i := 1; i < len(ls)-1; i += 2 {
switch ls[i] {
case "bg":
ls[i] = "background-color"
case "fg":
ls[i] = "color"
}
style = append(style, ls[i]+":"+ls[i+1])
}
line[i] = kit.Format(`<span style="%s">%s</span>`, strings.Join(style, ";"), ls[0])
}
}
list = append(list, line)
}
}
m.Optionv("head", head)
m.Optionv("list", list)
m.Render(ice.RENDER_TEMPLATE, m.Conf(cmd, "meta.template"))
}},
"stack": {Name: "stack name text", Help: "结构", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Option(kit.MDB_TYPE, cmd)
m.Option(kit.MDB_NAME, arg[0])
m.Option(kit.MDB_TEXT, arg[1])
chain := &Chain{}
m.Render(ice.RENDER_TEMPLATE, m.Conf(cmd, "meta.template"))
Stack(m, cmd, 0, kit.Parse(nil, "", chain.show(m, arg[1])...))
m.Echo("</div>")
}},
"data": {Name: "data path auto", Help: "数据表格", Meta: kit.Dict("display", "local/wiki/data"), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) > 0 && arg[0] == "action" {
switch arg[1] {
case "保存":
m.Cmd("nfs.save", path.Join(m.Conf(cmd, "meta.path"), arg[2]), arg[3])
}
return
}
if reply(m, cmd, arg...) {
// 目录列表
return
}
// 解析数据
m.CSV(m.Result())
}},
"feel": {Name: "feel path auto 上传:button=@upload", Help: "影音媒体", Meta: kit.Dict(
"display", "local/wiki/feel", "detail", []string{"标签", "删除"},
), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if m.Option("_action") == "上传" {
m.Cmd(web.CACHE, "watch", m.Option("_data"), path.Join(m.Option("name"), m.Option("_name")))
return
}
if len(arg) > 0 && arg[0] == "action" {
switch arg[1] {
case "删除":
m.Assert(os.Remove(path.Join(m.Conf(cmd, "meta.path"), m.Option("path"))))
case "保存":
m.Cmd("nfs.save", path.Join(m.Conf(cmd, "meta.path"), arg[2]), arg[3])
case "标签":
m.Conf(cmd, kit.Keys(path.Base(arg[2]), "-2"), arg[3])
p := path.Join(m.Conf(cmd, "meta.path"), arg[2])
q := path.Join(m.Conf(cmd, "meta.path"), arg[3])
os.MkdirAll(q, 0777)
m.Assert(os.Link(p, path.Join(q, path.Base(arg[2]))))
}
return
}
if len(arg) == 0 || strings.HasSuffix(arg[0], "/") {
// 文件列表
m.Option("dir_root", m.Conf(cmd, "meta.path"))
m.Option("dir_reg", m.Conf(cmd, "meta.regs"))
m.Cmdy("nfs.dir", kit.Select("./", arg, 0), "time size path").Table(func(index int, value map[string]string, head []string) {
m.Push("label", m.Conf(cmd, path.Base(value["path"])))
})
// 目录列表
m.Option("dir_reg", "")
m.Option("dir_type", "dir")
m.Cmdy("nfs.dir", kit.Select("./", arg, 0))
if len(arg) > 0 {
m.Sort("time", "time_r")
} else {
m.Sort("line", "int_r")
}
return
}
// 下载文件
m.Echo(path.Join(m.Conf(cmd, "meta.path"), arg[0]))
}},
"walk": {Name: "walk path=@province auto", Help: "走遍世界", Meta: kit.Dict("display", "local/wiki/walk"), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) > 0 && arg[0] == "action" {
switch arg[1] {

View File

@ -12,18 +12,257 @@ import (
"strings"
)
func _title_show(m *ice.Message, kind, text string, arg ...string) {
title, _ := m.Optionv(TITLE).(map[string]int)
switch kind {
case ENDMENU:
// 后置目录
m.Render(ice.RENDER_TEMPLATE, endmenu)
return
case PREMENU:
// 前置目录
m.Render(ice.RENDER_TEMPLATE, premenu)
return
case SECTION:
// 分节标题
title[SECTION]++
m.Option("level", "h3")
m.Option("prefix", fmt.Sprintf("%d.%d", title[CHAPTER], title[SECTION]))
case CHAPTER:
// 章节标题
title[CHAPTER]++
title[SECTION] = 0
m.Option("level", "h2")
m.Option("prefix", fmt.Sprintf("%d", title[CHAPTER]))
default:
// 文章标题
m.Option("level", "h1")
m.Option("prefix", "")
}
// 基本参数
m.Option(kit.MDB_TYPE, TITLE)
m.Option(kit.MDB_NAME, text)
m.Option(kit.MDB_TEXT, text)
// 添加目录
menu, _ := m.Optionv("menu").(map[string]interface{})
menu["list"] = append(menu["list"].([]interface{}), map[string]interface{}{
"content": m.Option("content", text),
"prefix": m.Option("prefix"),
"level": m.Option("level"),
})
// 渲染引擎
m.Render(ice.RENDER_TEMPLATE, m.Conf(TITLE, "meta.template"))
}
func _brief_show(m *ice.Message, name, text string, arg ...string) {
m.Option(kit.MDB_TYPE, BRIEF)
m.Option(kit.MDB_NAME, name)
m.Option(kit.MDB_TEXT, text)
// 渲染引擎
m.Render(ice.RENDER_TEMPLATE, m.Conf(BRIEF, "meta.template"))
}
func _refer_show(m *ice.Message, name, text string, arg ...string) {
m.Option(kit.MDB_TYPE, REFER)
m.Option(kit.MDB_NAME, name)
m.Option(kit.MDB_TEXT, text)
list := [][]string{}
for _, v := range kit.Split(strings.TrimSpace(text), "\n") {
list = append(list, kit.Split(v, " "))
}
m.Optionv("list", list)
m.Render(ice.RENDER_TEMPLATE, m.Conf(REFER, "meta.template"))
}
func _spark_show(m *ice.Message, name, text string, arg ...string) {
m.Option(kit.MDB_TYPE, SPARK)
m.Option(kit.MDB_NAME, name)
m.Option(kit.MDB_TEXT, text)
m.Optionv("list", kit.Split(text, "\n"))
m.Render(ice.RENDER_TEMPLATE, m.Conf(SPARK, "meta.template"))
}
func _chart_show(m *ice.Message, kind, name, text string, arg ...string) {
var chart Chart
switch kind {
case LABEL:
// 标签
chart = &Label{}
case CHAIN:
// 链接
chart = &Chain{}
}
name = strings.TrimSpace(name)
text = strings.TrimSpace(text)
// 基本参数
m.Option(kit.MDB_TYPE, kind)
m.Option(kit.MDB_NAME, name)
m.Option(kit.MDB_TEXT, text)
// 扩展参数
m.Option("font-size", "24")
m.Option("stroke", "blue")
m.Option("fill", "yellow")
// 扩展参数
m.Option("style", "")
m.Option("compact", "false")
m.Option("stroke-width", "2")
m.Option("padding", "10")
m.Option("margin", "10")
// m.Option("font-family", kit.Select("", "monospace", len(text) == len([]rune(text))))
m.Option("font-family", "monospace")
for i := 0; i < len(arg)-1; i++ {
m.Option(arg[i], arg[i+1])
}
// 计算尺寸
chart.Init(m, text)
m.Option("width", chart.GetWidth())
m.Option("height", chart.GetHeight())
// 渲染引擎
m.Render(ice.RENDER_TEMPLATE, m.Conf(CHART, "meta.template"))
chart.Draw(m, 0, 0)
m.Render(ice.RENDER_TEMPLATE, m.Conf(CHART, "meta.suffix"))
}
func _field_show(m *ice.Message, name, text string, arg ...string) {
// 基本参数
m.Option(kit.MDB_TYPE, FIELD)
m.Option(kit.MDB_NAME, name)
m.Option(kit.MDB_TEXT, text)
// 命令参数
data := kit.Dict(kit.MDB_NAME, name)
cmds := kit.Split(text)
m.Search(cmds[0], func(p *ice.Context, s *ice.Context, key string, cmd *ice.Command) {
if ls := strings.Split(cmds[0], "."); len(ls) > 1 {
m.Cmd(ctx.COMMAND, strings.Join(ls[:len(ls)-1], "."), key)
} else {
m.Cmd(ctx.COMMAND, key)
}
if data["feature"], data["inputs"] = cmd.Meta, cmd.List; len(cmd.List) == 0 {
data["inputs"] = m.Confv("field", "meta.some.simple.inputs")
}
})
// 扩展参数
for i := 0; i < len(arg)-1; i += 2 {
if data := m.Confv("field", kit.Keys("meta.some", arg[i+1], arg[i])); data != nil {
m.Option(arg[i], data)
} else {
m.Parse("option", arg[i], arg[i+1])
}
data[arg[i]] = m.Optionv(arg[i])
}
// 渲染引擎
m.Option("meta", data)
m.Render(ice.RENDER_TEMPLATE, m.Conf(FIELD, "meta.template"))
}
func _shell_show(m *ice.Message, name, text string, arg ...string) {
m.Option(kit.MDB_TYPE, SHELL)
m.Option(kit.MDB_NAME, name)
m.Option(kit.MDB_TEXT, text)
// 渲染引擎
m.Option("output", m.Cmdx(cli.SYSTEM, "sh", "-c", m.Option("input", text)))
m.Render(ice.RENDER_TEMPLATE, m.Conf(SHELL, "meta.template"))
}
func _local_show(m *ice.Message, name, text string, arg ...string) {
m.Option(kit.MDB_TYPE, LOCAL)
m.Option(kit.MDB_NAME, name)
m.Option(kit.MDB_TEXT, text)
m.Option("input", m.Cmdx("nfs.cat", text))
m.Render(ice.RENDER_TEMPLATE, m.Conf(LOCAL, "meta.template"))
}
func _order_show(m *ice.Message, name, text string, arg ...string) {
m.Option(kit.MDB_TYPE, ORDER)
m.Option(kit.MDB_NAME, name)
m.Option(kit.MDB_TEXT, text)
m.Optionv("list", kit.Split(strings.TrimSpace(text), "\n"))
m.Render(ice.RENDER_TEMPLATE, m.Conf(ORDER, "meta.template"))
}
func _table_show(m *ice.Message, name, text string, arg ...string) {
m.Option(kit.MDB_TYPE, TABLE)
m.Option(kit.MDB_NAME, name)
m.Option(kit.MDB_TEXT, text)
head, list := []string{}, [][]string{}
for i, v := range kit.Split(strings.TrimSpace(text), "\n") {
if i == 0 {
head = kit.Split(v)
} else {
line := kit.Split(v)
for i, v := range line {
if ls := kit.Split(v); len(ls) > 1 {
style := []string{}
for i := 1; i < len(ls)-1; i += 2 {
switch ls[i] {
case "bg":
ls[i] = "background-color"
case "fg":
ls[i] = "color"
}
style = append(style, ls[i]+":"+ls[i+1])
}
line[i] = kit.Format(`<span style="%s">%s</span>`, strings.Join(style, ";"), ls[0])
}
}
list = append(list, line)
}
}
m.Optionv("head", head)
m.Optionv("list", list)
m.Render(ice.RENDER_TEMPLATE, m.Conf(TABLE, "meta.template"))
}
func _stack_show(m *ice.Message, name, text string, arg ...string) {
m.Option(kit.MDB_TYPE, STACK)
m.Option(kit.MDB_NAME, name)
m.Option(kit.MDB_TEXT, text)
chain := &Chain{}
m.Render(ice.RENDER_TEMPLATE, m.Conf(STACK, "meta.template"))
Stack(m, STACK, 0, kit.Parse(nil, "", chain.show(m, text)...))
m.Echo("</div>")
}
func _word_show(m *ice.Message, name string, arg ...string) {
m.Set(ice.MSG_RESULT)
m.Option("render", "raw")
m.Optionv(TITLE, map[string]int{})
m.Optionv("menu", map[string]interface{}{"list": []interface{}{}})
m.Optionv(ice.MSG_ALIAS, m.Confv(WORD, "meta.alias"))
m.Cmdy(ssh.SOURCE, path.Join(m.Conf(WORD, "meta.path"), name))
}
const (
WORD = "word"
TITLE = "title"
BRIEF = "brief"
REFER = "refer"
SPARK = "spark"
CHART = "chart"
FIELD = "field"
SHELL = "shell"
LOCAL = "local"
ORDER = "order"
TABLE = "table"
STACK = "stack"
CHAPTER = "chapter"
SECTION = "section"
PREMENU = "premenu"
ENDMENU = "endmenu"
PREMENU = "premenu"
LABEL = "label"
CHAIN = "chain"
@ -33,17 +272,18 @@ func init() {
Index.Merge(&ice.Context{
Configs: map[string]*ice.Config{
TITLE: {Name: "title", Help: "标题", Value: kit.Data("template", title)},
CHART: {Name: "chart", Help: "图表", Value: kit.Data("template", prefix, "suffix", `</svg>`)},
FIELD: {Name: "field", Help: "插件", Value: kit.Data("template", field,
"some", kit.Dict("simple", kit.Dict(
"inputs", kit.List(
kit.MDB_INPUT, "text", "name", "name",
kit.MDB_INPUT, "button", "value", "查看", "action", "auto",
kit.MDB_INPUT, "button", "value", "返回", "cb", "Last",
),
)),
)},
BRIEF: {Name: "brief", Help: "摘要", Value: kit.Data("template", brief)},
REFER: {Name: "refer", Help: "参考", Value: kit.Data("template", refer)},
SPARK: {Name: "spark", Help: "段落", Value: kit.Data("template", spark)},
CHART: {Name: "chart", Help: "图表", Value: kit.Data("template", chart, "suffix", `</svg>`)},
FIELD: {Name: "field", Help: "插件", Value: kit.Data("template", field)},
SHELL: {Name: "shell", Help: "命令", Value: kit.Data("template", shell)},
LOCAL: {Name: "local", Help: "文件", Value: kit.Data("template", local)},
ORDER: {Name: "order", Help: "列表", Value: kit.Data("template", order)},
TABLE: {Name: "table", Help: "表格", Value: kit.Data("template", table)},
STACK: {Name: "stack", Help: "结构", Value: kit.Data("template", stack)},
WORD: {Name: "word", Help: "语言文字", Value: kit.Data(kit.MDB_SHORT, "name",
"path", "", "regs", ".*\\.shy", "alias", map[string]interface{}{
@ -59,144 +299,64 @@ func init() {
},
Commands: map[string]*ice.Command{
TITLE: {Name: "title [chapter|section|endmenu|premenu] text", Help: "标题", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
title, _ := m.Optionv(TITLE).(map[string]int)
switch arg[0] {
case ENDMENU:
// 后置目录
m.Render(ice.RENDER_TEMPLATE, endmenu)
return
case PREMENU:
// 前置目录
m.Render(ice.RENDER_TEMPLATE, premenu)
return
case SECTION:
// 分节标题
arg = arg[1:]
title[SECTION]++
m.Option("level", "h3")
m.Option("prefix", fmt.Sprintf("%d.%d", title[CHAPTER], title[SECTION]))
case CHAPTER:
// 章节标题
arg = arg[1:]
title[CHAPTER]++
title[SECTION] = 0
m.Option("level", "h2")
m.Option("prefix", fmt.Sprintf("%d", title[CHAPTER]))
default:
// 文章标题
m.Option("level", "h1")
m.Option("prefix", "")
if len(arg) == 0 {
ns := strings.Split(cli.NodeName, "-")
arg = append(arg, kit.Select(ns[len(ns)-1], ""))
}
// 基本参数
m.Option(kit.MDB_TYPE, TITLE)
m.Option(kit.MDB_NAME, arg[0])
m.Option(kit.MDB_TEXT, arg[0])
// 添加目录
ns := strings.Split(m.Conf("runtime", "node.name"), "-")
menu, _ := m.Optionv("menu").(map[string]interface{})
menu["list"] = append(menu["list"].([]interface{}), map[string]interface{}{
"content": m.Option("content", kit.Select(ns[len(ns)-1], arg, 0)),
"prefix": m.Option("prefix"),
"level": m.Option("level"),
})
// 渲染引擎
m.Render(ice.RENDER_TEMPLATE, m.Conf(TITLE, "meta.template"))
if len(arg) == 1 {
arg = append(arg, arg[0])
}
_title_show(m, arg[0], arg[1], arg[2:]...)
}},
CHART: {Name: "chart label|chain name text", Help: "图表", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
var chart Chart
switch arg[0] {
case LABEL:
// 标签
chart = &Label{}
case CHAIN:
// 链接
chart = &Chain{}
BRIEF: {Name: "brief name text", Help: "摘要", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 {
m.Echo(`<br class="story" data-type="brief">`)
return
}
arg[1] = strings.TrimSpace(arg[1])
arg[2] = strings.TrimSpace(arg[2])
// 基本参数
m.Option(kit.MDB_TYPE, arg[0])
m.Option(kit.MDB_NAME, arg[1])
m.Option(kit.MDB_TEXT, arg[2])
// 扩展参数
m.Option("font-size", "24")
m.Option("stroke", "blue")
m.Option("fill", "yellow")
// 扩展参数
m.Option("style", "")
m.Option("compact", "false")
m.Option("stroke-width", "2")
m.Option("padding", "10")
m.Option("margin", "10")
// m.Option("font-family", kit.Select("", "monospace", len(arg[2]) == len([]rune(arg[2]))))
m.Option("font-family", "monospace")
for i := 3; i < len(arg)-1; i++ {
m.Option(arg[i], arg[i+1])
if len(arg) == 1 {
arg = []string{"", arg[0]}
}
// 计算尺寸
chart.Init(m, arg[2])
m.Option("width", chart.GetWidth())
m.Option("height", chart.GetHeight())
// 渲染引擎
m.Render(ice.RENDER_TEMPLATE, m.Conf(CHART, "meta.template"))
chart.Draw(m, 0, 0)
m.Render(ice.RENDER_TEMPLATE, m.Conf(CHART, "meta.suffix"))
_brief_show(m, arg[0], arg[1], arg[2:]...)
}},
FIELD: {Name: "field name text", Help: "插件", Action: map[string]*ice.Action{
REFER: {Name: "refer name `[name url]...`", Help: "参考", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
_refer_show(m, arg[0], arg[1], arg[2:]...)
}},
SPARK: {Name: "spark name text", Help: "感悟", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 {
m.Echo(`<br class="story" data-type="spark">`)
return
}
if len(arg) == 1 {
arg = []string{"", arg[0]}
}
_spark_show(m, arg[0], arg[1], arg[2:]...)
}},
CHART: {Name: "chart label|chain name text arg...", Help: "图表", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
_chart_show(m, arg[0], arg[1], arg[2], arg[3:]...)
}},
FIELD: {Name: "field name cmd", Help: "插件", Action: map[string]*ice.Action{
"run": {Name: "run", Help: "运行", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(arg[1:])
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
// 基本参数
m.Option(kit.MDB_TYPE, FIELD)
m.Option(kit.MDB_NAME, arg[0])
m.Option(kit.MDB_TEXT, arg[1])
// 命令参数
data := kit.Dict(kit.MDB_NAME, arg[0])
cmds := kit.Split(arg[1])
m.Search(cmds[0], func(p *ice.Context, s *ice.Context, key string, cmd *ice.Command) {
if ls := strings.Split(cmds[0], "."); len(ls) > 1 {
m.Cmd(ctx.COMMAND, strings.Join(ls[:len(ls)-1], "."), key)
} else {
m.Cmd(ctx.COMMAND, key)
}
if data["feature"], data["inputs"] = cmd.Meta, cmd.List; len(cmd.List) == 0 {
data["inputs"] = m.Confv("field", "meta.some.simple.inputs")
}
})
// 扩展参数
for i := 2; i < len(arg)-1; i += 2 {
if data := m.Confv("field", kit.Keys("meta.some", arg[i+1], arg[i])); data != nil {
m.Option(arg[i], data)
} else {
m.Parse("option", arg[i], arg[i+1])
}
data[arg[i]] = m.Optionv(arg[i])
}
// 渲染引擎
m.Option("meta", data)
m.Render(ice.RENDER_TEMPLATE, m.Conf(cmd, "meta.template"))
_field_show(m, arg[0], arg[1], arg[2:]...)
}},
SHELL: {Name: "shell name cmd", Help: "命令", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
_shell_show(m, arg[0], arg[1])
}},
LOCAL: {Name: "local name text", Help: "文件", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
_local_show(m, arg[0], arg[1])
}},
SHELL: {Name: "shell name text", Help: "命令", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
// 基本参数
m.Option(kit.MDB_TYPE, SHELL)
m.Option(kit.MDB_NAME, arg[0])
m.Option(kit.MDB_TEXT, arg[1])
// 渲染引擎
m.Option("input", strings.Join(arg[1:], " "))
m.Option("output", m.Cmdx(cli.SYSTEM, "sh", "-c", m.Option("input")))
m.Render(ice.RENDER_TEMPLATE, m.Conf(SHELL, "meta.template"))
ORDER: {Name: "order name text", Help: "列表", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
_order_show(m, arg[0], arg[1], arg[2:]...)
}},
TABLE: {Name: "table name text", Help: "表格", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
_table_show(m, arg[0], arg[1], arg[2:]...)
}},
STACK: {Name: "stack name text", Help: "结构", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
_stack_show(m, arg[0], arg[1], arg[2:]...)
}},
WORD: {Name: "word path=自然/编程/hi.shy auto", Help: "语言文字", Meta: kit.Dict(
@ -210,13 +370,7 @@ func init() {
// 目录列表
return
}
// 解析脚本
m.Option("render", "raw")
m.Optionv(TITLE, map[string]int{})
m.Optionv("menu", map[string]interface{}{"list": []interface{}{}})
m.Optionv(ice.MSG_ALIAS, m.Confv(WORD, "meta.alias"))
m.Set(ice.MSG_RESULT).Cmdy(ssh.SOURCE, path.Join(m.Conf(WORD, "meta.path"), arg[0]))
_word_show(m, arg[0])
}},
},
}, nil)

12
init.go
View File

@ -106,6 +106,18 @@ var Index = &Context{Name: "ice", Help: "冰山模块",
"help": {Name: "help", Help: "帮助", Hand: func(m *Message, c *Context, cmd string, arg ...string) {
m.Echo(strings.Join(kit.Simple(m.Confv("help", "index")), "\n"))
}},
"name": {Name: "name", Help: "命名", Hand: func(m *Message, c *Context, cmd string, arg ...string) {
for k, v := range names {
m.Push("key", k)
switch v := v.(type) {
case *Context:
m.Push("value", v.Name)
default:
m.Push("value", "")
}
}
m.Sort("key")
}},
"exit": {Name: "exit", Help: "结束", Hand: func(m *Message, c *Context, cmd string, arg ...string) {
m.root.target.server.(*Frame).code = kit.Int(kit.Select("0", arg, 0))
m.Cmd("ssh.source", "etc/exit.shy", "exit.shy", "退出配置")

View File

@ -3,8 +3,10 @@ package git
import (
ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/cli"
"github.com/shylinux/icebergs/base/mdb"
"github.com/shylinux/icebergs/base/web"
"github.com/shylinux/icebergs/core/code"
"github.com/shylinux/icebergs/core/wiki"
kit "github.com/shylinux/toolkits"
"os"
@ -78,7 +80,7 @@ var Index = &ice.Context{Name: "git", Help: "代码库",
// 应用项目
m.Cmd("nfs.dir", m.Conf(web.DREAM, "meta.path"), "name path").Table(func(index int, value map[string]string, head []string) {
add(m, value["name"], value["path"])
// add(m, value["name"], value["path"])
})
}},
"auto": {Name: "auto", Help: "自动化", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
@ -110,7 +112,9 @@ var Index = &ice.Context{Name: "git", Help: "代码库",
})
m.Sort("name")
}},
"total": {Name: "total name=auto auto", Help: "提交统计", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
"total": {Name: "total name=auto auto", Help: "提交统计", Meta: kit.Dict(
mdb.PLUGIN, wiki.DataPlugin,
), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) > 0 {
// 提交详情
m.Richs("repos", nil, arg[0], func(key string, value map[string]interface{}) {
@ -145,7 +149,7 @@ var Index = &ice.Context{Name: "git", Help: "代码库",
})
wg.Wait()
m.Push("name", "total")
m.Push("days", days)
m.Push("days", kit.Int(days)+1)
m.Push("commit", commit)
m.Push("adds", adds)
m.Push("dels", dels)
@ -208,7 +212,7 @@ var Index = &ice.Context{Name: "git", Help: "代码库",
}
args := []string{}
args = append(args, "log", "--shortstat", "--pretty=commit: %ad %n%s", "--date=iso", "--reverse")
args = append(args, "log", kit.Format("--author=%s\\|shylinux", m.Option(ice.MSG_USERNAME)), "--shortstat", "--pretty=commit: %ad %n%s", "--date=iso", "--reverse")
if len(arg) > 0 {
args = append(args, kit.Select("-n", "--since", strings.Contains(arg[0], "-")))
if strings.Contains(arg[0], "-") && !strings.Contains(arg[0], ":") {