Compare commits
	
		
			5 Commits
		
	
	
		
			1639235a48
			...
			d7b0b447b7
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d7b0b447b7 | |||
| 25ad5ae0ec | |||
| 10f6072da9 | |||
| aceac26cbb | |||
| e250ae8255 | 
							
								
								
									
										19
									
								
								README.adoc
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								README.adoc
									
									
									
									
									
								
							| @ -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. | certificates, a remote relay interface, or basic support for Lua scripting. | ||||||
| As a unique bonus, you can launch a full text editor from within. | 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 | xP | ||||||
| -- | -- | ||||||
| The web frontend for 'xC', making use of its networked relay interface. | 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 | xD | ||||||
| -- | -- | ||||||
| @ -72,15 +73,15 @@ Building | |||||||
| Build-only dependencies: | Build-only dependencies: | ||||||
|  CMake, pkg-config, asciidoctor or asciidoc, awk, liberty (included) + |  CMake, pkg-config, asciidoctor or asciidoc, awk, liberty (included) + | ||||||
| Common runtime dependencies: openssl + | Common runtime dependencies: openssl + | ||||||
| Additionally for 'xC': curses, libffi, + | Additionally for 'xC': curses, libffi, readline >= 6.0 or libedit >= 2013-07-12, | ||||||
|  readline >= 6.0 or libedit >= 2013-07-12, lua >= 5.3 (optional) + |  lua >= 5.3 (optional) + | ||||||
| Additionally for 'xF': x11, xft | Additionally for 'xF': x11, xft | ||||||
| 
 | 
 | ||||||
|  $ git clone --recursive https://git.janouch.name/p/xK.git |  $ git clone --recursive https://git.janouch.name/p/xK.git | ||||||
|  $ mkdir xK/build |  $ mkdir xK/build | ||||||
|  $ cd xK/build |  $ cd xK/build | ||||||
|  $ cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=RelWithDebInfo \ |  $ 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 |  $ make | ||||||
| 
 | 
 | ||||||
| To install the application, you can do either the usual: | To install the application, you can do either the usual: | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								xC-proto
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								xC-proto
									
									
									
									
									
								
							| @ -69,6 +69,7 @@ struct EventMessage { | |||||||
| 			ERROR, | 			ERROR, | ||||||
| 			JOIN, | 			JOIN, | ||||||
| 			PART, | 			PART, | ||||||
|  | 			ACTION, | ||||||
| 		} rendition; | 		} rendition; | ||||||
| 		// Unix timestamp in seconds. | 		// Unix timestamp in seconds. | ||||||
| 		u64 when; | 		u64 when; | ||||||
|  | |||||||
							
								
								
									
										28
									
								
								xC.c
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								xC.c
									
									
									
									
									
								
							| @ -1480,7 +1480,7 @@ struct formatter_item | |||||||
| { | { | ||||||
| 	enum formatter_item_type type : 16; ///< Type of this item
 | 	enum formatter_item_type type : 16; ///< Type of this item
 | ||||||
| 	int attribute                 : 16; ///< Attribute ID or a TEXT_* mask
 | 	int attribute                 : 16; ///< Attribute ID or a TEXT_* mask
 | ||||||
| 	int color;                          ///< Colour
 | 	int color;                          ///< Colour ([256 << 16] | 16)
 | ||||||
| 	char *text;                         ///< String
 | 	char *text;                         ///< String
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -1536,6 +1536,7 @@ enum buffer_line_rendition | |||||||
| 	BUFFER_LINE_ERROR,                  ///< Error message
 | 	BUFFER_LINE_ERROR,                  ///< Error message
 | ||||||
| 	BUFFER_LINE_JOIN,                   ///< Join arrow
 | 	BUFFER_LINE_JOIN,                   ///< Join arrow
 | ||||||
| 	BUFFER_LINE_PART,                   ///< Part arrow
 | 	BUFFER_LINE_PART,                   ///< Part arrow
 | ||||||
|  | 	BUFFER_LINE_ACTION,                 ///< Highlighted asterisk
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct buffer_line | 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); | 	union relay_item_data *p = e->items = xcalloc (len * 6, sizeof *e->items); | ||||||
| 	for (struct formatter_item *i = line->items; len--; i++) | 	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) | 		switch (i->type) | ||||||
| 		{ | 		{ | ||||||
| 		case FORMATTER_ITEM_TEXT: | 		case FORMATTER_ITEM_TEXT: | ||||||
| @ -3125,11 +3129,11 @@ relay_prepare_buffer_line (struct app_context *ctx, struct buffer *buffer, | |||||||
| 			(p++)->kind = RELAY_ITEM_RESET; | 			(p++)->kind = RELAY_ITEM_RESET; | ||||||
| 			break; | 			break; | ||||||
| 		case FORMATTER_ITEM_FG_COLOR: | 		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; | 			(p++)->kind = RELAY_ITEM_FG_COLOR; | ||||||
| 			break; | 			break; | ||||||
| 		case FORMATTER_ITEM_BG_COLOR: | 		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; | 			(p++)->kind = RELAY_ITEM_BG_COLOR; | ||||||
| 			break; | 			break; | ||||||
| 		case FORMATTER_ITEM_SIMPLE: | 		case FORMATTER_ITEM_SIMPLE: | ||||||
| @ -4472,9 +4476,10 @@ buffer_line_flush (struct buffer_line *line, struct formatter *f, FILE *output, | |||||||
| 	case BUFFER_LINE_BARE:                               break; | 	case BUFFER_LINE_BARE:                               break; | ||||||
| 	case BUFFER_LINE_INDENT:  formatter_add (f, "    "); break; | 	case BUFFER_LINE_INDENT:  formatter_add (f, "    "); break; | ||||||
| 	case BUFFER_LINE_STATUS:  formatter_add (f, " -  "); break; | 	case BUFFER_LINE_STATUS:  formatter_add (f, " -  "); break; | ||||||
| 	case BUFFER_LINE_ERROR:   formatter_add (f, "#a=!=#r ", ATTR_ERROR); break; | 	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_JOIN:    formatter_add (f, "#a-->#r ", ATTR_JOIN);   break; | ||||||
| 	case BUFFER_LINE_PART:    formatter_add (f, "#a<--#r ", ATTR_PART);  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++) | 	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)                  \ | #define log_outcoming_privmsg(s, buffer, prefixes, who, text)                  \ | ||||||
| 	log_server ((s), (buffer), 0, 0, "<#s#n> #m", (prefixes), (who), (text)) | 	log_server ((s), (buffer), 0, 0, "<#s#n> #m", (prefixes), (who), (text)) | ||||||
| #define log_outcoming_action(s, buffer, who, text)                             \ | #define log_outcoming_action(s, buffer, who, text)                             \ | ||||||
| 	log_server ((s), (buffer), 0, 0, " #a*#r  #n #m", \ | 	log_server ((s), (buffer), 0, BUFFER_LINE_ACTION, "#n #m", (who), (text)) | ||||||
| 		ATTR_ACTION, (who), (text)) |  | ||||||
| 
 | 
 | ||||||
| #define log_outcoming_orphan_notice(s, target, text)                           \ | #define log_outcoming_orphan_notice(s, target, text)                           \ | ||||||
| 	log_server_status ((s), (s)->buffer, "Notice -> #n: #m", (target), (text)) | 	log_server_status ((s), (s)->buffer, "Notice -> #n: #m", (target), (text)) | ||||||
| #define log_outcoming_orphan_privmsg(s, 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)                           \ | #define log_outcoming_orphan_action(s, target, text)                           \ | ||||||
| 	log_server_status ((s), (s)->buffer, "MSG(#n):  #a*#r  #m", (target),      \ | 	log_server ((s), (s)->buffer, 0, BUFFER_LINE_ACTION,                       \ | ||||||
| 		ATTR_ACTION, (text)) | 		"MSG(#n): #m", (target), (text)) | ||||||
| 
 | 
 | ||||||
| #define log_ctcp_query(s, target, tag)                                         \ | #define log_ctcp_query(s, target, tag)                                         \ | ||||||
| 	log_server_status ((s), (s)->buffer, "CTCP query to #S: #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) | 		if (msg->params.len == 2) | ||||||
| 			irc_try_parse_welcome_for_userhost (s, msg->params.vector[1]); | 			irc_try_parse_welcome_for_userhost (s, msg->params.vector[1]); | ||||||
| 		break; | 		break; | ||||||
|  | 	case IRC_RPL_MOTDSTART: | ||||||
| 	case IRC_RPL_MOTD: | 	case IRC_RPL_MOTD: | ||||||
| 		if (copy.len) | 		if (copy.len) | ||||||
| 			irc_adjust_motd (©.vector[0]); | 			irc_adjust_motd (©.vector[0]); | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| module janouch.name/xK | module janouch.name/xK/xP | ||||||
| 
 | 
 | ||||||
| go 1.18 | go 1.18 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -79,6 +79,9 @@ body { | |||||||
| .mark.part { | .mark.part { | ||||||
| 	color: red; | 	color: red; | ||||||
| } | } | ||||||
|  | .mark.action { | ||||||
|  | 	color: darkred; | ||||||
|  | } | ||||||
| .content { | .content { | ||||||
| 	padding: .1rem .3rem; | 	padding: .1rem .3rem; | ||||||
| 	white-space: pre-wrap; | 	white-space: pre-wrap; | ||||||
|  | |||||||
| @ -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.
 | // TODO: Probably reset state on disconnect, and indicate to user.
 | ||||||
| let socket = new WebSocket(proxy) | let socket = new WebSocket(proxy) | ||||||
| 
 | 
 | ||||||
| @ -59,6 +96,8 @@ socket.onmessage = function(event) { | |||||||
| 	m.redraw() | 	m.redraw() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // ---- UI ---------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
| let BufferList = { | let BufferList = { | ||||||
| 	view: vnode => { | 	view: vnode => { | ||||||
| 		let items = [] | 		let items = [] | ||||||
| @ -81,11 +120,12 @@ let Content = { | |||||||
| 		let line = vnode.children[0] | 		let line = vnode.children[0] | ||||||
| 		let content = [] | 		let content = [] | ||||||
| 		switch (line.rendition) { | 		switch (line.rendition) { | ||||||
| 		case 'Indent': content.push(m('span.mark',       {}, ''));  break | 		case 'Indent': content.push(m('span.mark',        {}, ''));  break | ||||||
| 		case 'Status': content.push(m('span.mark',       {}, '–')); break | 		case 'Status': content.push(m('span.mark',        {}, '–')); break | ||||||
| 		case 'Error':  content.push(m('span.mark.error', {}, '⚠')); break | 		case 'Error':  content.push(m('span.mark.error',  {}, '⚠')); break | ||||||
| 		case 'Join':   content.push(m('span.mark.join',  {}, '→')); break | 		case 'Join':   content.push(m('span.mark.join',   {}, '→')); break | ||||||
| 		case 'Part':   content.push(m('span.mark.part',  {}, '←')); break | 		case 'Part':   content.push(m('span.mark.part',   {}, '←')); break | ||||||
|  | 		case 'Action': content.push(m('span.mark.action', {}, '✶')); break | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		let classes = new Set() | 		let classes = new Set() | ||||||
| @ -95,22 +135,33 @@ let Content = { | |||||||
| 			else | 			else | ||||||
| 				classes.add(c) | 				classes.add(c) | ||||||
| 		} | 		} | ||||||
|  | 		let fg = -1, bg = -1, inverse = false | ||||||
| 		line.items.forEach(item => { | 		line.items.forEach(item => { | ||||||
| 			// TODO: Colours.
 |  | ||||||
| 			switch (item.kind) { | 			switch (item.kind) { | ||||||
| 			case 'Text': | 			case 'Text': | ||||||
| 				// TODO: Detect and transform links.
 | 				// TODO: Detect and transform links.
 | ||||||
| 				content.push(m('span', { | 				content.push(m('span', { | ||||||
| 					class: Array.from(classes.keys()).join(' '), | 					class: Array.from(classes.keys()).join(' '), | ||||||
|  | 					style: applyColor(fg, bg, inverse), | ||||||
| 				}, item.text)) | 				}, item.text)) | ||||||
| 				break | 				break | ||||||
| 			case 'Reset': | 			case 'Reset': | ||||||
| 				classes.clear() | 				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 | 				break | ||||||
| 			case 'FlipBold':       flip('b'); break | 			case 'FlipBold':       flip('b'); break | ||||||
| 			case 'FlipItalic':     flip('i'); break | 			case 'FlipItalic':     flip('i'); break | ||||||
| 			case 'FlipUnderline':  flip('u'); break | 			case 'FlipUnderline':  flip('u'); break | ||||||
| 			case 'FlipInverse':    flip('i'); break |  | ||||||
| 			case 'FlipCrossedOut': flip('s'); break | 			case 'FlipCrossedOut': flip('s'); break | ||||||
| 			case 'FlipMonospace':  flip('m'); break | 			case 'FlipMonospace':  flip('m'); break | ||||||
| 			} | 			} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user