diff --git a/assets/translations/en_US.ts b/assets/translations/en_US.ts
index 523035be9..eecf57cf1 100644
--- a/assets/translations/en_US.ts
+++ b/assets/translations/en_US.ts
@@ -307,82 +307,47 @@
AskPageWidget
-
+
-
+
button
-
+
button
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
AttachInfoDialog
@@ -612,86 +577,91 @@
BinaryToolsManager
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
@@ -815,47 +785,47 @@
BreakpointModel
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -901,83 +871,83 @@
BuildManager
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -1015,11 +985,14 @@ storage: %2
CMakeBuilderGenerator
-
+
-
+
@@ -1048,7 +1021,7 @@ storage: %2
CmakeProjectGenerator
-
+
@@ -1058,47 +1031,47 @@ storage: %2
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -1157,52 +1130,52 @@ storage: %2
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -1312,9 +1285,9 @@ storage: %2
CodePortingManager
-
-
-
+
+
+
@@ -1322,7 +1295,7 @@ storage: %2
CodePortingPlugin
-
+
@@ -1555,27 +1528,77 @@ storage: %2
Controller
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -1629,39 +1652,39 @@ storage: %2
DAPDebugger
-
-
-
+
+
+
-
+
-
+
-
+
-
+
-
-
+
+
@@ -1681,128 +1704,128 @@ The debugee has Terminated.
-
-
+
+
-
+
name
-
+
meaning
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -2042,16 +2065,6 @@ Delete anyway?
-
-
-
-
-
-
-
-
-
-
DetailsButton
@@ -2149,28 +2162,20 @@ Delete anyway?
-
- EditorUtils
-
-
-
-
-
-
EnvironmentView
-
+
-
+
-
+
@@ -2178,23 +2183,22 @@ Delete anyway?
EnvironmentWidget
-
-
+
-
+
-
+
-
+
@@ -2202,105 +2206,100 @@ Delete anyway?
FileTreeView
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
+
-
+
-
+
-
+
@@ -2308,12 +2307,12 @@ Delete anyway?
FindPlugin
-
+
-
+
@@ -2321,48 +2320,38 @@ Delete anyway?
FindToolBar
-
+
-
-
+
+
-
+
-
+
-
-
-
-
+
-
-
-
-
-
-
-
-
+
-
+
@@ -2562,52 +2551,47 @@ need to manually copy the source code to this path
GitMenuManager
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
GitTabWidget
@@ -2737,6 +2721,34 @@ need to manually copy the source code to this path
+
+ InputEditWidget
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
InstantBlameWidget
@@ -2996,46 +3008,51 @@ need to manually copy the source code to this path
LanguageClientHandlerPrivate
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
LocatorManager
-
-
+
+
-
-
+
+
@@ -3149,7 +3166,7 @@ repos path: %0
MainWindow
-
+
@@ -3243,13 +3260,36 @@ repos path: %0
-
-
+
+
+
+
+
+
+
+
+
+
+
+ NameValueModel
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
@@ -3314,17 +3354,17 @@ repos path: %0
OptionsDialog
-
+
-
+
-
+
@@ -3389,7 +3429,7 @@ repos path: %0
PluginManagerModule
-
+
@@ -3864,6 +3904,11 @@ repos path: %0
+
+
+
+
+
QDialog
@@ -3941,25 +3986,20 @@ not exists support files: %0
-
+
-
+
-
+
-
-
-
-
-
@@ -4203,32 +4243,17 @@ not exists support files: %0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -4380,7 +4405,7 @@ not exists support files: %0
-
+
@@ -4554,17 +4579,17 @@ not exists support files: %0
ReverseDebugPlugin
-
+
-
+
-
+
@@ -4916,52 +4941,52 @@ not exists support files: %0
Runner
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -5489,72 +5514,122 @@ not exists support files: %0
- ShortCut
+ ShortcutDialog
-
-
+
+
-
-
+
+
-
-
+
+
+ button
-
-
+
+
+ button
-
-
+
+
-
-
- ShortCutEdit
-
-
+
+
ShortcutSettingWidget
-
-
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -5683,16 +5758,6 @@ not exists support files: %0
SvnClientWidget
-
-
-
-
-
-
-
-
-
-
@@ -5802,7 +5867,7 @@ not exists support files: %0
TabWidgetPrivate
-
+
@@ -5818,17 +5883,17 @@ not exists support files: %0
TextEditor
-
+
-
+
-
+
button
@@ -5837,75 +5902,80 @@ not exists support files: %0
TextEditorPrivate
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
ToolOptionWidget
@@ -6003,12 +6073,12 @@ not exists support files: %0
ValgrindRunner
-
+
-
+
@@ -6034,96 +6104,545 @@ not exists support files: %0
WorkspaceWidgetPrivate
-
+
-
-
+
+
+
+
+
+
+
-
-
+
+
-
-
-
+
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
button
-
+
button
-
+
button
-
+
button
-
-
+
+
button
-
+
-
+
-
+
button
-
+
button
-
+
button
diff --git a/assets/translations/zh_CN.ts b/assets/translations/zh_CN.ts
index 40f8339da..06b43682f 100644
--- a/assets/translations/zh_CN.ts
+++ b/assets/translations/zh_CN.ts
@@ -307,82 +307,47 @@
AskPageWidget
-
+
该操作将删除该会话的全部内容,确定删除吗?
-
+
button
取消
-
+
button
删除
-
+
终止生成
-
+
删除该会话
-
-
- 引用文件
-
-
-
-
- 联网
-
-
-
+
历史会话
-
+
创建新会话
-
+
在这里提问,按Enter键发送...
-
-
-
- 当前文件
-
-
-
-
- 已打开文件
-
-
-
-
- 选择文件
-
-
-
-
- 清空
-
-
-
-
- 选择文件
-
AttachInfoDialog
@@ -612,94 +577,99 @@
BinaryToolsManager
-
+
默认分组
-
+
开始执行工具 “%1”。
-
+
这个工具正在运行。请将其停止后再运行。
-
+
工具 (%1) 执行程序不存在,请安装并重试
-
+
确定
-
+
配置...
-
+
+
+ 二进制工具
+
+
+
工具 "%1" 正常退出。
-
+
工具 "%1" 以code %2 结束。
-
+
工具 "%1" 崩溃。
-
+
工具 "%1" 执行完成。
-
+
取消
-
+
安装
-
+
这个工具设置了工作目录,但是工具目录解析为空。请检测后重试。
-
+
这个工具设置了管道数据,但是管道数据解析为空。请检测后重试。
-
-
+
+
应用程序输出(&A)
@@ -823,47 +793,47 @@
BreakpointModel
-
+
...
-
+
<More>
-
+
索引
-
+
状态
-
+
函数
-
+
文件
-
+
行
-
+
条件
-
+
地址
@@ -909,88 +879,88 @@
BuildManager
-
+
编译输出
-
+
问题列表
-
+
信息过滤
-
+
全部
-
+
错误
-
-
+
+
警告
-
+
清空输出
-
+
该工程没有关联的构建工具,请重新打开该工程并选择对应的构建工具.
-
+
编译(&B)
-
+
执行命令失败!
-
+
开始在工作区%3中执行%1 %2命令。
-
+
进程%1正常退出。
-
+
进程%1退出,代码为%2。
-
+
进程 %1崩溃。
-
+
命令执行完成。
@@ -1032,11 +1002,14 @@ storage: %2
CMakeBuilderGenerator
-
- %1项目的生成命令为空!请使用“sudo apt install cmake”在控制台中安装它,然后重新启动该工具。
+
+
-
+
"%1" 不存在!请检查并重新打开工程
@@ -1065,7 +1038,7 @@ storage: %2
CmakeProjectGenerator
-
+
执行CMake
@@ -1075,47 +1048,47 @@ storage: %2
清除CMake
-
+
项目%1中的文件已经更改,需要运行 cmake 来更新
-
+
工程属性
-
+
文件不会自动添加到 Cmake 项目的 CmakeList.txt 文件中。将源文件的路径复制到剪贴板?
-
+
复制到剪贴板?
-
+
确定
-
+
工程属性
-
+
编译
-
+
运行
-
+
套件
@@ -1174,52 +1147,52 @@ storage: %2
前进
-
+
关闭当前编辑器
-
+
切换头文件/源文件
-
+
跟随光标下符号
-
+
切换断点
-
+
查找引用
-
+
重命名
-
+
当前文档
-
+
当前文档内容
-
+
后退
-
+
前进
@@ -1335,9 +1308,9 @@ storage: %2
CodePortingManager
-
-
-
+
+
+
代码迁移(&O)
@@ -1345,7 +1318,7 @@ storage: %2
CodePortingPlugin
-
+
代码迁移
@@ -1578,27 +1551,77 @@ storage: %2
Controller
-
+
打开文件
-
+
隐藏内容区
-
+
当前视图中的窗口
-
+
+
+ 文件(&F)
+
+
+
+
+ 编辑(&E)
+
+
+
+
+ 编译(&B)
+
+
+
+
+ 调试(&D)
+
+
+
+
+ 工具(&T)
+
+
+
+
+ 帮助(&H)
+
+
+
+
+ 打开文件
+
+
+
+
+ 打开工程
+
+
+
+
+ 报告Bug
+
+
+
+
+ 帮助文档
+
+
+
展开所有
-
+
折叠所有
@@ -1652,9 +1675,9 @@ storage: %2
DAPDebugger
-
-
-
+
+
+
@@ -1663,31 +1686,31 @@ The debugee has Terminated.
-
+
调试已退出。
-
+
输入条件表达式
-
+
条件
-
+
当断点到达,仅在表达式为真时触发
-
-
+
+
取消
@@ -1707,107 +1730,107 @@ The debugee has Terminated.
请求cxx dap端口失败,请重新尝试。
-
-
+
+
确认
-
+
name
-
+
meaning
-
+
<p>下位机停止,因为它收到了来自操作系统的信号。<p><table><tr><td>信号名: </td><td>%1</td></tr><tr><td>信号含义: </td><td>%2</td></tr></table>
-
+
信号已接收
-
+
新评估表达式
-
+
输入求值表达式
-
+
线程:
-
+
堆栈列表
-
+
添加新评估表达式
-
+
删除评估
-
+
名称
-
+
值
-
+
类型
-
+
断点列表
-
+
请先编译工程。
编译:Ctrl + B
-
+
正在加载依赖项,请等待
-
+
正在获取dap端口,请等待
-
+
请求调试端口...
-
+
@@ -1816,22 +1839,22 @@ dap端口未就绪,请重试。
-
+
调试开始
-
+
开始调试coredump文件:
-
+
coredump目标文件错误:
-
+
coredump文件错误:
@@ -2072,16 +2095,6 @@ Delete anyway?
找不到配套工具。
-
-
-
- 快速回答问题
-
-
-
-
- 在技术问题上提供更准确的回答
-
DetailsButton
@@ -2179,28 +2192,20 @@ Delete anyway?
编辑器
-
- EditorUtils
-
-
-
- 编辑(&E)
-
-
EnvironmentView
-
+
增加
-
+
减少
-
+
重置
@@ -2208,23 +2213,22 @@ Delete anyway?
EnvironmentWidget
-
-
+
启用所有环境
-
+
增加
-
+
减少
-
+
重置
@@ -2232,105 +2236,100 @@ Delete anyway?
FileTreeView
-
+
错误,无法移到废纸篓:
-
+
错误,无法删除:
-
+
新文件名
-
-
+
+
新建文件
-
-
+
+
-
+
打开
-
-
+
+
新建文件夹
-
+
删除操作不可逆转,是否删除?
-
+
删除警告
-
+
取消
-
+
确定
-
+
新文件名
-
+
创建新文件
-
+
新文件夹
-
+
无法创建文件或文件夹,请检查文件名是否已经存在!
-
-
- 非目录下无法在创建文件或文件夹
-
-
-
+
移到回收站
-
+
删除
-
+
重命名
-
+
恢复
@@ -2338,12 +2337,12 @@ Delete anyway?
FindPlugin
-
+
高级查找
-
+
高级搜索
@@ -2351,48 +2350,38 @@ Delete anyway?
FindToolBar
-
+
查找
-
-
+
+
替换
-
+
替换全部
-
+
替换并查找
-
-
-
-
+
查找/替换
-
-
-
-
- &查看
-
-
-
+
查找下一个
-
+
查找上一个
@@ -2593,52 +2582,47 @@ need to manually copy the source code to this path
GitMenuManager
-
-
+
+
Log of "%1"
-
-
+
+
Diff of "%1"
-
+
Blame of "%1"
-
+
当前文件
-
+
当前工程
-
+
-
+
-
+
-
-
-
-
-
GitTabWidget
@@ -2768,6 +2752,34 @@ need to manually copy the source code to this path
历史对话
+
+ InputEditWidget
+
+
+
+ 引用文件
+
+
+
+
+ 联网
+
+
+
+
+ 当前文件
+
+
+
+
+ 选择文件
+
+
+
+
+ 打开文件
+
+
InstantBlameWidget
@@ -3027,46 +3039,51 @@ need to manually copy the source code to this path
LanguageClientHandlerPrivate
-
+
重构
-
+
重命名
-
+
切换头文件/源文件
-
+
跟随光标下符号
-
+
查找引用
-
+
格式化选中部分
+
+
+
+
+
LocatorManager
-
-
- 键入命令
+
+
+
-
-
+
+
键入命令 %1
@@ -3182,7 +3199,7 @@ repos path: %0
MainWindow
-
+
隐藏驻留区
@@ -3276,14 +3293,37 @@ repos path: %0
编辑
-
-
- 联网搜索 --- %1.
+
+
+
-
-
- 引用
+
+
+
+
+
+
+ NameValueModel
+
+
+
+ 变量名
+
+
+
+
+ 值
+
+
+
+
+
+
+
+
+
+
@@ -3347,17 +3387,17 @@ repos path: %0
OptionsDialog
-
+
全局选项
-
+
应用
-
+
取消
@@ -3422,7 +3462,7 @@ repos path: %0
PluginManagerModule
-
+
扩展
@@ -3897,6 +3937,11 @@ repos path: %0
用户行为分析
+
+
+
+ 选择文件
+
QDialog
@@ -3976,25 +4021,20 @@ not exists support files: %0
编译配置:
-
+
代码补全:
-
+
全局语言偏好:
-
+
Commits语言偏好:
-
-
-
- 模型
-
@@ -4238,32 +4278,17 @@ not exists support files: %0
CMake 配置
-
-
-
-
- 变量名
-
-
-
-
-
值
-
-
-
- 环境
-
用户界面
-
+
命令
@@ -4415,7 +4440,7 @@ not exists support files: %0
符号
-
+
查找结果(&R)
@@ -4589,17 +4614,17 @@ not exists support files: %0
ReverseDebugPlugin
-
+
反向调试
-
+
记录
-
+
重放
@@ -4951,57 +4976,57 @@ not exists support files: %0
Runner
-
+
警告
-
+
该工程没有关联的构建工具,请重新打开该工程并选择对应的构建工具.
-
+
应用程序输出(&A)
-
+
错误:执行命令错误!原因未知。
-
+
开始在工作区%3中执行%1 %2命令。
-
+
进程%1正常退出。
-
+
进程%1退出,代码为%2。
-
+
进程 %1崩溃。
-
+
命令执行完成。
@@ -5530,73 +5555,123 @@ not exists support files: %0
- ShortCut
+ ShortcutDialog
-
-
- 快捷键不合法
+
+
+
-
-
- 快捷键不合法,请重新输入!
+
+
+
-
-
- 快捷键重复
+
+
+ button
+ 取消
-
-
- 快捷键重复,请重新输入!
+
+
+ button
+
-
-
- 确定
+
+
+
-
-
- ShortCutEdit
-
-
- 清除
+
+
+
ShortcutSettingWidget
-
-
- 重置所有
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
导入
-
-
- 导出
+
+
+
-
-
- 打开文件
+
+
+
-
-
-
- Json 文件(*.json)
+
+
+
-
-
- 保存文件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 导出
@@ -5724,16 +5799,6 @@ not exists support files: %0
SvnClientWidget
-
-
-
- 检出仓库
-
-
-
-
- 打开仓库
-
@@ -5843,7 +5908,7 @@ not exists support files: %0
TabWidgetPrivate
-
+
文件操作
@@ -5859,17 +5924,17 @@ not exists support files: %0
TextEditor
-
+
保存文件
-
+
文件“%1”没有写权限。请添加写权限并重试
-
+
button
确定
@@ -5878,75 +5943,80 @@ not exists support files: %0
TextEditorPrivate
-
+
重构
-
+
撤销
-
+
恢复
-
+
剪切
-
+
复制
-
+
粘贴
-
+
删除
-
+
选择全部
-
+
移除断点
-
+
禁用断点
-
+
启用断点
-
+
添加条件
-
+
在第 %1 行添加断点
-
+
跳转到 %1 行
+
+
+
+
+
ToolOptionWidget
@@ -6044,12 +6114,12 @@ not exists support files: %0
ValgrindRunner
-
+
请从终端安装“valgrind”工具:$sudo apt install valgrind.
-
+
应用程序输出(&A)
@@ -6075,96 +6145,545 @@ not exists support files: %0
WorkspaceWidgetPrivate
-
+
添加/删除注释
-
-
- 添加/删除注释
+
+
+ 显示打开的文件
+
+
+
+
+
-
-
- &添加/删除注释
+
+
+
-
-
-
- 显示打开的文件
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
- &显示打开的文件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 粘贴
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 放大
+
+
+
+
+ 缩小
+
+
+
%1 被修改,是否重新加载?
-
+
文件发生修改
-
+
button
确定
-
+
button
应用所有
-
+
button
取消
-
+
button
取消所有
-
-
+
+
button
关闭
-
+
%1 被移除,是否需要另存为,或者关闭当前编辑页?
-
+
文件被移除
-
+
button
保存
-
+
button
另存为
-
+
button
关闭所有
diff --git a/debian/control b/debian/control
index 3dd7d3b42..a84e0d128 100644
--- a/debian/control
+++ b/debian/control
@@ -38,7 +38,8 @@ Build-Depends:
libdtkcore-dev,
libdtkcore5-bin,
libkf5syntaxhighlighting-dev,
- libyaml-cpp-dev
+ libyaml-cpp-dev,
+ libcmark-dev
Standards-version: 3.9.8
Homepage: http://www.deepin.org
diff --git a/src/common/lsp/client/client.cpp b/src/common/lsp/client/client.cpp
index cbeb93dfa..27268dca7 100644
--- a/src/common/lsp/client/client.cpp
+++ b/src/common/lsp/client/client.cpp
@@ -1115,7 +1115,7 @@ bool ClientPrivate::diagnosticsCalled(const QJsonObject &jsonObj)
newlsp::Location {
newlsp::DocumentUri { reInfoLocationUrl },
newlsp::Range {
- { reInfoLocationRangeObj.value(lsp::K_LINE).toInt(), reInfoLocationRangeObj.value(lsp::K_CHARACTER).toInt() },
+ { reInfoLocationStartObj.value(lsp::K_LINE).toInt(), reInfoLocationStartObj.value(lsp::K_CHARACTER).toInt() },
{ reInfoLocationEndObj.value(lsp::K_LINE).toInt(), reInfoLocationEndObj.value(lsp::K_CHARACTER).toInt() } } },
std::string {
reInfoMessage }
diff --git a/src/common/lsp/protocol/protocol.cpp b/src/common/lsp/protocol/protocol.cpp
index 65e847810..cd2d60783 100644
--- a/src/common/lsp/protocol/protocol.cpp
+++ b/src/common/lsp/protocol/protocol.cpp
@@ -240,6 +240,7 @@ QJsonObject initialize(const QString &workspaceFolder, const QString &language,
{ "declaration", QJsonObject { { "dynamicRegistration", true }, { "linkSupport", true } } },
{ "semanticHighlightingCapabilities", QJsonObject { { "semanticHighlighting", true } } },
{ "semanticTokens", capabilitiesSemanticTokens },
+ { "hover", QJsonObject { { "contentFormat", QJsonArray { "markdown", "plaintext" } } } },
{ "completion", QJsonObject { { "editsNearCursor", true } } } } },
{ "workspace", workspace() },
{
diff --git a/src/common/tooltip/tips.cpp b/src/common/tooltip/tips.cpp
new file mode 100644
index 000000000..5427f7269
--- /dev/null
+++ b/src/common/tooltip/tips.cpp
@@ -0,0 +1,149 @@
+// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "tips.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+TipLabel::TipLabel(QWidget *parent)
+ : QLabel(parent, Qt::ToolTip | Qt::BypassGraphicsProxyWidget)
+{
+}
+
+TextTip::TextTip(QWidget *parent)
+ : TipLabel(parent)
+{
+ setAutoFillBackground(true);
+ setForegroundRole(QPalette::BrightText);
+ setBackgroundRole(QPalette::Base);
+ ensurePolished();
+ setMargin(1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, nullptr, this));
+ setFrameStyle(QFrame::NoFrame);
+ setAlignment(Qt::AlignLeft);
+ setIndent(1);
+ setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, nullptr, this) / 255.0);
+}
+
+void TextTip::setContent(const QVariant &content)
+{
+ tipText = content.toString();
+ setOpenExternalLinks(likelyContainsLink());
+}
+
+bool TextTip::isInteractive() const
+{
+ return likelyContainsLink();
+}
+
+void TextTip::configure(const QPoint &pos)
+{
+ setText(tipText);
+
+ QFontMetrics fm(font());
+ int extraHeight = 0;
+ if (fm.descent() == 2 && fm.ascent() >= 11)
+ ++extraHeight;
+
+ setWordWrap(false);
+ int tipWidth = sizeHint().width();
+
+ QScreen *screen = QGuiApplication::screenAt(pos);
+ if (!screen)
+ screen = QGuiApplication::primaryScreen();
+
+ const int screenWidth = screen->availableGeometry().width();
+ const int maxDesiredWidth = int(screenWidth * .5);
+ if (tipWidth > maxDesiredWidth) {
+ setWordWrap(true);
+ tipWidth = maxDesiredWidth;
+ }
+
+ resize(tipWidth, heightForWidth(tipWidth) + extraHeight);
+}
+
+bool TextTip::canHandleContentReplacement(ContentType type) const
+{
+ return type == TextContent;
+}
+
+int TextTip::showTime() const
+{
+ return 100000 + 40 * qMax(0, tipText.size() - 100);
+}
+
+bool TextTip::equals(ContentType type, const QVariant &other) const
+{
+ return type == TextContent && other.canConvert() && other.toString() == tipText;
+}
+
+void TextTip::paintEvent(QPaintEvent *event)
+{
+ QStylePainter p(this);
+ QStyleOptionFrame opt;
+ opt.initFrom(this);
+ p.drawPrimitive(QStyle::PE_PanelTipLabel, opt);
+ p.end();
+
+ QLabel::paintEvent(event);
+}
+
+void TextTip::resizeEvent(QResizeEvent *event)
+{
+ QStyleHintReturnMask frameMask;
+ QStyleOption option;
+ option.initFrom(this);
+ if (style()->styleHint(QStyle::SH_ToolTip_Mask, &option, this, &frameMask))
+ setMask(frameMask.region);
+
+ QLabel::resizeEvent(event);
+}
+
+bool TextTip::likelyContainsLink() const
+{
+ if (tipText.contains("href"), Qt::CaseInsensitive)
+ return true;
+
+ return false;
+}
+
+WidgetTip::WidgetTip(QWidget *parent)
+ : TipLabel(parent)
+{
+ layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ setLayout(layout);
+}
+
+void WidgetTip::setContent(const QVariant &content)
+{
+ widget = content.value();
+}
+
+void WidgetTip::configure(const QPoint &pos)
+{
+ if (!widget || layout->count() != 0)
+ return;
+
+ move(pos);
+ layout->addWidget(widget);
+ layout->setSizeConstraint(QLayout::SetFixedSize);
+ adjustSize();
+}
+
+bool WidgetTip::canHandleContentReplacement(ContentType type) const
+{
+ Q_UNUSED(type)
+ return false;
+}
+
+bool WidgetTip::equals(ContentType type, const QVariant &other) const
+{
+ return type == WidgetContent && other.value() == widget;
+}
diff --git a/src/common/tooltip/tips.h b/src/common/tooltip/tips.h
new file mode 100644
index 000000000..e1b560b25
--- /dev/null
+++ b/src/common/tooltip/tips.h
@@ -0,0 +1,71 @@
+// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef TIPS_H
+#define TIPS_H
+
+#include
+#include
+
+QT_BEGIN_NAMESPACE
+class QVBoxLayout;
+QT_END_NAMESPACE
+
+class TipLabel : public QLabel
+{
+public:
+ enum ContentType {
+ TextContent = 0,
+ WidgetContent
+ };
+
+ explicit TipLabel(QWidget *parent = nullptr);
+
+ virtual void setContent(const QVariant &content) = 0;
+ virtual bool isInteractive() const { return false; }
+ virtual int showTime() const = 0;
+ virtual void configure(const QPoint &pos) = 0;
+ virtual bool canHandleContentReplacement(ContentType type) const = 0;
+ virtual bool equals(ContentType type, const QVariant &other) const = 0;
+};
+
+class TextTip : public TipLabel
+{
+public:
+ explicit TextTip(QWidget *parent = nullptr);
+
+ void setContent(const QVariant &content) override;
+ bool isInteractive() const override;
+ void configure(const QPoint &pos) override;
+ bool canHandleContentReplacement(ContentType type) const override;
+ int showTime() const override;
+ bool equals(ContentType type, const QVariant &other) const override;
+ void paintEvent(QPaintEvent *event) override;
+ void resizeEvent(QResizeEvent *event) override;
+
+private:
+ bool likelyContainsLink() const;
+
+ QString tipText;
+};
+
+class WidgetTip : public TipLabel
+{
+ Q_OBJECT
+public:
+ explicit WidgetTip(QWidget *parent = nullptr);
+
+ void setContent(const QVariant &content) override;
+ void configure(const QPoint &pos) override;
+ bool canHandleContentReplacement(ContentType type) const override;
+ int showTime() const override { return 30000; }
+ bool equals(ContentType type, const QVariant &other) const override;
+ bool isInteractive() const override { return true; }
+
+private:
+ QWidget *widget { nullptr };
+ QVBoxLayout *layout { nullptr };
+};
+
+#endif // TIPS_H
diff --git a/src/common/tooltip/tooltip.cpp b/src/common/tooltip/tooltip.cpp
new file mode 100644
index 000000000..230896c4a
--- /dev/null
+++ b/src/common/tooltip/tooltip.cpp
@@ -0,0 +1,286 @@
+// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "tooltip.h"
+#include "tips.h"
+
+#include
+#include
+#include
+#include
+#include
+
+class ToolTipPrivate : public QObject
+{
+public:
+ explicit ToolTipPrivate(ToolTip *qq);
+ ~ToolTipPrivate();
+
+ void showTip(const QPoint &pos, const QVariant &content, TipLabel::ContentType type, QWidget *w, const QRect &rect);
+ void hideTip();
+ void delayHideTip();
+ bool acceptShow(const QVariant &content, TipLabel::ContentType type, const QPoint &pos, QWidget *w, const QRect &rect);
+ void setUp(const QPoint &pos, QWidget *w, const QRect &rect);
+ bool tipChanged(const QPoint &pos, TipLabel::ContentType type, const QVariant &content, QWidget *w) const;
+ void setTipRect(QWidget *w, const QRect &rect);
+ void placeTip(const QPoint &pos);
+
+public:
+ ToolTip *q;
+
+ TipLabel *tipLabel { nullptr };
+ QWidget *widget { nullptr };
+ QRect rect;
+ QTimer showTimer;
+ QTimer hideDelayTimer;
+};
+
+ToolTipPrivate::ToolTipPrivate(ToolTip *qq)
+ : q(qq)
+{
+ connect(&showTimer, &QTimer::timeout, this, &ToolTipPrivate::hideTip);
+ connect(&hideDelayTimer, &QTimer::timeout, this, &ToolTipPrivate::hideTip);
+}
+
+ToolTipPrivate::~ToolTipPrivate()
+{
+ tipLabel = nullptr;
+}
+
+void ToolTipPrivate::showTip(const QPoint &pos, const QVariant &content, TipLabel::ContentType type, QWidget *w, const QRect &rect)
+{
+ if (acceptShow(content, type, pos, w, rect)) {
+ switch (type) {
+ case TipLabel::TextContent:
+ tipLabel = new TextTip(w);
+ break;
+ case TipLabel::WidgetContent:
+ tipLabel = new WidgetTip(w);
+ break;
+ }
+
+ tipLabel->setObjectName("ToolTip");
+ tipLabel->setContent(content);
+ setUp(pos, w, rect);
+ qApp->installEventFilter(q);
+ tipLabel->show();
+ }
+}
+
+void ToolTipPrivate::hideTip()
+{
+ if (tipLabel) {
+ tipLabel->close();
+ tipLabel->deleteLater();
+ tipLabel = nullptr;
+ }
+
+ showTimer.stop();
+ hideDelayTimer.stop();
+ qApp->removeEventFilter(q);
+ Q_EMIT q->hidden();
+}
+
+void ToolTipPrivate::delayHideTip()
+{
+ if (!hideDelayTimer.isActive())
+ hideDelayTimer.start(300);
+}
+
+bool ToolTipPrivate::acceptShow(const QVariant &content, TipLabel::ContentType type, const QPoint &pos, QWidget *w, const QRect &rect)
+{
+ if (q->isVisible()) {
+ if (tipLabel->canHandleContentReplacement(type)) {
+ QPoint localPos = pos;
+ if (w)
+ localPos = w->mapFromGlobal(pos);
+ if (tipChanged(localPos, type, content, w)) {
+ tipLabel->setContent(content);
+ setUp(pos, w, rect);
+ }
+ return false;
+ }
+ hideTip();
+ }
+
+ return true;
+}
+
+void ToolTipPrivate::setUp(const QPoint &pos, QWidget *w, const QRect &rect)
+{
+ tipLabel->configure(pos);
+
+ placeTip(pos);
+ setTipRect(w, rect);
+
+ if (hideDelayTimer.isActive())
+ hideDelayTimer.stop();
+ showTimer.start(tipLabel->showTime());
+}
+
+bool ToolTipPrivate::tipChanged(const QPoint &pos, TipLabel::ContentType type, const QVariant &content, QWidget *w) const
+{
+ if (!tipLabel->equals(type, content) || widget != w)
+ return true;
+ if (!rect.isNull())
+ return !rect.contains(pos);
+ return false;
+}
+
+void ToolTipPrivate::setTipRect(QWidget *w, const QRect &rect)
+{
+ if (!this->rect.isNull() && !w) {
+ qWarning("ToolTip::show: Cannot pass null widget if rect is set");
+ } else {
+ widget = w;
+ this->rect = rect;
+ }
+}
+
+void ToolTipPrivate::placeTip(const QPoint &pos)
+{
+ QScreen *qscreen = QGuiApplication::screenAt(pos);
+ if (!qscreen)
+ qscreen = QGuiApplication::primaryScreen();
+
+ const QRect screen = qscreen->availableGeometry();
+ QPoint p = pos;
+ p += { 2, 16 };
+ if (p.x() + tipLabel->width() > screen.x() + screen.width())
+ p.rx() -= 4 + tipLabel->width();
+ if (p.y() + tipLabel->height() > screen.y() + screen.height())
+ p.ry() -= 24 + tipLabel->height();
+ if (p.y() < screen.y())
+ p.setY(screen.y());
+ if (p.x() + tipLabel->width() > screen.x() + screen.width())
+ p.setX(screen.x() + screen.width() - tipLabel->width());
+ if (p.x() < screen.x())
+ p.setX(screen.x());
+ if (p.y() + tipLabel->height() > screen.y() + screen.height())
+ p.setY(screen.y() + screen.height() - tipLabel->height());
+
+ tipLabel->move(p);
+}
+
+ToolTip::ToolTip()
+ : d(new ToolTipPrivate(this))
+{
+}
+
+ToolTip::~ToolTip()
+{
+ delete d;
+}
+
+ToolTip *ToolTip::instance()
+{
+ static ToolTip ins;
+ return &ins;
+}
+
+void ToolTip::show(const QPoint &pos, const QString &content, QWidget *w, const QRect &rect)
+{
+ if (content.isEmpty())
+ hide();
+ else
+ instance()->d->showTip(pos, content, TipLabel::TextContent, w, rect);
+}
+
+void ToolTip::show(const QPoint &pos, QWidget *content, QWidget *w, const QRect &rect)
+{
+ if (!content)
+ hide();
+ else
+ instance()->d->showTip(pos, QVariant::fromValue(content), TipLabel::WidgetContent, w, rect);
+}
+
+void ToolTip::show(const QPoint &pos, QLayout *content, QWidget *w, const QRect &rect)
+{
+ if (content && content->count()) {
+ auto tooltipWidget = new QWidget;
+ QScreen *qscreen = QGuiApplication::screenAt(pos);
+ if (!qscreen)
+ qscreen = QGuiApplication::primaryScreen();
+ tooltipWidget->setMaximumSize(qscreen->availableSize() * 0.9);
+ tooltipWidget->setLayout(content);
+ instance()->d->showTip(pos, QVariant::fromValue(tooltipWidget), TipLabel::WidgetContent, w, rect);
+ } else {
+ hide();
+ }
+}
+
+void ToolTip::hide()
+{
+ instance()->d->delayHideTip();
+}
+
+void ToolTip::hideImmediately()
+{
+ instance()->d->hideTip();
+}
+
+bool ToolTip::isVisible()
+{
+ ToolTipPrivate *p = instance()->d;
+ return p->tipLabel && p->tipLabel->isVisible();
+}
+
+bool ToolTip::eventFilter(QObject *obj, QEvent *event)
+{
+ if (d->tipLabel && event->type() == QEvent::ApplicationStateChange
+ && QGuiApplication::applicationState() != Qt::ApplicationActive) {
+ d->hideTip();
+ }
+
+ if (!obj->isWidgetType())
+ return false;
+
+ switch (event->type()) {
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease: {
+ int key = static_cast(event)->key();
+ if (key == Qt::Key_Escape)
+ d->hideTip();
+ break;
+ }
+ case QEvent::Leave:
+ if (obj == d->tipLabel && !d->tipLabel->isAncestorOf(QApplication::focusWidget()))
+ d->delayHideTip();
+ break;
+ case QEvent::Enter:
+ if (d->tipLabel && d->tipLabel->isInteractive() && obj == d->tipLabel) {
+ if (d->hideDelayTimer.isActive())
+ d->hideDelayTimer.stop();
+ }
+ break;
+ case QEvent::WindowActivate:
+ case QEvent::WindowDeactivate:
+ case QEvent::FocusOut:
+ case QEvent::FocusIn:
+ if (d->tipLabel && !d->tipLabel->isInteractive())
+ d->hideTip();
+ break;
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::Wheel:
+ if (d->tipLabel) {
+ if (d->tipLabel->isInteractive()) {
+ if (obj != d->tipLabel && !d->tipLabel->isAncestorOf(static_cast(obj)))
+ d->hideTip();
+ } else {
+ d->hideTip();
+ }
+ }
+ break;
+ case QEvent::MouseMove:
+ if (obj == d->widget && !d->rect.isNull() && !d->rect.contains(static_cast(event)->pos())) {
+ d->delayHideTip();
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+}
diff --git a/src/common/tooltip/tooltip.h b/src/common/tooltip/tooltip.h
new file mode 100644
index 000000000..6b8bb7a4f
--- /dev/null
+++ b/src/common/tooltip/tooltip.h
@@ -0,0 +1,43 @@
+// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef TOOLTIP_H
+#define TOOLTIP_H
+
+#include
+#include
+
+QT_BEGIN_NAMESPACE
+class QLayout;
+class QWidget;
+QT_END_NAMESPACE
+
+class ToolTipPrivate;
+class ToolTip : public QObject
+{
+ Q_OBJECT
+public:
+ static ToolTip *instance();
+
+ static void show(const QPoint &pos, const QString &content, QWidget *w = nullptr, const QRect &rect = QRect());
+ static void show(const QPoint &pos, QWidget *content, QWidget *w = nullptr, const QRect &rect = QRect());
+ static void show(const QPoint &pos, QLayout *content, QWidget *w = nullptr, const QRect &rect = QRect());
+ static void hide();
+ static void hideImmediately();
+ static bool isVisible();
+
+Q_SIGNALS:
+ void hidden();
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *event) override;
+
+private:
+ ToolTip();
+ ~ToolTip();
+
+ ToolTipPrivate *const d;
+};
+
+#endif // TOOLTIP_H
diff --git a/src/plugins/codeeditor/CMakeLists.txt b/src/plugins/codeeditor/CMakeLists.txt
index da61fcd8d..17a2caa72 100644
--- a/src/plugins/codeeditor/CMakeLists.txt
+++ b/src/plugins/codeeditor/CMakeLists.txt
@@ -7,6 +7,9 @@ set(CMAKE_INCLUDE_CURRENT_DIR true)
add_definitions(-DLIBRARY_INSTALL_PREFIX="${LIBRARY_INSTALL_PREFIX}")
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(CMARK REQUIRED libcmark)
+
FILE(GLOB_RECURSE PROJECT_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/*.h"
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
@@ -25,6 +28,11 @@ add_library(${PROJECT_NAME}
${QRC_FILES}
)
+target_include_directories(${PROJECT_NAME}
+ PUBLIC
+ ${CMARK_INCLUDE_DIRS}
+)
+
target_link_libraries(${PROJECT_NAME}
framework
base
@@ -33,6 +41,7 @@ target_link_libraries(${PROJECT_NAME}
${QtUseModules}
${PkgUserModules}
${DtkWidget_LIBRARIES}
+ ${CMARK_LIBRARIES}
)
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${PLUGIN_INSTALL_PATH})
diff --git a/src/plugins/codeeditor/codeeditor.cpp b/src/plugins/codeeditor/codeeditor.cpp
index 598abcc63..8f23e6ac5 100644
--- a/src/plugins/codeeditor/codeeditor.cpp
+++ b/src/plugins/codeeditor/codeeditor.cpp
@@ -187,6 +187,8 @@ void CodeEditor::initEditorService()
editorService->showLineWidget = std::bind(&WorkspaceWidget::showLineWidget, workspaceWidget, _1, _2);
editorService->closeLineWidget = std::bind(&WorkspaceWidget::closeLineWidget, workspaceWidget);
editorService->cursorPosition = std::bind(&WorkspaceWidget::cursorPosition, workspaceWidget, _1, _2);
+ editorService->registerDiagnosticRepairTool = std::bind(&WorkspaceWidget::registerDiagnosticRepairTool, workspaceWidget, _1, _2);
+ editorService->getDiagnosticRepairTool = std::bind(&WorkspaceWidget::getDiagnosticRepairTool, workspaceWidget);
LexerManager::instance()->init(editorService);
}
diff --git a/src/plugins/codeeditor/gui/private/texteditor_p.cpp b/src/plugins/codeeditor/gui/private/texteditor_p.cpp
index b83c927a2..dbae6e452 100644
--- a/src/plugins/codeeditor/gui/private/texteditor_p.cpp
+++ b/src/plugins/codeeditor/gui/private/texteditor_p.cpp
@@ -17,7 +17,6 @@
#include
-#include
#include
#include
#include
@@ -119,7 +118,6 @@ void TextEditorPrivate::updateColorTheme()
q->markerDefine(rtIcon.pixmap(14, 14), Runtime);
q->setColor(q->palette().color(QPalette::WindowText));
- auto palette = QToolTip::palette();
if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::DarkType) {
// editor
q->setPaper(QColor("#2e2f30"));
@@ -138,9 +136,6 @@ void TextEditorPrivate::updateColorTheme()
rlbColor.setAlpha(qRound(255 * 0.1));
q->setMarkerForegroundColor(rlbColor, RuntimeLineBackground);
q->setMarkerBackgroundColor(rlbColor, RuntimeLineBackground);
-
- // tooltip
- palette.setColor(QPalette::Inactive, QPalette::ToolTipText, Qt::lightGray);
} else {
// editor
q->setPaper(QColor("#F8F8F8"));
@@ -159,12 +154,7 @@ void TextEditorPrivate::updateColorTheme()
rlbColor.setAlpha(qRound(255 * 0.1));
q->setMarkerForegroundColor(rlbColor, RuntimeLineBackground);
q->setMarkerBackgroundColor(rlbColor, RuntimeLineBackground);
-
- // tooltip
- palette.setColor(QPalette::Inactive, QPalette::ToolTipText, Qt::black);
}
-
- QToolTip::setPalette(palette);
}
void TextEditorPrivate::updateSettings()
diff --git a/src/plugins/codeeditor/gui/private/workspacewidget_p.h b/src/plugins/codeeditor/gui/private/workspacewidget_p.h
index e85c9e881..e5bff9f66 100644
--- a/src/plugins/codeeditor/gui/private/workspacewidget_p.h
+++ b/src/plugins/codeeditor/gui/private/workspacewidget_p.h
@@ -72,6 +72,7 @@ public slots:
QList tabWidgetList;
QStackedWidget *stackWidget { nullptr };
QMap registeredWidget;
+ QMap repairToolInfo;
QStringList autoReloadList;
QStringList modifiedFileList;
diff --git a/src/plugins/codeeditor/gui/texteditor.cpp b/src/plugins/codeeditor/gui/texteditor.cpp
index 6f15ccc71..1ae700596 100644
--- a/src/plugins/codeeditor/gui/texteditor.cpp
+++ b/src/plugins/codeeditor/gui/texteditor.cpp
@@ -6,6 +6,7 @@
#include "private/texteditor_p.h"
#include "utils/editorutils.h"
#include "common/common.h"
+#include "common/tooltip/tooltip.h"
#include "settings/settingsdefine.h"
#include "Qsci/qscidocument.h"
@@ -13,7 +14,6 @@
#include
#include
-#include
#include
#include
#include
@@ -377,12 +377,25 @@ void TextEditor::showTips(int pos, const QString &tips)
return;
auto point = pointFromPosition(pos);
- QToolTip::showText(mapToGlobal(point), tips, this);
+ ToolTip::show(mapToGlobal(point), tips, this);
+}
+
+void TextEditor::showTips(int pos, QWidget *w)
+{
+ if (!hasFocus() || !d->tipsDisplayable)
+ return;
+
+ bool isCtrlPressed = qApp->queryKeyboardModifiers().testFlag(Qt::ControlModifier);
+ if (isCtrlPressed)
+ return;
+
+ auto point = pointFromPosition(pos);
+ ToolTip::show(mapToGlobal(point), w, this);
}
void TextEditor::cancelTips()
{
- QToolTip::hideText();
+ ToolTip::hideImmediately();
}
void TextEditor::addAnnotation(const QString &title, const QString &content, int line, int type)
diff --git a/src/plugins/codeeditor/gui/texteditor.h b/src/plugins/codeeditor/gui/texteditor.h
index 1cd3cbb50..b08da34fe 100644
--- a/src/plugins/codeeditor/gui/texteditor.h
+++ b/src/plugins/codeeditor/gui/texteditor.h
@@ -71,6 +71,7 @@ class TextEditor : public QsciScintilla
void clearAllBackgroundColor(int marker);
void showTips(const QString &tips);
void showTips(int pos, const QString &tips);
+ void showTips(int pos, QWidget *w);
void cancelTips();
void addAnnotation(const QString &title, const QString &content, int line, int type);
void addAnnotation(const QString &content, int line, int type);
diff --git a/src/plugins/codeeditor/gui/workspacewidget.cpp b/src/plugins/codeeditor/gui/workspacewidget.cpp
index 29136488d..1686a1d26 100644
--- a/src/plugins/codeeditor/gui/workspacewidget.cpp
+++ b/src/plugins/codeeditor/gui/workspacewidget.cpp
@@ -1231,6 +1231,19 @@ void WorkspaceWidget::closeLineWidget()
tabWidget->closeLineWidget();
}
+void WorkspaceWidget::registerDiagnosticRepairTool(const QString &toolName, RepairCallback callback)
+{
+ if (d->repairToolInfo.contains(toolName) || !callback)
+ return;
+
+ d->repairToolInfo.insert(toolName, callback);
+}
+
+QMap WorkspaceWidget::getDiagnosticRepairTool() const
+{
+ return d->repairToolInfo;
+}
+
bool WorkspaceWidget::event(QEvent *event)
{
if (event->type() == QEvent::WindowActivate)
diff --git a/src/plugins/codeeditor/gui/workspacewidget.h b/src/plugins/codeeditor/gui/workspacewidget.h
index f11ab2a30..518baf2b6 100644
--- a/src/plugins/codeeditor/gui/workspacewidget.h
+++ b/src/plugins/codeeditor/gui/workspacewidget.h
@@ -8,6 +8,8 @@
#include
#include
+#include
+
class TabWidget;
class AbstractEditWidget;
class WorkspaceWidgetPrivate;
@@ -50,6 +52,10 @@ class WorkspaceWidget : public QWidget
void showLineWidget(int line, QWidget *widget);
void closeLineWidget();
+ using RepairCallback = std::function;
+ void registerDiagnosticRepairTool(const QString &toolName, RepairCallback callback);
+ QMap getDiagnosticRepairTool() const;
+
protected:
bool event(QEvent *event) override;
diff --git a/src/plugins/codeeditor/lsp/languageclienthandler.cpp b/src/plugins/codeeditor/lsp/languageclienthandler.cpp
index adf0bed48..b70ea2326 100644
--- a/src/plugins/codeeditor/lsp/languageclienthandler.cpp
+++ b/src/plugins/codeeditor/lsp/languageclienthandler.cpp
@@ -13,15 +13,23 @@
#include "symbol/symbolmanager.h"
#include "services/project/projectservice.h"
+#include "services/editor/editorservice.h"
+#include "common/tooltip/tooltip.h"
#include "Qsci/qscilexer.h"
+#include
#include
+#include
+
#include
+#include
#include
+#include
DGUI_USE_NAMESPACE
+DWIDGET_USE_NAMESPACE
LanguageClientHandlerPrivate::LanguageClientHandlerPrivate(TextEditor *edit, LanguageClientHandler *qq)
: q(qq),
@@ -39,7 +47,6 @@ LanguageClientHandlerPrivate::~LanguageClientHandlerPrivate()
void LanguageClientHandlerPrivate::init()
{
- diagnosticFormat = "%1\n%2:%3";
textChangedTimer.setSingleShot(true);
textChangedTimer.setInterval(200);
@@ -71,6 +78,7 @@ void LanguageClientHandlerPrivate::initConnection()
connect(&textChangedTimer, &QTimer::timeout, this, &LanguageClientHandlerPrivate::delayTextChanged);
connect(&positionChangedTimer, &QTimer::timeout, this, &LanguageClientHandlerPrivate::delayPositionChanged);
connect(languageWorker, &LanguageWorker::highlightToken, this, &LanguageClientHandlerPrivate::handleHighlightToken);
+ connect(ToolTip::instance(), &ToolTip::hidden, this, [this] { hoverCache.clean(); });
}
void LanguageClientHandlerPrivate::initLspConnection()
@@ -138,20 +146,6 @@ void LanguageClientHandlerPrivate::initIndicStyle()
editor->indicatorDefine(TextEditor::TriangleCharacterIndicator, TextEditor::INDIC_POINTCHARACTER);
}
-QString LanguageClientHandlerPrivate::formatDiagnosticMessage(const QString &message, int type)
-{
- auto result = message;
- switch (type) {
- case AnnotationType::ErrorAnnotation:
- result = diagnosticFormat.arg("Parse Issue", "Error", result);
- break;
- default:
- break;
- }
-
- return result;
-}
-
bool LanguageClientHandlerPrivate::shouldStartCompletion(const QString &insertedText)
{
if (insertedText.isEmpty())
@@ -238,8 +232,18 @@ void LanguageClientHandlerPrivate::handleDiagnostics(const newlsp::PublishDiagno
editor->SendScintilla(TextEditor::SCI_INDICSETFORE, TextEditor::INDIC_SQUIGGLE, QColor(Qt::red));
editor->SendScintilla(TextEditor::SCI_INDICATORFILLRANGE, static_cast(startPos), endPos - startPos);
- std::string message = val.message.value();
- diagnosticCache.append({ startPos, endPos, message.c_str(), AnnotationType::ErrorAnnotation });
+ QString message = val.message.value().c_str();
+ if (val.relatedInformation.has_value()) {
+ message += "\n\n";
+ for (const auto &info : val.relatedInformation.value()) {
+ QString infoMsg("%1:%2:%3:\nnote:%4");
+ auto path = QUrl(info.location.uri.c_str()).path();
+ message += infoMsg.arg(path, QString::number(info.location.range.start.line + 1),
+ QString::number(info.location.range.start.character + 1),
+ info.message.c_str());
+ }
+ }
+ diagnosticCache.append({ startPos, endPos, message, AnnotationType::ErrorAnnotation });
}
}
}
@@ -279,6 +283,11 @@ void LanguageClientHandlerPrivate::handleShowHoverInfo(const newlsp::Hover &hove
} else if (newlsp::any_contrast(hover.contents)) {
auto markupContent = std::any_cast(hover.contents);
showText = markupContent.value;
+ if (markupContent.kind == newlsp::Enum::MarkupKind::get()->Markdown) {
+ char *output = cmark_markdown_to_html(showText.c_str(), showText.size(), CMARK_OPT_DEFAULT);
+ showText = output;
+ free(output);
+ }
} else if (newlsp::any_contrast(hover.contents)) {
auto markedString = std::any_cast(hover.contents);
if (!std::string(markedString).empty()) {
@@ -401,18 +410,6 @@ void LanguageClientHandlerPrivate::handleHoveredStart(int position)
if (!editor || !getClient())
return;
- if (!diagnosticCache.isEmpty()) {
- auto iter = std::find_if(diagnosticCache.begin(), diagnosticCache.end(),
- [position](const DiagnosticCache &cache) {
- return cache.contains(position);
- });
- if (iter != diagnosticCache.end()) {
- const auto &msg = formatDiagnosticMessage(iter->message, iter->type);
- editor->showTips(position, msg);
- return;
- }
- }
-
hoverCache.setPosition(position);
auto textRange = hoverCache.getTextRange();
if (!textRange.isEmpty() && textRange.contaions(position))
@@ -425,6 +422,17 @@ void LanguageClientHandlerPrivate::handleHoveredStart(int position)
return;
hoverCache.setTextRange(static_cast(startPos), static_cast(endPos));
+ if (!diagnosticCache.isEmpty()) {
+ auto iter = std::find_if(diagnosticCache.begin(), diagnosticCache.end(),
+ [position](const DiagnosticCache &cache) {
+ return cache.contains(position);
+ });
+ if (iter != diagnosticCache.end()) {
+ showDiagnosticTip(position, iter->message);
+ return;
+ }
+ }
+
lsp::Position pos;
editor->lineIndexFromPosition(position, &pos.line, &pos.character);
getClient()->docHoverRequest(editor->getFile(), pos);
@@ -556,6 +564,49 @@ void LanguageClientHandlerPrivate::gotoDefinition()
}
}
+void LanguageClientHandlerPrivate::showDiagnosticTip(int pos, const QString &message)
+{
+ if (!editor)
+ return;
+
+ QWidget *widget = new QWidget;
+ widget->setAutoFillBackground(true);
+ widget->setForegroundRole(QPalette::BrightText);
+ widget->setBackgroundRole(QPalette::Base);
+ QVBoxLayout *layout = new QVBoxLayout(widget);
+ layout->setContentsMargins(5, 5, 5, 5);
+
+ QLabel *msgLabel = new QLabel(message, widget);
+ layout->addWidget(msgLabel);
+ QString repairMsg = tr("%1: Repair with %2");
+
+ // create repair tool
+ auto editSrv = dpfGetService(dpfservice::EditorService);
+ auto repairTools = editSrv->getDiagnosticRepairTool();
+ for (auto iter = repairTools.cbegin(); iter != repairTools.cend(); ++iter) {
+ auto callback = iter.value();
+ QLabel *repairLabel = new QLabel(widget);
+ QString msg = message.mid(0, message.indexOf('\n'));
+ repairLabel->setText(repairMsg.arg(iter.key(), iter.key()));
+ connect(repairLabel, &QLabel::linkActivated, this,
+ [msg, callback, this]() {
+ QJsonObject info {
+ { "fileName", editor->getFile() },
+ { "msg", msg }
+ };
+
+ QJsonDocument doc(info);
+ callback(doc.toJson());
+ ToolTip::hideImmediately();
+ });
+
+ layout->addWidget(new DHorizontalLine(widget));
+ layout->addWidget(repairLabel);
+ }
+
+ editor->showTips(pos, widget);
+}
+
void LanguageClientHandlerPrivate::handleSwitchHeaderSource(const QString &file)
{
if (file.isEmpty())
diff --git a/src/plugins/codeeditor/lsp/private/languageclienthandler_p.h b/src/plugins/codeeditor/lsp/private/languageclienthandler_p.h
index a58dde85b..48b82d644 100644
--- a/src/plugins/codeeditor/lsp/private/languageclienthandler_p.h
+++ b/src/plugins/codeeditor/lsp/private/languageclienthandler_p.h
@@ -173,7 +173,6 @@ class LanguageClientHandlerPrivate : public QObject
void initLspConnection();
void initIndicStyle();
- QString formatDiagnosticMessage(const QString &message, int type);
bool shouldStartCompletion(const QString &insertedText);
int wordPostion();
newlsp::Client *getClient();
@@ -182,6 +181,7 @@ class LanguageClientHandlerPrivate : public QObject
void cleanDefinition(int pos);
void setDefinitionSelectedStyle(int start, int end);
void gotoDefinition();
+ void showDiagnosticTip(int pos, const QString &message);
public slots:
void handleTokenFull(const QList &tokens, const QString &filePath);
@@ -218,7 +218,6 @@ public slots:
TextEditor *editor { nullptr };
QList tokensCache;
QList diagnosticCache;
- QString diagnosticFormat;
newlsp::ProjectKey projectKey;
QTimer textChangedTimer;
diff --git a/src/services/editor/editorservice.h b/src/services/editor/editorservice.h
index e05b19418..9a437a103 100644
--- a/src/services/editor/editorservice.h
+++ b/src/services/editor/editorservice.h
@@ -60,6 +60,11 @@ class EditorService final : public dpf::PluginService,
DPF_INTERFACE(void, clearAllBackgroundColor, const QString &file, int marker);
DPF_INTERFACE(void, showLineWidget, int line, QWidget *widget);
DPF_INTERFACE(void, closeLineWidget);
+
+ using RepairCallback = std::function;
+ using RepairToolInfo = QMap;
+ DPF_INTERFACE(void, registerDiagnosticRepairTool, const QString &toolName, RepairCallback callback);
+ DPF_INTERFACE(RepairToolInfo, getDiagnosticRepairTool);
};
} // namespace dpfservice