1
0
mirror of https://shylinux.com/x/icebergs synced 2025-04-26 01:24:05 +08:00

opt vimer

This commit is contained in:
harveyshao 2022-05-15 23:28:56 +08:00
parent ef81d0b5a2
commit 13a9b81ea4
7 changed files with 243 additions and 114 deletions

View File

@ -121,8 +121,10 @@ func _cat_list(m *ice.Message, name string) {
const ( const (
CAT_CONTENT = "cat_content" CAT_CONTENT = "cat_content"
TEMPLATE = "template" TEMPLATE = "template"
WEBSITE = "website"
SOURCE = "source" SOURCE = "source"
SCRIPT = "script"
BINARY = "binary" BINARY = "binary"
TARGET = "target" TARGET = "target"

View File

@ -67,15 +67,19 @@ func _copy_file(m *ice.Message, name string, from ...string) {
} }
} }
func _link_file(m *ice.Message, name string, from string) { func _link_file(m *ice.Message, name string, from string) {
if from == "" { if from == "" || m.Warn(!kit.FileExists(from), ice.ErrNotFound, from) {
return return
} }
os.Remove(name) os.Remove(name)
MkdirAll(m, path.Dir(name)) MkdirAll(m, path.Dir(name))
if e := os.Link(from, name); e != nil { if e := os.Link(from, name); e != nil {
m.Warn(os.Symlink(from, name), ice.ErrFailure, from) if m.Warn(os.Symlink(from, name), ice.ErrFailure, from) {
return
}
} }
m.Log_EXPORT(name, "from", from)
m.Echo(name) m.Echo(name)
} }
const ( const (

View File

@ -11,6 +11,15 @@ import (
) )
func _sh_main_script(m *ice.Message, arg ...string) (res []string) { func _sh_main_script(m *ice.Message, arg ...string) (res []string) {
if cmd := ice.GetFileCmd(path.Join(arg[2], arg[1])); cmd != "" {
res = append(res, kit.Format(`#! /bin/sh
export ctx_dev=%s; ctx_temp=$(mktemp); curl -fsSL $ctx_dev -o $ctx_temp; source $ctx_temp %s &>/dev/null
_list() {
ish_sys_dev_run_command "$@"
}
`, "http://localhost:9020", cmd))
}
if kit.FileExists(kit.Path(arg[2], arg[1])) { if kit.FileExists(kit.Path(arg[2], arg[1])) {
res = append(res, kit.Format("source %s", kit.Path(arg[2], arg[1]))) res = append(res, kit.Format("source %s", kit.Path(arg[2], arg[1])))
} else if b, ok := ice.Info.Pack[path.Join(arg[2], arg[1])]; ok && len(b) > 0 { } else if b, ok := ice.Info.Pack[path.Join(arg[2], arg[1])]; ok && len(b) > 0 {
@ -55,8 +64,8 @@ func init() {
_sh_main_script(m, SH, arg[0], ice.SRC) _sh_main_script(m, SH, arg[0], ice.SRC)
return return
} }
m.Option(nfs.DIR_DEEP, ice.TRUE)
m.Option(nfs.DIR_ROOT, ice.SRC) m.Option(nfs.DIR_ROOT, ice.SRC)
m.Option(nfs.DIR_DEEP, ice.TRUE)
m.Option(nfs.DIR_REG, ".*.(sh)$") m.Option(nfs.DIR_REG, ".*.(sh)$")
m.Cmdy(nfs.DIR, arg) m.Cmdy(nfs.DIR, arg)
}}, }},
@ -81,7 +90,7 @@ func init() {
"cd", "cd",
), ),
FUNCTION, kit.Simple( FUNCTION, kit.Simple(
"xargs", "xargs", "_list",
"date", "uptime", "uname", "whoami", "date", "uptime", "uname", "whoami",
"find", "grep", "sed", "awk", "find", "grep", "sed", "awk",
"pwd", "pwd",

View File

@ -13,7 +13,7 @@ import (
const SHY = "shy" const SHY = "shy"
func init() { func init() {
Index.Register(&ice.Context{Name: SHY, Help: "脚本", Commands: map[string]*ice.Command{ Index.Merge(&ice.Context{Name: SHY, Help: "脚本", Commands: map[string]*ice.Command{
SHY: {Name: "shy path auto", Help: "脚本", Action: ice.MergeAction(map[string]*ice.Action{ SHY: {Name: "shy path auto", Help: "脚本", Action: ice.MergeAction(map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
for _, cmd := range []string{mdb.SEARCH, mdb.ENGINE, mdb.RENDER, mdb.PLUGIN} { for _, cmd := range []string{mdb.SEARCH, mdb.ENGINE, mdb.RENDER, mdb.PLUGIN} {
@ -53,5 +53,5 @@ func init() {
), ),
), KEYWORD, kit.Dict(), ), KEYWORD, kit.Dict(),
))}, ))},
}}, nil) }})
} }

View File

@ -13,43 +13,28 @@ import (
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _vimer_inputs(m *ice.Message, arg ...string) { var _cache_msg *ice.Message
switch m.Option(ctx.ACTION) { var _cache_ice *ice.Message
case web.DREAM: var _cache_bin *ice.Message
m.Cmdy(web.DREAM, mdb.INPUTS, arg)
case "script": func _vimer_defs(m *ice.Message, ext string) string {
switch arg[0] { defs := kit.Dict(
case nfs.FILE: nfs.SH, `
file, ext := m.Option(nfs.FILE), kit.Ext(m.Option(nfs.FILE)) _list
for _, t := range []string{nfs.SH, nfs.SHY, nfs.PY, nfs.JS} { `,
m.Push(nfs.FILE, strings.ReplaceAll(file, ice.PT+ext, ice.PT+t)) nfs.SHY, `
} chapter "hi"
case mdb.TEXT: `,
switch kit.Ext(m.Option(nfs.FILE)) { nfs.PY, `
case nfs.SH: print "hello world"
m.Push(mdb.TEXT, `echo "hello world"`) `,
case nfs.SHY: nfs.JS, `
m.Push(mdb.TEXT, `chapter "hi"`) Volcanos("onimport", {help: "导入数据", _init: function(can, msg) {
case nfs.PY:
m.Push(mdb.TEXT, `print "hello world"`)
case nfs.JS:
m.Push(mdb.TEXT, `Volcanos("onimport", {help: "导入数据", list:[], _init: function(can, msg, cb, target) {
msg.Echo("hello world") msg.Echo("hello world")
can.onappend.table(can, msg) msg.Dump(can)
can.onappend.board(can, msg) }})
}})`) `,
} nfs.ZML, `
}
case "website":
switch arg[0] {
case nfs.FILE:
m.Push(nfs.FILE, "hi.zml")
m.Push(nfs.FILE, "hi.iml")
case mdb.TEXT:
switch kit.Ext(m.Option(nfs.FILE)) {
case nfs.ZML:
m.Push(mdb.TEXT, `
left left
username username
系统 系统
@ -58,10 +43,15 @@ left
代码 代码
趋势 index web.code.git.trend args icebergs action auto 趋势 index web.code.git.trend args icebergs action auto
状态 index web.code.git.status args icebergs 状态 index web.code.git.status args icebergs
脚本
终端 index hi/hi.sh
文档 index hi/hi.shy
数据 index hi/hi.py
后端 index hi/hi.go
前端 index hi/hi.js
main main
`) `,
case nfs.IML: nfs.IML, `
m.Push(mdb.TEXT, `
系统 系统
命令 命令
cli.system cli.system
@ -72,13 +62,166 @@ main
hi/hi.go hi/hi.go
脚本 脚本
hi/hi.sh hi/hi.sh
hi/hi.shy
hi/hi.py
hi/hi.go
hi/hi.js hi/hi.js
`) `,
)
return kit.Format(defs[ext])
}
func _vimer_list(m *ice.Message, dir string, arg ...string) { // field
m.Copy(m.Cmd(nfs.DIR, nfs.PWD, kit.Dict(nfs.DIR_ROOT, dir, nfs.DIR_DEEP, ice.TRUE)).Cut(nfs.PATH).RenameAppend(nfs.PATH, kit.Select(mdb.NAME, arg, 0)))
}
func _vimer_inputs(m *ice.Message, arg ...string) {
switch m.Option(ctx.ACTION) {
case nfs.SCRIPT:
switch arg[0] {
case nfs.FILE:
file, ext := m.Option(nfs.FILE), kit.Ext(m.Option(nfs.FILE))
for _, t := range []string{nfs.SH, nfs.SHY, nfs.PY, nfs.JS} {
m.Push(nfs.FILE, strings.ReplaceAll(file, ice.PT+ext, ice.PT+t))
} }
} }
default:
case nfs.WEBSITE:
switch arg[0] {
case nfs.FILE:
m.Push(nfs.FILE, "hi.zml")
m.Push(nfs.FILE, "hi.iml")
}
case web.DREAM:
m.Cmdy(web.DREAM, mdb.INPUTS, arg)
} }
} }
func _vimer_complete(m *ice.Message, arg ...string) {
const (
PRE = "pre"
END = "end"
)
switch left := kit.Select("", kit.Slice(kit.Split(m.Option(PRE), "\t \n`"), -1), 0); kit.Ext(m.Option(nfs.FILE)) {
case nfs.SH:
if m.Option(PRE) == "" {
// if _cache_bin != nil {
// m.Copy(_cache_bin)
// break
// }
// _cache_bin = m
// m.Push(mdb.NAME, "_list")
// _vimer_list(m, "/bin")
// _vimer_list(m, "/sbin")
}
case nfs.SHY:
switch strings.TrimSpace(left) {
case cli.FG, cli.BG:
m.Push(mdb.NAME, cli.RED)
m.Push(mdb.NAME, cli.BLUE)
m.Push(mdb.NAME, cli.GREEN)
default:
switch kit.Select("", kit.Split(m.Option(PRE)), 0) {
case "field":
m.Cmdy(ctx.COMMAND, mdb.SEARCH, ctx.COMMAND, "", "", ice.OptionFields("index,name,text"))
_vimer_list(m, ice.SRC, ctx.INDEX)
case "chain":
m.Push(mdb.NAME, cli.FG)
m.Push(mdb.NAME, cli.BG)
}
}
case nfs.GO:
if m.Option(mdb.NAME) == ice.PT {
switch m.Option(mdb.TYPE) {
case "msg", "m":
if _cache_msg != nil {
m.Copy(_cache_msg)
break
}
_cache_msg = m
_vimer_go_complete(m, "shylinux.com/x/icebergs.Message")
_vimer_go_complete(m, "shylinux.com/x/ice.Message")
case "ice", "*ice":
if _cache_ice != nil {
m.Copy(_cache_ice)
break
}
_cache_ice = m
_vimer_go_complete(m, "shylinux.com/x/ice")
default:
_vimer_go_complete(m, m.Option(mdb.TYPE))
}
} else {
m.Push(mdb.NAME, "msg")
m.Push(mdb.NAME, "ice")
}
case nfs.JS:
if m.Option(mdb.NAME) == ice.PT {
switch m.Option(mdb.TYPE) {
case "msg":
m.Cmdy("web.code.vim.tags", "msg").Cut("name,text")
case "can":
m.Cmdy("web.code.vim.tags").Cut(mdb.ZONE)
default:
m.Cmdy("web.code.vim.tags", strings.TrimPrefix(m.Option(mdb.TYPE), "can.")).Cut("name,text")
}
} else {
m.Push(mdb.NAME, "msg")
m.Push(mdb.NAME, "can")
}
case nfs.ZML:
switch left {
case mdb.TYPE:
m.Push(mdb.NAME, "menu")
case ctx.INDEX:
m.Cmdy(ctx.COMMAND, mdb.SEARCH, ctx.COMMAND, "", "", ice.OptionFields("index,name,text"))
_vimer_list(m, ice.SRC, ctx.INDEX)
case ctx.ACTION:
m.Push(mdb.NAME, "auto")
m.Push(mdb.NAME, "push")
m.Push(mdb.NAME, "open")
default:
if strings.HasSuffix(m.Option(PRE), " ") {
m.Push(mdb.NAME, "index")
m.Push(mdb.NAME, "action")
m.Push(mdb.NAME, "args")
m.Push(mdb.NAME, "type")
} else if m.Option(PRE) == "" {
m.Push(mdb.NAME, "head")
m.Push(mdb.NAME, "left")
m.Push(mdb.NAME, "main")
m.Push(mdb.NAME, "foot")
}
}
}
}
func _vimer_go_complete(m *ice.Message, name string, arg ...string) {
kit.Fetch(kit.Split(m.Cmdx(cli.SYSTEM, GO, "doc", name), ice.NL, ice.NL, ice.NL), func(index int, value string) {
if ls := kit.Split(value); len(ls) > 1 {
switch ls[0] {
case "const", "type", "func", "var":
if ls[1] == "(" {
m.Push(mdb.NAME, strings.TrimSpace(ls[5]))
} else {
m.Push(mdb.NAME, strings.TrimSpace(ls[1]))
}
m.Push(mdb.TEXT, strings.TrimSpace(value))
}
}
})
}
const VIMER = "vimer" const VIMER = "vimer"
@ -86,30 +229,31 @@ func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{ Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
VIMER: {Name: "vimer path=src/ file=main.go line=1 list", Help: "编辑器", Meta: kit.Dict(ice.DisplayLocal("", INNER)), Action: map[string]*ice.Action{ VIMER: {Name: "vimer path=src/ file=main.go line=1 list", Help: "编辑器", Meta: kit.Dict(ice.DisplayLocal("", INNER)), Action: map[string]*ice.Action{
nfs.SAVE: {Name: "save type file path", Help: "保存", Hand: func(m *ice.Message, arg ...string) { nfs.SAVE: {Name: "save type file path", Help: "保存", Hand: func(m *ice.Message, arg ...string) {
m.Option(nfs.CONTENT, kit.Select(_vimer_defs(m, kit.Ext(m.Option(nfs.FILE))), m.Option(nfs.CONTENT)))
m.Cmdy(nfs.SAVE, path.Join(m.Option(nfs.PATH), m.Option(nfs.FILE))) m.Cmdy(nfs.SAVE, path.Join(m.Option(nfs.PATH), m.Option(nfs.FILE)))
}}, }},
AUTOGEN: {Name: "create main=src/main.go zone name=hi help=示例 type=Zone,Hash,Lists,Data,Code key", Help: "模块", Hand: func(m *ice.Message, arg ...string) { AUTOGEN: {Name: "create main=src/main.go zone name=hi help=示例 type=Zone,Hash,Lists,Data,Code key", Help: "模块", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(AUTOGEN, mdb.CREATE, arg) m.Cmdy(AUTOGEN, mdb.CREATE, arg)
}}, }},
COMPILE: {Name: "compile", Help: "编译", Hand: func(m *ice.Message, arg ...string) { COMPILE: {Name: "compile", Help: "编译", Hand: func(m *ice.Message, arg ...string) {
if msg := m.Cmd(COMPILE, ice.SRC_MAIN_GO, ice.BIN_ICE_BIN); !cli.IsSuccess(msg) { if msg := m.Cmd(COMPILE, ice.SRC_MAIN_GO, ice.BIN_ICE_BIN); cli.IsSuccess(msg) {
_inner_make(m, msg)
} else {
m.Cmd(UPGRADE, cli.RESTART) m.Cmd(UPGRADE, cli.RESTART)
} else {
_inner_make(m, msg)
} }
}}, }},
"script": {Name: "script file=hi/hi.js text=", Help: "脚本", Hand: func(m *ice.Message, arg ...string) { nfs.SCRIPT: {Name: "script file=hi/hi.js", Help: "脚本", Hand: func(m *ice.Message, arg ...string) {
m.Option(mdb.TEXT, strings.TrimSpace(m.Option(mdb.TEXT))) m.Option(mdb.TEXT, strings.TrimSpace(kit.Select(_vimer_defs(m, kit.Ext(m.Option(nfs.FILE))), m.Option(mdb.TEXT))))
m.Cmdy(TEMPLATE, nfs.DEFS)
}},
nfs.WEBSITE: {Name: "website file=hi.zml", Help: "网页", Hand: func(m *ice.Message, arg ...string) {
m.Option(mdb.TEXT, strings.TrimSpace(kit.Select(_vimer_defs(m, kit.Ext(m.Option(nfs.FILE))), m.Option(mdb.TEXT))))
m.Option(nfs.FILE, path.Join(nfs.WEBSITE, m.Option(nfs.FILE)))
m.Cmdy(TEMPLATE, nfs.DEFS) m.Cmdy(TEMPLATE, nfs.DEFS)
}}, }},
web.DREAM: {Name: "dream name=hi repos", Help: "空间", Hand: func(m *ice.Message, arg ...string) { web.DREAM: {Name: "dream name=hi repos", Help: "空间", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(web.DREAM, cli.START, arg) m.Cmdy(web.DREAM, cli.START, arg)
}}, }},
"website": {Name: "script file=hi.zml@key text@key", Help: "网页", Hand: func(m *ice.Message, arg ...string) {
m.Option(nfs.FILE, path.Join("website", m.Option(nfs.FILE)))
m.Option(mdb.TEXT, strings.TrimSpace(m.Option(mdb.TEXT)))
m.Cmdy(TEMPLATE, nfs.DEFS)
}},
PUBLISH: {Name: "publish", Help: "发布", Hand: func(m *ice.Message, arg ...string) { PUBLISH: {Name: "publish", Help: "发布", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(PUBLISH, ice.CONTEXTS) m.Cmdy(PUBLISH, ice.CONTEXTS)
}}, }},
@ -123,71 +267,30 @@ func init() {
_vimer_inputs(m, arg...) _vimer_inputs(m, arg...)
}}, }},
"complete": {Name: "complete", Help: "补全", Hand: func(m *ice.Message, arg ...string) { "complete": {Name: "complete", Help: "补全", Hand: func(m *ice.Message, arg ...string) {
left := kit.Slice(kit.Split(m.Option("pre")), -1)[0] _vimer_complete(m, arg...)
switch kit.Ext(m.Option(nfs.FILE)) { }},
case nfs.GO: "listTags": {Name: "listTags", Help: "索引", Hand: func(m *ice.Message, arg ...string) {
switch m.Option("key") { m.Cmdy("web.code.vim.tags", "listTags", arg)
case "ice", "*ice":
m.Push(mdb.NAME, "Message")
m.Push(mdb.NAME, "Context")
}
case nfs.SHY:
switch left {
case cli.FG, cli.BG:
m.Push(mdb.NAME, cli.RED)
m.Push(mdb.NAME, cli.BLUE)
m.Push(mdb.NAME, cli.GREEN)
}
case nfs.ZML:
switch left {
case ctx.INDEX:
m.OptionFields(ctx.INDEX)
m.Cmdy(ctx.COMMAND, mdb.SEARCH, ctx.COMMAND, "", "")
case ctx.ACTION:
m.Push(mdb.NAME, "auto")
m.Push(mdb.NAME, "push")
m.Push(mdb.NAME, "open")
case mdb.TYPE:
m.Push(mdb.NAME, "menu")
default:
if strings.HasSuffix(m.Option("pre"), " ") {
m.Push(mdb.NAME, "index")
m.Push(mdb.NAME, "action")
m.Push(mdb.NAME, "args")
m.Push(mdb.NAME, "type")
} else if m.Option("pre") == "" {
m.Push(mdb.NAME, "left")
m.Push(mdb.NAME, "head")
m.Push(mdb.NAME, "main")
m.Push(mdb.NAME, "foot")
}
}
}
}}, }},
"unpack": {Name: "unpack", Help: "导出文件", Hand: func(m *ice.Message, arg ...string) { "unpack": {Name: "unpack", Help: "导出文件", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(BINPACK, mdb.EXPORT) m.Cmdy(BINPACK, mdb.EXPORT)
}}, }},
BINPACK: {Name: "binpack", Help: "打包模式", Hand: func(m *ice.Message, arg ...string) {
if kit.FileExists(ice.SRC_RELEASE) {
m.Cmd(nfs.LINK, ice.GO_MOD, path.Join(ice.SRC_RELEASE, ice.GO_MOD))
m.Cmd(nfs.LINK, ice.GO_SUM, path.Join(ice.SRC_RELEASE, ice.GO_SUM))
}
m.Cmdy(nfs.CAT, ice.GO_MOD)
m.Cmdy(AUTOGEN, BINPACK)
m.ToastSuccess()
m.ProcessInner()
}},
DEVPACK: {Name: "devpack", Help: "开发模式", Hand: func(m *ice.Message, arg ...string) { DEVPACK: {Name: "devpack", Help: "开发模式", Hand: func(m *ice.Message, arg ...string) {
if kit.FileExists(ice.SRC_DEBUG) { m.Cmd(nfs.LINK, ice.GO_SUM, path.Join(ice.SRC_DEBUG, ice.GO_SUM))
m.Cmd(nfs.LINK, ice.GO_MOD, path.Join(ice.SRC_DEBUG, ice.GO_MOD)) m.Cmd(nfs.LINK, ice.GO_MOD, path.Join(ice.SRC_DEBUG, ice.GO_MOD))
m.Cmd(nfs.LINK, ice.GO_SUM, path.Join(ice.SRC_DEBUG, ice.GO_SUM))
}
m.Cmdy(nfs.CAT, ice.GO_MOD) m.Cmdy(nfs.CAT, ice.GO_MOD)
m.Cmdy(WEBPACK, mdb.REMOVE) m.Cmdy(WEBPACK, mdb.REMOVE)
m.ToastSuccess()
m.ProcessInner() m.ProcessInner()
m.ToastSuccess()
}},
BINPACK: {Name: "binpack", Help: "打包模式", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(nfs.LINK, ice.GO_SUM, path.Join(ice.SRC_RELEASE, ice.GO_SUM))
m.Cmd(nfs.LINK, ice.GO_MOD, path.Join(ice.SRC_RELEASE, ice.GO_MOD))
m.Cmdy(nfs.CAT, ice.GO_MOD)
m.Cmdy(AUTOGEN, BINPACK)
m.ProcessInner()
m.ToastSuccess()
}}, }},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Cmdy(INNER, arg) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Cmdy(INNER, arg) }},
}}) }})

View File

@ -21,6 +21,9 @@ func init() {
m.Cmd(m.PrefixKey(), mdb.INSERT, kit.SimpleKV("", "tags", arg[0], m.Result())) m.Cmd(m.PrefixKey(), mdb.INSERT, kit.SimpleKV("", "tags", arg[0], m.Result()))
return // 代码补全 return // 代码补全
} }
if arg[0] == ice.PT {
return
}
if m.Cmdy("web.code.input.wubi", ctx.ACTION, INPUT, arg[0]); m.Length() > 0 { if m.Cmdy("web.code.input.wubi", ctx.ACTION, INPUT, arg[0]); m.Length() > 0 {
m.Cmd(m.PrefixKey(), mdb.INSERT, kit.SimpleKV("", "wubi", arg[0], m.Result())) m.Cmd(m.PrefixKey(), mdb.INSERT, kit.SimpleKV("", "wubi", arg[0], m.Result()))
return // 五笔输入 return // 五笔输入

View File

@ -63,8 +63,16 @@ func init() {
if m.Option(mdb.TEXT) == "" { if m.Option(mdb.TEXT) == "" {
return return
} }
mdb.ZoneSelectCB(m, kit.Slice(kit.Split(m.Option(mdb.TEXT), ice.PT), -1)[0], func(value map[string]string) { name, list := "", kit.Select("", kit.Slice(kit.Split(m.Option(mdb.TEXT), "\t \n."), -1), 0)
if !strings.Contains(value[mdb.NAME], m.Option(mdb.NAME)) { switch name {
case "can":
mdb.ZoneSelectCB(m, "", func(value map[string]string) {
m.Echo(value[mdb.NAME] + ice.NL)
})
return
}
mdb.ZoneSelectCB(m, name, func(value map[string]string) {
if !strings.Contains(value[mdb.NAME], m.Option(mdb.NAME)) && m.Option(mdb.NAME) != "." {
return return
} }
if m.Length() == 0 { if m.Length() == 0 {