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 - + This operation will delete all the content of this session. confirm to delete it? - + Cancel button - + Delete button - + stop generate - + delete this session - - reference files - - - - - connect to network - - - - + history sessions - + create new session - + Ask question here, press Enter to send... - - - Current file - - - - - Opened files - - - - - Select file - - - - - clear - - - - - Select File - - AttachInfoDialog @@ -612,86 +577,91 @@ BinaryToolsManager - + Default Group - + Start execute tool "%1". - + The tool is running. Please stop it before running. - + The tool (%1) execution program does not exist. Install and run it again - + Ok - + Configure... - + + Binary Tools + + + + The tool "%1" exited normally. - + The tool "%1" exited with code %2. - + The tool "%1" crashed. - + Execute tool "%1" finished. - + Cancel - + Install - + The tool has set the working directory, but the working directory parsing is empty. Please check and try again. - + The tool has set the channel data, but the channel data parsing is empty. Please check and try again. - - + + &Application Output @@ -815,47 +785,47 @@ BreakpointModel - + ... - + <More> - + Index - + Status - + Function - + File - + Line - + Condition - + Address @@ -901,83 +871,83 @@ BuildManager - + Compile Output - + Issues list - + Filter - + All - + Error - - + + Warning - + Clear Output - + The project does not have an associated build kit. Please reopen the project and select the corresponding build tool. - + &Build - + Execute command failed! - + Start execute command: "%1" "%2" in workspace "%3". - + The process "%1" exited normally. - + The process "%1" exited with code %2. - + The process "%1" crashed. - + Execute command finished. @@ -1015,11 +985,14 @@ storage: %2 CMakeBuilderGenerator - The build command of %1 project is null! please install it in console with "sudo apt install cmake", and then restart the tool. + The build command %1 project is null! You can solve this problem in the following ways: +1.Check whether cmake is installed; +2.Global Options > CMake > Select the CMake tool installed locally; +3.If none of the above methods work, delete the ".unioncode" folder in the current project directory and open the project again. - + The path of "%1" is not exist! please check and reopen the project. @@ -1048,7 +1021,7 @@ storage: %2 CmakeProjectGenerator - + Run CMake @@ -1058,47 +1031,47 @@ storage: %2 - + Files in project %1 have changed, needs to run cmake to update - + Properties - + File are not automatically added to the CmakeList.txt file to the Cmake project. Copy the path to the source files to the clipboard? - + Copy to Clipboard? - + Ok - + Project Properties - + Build - + Run - + Kit @@ -1157,52 +1130,52 @@ storage: %2 - + Close Current Editor - + Switch Header/Source - + Follow Symbol Under Cursor - + Toggle Breakpoint - + Find Usages - + Rename Symbol Under Cursor - + Current document - + Current document content - + Backward - + Forward @@ -1312,9 +1285,9 @@ storage: %2 CodePortingManager - - - + + + C&ode Porting @@ -1322,7 +1295,7 @@ storage: %2 CodePortingPlugin - + Code Porting @@ -1555,27 +1528,77 @@ storage: %2 Controller - + Open Document - + Hide ContextWidget - + Show docks in this view - + + &File + + + + + &Edit + + + + + &Build + + + + + &Debug + + + + + &Tools + + + + + &Help + + + + + Open File + + + + + Open Project + + + + + Report Bug + + + + + Help Documents + + + + Expand All - + Fold All @@ -1629,39 +1652,39 @@ storage: %2 DAPDebugger - - - + + + The debugee has Terminated. - + The debugee has Exited. - + Input Condition Expression - + Condition - + When the breakpoint is reached, it will be hit only when the expression is true - - + + Cancel @@ -1681,128 +1704,128 @@ The debugee has Terminated. - - + + Ok - + <Unknown> name - + <Unknown> meaning - + <p>The inferior stopped because it received a signal from the operating system.<p><table><tr><td>Signal name : </td><td>%1</td></tr><tr><td>Signal meaning : </td><td>%2</td></tr></table> - + Signal Received - + New Evaluator Expression - + Enter an expression to evaluate - + Threads: - + Stack List - + Add New Expression Evaluator - + Remove This Evaluator - + Name - + Value - + Type - + Breakpoint List - + Please build first. Build : Ctrl + B - + Is preparing dependence, please waiting for a moment - + Is getting the dap port, please waiting for a moment - + Requesting debug port... - + The dap port is not ready, please retry. - + Debugging starts - + Start debugging coredump file: - + The coredump target file is error: - + The coredump file is error: @@ -2042,16 +2065,6 @@ Delete anyway? Can not find kit. - - - Quickly Answer Questions - - - - - Provide More Accurate Answers to Technical Questions - - DetailsButton @@ -2149,28 +2162,20 @@ Delete anyway? - - EditorUtils - - - &Edit - - - EnvironmentView - + append - + reduce - + reset @@ -2178,23 +2183,22 @@ Delete anyway? EnvironmentWidget - - + Enable All Environment - + append - + reduce - + reset @@ -2202,105 +2206,100 @@ Delete anyway? FileTreeView - + Error, Can't move to trash: - + Error, Can't delete: - + New Document Name - - + + New Document - - + + Ok - + Open - - + + New Folder - + Delete operation not be recoverable, delete anyway? - + Delete Warining - + Cancel - + OK - + New File Name - + New File - + New Folder Name - + Error: Can't create new document or folder, please check whether the name already exists! - - Error: Can't create new document or folder, parent not's dir - - - - + Move To Trash - + Remove - + Rename - + Recover From Trash @@ -2308,12 +2307,12 @@ Delete anyway? FindPlugin - + Advanced Find - + ADVANCED SEARCH @@ -2321,48 +2320,38 @@ Delete anyway? FindToolBar - + Find - - + + Replace - + Replace All - + Replace && Find - - - - + Find/Replace - - - - &Find - - - - + Find Next - + Find Previous @@ -2562,52 +2551,47 @@ need to manually copy the source code to this path GitMenuManager - - + + Log of "%1" - - + + Diff of "%1" - + Blame of "%1" - + Current File - + Current Project - + Git Log - + Git Blame - + Git Diff - - - &Git - - GitTabWidget @@ -2737,6 +2721,34 @@ need to manually copy the source code to this path + + InputEditWidget + + + reference files + + + + + connect to network + + + + + Current File + + + + + Select File + + + + + Opened Files + + + InstantBlameWidget @@ -2996,46 +3008,51 @@ need to manually copy the source code to this path LanguageClientHandlerPrivate - + Refactor - + Rename Symbol Under Cursor - + Switch Header/Source - + Follow Symbol Under Cursor - + Find Usages - + Format Selection + + + %1: <a href='repair'>Repair with %2</a> + + LocatorManager - - Enter command + + Enter Command - - + + Enter command %1 @@ -3149,7 +3166,7 @@ repos path: %0 MainWindow - + Hide Dock Widget @@ -3243,13 +3260,36 @@ repos path: %0 - - online searching --- %1 + + Online Searching + + + + + Show Reference + + + + + NameValueModel + + + Variable + + + + + Value + + + + + <VARIABLE> - - References + + <VALUE> @@ -3314,17 +3354,17 @@ repos path: %0 OptionsDialog - + Global Options - + Apply - + Cancel @@ -3389,7 +3429,7 @@ repos path: %0 PluginManagerModule - + Extensions @@ -3864,6 +3904,11 @@ repos path: %0 User Action Analyse + + + Select File + + QDialog @@ -3941,25 +3986,20 @@ not exists support files: %0 - + Code Completion: - + Global Language Preference: - + Commits Language Preference: - - - model - - @@ -4203,32 +4243,17 @@ not exists support files: %0 - - - - Variable - - - - - - Value - - - Environment - - Interface - + Commands @@ -4380,7 +4405,7 @@ not exists support files: %0 - + Search &Results @@ -4554,17 +4579,17 @@ not exists support files: %0 ReverseDebugPlugin - + Reverse debug - + Record - + Replay @@ -4916,52 +4941,52 @@ not exists support files: %0 Runner - + Warning - + The project does not have an associated build kit. Please reopen the project and select the corresponding build tool. - + &Application Output - + Error: execute command error! The reason is unknown. - + Start execute command: "%1" "%2" in workspace "%3". - + The process "%1" exited normally. - + The process "%1" exited with code %2. - + The process "%1" crashed. - + Execute command finished. @@ -5489,72 +5514,122 @@ not exists support files: %0 - ShortCut + ShortcutDialog - - Shortcut Invalid + + Add Shortcut - - Shortcut Invalid, Please enter again! + + Press desired key combination to add shortcut - - Shortcut Repeated + + Cancel + button - - Shortcut Repeated, Please enter again! + + Ok + button - - OK + + 1 same shortcut command exist - - - ShortCutEdit - - Clear + + %1 same shortcut commands exist ShortcutSettingWidget - - Reset All + + + Type to search in keybindings + + + + + Record Keys - + + Command + + + + + Label + + + + + Shortcut + + + + Import - - Export + + Add Shortcut - - Open File + + Change %1 - - - Json File(*.json) + + Remove %1 - - Save File + + Remove All Shortcut + + + + + Reset Shortcut + + + + + Export Keyboard Mapping Scheme + + + + + + Keyboard Mapping Scheme (*.kms) + + + + + Import Keyboard Mapping Scheme + + + + + Recording Keys. Press Escape to exit + + + + + Export @@ -5683,16 +5758,6 @@ not exists support files: %0 SvnClientWidget - - - Checkout repository - - - - - Open repository - - select local reops @@ -5802,7 +5867,7 @@ not exists support files: %0 TabWidgetPrivate - + File Operation @@ -5818,17 +5883,17 @@ not exists support files: %0 TextEditor - + Save File - + The file "%1" has no write permission. Please add write permission and try again - + Ok button @@ -5837,75 +5902,80 @@ not exists support files: %0 TextEditorPrivate - + Refactor - + Undo - + Redo - + Cut - + Copy - + Paste - + Delete - + Select All - + Remove Breakpoint - + Disable Breakpoint - + Enable Breakpoint - + Add Condition - + Add a breakpoint on line %1 - + jump to %1 line + + + run to %1 line + + ToolOptionWidget @@ -6003,12 +6073,12 @@ not exists support files: %0 ValgrindRunner - + please install valgrind tool in console with "sudo apt install valgrind". - + &Application Output @@ -6034,96 +6104,545 @@ not exists support files: %0 WorkspaceWidgetPrivate - + Add/Delete Comment - - Add/Remove Comment + + Show opened files + + + + + Extend selection down one line - - &Add/Remove Comment + + Extend rectangular selection down one line - - - Show opened files + + Scroll view down one line - - &Show open files + + Extend selection up one line - + + Extend rectangular selection up one line + + + + + Scroll view up one line + + + + + Scroll to start of document + + + + + Scroll to end of document + + + + + Scroll vertically to centre current line + + + + + Move down one paragraph + + + + + Extend selection down one paragraph + + + + + Move up one paragraph + + + + + Extend selection up one paragraph + + + + + Move left one character + + + + + Extend selection left one character + + + + + Extend rectangular selection left one character + + + + + Move right one character + + + + + Extend selection right one character + + + + + Extend rectangular selection right one character + + + + + Move left one word + + + + + Extend selection left one word + + + + + Move right one word + + + + + Extend selection right one word + + + + + Move to end of previous word + + + + + Extend selection to end of previous word + + + + + Move to end of next word + + + + + Extend selection to end of next word + + + + + Move left one word part + + + + + Extend selection left one word part + + + + + Move right one word part + + + + + Extend selection right one word part + + + + + Move to start of document line + + + + + Extend selection to start of document line + + + + + Extend rectangular selection to start of document line + + + + + Move to start of display line + + + + + Extend selection to start of display line + + + + + Move to start of display or document line + + + + + Extend selection to start of display or document line + + + + + Move to first visible character in document line + + + + + Extend selection to first visible character in document line + + + + + Extend rectangular selection to first visible character in document line + + + + + Move to first visible character of display in document line + + + + + Extend selection to first visible character in display or document line + + + + + Move to end of document line + + + + + Extend selection to end of document line + + + + + Extend rectangular selection to end of document line + + + + + Move to end of display line + + + + + Extend selection to end of display line + + + + + Move to end of display or document line + + + + + Extend selection to end of display or document line + + + + + Move to start of document + + + + + Extend selection to start of document + + + + + Move to end of document + + + + + Extend selection to end of document + + + + + Move up one page + + + + + Extend selection up one page + + + + + Extend rectangular selection up one page + + + + + Move down one page + + + + + Extend selection down one page + + + + + Extend rectangular selection down one page + + + + + Stuttered move up one page + + + + + Stuttered extend selection up one page + + + + + Stuttered move down one page + + + + + Stuttered extend selection down one page + + + + + Delete current character + + + + + Delete previous character + + + + + Delete previous character if not at start of line + + + + + Delete word to left + + + + + Delete word to right + + + + + Delete right to end of next word + + + + + Delete line to left + + + + + Delete line to right + + + + + Delete current line + + + + + Cut current line + + + + + Copy current line + + + + + Transpose current and previous lines + + + + + Duplicate the current line + + + + + Select all + + + + + Move selected lines up one line + + + + + Move selected lines down one line + + + + + Duplicate selection + + + + + Convert selection to lower case + + + + + Convert selection to upper case + + + + + Cut selection + + + + + Copy selection + + + + + Paste + + + + + Toggle insert/overtype + + + + + Formfeed + + + + + De-indent one level + + + + + Undo last command + + + + + Redo last command + + + + + Zoom in + + + + + Zoom out + + + + The file <i>%1</i> has been changed on disk.Do you want to reload it? - + File Has Been Changed - + Yes button - + Yes To All button - + No button - + No To All button - - + + Close button - + The file <i>%1</i> has been removed from disk. Do you want to save it under a different name, or close the editor? - + File Has Been Removed - + Save button - + Save As button - + Close All 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 - + This operation will delete all the content of this session. confirm to delete it? 该操作将删除该会话的全部内容,确定删除吗? - + Cancel button 取消 - + Delete button 删除 - + stop generate 终止生成 - + delete this session 删除该会话 - - reference files - 引用文件 - - - - connect to network - 联网 - - - + history sessions 历史会话 - + create new session 创建新会话 - + Ask question here, press Enter to send... 在这里提问,按Enter键发送... - - - Current file - 当前文件 - - - - Opened files - 已打开文件 - - - - Select file - 选择文件 - - - - clear - 清空 - - - - Select File - 选择文件 - AttachInfoDialog @@ -612,94 +577,99 @@ BinaryToolsManager - + Default Group 默认分组 - + Start execute tool "%1". 开始执行工具 “%1”。 - + The tool is running. Please stop it before running. 这个工具正在运行。请将其停止后再运行。 - + The tool (%1) execution program does not exist. Install and run it again 工具 (%1) 执行程序不存在,请安装并重试 - + Ok 确定 - + Configure... 配置... - + + Binary Tools + 二进制工具 + + + The tool "%1" exited normally. 工具 "%1" 正常退出。 - + The tool "%1" exited with code %2. 工具 "%1" 以code %2 结束。 - + The tool "%1" crashed. 工具 "%1" 崩溃。 - + Execute tool "%1" finished. 工具 "%1" 执行完成。 - + Cancel 取消 - + Install 安装 - + The tool has set the working directory, but the working directory parsing is empty. Please check and try again. 这个工具设置了工作目录,但是工具目录解析为空。请检测后重试。 - + The tool has set the channel data, but the channel data parsing is empty. Please check and try again. 这个工具设置了管道数据,但是管道数据解析为空。请检测后重试。 - - + + &Application Output 应用程序输出(&A) @@ -823,47 +793,47 @@ BreakpointModel - + ... ... - + <More> <More> - + Index 索引 - + Status 状态 - + Function 函数 - + File 文件 - + Line - + Condition 条件 - + Address 地址 @@ -909,88 +879,88 @@ BuildManager - + Compile Output 编译输出 - + Issues list 问题列表 - + Filter 信息过滤 - + All 全部 - + Error 错误 - - + + Warning 警告 - + Clear Output 清空输出 - + The project does not have an associated build kit. Please reopen the project and select the corresponding build tool. 该工程没有关联的构建工具,请重新打开该工程并选择对应的构建工具. - + &Build 编译(&B) - + Execute command failed! 执行命令失败! - + Start execute command: "%1" "%2" in workspace "%3". 开始在工作区%3中执行%1 %2命令。 - + The process "%1" exited normally. 进程%1正常退出。 - + The process "%1" exited with code %2. 进程%1退出,代码为%2。 - + The process "%1" crashed. 进程 %1崩溃。 - + Execute command finished. 命令执行完成。 @@ -1032,11 +1002,14 @@ storage: %2 CMakeBuilderGenerator - The build command of %1 project is null! please install it in console with "sudo apt install cmake", and then restart the tool. - %1项目的生成命令为空!请使用“sudo apt install cmake”在控制台中安装它,然后重新启动该工具。 + The build command %1 project is null! You can solve this problem in the following ways: +1.Check whether cmake is installed; +2.Global Options > CMake > Select the CMake tool installed locally; +3.If none of the above methods work, delete the ".unioncode" folder in the current project directory and open the project again. + - + The path of "%1" is not exist! please check and reopen the project. "%1" 不存在!请检查并重新打开工程 @@ -1065,7 +1038,7 @@ storage: %2 CmakeProjectGenerator - + Run CMake 执行CMake @@ -1075,47 +1048,47 @@ storage: %2 清除CMake - + Files in project %1 have changed, needs to run cmake to update 项目%1中的文件已经更改,需要运行 cmake 来更新 - + Properties 工程属性 - + File are not automatically added to the CmakeList.txt file to the Cmake project. Copy the path to the source files to the clipboard? 文件不会自动添加到 Cmake 项目的 CmakeList.txt 文件中。将源文件的路径复制到剪贴板? - + Copy to Clipboard? 复制到剪贴板? - + Ok 确定 - + Project Properties 工程属性 - + Build 编译 - + Run 运行 - + Kit 套件 @@ -1174,52 +1147,52 @@ storage: %2 前进 - + Close Current Editor 关闭当前编辑器 - + Switch Header/Source 切换头文件/源文件 - + Follow Symbol Under Cursor 跟随光标下符号 - + Toggle Breakpoint 切换断点 - + Find Usages 查找引用 - + Rename Symbol Under Cursor 重命名 - + Current document 当前文档 - + Current document content 当前文档内容 - + Backward 后退 - + Forward 前进 @@ -1335,9 +1308,9 @@ storage: %2 CodePortingManager - - - + + + C&ode Porting 代码迁移(&O) @@ -1345,7 +1318,7 @@ storage: %2 CodePortingPlugin - + Code Porting 代码迁移 @@ -1578,27 +1551,77 @@ storage: %2 Controller - + Open Document 打开文件 - + Hide ContextWidget 隐藏内容区 - + Show docks in this view 当前视图中的窗口 - + + &File + 文件(&F) + + + + &Edit + 编辑(&E) + + + + &Build + 编译(&B) + + + + &Debug + 调试(&D) + + + + &Tools + 工具(&T) + + + + &Help + 帮助(&H) + + + + Open File + 打开文件 + + + + Open Project + 打开工程 + + + + Report Bug + 报告Bug + + + + Help Documents + 帮助文档 + + + Expand All 展开所有 - + Fold All 折叠所有 @@ -1652,9 +1675,9 @@ storage: %2 DAPDebugger - - - + + + The debugee has Terminated. @@ -1663,31 +1686,31 @@ The debugee has Terminated. - + The debugee has Exited. 调试已退出。 - + Input Condition Expression 输入条件表达式 - + Condition 条件 - + When the breakpoint is reached, it will be hit only when the expression is true 当断点到达,仅在表达式为真时触发 - - + + Cancel 取消 @@ -1707,107 +1730,107 @@ The debugee has Terminated. 请求cxx dap端口失败,请重新尝试。 - - + + Ok 确认 - + <Unknown> name - + <Unknown> meaning - + <p>The inferior stopped because it received a signal from the operating system.<p><table><tr><td>Signal name : </td><td>%1</td></tr><tr><td>Signal meaning : </td><td>%2</td></tr></table> <p>下位机停止,因为它收到了来自操作系统的信号。<p><table><tr><td>信号名: </td><td>%1</td></tr><tr><td>信号含义: </td><td>%2</td></tr></table> - + Signal Received 信号已接收 - + New Evaluator Expression 新评估表达式 - + Enter an expression to evaluate 输入求值表达式 - + Threads: 线程: - + Stack List 堆栈列表 - + Add New Expression Evaluator 添加新评估表达式 - + Remove This Evaluator 删除评估 - + Name 名称 - + Value - + Type 类型 - + Breakpoint List 断点列表 - + Please build first. Build : Ctrl + B 请先编译工程。 编译:Ctrl + B - + Is preparing dependence, please waiting for a moment 正在加载依赖项,请等待 - + Is getting the dap port, please waiting for a moment 正在获取dap端口,请等待 - + Requesting debug port... 请求调试端口... - + The dap port is not ready, please retry. @@ -1816,22 +1839,22 @@ dap端口未就绪,请重试。 - + Debugging starts 调试开始 - + Start debugging coredump file: 开始调试coredump文件: - + The coredump target file is error: coredump目标文件错误: - + The coredump file is error: coredump文件错误: @@ -2072,16 +2095,6 @@ Delete anyway? Can not find kit. 找不到配套工具。 - - - Quickly Answer Questions - 快速回答问题 - - - - Provide More Accurate Answers to Technical Questions - 在技术问题上提供更准确的回答 - DetailsButton @@ -2179,28 +2192,20 @@ Delete anyway? 编辑器 - - EditorUtils - - - &Edit - 编辑(&E) - - EnvironmentView - + append 增加 - + reduce 减少 - + reset 重置 @@ -2208,23 +2213,22 @@ Delete anyway? EnvironmentWidget - - + Enable All Environment 启用所有环境 - + append 增加 - + reduce 减少 - + reset 重置 @@ -2232,105 +2236,100 @@ Delete anyway? FileTreeView - + Error, Can't move to trash: 错误,无法移到废纸篓: - + Error, Can't delete: 错误,无法删除: - + New Document Name 新文件名 - - + + New Document 新建文件 - - + + Ok - + Open 打开 - - + + New Folder 新建文件夹 - + Delete operation not be recoverable, delete anyway? 删除操作不可逆转,是否删除? - + Delete Warining 删除警告 - + Cancel 取消 - + OK 确定 - + New File Name 新文件名 - + New File 创建新文件 - + New Folder Name 新文件夹 - + Error: Can't create new document or folder, please check whether the name already exists! 无法创建文件或文件夹,请检查文件名是否已经存在! - - Error: Can't create new document or folder, parent not's dir - 非目录下无法在创建文件或文件夹 - - - + Move To Trash 移到回收站 - + Remove 删除 - + Rename 重命名 - + Recover From Trash 恢复 @@ -2338,12 +2337,12 @@ Delete anyway? FindPlugin - + Advanced Find 高级查找 - + ADVANCED SEARCH 高级搜索 @@ -2351,48 +2350,38 @@ Delete anyway? FindToolBar - + Find 查找 - - + + Replace 替换 - + Replace All 替换全部 - + Replace && Find 替换并查找 - - - - + Find/Replace 查找/替换 - - - - &Find - &查看 - - - + Find Next 查找下一个 - + Find Previous 查找上一个 @@ -2593,52 +2582,47 @@ need to manually copy the source code to this path GitMenuManager - - + + Log of "%1" Log of "%1" - - + + Diff of "%1" Diff of "%1" - + Blame of "%1" Blame of "%1" - + Current File 当前文件 - + Current Project 当前工程 - + Git Log - + Git Blame - + Git Diff - - - &Git - - GitTabWidget @@ -2768,6 +2752,34 @@ need to manually copy the source code to this path 历史对话 + + InputEditWidget + + + reference files + 引用文件 + + + + connect to network + 联网 + + + + Current File + 当前文件 + + + + Select File + 选择文件 + + + + Opened Files + 打开文件 + + InstantBlameWidget @@ -3027,46 +3039,51 @@ need to manually copy the source code to this path LanguageClientHandlerPrivate - + Refactor 重构 - + Rename Symbol Under Cursor 重命名 - + Switch Header/Source 切换头文件/源文件 - + Follow Symbol Under Cursor 跟随光标下符号 - + Find Usages 查找引用 - + Format Selection 格式化选中部分 + + + %1: <a href='repair'>Repair with %2</a> + + LocatorManager - - Enter command - 键入命令 + + Enter Command + - - + + Enter command %1 键入命令 %1 @@ -3182,7 +3199,7 @@ repos path: %0 MainWindow - + Hide Dock Widget 隐藏驻留区 @@ -3276,14 +3293,37 @@ repos path: %0 编辑 - - online searching --- %1 - 联网搜索 --- %1. + + Online Searching + - - References - 引用 + + Show Reference + + + + + NameValueModel + + + Variable + 变量名 + + + + Value + + + + + <VARIABLE> + + + + + <VALUE> + @@ -3347,17 +3387,17 @@ repos path: %0 OptionsDialog - + Global Options 全局选项 - + Apply 应用 - + Cancel 取消 @@ -3422,7 +3462,7 @@ repos path: %0 PluginManagerModule - + Extensions 扩展 @@ -3897,6 +3937,11 @@ repos path: %0 User Action Analyse 用户行为分析 + + + Select File + 选择文件 + QDialog @@ -3976,25 +4021,20 @@ not exists support files: %0 编译配置: - + Code Completion: 代码补全: - + Global Language Preference: 全局语言偏好: - + Commits Language Preference: Commits语言偏好: - - - model - 模型 - @@ -4238,32 +4278,17 @@ not exists support files: %0 CMake 配置 - - - - Variable - 变量名 - - - - - Value - - - Environment - 环境 - Interface 用户界面 - + Commands 命令 @@ -4415,7 +4440,7 @@ not exists support files: %0 符号 - + Search &Results 查找结果(&R) @@ -4589,17 +4614,17 @@ not exists support files: %0 ReverseDebugPlugin - + Reverse debug 反向调试 - + Record 记录 - + Replay 重放 @@ -4951,57 +4976,57 @@ not exists support files: %0 Runner - + Warning 警告 - + The project does not have an associated build kit. Please reopen the project and select the corresponding build tool. 该工程没有关联的构建工具,请重新打开该工程并选择对应的构建工具. - + &Application Output 应用程序输出(&A) - + Error: execute command error! The reason is unknown. 错误:执行命令错误!原因未知。 - + Start execute command: "%1" "%2" in workspace "%3". 开始在工作区%3中执行%1 %2命令。 - + The process "%1" exited normally. 进程%1正常退出。 - + The process "%1" exited with code %2. 进程%1退出,代码为%2。 - + The process "%1" crashed. 进程 %1崩溃。 - + Execute command finished. 命令执行完成。 @@ -5530,73 +5555,123 @@ not exists support files: %0 - ShortCut + ShortcutDialog - - Shortcut Invalid - 快捷键不合法 + + Add Shortcut + - - Shortcut Invalid, Please enter again! - 快捷键不合法,请重新输入! + + Press desired key combination to add shortcut + - - Shortcut Repeated - 快捷键重复 + + Cancel + button + 取消 - - Shortcut Repeated, Please enter again! - 快捷键重复,请重新输入! + + Ok + button + - - OK - 确定 + + 1 same shortcut command exist + - - - ShortCutEdit - - Clear - 清除 + + %1 same shortcut commands exist + ShortcutSettingWidget - - Reset All - 重置所有 + + + Type to search in keybindings + + + + + Record Keys + + + + + Command + + + + + Label + - + + Shortcut + + + + Import 导入 - - Export - 导出 + + Add Shortcut + - - Open File - 打开文件 + + Change %1 + - - - Json File(*.json) - Json 文件(*.json) + + Remove %1 + - - Save File - 保存文件 + + Remove All Shortcut + + + + + Reset Shortcut + + + + + Export Keyboard Mapping Scheme + + + + + + Keyboard Mapping Scheme (*.kms) + + + + + Import Keyboard Mapping Scheme + + + + + Recording Keys. Press Escape to exit + + + + + Export + 导出 @@ -5724,16 +5799,6 @@ not exists support files: %0 SvnClientWidget - - - Checkout repository - 检出仓库 - - - - Open repository - 打开仓库 - select local reops @@ -5843,7 +5908,7 @@ not exists support files: %0 TabWidgetPrivate - + File Operation 文件操作 @@ -5859,17 +5924,17 @@ not exists support files: %0 TextEditor - + Save File 保存文件 - + The file "%1" has no write permission. Please add write permission and try again 文件“%1”没有写权限。请添加写权限并重试 - + Ok button 确定 @@ -5878,75 +5943,80 @@ not exists support files: %0 TextEditorPrivate - + Refactor 重构 - + Undo 撤销 - + Redo 恢复 - + Cut 剪切 - + Copy 复制 - + Paste 粘贴 - + Delete 删除 - + Select All 选择全部 - + Remove Breakpoint 移除断点 - + Disable Breakpoint 禁用断点 - + Enable Breakpoint 启用断点 - + Add Condition 添加条件 - + Add a breakpoint on line %1 在第 %1 行添加断点 - + jump to %1 line 跳转到 %1 行 + + + run to %1 line + + ToolOptionWidget @@ -6044,12 +6114,12 @@ not exists support files: %0 ValgrindRunner - + please install valgrind tool in console with "sudo apt install valgrind". 请从终端安装“valgrind”工具:$sudo apt install valgrind. - + &Application Output 应用程序输出(&A) @@ -6075,96 +6145,545 @@ not exists support files: %0 WorkspaceWidgetPrivate - + Add/Delete Comment 添加/删除注释 - - Add/Remove Comment - 添加/删除注释 + + Show opened files + 显示打开的文件 + + + + Extend selection down one line + - - &Add/Remove Comment - &添加/删除注释 + + Extend rectangular selection down one line + - - - Show opened files - 显示打开的文件 + + Scroll view down one line + + + + + Extend selection up one line + + + + + Extend rectangular selection up one line + - - &Show open files - &显示打开的文件 + + Scroll view up one line + + + + + Scroll to start of document + + + + + Scroll to end of document + + + + + Scroll vertically to centre current line + + + + + Move down one paragraph + + + + + Extend selection down one paragraph + + + + + Move up one paragraph + - + + Extend selection up one paragraph + + + + + Move left one character + + + + + Extend selection left one character + + + + + Extend rectangular selection left one character + + + + + Move right one character + + + + + Extend selection right one character + + + + + Extend rectangular selection right one character + + + + + Move left one word + + + + + Extend selection left one word + + + + + Move right one word + + + + + Extend selection right one word + + + + + Move to end of previous word + + + + + Extend selection to end of previous word + + + + + Move to end of next word + + + + + Extend selection to end of next word + + + + + Move left one word part + + + + + Extend selection left one word part + + + + + Move right one word part + + + + + Extend selection right one word part + + + + + Move to start of document line + + + + + Extend selection to start of document line + + + + + Extend rectangular selection to start of document line + + + + + Move to start of display line + + + + + Extend selection to start of display line + + + + + Move to start of display or document line + + + + + Extend selection to start of display or document line + + + + + Move to first visible character in document line + + + + + Extend selection to first visible character in document line + + + + + Extend rectangular selection to first visible character in document line + + + + + Move to first visible character of display in document line + + + + + Extend selection to first visible character in display or document line + + + + + Move to end of document line + + + + + Extend selection to end of document line + + + + + Extend rectangular selection to end of document line + + + + + Move to end of display line + + + + + Extend selection to end of display line + + + + + Move to end of display or document line + + + + + Extend selection to end of display or document line + + + + + Move to start of document + + + + + Extend selection to start of document + + + + + Move to end of document + + + + + Extend selection to end of document + + + + + Move up one page + + + + + Extend selection up one page + + + + + Extend rectangular selection up one page + + + + + Move down one page + + + + + Extend selection down one page + + + + + Extend rectangular selection down one page + + + + + Stuttered move up one page + + + + + Stuttered extend selection up one page + + + + + Stuttered move down one page + + + + + Stuttered extend selection down one page + + + + + Delete current character + + + + + Delete previous character + + + + + Delete previous character if not at start of line + + + + + Delete word to left + + + + + Delete word to right + + + + + Delete right to end of next word + + + + + Delete line to left + + + + + Delete line to right + + + + + Delete current line + + + + + Cut current line + + + + + Copy current line + + + + + Transpose current and previous lines + + + + + Duplicate the current line + + + + + Select all + + + + + Move selected lines up one line + + + + + Move selected lines down one line + + + + + Duplicate selection + + + + + Convert selection to lower case + + + + + Convert selection to upper case + + + + + Cut selection + + + + + Copy selection + + + + + Paste + 粘贴 + + + + Toggle insert/overtype + + + + + Formfeed + + + + + De-indent one level + + + + + Undo last command + + + + + Redo last command + + + + + Zoom in + 放大 + + + + Zoom out + 缩小 + + + The file <i>%1</i> has been changed on disk.Do you want to reload it? %1 被修改,是否重新加载? - + File Has Been Changed 文件发生修改 - + Yes button 确定 - + Yes To All button 应用所有 - + No button 取消 - + No To All button 取消所有 - - + + Close button 关闭 - + The file <i>%1</i> has been removed from disk. Do you want to save it under a different name, or close the editor? %1 被移除,是否需要另存为,或者关闭当前编辑页? - + File Has Been Removed 文件被移除 - + Save button 保存 - + Save As button 另存为 - + Close All 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