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 }, };