diff --git a/frame.js b/frame.js index 18526121..b753c084 100644 --- a/frame.js +++ b/frame.js @@ -102,14 +102,20 @@ Volcanos("onappend", { _init: function(can, meta, list, cb, target, field) { _option: option, _action: action, _output: output, _follow: can._follow+"."+meta.name, _history: [], Option: function(key, value) { - sub.page.Select(sub, option, "input[name="+key+"]", function(item) { + sub.page.Select(sub, option, "select[name="+key+"],input[name="+key+"]", function(item) { + value == undefined? (value = item.value): (item.value = value) + }) + return value + }, + Action: function(key, value) { + sub.page.Select(sub, action, "select[name="+key+"],input[name="+key+"]", function(item) { value == undefined? (value = item.value): (item.value = value) }) return value }, Status: function(key, value) { - sub.page.Select(sub, status, "div."+key, function(item) { - item.innerHTML = key+": "+value + sub.page.Select(sub, status, "div."+key+">span", function(item) { + item.innerHTML = value }) return value }, @@ -157,20 +163,22 @@ Volcanos("onappend", { _init: function(can, meta, list, cb, target, field) { sub[display] = Volcanos(display, { _help: display, _target: output, _option: option, _action: action, _output: output, _follow: can._follow+"."+meta.name+"."+display, - Option: sub.Option, Status: sub.Status, + Option: sub.Option, Action: sub.Action, Status: sub.Status, }, Volcanos.meta.libs.concat(["/frame.js", display]), function(table) { table.Conf(sub.Conf()) table.onimport._init(table, msg, msg.append||[], function() {}, output) - table.run = function(event, cmds, cb, silent) { + table.run = function(event, cmds, cb, silent) { cmds = cmds || [] // 组件回调 cmds[0] == "field"? sub.run(event, cmds.slice(1), cb, silent): input.run(event, cmds, cb, silent) } // 工具栏 action.innerHTML = "", table.onaction && can.core.List(table.onaction.list, function(item) { - can.onappend.input(can, action, "input", {type: "button", value: item, onclick: function(event) { + typeof item == "string"? can.onappend.input(can, action, "input", {type: "button", value: item, onclick: function(event) { table.onaction[item](event, table, msg) - }}) + }}): item.length > 0? can.onappend.input(can, action, "input", {type: "select", values: item.slice(1), name: item[0], onchange: function(event) { + table.onaction[item[0]](event, table, msg, item[event.target.selectedIndex+1]) + }}): typeof item == "object" && can.onappend.input(can, action, "input", item) }) // 上下文 @@ -182,7 +190,7 @@ Volcanos("onappend", { _init: function(can, meta, list, cb, target, field) { // 状态条 status.innerHTML = "", table.onexport && can.core.List(table.onexport.list, function(item) { - can.page.Append(can, status, [{view: "item "+item, inner: item, title: item}]) + can.page.Append(can, status, [{view: "item "+item, title: item, list: [{text: [item+": ", "label"]}, {text: ["", "span"]}]}]) }) }) var table = sub[display]; @@ -268,7 +276,7 @@ Volcanos("onappend", { _init: function(can, meta, list, cb, target, field) { item.type == "text" && !target.placeholder && (target.placeholder = item.name || ""); item.type != "button" && !target.title && (target.title = target.placeholder); // item.type == "button" && item.action == "auto" && can.run && can.run({}); - item.type == "select" && (target.value = item.value || item.values[item.index||0]); + // item.type == "select" && (target.value = item.value || item.values[item.index||0]); return target; }, table: function(can, target, type, msg) { diff --git a/index.css b/index.css index dbb6741c..6737a091 100644 --- a/index.css +++ b/index.css @@ -79,6 +79,11 @@ fieldset>div.action>div.item { } fieldset>div.status>div.item { float:left; + padding:4px; +} +fieldset>div.status>div.item>label { + font-size:14px; + color:gray; } fieldset div.output { diff --git a/lib/core.js b/lib/core.js index bd2c3d7a..a3f6aa8b 100644 --- a/lib/core.js +++ b/lib/core.js @@ -61,7 +61,93 @@ Volcanos("core", {help: "核心模块", return obj }), - Split: shy("分词器", function(str, sep) { - return str.trim().split(sep||" ") + Split: shy("分词器", function(str) { if (!str || !str.length) {return []} + + var arg = []; for (var i = 1; i < arguments.length; i++) { + arg.push(arguments[i]) + } + + // 空白符 + var sep = "\t ,\n" + if (arg.length > 0 && arg[0].length > 0) { + sep = arg[0] + } + for (var i = sep.length; i < 5; i++) { + sep += sep[0] + } + + // 分隔符 + var sup = "{[()]}" + if (arg.length > 1 && arg[1].length > 0) { + sup = arg[1] + } + for (var i = sup.length; i < 10; i++) { + sup += sup[0] + } + + // 引用符 + var sub = "'\"`" + if (arg.length > 2 && arg[2].length > 0) { + sub = arg[2] + } + for (var i = sub.length; i < 5; i++) { + sub += sub[0] + } + + var res = [] + // 开始分词 + var list = str + var left = '\000', space = true, begin = 0 + for (var i = 0; i < list.length; i++) { + if (list[i] == sep[0] || list[i] == sep[1] || list[i] == sep[2] || list[i] == sep[3] || list[i] == sep[4]) { + if (left == '\000') { + if (!space) { + // 空白分隔 + res.push(list.slice(begin, i)) + } + space = true, begin = i+1 + } + } else if (list[i] == sub[0] || list[i] == sub[1] || list[i] == sub[2] || list[i] == sub[3] || list[i] == sub[4]) { + if (arg.length > 0) { + if (left == '\000') { + left = list[i] + } else if (left == list[i]) { + left = '\000' + } + break + } else { + if (left == '\000') { + left = list[i], space = false, begin = i+1 + } else if (left == list[i]) { + // 引用分隔 + res.push({text: list.slice(begin, i), type: "str"}) + left = '\000', space = true, begin = i+1 + } + } + } else if (list[i] == sup[0] || list[i] == sup[1] || list[i] == sup[2] || list[i] == sup[3] || list[i] == sup[4] || list[i] == sup[5] || list[i] == sup[6] || list[i] == sup[7] || list[i] == sup[8] || list[i] == sup[9]) { + if (left == '\000') { + if (!space) { + res.push(list.slice(begin, i)) + } + // 分隔分隔 + res.push(list.slice(i, i+1)) + space = true, begin = i+1 + } + } else if (list[0] == '\\') { + for (var i = i; i < list.length-1; i++) { + list[i] = list[i+1] + } + list = list.slice(0, list.length-1) + space = false + } else { + space = false + } + } + + // 末尾单词 + if (begin < list.length) { + res.push(list.slice(begin)) + } + return res }), }) diff --git a/plugin/inner.css b/plugin/inner.css index 8573e490..ab28ff52 100644 --- a/plugin/inner.css +++ b/plugin/inner.css @@ -38,6 +38,12 @@ fieldset.editor>div.output div.content>pre.item { height:20px; margin:0; } -fieldset.editor>div.output div.content>pre.item:hover { - background-color:green; +fieldset.editor>div.output div.content>pre.item span.keyword { + color:yellow; +} +fieldset.editor>div.output div.content>pre.item span.string { + color:magenta; +} +fieldset.editor>div.output div.content>pre.item:hover { + border:solid 1px red; } diff --git a/plugin/inner.js b/plugin/inner.js index ab86991f..91c009ba 100644 --- a/plugin/inner.js +++ b/plugin/inner.js @@ -1,50 +1,163 @@ Volcanos("onimport", {help: "导入数据", _init: function(can, msg, list, cb, target) { target.innerHTML = ""; can.onappend.table(can, target, "table", msg); + can.history = [] can.ui = can.page.Append(can, target, [{view: ["editor", "textarea"], onkeydown: function(event) { - (can.onkeymap[can.mode][event.key]||function() {})(event, can) + can.history.push(event.key); if (can.mode == "normal") { + event.stopPropagation() + event.preventDefault() + } + + can.Status("输入值", can.history.join()) + var cb = can.onkeymap[can.mode][event.key] + if (typeof cb == "function") { can.history = []; return cb(event, can) } + + var map = can.onkeymap[can.mode]._engine + for (var i = can.history.length-1; i > -1; i--) { + var pos = map[can.history[i]] + if (typeof pos == "object") { map = pos; continue } + if (typeof pos == "function") { pos(event, can); can.history = [] } break + } }, onkeyup: function(event) { }, onblur: function(event) { can.onaction.modifyLine(can, can.current, can.editor.value) }}, {view: "lineno", style: {width: "30px"}}, {view: "content", style: {"margin-left": "30px"}}, ]); - can.max = 0, can.ls = msg.Result().split("\n"); - can.editor = can.ui.editor, can.mode = "modify"; + can.core.List(can.onkeymap.list, function(item) { var engine = {}; + can.core.Item(can.onkeymap[item], function(key, cb) { var map = engine; + for (var i = key.length-1; i > -1; i--) { + map = map[key[i]] = i == 0? cb: (map[key[i]]||{}); + } + }) + can.onkeymap[item]._engine = engine + }) + console.log(can.onkeymap) + + can.editor = can.ui.editor, can.max = 0, can.ls = msg.Result().split("\n"); can.core.List(can.ls, function(item) { can.onaction.appendLine(can, item) }); + can.Timer(100, function() { + can.onaction.selectLine(can, 0); + can.onaction.mode(null, can, null, "normal"); + can.Status("文件名", can.Option("path")) + can.Status("解析器", "go") + }) return typeof cb == "function" && cb(msg); }, }, ["/plugin/inner.css"]) -Volcanos("onkeymap", {help: "键盘交互", list: ["modify", "normal"], - modify: { +Volcanos("onsyntax", {help: "语法高亮", list: ["normal", "insert"], + go: { + line: function(can, line) { + var keyword = { + "package": "keyword", + "import": "keyword", + "func": "keyword", + } + can.core.List(can.core.Split(line), function(item) { var p = keyword[item]; + if (typeof item == "object") { + item.type == "str" && (line = line.replace(item.text, ''+item.text+'')) + } else { + p && (line = line.replace(item, ''+item+'')) + } + }) + return line + }, + }, +}) +Volcanos("onkeymap", {help: "键盘交互", list: ["normal", "insert"], + normal: { + ":w": function(event, can) { + can.onaction.remote(event, can, null, "保存") + }, + h: function(event, can) { + can.editor.setSelectionRange(can.editor.selectionStart-1, can.editor.selectionStart-1) + }, + l: function(event, can) { + can.editor.setSelectionRange(can.editor.selectionStart+1, can.editor.selectionStart+1) + }, + j: function(event, can) { + can.onaction.selectLine(can, can.current.nextSibling) + }, + k: function(event, can) { + can.onaction.selectLine(can, can.current.previousSibling) + }, + + r: function(event, can) { + can.run(event) + }, + i: function(event, can) { + can.onaction.mode(event, can, null, "insert") + }, + O: function(event, can) { + can.onaction.mode(event, can, null, "insert") + can.onaction.insertLine(can, can.current, "", true).click() + }, + o: function(event, can) { + can.onaction.mode(event, can, null, "insert") + can.onaction.insertLine(can, can.current).click() + }, + yy: function(event, can) { + can.last = can.current.innerText + }, + dd: function(event, can) { + can.last = can.current.innerText + var next = can.current.nextSibling || can.current.previousSibling + can.onaction.deleteLine(can, can.current) + next.click() + }, + p: function(event, can) { + can.onaction.insertLine(can, can.current, can.last).click() + }, + P: function(event, can) { + can.onaction.insertLine(can, can.current, can.last, true).click() + }, + }, + insert: { ArrowDown: function(event, can) { can.onaction.selectLine(can, can.current.nextSibling) }, ArrowUp: function(event, can) { can.onaction.selectLine(can, can.current.previousSibling) }, + Escape: function(event, can) { + can.onaction.modifyLine(can, can.current, can.editor.value) + can.onaction.mode(event, can, null, "normal") + }, Enter: function(event, can) { can.onaction.modifyLine(can, can.current, can.editor.value) - can.onaction.insertLine(can, can.current, event.shiftKey).click() + can.onaction.insertLine(can, can.current, "", event.shiftKey).click() event.stopPropagation() event.preventDefault() }, Backspace: function(event, can) { can.editor.selectionStart == 0 && can.onaction.mergeLine(can, can.current.previousSibling).click() }, + jk: function(event, can) { + can.page.DelText(can.editor, can.editor.selectionStart-1, 1) + + can.onaction.modifyLine(can, can.current, can.editor.value) + can.onaction.mode(event, can, null, "normal") + event.stopPropagation() + event.preventDefault() + }, }, }) -Volcanos("onaction", {help: "控件交互", list: ["保存", "提交"], +Volcanos("onaction", {help: "控件交互", list: ["保存", "提交", ["mode", "normal", "insert"]], modifyLine: function(can, target, value) { + value = can.onsyntax.go.line(can, value) target.innerHTML = value }, deleteLine: function(can, target) { can.page.Remove(can, target) + + var ls = can.page.Select(can, can.ui.lineno, "div.item") + can.page.Remove(can, ls[ls.length-1]) + // can.max-- }, - selectLine: function(can, target) { + selectLine: function(can, target) { if (!target) { return } can.page.Select(can, can.ui.content, "pre.item", function(item, index) { if (item != target && index != target) { return } - can.Status("当前行", index+1) && can.page.Select(can, can.ui.lineno, "div.item", function(item, i) { + target = item, can.Status("当前行", can.onexport.position(can, index)), can.page.Select(can, can.ui.lineno, "div.item", function(item, i) { can.page.ClassList.del(can, item, "select") index == i && can.page.ClassList.add(can, item, "select") }) @@ -56,21 +169,22 @@ Volcanos("onaction", {help: "控件交互", list: ["保存", "提交"], }}), can.editor.focus(); }, appendLine: function(can, value) { var index = can.max++; - can.page.Append(can, can.ui.lineno, [{view: ["item", "div", can.Status("总行数", index+1)], onclick: function(event) { + can.page.Append(can, can.ui.lineno, [{view: ["item", "div", index+1], onclick: function(event) { can.onaction.selectLine(can, index) }}]) + value = can.onsyntax.go.line(can, value) return can.page.Append(can, can.ui.content, [{view: ["item", "pre", value||""], onclick: function(event) { can.onaction.selectLine(can, event.target) }}]).last }, - insertLine: function(can, target, before) { - var line = can.onaction.appendLine(can) + insertLine: function(can, target, value, before) { + var line = can.onaction.appendLine(can, value) can.ui.content.insertBefore(line, before && target || target.nextSibling) return line }, - mergeLine: function(can, target) { - can.ondetail.modifyLine(can, target, target.innerHTML + target.nextSibling.innerHTML); - can.ondetail.deleteLine(can, target.nextSibling); + mergeLine: function(can, target) { if (!target) {return} + can.onaction.modifyLine(can, target, target.innerHTML + target.nextSibling.innerHTML); + can.onaction.deleteLine(can, target.nextSibling); return target }, @@ -79,6 +193,12 @@ Volcanos("onaction", {help: "控件交互", list: ["保存", "提交"], can.run(event, ["action", key, can.Option("path")], function(res) { }, true) }, + + mode: function(event, can, msg, value) { + can.Action("mode", can.mode = value) + can.Status("输入法", can.mode) + return value + }, "保存": function(event, can, msg) { can.onaction.remote(event, can, msg, "保存") }, @@ -94,19 +214,22 @@ Volcanos("ondetail", {help: "菜单交互", list: ["删除行", "合并行", " can.onaction.mergeLine(can, can.current) }, "插入行": function(event, can, msg) { - can.onaction.insertLine(can, can.current, true) + can.onaction.insertLine(can, can.current, "", true) }, "添加行": function(event, can, msg) { - can.onaction.insertLine(can, can.current, false) + can.onaction.insertLine(can, can.current) }, "追加行": function(event, can, msg) { can.onaction.appendLine(can) }, }) -Volcanos("onexport", {help: "导出数据", list: ["当前行", "总行数"], +Volcanos("onexport", {help: "导出数据", list: ["输入法", "输入值", "文件名", "解析器", "当前行"], content: function(can) { return can.page.Select(can, can._output, "div.content>pre.item", function(item) { return can.current == item? can.editor.value: item.innerText }).join("\n") }, + position: function(can, index) { + return parseInt((index+1)*100/can.max)+"%"+" = "+(index+1)+"/"+can.max + }, })