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/common/util/eventdefinitions.h b/src/common/util/eventdefinitions.h index 7955fa777..fa5a36ba5 100644 --- a/src/common/util/eventdefinitions.h +++ b/src/common/util/eventdefinitions.h @@ -55,9 +55,6 @@ OPI_OBJECT(editor, OPI_INTERFACE(clearAllAnnotation, "title") OPI_INTERFACE(setDebugLine, "fileName", "line") OPI_INTERFACE(removeDebugLine) - OPI_INTERFACE(setLineBackgroundColor, "fileName", "line", "color") - OPI_INTERFACE(resetLineBackgroundColor, "fileName", "line") - OPI_INTERFACE(clearLineBackgroundColor, "fileName") OPI_INTERFACE(setModifiedAutoReload, "fileName", "flag") OPI_INTERFACE(addBreakpoint, "fileName", "line", "enabled") OPI_INTERFACE(removeBreakpoint, "fileName", "line") @@ -74,6 +71,7 @@ OPI_OBJECT(editor, OPI_INTERFACE(breakpointStatusChanged, "fileName", "line", "enabled") OPI_INTERFACE(textChanged) OPI_INTERFACE(cursorPositionChanged, "fileName", "line", "index") + OPI_INTERFACE(selectionChanged, "fileName", "lineFrom", "indexFrom", "lineTo", "indexTo") //right-cliked menu, Related to debugging OPI_INTERFACE(setBreakpointCondition, "fileName", "line") diff --git a/src/plugins/builder/tasks/taskmanager.cpp b/src/plugins/builder/tasks/taskmanager.cpp index 4760d2152..028100529 100644 --- a/src/plugins/builder/tasks/taskmanager.cpp +++ b/src/plugins/builder/tasks/taskmanager.cpp @@ -72,6 +72,6 @@ void TaskManager::triggerDefaultHandler(const QModelIndex &index) return; if (task.file.exists()) { - editor.gotoLine(task.file.toString(), task.movedLine); + editor.gotoLine(task.file.toString(), task.movedLine - 1); } } 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 a3abfef76..8f23e6ac5 100644 --- a/src/plugins/codeeditor/codeeditor.cpp +++ b/src/plugins/codeeditor/codeeditor.cpp @@ -181,6 +181,14 @@ void CodeEditor::initEditorService() editorService->fileText = std::bind(&WorkspaceWidget::fileText, workspaceWidget, _1); editorService->replaceAll = std::bind(&WorkspaceWidget::replaceAll, workspaceWidget, _1, _2, _3, _4, _5); editorService->replaceRange = std::bind(&WorkspaceWidget::replaceRange, workspaceWidget, _1, _2, _3, _4, _5); + editorService->setRangeBackgroundColor = std::bind(&WorkspaceWidget::setRangeBackgroundColor, workspaceWidget, _1, _2, _3, _4); + editorService->clearRangeBackgroundColor = std::bind(&WorkspaceWidget::clearRangeBackgroundColor, workspaceWidget, _1, _2, _3, _4); + editorService->clearAllBackgroundColor = std::bind(&WorkspaceWidget::clearAllBackgroundColor, workspaceWidget, _1, _2); + 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/tabwidget_p.h b/src/plugins/codeeditor/gui/private/tabwidget_p.h index c364d9f9a..b6e5edce8 100644 --- a/src/plugins/codeeditor/gui/private/tabwidget_p.h +++ b/src/plugins/codeeditor/gui/private/tabwidget_p.h @@ -56,9 +56,6 @@ public slots: void handleAddAnnotation(const QString &fileName, const QString &title, const QString &content, int line, AnnotationType type); void handleRemoveAnnotation(const QString &fileName, const QString &title); void handleClearAllAnnotation(const QString &title); - void handleSetLineBackgroundColor(const QString &fileName, int line, const QColor &color); - void handleResetLineBackground(const QString &fileName, int line); - void handleClearLineBackground(const QString &fileName); void handleDoRename(const newlsp::WorkspaceEdit &info); void handleOpenFiles(const QList &fileList); diff --git a/src/plugins/codeeditor/gui/private/texteditor_p.cpp b/src/plugins/codeeditor/gui/private/texteditor_p.cpp index fecf23327..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 @@ -55,6 +54,13 @@ void TextEditorPrivate::init() q->SendScintilla(TextEditor::SCI_AUTOCSETCASEINSENSITIVEBEHAVIOUR, TextEditor::SC_CASEINSENSITIVEBEHAVIOUR_IGNORECASE); + lineWidgetContainer = new QFrame(q, Qt::Tool | Qt::FramelessWindowHint); + lineWidgetContainer->setLayout(new QVBoxLayout); + lineWidgetContainer->setContentsMargins(0, 0, 0, 0); + lineWidgetContainer->installEventFilter(q); + if (mainWindow()) + mainWindow()->installEventFilter(q); + initMargins(); updateColorTheme(); updateSettings(); @@ -69,6 +75,7 @@ void TextEditorPrivate::initConnection() q->cancelTips(); }); + connect(q->verticalScrollBar(), &QScrollBar::valueChanged, this, &TextEditorPrivate::updateLineWidgetPosition); connect(q, &TextEditor::SCN_ZOOM, q, &TextEditor::zoomValueChanged); connect(q, &TextEditor::SCN_DWELLSTART, this, &TextEditorPrivate::onDwellStart); connect(q, &TextEditor::SCN_DWELLEND, this, &TextEditorPrivate::onDwellEnd); @@ -91,13 +98,12 @@ void TextEditorPrivate::initMargins() q->setMarginMarkerMask(SymbolMargin, 1 << Breakpoint | 1 << BreakpointDisabled | 1 << Bookmark | 1 << Runtime - | 1 << RuntimeLineBackground | 1 << CustomLineBackground); + | 1 << RuntimeLineBackground); q->markerDefine(TextEditor::RightTriangle, Bookmark); q->setMarkerBackgroundColor(QColor(Qt::red), Bookmark); q->markerDefine(TextEditor::Background, RuntimeLineBackground); - q->markerDefine(TextEditor::Background, CustomLineBackground); } void TextEditorPrivate::updateColorTheme() @@ -112,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")); @@ -131,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")); @@ -152,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() @@ -342,8 +339,8 @@ void TextEditorPrivate::showMarginMenu() DebuggerService *debuggerService = ctx.service(DebuggerService::name()); if (debuggerService->getDebugState() == AbstractDebugger::RunState::kStopped) { menu.addSeparator(); - menu.addAction(tr("jump to %1 line").arg(line + 1), q, [this, line] { editor.jumpToLine(fileName, line + 1); }); - menu.addAction(tr("run to %1 line").arg(line + 1), q, [this, line] { editor.runToLine(fileName, line + 1); }); + menu.addAction(tr("jump to %1 line").arg(line + 1), q, [this, line] { editor.jumpToLine(fileName, line); }); + menu.addAction(tr("run to %1 line").arg(line + 1), q, [this, line] { editor.runToLine(fileName, line); }); } // notify other plugin to add action. @@ -440,7 +437,7 @@ QMap TextEditorPrivate::allMarkers() if (mask != 0) markers.insert(line, mask); } - + return markers; } @@ -450,7 +447,7 @@ void TextEditorPrivate::setMarkers(const QMap &maskMap) for (auto iter = maskMap.begin(); iter != maskMap.end(); ++iter) { if (iter.key() >= totalLine) break; - + if (iter.value() & (1 << Breakpoint)) { q->addBreakpoint(iter.key(), true); } else if (iter.value() & (1 << BreakpointDisabled)) { @@ -459,6 +456,66 @@ void TextEditorPrivate::setMarkers(const QMap &maskMap) } } +QWidget *TextEditorPrivate::mainWindow() +{ + static QWidget *mw { nullptr }; + if (mw) + return mw; + + for (auto w : qApp->allWidgets()) { + if (w->objectName() == "MainWindow") { + mw = w; + break; + } + } + + return mw; +} + +void TextEditorPrivate::setContainerWidget(QWidget *widget) +{ + auto layout = lineWidgetContainer->layout(); + while (auto item = layout->takeAt(0)) { + if (QWidget *w = item->widget()) + w->setVisible(false); + delete item; + } + + widget->setVisible(true); + lineWidgetContainer->setFocusProxy(widget); + lineWidgetContainer->layout()->addWidget(widget); + lineWidgetContainer->show(); + updateLineWidgetPosition(); +} + +void TextEditorPrivate::updateLineWidgetPosition() +{ + if (!lineWidgetContainer->isVisible() || showAtLine < 0 || showAtLine > q->lines() - 1) + return; + + int pos = q->positionFromLineIndex(showAtLine, 0); + auto point = q->mapToGlobal(q->pointFromPosition(pos)); + auto displayY = point.y() - lineWidgetContainer->height(); + + auto rect = q->rect(); + auto rectTL = q->mapToGlobal(rect.topLeft()); + auto rectBL = q->mapToGlobal(rect.bottomLeft()); + + // NOTE: upate the `lineWidgetContainer` position + // 1.It is displayed above `showAtLine` by default + // 2.The `lineWidgetContainer` does not extend beyond the top and bottom of the editor + // 3.When the `lineWidgetContainer` will block the `showAtLine`, display it below the `showAtLine` + if (displayY < rectTL.y()) { + displayY = point.y() + q->textHeight(showAtLine); + if (displayY < rectTL.y()) + displayY = rectTL.y(); + } else if (displayY > rectBL.y() - lineWidgetContainer->height()) { + displayY = rectBL.y() - lineWidgetContainer->height(); + } + + lineWidgetContainer->move(point.x(), displayY); +} + void TextEditorPrivate::resetThemeColor() { if (q->lexer()) { @@ -505,11 +562,17 @@ void TextEditorPrivate::onModified(int pos, int mtype, const QString &text, int contentsChanged = true; if (isAutoCompletionEnabled && !text.isEmpty()) editor.textChanged(); - + if (added != 0) { int line = 0, index = 0; q->lineIndexFromPosition(pos, &line, &index); - editor.lineChanged(fileName, line + 1, added); + editor.lineChanged(fileName, line, added); + if (lineWidgetContainer->isVisible()) { + if (showAtLine > line) { + showAtLine += added; + updateLineWidgetPosition(); + } + } } if (mtype & TextEditor::SC_MOD_INSERTTEXT) { diff --git a/src/plugins/codeeditor/gui/private/texteditor_p.h b/src/plugins/codeeditor/gui/private/texteditor_p.h index fcf14b89f..b8b4144bc 100644 --- a/src/plugins/codeeditor/gui/private/texteditor_p.h +++ b/src/plugins/codeeditor/gui/private/texteditor_p.h @@ -28,8 +28,7 @@ class TextEditorPrivate : public QObject BreakpointDisabled, Bookmark, Runtime, - RuntimeLineBackground, - CustomLineBackground + RuntimeLineBackground }; explicit TextEditorPrivate(TextEditor *qq); @@ -56,6 +55,10 @@ class TextEditorPrivate : public QObject QMap allMarkers(); void setMarkers(const QMap &maskMap); + QWidget *mainWindow(); + void setContainerWidget(QWidget *widget); + void updateLineWidgetPosition(); + public slots: void resetThemeColor(); void onDwellStart(int position, int x, int y); @@ -71,7 +74,7 @@ public slots: int preFirstLineNum { 0 }; int lastCursorPos { 0 }; QMultiHash annotationRecords; - + LanguageClientHandler *languageClient { nullptr }; bool isAutoCompletionEnabled { false }; @@ -83,8 +86,11 @@ public slots: int fontSize { 10 }; CodeCompletionWidget *completionWidget { nullptr }; - QMap commentSettings; + + std::tuple selectionCache { -1, -1, -1, -1 }; + QFrame *lineWidgetContainer { nullptr }; + int showAtLine { 0 }; }; #endif // TEXTEDITOR_P_H 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/tabwidget.cpp b/src/plugins/codeeditor/gui/tabwidget.cpp index c628ad89b..640e6751c 100644 --- a/src/plugins/codeeditor/gui/tabwidget.cpp +++ b/src/plugins/codeeditor/gui/tabwidget.cpp @@ -145,9 +145,6 @@ void TabWidgetPrivate::initConnection() connect(EditorCallProxy::instance(), &EditorCallProxy::reqAddAnnotation, this, &TabWidgetPrivate::handleAddAnnotation); connect(EditorCallProxy::instance(), &EditorCallProxy::reqRemoveAnnotation, this, &TabWidgetPrivate::handleRemoveAnnotation); connect(EditorCallProxy::instance(), &EditorCallProxy::reqClearAllAnnotation, this, &TabWidgetPrivate::handleClearAllAnnotation); - connect(EditorCallProxy::instance(), &EditorCallProxy::reqSetLineBackgroundColor, this, &TabWidgetPrivate::handleSetLineBackgroundColor); - connect(EditorCallProxy::instance(), &EditorCallProxy::reqResetLineBackground, this, &TabWidgetPrivate::handleResetLineBackground); - connect(EditorCallProxy::instance(), &EditorCallProxy::reqClearLineBackground, this, &TabWidgetPrivate::handleClearLineBackground); connect(EditorCallProxy::instance(), &EditorCallProxy::reqDoRename, this, &TabWidgetPrivate::handleDoRename); } @@ -439,24 +436,6 @@ void TabWidgetPrivate::handleClearAllAnnotation(const QString &title) editor->removeAnnotation(title); } -void TabWidgetPrivate::handleSetLineBackgroundColor(const QString &fileName, int line, const QColor &color) -{ - if (auto editor = findEditor(fileName)) - editor->setLineBackgroundColor(line, color); -} - -void TabWidgetPrivate::handleResetLineBackground(const QString &fileName, int line) -{ - if (auto editor = findEditor(fileName)) - editor->resetLineBackgroundColor(line); -} - -void TabWidgetPrivate::handleClearLineBackground(const QString &fileName) -{ - if (auto editor = findEditor(fileName)) - editor->clearLineBackgroundColor(); -} - void TabWidgetPrivate::handleDoRename(const newlsp::WorkspaceEdit &info) { if (info.changes) { @@ -861,6 +840,57 @@ void TabWidget::updateZoomValue(int value) } } +bool TabWidget::setRangeBackgroundColor(const QString &fileName, int startLine, int endLine, const QColor &color, int &marker) +{ + if (auto editor = d->findEditor(fileName)) { + marker = editor->setRangeBackgroundColor(startLine, endLine, color); + return true; + } + + return false; +} + +bool TabWidget::clearRangeBackground(const QString &fileName, int startLine, int endLine, int marker) +{ + if (auto editor = d->findEditor(fileName)) { + editor->clearRangeBackgroundColor(startLine, endLine, marker); + return true; + } + + return false; +} + +bool TabWidget::clearAllBackground(const QString &fileName, int marker) +{ + if (auto editor = d->findEditor(fileName)) { + editor->clearAllBackgroundColor(marker); + return true; + } + + return false; +} + +void TabWidget::showLineWidget(int line, QWidget *widget) +{ + if (auto editor = d->currentTextEditor()) + editor->showLineWidget(line, widget); +} + +void TabWidget::closeLineWidget() +{ + if (auto editor = d->currentTextEditor()) + editor->closeLineWidget(); +} + +void TabWidget::cursorPosition(int *line, int *index) +{ + if (!line || !index) + return; + + if (auto editor = d->currentTextEditor()) + editor->getCursorPosition(line, index); +} + TextEditor *TabWidget::currentEditor() const { return d->currentTextEditor(); diff --git a/src/plugins/codeeditor/gui/tabwidget.h b/src/plugins/codeeditor/gui/tabwidget.h index d6b909659..c1dbece00 100644 --- a/src/plugins/codeeditor/gui/tabwidget.h +++ b/src/plugins/codeeditor/gui/tabwidget.h @@ -65,6 +65,13 @@ class TabWidget : public QWidget int zoomValue(); void updateZoomValue(int value); + bool setRangeBackgroundColor(const QString &fileName, int startLine, int endLine, const QColor &color, int &marker); + bool clearRangeBackground(const QString &fileName, int startLine, int endLine, int marker); + bool clearAllBackground(const QString &fileName, int marker); + void showLineWidget(int line, QWidget *widget); + void closeLineWidget(); + void cursorPosition(int *line, int *index); + TextEditor *currentEditor() const; TextEditor *findEditor(const QString &fileName); diff --git a/src/plugins/codeeditor/gui/texteditor.cpp b/src/plugins/codeeditor/gui/texteditor.cpp index bcba52c4d..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 @@ -163,7 +163,7 @@ void TextEditor::addBreakpoint(int line, bool enabled) markerAdd(line, TextEditorPrivate::BreakpointDisabled); } - editor.breakpointAdded(d->fileName, line + 1, enabled); + editor.breakpointAdded(d->fileName, line, enabled); } void TextEditor::removeBreakpoint(int line) @@ -173,7 +173,7 @@ void TextEditor::removeBreakpoint(int line) else markerDelete(line, TextEditorPrivate::BreakpointDisabled); - editor.breakpointRemoved(d->fileName, line + 1); + editor.breakpointRemoved(d->fileName, line); } void TextEditor::toggleBreakpoint() @@ -198,12 +198,12 @@ void TextEditor::setBreakpointEnabled(int line, bool enabled) markerDelete(line, TextEditorPrivate::Breakpoint); markerAdd(line, TextEditorPrivate::BreakpointDisabled); } - editor.breakpointStatusChanged(d->fileName, line + 1, enabled); + editor.breakpointStatusChanged(d->fileName, line, enabled); } void TextEditor::setBreakpointCondition(int line) { - editor.setBreakpointCondition(d->fileName, line + 1); + editor.setBreakpointCondition(d->fileName, line); } bool TextEditor::breakpointEnabled(int line) @@ -329,20 +329,36 @@ int TextEditor::cursorPosition() return static_cast(SendScintilla(TextEditor::SCI_GETCURRENTPOS)); } -void TextEditor::setLineBackgroundColor(int line, const QColor &color) +int TextEditor::setRangeBackgroundColor(int startLine, int endLine, const QColor &color) { - markerAdd(line, TextEditorPrivate::CustomLineBackground); - setMarkerBackgroundColor(color, TextEditorPrivate::CustomLineBackground); + startLine = qMax(startLine, 0); + endLine = qMin(endLine, lines() - 1); + if (startLine > endLine) + return -1; + + int marker = markerDefine(Background); + for (; startLine <= endLine; ++startLine) { + markerAdd(startLine, marker); + } + + return marker; } -void TextEditor::resetLineBackgroundColor(int line) +void TextEditor::clearRangeBackgroundColor(int startLine, int endLine, int marker) { - markerDelete(line, TextEditorPrivate::CustomLineBackground); + startLine = qMax(startLine, 0); + endLine = qMin(endLine, lines() - 1); + if (startLine > endLine) + return; + + for (; startLine <= endLine; ++startLine) { + markerDelete(startLine, marker); + } } -void TextEditor::clearLineBackgroundColor() +void TextEditor::clearAllBackgroundColor(int marker) { - markerDeleteAll(TextEditorPrivate::CustomLineBackground); + markerDeleteAll(marker); } void TextEditor::showTips(const QString &tips) @@ -361,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) @@ -686,6 +715,21 @@ bool TextEditor::isAutomaticInvocationEnabled() const return d->isAutoCompletionEnabled; } +bool TextEditor::showLineWidget(int line, QWidget *widget) +{ + if (line < 0 || line >= lines()) + return false; + + d->showAtLine = line; + d->setContainerWidget(widget); + return true; +} + +void TextEditor::closeLineWidget() +{ + d->lineWidgetContainer->setVisible(false); +} + void TextEditor::onMarginClicked(int margin, int line, Qt::KeyboardModifiers state) { Q_UNUSED(state) @@ -762,6 +806,9 @@ void TextEditor::onCursorPositionChanged(int line, int index) void TextEditor::focusOutEvent(QFocusEvent *event) { + if (!d->lineWidgetContainer->hasFocus()) + d->lineWidgetContainer->setVisible(false); + Q_EMIT focusOut(); Q_EMIT followTypeEnd(); QsciScintilla::focusOutEvent(event); @@ -787,6 +834,33 @@ void TextEditor::mouseMoveEvent(QMouseEvent *event) QsciScintilla::mouseMoveEvent(event); } +void TextEditor::mouseReleaseEvent(QMouseEvent *event) +{ + QsciScintilla::mouseReleaseEvent(event); + + bool selChanged = hasSelectedText(); + if (!selChanged && d->selectionCache != std::make_tuple(-1, -1, -1, -1)) + selChanged = true; + + if (selChanged) { + int lineFrom = -1, indexFrom = -1, lineTo = -1, indexTo = -1; + getSelection(&lineFrom, &indexFrom, &lineTo, &indexTo); + d->selectionCache = std::make_tuple(lineFrom, indexFrom, lineTo, indexTo); + editor.selectionChanged(d->fileName, lineFrom, indexFrom, lineTo, indexTo); + } +} + +bool TextEditor::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == d->lineWidgetContainer && event->type() == QEvent::Resize) { + d->updateLineWidgetPosition(); + } else if (obj == d->mainWindow() && event->type() == QEvent::Move) { + d->updateLineWidgetPosition(); + } + + return QsciScintilla::eventFilter(obj, event); +} + bool TextEditor::event(QEvent *event) { if (!d) diff --git a/src/plugins/codeeditor/gui/texteditor.h b/src/plugins/codeeditor/gui/texteditor.h index f53ea9d08..b08da34fe 100644 --- a/src/plugins/codeeditor/gui/texteditor.h +++ b/src/plugins/codeeditor/gui/texteditor.h @@ -66,11 +66,12 @@ class TextEditor : public QsciScintilla void gotoPosition(int pos); int cursorLastPosition(); int cursorPosition(); - void setLineBackgroundColor(int line, const QColor &color); - void resetLineBackgroundColor(int line); - void clearLineBackgroundColor(); + int setRangeBackgroundColor(int startLine, int endLine, const QColor &color); + void clearRangeBackgroundColor(int startLine, int endLine, int marker); + 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); @@ -103,6 +104,8 @@ class TextEditor : public QsciScintilla void setAutomaticInvocationEnabled(bool enabled); bool isAutomaticInvocationEnabled() const; + bool showLineWidget(int line, QWidget *widget); + void closeLineWidget(); public slots: void onMarginClicked(int margin, int line, Qt::KeyboardModifiers state); @@ -114,6 +117,8 @@ public slots: virtual void focusOutEvent(QFocusEvent *event) override; virtual void keyPressEvent(QKeyEvent *event) override; virtual void mouseMoveEvent(QMouseEvent *event) override; + virtual void mouseReleaseEvent(QMouseEvent *event) override; + virtual bool eventFilter(QObject *obj, QEvent *event) override; virtual bool event(QEvent *event) override; signals: diff --git a/src/plugins/codeeditor/gui/workspacewidget.cpp b/src/plugins/codeeditor/gui/workspacewidget.cpp index 9049ca8fe..1686a1d26 100644 --- a/src/plugins/codeeditor/gui/workspacewidget.cpp +++ b/src/plugins/codeeditor/gui/workspacewidget.cpp @@ -1167,6 +1167,12 @@ TabWidget *WorkspaceWidget::currentTabWidget() const return d->currentTabWidget(); } +void WorkspaceWidget::cursorPosition(int *line, int *index) +{ + if (auto tabWidget = d->currentTabWidget()) + tabWidget->cursorPosition(line, index); +} + void WorkspaceWidget::registerWidget(const QString &id, AbstractEditWidget *widget) { d->registeredWidget.insert(id, widget); @@ -1186,6 +1192,58 @@ void WorkspaceWidget::switchDefaultWidget() d->stackWidget->setCurrentIndex(0); } +int WorkspaceWidget::setRangeBackgroundColor(const QString &fileName, int startLine, int endLine, const QColor &color) +{ + int marker = 0; + for (auto tabWidget : d->tabWidgetList) { + if (tabWidget->setRangeBackgroundColor(fileName, startLine, endLine, color, marker)) + break; + } + + return marker; +} + +void WorkspaceWidget::clearRangeBackgroundColor(const QString &fileName, int startLine, int endLine, int marker) +{ + for (auto tabWidget : d->tabWidgetList) { + if (tabWidget->clearRangeBackground(fileName, startLine, endLine, marker)) + break; + } +} + +void WorkspaceWidget::clearAllBackgroundColor(const QString &fileName, int marker) +{ + for (auto tabWidget : d->tabWidgetList) { + if (tabWidget->clearAllBackground(fileName, marker)) + break; + } +} + +void WorkspaceWidget::showLineWidget(int line, QWidget *widget) +{ + if (auto tabWidget = d->currentTabWidget()) + tabWidget->showLineWidget(line, widget); +} + +void WorkspaceWidget::closeLineWidget() +{ + if (auto tabWidget = d->currentTabWidget()) + 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 76773fbca..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; @@ -38,11 +40,22 @@ class WorkspaceWidget : public QWidget void replaceAll(const QString &fileName, const QString &oldText, const QString &newText, bool caseSensitive, bool wholeWords); void replaceRange(const QString &fileName, int line, int index, int length, const QString &after); TabWidget *currentTabWidget() const; + void cursorPosition(int *line, int *index); void registerWidget(const QString &id, AbstractEditWidget *widget); void switchWidget(const QString &id); void switchDefaultWidget(); + int setRangeBackgroundColor(const QString &fileName, int startLine, int endLine, const QColor &color); + void clearRangeBackgroundColor(const QString &fileName, int startLine, int endLine, int marker); + void clearAllBackgroundColor(const QString &fileName, int marker); + 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/plugins/codeeditor/symbol/symbolview.cpp b/src/plugins/codeeditor/symbol/symbolview.cpp index 65532bbc0..dfa3b9012 100644 --- a/src/plugins/codeeditor/symbol/symbolview.cpp +++ b/src/plugins/codeeditor/symbol/symbolview.cpp @@ -109,7 +109,7 @@ void SymbolViewPrivate::handleItemClicked(const QModelIndex &index) return; const auto &range = index.data(SymbolRangeRole).value(); - editor.gotoPosition(path, range.start.line + 1, range.start.character); + editor.gotoPosition(path, range.start.line, range.start.character); } else { if (QFileInfo(path).isDir()) { view->setExpanded(index, !view->isExpanded(index)); diff --git a/src/plugins/codeeditor/transceiver/codeeditorreceiver.cpp b/src/plugins/codeeditor/transceiver/codeeditorreceiver.cpp index 84e809123..fb567689d 100644 --- a/src/plugins/codeeditor/transceiver/codeeditorreceiver.cpp +++ b/src/plugins/codeeditor/transceiver/codeeditorreceiver.cpp @@ -23,9 +23,6 @@ CodeEditorReceiver::CodeEditorReceiver(QObject *parent) eventHandleMap.insert(editor.clearAllAnnotation.name, std::bind(&CodeEditorReceiver::processClearAllAnnotationEvent, this, _1)); eventHandleMap.insert(editor.setDebugLine.name, std::bind(&CodeEditorReceiver::processSetDebugLineEvent, this, _1)); eventHandleMap.insert(editor.removeDebugLine.name, std::bind(&CodeEditorReceiver::processRemoveDebugLineEvent, this, _1)); - eventHandleMap.insert(editor.setLineBackgroundColor.name, std::bind(&CodeEditorReceiver::processSetLineBackgroundColorEvent, this, _1)); - eventHandleMap.insert(editor.resetLineBackgroundColor.name, std::bind(&CodeEditorReceiver::processResetLineBackgroundEvent, this, _1)); - eventHandleMap.insert(editor.clearLineBackgroundColor.name, std::bind(&CodeEditorReceiver::processClearLineBackgroundEvent, this, _1)); eventHandleMap.insert(editor.addBreakpoint.name, std::bind(&CodeEditorReceiver::processAddBreakpointEvent, this, _1)); eventHandleMap.insert(editor.removeBreakpoint.name, std::bind(&CodeEditorReceiver::processRemoveBreakpointEvent, this, _1)); eventHandleMap.insert(editor.setBreakpointEnabled.name, std::bind(&CodeEditorReceiver::processSetBreakpointEnabledEvent, this, _1)); @@ -83,39 +80,18 @@ void CodeEditorReceiver::processForwardEvent(const dpf::Event &event) void CodeEditorReceiver::processGotoLineEvent(const dpf::Event &event) { QString filePath = event.property("fileName").toString(); - int line = event.property("line").toInt() - 1; + int line = event.property("line").toInt(); Q_EMIT EditorCallProxy::instance()->reqGotoLine(filePath, line); } void CodeEditorReceiver::processGotoPositionEvent(const dpf::Event &event) { QString filePath = event.property("fileName").toString(); - int line = event.property("line").toInt() - 1; + int line = event.property("line").toInt(); int col = event.property("column").toInt(); Q_EMIT EditorCallProxy::instance()->reqGotoPosition(filePath, line, col); } -void CodeEditorReceiver::processSetLineBackgroundColorEvent(const dpf::Event &event) -{ - QString filePath = event.property("fileName").toString(); - int line = event.property("line").toInt() - 1; - QColor color = qvariant_cast(event.property("color")); - Q_EMIT EditorCallProxy::instance()->reqSetLineBackgroundColor(filePath, line, color); -} - -void CodeEditorReceiver::processResetLineBackgroundEvent(const dpf::Event &event) -{ - QString filePath = event.property("fileName").toString(); - int line = event.property("line").toInt() - 1; - Q_EMIT EditorCallProxy::instance()->reqResetLineBackground(filePath, line); -} - -void CodeEditorReceiver::processClearLineBackgroundEvent(const dpf::Event &event) -{ - QString filePath = event.property("fileName").toString(); - Q_EMIT EditorCallProxy::instance()->reqClearLineBackground(filePath); -} - void CodeEditorReceiver::processSetModifiedAutoReloadEvent(const dpf::Event &event) { QString filePath = event.property("fileName").toString(); @@ -127,7 +103,7 @@ void CodeEditorReceiver::processAddAnnotationEvent(const dpf::Event &event) { QString filePath = event.property("fileName").toString(); QString title = event.property("title").toString(); - int line = event.property("line").toInt() - 1; + int line = event.property("line").toInt(); QString content = event.property("content").toString(); AnnotationType type = qvariant_cast(event.property("type")); Q_EMIT EditorCallProxy::instance()->reqAddAnnotation(filePath, title, content, line, type); @@ -149,7 +125,7 @@ void CodeEditorReceiver::processClearAllAnnotationEvent(const dpf::Event &event) void CodeEditorReceiver::processAddBreakpointEvent(const dpf::Event &event) { QString filePath = event.property("fileName").toString(); - int line = event.property("line").toInt() - 1; + int line = event.property("line").toInt(); bool enabled = event.property("enabled").toBool(); Q_EMIT EditorCallProxy::instance()->reqAddBreakpoint(filePath, line, enabled); } @@ -157,14 +133,14 @@ void CodeEditorReceiver::processAddBreakpointEvent(const dpf::Event &event) void CodeEditorReceiver::processRemoveBreakpointEvent(const dpf::Event &event) { QString filePath = event.property("fileName").toString(); - int line = event.property("line").toInt() - 1; + int line = event.property("line").toInt(); Q_EMIT EditorCallProxy::instance()->reqRemoveBreakpoint(filePath, line); } void CodeEditorReceiver::processSetBreakpointEnabledEvent(const dpf::Event &event) { QString filePath = event.property("fileName").toString(); - int line = event.property("line").toInt() - 1; + int line = event.property("line").toInt(); bool enabled = event.property("enabled").toBool(); Q_EMIT EditorCallProxy::instance()->reqSetBreakpointEnabled(filePath, line, enabled); } @@ -179,7 +155,7 @@ void CodeEditorReceiver::processClearAllBreakpointsEvent(const dpf::Event &event void CodeEditorReceiver::processSetDebugLineEvent(const dpf::Event &event) { QString filePath = event.property("fileName").toString(); - int line = event.property("line").toInt() - 1; + int line = event.property("line").toInt(); Q_EMIT EditorCallProxy::instance()->reqSetDebugLine(filePath, line); } diff --git a/src/plugins/codeeditor/transceiver/codeeditorreceiver.h b/src/plugins/codeeditor/transceiver/codeeditorreceiver.h index f36e22a53..37315c21c 100644 --- a/src/plugins/codeeditor/transceiver/codeeditorreceiver.h +++ b/src/plugins/codeeditor/transceiver/codeeditorreceiver.h @@ -25,9 +25,6 @@ class CodeEditorReceiver : public dpf::EventHandler, dpf::AutoEventHandlerRegist void processForwardEvent(const dpf::Event &event); void processGotoLineEvent(const dpf::Event &event); void processGotoPositionEvent(const dpf::Event &event); - void processSetLineBackgroundColorEvent(const dpf::Event &event); - void processResetLineBackgroundEvent(const dpf::Event &event); - void processClearLineBackgroundEvent(const dpf::Event &event); void processSetModifiedAutoReloadEvent(const dpf::Event &event); // annotation @@ -63,9 +60,6 @@ class EditorCallProxy : public QObject void reqForward(); void reqGotoLine(const QString &fileName, int line); void reqGotoPosition(const QString &fileName, int line, int column); - void reqSetLineBackgroundColor(const QString &fileName, int line, const QColor &color); - void reqResetLineBackground(const QString &fileName, int line); - void reqClearLineBackground(const QString &fileName); void reqSetModifiedAutoReload(const QString &fileName, bool flag); void reqDoRename(const newlsp::WorkspaceEdit &info); void reqCloseCurrentEditor(); diff --git a/src/plugins/codeporting/codeportingmanager.cpp b/src/plugins/codeporting/codeportingmanager.cpp index ec861eb7c..ee51cc661 100644 --- a/src/plugins/codeporting/codeportingmanager.cpp +++ b/src/plugins/codeporting/codeportingmanager.cpp @@ -8,6 +8,7 @@ #include "base/abstractwidget.h" #include "services/window/windowservice.h" #include "services/project/projectservice.h" +#include "services/editor/editorservice.h" #include "reportpane.h" #include @@ -84,15 +85,13 @@ void CodePortingManager::slotSelectedChanged(const QString &filePath, const QStr { Q_UNUSED(endLine) - int startLineInEditor = startLine + kLineNumberAdaptation; - int endLineInEditor = endLine + kLineNumberAdaptation; - editor.gotoLine(filePath, startLineInEditor); + editor.gotoLine(filePath, startLine); editor.addAnnotation(filePath, QString("CodePorting"), suggestion, startLine, AnnotationType::NoteAnnotation); QColor backgroundColor(Qt::red); backgroundColor.setAlpha(100); - for (int lineNumber = startLineInEditor; lineNumber <= endLineInEditor; ++lineNumber) { - editor.setLineBackgroundColor(filePath, lineNumber, backgroundColor); - } + + if (auto editSrv = dpfGetService(EditorService)) + editSrv->setRangeBackgroundColor(filePath, startLine, endLine, backgroundColor); } void CodePortingManager::slotAppendOutput(const QString &content, OutputPane::OutputFormat format, OutputPane::AppendMode mode) diff --git a/src/plugins/debugger/dap/dapdebugger.cpp b/src/plugins/debugger/dap/dapdebugger.cpp index cfd0bd54e..d770ae1f9 100644 --- a/src/plugins/debugger/dap/dapdebugger.cpp +++ b/src/plugins/debugger/dap/dapdebugger.cpp @@ -823,7 +823,7 @@ void DAPDebugger::handleEvents(const dpf::Event &event) for (auto index = 0; index < d->breakpointModel.breakpointSize(); index++) { auto bp = d->breakpointModel.BreakpointAt(index); if (bp.filePath == filePath) - editor.addBreakpoint(filePath, bp.lineNumber, bp.enabled); + editor.addBreakpoint(filePath, bp.lineNumber - 1, bp.enabled); } } } else if (event.data() == editor.fileClosed.name) { @@ -833,24 +833,24 @@ void DAPDebugger::handleEvents(const dpf::Event &event) } } else if (event.data() == editor.breakpointAdded.name) { QString filePath = event.property(editor.breakpointAdded.pKeys[0]).toString(); - int line = event.property(editor.breakpointAdded.pKeys[1]).toInt(); + int line = event.property(editor.breakpointAdded.pKeys[1]).toInt() + 1; if (d->bps.contains(filePath) && d->bps.values(filePath).contains(line)) return; d->bps.insert(filePath, line); addBreakpoint(filePath, line); } else if (event.data() == editor.breakpointRemoved.name) { QString filePath = event.property(editor.breakpointRemoved.pKeys[0]).toString(); - int line = event.property(editor.breakpointRemoved.pKeys[1]).toInt(); + int line = event.property(editor.breakpointRemoved.pKeys[1]).toInt() + 1; d->bps.remove(filePath, line); removeBreakpoint(filePath, line); } else if (event.data() == editor.breakpointStatusChanged.name) { QString filePath = event.property("fileName").toString(); - int line = event.property("line").toInt(); + int line = event.property("line").toInt() + 1; bool enabled = event.property("enabled").toBool(); switchBreakpointsStatus(filePath, line, enabled); } else if (event.data() == editor.setBreakpointCondition.name) { QString filePath = event.property("fileName").toString(); - int line = event.property("line").toInt(); + int line = event.property("line").toInt() + 1; DDialog condition; DLineEdit *edit = new DLineEdit(d->breakpointView); @@ -867,12 +867,12 @@ void DAPDebugger::handleEvents(const dpf::Event &event) } } else if (event.data() == editor.jumpToLine.name) { QString filePath = event.property("fileName").toString(); - int line = event.property("line").toInt(); + int line = event.property("line").toInt() + 1; jumpToLine(filePath, line); } else if (event.data() == editor.runToLine.name) { QString filePath = event.property("fileName").toString(); - int line = event.property("line").toInt(); + int line = event.property("line").toInt() + 1; runToLine(filePath, line); } @@ -1055,7 +1055,7 @@ void DAPDebugger::slotBreakpointSelected(const QModelIndex &index) { Q_UNUSED(index); auto curBP = d->breakpointModel.currentBreakpoint(); - editor.gotoLine(curBP.filePath, curBP.lineNumber); + editor.gotoLine(curBP.filePath, curBP.lineNumber - 1); } void DAPDebugger::slotGetChildVariable(const QModelIndex &index) @@ -1568,7 +1568,7 @@ void DAPDebugger::handleUpdateDebugLine() localFile = d->isRemote ? transformRemotePath(curFrame.file) : curFrame.file; if (QFileInfo(localFile).exists()) { - editor.setDebugLine(localFile, curFrame.line); + editor.setDebugLine(localFile, curFrame.line - 1); } else if (!curFrame.address.isEmpty()) { disassemble(curFrame.address); } diff --git a/src/plugins/debugger/interface/breakpointview.cpp b/src/plugins/debugger/interface/breakpointview.cpp index 0ebffdd6d..24ec34abe 100644 --- a/src/plugins/debugger/interface/breakpointview.cpp +++ b/src/plugins/debugger/interface/breakpointview.cpp @@ -108,9 +108,9 @@ void BreakpointView::enableBreakpoints(const QModelIndexList &rows) for (auto row : rows) { auto bp = bpModel->BreakpointAt(row.row()); if (openedFiles.contains(bp.filePath)) - editor.setBreakpointEnabled(bp.filePath, bp.lineNumber, true); + editor.setBreakpointEnabled(bp.filePath, bp.lineNumber - 1, true); else - editor.breakpointStatusChanged(bp.filePath, bp.lineNumber, true); + editor.breakpointStatusChanged(bp.filePath, bp.lineNumber - 1, true); } } @@ -121,9 +121,9 @@ void BreakpointView::disableBreakpoints(const QModelIndexList &rows) for (auto row : rows) { auto bp = bpModel->BreakpointAt(row.row()); if (openedFiles.contains(bp.filePath)) - editor.setBreakpointEnabled(bp.filePath, bp.lineNumber, false); + editor.setBreakpointEnabled(bp.filePath, bp.lineNumber - 1, false); else - editor.breakpointStatusChanged(bp.filePath, bp.lineNumber, false); + editor.breakpointStatusChanged(bp.filePath, bp.lineNumber - 1, false); } } @@ -134,9 +134,9 @@ void BreakpointView::removeBreakpoints(const QModelIndexList &rows) for (auto row : rows) { auto bp = bpModel->BreakpointAt(row.row()); if (openedFiles.contains(bp.filePath)) - editor.removeBreakpoint(bp.filePath, bp.lineNumber); + editor.removeBreakpoint(bp.filePath, bp.lineNumber - 1); else - editor.breakpointRemoved(bp.filePath, bp.lineNumber); + editor.breakpointRemoved(bp.filePath, bp.lineNumber - 1); } } @@ -145,7 +145,7 @@ void BreakpointView::editBreakpointCondition(const QModelIndex &index) BreakpointModel *bpModel = static_cast(model()); auto bp = bpModel->BreakpointAt(index.row()); - editor.setBreakpointCondition(bp.filePath, bp.lineNumber); + editor.setBreakpointCondition(bp.filePath, bp.lineNumber - 1); } void BreakpointView::initHeaderView() diff --git a/src/plugins/find/gui/searchresultwidget.cpp b/src/plugins/find/gui/searchresultwidget.cpp index eff00de54..2f54533ac 100644 --- a/src/plugins/find/gui/searchresultwidget.cpp +++ b/src/plugins/find/gui/searchresultwidget.cpp @@ -82,7 +82,7 @@ void SearchResultWidgetPrivate::openFile(const QModelIndex &index) if (!item) return; - editor.gotoPosition(item->filePathName, item->line, item->column); + editor.gotoPosition(item->filePathName, item->line - 1, item->column); } void SearchResultWidgetPrivate::handleMenuRequested(const QPoint &pos) diff --git a/src/plugins/symbol/mainframe/symbolkeeper.cpp b/src/plugins/symbol/mainframe/symbolkeeper.cpp index 3a578c2fe..71d8b9917 100644 --- a/src/plugins/symbol/mainframe/symbolkeeper.cpp +++ b/src/plugins/symbol/mainframe/symbolkeeper.cpp @@ -56,7 +56,7 @@ void SymbolKeeper::doParse(const SymbolParseArgs &args) void SymbolKeeper::jumpToLine(const QString &filePath, const QString &fileLine) { - editor.gotoLine(filePath, fileLine.toInt()); + editor.gotoLine(filePath, fileLine.toInt() - 1); } void SymbolKeeper::doParseDone(bool result) diff --git a/src/plugins/valgrind/mainframe/xmlstreamreader.cpp b/src/plugins/valgrind/mainframe/xmlstreamreader.cpp index 19f6815b7..d2db53c41 100644 --- a/src/plugins/valgrind/mainframe/xmlstreamreader.cpp +++ b/src/plugins/valgrind/mainframe/xmlstreamreader.cpp @@ -21,7 +21,7 @@ XmlStreamReader::XmlStreamReader(DTreeWidget *tree) if (toolTip.count() > 1) { QString filePath = toolTip.at(0); QString line = toolTip.at(1); - editor.gotoLine(filePath, line.toInt()); + editor.gotoLine(filePath, line.toInt() - 1); } }); } diff --git a/src/services/editor/editorservice.h b/src/services/editor/editorservice.h index 43a13a413..9a437a103 100644 --- a/src/services/editor/editorservice.h +++ b/src/services/editor/editorservice.h @@ -43,6 +43,7 @@ class EditorService final : public dpf::PluginService, DPF_INTERFACE(QString, currentFile); DPF_INTERFACE(QStringList, openedFiles); DPF_INTERFACE(QString, fileText, const QString &file); + DPF_INTERFACE(void, cursorPosition, int *line, int *index); DPF_INTERFACE(void, replaceAll, const QString &file, const QString &oldText, const QString &newText, bool caseSensitive, bool wholeWords); DPF_INTERFACE(void, replaceRange, const QString &file, int line, int index, int length, const QString &after); @@ -51,6 +52,19 @@ class EditorService final : public dpf::PluginService, DPF_INTERFACE(void, registerWidget, const QString &id, AbstractEditWidget *widget); DPF_INTERFACE(void, switchWidget, const QString &id); DPF_INTERFACE(void, switchDefaultWidget); + + // NOTE: Return the `marker` value, + // if the return value is -1, it indicates that the setting failed. + DPF_INTERFACE(int, setRangeBackgroundColor, const QString &file, int startLine, int endLine, const QColor &color); + DPF_INTERFACE(void, clearRangeBackgroundColor, const QString &file, int startLine, int endLine, int marker); + 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