From f7be510d2669646c60845b091087362d51ae29ea Mon Sep 17 00:00:00 2001
From: Přemysl Eric Janouch
Date: Sat, 27 Aug 2022 08:55:44 +0200
Subject: xC: make fancy-prompt.lua alignment more reliable
And generally clean up that script.
---
plugins/xC/fancy-prompt.lua | 36 ++++++++++++++++++++++--------------
xC.c | 33 ++++++++++++++++++++++++++++++---
2 files changed, 52 insertions(+), 17 deletions(-)
diff --git a/plugins/xC/fancy-prompt.lua b/plugins/xC/fancy-prompt.lua
index 8ec697a..0b7000c 100644
--- a/plugins/xC/fancy-prompt.lua
+++ b/plugins/xC/fancy-prompt.lua
@@ -1,7 +1,7 @@
--
-- fancy-prompt.lua: the fancy multiline prompt you probably want
--
--- Copyright (c) 2016, Přemysl Eric Janouch
+-- Copyright (c) 2016 - 2022, Přemysl Eric Janouch
--
-- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted.
@@ -40,7 +40,7 @@ xC.hook_prompt (function (hook)
if buffer == current then
current_n = i
elseif buffer.new_messages_count ~= buffer.new_unimportant_count then
- if active ~= "" then active = active .. "," end
+ active = active .. ","
if buffer.highlighted then
active = active .. "!"
bg_color = "224"
@@ -48,7 +48,6 @@ xC.hook_prompt (function (hook)
active = active .. i
end
end
- if active ~= "" then active = "(" .. active .. ")" end
local x = current_n .. ":" .. current.name
if chan and chan.users_len ~= 0 then
local params = ""
@@ -56,25 +55,34 @@ xC.hook_prompt (function (hook)
params = params .. " +" .. mode .. " " .. param
end
local modes = chan.no_param_modes .. params:sub (3)
- if modes ~= "" then x = x .. "(+" .. modes .. ")" end
+ if modes ~= "" then
+ x = x .. "(+" .. modes .. ")"
+ end
x = x .. "{" .. chan.users_len .. "}"
end
- if current.hide_unimportant then x = x .. "" end
-
- local lines, cols = xC.get_screen_size ()
- x = x .. " " .. active .. string.rep (" ", cols)
+ if current.hide_unimportant then
+ x = x .. ""
+ end
+ if active ~= "" then
+ x = x .. " (" .. active:sub (2) .. ")"
+ end
-- Readline 7.0.003 seems to be broken and completely corrupts the prompt.
-- However 8.0.004 seems to be fine with these, as is libedit 20191231-3.1.
--x = x:gsub("[\128-\255]", "?")
- -- Cut off extra characters and apply formatting, including the hack.
- -- FIXME: this doesn't count with full-width or zero-width characters.
- -- We might want to export wcwidth() above term_from_utf8 somehow.
- local overflow = utf8.offset (x, cols - 1)
- if overflow then x = x:sub (1, overflow) end
+ -- Align to the terminal's width and apply formatting, including the hack.
+ local lines, cols = xC.get_screen_size ()
+ local trailing, width = " ", xC.measure (x)
+ while cols > 0 and width >= cols do
+ x = x:sub (1, utf8.offset (x, -1) - 1)
+ trailing, width = ">", xC.measure (x)
+ end
+
x = "\x01\x1b[0;4;1;38;5;16m\x1b[48;5;" .. bg_color .. "m\x02" ..
- x .. "\x01\x1b[0;4;1;7;38;5;" .. bg_color .. "m\x02 \x01\x1b[0;1m\x02"
+ x .. string.rep (" ", cols - width - 1) ..
+ "\x01\x1b[0;4;1;7;38;5;" .. bg_color .. "m\x02" ..
+ trailing .. "\x01\x1b[0;1m\x02"
local user_prefix = function (chan, user)
for i, chan_user in ipairs (chan.users) do
diff --git a/xC.c b/xC.c
index 9cb97c8..7b61fb9 100644
--- a/xC.c
+++ b/xC.c
@@ -3776,7 +3776,7 @@ explode_text (struct exploder *self, const char *text)
if (!strchr ("\a\b\x0e\x0f\x1b" /* BEL BS SO SI ESC */, *p))
str_append_c (&filtered, *p);
- size_t term_len = 0;
+ size_t term_len = 0, processed = 0, len;
char *term = iconv_xstrdup (self->ctx->term_from_utf8,
filtered.str, filtered.len + 1, &term_len);
str_free (&filtered);
@@ -3785,11 +3785,10 @@ explode_text (struct exploder *self, const char *text)
memset (&ps, 0, sizeof ps);
wchar_t wch;
- size_t len, processed = 0;
while ((len = mbrtowc (&wch, term + processed, term_len - processed, &ps)))
{
hard_assert (len != (size_t) -2 && len != (size_t) -1);
- processed += len;
+ hard_assert ((processed += len) <= term_len);
struct line_char *c = line_char_new (wch);
c->attrs = self->attrs;
@@ -10527,6 +10526,33 @@ lua_plugin_get_screen_size (lua_State *L)
return 2;
}
+static int
+lua_plugin_measure (lua_State *L)
+{
+ struct lua_plugin *plugin = lua_touserdata (L, lua_upvalueindex (1));
+ const char *line = lua_plugin_check_utf8 (L, 1);
+
+ size_t term_len = 0, processed = 0, width = 0, len;
+ char *term = iconv_xstrdup (plugin->ctx->term_from_utf8,
+ (char *) line, strlen (line) + 1, &term_len);
+
+ mbstate_t ps;
+ memset (&ps, 0, sizeof ps);
+
+ wchar_t wch;
+ while ((len = mbrtowc (&wch, term + processed, term_len - processed, &ps)))
+ {
+ hard_assert (len != (size_t) -2 && len != (size_t) -1);
+ hard_assert ((processed += len) <= term_len);
+
+ int wch_width = wcwidth (wch);
+ width += MAX (0, wch_width);
+ }
+ free (term);
+ lua_pushinteger (L, width);
+ return 1;
+}
+
static int
lua_ctx_gc (lua_State *L)
{
@@ -10547,6 +10573,7 @@ static luaL_Reg lua_plugin_library[] =
// And these are methods:
{ "get_screen_size", lua_plugin_get_screen_size },
+ { "measure", lua_plugin_measure },
{ "__gc", lua_ctx_gc },
{ NULL, NULL },
};
--
cgit v1.2.3-70-g09d2