IntelliJ-EmmyLua
IntelliJ-EmmyLua copied to clipboard
增强字符串信息可视化
概述
有时,我们会发现在使用 IntelliJ-EmmyLua 来 Debug 时,一些字符串信息会显示不全。 具体的显示不全的情况有:字符串截断,ASCII控制字符被替换为固定字符,等等。 显示不全,导致调试过程中不方便,无法准确得知字符串的内容。
为了解决这个问题,本PR为 IntelliJ-EmmyLua 增加特性,可以使得 EmmyLua 在必要时增加显示字符串的Hex及ASCII码。
需要注意的是,本PR依赖EmmyLuaDebugger的PR,见https://github.com/EmmyLua/EmmyLuaDebugger/pull/50。
结合示例说明本PR
测试用例
假设正在断点调试以下代码:
local function hexToString(hexStr)
return (hexStr:gsub('(%x%x)', function(h)
local charNum = tonumber(h, 16)
return string.char(charNum)
end))
end
-- 常规的、可打印 单字节(ASCII) 字符串
local a = "abc"
-- 常规的、可打印的 单字节(ASCII) 及 三字节(中文) 字符串
local b = "a我c"
-- 不常规的本来不可直接打印的(如这里的0A,\n)
local c = hexToString("0A61E6889163")
-- 带终止符的字符串
local d = hexToString("6100E6889163")
-- 所有控制字符
local e = hexToString("610102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F7F63")
原版EmmyLua
当前最新官方版本:1.4.9-IDEA231,发布日期:Nov 15, 2023,
断点,能看到以下内容:
分析:
- 观察c,我们知道,rider对0x0A(LF,换行符)进行了转义,能显示成\n。
- 观察d,lua底层是c,c遇到0x00(终止符),就把后面的字节流忽略了。
- 观察e,这里能看到rider对哪些ASCII控制码有做转义,没有做转义的,特别地,7F(删除符)显示成了空格。
本PR版本
对同样的Lua代码进行断点,查看字符串的内容,有:
分析:
- 观察a、b、c,与原版没有差异,因为原版已经把足够的信息表达出来了,所以我这里追加更多信息,避免干扰(平时开发过程中,遇到的大多数情况都属于这种常规情况)。
- 观察d、e,使用[Hex]、[ASCII]、[tostring]分割了三段字符串的表达形式:在[tostring]段,保留了原版的形式,;同时增加对应的Hex表示,以及ASCII表示。
实现细节
修改EmmyLuaDebug
核心修改为:https://github.com/zhangjiequan/EmmyLuaDebugger/commit/38946d6df7b8ceb32e368715c0ada3c7bad419de。
见EmmyLuaDebugger的PR:https://github.com/EmmyLua/EmmyLuaDebugger/pull/50。
主要是增加string类型,使得可以由后续的IntelliJ-EmmyLua中的emmyHelper.lua控制显示的内容。
修改IntelliJ-EmmyLua
核心修改为:https://github.com/EmmyLua/IntelliJ-EmmyLua/commit/88fb70a79854c31480e1e5ff12bbaf986174d2ea。
增加内容的条件
只在必要时,才去追加内容,避免不必要时追加了内容,造成干扰。
需要追加内容的条件是:
- 是合法的utf8
- 如果是utf8中的单字节,还需要符合rider下的可打印“isPrintable()” (什么是可打印:根据实验,得到定义printableChars的字符是会被rider转义的,所以是可打印的;同时,按ascii规定,32~126的字符也是可打印的。)
输出模式
为了方便控制,我还提供了输出模式选项。
- Auto,自动,默认值,即判断如果当前字符串符合上面《增加内容的条件》的,就追加,否则不增加。
- Concise,简洁,总是不增加。
- Complete,完全,总是增加。
待办
插件面板中增加输出模式的选择
类似架构选择,可以选择x64、x86,
这里增加对应的RadioButton,选择后会自动修改下方代码中的Mode。
需要修改的文件有:
- IntelliJ-EmmyLua\src\main\java\com\tang\intellij\lua\debugger\emmy\EmmyDebugSettingsPanel.form
- IntelliJ-EmmyLua\src\main\java\com\tang\intellij\lua\debugger\emmy\EmmyDebugSettingsPanel.java
- IntelliJ-EmmyLua\src\main\java\com\tang\intellij\lua\debugger\emmy\EmmyDebugConfigurationType.kt
这种显示方式是不是有歧义?[HEX] 这种会不会误以为是文本的一部分?
阿唐,你好,感谢回复。
你指出的潜在歧义确实值得关注。
为了维护通用插件的准确性和可靠性,我们必须仔细考虑所有潜在的歧义问题。
歧义的具体情况
我们可以分为两种情况分别讨论。
情况一:用户对[Hex]的误解
概述
可能会有用户不清楚 [Hex]:xxxx [ASCII]:xxxx [tostring]:
的含义,
将其误认为是原字符串的一部分,从而导致误导。
应对方案
当前方案下,可以通过教育用户,以避免误解。 教育用户的手段可以有:
- 在文档中增加相关说明;
-
value
中增加说明,如增加前缀Encoded Data ->
-
输出模式
中,默认使用Concise
(简洁,总是不增加额外信息),并增加对应说明,说明选择了其它模式可能导致产生歧义。
情况二:字符串无法区分的情况
概述
考虑这样两个字符串,比如下面的d
和 f
,
尽管它们存储的字节流不同,但在当前的展示方案下,观察到的value
是相同的,导致无法区分。
-- 带终止符的字符串
local d = hexToString("6100E6889163")
-- 无法与d区分的f
local f = "[Hex]:6100E6889163 [ASCII]:a����c [tostring]:a"
应对方案
当前方案下,无法避免这个情况。
但考虑到原字符串出现 [Hex]:xxxx [ASCII]:xxxx [tostring]:xxxx
的概率是如此的小,我们基本可以忽略这种情况。
应对方案只能是不处理。
反过来想,虽然歧义的出现几率很小, 但为了确保作为一个通用插件的严谨性,我们需要考虑所有可能的情况。
避免歧义的方案
当前方案,虽然有歧义,但我并不认为会比最新的发布版本的方案差。
理由是,起码当前版本能区分 0x610061
与 0x610062
,
而最新的发布版本无法区分两者,只能将它们都显示为 a
。
如果要进一步优化当前方案,我们可以做以下的事情。
方案一
将 {string}
修改为一个特殊的标识符,例如 {string_buff}
。
方案二
避免直接在当前位置修改 value
,而是考虑将 Hex 和 ASCII 信息展示在其他位置。
我们可以增加一个额外的 Inspector 面板,用于展示这些信息。
或者是直接在这个位置展示:
开放接口以允许项目侧自定义展示内容
目前,我们通过修改插件源码来更改 value
的展示内容。
我们是否可以考虑对 EmmyLuaDebugger 进行修改,以开放所有 Lua 类型,
并在 IntelliJ-EmmyLua 侧增加接口,允许用户自定义 value
的展示内容?
我觉得不行, IDE通常会有个功能叫hexeditor, 这个可以集成到调试功能上(vscode如此), 另外不可见字符应该由调试器统一转化为可见形式的'\33'这样的形式