diff --git a/base/lex/split.go b/base/lex/split.go index bcd833fe..1b3ad89e 100644 --- a/base/lex/split.go +++ b/base/lex/split.go @@ -8,37 +8,34 @@ import ( kit "shylinux.com/x/toolkits" ) -func _split_deep(text string) (deep int) { +func _split_tab(text string) (tab int) { for _, c := range text { switch c { case '\t': - deep += 4 + tab += 4 case ' ': - deep++ + tab++ default: return } } return } -func _split_deep2(stack []int, text string) ([]int, int) { - deep := _split_deep(text) +func _split_deep(stack []int, text string) ([]int, int) { + tab := _split_tab(text) for i := len(stack) - 1; i >= 0; i-- { - if deep <= stack[i] { + if tab <= stack[i] { stack = stack[:len(stack)-1] } } - stack = append(stack, deep) + stack = append(stack, tab) return stack, len(stack) } -func _split_list(m *ice.Message, file string, arg ...string) { +func _split_list(m *ice.Message, file string, arg ...string) map[string]interface{} { const DEEP = "_deep" - list := kit.List(kit.Data(DEEP, -1)) stack, deep := []int{}, 0 + list := kit.List(kit.Data(DEEP, -1)) m.Cmd(nfs.CAT, file, func(text string) { - // if text = kit.Split(text, "#", "#")[0]; strings.TrimSpace(text) == "" { - // return - // } if strings.HasPrefix(strings.TrimSpace(text), "# ") { return } @@ -46,11 +43,10 @@ func _split_list(m *ice.Message, file string, arg ...string) { return } - // deep := _split_deep(text) - stack, deep = _split_deep2(stack, text) + stack, deep = _split_deep(stack, text) data := kit.Data(DEEP, deep) - ls := kit.Split(text) + ls := kit.Split(text, m.Option(SPLIT_SPACE), m.Option(SPLIT_BLOCK), m.Option(SPLIT_QUOTE)) switch cb := m.OptionCB(SPLIT).(type) { case func([]string, map[string]interface{}) []string: ls = cb(ls, data) @@ -77,9 +73,17 @@ func _split_list(m *ice.Message, file string, arg ...string) { list = list[:len(list)-1] } }) - m.Echo(kit.Format(list[0])) + return list[0].(map[string]interface{}) +} +func Split(m *ice.Message, arg ...string) map[string]interface{} { + return kit.Value(_split_list(m, arg[0], arg[1:]...), "list.0").(map[string]interface{}) } +const ( + SPLIT_SPACE = "split.space" + SPLIT_BLOCK = "split.block" + SPLIT_QUOTE = "split.quote" +) const SPLIT = "split" func init() { @@ -92,7 +96,7 @@ func init() { return } - _split_list(m, arg[0], arg[1:]...) + m.Echo(kit.Format(_split_list(m, arg[0], arg[1:]...))) m.ProcessDisplay("/plugin/local/wiki/json.js") }}, }}) diff --git a/core/wiki/chart.go b/core/wiki/chart.go index 56a8d813..f43046b7 100644 --- a/core/wiki/chart.go +++ b/core/wiki/chart.go @@ -1,21 +1,55 @@ package wiki import ( + "strings" + ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/cli" + "shylinux.com/x/icebergs/base/lex" + "shylinux.com/x/icebergs/base/nfs" kit "shylinux.com/x/toolkits" - - "strings" ) +type item struct { + list []string + args []interface{} +} + +func newItem(list []string, args ...interface{}) *item { + return &item{list, args} +} +func (item *item) echo(str string, arg ...interface{}) *item { + item.list = append(item.list, kit.Format(str, arg...)) + return item +} +func (item *item) push(str string, arg interface{}) *item { + switch arg := arg.(type) { + case string: + if arg == "" { + return item + } + case int: + if arg == 0 { + return item + } + } + item.list, item.args = append(item.list, str), append(item.args, arg) + return item +} +func (item *item) dump(m *ice.Message) *item { + m.Echo(kit.Join(item.list, ice.SP), item.args...) + m.Echo(ice.NL) + return item +} + // 图形接口 type Chart interface { Init(*ice.Message, ...string) Chart Data(*ice.Message, interface{}) Chart Draw(*ice.Message, int, int) Chart - GetWidth(...string) int GetHeight(...string) int + GetWidth(...string) int } // 图形基类 @@ -25,31 +59,46 @@ type Block struct { FontColor string BackGround string + TextData string + RectData string + Padding int MarginX int MarginY int - Width, Height int - - TextData string - RectData string - - x, y int + Height int + Width int + x, y int } func (b *Block) Init(m *ice.Message, arg ...string) Chart { - b.Text = kit.Select(b.Text, arg, 0) - b.FontSize = kit.Int(kit.Select(m.Option(FONT_SIZE), kit.Select(kit.Format(b.FontSize), arg, 1))) - b.FontColor = kit.Select(m.Option(STROKE), kit.Select(b.FontColor, arg, 2)) - b.BackGround = kit.Select(m.Option(FILL), kit.Select(b.BackGround, arg, 3)) - b.Padding = kit.Int(kit.Select(m.Option(PADDING), kit.Select(kit.Format(b.Padding), arg, 4))) - b.MarginX = kit.Int(kit.Select(m.Option(MARGINX), kit.Select(kit.Format(b.MarginX), arg, 5))) - b.MarginY = kit.Int(kit.Select(m.Option(MARGINY), kit.Select(kit.Format(b.MarginY), arg, 5))) + if len(arg) > 0 { + b.Text = arg[0] + } + if len(arg) > 1 { + b.FontSize = kit.Int(arg[1]) + } + if len(arg) > 2 { + b.FontColor = arg[2] + } + if len(arg) > 3 { + b.BackGround = arg[3] + } + if len(arg) > 4 { + b.Padding = kit.Int(arg[4]) + } + if len(arg) > 5 { + b.MarginX = kit.Int(arg[5]) + b.MarginY = kit.Int(arg[5]) + } + if len(arg) > 6 { + b.MarginY = kit.Int(arg[6]) + } return b } -func (b *Block) Data(m *ice.Message, root interface{}) Chart { - b.Text = kit.Select(b.Text, kit.Value(root, kit.MDB_TEXT)) - kit.Fetch(root, func(key string, value string) { +func (b *Block) Data(m *ice.Message, meta interface{}) Chart { + b.Text = kit.Select(b.Text, kit.Value(meta, kit.MDB_TEXT)) + kit.Fetch(meta, func(key string, value string) { switch key { case FG: b.TextData += kit.Format("%s='%s' ", FILL, value) @@ -57,10 +106,10 @@ func (b *Block) Data(m *ice.Message, root interface{}) Chart { b.RectData += kit.Format("%s='%s' ", FILL, value) } }) - kit.Fetch(kit.Value(root, "data"), func(key string, value string) { + kit.Fetch(kit.Value(meta, "data"), func(key string, value string) { b.TextData += kit.Format("%s='%s' ", key, value) }) - kit.Fetch(kit.Value(root, "rect"), func(key string, value string) { + kit.Fetch(kit.Value(meta, "rect"), func(key string, value string) { b.RectData += kit.Format("%s='%s' ", key, value) }) return b @@ -70,15 +119,21 @@ func (b *Block) Draw(m *ice.Message, x, y int) Chart { if strings.Contains(m.Option(ice.MSG_USERUA), "iPhone") { float += 5 } - m.Echo(``, - x+b.MarginX/2, y+b.MarginY/2, b.GetWidth(), b.GetHeight(), b.BackGround, b.RectData) - m.Echo(ice.NL) - m.Echo(`%v`, - x+b.GetWidths()/2, y+b.GetHeights()/2+float, b.FontColor, b.FontColor, b.TextData, b.Text) - m.Echo("\n") + if m.Option(HIDE_BLOCK) != ice.TRUE { + item := newItem([]string{`").dump(m) + } + item := newItem([]string{`%v`, b.Text).dump(m) return b } +func (b *Block) GetHeight(str ...string) int { + if b.Height != 0 { + return b.Height + } + return b.FontSize + b.Padding +} func (b *Block) GetWidth(str ...string) int { if b.Width != 0 { return b.Width @@ -88,12 +143,6 @@ func (b *Block) GetWidth(str ...string) int { en := len([]rune(s)) - cn return cn*b.FontSize + en*b.FontSize*10/16 + b.Padding } -func (b *Block) GetHeight(str ...string) int { - if b.Height != 0 { - return b.Height - } - return b.FontSize + b.Padding -} func (b *Block) GetWidths(str ...string) int { return b.GetWidth(str...) + b.MarginX } @@ -109,7 +158,6 @@ type Label struct { } func (b *Label) Init(m *ice.Message, arg ...string) Chart { - b.Text = kit.Select(b.Text, arg, 0) b.FontSize = kit.Int(m.Option(FONT_SIZE)) b.Padding = kit.Int(m.Option(PADDING)) b.MarginX = kit.Int(m.Option(MARGINX)) @@ -119,54 +167,35 @@ func (b *Label) Init(m *ice.Message, arg ...string) Chart { b.max = map[int]int{} for _, v := range strings.Split(arg[0], ice.NL) { l := kit.Split(v, ice.SP, ice.SP) + b.data = append(b.data, l) + for i, v := range l { switch data := kit.Parse(nil, "", kit.Split(v)...).(type) { case map[string]interface{}: v = kit.Select("", data[kit.MDB_TEXT]) } - if w := b.GetWidth(v); w > b.max[i] { b.max[i] = w } } - b.data = append(b.data, l) } // 计算尺寸 + b.Height = len(b.data) * b.GetHeights() for _, v := range b.max { b.Width += v + b.MarginX } - b.Height = len(b.data) * b.GetHeights() return b } func (b *Label) Draw(m *ice.Message, x, y int) Chart { - order, _ := kit.Parse(nil, "", kit.Split(m.Option("order"))...).(map[string]interface{}) - + var item *Block top := y for _, line := range b.data { left := x for i, text := range line { // 数据 - item := &Block{ - FontSize: b.FontSize, - Padding: b.Padding, - MarginX: b.MarginX, - MarginY: b.MarginY, - } - if order != nil { - if w := kit.Int(kit.Value(order, "index")); w != 0 && i%w == 0 { - for k, v := range order { - switch k { - case FG: - item.FontColor = kit.Format(v) - case BG: - item.BackGround = kit.Format(v) - } - } - } - } - + item = &Block{FontSize: b.FontSize, Padding: b.Padding, MarginX: b.MarginX, MarginY: b.MarginY} switch data := kit.Parse(nil, "", kit.Split(text)...).(type) { case map[string]interface{}: item.Init(m, kit.Select(text, data[kit.MDB_TEXT])).Data(m, data) @@ -185,10 +214,9 @@ func (b *Label) Draw(m *ice.Message, x, y int) Chart { } item.Draw(m, left, top) - left += item.GetWidth() + item.MarginX - b.Height = item.GetHeight() + left += item.GetWidths() } - top += b.Height + b.MarginY + top += item.GetHeights() } return b } @@ -196,7 +224,7 @@ func (b *Label) Draw(m *ice.Message, x, y int) Chart { // 链 type Chain struct { data map[string]interface{} - max map[int]int + ship []string Block } @@ -207,161 +235,105 @@ func (b *Chain) Init(m *ice.Message, arg ...string) Chart { b.MarginY = kit.Int(m.Option(MARGINY)) // 解析数据 - b.data = kit.Parse(nil, "", b.show(m, arg[0])...).(map[string]interface{}) + m.Option(nfs.CAT_CONTENT, arg[0]) + m.Option(lex.SPLIT_SPACE, "\t \n") + m.Option(lex.SPLIT_BLOCK, "\t \n") + b.data = lex.Split(m, "", kit.MDB_TEXT) // 计算尺寸 - b.max = map[int]int{} - b.Height = b.size(m, b.data, 0, b.max) * b.GetHeights() - for _, v := range b.max { - b.Width += v + b.MarginX - } + b.Height = b.size(m, b.data) * b.GetHeights() + b.Draw(m, 0, 0) + b.Width += 200 + m.Set(ice.MSG_RESULT) return b } func (b *Chain) Draw(m *ice.Message, x, y int) Chart { - b.draw(m, b.data, 0, b.max, x, y, &Block{}) + b.draw(m, b.data, x, y, &b.Block) + m.Echo(``, m.Option(SHIP_STROKE), m.Option(SHIP_STROKE_WIDTH)) + defer m.Echo(``) + for _, ship := range b.ship { + m.Echo(ship) + } return b } -func (b *Chain) show(m *ice.Message, str string) (res []string) { - miss := []int{} - for _, line := range kit.Split(str, ice.NL, ice.NL) { - // 计算缩进 - dep := 0 - loop: - for _, v := range []rune(line) { - switch v { - case ' ': - dep++ - case '\t': - dep += 4 - default: - break loop - } - } - - // 计算层次 - if len(miss) > 0 { - if miss[len(miss)-1] > dep { - for i := len(miss) - 1; i >= 0; i-- { - if miss[i] < dep { - break - } - res = append(res, "]", "}") - miss = miss[:i] - } - miss = append(miss, dep) - } else if miss[len(miss)-1] < dep { - miss = append(miss, dep) - } else { - res = append(res, "]", "}") - } - } else { - miss = append(miss, dep) - } - - // 输出节点 - word := kit.Split(line, "\t ", "\t ") - res = append(res, "{", kit.MDB_META, "{", "text") - res = append(res, word...) - res = append(res, "}", kit.MDB_LIST, "[") - } - return -} -func (b *Chain) size(m *ice.Message, root map[string]interface{}, depth int, width map[int]int) int { - meta := root[kit.MDB_META].(map[string]interface{}) - - // 最大宽度 - if w := b.GetWidths(kit.Format(meta[kit.MDB_TEXT])); w > width[depth] { - width[depth] = w - } - - // 计算高度 - height := 0 +func (b *Chain) size(m *ice.Message, root map[string]interface{}) (height int) { + meta := kit.GetMeta(root) if list, ok := root[kit.MDB_LIST].([]interface{}); ok && len(list) > 0 { kit.Fetch(root[kit.MDB_LIST], func(index int, value map[string]interface{}) { - height += b.size(m, value, depth+1, width) + height += b.size(m, value) }) } else { height = 1 } - meta[HEIGHT] = height return height } -func (b *Chain) draw(m *ice.Message, root map[string]interface{}, depth int, width map[int]int, x, y int, p *Block) int { - meta := root[kit.MDB_META].(map[string]interface{}) - b.Width, b.Height = 0, 0 +func (b *Chain) draw(m *ice.Message, root map[string]interface{}, x, y int, p *Block) int { + meta := kit.GetMeta(root) + b.Height, b.Width = 0, 0 // 当前节点 item := &Block{ - BackGround: kit.Select(b.BackGround, kit.Select(p.BackGround, meta[BG])), - FontColor: kit.Select(b.FontColor, kit.Select(p.FontColor, meta[FG])), - FontSize: b.FontSize, - Padding: b.Padding, - MarginX: b.MarginX, - MarginY: b.MarginY, + BackGround: kit.Select(p.BackGround, meta[BG]), + FontColor: kit.Select(p.FontColor, meta[FG]), + FontSize: p.FontSize, + Padding: p.Padding, + MarginX: p.MarginX, + MarginY: p.MarginY, } - if m.Option(COMPACT) != ice.TRUE { - item.Width = b.max[depth] - } - item.x = x - item.y = y + (kit.Int(meta[HEIGHT])-1)*b.GetHeights()/2 + item.x, item.y = x, y+(kit.Int(meta[HEIGHT])-1)*b.GetHeights()/2 item.Init(m, kit.Format(meta[kit.MDB_TEXT])).Data(m, meta) item.Draw(m, item.x, item.y) + // 画面尺寸 + if item.y+item.GetHeight()+b.MarginY > b.Height { + b.Height = item.y + item.GetHeight() + b.MarginY + } + if item.x+item.GetWidth()+b.MarginX > b.Width { + b.Width = item.x + item.GetWidth() + b.MarginX + } + + // 模块连线 if p != nil && p.y != 0 { - x1 := p.x + p.GetWidths() - (p.MarginX+item.MarginX)/4 - y1 := p.y + p.GetHeights()/2 - x4 := item.x + (p.MarginX+item.MarginX)/4 - y4 := item.y + item.GetHeights()/2 - m.Echo(``, - x1, y1, x1+(x4-x1)/4, y1, x1+(x4-x1)/2, y1+(y4-y1)/2, x4, y4) + x1, y1 := p.x+p.GetWidths()-(p.MarginX+item.MarginX)/4, p.y+p.GetHeights()/2 + x4, y4 := item.x+(p.MarginX+item.MarginX)/4, item.y+item.GetHeights()/2 + b.ship = append(b.ship, kit.Format(``, + x1, y1, x1+(x4-x1)/4, y1, x1+(x4-x1)/2, y1+(y4-y1)/2, x4, y4)) } // 递归节点 - h := 0 - x += item.GetWidths() - kit.Fetch(root[kit.MDB_LIST], func(index int, value map[string]interface{}) { - h += b.draw(m, value, depth+1, width, x, y+h, item) - }) - if h == 0 { + h, x := 0, x+item.GetWidths() + if kit.Fetch(root[kit.MDB_LIST], func(index int, value map[string]interface{}) { + h += b.draw(m, value, x, y+h, item) + }); h == 0 { return item.GetHeights() } return h } -func _chart_show(m *ice.Message, kind, text string, arg ...string) { - var chart Chart - switch kind { - case LABEL: // 标签 - chart = &Label{} - case CHAIN: // 链接 - chart = &Chain{} - } +var chart_list = map[string]func(m *ice.Message) Chart{} - // 扩展参数 - m.Option(FONT_SIZE, "24") +func _chart_show(m *ice.Message, kind, text string, arg ...string) { + // 画笔参数 + m.Option(STROKE_WIDTH, "2") m.Option(STROKE, cli.BLUE) m.Option(FILL, cli.YELLOW) - // 扩展参数 - m.Option(STYLE, "") - m.Option(STROKE_WIDTH, "2") + m.Option(FONT_SIZE, "24") m.Option(FONT_FAMILY, "monospace") - // 扩展参数 - m.Option(COMPACT, ice.FALSE) + + // 几何参数 m.Option(PADDING, "10") m.Option(MARGINX, "10") m.Option(MARGINY, "10") - // m.Option("font-family", kit.Select("", "monospace", len(text) == len([]rune(text)))) + chart := chart_list[kind](m) + + // 解析参数 for i := 0; i < len(arg)-1; i++ { m.Option(arg[i], arg[i+1]) } - if m.Option(BG) != "" { - m.Option(FILL, m.Option(BG)) - } - if m.Option(FG) != "" { - m.Option(STROKE, m.Option(FG)) - } + m.Option(FILL, kit.Select(m.Option(FILL), m.Option(BG))) + m.Option(STROKE, kit.Select(m.Option(STROKE), m.Option(FG))) // 计算尺寸 chart.Init(m, text) @@ -370,30 +342,36 @@ func _chart_show(m *ice.Message, kind, text string, arg ...string) { // 渲染引擎 _wiki_template(m, CHART, "", text) - defer m.Echo(``) + defer m.Echo("") chart.Draw(m, 0, 0) + m.RenderResult() +} +func AddChart(name string, hand func(m *ice.Message) Chart) { + chart_list[name] = hand } const ( - FG = "fg" - BG = "bg" - FILL = "fill" - STROKE = "stroke" + FG = "fg" + BG = "bg" + + STROKE_WIDTH = "stroke-width" + STROKE = "stroke" + FILL = "fill" + FONT_SIZE = "font-size" + FONT_FAMILY = "font-family" - STYLE = "style" - WIDTH = "width" - HEIGHT = "height" PADDING = "padding" MARGINX = "marginx" MARGINY = "marginy" + HEIGHT = "height" + WIDTH = "width" - FONT_SIZE = "font-size" - FONT_FAMILY = "font-family" - - STROKE_WIDTH = "stroke-width" - - COMPACT = "compact" - + COMPACT = "compact" + HIDE_BLOCK = "hide-block" + SHIP_STROKE = "ship-stroke" + SHIP_STROKE_WIDTH = "ship-stroke-width" +) +const ( LABEL = "label" CHAIN = "chain" ) @@ -401,17 +379,35 @@ const CHART = "chart" func init() { Index.Merge(&ice.Context{Commands: map[string]*ice.Command{ - CHART: {Name: "chart label|chain text", Help: "图表", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - _chart_show(m, arg[0], strings.TrimSpace(arg[1]), arg[2:]...) + CHART: {Name: "chart type=label,chain auto text", Help: "图表", Action: map[string]*ice.Action{ + ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { + AddChart(LABEL, func(m *ice.Message) Chart { + return &Label{} + }) + AddChart(CHAIN, func(m *ice.Message) Chart { + m.Option(STROKE_WIDTH, "1") + m.Option(FILL, cli.BLUE) + m.Option(MARGINX, "40") + m.Option(MARGINY, "0") + + m.Option(COMPACT, ice.TRUE) + m.Option(HIDE_BLOCK, ice.TRUE) + m.Option(SHIP_STROKE, cli.CYAN) + m.Option(SHIP_STROKE_WIDTH, "1") + return &Chain{} + }) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if len(arg) > 1 { + _chart_show(m, arg[0], strings.TrimSpace(arg[1]), arg[2:]...) + } }}, }, Configs: map[string]*ice.Config{ CHART: {Name: CHART, Help: "图表", Value: kit.Data( kit.MDB_TEMPLATE, ``, +vertion="1.1" xmlns="http://www.w3.org/2000/svg" height="{{.Option "height"}}" width="{{.Option "width"}}" +stroke-width="{{.Option "stroke-width"}}" stroke="{{.Option "stroke"}}" fill="{{.Option "fill"}}" +font-size="{{.Option "font-size"}}" font-family="{{.Option "font-family"}}" text-anchor="middle" dominant-baseline="middle">`, )}, }}) } diff --git a/core/wiki/word.go b/core/wiki/word.go index 5c651e02..0e21f41b 100644 --- a/core/wiki/word.go +++ b/core/wiki/word.go @@ -3,6 +3,7 @@ package wiki import ( ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/ctx" + "shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/ssh" "shylinux.com/x/icebergs/base/web" @@ -25,19 +26,22 @@ func init() { Index.Merge(&ice.Context{Configs: map[string]*ice.Config{ WORD: {Name: WORD, Help: "语言文字", Value: kit.Data( kit.MDB_PATH, "", kit.MDB_REGEXP, ".*\\.shy", kit.MDB_ALIAS, kit.Dict( - NAVMENU, []interface{}{TITLE, NAVMENU}, - PREMENU, []interface{}{TITLE, PREMENU}, - CHAPTER, []interface{}{TITLE, CHAPTER}, - SECTION, []interface{}{TITLE, SECTION}, - ENDMENU, []interface{}{TITLE, ENDMENU}, - LABEL, []interface{}{CHART, LABEL}, - CHAIN, []interface{}{CHART, CHAIN}, + NAVMENU, kit.List(TITLE, NAVMENU), + PREMENU, kit.List(TITLE, PREMENU), + CHAPTER, kit.List(TITLE, CHAPTER), + SECTION, kit.List(TITLE, SECTION), + ENDMENU, kit.List(TITLE, ENDMENU), + LABEL, kit.List(CHART, LABEL), + CHAIN, kit.List(CHART, CHAIN), ), )}, }, Commands: map[string]*ice.Command{ - WORD: {Name: "word path=src/main.shy auto play", Help: "语言文字", Meta: kit.Dict( + WORD: {Name: "word path=src/main.shy@key auto play", Help: "语言文字", Meta: kit.Dict( ice.Display("/plugin/local/wiki/word.js"), ), Action: ice.MergeAction(map[string]*ice.Action{ + mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(nfs.DIR, "src/", kit.Dict(nfs.DIR_DEEP, ice.TRUE, nfs.DIR_REG, ".*\\.shy"), "path,time") + }}, web.STORY: {Name: "story", Help: "运行", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(arg[0], ctx.ACTION, ice.RUN, arg[2:]) }},