From 166f4b389c6dd2a159ab1e5079c19c7d296b0ef3 Mon Sep 17 00:00:00 2001 From: harveyshao Date: Thu, 22 Dec 2022 12:04:26 +0800 Subject: [PATCH] opt vimer --- lib/base.js | 2 +- lib/misc.js | 1 - plugin/local/code/inner.css | 2 +- plugin/local/code/inner.js | 29 ++- plugin/local/code/vimer.js | 440 +++++++++++++++--------------------- proto.js | 3 +- 6 files changed, 209 insertions(+), 268 deletions(-) diff --git a/lib/base.js b/lib/base.js index b1de284f..a5d50e0e 100644 --- a/lib/base.js +++ b/lib/base.js @@ -127,7 +127,7 @@ Volcanos("base", { } return str }, beginWith: function(str) { for (var i = 1; i < arguments.length; i++) { if (typeof str == lang.STRING && str.trim().indexOf(arguments[i]) == 0) { return true } } }, - endWith: function(str, end) { return typeof str == lang.STRING && str.lastIndexOf(end) + end.length == str.length }, + endWith: function(str) { for (var i = 1; i < arguments.length; i++) { if (typeof str == lang.STRING && str.lastIndexOf(arguments[i]) + arguments[i].length == str.length) { return true } } }, trimPrefix: function(str, pre) { if (typeof str != lang.STRING) { return str } var callee = arguments.callee if (arguments.length > 2) { for (var i = 1; i < arguments.length; i++) { str = callee(str, arguments[i]) } return str } if (str.indexOf(pre) == -1) { return str } return str.slice(pre.length) diff --git a/lib/misc.js b/lib/misc.js index df6d7ee3..cb9b587f 100644 --- a/lib/misc.js +++ b/lib/misc.js @@ -223,7 +223,6 @@ Volcanos("misc", {Message: function(event, can) { var msg = {} for (var i in arguments) { arguments[i] != undefined && args.push(arguments[i]) } args.push(ice.NL, this._stacks().slice(1, 4).join(ice.NL)) console.debug.apply(console, args), this._signal(arguments[0], args) - debugger }, Trace: function() { var filter = "", output = false var args = [this._time(), this.fileLine(2, 3).link, log.TRACE] diff --git a/plugin/local/code/inner.css b/plugin/local/code/inner.css index ab3e19c8..fa261350 100644 --- a/plugin/local/code/inner.css +++ b/plugin/local/code/inner.css @@ -21,7 +21,7 @@ fieldset.inner>div.output div.content td.text span.string { color:magenta; } fieldset.inner>div.output div.content td.text span.object { color:cyan; } fieldset.inner>div.output div.find.float { position:absolute; } fieldset.inner.cmd>div.output>div.layout.flow>div.tabs { background-color:#70809096; height:28px; overflow:auto; display:block; } -fieldset.inner.cmd>div.output>div.layout.flow>div.tabs div { background-color:teal; font-family:monospace; padding:5px 10px; float:left; } +fieldset.inner.cmd>div.output>div.layout.flow>div.tabs div { background-color:teal; font-family:monospace; padding:5px 15px; float:left; } fieldset.inner.cmd>div.output>div.layout.flow>div.tabs div:hover { background-color:#1d3349; } fieldset.inner.cmd>div.output>div.layout.flow>div.tabs div.select { background-color:#1d3349; } fieldset.inner.cmd>div.output>div.layout.flow>div.tabs div.avatar { padding:0; height:28px; float:right; } diff --git a/plugin/local/code/inner.js b/plugin/local/code/inner.js index e4c16900..e712a82c 100644 --- a/plugin/local/code/inner.js +++ b/plugin/local/code/inner.js @@ -6,7 +6,7 @@ Volcanos(chat.ONIMPORT, {_init: function(can, msg, cb, target) { can.onmotion.cl var files = can.core.Split(can.Option(nfs.FILE), ice.FS); can.Option(nfs.FILE, files[0]) var paths = can.core.Split(can.Option(nfs.PATH), ice.FS); can.Option(nfs.PATH, paths[0]) can.core.List(paths.concat(can.core.Split(msg.Option(nfs.REPOS))), function(p) { if (p && paths.indexOf(p) == -1 && p[0] != ice.PS) { paths.push(p) } }) - can.db = {paths: paths, tabview: {}, history: [], profile_size: {}, display_size: {}, extentions: {}}, can.onengine.plugin(can, can.onplugin) + can.db = {paths: paths, tabview: {}, history: [], profile_size: {}, display_size: {}, toolkit: {}, extentions: {}}, can.onengine.plugin(can, can.onplugin) can.ui = can.onappend.layout(can, can._output, "", [html.PROJECT, [html.TABS, nfs.PATH, [html.CONTENT, html.PROFILE], html.DISPLAY]]) can.ui._content = can.ui.content, can.ui._profile = can.ui.profile, can.ui._display = can.ui.display switch (can.Mode()) { @@ -26,8 +26,8 @@ Volcanos(chat.ONIMPORT, {_init: function(can, msg, cb, target) { can.onmotion.cl can.onimport.tabview(can, can.Option(nfs.PATH), can.Option(nfs.FILE), can.Option(nfs.LINE), function() { if (can.isCmdMode() && hash) { var args = can.core.Split(decodeURIComponent(hash).slice(1), ice.DF) can.onmotion.delayLong(can, function() { can.onimport.tabview(can, args[args.length-3]||can.Option(nfs.PATH), args[args.length-2]||can.Option(nfs.FILE), args[args.length-1]) }) - } can.base.isFunc(cb) && cb(msg) - }) + } + }), can.base.isFunc(cb) && cb(msg) }, _keydown: function(can) { can.onkeymap._build(can), can._root.onengine.listen(can, chat.ONKEYDOWN, function(event) { @@ -65,7 +65,7 @@ Volcanos(chat.ONIMPORT, {_init: function(can, msg, cb, target) { can.onmotion.cl function isDream() { return line == web.DREAM } function show(skip) { if (can.isCmdMode()) { can.onimport._title(can, path+file) } can._msg && can._msg.Option(nfs.LINE, can.Option(nfs.LINE)), can._msg = can.db.tabview[key] - can.Option(can.onimport.history(can, {path: path, file: file, line: line||can.misc.localStorage(can, "web.code.vimer:selectLine:"+path+file)||can._msg.Option(nfs.LINE)||1})) + can.Option(can.onimport.history(can, {path: path, file: file, line: line||can.misc.localStorage(can, "web.code.inner:selectLine:"+path+file)||can._msg.Option(nfs.LINE)||1})) can.onsyntax._init(can, can._msg, function(content) { var msg = can._msg can.onexport.hash(can), can.onmotion.select(can, can.ui.tabs, html.DIV_TABS, msg._tab) if (isCommand()) { @@ -88,7 +88,7 @@ Volcanos(chat.ONIMPORT, {_init: function(can, msg, cb, target) { can.onmotion.cl if (can.onmotion.toggle(can, item, item == msg._profile)) { can.ui.profile = msg._profile } }), can.ui.current && can.onmotion.toggle(can, can.ui.current, !isCommand() && !isDream()) var ls = can.file.split(ice.PS); if (ls.length > 4) { ls = [ls.slice(0, 2).join(ice.PS)+"/.../"+ls.slice(-2).join(ice.PS)] } - can.Status(kit.Dict("文件名", ls.join(ice.PS), "解析器", can.parse)), can.onimport.layout(can) + can.Status(kit.Dict("文件", ls.join(ice.PS), "类型", can.parse)), can.onimport.layout(can) if (!skip) { can.onaction.selectLine(can, can.Option(nfs.LINE)), can.onaction.scrollIntoView(can) } can.base.isFunc(cb) && cb(), cb = null }) } @@ -106,7 +106,7 @@ Volcanos(chat.ONIMPORT, {_init: function(can, msg, cb, target) { can.onmotion.cl }, history: function(can, record) { can.base.Eq(record, can.db.history[can.db.history.length-1]) || can.db.history.push(record) - return can.Status("跳转数", can.db.history.length), record + return can.Status("跳转", can.db.history.length), record }, project: function(can, path) { can.onimport.zone(can, can.core.Item(can.onfigure, function(name, cb) { @@ -192,7 +192,7 @@ Volcanos(chat.ONFIGURE, { source: function(can, target, zone, path) { var total = 0 function show(target, path) { can.run(can.request({}, {dir_root: path, dir_deep: true}), [nfs.PWD], function(msg) { can.onimport.tree(can, msg.Table(), nfs.PATH, ice.PS, function(event, item) { can.onimport.tabview(can, path, item.path) }, target) - can.Status("文件数", zone._total(total += msg.Length())) + can.Status("目录", zone._total(total += msg.Length())) }, true) } if (path.length == 1) { return show(target, path[0]) } can.page.Remove(can, target.previousSibling) can.onimport.zone(can, can.core.List(path, function(path) { return {name: path, _init: function(target) { show(target, path) }} }), target) }, @@ -261,6 +261,8 @@ Volcanos(chat.ONSYNTAX, {_init: function(can, msg, cb) { }, }) Volcanos(chat.ONACTION, { + _getLine: function(can, line) { return can.page.Select(can, can.ui.content, "tr>td.line", function(td, index) { if (td.parentNode == line || index+1 == line) { return td.parentNode } })[0] }, + _getLineno: function(can, line) { return can.page.Select(can, can.ui.content, "tr>td.line", function(td, index) { if (td.parentNode == line || index+1 == line) { return index+1 } })[0] }, appendLine: function(can, value) { var ui = can.page.Append(can, can.ui._content, [{type: html.TR, list: [ {view: [[nfs.LINE, "unselectable"], html.TD, ++can.max], onclick: function(event) { @@ -278,7 +280,7 @@ Volcanos(chat.ONACTION, { selectLine: function(can, line) { if (!line) { return can.onexport.line(can, can.page.SelectOne(can, can.ui._content, "tr.select")) } can.page.Select(can, can.ui._content, "tr>td.line", function(td, index) { var tr = td.parentNode, n = parseInt(td.innerText) if (!can.page.ClassList.set(can, tr, html.SELECT, tr == line || n == line)) { return } - line = tr, can.Status("当前行", can.onexport.position(can, can.Option(nfs.LINE, n))) + line = tr, can.Status("行号", can.onexport.position(can, can.Option(nfs.LINE, n))) }); if (!can.base.isObject(line)) { return 0 } can.page.Select(can, line, "td.text", function(item) { can.current = { @@ -289,7 +291,10 @@ Volcanos(chat.ONACTION, { line: line, text: function(text) { return text != undefined && can.onaction.modifyLine(can, line, text), item.innerText }, }, can.onimport.history(can, {path: can.Option(nfs.PATH), file: can.Option(nfs.FILE), line: can.Option(nfs.LINE)}) can.onexport.hash(can), can.onaction.scrollIntoView(can, 3), can.onengine.signal(can, "tabview.line.select") - }); return can.onexport.line(can, line) + }) + can.misc.localStorage(can, "web.code.inner:currentFile", can.Option(nfs.PATH)+ice.DF+can.Option(nfs.FILE)+ice.DF+can.onaction._getLineno(can, can.current.line)) + can.misc.localStorage(can, "web.code.inner:selectLine:"+can.Option(nfs.PATH)+can.Option(nfs.FILE), can.onaction._getLineno(can, can.current.line)) + return can.onexport.line(can, line) }, searchLine: function(event, can, value) { can.runAction(can.request(event, {name: value, text: can.current.text()}, can.Option()), code.NAVIGATE, [], function(msg) { @@ -374,13 +379,13 @@ Volcanos(chat.ONACTION, { find: function() { find(last+1, from.value) }, grep: function() { can.onimport.exts(can, "inner/search.js", function(sub) { meta.close(), sub.runAction(event, nfs.GREP, [from.value]) }) }, replace: function() { var text = can.current.text(), line = can.onaction._getLineno(can, can.current.line) - can.undo.push(function() { can.onaction.selectLine(can, line), can.onaction.modifyLine(can, line, text) }) + can.db.undo.push(function() { can.onaction.selectLine(can, line), can.onaction.modifyLine(can, line, text) }) can.current.text(text.replace(from.value, to.value)), can.current.text().indexOf(from.value) == -1 && meta.find() }, close: function() { can.page.Remove(can, ui._target) }, }); var from, to }, }) -Volcanos(chat.ONEXPORT, {list: ["文件数", "解析器", "文件名", "当前行", "跳转数"], +Volcanos(chat.ONEXPORT, {list: ["目录", "类型", "文件", "行号", "跳转"], hash: function(can) { if (!can.isCmdMode()) { return } var list = []; if (can.Option(nfs.PATH) != can.misc.Search(can, nfs.PATH)) { list.push(can.Option(nfs.PATH)) } if (list.length > 0 || can.Option(nfs.FILE) != can.misc.Search(can, nfs.FILE)) { list.push(can.Option(nfs.FILE)) } @@ -409,4 +414,4 @@ Volcanos(chat.ONKEYMAP, { h: shy("打开左边标签", function(can) { var prev = can._tab.previousSibling; prev && prev.click() }), x: shy("关闭标签", function(can) { can._tab._close() }), }}, _engine: {}, -}) \ No newline at end of file +}) diff --git a/plugin/local/code/vimer.js b/plugin/local/code/vimer.js index 392a1652..df86376c 100644 --- a/plugin/local/code/vimer.js +++ b/plugin/local/code/vimer.js @@ -1,19 +1,22 @@ Volcanos(chat.ONIMPORT, {_init: function(can, msg, cb, target) { can.require(["inner.js"], function(can) { can.onimport._last_init(can, msg, function() { - can.db.undo = [], can.db.redo = [], can.page.ClassList.add(can, can._fields, code.VIMER) - can.onimport._input(can), can.onkeymap._build(can), can.onkeymap._plugin({}, can) + can.db.undo = [], can.db.redo = [], can.onappend.style(can, code.VIMER) + can.onimport._input(can), can.onkeymap._build(can), can.onkeymap._plugin(can) can.onengine.listen(can, "tabview.line.select", function(msg) { can.onaction._selectLine(can) }) can.onengine.plugin(can, can.onplugin), can.base.isFunc(cb) && cb(msg) }, target) }) }, _input: function(can) { var ui = can.page.Append(can, can.ui.content.parentNode, [ - {view: ["current", html.INPUT], spellcheck: false, onkeydown: function(event) { - if (event.metaKey) { return can.mode == "insert" && can.onmotion.delay(can, function() { can.current.text(can.ui.current.value) }) } + {view: [code.CURRENT, html.INPUT], spellcheck: false, onkeydown: function(event) { + if (event.metaKey) { return can.mode == mdb.INSERT && can.onmotion.delay(can, function() { can.current.text(can.ui.current.value) }) } if (event.ctrlKey && can.onaction._complete(event, can)) { return } - can._keylist = can.onkeymap._parse(event, can, can.mode+(event.ctrlKey? "_ctrl": ""), can._keylist, can.ui.current) - if (can.mode == "insert") { can.onmotion.delay(can, function() { can.current.text(can.ui.current.value) }) } - if (can.mode == "normal") { can.onkeymap.prevent(event), can.Status("按键", can._keylist.join("")) } - }, onkeyup: function(event) { can.onaction._complete(event, can) }, onclick: function(event) { can.onkeymap._insert(event, can) }}, code.COMPLETE, + can.db._keylist = can.onkeymap._parse(event, can, can.mode+(event.ctrlKey? "_ctrl": ""), can.db._keylist, can.ui.current) + if (can.mode == mdb.INSERT) { can.db._keylist = [], can.onmotion.delay(can, function() { can.current.text(can.ui.current.value) }) } + if (can.mode == mdb.NORMAL) { can.onkeymap.prevent(event), can.Status("按键", can.db._keylist.join("")) } + }, onkeyup: function(event) { can.onaction._complete(event, can) }, onfocus: function() { + var target = can.ui.complete; can.current.line.appendChild(target), can.onmotion.toggle(can, target, true) + can.page.style(can, target, html.LEFT, can.ui.current.offsetLeft-1, html.MARGIN_TOP, can.ui.current.offsetHeight-1) + }, onblur: function(event) { can.onmotion.hidden(can, can.ui.complete) }, onclick: function(event) { can.onkeymap._insert(event, can) }}, code.COMPLETE, ]); can.ui.current = ui.current, can.ui.complete = ui.complete }, }, [""]) Volcanos(chat.ONFIGURE, { @@ -50,7 +53,7 @@ Volcanos(chat.ONFIGURE, { trash: function(event) { can.runAction(event, nfs.TRASH, [can.base.Path(path, item.path)], function() { item._remove() }) }, }), item._init = function(target) { item._remove = function() { can.page.Remove(can, target.parentNode), delete(node[item.path]) } } }) return can.onimport.tree(can, list, nfs.PATH, ice.PS, function(event, item) { can.onimport.tabview(can, path, item.path) }, target, node) - } node = add(msg.Table(), node), can.Status("文件数", zone._total(total += msg.Length())) + } node = add(msg.Table(), node), can.Status("目录", zone._total(total += msg.Length())) }, true) } if (path.length == 1) { return show(target, path[0]) } can.onimport.zone(can, can.core.List(path, function(path) { return {name: path, _init: function(target, zone) { can.onmotion.hidden(can, zone._action), can.onmotion.hidden(can, zone._target) @@ -85,22 +88,11 @@ Volcanos(chat.ONFIGURE, { }, }) Volcanos(chat.ONACTION, { - _daemon: function(event, can, arg) { - switch (arg[0]) { - case web.DREAM: - can.runAction({}, arg[0], arg.slice(1), function(msg) { - can.onimport.tabview(can, can.Option(nfs.PATH), can.core.Keys(can.misc.Search(can, ice.POD), msg.Option(mdb.NAME)), web.DREAM) - }); break - case code.XTERM: - can.runAction({}, arg[0], arg.slice(1), function(msg) { - can.onimport.tabview(can, ctx.COMMAND, code.XTERM, msg.Result()) - }); break - default: - can.runAction({}, arg[0], arg.slice(1), function(msg) { - can.onimport.tabview(can, msg.Option(nfs.PATH)||can.Option(nfs.PATH), msg.Option(nfs.FILE)), can.ui.source.refresh() - }) - } - }, + _daemon: function(event, can, arg) { switch (arg[0]) { + case web.DREAM: can.runAction({}, arg[0], arg.slice(1), function(msg) { can.onimport.tabview(can, can.Option(nfs.PATH), can.core.Keys(can.misc.Search(can, ice.POD), msg.Option(mdb.NAME)), web.DREAM) }); break + case code.XTERM: can.runAction({}, arg[0], arg.slice(1), function(msg) { can.onimport.tabview(can, ctx.COMMAND, code.XTERM, msg.Result()) }); break + default: can.runAction({}, arg[0], arg.slice(1), function(msg) { can.onimport.tabview(can, msg.Option(nfs.PATH)||can.Option(nfs.PATH), msg.Option(nfs.FILE)), can.ui.source.refresh() }) + } }, _run: function(event, can, button, args, cb) { can.runAction(event, button, args, cb||function(msg) { can.onimport.tabview(can, msg.Option(nfs.PATH)||can.Option(nfs.PATH), msg.Option(nfs.FILE)), can.ui.source.refresh(), can.user.toastSuccess(can, button) }) }, @@ -134,124 +126,72 @@ Volcanos(chat.ONACTION, { }, favor: function(event, can) { can.onimport.tabview(can, can.Option(nfs.PATH), "web.code.favor", ctx.INDEX) }, git: function(event, can) { can.onimport.tabview(can, can.Option(nfs.PATH), "web.code.git.status", ctx.INDEX) }, - "收藏": function(event, can) { can.onaction._open(can, location.protocol+"//"+location.host+"/chat/cmd/web.chat.favor") }, + status: function(event, can) { can.onimport.tabview(can, can.Option(nfs.PATH), "web.code.git.status", ctx.INDEX) }, + plan: function(event, can) { can.onimport.tabview(can, can.Option(nfs.PATH), "web.team.plan", ctx.INDEX) }, + vim: function(event, can) { can.onaction._run(can.request(event, can.Option()), can, code.XTERM, [mdb.TYPE, "vim +"+can.Option(nfs.LINE)+" "+can.Option(nfs.PATH)+can.Option(nfs.FILE)], function(msg) { + can.onimport.tabview(can, can.Option(nfs.PATH), msg.Result(), code.XTERM), can.ui.xterm.refresh(), can.user.toastSuccess(can) + }) }, + xterm: function(event, can, button) { can.onaction._runs(can.request(event, can.Option()), can, button, function(msg) { + can.onimport.tabview(can, can.Option(nfs.PATH), msg.Result(), code.XTERM), can.ui.xterm.refresh(), can.user.toastSuccess(can) + }) }, "首页": function(event, can) { can.onaction._open(can, location.protocol+"//"+location.host) }, "官网": function(event, can) { can.onaction._open(can, "https://shylinux.com/") }, "文档": function(event, can) { can.onaction._open(can, "https://developer.mozilla.org/") }, "百度": function(event, can) { can.onaction._open(can, "https://baidu.com") }, - - xterm: function(event, can, button) { - can.onaction._runs(can.request(event, can.Option()), can, button, function(msg) { - can.onimport.tabview(can, can.Option(nfs.PATH), msg.Result(), code.XTERM) - can.ui.xterm.refresh(), can.user.toastSuccess(can) - }) - }, - status: function(event, can) { can.onimport.tabview(can, can.Option(nfs.PATH), "web.code.git.status", ctx.INDEX) }, - plan: function(event, can) { can.onimport.tabview(can, can.Option(nfs.PATH), "web.team.plan", ctx.INDEX) }, - vim: function(event, can) { - can.onaction._run(can.request(event, can.Option()), can, code.XTERM, [mdb.TYPE, "vim +"+can.Option(nfs.LINE)+" "+can.Option(nfs.PATH)+can.Option(nfs.FILE)], function(msg) { - can.onimport.tabview(can, can.Option(nfs.PATH), msg.Result(), code.XTERM), can.ui.xterm.refresh(), can.user.toastSuccess(can) - }) - }, - "命令": function(event, can) { - can.user.input(event, can, [ctx.INDEX], function(list) { - can.onimport.tabview(can, can.Option(nfs.PATH), list[0], ctx.INDEX) - }) - }, - "插件": function(event, can) { - can.user.input(event, can, [ctx.INDEX], function(list) { - var sub = can.toolkit[list[0]]; if (sub) { sub.select(); return } - can.onimport.toolkit(can, {index: list[0]}, function(sub) { can.toolkit[list[0]] = sub.select() }) - }) - }, - "扩展": function(event, can) { can.request(event, {action: "extension"}) - can.user.input(event, can, ["url"], function(list) { - var sub = can.extentions[list[0]]; if (sub) { sub.select(); return } - can.onimport.exts(can, list[0]) - }) - }, + "命令": function(event, can) { can.user.input(event, can, [ctx.INDEX], function(list) { can.onimport.tabview(can, can.Option(nfs.PATH), list[0], ctx.INDEX) }) }, + "插件": function(event, can) { can.user.input(event, can, [ctx.INDEX], function(list) { var sub = can.toolkit[list[0]]; if (sub) { sub.select(); return } + can.onimport.toolkit(can, {index: list[0]}, function(sub) { can.toolkit[list[0]] = sub.select() }) + }) }, + "扩展": function(event, can) { can.user.input(can.request(event, {action: "extension"}), can, ["url"], function(list) { + var sub = can.extentions[list[0]]; sub? sub.select(): can.onimport.exts(can, list[0]) + }) }, "录屏": function(event, can) { window.openapp("QuickTime Player") }, "日志": function(event, can) { window.opencmd("cd ~/contexts; tail -f var/log/bench.log") }, "编辑器": function(event, can) { window.opencmd("cd ~/contexts; vim +"+can.Option(nfs.LINE)+" "+can.Option(nfs.PATH)+can.Option(nfs.FILE)) }, "浏览器": function(event, can) { window.openurl(location.href) }, _open: function(can, url) { can.user.isWebview? window.openurl(url): window.open(url) }, - - _complete: function(event, can, target) { target = target||can.ui.complete - if (event == undefined) { return } - var pre = can.ui.current.value.slice(0, can.ui.current.selectionStart) - var end = can.ui.current.value.slice(can.ui.current.selectionStart) - const PRE = "pre" - - var type = can.core.Split(pre).pop()||"" - var name = can.core.Split(type, "", ice.PT).pop()||"" - type = can.base.trimSuffix(type, name) - type = can.base.trimSuffix(type, ice.PT) - - function update() { target._pre = pre, target._index = -1 + _complete: function(event, can, target) { if (event == undefined) { return } target = target||can.ui.complete + var pre = can.ui.current.value.slice(0, can.ui.current.selectionStart), key = can.core.Split(pre, "", ice.PT).pop()||"", end = can.ui.current.value.slice(can.ui.current.selectionStart) + function update() { target._pre = pre, target._end = end, target._index = -1 can.current.line.appendChild(target), can.page.style(can, target, html.LEFT, can.ui.current.offsetLeft-1, html.MARGIN_TOP, can.ui.current.offsetHeight-1) - can.runAction(can.request(event, {text: pre}, can.Option()), code.COMPLETE, [], function(msg) { - can.page.Appends(can, target, [{view: [PRE, html.DIV, pre]}]) + can.runAction(can.request(event, {text: pre}, can.Option()), code.COMPLETE, [], function(msg) { can.page.Appends(can, target, [{view: ["pre", html.DIV, pre]}]) can.onappend.table(can, msg, function(value, key, index) { return {text: [value, html.TD], onclick: function(event) { - var left = can.ui.current.value.slice(0, can.ui.current.selectionStart)+value - can.current.text(can.ui.current.value = left+can.ui.current.value.slice(can.ui.current.selectionEnd)) - can.ui.current.focus(), can.ui.content.scrollLeft -= 10000, can.ui.current.setSelectionRange(left.length, left.length) - }} }, target) - can.page.style(can, target, html.MAX_HEIGHT, can.ui._content.offsetHeight-(can.current.line.offsetTop-can.ui.content.scrollTop)-can.current.line.offsetHeight) + can.current.text(can.ui.current.value = target._pre+value+target._end), can.onaction.scrollHold(can, target._pre.length+value.length) + }} }, target), can.page.style(can, target, html.MAX_HEIGHT, can.ui._content.offsetHeight-(can.current.line.offsetTop-can.ui.content.scrollTop)-can.current.line.offsetHeight) }) } - function filter() { - return can.page.Select(can, target, [html.TBODY, html.TR], function(tr) { - if (!can.page.ClassList.set(can, tr, html.HIDE, can.page.Select(can, tr, html.TD, function(td) { - if (td.innerText.toLowerCase().indexOf(can.base.trimSuffix((name == ice.PT? type: name).toLowerCase(), "(")) == 0) { return td } - }).length == 0)) { return tr } - }).length > (name == ice.PT? 1: 0) - } - function select(index, total) { index = (index+(total+1))%(total+1) - if (index == total) { can.current.text(can.ui.current.value = target._pre) } + function filter() { can.page.Select(can, target, [html.TBODY, html.TR], function(tr) { + can.page.ClassList.set(can, tr, html.HIDE, can.page.Select(can, tr, html.TD, function(td) { if (td.innerText.toLowerCase().indexOf(key.toLowerCase()) == 0) { return td } }).length == 0) + }) } + function select(index, total) { index = (index+(total+1))%(total+1); if (index == total) { can.current.text(can.ui.current.value = target._pre+target._end) } can.page.Select(can, target, [html.TBODY, "tr:not(.hide)"], function(tr, i) { if (can.page.ClassList.set(can, tr, html.SELECT, i == index)) { - can.current.text(can.ui.current.value = target._pre+can.page.Select(can, tr, html.TD)[0].innerText) + can.current.text(can.ui.current.value = target._pre+can.page.Select(can, tr, html.TD)[0].innerText+target._end) } }); return index } - - if (event.ctrlKey) { if (event.type == "keyup") { - var total = can.page.Select(can, target, [html.TBODY, "tr:not(.hide)"]).length - switch (event.key) { - case "n": target._index = select(target._index+1, total); break - case "p": target._index = select(target._index-1, total); break - default: return false - } - return can.onkeymap.prevent(event) - } return } - - switch (pre.slice(-1)) { - case "\t": - case " ": - case ".": - case "(": - case "{": - update() - break - case "": + if (event.ctrlKey) { if (event.type == "keyup") { var total = can.page.Select(can, target, [html.TBODY, "tr:not(.hide)"]).length; switch (event.key) { + case "n": target._index = select(target._index+1, total); break + case "p": target._index = select(target._index-1, total); break default: - filter() + return can.onkeymap.selectCtrlN(event, can, target, [html.TBODY, "tr:not(.hide)"], function(tr) { + can.current.text(can.ui.current.value = target._pre+can.page.Select(can, tr, html.TD)[0].innerText+target._end) + }) + } return can.onkeymap.prevent(event) } return } + switch (pre.slice(-1)) { + case ice.TB: + case ice.SP: + case ice.PT: + case "(": + case "{": update(); break + case "": + default: filter() } }, _selectLine: function(can) { if (!can.current) { return } can.page.Select(can, can.current.line, "td.text", function(td) { var target = can.ui.current; target.value = td.innerText can.current.line.appendChild(target), can.page.style(can, target, html.LEFT, td.offsetLeft-1, html.WIDTH, can.base.Min(td.offsetWidth, can.ui._content.offsetWidth)) - var scroll = can.ui.content.scrollLeft - if (event && event.type == "click") { - can.onkeymap._insert(event, can, 0, (event.offsetX)/12-1) - } else { - target.focus(), can.onkeymap.cursorMove(can.ui.current, 0, 0) - } can.ui.content.scrollLeft = scroll + if (event && event.type == "click") { can.onkeymap._insert(event, can, 0, (event.offsetX)/12-1) } else { can.onaction.scrollHold(can, 0) } }) - can.misc.localStorage(can, "web.code.inner:currentFile", can.Option(nfs.PATH)+ice.DF+can.Option(nfs.FILE)+ice.DF+can.onaction._getLineno(can, can.current.line)) - can.misc.localStorage(can, "web.code.vimer:selectLine:"+can.Option(nfs.PATH)+can.Option(nfs.FILE), can.onaction._getLineno(can, can.current.line)) }, - - _getLine: function(can, line) { return can.page.SelectOne(can, can.ui.content, "tr>td.line", function(td, index) { if (td.parentNode == line || index+1 == line) { return td.parentNode } }) }, - _getLineno: function(can, line) { return can.page.SelectOne(can, can.ui.content, "tr>td.line", function(td, index) { if (td.parentNode == line || index+1 == line) { return index+1 } }) }, rerankLine: function(can, value) { can.max = can.page.Select(can, can.ui.content, "tr>td.line", function(td, index) { return td.innerText = index+1 }).length }, insertLine: function(can, value, before) { var line = can.onaction.appendLine(can, value) before && can.ui.content.insertBefore(line, can.onaction._getLine(can, before)) @@ -264,157 +204,157 @@ Volcanos(chat.ONACTION, { modifyLine: function(can, line, value) { can.page.Select(can, can.onaction._getLine(can, line), "td.text", function(td) { td.innerHTML = can.onsyntax._parse(can, value) }) }, cursorUp: function(can, target) { var p = can.onkeymap.cursorMove(target); can.onaction.selectLine(can, can.current.prev()), can.onkeymap.cursorMove(target, 0, p) }, cursorDown: function(can, target) { var p = can.onkeymap.cursorMove(target); can.onaction.selectLine(can, can.current.next()), can.onkeymap.cursorMove(target, 0, p) }, + scrollHold: function(can, count, begin) { var scroll = can.ui.content.scrollLeft; can.ui.current.focus(), count != undefined && can.onkeymap.cursorMove(can.ui.current, count, begin == undefined? count: begin), can.ui.content.scrollLeft = scroll }, }) -Volcanos(chat.ONEXPORT, {list: ["文件数", "模式", "按键", "解析器", "文件名", "当前行", "跳转数"]}) +Volcanos(chat.ONEXPORT, {list: ["目录", "模式", "按键", "类型", "文件", "行号", "跳转"]}) Volcanos(chat.ONKEYMAP, { - _model: function(can, value) { can.Status("模式", can.mode = value) - can.page.styleClass(can, can.ui.current, ["current", can.mode]), value - can.page.styleClass(can, can.ui.complete, [code.COMPLETE, can.mode]), value - }, - _plugin: function(event, can) { can.onkeymap._model(can, "plugin"), can.ui.current.blur() }, - _normal: function(event, can) { can.onkeymap._model(can, "normal"), can.ui.current.focus() }, - _insert: function(event, can, count, begin) { can.onkeymap._model(can, "insert"), can.onkeymap.prevent(event) - var scroll = can.ui.content.scrollLeft; can.ui.current.focus(), can.ui.content.scrollLeft = scroll - can.onkeymap.cursorMove(can.ui.current, count, begin) - }, - + _model: function(can, value) { can.Status("模式", can.mode = value), can.page.styleClass(can, can.ui.current, [code.CURRENT, can.mode]), can.page.styleClass(can, can.ui.complete, [code.COMPLETE, can.mode]) }, + _plugin: function(can) { can.onkeymap._model(can, mdb.PLUGIN), can.ui.current.blur() }, + _normal: function(can) { can.onkeymap._model(can, mdb.NORMAL), can.ui.current.focus() }, + _insert: function(event, can, count, begin) { can.onkeymap._model(can, mdb.INSERT), can.onaction.scrollHold(can, count, begin), can.onkeymap.prevent(event) }, _mode: { plugin: { Escape: shy("切换模式", function(event, can) { can.onaction.clear(event, can) }), - r: shy("执行命令", function(event, can) { can.onaction.exec(event, can) }), - v: shy("渲染界面", function(event, can) { can.onaction.show(event, can) }), - f: shy("打开文件", function(event, can) { can.onaction.open(event, can) }), - l: shy("打开右边标签", function(can) { var next = can._tab.nextSibling; next && next.click() }), - h: shy("打开左边标签", function(can) { var prev = can._tab.previousSibling; prev && prev.click() }), - x: shy("关闭标签", function(can) { can._tab._close() }), + r: shy("执行命令", function(event, can) { can.onaction.exec(event, can) }), + v: shy("渲染界面", function(event, can) { can.onaction.show(event, can) }), + f: shy("打开文件", function(event, can) { can.onaction.open(event, can) }), + l: shy("打开右边标签", function(can) { var next = can._tab.nextSibling; next && next.click() }), + h: shy("打开左边标签", function(can) { var prev = can._tab.previousSibling; prev && prev.click() }), + x: shy("关闭标签", function(can) { can._tab._close() }), - t: shy("添加命令", function(event, can) { can.onaction["命令"](event, can) }), - p: shy("添加插件", function(event, can) { can.onaction["插件"](event, can) }), - e: shy("添加扩展", function(event, can) { can.onaction["扩展"](event, can) }), + t: shy("添加命令", function(event, can) { can.onaction["命令"](event, can) }), + p: shy("添加插件", function(event, can) { can.onaction["插件"](event, can) }), + e: shy("添加扩展", function(event, can) { can.onaction["扩展"](event, can) }), - i: shy("插入模式", function(event, can) { can.onkeymap._insert(event, can) }), - n: shy("命令模式", function(event, can) { can.onkeymap._normal(event, can) }), - ":": shy("底行模式", function(event, can) { can.onimport.toolkit(can, {index: "cli.system"}, function(sub) { can.toolkit["cli.system"] = sub.select() }) }), + i: shy("插入模式", function(event, can) { can.onkeymap._insert(event, can) }), + n: shy("命令模式", function(event, can) { can.onkeymap._normal(can) }), + ":": shy("底行模式", function(event, can) { can.onimport.toolkit(can, {index: "cli.system"}, function(sub) { can.db.toolkit["cli.system"] = sub.select(), can.onmotion.delay(can, function() { sub.Focus() }) }) }), - g: shy("查找替换", function(event, can) { can.onaction.find(event, can) }), - s: shy("保存文件", function(event, can) { can.onaction.save(event, can, nfs.SAVE) }), - c: shy("编译项目", function(event, can) { can.onaction.compile(event, can, code.COMPILE) }), + g: shy("查找替换", function(event, can) { can.onaction.find(event, can) }), + s: shy("保存文件", function(event, can) { can.onaction.save(event, can, nfs.SAVE) }), + c: shy("编译项目", function(event, can) { can.onaction.compile(event, can, code.COMPILE) }), }, normal: { - Escape: shy("切换模式", function(event, can) { can.onkeymap._plugin(event, can) }), - ArrowLeft: shy("光标左移", function(can, target) { can.onkeymap.cursorMove(target, -1) }), - ArrowRight: shy("光标右移", function(can, target) { can.onkeymap.cursorMove(target, 1) }), - ArrowDown: shy("光标下移", function(can, target) { can.onaction.cursorDown(can, target) }), - ArrowUp: shy("光标上移", function(can, target) { can.onaction.cursorUp(can, target) }), + Escape: shy("切换模式", function(event, can) { can.onkeymap._plugin(can) }), + ArrowLeft: shy("光标左移", function(can, target) { can.onkeymap.cursorMove(target, -1) }), + ArrowRight: shy("光标右移", function(can, target) { can.onkeymap.cursorMove(target, 1) }), + ArrowDown: shy("光标下移", function(can, target) { can.onaction.cursorDown(can, target) }), + ArrowUp: shy("光标上移", function(can, target) { can.onaction.cursorUp(can, target) }), - H: shy("跳到行首", function(can, target) { can.onkeymap.cursorMove(target, 0, 0) }), - L: shy("跳到行尾", function(can, target) { can.onkeymap.cursorMove(target, 0, -1) }), - h: shy("光标左移", function(can, target) { can.onkeymap.cursorMove(target, -1) }), - l: shy("光标右移", function(can, target) { can.onkeymap.cursorMove(target, 1) }), - j: shy("光标下移", function(can, target) { can.onaction.cursorDown(can, target) }), - k: shy("光标上移", function(can, target) { can.onaction.cursorUp(can, target) }), + H: shy("跳到行首", function(can, target) { can.onkeymap.cursorMove(target, 0, 0) }), + L: shy("跳到行尾", function(can, target) { can.onkeymap.cursorMove(target, 0, -1) }), + h: shy("光标左移", function(can, target) { can.onkeymap.cursorMove(target, -1) }), + l: shy("光标右移", function(can, target) { can.onkeymap.cursorMove(target, 1) }), + j: shy("光标下移", function(can, target) { can.onaction.cursorDown(can, target) }), + k: shy("光标上移", function(can, target) { can.onaction.cursorUp(can, target) }), - I: shy("插入行首", function(event, can) { can.onkeymap._insert(event, can, 0, 0) }), - A: shy("插入行尾", function(event, can) { can.onkeymap._insert(event, can, 0, -1) }), - i: shy("插入模式", function(event, can) { can.onkeymap._insert(event, can) }), - a: shy("插入模式", function(event, can) { can.onkeymap._insert(event, can, 1) }), - o: shy("插入下一行", function(event, can) { var text = can.current.text() - text = text.substr(0, text.indexOf(text.trimLeft()))+(text.endsWith("{")?"\t":"") - can.onaction.selectLine(can, can.onaction.insertLine(can, text, can.current.next())) - can.onkeymap._insert(event, can, 0, -1) - }), - O: shy("插入上一行", function(event, can) { var text = can.current.text() - text = text.substr(0, text.indexOf(text.trimLeft()))+(text.endsWith("}")?"\t":"") - can.onaction.selectLine(can, can.onaction.insertLine(can, text, can.current.line)) - can.onkeymap._insert(event, can, 0, -1) - }), + I: shy("插入行首", function(event, can) { can.onkeymap._insert(event, can, 0, 0) }), + A: shy("插入行尾", function(event, can) { can.onkeymap._insert(event, can, 0, -1) }), + i: shy("插入模式", function(event, can) { can.onkeymap._insert(event, can) }), + a: shy("插入模式", function(event, can) { can.onkeymap._insert(event, can, 1) }), + o: shy("插入下一行", function(event, can) { var text = can.current.text() + text = text.substr(0, text.indexOf(text.trimLeft()))+(can.base.endWith(text, "{")? ice.TB: "") + can.onaction.selectLine(can, can.onaction.insertLine(can, text, can.current.next())) + can.onkeymap._insert(event, can, 0, -1) + }), + O: shy("插入上一行", function(event, can) { var text = can.current.text() + text = text.substr(0, text.indexOf(text.trimLeft()))+(can.base.beginWith(text, "}")? ice.TB: "") + can.onaction.selectLine(can, can.onaction.insertLine(can, text, can.current.line)) + can.onkeymap._insert(event, can, 0, -1) + }), - yy: shy("复制当前行", function(event, can, target, count) { - var list = [], line = can.current.line; for (var i = 0; i < count; i++) { - list.push(can.onexport.text(can, line)), line = line.nextSibling - } can._last_text = list - return true - }), - dd: shy("剪切当前行", function(event, can, target, count) { - var list = []; for (var i = 0; i < count; i++) { (function() { - var line = can.onaction.selectLine(can), text = can.current.text(); list.push(text) - can.onaction.selectLine(can, can.onaction.deleteLine(can, line)) - can.db.undo.push(function() { can.onaction.insertLine(can, text, line), can.onaction.selectLine(can, line) }) - var callee = arguments.callee; can.db.redo.push(function() { callee(can) }) - })() } can._last_text = list - return true - }), - p: shy("粘贴", function(can) { if (!can._last_text) { return } - for (var i = can._last_text.length-1; i >= 0; i--) { (function() { - var line = can.onaction.insertLine(can, can._last_text[i], can.current.next()) - can.db.undo.push(function() { can.onaction.deleteLine(can, line), can.onaction.selectLine(can, line-1) }) - var call = arguments.callee; can.db.redo.push(function() { call(event, can) }) - })() } - }), - P: shy("粘贴", function(can) { if (!can._last_text) { return } - for (var i = 0; i < can._last_text.length; i++) { (function() { - var line = can.onaction.insertLine(can, can._last_text[i], can.current.line) - can.db.undo.push(function() { can.onaction.deleteLine(can, line), can.onaction.selectLine(can, line+1) }) - var call = arguments.callee; can.db.redo.push(function() { call(event, can) }) - })() } - }), - J: shy("合并两行", function(can) { - var next = can.current.next(); if (!next) { return } - var rest = can.onexport.text(can, next) - var line = can.onaction.selectLine(can), text = can.current.text() - can.ui.current.value = can.current.text(text.trimRight()+ice.SP+rest.trimLeft()), can.onaction.deleteLine(can, next) - can.db.undo.push(function() { can.onaction.modifyLine(can, line, text), can.onaction.insertLine(can, rest, line+1) }) - }), - ".": shy("重复操作", function(can) { var cb = can.db.redo.pop(); cb && cb() }), - u: shy("撤销操作", function(can) { var cb = can.db.undo.pop(); cb && cb() }), + yy: shy("复制当前行", function(event, can, target, count) { + var list = [], line = can.current.line; for (var i = 0; i < count; i++) { + list.push(can.onexport.text(can, line)), line = line.nextSibling + } can.db._last_text = list + return true + }), + dd: shy("剪切当前行", function(event, can, target, count) { + var line = can.onaction.selectLine(can), callee = arguments.callee + can.db.redo.push(function() { callee(event, can, target, count) }) + var list = []; for (var i = 0; i < count; i++) { (function() { + var line = can.onaction.selectLine(can), text = can.current.text(); list.push(text) + can.onaction.selectLine(can, can.onaction.deleteLine(can, line)) + can.db.undo.push(function() { can.onaction.insertLine(can, text, line), can.onaction.selectLine(can, line) }) + })() } can.db._last_text = list + return true + }), + p: shy("粘贴", function(can) { if (!can.db._last_text) { return } + var line = can.onaction.selectLine(can), callee = arguments.callee + can.db.redo.push(function() { callee(event, can, target, count) }) + for (var i = can.db._last_text.length-1; i >= 0; i--) { (function() { + var line = can.onaction.insertLine(can, can.db._last_text[i], can.current.next()) + can.db.undo.push(function() { can.onaction.deleteLine(can, line), can.onaction.selectLine(can, line-1) }) + })() } + }), + P: shy("粘贴", function(can) { if (!can.db._last_text) { return } + var line = can.onaction.selectLine(can), callee = arguments.callee + can.db.redo.push(function() { callee(event, can, target, count) }) + for (var i = 0; i < can.db._last_text.length; i++) { (function() { + var line = can.onaction.insertLine(can, can.db._last_text[i], can.current.line) + can.db.undo.push(function() { can.onaction.deleteLine(can, line), can.onaction.selectLine(can, line+1) }) + })() } + }), + J: shy("合并两行", function(can) { var next = can.current.next(); if (!next) { return } + var line = can.onaction.selectLine(can), text = can.current.text(), rest = can.onexport.text(can, next) + can.ui.current.value = can.current.text(text.trimRight()+(can.base.endWith(text, "(")||can.base.beginWith(rest, ")")? "": ice.SP)+rest.trimLeft()), can.onaction.deleteLine(can, next) + can.db.undo.push(function() { can.onaction.modifyLine(can, line, text), can.onaction.insertLine(can, rest, line+1) }) + }), + ".": shy("重复操作", function(can) { var cb = can.db.redo.pop(); cb && cb() }), + u: shy("撤销操作", function(can) { var cb = can.db.undo.pop(); cb && cb() }), - gg: shy("跳到某行", function(can, count) { return can.onaction.selectLine(can, count), true }), - G: shy("跳到某行", function(can, count) { return can.onaction.selectLine(can, count = count>1? count: can.max), true }), - zt: shy("将当前行拉到屏幕最上", function(can, count) { return can.current.scroll(can.current.scroll()-(count>1? count: 3)), true }), - zz: shy("将当前行拉到屏幕中间", function(can, count) { return can.current.scroll(can.current.scroll()-(count = count>1? count: can.current.window()/2)), true }), - zb: shy("将当前行拉到屏幕最下", function(can, count) { return can.current.scroll(can.current.scroll()-can.current.window()+(count>1? count: 5)), true }), + gg: shy("跳到某行", function(can, count) { return can.onaction.selectLine(can, count), true }), + G: shy("跳到某行", function(can, count) { return can.onaction.selectLine(can, count = count>1? count: can.max), true }), + zt: shy("将当前行拉到屏幕最上", function(can, count) { return can.current.scroll(can.current.scroll()-(count>1? count: 3)), true }), + zz: shy("将当前行拉到屏幕中间", function(can, count) { return can.current.scroll(can.current.scroll()-(count = count>1? count: can.current.window()/2)), true }), + zb: shy("将当前行拉到屏幕最下", function(can, count) { return can.current.scroll(can.current.scroll()-can.current.window()+(count>1? count: 5)), true }), }, normal_ctrl: { f: shy("向下翻页", function(can, count) { var line = can.onaction.selectLine(can)+can.current.window()-3-can.current.scroll() return can.current.scroll(line), can.onaction.selectLine(can, line), true }), - b: shy("向上翻页", function(can, count) { - var line = can.onaction.selectLine(can)-can.current.window()+3 - return can.current.scroll(line), can.onaction.selectLine(can, line), true - }), - e: shy("向下滚屏", function(can) { can.current.scroll(1) }), - y: shy("向上滚屏", function(can) { can.current.scroll(-1) }), + b: shy("向上翻页", function(can, count) { + var line = can.onaction.selectLine(can)-can.current.window()+3 + return can.current.scroll(line), can.onaction.selectLine(can, line), true + }), + e: shy("向下滚屏", function(can) { can.current.scroll(1) }), + y: shy("向上滚屏", function(can) { can.current.scroll(-1) }), }, insert: { - Escape: shy("退出编辑", function(event, can) { event.key == lang.ESCAPE && can.onkeymap._normal(event, can) }), - Tab: shy("缩进", function(event, can) { if (event.key != lang.TAB) { return } - can.onkeymap.insertText(can.ui.current, ice.TB), can.onkeymap.prevent(event) - }), - Backspace: shy("删除", function(event, can, target) { if (event.key != lang.BACKSPACE) { return } - if (target.selectionStart > 0 || !can.current.prev()) { return } can.onkeymap.prevent(event) - var rest = can.current.text(); can.onaction.selectLine(can, can.current.prev()), can.onaction.deleteLine(can, can.current.next()) - var text = can.current.text(); can.ui.current.value = text+rest, can.onkeymap.cursorMove(target, 0, text.length) - }), - Enter: shy("换行", function(can, target) { if (event.key != lang.ENTER) { return } - var rest = can.onkeymap.deleteText(target, target.selectionEnd), text = can.ui.current.value - var left = text.substr(0, text.indexOf(text.trimLeft()))||(text.trimRight() == ""? text: "") - text && can.core.List(["{}", "[]", "()"], function(item) { if (can.base.endWith(text, item[0])) { - if (can.base.beginWith(rest, item[1])) { return true } - (!rest && can.onaction.insertLine(can, left+item[1], can.current.next()), left += ice.TB) - } }).length == 0 && rest && ["}", "]", ")"].indexOf(rest[0]) > -1 && (left = left.slice(0, -1)) || (rest.trim()[0] == "}" && text.trim()[text.length-1] != "{") && (left = left.slice(0, -1)) - if (can.base.endWith(text, "`") && can.base.count(text, "`")%2==1) { !rest && can.onaction.insertLine(can, left+"`", can.current.next()) } - var line = can.onaction.insertLine(can, left+rest.trimLeft(), can.current.next()) - can.current.text(text.trimRight()||text), can.onaction.selectLine(can, line) - can.onkeymap.cursorMove(target, 0, left.length) - }), - ArrowDown: shy("光标下移", function(can, target) { event.key == "ArrowDown" && can.onaction.cursorDown(can, target) }), - ArrowUp: shy("光标上移", function(can, target) { event.key == "ArrowUp" && can.onaction.cursorUp(can, target) }), + Escape: shy("退出编辑", function(event, can) { can.onkeymap._normal(can) }), + Tab: shy("缩进", function(event, can) { can.onkeymap.insertText(can.ui.current, ice.TB), can.onkeymap.prevent(event) }), + Backspace: shy("删除", function(event, can, target) { if (target.selectionStart > 0 || !can.current.prev()) { return } can.onkeymap.prevent(event) + var rest = can.current.text(); can.onaction.selectLine(can, can.current.prev()), can.onaction.deleteLine(can, can.current.next()) + var text = can.current.text(); can.ui.current.value = text+rest, can.onkeymap.cursorMove(target, 0, text.length) + }), + Enter: shy("换行", function(can, target) { + var rest = can.onkeymap.deleteText(target, target.selectionEnd).trimLeft(), text = can.ui.current.value + var left = text.substr(0, text.indexOf(text.trimLeft()))||(text.trimRight() == ""? text: "") + var line = can.onaction.selectLine(can), next = rest; for (var i = line; i < can.max; i++) { + next += can.onexport.text(can, i).trimLeft(); if (next != "") { break } + } + function deep(text) { var deep = 0; for (var i = 0; i < text.length; i++) { + if (text[i] == "\t") { deep += 4 } else if (text[i] == " ") { deep++ } else { break } + } return deep } + text.trim() && can.core.List(["{}", "[]", "()", "``"], function(item) { if (can.base.endWith(text, item[0])) { + if (can.base.beginWith(next, item[1])) { + can.onaction.insertLine(can, left+rest, can.current.next()), rest = "" + } else if (deep(text) >= deep(can.onexport.text(can, line+1))) { + can.onaction.insertLine(can, left+item[1], can.current.next()) + } left += ice.TB + }}) + var line = can.onaction.insertLine(can, left+rest, can.current.next()) + can.current.text(text.trimRight()||text), can.onaction.selectLine(can, line) + can.onkeymap.cursorMove(target, 0, left.length) + }), + ArrowDown: shy("光标下移", function(can, target) { event.key == "ArrowDown" && can.onaction.cursorDown(can, target) }), + ArrowUp: shy("光标上移", function(can, target) { event.key == "ArrowUp" && can.onaction.cursorUp(can, target) }), }, }, _engine: {}, }) Volcanos(chat.ONEXPORT, { - text: function(can, line) { return can.core.Value(can.page.Select(can, line, "td.text")[0], "innerText") }, + text: function(can, line) { return can.core.Value(can.page.Select(can, can.onaction._getLine(can, line), "td.text")[0], "innerText") }, content: function(can) { return can.page.Select(can, can.ui.content, "td.text", function(item) { return item.innerText }).join(ice.NL) }, }) Volcanos(chat.ONPLUGIN, { @@ -422,14 +362,10 @@ Volcanos(chat.ONPLUGIN, { can.core.Item(can.onkeymap._mode, function(mode, value) { (!cmds[0] || cmds[0] == mode) && can.core.Item(value, function(key, func) { if (cmds[0] == mode && cmds[1] == key) { - msg.Push("key", "mode") - msg.Push("value", mode) - msg.Push("key", "key") - msg.Push("value", key) - msg.Push("key", "help") - msg.Push("value", func.help) - msg.Push("key", "func") - msg.Push("value", func.toString()) + msg.Push(mdb.KEY, "mode").Push(mdb.VALUE, mode) + msg.Push(mdb.KEY, "key").Push(mdb.VALUE, key) + msg.Push(mdb.KEY, "help").Push(mdb.VALUE, func.help) + msg.Push(mdb.KEY, "func").Push(mdb.VALUE, func.toString()) } else if (!cmds[0] || !cmds[1]) { msg.Push(kit.Dict("mode", mode, "key", key, "help", func.help||func.toString())) } diff --git a/proto.js b/proto.js index 93d1c19e..afa0d86c 100644 --- a/proto.js +++ b/proto.js @@ -77,6 +77,7 @@ var mdb = { INPUTS: "inputs", PRUNES: "prunes", EXPORT: "export", IMPORT: "import", SEARCH: "search", ENGINE: "engine", RENDER: "render", PLUGIN: "plugin", REVERT: "revert", + NORMAL: "normal", MAIN: "main", PAGE: "page", NEXT: "next", PREV: "prev", LIMIT: "limit", OFFEND: "offend", FOREACH: "*", RANDOMS: "%", @@ -135,7 +136,7 @@ var code = { FAVOR: "favor", XTERM: "xterm", INNER: "inner", VIMER: "vimer", WEBPACK: "webpack", BINPACK: "binpack", AUTOGEN: "autogen", COMPILE: "compile", PUBLISH: "publish", COMMENT: "comment", KEYWORD: "keyword", PACKAGE: "package", DATATYPE: "datatype", FUNCTION: "function", CONSTANT: "constant", STRING: "string", OBJECT: "object", - TEMPLATE: "template", COMPLETE: "complete", NAVIGATE: "navigate", + TEMPLATE: "template", COMPLETE: "complete", NAVIGATE: "navigate", CURRENT: "current", } var wiki = { TITLE: "title", BRIEF: "brief", REFER: "refer", SPARK: "spark",