Compare commits

...

5 Commits

7 changed files with 93 additions and 28 deletions

View File

@ -23,15 +23,16 @@ command aliases, SOCKS proxying, SASL EXTERNAL authentication using TLS client
certificates, a remote relay interface, or basic support for Lua scripting.
As a unique bonus, you can launch a full text editor from within.
xF
--
The X11 frontend for 'xC', making use of its networked relay interface.
It's currently in development, and is hidden behind a CMake option.
xP
--
The web frontend for 'xC', making use of its networked relay interface.
It's currently rather elementary, and can be built from within its directory.
So far it's quite basic, yet usable. Build it using `make` in its directory,
and run it from within the _public_ subdirectory.
xF
--
The X11 frontend for 'xC', making use of its networked relay interface.
It's currently in development, and hidden behind a CMake option.
xD
--
@ -72,15 +73,15 @@ Building
Build-only dependencies:
CMake, pkg-config, asciidoctor or asciidoc, awk, liberty (included) +
Common runtime dependencies: openssl +
Additionally for 'xC': curses, libffi, +
readline >= 6.0 or libedit >= 2013-07-12, lua >= 5.3 (optional) +
Additionally for 'xC': curses, libffi, readline >= 6.0 or libedit >= 2013-07-12,
lua >= 5.3 (optional) +
Additionally for 'xF': x11, xft
$ git clone --recursive https://git.janouch.name/p/xK.git
$ mkdir xK/build
$ cd xK/build
$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DWANT_READLINE=ON -DWANT_LIBEDIT=OFF -DWANT_LUA=ON
-DWANT_READLINE=ON -DWANT_LIBEDIT=OFF -DWITH_LUA=ON
$ make
To install the application, you can do either the usual:

View File

@ -69,6 +69,7 @@ struct EventMessage {
ERROR,
JOIN,
PART,
ACTION,
} rendition;
// Unix timestamp in seconds.
u64 when;

22
xC.c
View File

@ -1480,7 +1480,7 @@ struct formatter_item
{
enum formatter_item_type type : 16; ///< Type of this item
int attribute : 16; ///< Attribute ID or a TEXT_* mask
int color; ///< Colour
int color; ///< Colour ([256 << 16] | 16)
char *text; ///< String
};
@ -1536,6 +1536,7 @@ enum buffer_line_rendition
BUFFER_LINE_ERROR, ///< Error message
BUFFER_LINE_JOIN, ///< Join arrow
BUFFER_LINE_PART, ///< Part arrow
BUFFER_LINE_ACTION, ///< Highlighted asterisk
};
struct buffer_line
@ -3114,6 +3115,9 @@ relay_prepare_buffer_line (struct app_context *ctx, struct buffer *buffer,
union relay_item_data *p = e->items = xcalloc (len * 6, sizeof *e->items);
for (struct formatter_item *i = line->items; len--; i++)
{
// XXX: See attr_printer_decode_color(), this is a footgun.
int16_t c16 = i->color;
int16_t c256 = i->color >> 16;
switch (i->type)
{
case FORMATTER_ITEM_TEXT:
@ -3125,11 +3129,11 @@ relay_prepare_buffer_line (struct app_context *ctx, struct buffer *buffer,
(p++)->kind = RELAY_ITEM_RESET;
break;
case FORMATTER_ITEM_FG_COLOR:
p->fg_color.color = i->color;
p->fg_color.color = c256 <= 0 ? c16 : c256;
(p++)->kind = RELAY_ITEM_FG_COLOR;
break;
case FORMATTER_ITEM_BG_COLOR:
p->bg_color.color = i->color;
p->bg_color.color = c256 <= 0 ? c16 : c256;
(p++)->kind = RELAY_ITEM_BG_COLOR;
break;
case FORMATTER_ITEM_SIMPLE:
@ -4475,6 +4479,7 @@ buffer_line_flush (struct buffer_line *line, struct formatter *f, FILE *output,
case BUFFER_LINE_ERROR: formatter_add (f, "#a=!=#r ", ATTR_ERROR); break;
case BUFFER_LINE_JOIN: formatter_add (f, "#a-->#r ", ATTR_JOIN); break;
case BUFFER_LINE_PART: formatter_add (f, "#a<--#r ", ATTR_PART); break;
case BUFFER_LINE_ACTION: formatter_add (f, " #a*#r ", ATTR_ACTION); break;
}
for (struct formatter_item *iter = line->items; iter->type; iter++)
@ -4691,16 +4696,16 @@ log_full (struct app_context *ctx, struct server *s, struct buffer *buffer,
#define log_outcoming_privmsg(s, buffer, prefixes, who, text) \
log_server ((s), (buffer), 0, 0, "<#s#n> #m", (prefixes), (who), (text))
#define log_outcoming_action(s, buffer, who, text) \
log_server ((s), (buffer), 0, 0, " #a*#r #n #m", \
ATTR_ACTION, (who), (text))
log_server ((s), (buffer), 0, BUFFER_LINE_ACTION, "#n #m", (who), (text))
#define log_outcoming_orphan_notice(s, target, text) \
log_server_status ((s), (s)->buffer, "Notice -> #n: #m", (target), (text))
#define log_outcoming_orphan_privmsg(s, target, text) \
log_server_status ((s), (s)->buffer, "MSG(#n): #m", (target), (text))
log_server ((s), (s)->buffer, 0, BUFFER_LINE_STATUS, \
"MSG(#n): #m", (target), (text))
#define log_outcoming_orphan_action(s, target, text) \
log_server_status ((s), (s)->buffer, "MSG(#n): #a*#r #m", (target), \
ATTR_ACTION, (text))
log_server ((s), (s)->buffer, 0, BUFFER_LINE_ACTION, \
"MSG(#n): #m", (target), (text))
#define log_ctcp_query(s, target, tag) \
log_server_status ((s), (s)->buffer, "CTCP query to #S: #S", target, tag)
@ -8763,6 +8768,7 @@ irc_process_numeric (struct server *s,
if (msg->params.len == 2)
irc_try_parse_welcome_for_userhost (s, msg->params.vector[1]);
break;
case IRC_RPL_MOTDSTART:
case IRC_RPL_MOTD:
if (copy.len)
irc_adjust_motd (&copy.vector[0]);

View File

@ -1,4 +1,4 @@
module janouch.name/xK
module janouch.name/xK/xP
go 1.18

View File

@ -79,6 +79,9 @@ body {
.mark.part {
color: red;
}
.mark.action {
color: darkred;
}
.content {
padding: .1rem .3rem;
white-space: pre-wrap;

View File

@ -1,3 +1,40 @@
// Copyright (c) 2022, Přemysl Eric Janouch <p@janouch.name>
// SPDX-License-Identifier: 0BSD
// --- Colours -----------------------------------------------------------------
let palette = [
'#000', '#800', '#080', '#880', '#008', '#808', '#088', '#ccc',
'#888', '#f00', '#0f0', '#ff0', '#00f', '#f0f', '#0ff', '#fff',
]
palette.length = 256
for (let i = 0; i < 216; i++) {
let r = i / 36 >> 0, g = (i / 6 >> 0) % 6, b = i % 6
r = !r ? '00' : (55 + 40 * r).toString(16)
g = !g ? '00' : (55 + 40 * g).toString(16)
b = !b ? '00' : (55 + 40 * b).toString(16)
palette[16 + i] = `#${r}${g}${b}`
}
for (let i = 0; i < 24; i++) {
let g = ('0' + (8 + i * 10).toString(16)).slice(-2)
palette[232 + i] = `#${g}${g}${g}`
}
function applyColor(fg, bg, inverse) {
if (inverse)
[fg, bg] = [bg >= 0 ? bg : 15, fg >= 0 ? fg : 0]
let style = ''
if (fg >= 0)
style += `color: ${palette[fg]};`
if (bg >= 0)
style += `background-color: ${palette[bg]};`
if (style)
return style
}
// ---- Event processing -------------------------------------------------------
// TODO: Probably reset state on disconnect, and indicate to user.
let socket = new WebSocket(proxy)
@ -59,6 +96,8 @@ socket.onmessage = function(event) {
m.redraw()
}
// ---- UI ---------------------------------------------------------------------
let BufferList = {
view: vnode => {
let items = []
@ -86,6 +125,7 @@ let Content = {
case 'Error': content.push(m('span.mark.error', {}, '⚠')); break
case 'Join': content.push(m('span.mark.join', {}, '→')); break
case 'Part': content.push(m('span.mark.part', {}, '←')); break
case 'Action': content.push(m('span.mark.action', {}, '✶')); break
}
let classes = new Set()
@ -95,22 +135,33 @@ let Content = {
else
classes.add(c)
}
let fg = -1, bg = -1, inverse = false
line.items.forEach(item => {
// TODO: Colours.
switch (item.kind) {
case 'Text':
// TODO: Detect and transform links.
content.push(m('span', {
class: Array.from(classes.keys()).join(' '),
style: applyColor(fg, bg, inverse),
}, item.text))
break
case 'Reset':
classes.clear()
fg = bg = -1
inverse = false
break
case 'FgColor':
fg = item.color
break
case 'BgColor':
bg = item.color
break
case 'FlipInverse':
inverse = !inverse
break
case 'FlipBold': flip('b'); break
case 'FlipItalic': flip('i'); break
case 'FlipUnderline': flip('u'); break
case 'FlipInverse': flip('i'); break
case 'FlipCrossedOut': flip('s'); break
case 'FlipMonospace': flip('m'); break
}

View File

@ -1,3 +1,6 @@
// Copyright (c) 2022, Přemysl Eric Janouch <p@janouch.name>
// SPDX-License-Identifier: 0BSD
package main
import (