From 416668d3c8bb5d09ebb3d5e3dbe715856165898b Mon Sep 17 00:00:00 2001 From: "Avi Halachmi (:avih)" Date: Fri, 30 Jul 2021 09:23:56 +0300 Subject: stats.lua: page 4 (keys): better alignment of non-ascii keys Previously we assumed the key-name string occupies strlen(name) cells, now we count codepoints instead. This improves alignment of non-english key names. Still not perfect because we don't know if the key name is single or double width, but wcwidth not available to scripts, notoriously unreliable (depends on locale, correct and updated tables, etc), and also not always available (Windows). Still, better than nothing, and we err by at most one cell - vs up to three before this commit (4 bytes keyname codepoint). In the future we could do the alignment using libass tags, however, this both complicates the ass-output generation, and also not available when we output for the terminal, so for now only count codepoints. Also, if the key name was in a right-to-left language, then previously the name/command were swapped visually. Now we inject a left-to-right marker before the name to ensure direction. This works also when harfbuzz is disabled for libass (--sub-ass-shaper=simple). --- player/lua/stats.lua | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'player') diff --git a/player/lua/stats.lua b/player/lua/stats.lua index 2c906a6e32..87bff24f0f 100644 --- a/player/lua/stats.lua +++ b/player/lua/stats.lua @@ -405,6 +405,19 @@ local function cmd_subject(cmd) return subw:len() > 1 and subw or "[unknown]" end +-- key names are valid UTF-8, ascii7 except maybe the last/only codepoint. +-- we count codepoints and ignore wcwidth. no need for grapheme clusters. +-- our error for alignment is at most one cell (if last CP is double-width). +-- (if k was valid but arbitrary: we'd count all bytes <0x80 or >=0xc0) +local function keyname_cells(k) + local klen = k:len() + if klen > 1 and k:byte(klen) >= 0x80 then -- last/only CP is not ascii7 + repeat klen = klen-1 + until klen == 1 or k:byte(klen) >= 0xc0 -- last CP begins at klen + end + return klen +end + local function get_kbinfo_lines(width) -- active keys: only highest priotity of each key, and not our (stats) keys local bindings = mp.get_property_native("input-bindings", {}) @@ -437,7 +450,7 @@ local function get_kbinfo_lines(width) end local function align_right(key) - return kspaces:sub(key:len()) .. key + return kspaces:sub(keyname_cells(key)) .. key end -- sort by: subject, mod(ifier)s count, mods, key-len, lowercase-key, key @@ -460,8 +473,9 @@ local function get_kbinfo_lines(width) -- key/subject pre/post formatting for terminal/ass. -- key/subject alignment uses spaces (with mono font if ass) -- word-wrapping is disabled for ass, or cut at 79 for the terminal + local LTR = string.char(0xE2, 0x80, 0x8E) -- U+200E Left To Right mark local term = not o.use_ass - local kpre = term and "" or format("{\\q2\\fn%s}", o.font_mono) + local kpre = term and "" or format("{\\q2\\fn%s}%s", o.font_mono, LTR) local kpost = term and " " or format(" {\\fn%s}", o.font) local spre = term and kspaces .. " " or format("{\\q2\\fn%s}%s {\\fn%s}{\\fs%d\\u1}", -- cgit v1.2.3