Compare commits
No commits in common. "2b13f891c9205e3bd0da7c562ee95d1b9b664e7d" and "93b66b6a2693ebbd8eb234a9436b457b0bdaba12" have entirely different histories.
2b13f891c9
...
93b66b6a26
50
xC.c
50
xC.c
@ -2868,7 +2868,6 @@ relay_try_fetch_client (struct app_context *ctx, int listen_fd)
|
|||||||
if (accept_error_is_transient (errno))
|
if (accept_error_is_transient (errno))
|
||||||
print_warning ("%s: %s", "accept", strerror (errno));
|
print_warning ("%s: %s", "accept", strerror (errno));
|
||||||
else
|
else
|
||||||
// TODO: Rather dispose of the listening socket.
|
|
||||||
print_fatal ("%s: %s", "accept", strerror (errno));
|
print_fatal ("%s: %s", "accept", strerror (errno));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -12054,23 +12053,6 @@ handle_command_plugin (struct handler_args *a)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
handle_command_relay (struct handler_args *a)
|
|
||||||
{
|
|
||||||
if (*a->arguments)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int len = 0;
|
|
||||||
LIST_FOR_EACH (struct client, c, a->ctx->clients)
|
|
||||||
len++;
|
|
||||||
|
|
||||||
if (a->ctx->relay_fd == -1)
|
|
||||||
log_global_status (a->ctx, "The relay is not enabled");
|
|
||||||
else
|
|
||||||
log_global_status (a->ctx, "The relay has #d clients", len);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
show_aliases_list (struct app_context *ctx)
|
show_aliases_list (struct app_context *ctx)
|
||||||
{
|
{
|
||||||
@ -12807,9 +12789,6 @@ g_command_handlers[] =
|
|||||||
{ "plugin", "Manage plugins",
|
{ "plugin", "Manage plugins",
|
||||||
"list | load <name> | unload <name>",
|
"list | load <name> | unload <name>",
|
||||||
handle_command_plugin, 0 },
|
handle_command_plugin, 0 },
|
||||||
{ "relay", "Show relay information",
|
|
||||||
NULL,
|
|
||||||
handle_command_relay, 0 },
|
|
||||||
|
|
||||||
{ "alias", "List or set aliases",
|
{ "alias", "List or set aliases",
|
||||||
"[<name> <definition>]",
|
"[<name> <definition>]",
|
||||||
@ -13908,27 +13887,22 @@ build_editor_command (struct app_context *ctx, const char *filename)
|
|||||||
{
|
{
|
||||||
case 'F':
|
case 'F':
|
||||||
str_append (&argument, filename);
|
str_append (&argument, filename);
|
||||||
continue;
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
str_append_printf (&argument, "%zu", line_one_based);
|
str_append_printf (&argument, "%zu", line_one_based);
|
||||||
continue;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
str_append_printf (&argument, "%zu", column + 1);
|
str_append_printf (&argument, "%zu", column + 1);
|
||||||
continue;
|
break;
|
||||||
case 'B':
|
case 'B':
|
||||||
str_append_printf (&argument, "%d", cursor + 1);
|
str_append_printf (&argument, "%d", cursor + 1);
|
||||||
continue;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
case ' ':
|
case ' ':
|
||||||
str_append_c (&argument, *editor);
|
str_append_c (&argument, *editor);
|
||||||
continue;
|
break;
|
||||||
}
|
default:
|
||||||
|
print_warning ("unknown substitution variable");
|
||||||
const char *p = editor;
|
|
||||||
if (soft_assert (utf8_decode (&p, strlen (p)) > 0))
|
|
||||||
{
|
|
||||||
log_global_error (ctx, "Unknown substitution variable: %#&s",
|
|
||||||
xstrndup (editor, p - editor));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (argument.len)
|
if (argument.len)
|
||||||
@ -14781,8 +14755,7 @@ try_reap_child (struct app_context *ctx)
|
|||||||
if (WIFSTOPPED (status))
|
if (WIFSTOPPED (status))
|
||||||
{
|
{
|
||||||
// We could also send SIGCONT but what's the point
|
// We could also send SIGCONT but what's the point
|
||||||
log_global_debug (ctx,
|
print_debug ("a child has been stopped, killing its process group");
|
||||||
"A child has been stopped, killing its process group");
|
|
||||||
kill (-zombie, SIGKILL);
|
kill (-zombie, SIGKILL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -15280,7 +15253,7 @@ client_process_message (struct client *c,
|
|||||||
if (!relay_command_message_deserialize (m, r)
|
if (!relay_command_message_deserialize (m, r)
|
||||||
|| msg_unpacker_get_available (r))
|
|| msg_unpacker_get_available (r))
|
||||||
{
|
{
|
||||||
log_global_error (c->ctx, "Deserialization failed, killing client");
|
print_error ("deserialization failed, killing client");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15299,8 +15272,7 @@ client_process_message (struct client *c,
|
|||||||
if (m->data.hello.version != RELAY_VERSION)
|
if (m->data.hello.version != RELAY_VERSION)
|
||||||
{
|
{
|
||||||
// TODO: This should send back an error message and shut down.
|
// TODO: This should send back an error message and shut down.
|
||||||
log_global_error (c->ctx,
|
print_error ("protocol version mismatch, killing client");
|
||||||
"Protocol version mismatch, killing client");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
c->initialized = true;
|
c->initialized = true;
|
||||||
@ -15328,7 +15300,7 @@ client_process_message (struct client *c,
|
|||||||
client_process_buffer_log (c, m->command_seq, buffer);
|
client_process_buffer_log (c, m->command_seq, buffer);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_global_debug (c->ctx, "Unhandled client command");
|
print_warning ("unhandled client command");
|
||||||
relay_prepare_error (c->ctx, m->command_seq, "Unknown command");
|
relay_prepare_error (c->ctx, m->command_seq, "Unknown command");
|
||||||
relay_send (c);
|
relay_send (c);
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,6 @@ body {
|
|||||||
border-bottom: 1px solid #ccc;
|
border-bottom: 1px solid #ccc;
|
||||||
padding: .05rem .3rem;
|
padding: .05rem .3rem;
|
||||||
}
|
}
|
||||||
.title {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.middle {
|
.middle {
|
||||||
flex: auto;
|
flex: auto;
|
||||||
@ -56,12 +52,6 @@ body {
|
|||||||
grid-template-columns: max-content auto;
|
grid-template-columns: max-content auto;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.log {
|
|
||||||
padding: .1rem .3rem;
|
|
||||||
font-family: monospace;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.date {
|
.date {
|
||||||
padding: .3rem;
|
padding: .3rem;
|
||||||
|
270
xP/public/xP.js
270
xP/public/xP.js
@ -118,11 +118,6 @@ class RelayRpc extends EventTarget {
|
|||||||
this.promised[seq] = {resolve, reject}
|
this.promised[seq] = {resolve, reject}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
base64decode(str) {
|
|
||||||
return decodeURIComponent(atob(str).split('').map(c =>
|
|
||||||
'%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join(''))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Event processing -------------------------------------------------------
|
// ---- Event processing -------------------------------------------------------
|
||||||
@ -131,16 +126,10 @@ let rpc = new RelayRpc(proxy)
|
|||||||
|
|
||||||
let buffers = new Map()
|
let buffers = new Map()
|
||||||
let bufferCurrent = undefined
|
let bufferCurrent = undefined
|
||||||
let bufferLog = undefined
|
|
||||||
let bufferAutoscroll = true
|
|
||||||
|
|
||||||
let connecting = true
|
let connecting = true
|
||||||
rpc.connect().then(result => {
|
rpc.connect().then(result => {
|
||||||
buffers.clear()
|
buffers.clear()
|
||||||
bufferCurrent = undefined
|
bufferCurrent = undefined
|
||||||
bufferLog = undefined
|
|
||||||
bufferAutoscroll = true
|
|
||||||
|
|
||||||
rpc.send({command: 'Hello', version: 1})
|
rpc.send({command: 'Hello', version: 1})
|
||||||
connecting = false
|
connecting = false
|
||||||
m.redraw()
|
m.redraw()
|
||||||
@ -174,24 +163,13 @@ rpc.addEventListener('BufferRemove', event => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
rpc.addEventListener('BufferActivate', event => {
|
rpc.addEventListener('BufferActivate', event => {
|
||||||
let e = event.detail, b = buffers.get(e.bufferName)
|
let e = event.detail
|
||||||
let old = buffers.get(bufferCurrent)
|
|
||||||
bufferCurrent = e.bufferName
|
bufferCurrent = e.bufferName
|
||||||
bufferLog = undefined
|
setTimeout(() => {
|
||||||
bufferAutoscroll = true
|
let el = document.getElementById('input')
|
||||||
|
if (el !== null)
|
||||||
let textarea = document.getElementById('input')
|
el.focus()
|
||||||
if (textarea === null)
|
})
|
||||||
return
|
|
||||||
|
|
||||||
textarea.focus()
|
|
||||||
if (old !== undefined)
|
|
||||||
old.input = textarea.value
|
|
||||||
|
|
||||||
if (b !== undefined)
|
|
||||||
textarea.value = b.input || ''
|
|
||||||
else
|
|
||||||
textarea.value = ''
|
|
||||||
})
|
})
|
||||||
|
|
||||||
rpc.addEventListener('BufferLine', event => {
|
rpc.addEventListener('BufferLine', event => {
|
||||||
@ -226,56 +204,7 @@ for (let i = 0; i < 24; i++) {
|
|||||||
palette[232 + i] = `#${g}${g}${g}`
|
palette[232 + i] = `#${g}${g}${g}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- UI ---------------------------------------------------------------------
|
function applyColor(fg, bg, inverse) {
|
||||||
|
|
||||||
let Toolbar = {
|
|
||||||
toggleAutoscroll: () => {
|
|
||||||
bufferAutoscroll = !bufferAutoscroll
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleLog: () => {
|
|
||||||
if (bufferLog) {
|
|
||||||
bufferLog = undefined
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rpc.send({
|
|
||||||
command: 'BufferLog',
|
|
||||||
bufferName: bufferCurrent,
|
|
||||||
}).then(resp => {
|
|
||||||
bufferLog = rpc.base64decode(resp.log)
|
|
||||||
m.redraw()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
view: vnode => {
|
|
||||||
return m('.toolbar', {}, [
|
|
||||||
m('button', {onclick: Toolbar.toggleAutoscroll},
|
|
||||||
bufferAutoscroll ? 'Pause autoscroll' : 'Unpause autoscroll'),
|
|
||||||
m('button', {onclick: Toolbar.toggleLog},
|
|
||||||
bufferLog === undefined ? 'Show log' : 'Hide log'),
|
|
||||||
])
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
let BufferList = {
|
|
||||||
activate: name => {
|
|
||||||
rpc.send({command: 'BufferActivate', bufferName: name})
|
|
||||||
},
|
|
||||||
|
|
||||||
view: vnode => {
|
|
||||||
let items = Array.from(buffers, ([name, b]) => {
|
|
||||||
let attrs = {onclick: event => BufferList.activate(name)}
|
|
||||||
if (name == bufferCurrent)
|
|
||||||
attrs.class = 'active'
|
|
||||||
return m('.item', attrs, name)
|
|
||||||
})
|
|
||||||
return m('.list', {}, items)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
let Content = {
|
|
||||||
applyColor: (fg, bg, inverse) => {
|
|
||||||
if (inverse)
|
if (inverse)
|
||||||
[fg, bg] = [bg >= 0 ? bg : 15, fg >= 0 ? fg : 0]
|
[fg, bg] = [bg >= 0 ? bg : 15, fg >= 0 ? fg : 0]
|
||||||
|
|
||||||
@ -286,16 +215,35 @@ let Content = {
|
|||||||
style.backgroundColor = palette[bg]
|
style.backgroundColor = palette[bg]
|
||||||
if (style)
|
if (style)
|
||||||
return style
|
return style
|
||||||
},
|
}
|
||||||
|
|
||||||
linkify: (text, attrs) => {
|
// ---- UI ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
let BufferList = {
|
||||||
|
view: vnode => {
|
||||||
|
let items = []
|
||||||
|
buffers.forEach((b, name) => {
|
||||||
|
let attrs = {
|
||||||
|
onclick: event => {
|
||||||
|
rpc.send({command: 'BufferActivate', bufferName: name})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if (name == bufferCurrent)
|
||||||
|
attrs.class = 'active'
|
||||||
|
items.push(m('.item', attrs, name))
|
||||||
|
})
|
||||||
|
return m('.list', {}, items)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function linkify(text, attrs, a) {
|
||||||
let re = new RegExp([
|
let re = new RegExp([
|
||||||
/https?:\/\//,
|
/https?:\/\//,
|
||||||
/([^\[\](){}<>"'\s]|\([^\[\](){}<>"'\s]*\))+/,
|
/([^\[\](){}<>"'\s]|\([^\[\](){}<>"'\s]*\))+/,
|
||||||
/[^\[\](){}<>"'\s,.:]/,
|
/[^\[\](){}<>"'\s,.:]/,
|
||||||
].map(r => r.source).join(''), 'g')
|
].map(r => r.source).join(''), 'g')
|
||||||
|
|
||||||
let a = [], end = 0, match
|
let end = 0, match
|
||||||
while ((match = re.exec(text)) !== null) {
|
while ((match = re.exec(text)) !== null) {
|
||||||
if (end < match.index)
|
if (end < match.index)
|
||||||
a.push(m('span', attrs, text.substring(end, match.index)))
|
a.push(m('span', attrs, text.substring(end, match.index)))
|
||||||
@ -304,19 +252,19 @@ let Content = {
|
|||||||
}
|
}
|
||||||
if (end < text.length)
|
if (end < text.length)
|
||||||
a.push(m('span', attrs, text.substring(end)))
|
a.push(m('span', attrs, text.substring(end)))
|
||||||
return a
|
}
|
||||||
},
|
|
||||||
|
|
||||||
|
let Content = {
|
||||||
view: vnode => {
|
view: vnode => {
|
||||||
let line = vnode.children[0]
|
let line = vnode.children[0]
|
||||||
let mark = undefined
|
let content = []
|
||||||
switch (line.rendition) {
|
switch (line.rendition) {
|
||||||
case 'Indent': mark = m('span.mark', {}, ''); break
|
case 'Indent': content.push(m('span.mark', {}, '')); break
|
||||||
case 'Status': mark = m('span.mark', {}, '–'); break
|
case 'Status': content.push(m('span.mark', {}, '–')); break
|
||||||
case 'Error': mark = m('span.mark.error', {}, '⚠'); break
|
case 'Error': content.push(m('span.mark.error', {}, '⚠')); break
|
||||||
case 'Join': mark = m('span.mark.join', {}, '→'); break
|
case 'Join': content.push(m('span.mark.join', {}, '→')); break
|
||||||
case 'Part': mark = m('span.mark.part', {}, '←'); break
|
case 'Part': content.push(m('span.mark.part', {}, '←')); break
|
||||||
case 'Action': mark = m('span.mark.action', {}, '✶'); break
|
case 'Action': content.push(m('span.mark.action', {}, '✶')); break
|
||||||
}
|
}
|
||||||
|
|
||||||
let classes = new Set()
|
let classes = new Set()
|
||||||
@ -327,13 +275,14 @@ let Content = {
|
|||||||
classes.add(c)
|
classes.add(c)
|
||||||
}
|
}
|
||||||
let fg = -1, bg = -1, inverse = false
|
let fg = -1, bg = -1, inverse = false
|
||||||
return m('.content', {}, [mark, line.items.flatMap(item => {
|
line.items.forEach(item => {
|
||||||
switch (item.kind) {
|
switch (item.kind) {
|
||||||
case 'Text':
|
case 'Text':
|
||||||
return Content.linkify(item.text, {
|
linkify(item.text, {
|
||||||
class: Array.from(classes.keys()).join(' '),
|
class: Array.from(classes.keys()).join(' '),
|
||||||
style: Content.applyColor(fg, bg, inverse),
|
style: applyColor(fg, bg, inverse),
|
||||||
})
|
}, content)
|
||||||
|
break
|
||||||
case 'Reset':
|
case 'Reset':
|
||||||
classes.clear()
|
classes.clear()
|
||||||
fg = bg = -1
|
fg = bg = -1
|
||||||
@ -348,30 +297,25 @@ let Content = {
|
|||||||
case 'FlipInverse':
|
case 'FlipInverse':
|
||||||
inverse = !inverse
|
inverse = !inverse
|
||||||
break
|
break
|
||||||
case 'FlipBold':
|
case 'FlipBold': flip('b'); break
|
||||||
flip('b')
|
case 'FlipItalic': flip('i'); break
|
||||||
break
|
case 'FlipUnderline': flip('u'); break
|
||||||
case 'FlipItalic':
|
case 'FlipCrossedOut': flip('s'); break
|
||||||
flip('i')
|
case 'FlipMonospace': flip('m'); break
|
||||||
break
|
|
||||||
case 'FlipUnderline':
|
|
||||||
flip('u')
|
|
||||||
break
|
|
||||||
case 'FlipCrossedOut':
|
|
||||||
flip('s')
|
|
||||||
break
|
|
||||||
case 'FlipMonospace':
|
|
||||||
flip('m')
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
})])
|
})
|
||||||
|
return m('.content', {}, content)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let Buffer = {
|
let Buffer = {
|
||||||
oncreate: vnode => {
|
oncreate: vnode => {
|
||||||
if (vnode.dom !== undefined && bufferAutoscroll)
|
if (vnode.dom === undefined)
|
||||||
vnode.dom.scrollTop = vnode.dom.scrollHeight
|
return
|
||||||
|
|
||||||
|
let el = vnode.dom.children[1]
|
||||||
|
if (el !== null)
|
||||||
|
el.scrollTop = el.scrollHeight
|
||||||
},
|
},
|
||||||
|
|
||||||
onupdate: vnode => {
|
onupdate: vnode => {
|
||||||
@ -396,84 +340,62 @@ let Buffer = {
|
|||||||
lines.push(m('.time', {}, date.toLocaleTimeString()))
|
lines.push(m('.time', {}, date.toLocaleTimeString()))
|
||||||
lines.push(m(Content, {}, line))
|
lines.push(m(Content, {}, line))
|
||||||
})
|
})
|
||||||
return m('.buffer', {}, lines)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
let Log = {
|
|
||||||
oncreate: vnode => {
|
|
||||||
if (vnode.dom !== undefined)
|
|
||||||
vnode.dom.scrollTop = vnode.dom.scrollHeight
|
|
||||||
},
|
|
||||||
|
|
||||||
view: vnode => {
|
|
||||||
return m(".log", {}, bufferLog)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
let BufferContainer = {
|
|
||||||
view: vnode => {
|
|
||||||
return m('.buffer-container', {}, [
|
return m('.buffer-container', {}, [
|
||||||
m('.filler'),
|
m('.filler'),
|
||||||
bufferLog !== undefined ? m(Log) : m(Buffer),
|
m('.buffer', {}, lines),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let Input = {
|
function onKeyDown(event) {
|
||||||
complete: textarea => {
|
|
||||||
if (textarea.selectionStart !== textarea.selectionEnd)
|
|
||||||
return false
|
|
||||||
|
|
||||||
rpc.send({
|
|
||||||
command: 'BufferComplete',
|
|
||||||
bufferName: bufferCurrent,
|
|
||||||
text: textarea.value,
|
|
||||||
position: textarea.selectionEnd,
|
|
||||||
}).then(resp => {
|
|
||||||
// TODO: Somehow display remaining options, or cycle through.
|
|
||||||
if (resp.completions.length)
|
|
||||||
textarea.setRangeText(resp.completions[0],
|
|
||||||
resp.start, textarea.selectionEnd, 'end')
|
|
||||||
if (resp.completions.length === 1)
|
|
||||||
textarea.setRangeText(' ',
|
|
||||||
textarea.selectionStart, textarea.selectionEnd, 'end')
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
|
|
||||||
submit: textarea => {
|
|
||||||
rpc.send({
|
|
||||||
command: 'BufferInput',
|
|
||||||
bufferName: bufferCurrent,
|
|
||||||
text: textarea.value,
|
|
||||||
})
|
|
||||||
textarea.value = ''
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
|
|
||||||
onKeyDown: event => {
|
|
||||||
// TODO: And perhaps on other actions, too.
|
// TODO: And perhaps on other actions, too.
|
||||||
rpc.send({command: 'Active'})
|
rpc.send({command: 'Active'})
|
||||||
|
|
||||||
// TODO: Cancel any current autocomplete.
|
// TODO: Cancel any current autocomplete.
|
||||||
|
|
||||||
let textarea = event.currentTarget
|
let textarea = event.currentTarget
|
||||||
let handled = false
|
|
||||||
switch (event.keyCode) {
|
switch (event.keyCode) {
|
||||||
case 9:
|
case 9:
|
||||||
handled = Input.complete(textarea)
|
if (textarea.selectionStart !== textarea.selectionEnd)
|
||||||
break
|
return
|
||||||
|
rpc.send({
|
||||||
|
command: 'BufferComplete',
|
||||||
|
bufferName: bufferCurrent,
|
||||||
|
text: textarea.value,
|
||||||
|
position: textarea.selectionEnd,
|
||||||
|
}).then(response => {
|
||||||
|
// TODO: Somehow display remaining options, or cycle through.
|
||||||
|
if (response.completions.length)
|
||||||
|
textarea.setRangeText(response.completions[0],
|
||||||
|
response.start, textarea.selectionEnd, 'end')
|
||||||
|
if (response.completions.length === 1)
|
||||||
|
textarea.setRangeText(' ',
|
||||||
|
textarea.selectionStart, textarea.selectionEnd, 'end')
|
||||||
|
})
|
||||||
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
handled = Input.submit(textarea)
|
rpc.send({
|
||||||
break
|
command: 'BufferInput',
|
||||||
|
bufferName: bufferCurrent,
|
||||||
|
text: textarea.value,
|
||||||
|
})
|
||||||
|
textarea.value = ''
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if (handled)
|
|
||||||
event.preventDefault()
|
|
||||||
},
|
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This should be remembered across buffer switches,
|
||||||
|
// and we'll probably have to intercept /all/ key presses.
|
||||||
|
let Input = {
|
||||||
view: vnode => {
|
view: vnode => {
|
||||||
return m('textarea#input', {rows: 1, onkeydown: Input.onKeyDown})
|
return m('textarea#input', {
|
||||||
|
rows: 1,
|
||||||
|
onkeydown: onKeyDown,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,8 +408,8 @@ let Main = {
|
|||||||
state = "Disconnected"
|
state = "Disconnected"
|
||||||
|
|
||||||
return m('.xP', {}, [
|
return m('.xP', {}, [
|
||||||
m('.title', {}, [`xP (${state})`, m(Toolbar)]),
|
m('.title', {}, `xP (${state})`),
|
||||||
m('.middle', {}, [m(BufferList), m(BufferContainer)]),
|
m('.middle', {}, [m(BufferList), m(Buffer)]),
|
||||||
m('.status', {}, bufferCurrent),
|
m('.status', {}, bufferCurrent),
|
||||||
m(Input),
|
m(Input),
|
||||||
])
|
])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user