diff --git a/lang/zh_CN/winghex_zh_CN.ts b/lang/zh_CN/winghex_zh_CN.ts index 5e9678c..c7cf1c3 100644 --- a/lang/zh_CN/winghex_zh_CN.ts +++ b/lang/zh_CN/winghex_zh_CN.ts @@ -478,12 +478,12 @@ 书签 - + Untitled 未命名 - + Not allowed operation in non-UI thread 该操作在非 UI 线程非法 @@ -865,18 +865,18 @@ MainWindow - + File 文件 - - + + View 视图 - + About 关于 @@ -897,317 +897,319 @@ 选长: - + Edit 编辑 - + Script 脚本 - - - + + + Plugin 插件 - + Setting 设置 - - + + Log 日志 - + ExportFindResult 导出搜索结果 - + ClearFindResult 清空记录 - - + + FindResult 搜索结果 - - - - + + + + Copy 复制 - - - - - + + + + + CopyToClipBoard 数据已拷贝到粘贴板 - + LittleEndian 小端 - + BigEndian 大端 - + Number 数值 - - + + CheckSum 校验和 - - + + DeleteBookMark 删除书签 - - + + ClearBookMark 清空书签 - - - - + + + + BookMark 书签 - - + + DecodeText 解码字符串 - + ScriptConsole 脚本控制台 - - + + Basic 基础 - + New 新建 - + OpenF 打开文件 - + OpenWorkSpace 打开工作区 - + RecentFiles 最近打开 - + + + Reload 重新加载 - - + + Save 保存 - + SaveAs 另存为 - + ConvertWS 转为工作区 - + Export 导出 - + SaveSel 保存选区字节 - - - - + + + + General 基本 - + Undo 撤销 - + Redo 恢复 - + Cut 剪切 - + Paste 粘贴 - + Delete 删除 - + Clone 克隆 - + Lookup 查询 - + Find 查找 - + Goto 跳转 - - + + Encoding 编码 - + FileInfo 文件信息 - - + + Hex 十六进制 - + CutHex 剪切(十六进制) - + CopyHex 复制(十六进制) - + PasteHex 粘贴(十六进制) - - + + Fill 填充 - + FillZero 填充零 - - - - - + + + + + MetaData 标注 - + DeleteMetadata 删除标注 - + ClearMetadata 清空标注 - + MetaDataEdit 编辑标注 - + DeleteMetaData 删除标注 - + ClearMetaData 清空标注 - + Display 显示 - + ViewText 文本预览 - + Scale 缩放 @@ -1242,781 +1244,793 @@ 加载插件中: - + SetupConsole 启动脚本控制台 - + SetupScriptManager 启动脚本管理器 - + SetupScriptService 启动脚本服务 - + SetupScriptEditor 构建脚本编辑器 - + SetupSetDialog 构建设置窗体 - + SetupPlgWidgets 启动插件组件 - + SetupDockingLayout 恢复 Dock 布局 - + SetupWaiting 启动即将完成 - + SetupFinished 启动完毕 - + NoExtension 无扩展 - - + + ExportResult 导出结果 - + NothingToSave 没有保存的数据 - + OpenExt 打开 - 拓展 - + ResetScale 重置缩放 - + ShowMetafg 标注前景色 - + ShowMetabg 标注背景色 - + ShowMetaComment 批注 - + MetaShowAll 显示所有标注 - + MetaHideAll 隐藏所有标注 - + FileStatus 文件状态 - + InfoSave 是否保存 - + ReadOnly 可读写 - + SetLocked 启用/禁用锁定编辑 - + ErrUnLock 锁定编辑失败 - + SetOver 启用/禁用改变大小 - + + InputRequest + + + + UnsignedHex 无符号 Hex - + BgScriptOutput 后台脚本输出 - + ErrUnOver 锁定文件大小失败 - + Window 窗体 - + Editor 编辑器 - + Tools 工具 - + HexEditorLayout 编辑器布局 - + SetBaseAddr 设置基址 - + addressBase 基址 - + inputAddressBase 请输入基址 - + WarnBigBaseAddress 基址过大,你得到的地址将会不正确! - + ErrBaseAddress 非法基址输入 - + SetColInfo 显示/隐藏地址栏 - + SetHeaderInfo 显示/隐藏表头 - + SetAsciiString 显示/隐藏解码字符串 - + Layout 布局 - + Fullscreen 全屏 - + Default 默认 - - - + + + LayoutRestoring... 恢复布局中... - + RestoreLayout 恢复布局 - - + + SaveLayout 保存布局 - + ExportLog 导出日志 - + ClearLog 清空日志 - + InsepctQt 监视 Qt - + ScriptEditor 脚本编辑器 - + Scripts 脚本仓库 - + PluginFunctions 插件功能 - + ScriptSetting 脚本设置 - + PluginSettings 插件设置 - + Info 信息 - + Software 软件 - + Sponsor 赞助 - + CheckUpdate 检查更新 - + Wiki 网页 Wiki - + AboutQT 关于 QT - + SetPageIDEmptyTryUseName 设置页 ID 为空,尝试使用名称作为 ID - + SetPageDupNameIgnored 设置页重复的 ID 名称,已忽略加载 - + Plugin %1 contains a duplicate ID (%2) that is already registered by plugin %3 插件 %1 包含重复 ID (%2),该 ID 已被插件 %3 注册 - - + + ChooseFile 选择文件 - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + Error 错误 - - + + FileNotExist 文件不存在! - - - - - + + + + + FilePermission 因文件权限无法继续! - + ProjectFile (*.wingpro) 项目文件 (*.wingpro) - + ReloadSuccessfully 文件重新加载成功! - + ReloadUnSuccessfully 文件重新加载失败! - - - - + + + + ChooseSaveFile 请选择保存文件路径: - + NoMoreClone 克隆已到上限,无法继续操作! - + FindFininishBusy 查找任务繁忙,请勿重复查找! - + MayTooMuchFindResult 搜索数量已到达上限,结果可能不全,建议请按区段搜索。 - + SaveLayoutSuccess 保存布局成功 - + SaveLayoutError 保存布局失败 - + HasClonedView 该编辑页已被克隆编辑,如果关闭,相关联的页也会被关闭,你确认继续吗? - + + + ReloadNeededYesOrNo + + + + SaveWorkSpace 保存工作区 - + WingHexWorkSpace (*.wingpro) 羽云十六进制工作区 (*.wingpro) - + ConfirmSave 正在关闭未保存的文件或工作区,你确定保存吗? - + [Info] 【信息】 - + [Warn] 【警告】 - + [Error] 【错误】 - + ConfirmAPPSave 你尝试关闭程序,但仍存在未保存的文件或工作区,你确定保存这些更改吗? - - - + + + SaveSuccessfully 保存成功! - - + + SaveWSError 保存工作区错误! - - + + Warn 警告 - + Opening... 打开文件中... - + WorkSpaceOpening... 打开工作区中... - + Reloading... 重载文件中... - + Saving... 保存中... - + SaveNewFirst 请首先保存新建的文件 - + AlreadyWorkSpace 已经是工作区,无需转化 - + ConvWorkSpaceFailed 转化为工作区失败 - + ConvWorkSpaceSuccess 转化为工作区成功 - + SavingAs... 另存为中... - + SaveUnSuccessfully 保存失败! - + Exporting... 导出中... - + ChooseExportFile 请选择导出文件路径: - + ExportSuccessfully 导出成功! - + ExportUnSuccessfully 导出失败! - + SavingSel... 保存选中字节中... - + SaveSelSuccess 保存选区字节成功! - + SaveSelError 保存选区字节失败,因文件不具有可写权限! - - + + CutToClipBoard 数据已剪切到粘贴板! - - + + UnCutToClipBoard 由于保持大小限制,数据剪切到粘贴板失败! - - + + UnCopyToClipBoard 由于保持大小限制,数据剪切到复制板失败! - - + + Finding... 查找中... - + DeleteSuccess 删除成功 - + DeleteFailed 删除失败 - + FindFininish 查找结果完毕! - + PleaseInputFill 请输入填充字节值 - + FillInputTruncWarn 填充输入数值过大,将会被截断填充 - + FillInputError 填充字节输入错误 - - + + InputComment 请输入批注: - - + + BookmarkDelSuccess 删除书签成功 - + BookmarkDelNoItem 无书签可删除 - + BookmarkClearSuccess 书签清空完毕 - - - + + + NoSelection 没有选区,无法继续的操作! - + NoMetaData 无可编辑标记 - + PleaseClearSel 请清空选择 - + MetaDelSuccess 元数据删除成功 - + MetaDelNoItem 无元数据可删除 - + MetaClearSuccess 元数据清空完毕 - + FindResultExporting... 查找结果导出中... - - + + EmptyFindResult 没有可导出的搜索结果! - + SaveFindResult 导出搜索结果成功! - + SaveFindResultError 导出结果失败! - + TooManyBytesDecode 超出解码字节限制…… - + NoTextFileMayInvalid 该文件不是文本文件,以文本方式预览并不是一个好的方式,你确认继续吗? - + LayoutSaving... 布局保存中... - + + PleaseInput 请输入 - + LogExporting... 日志导出中... - + ExportLogError 导出日志失败! - + ExportLogSuccess 导出日志成功,路径: - + ClearLogSuccess 清空日志成功! - + BadNetwork 无法与远程服务器的更新检查建立连接,请检查网络。 - + NewestVersion 当前软件为最新版本 - - + + OlderVersion 你使用的软件为老版本,建议到 Github 和 Gitee 的仓库发行版下载更新。 - + CheckingUpdate 检查更新中…… - + Too much opened files 打开的文件过多,无法继续操作! - + FilePermissionSure2Quit 因文件权限无法保存,你确认要退出吗? - + UnknownErrorSure2Quit 因未知错误无法保存,你确认要退出吗? - + WorkSpaceUnSavedSure2Quit 工作区文件无法保存,你确认要退出吗? - + CopyLimit 拷贝字节超出限制 - + ErrOpenFileBelow 打开文件出现错误(由于权限不足),如下为打开错误的文件: diff --git a/lang/zh_TW/winghex_zh_TW.ts b/lang/zh_TW/winghex_zh_TW.ts index e443ec8..7156f66 100644 --- a/lang/zh_TW/winghex_zh_TW.ts +++ b/lang/zh_TW/winghex_zh_TW.ts @@ -478,12 +478,12 @@ 書簽 - + Untitled 未命名 - + Not allowed operation in non-UI thread 該操作在非 UI 線程非法 @@ -865,18 +865,18 @@ MainWindow - + File - - + + View 視圖 - + About 關於 @@ -897,317 +897,319 @@ 選長: - + Edit 編輯 - + Script 腳本 - - - + + + Plugin 插件 - + Setting 設置 - - + + Log 日誌 - + ExportFindResult 導出搜索結果 - + ClearFindResult 清空記錄 - - + + FindResult 搜索結果 - - - - + + + + Copy 複製 - - - - - + + + + + CopyToClipBoard 數據已拷貝到粘貼板 - + LittleEndian 小端 - + BigEndian 大端 - + Number 數值 - - + + CheckSum 校驗和 - - + + DeleteBookMark 刪除書簽 - - + + ClearBookMark 清空書簽 - - - - + + + + BookMark 書簽 - - + + DecodeText 解碼字串 - + ScriptConsole 腳本控制臺 - - + + Basic 基礎 - + New 新建 - + OpenF 打開檔 - + OpenWorkSpace 打開工作區 - + RecentFiles 最近打開 - + + + Reload 重新加載 - - + + Save 保存 - + SaveAs 另存為 - + ConvertWS 轉為工作區 - + Export 導出 - + SaveSel 保存選區位元組 - - - - + + + + General 基本 - + Undo 撤銷 - + Redo 恢復 - + Cut 剪切 - + Paste 粘貼 - + Delete 刪除 - + Clone 克隆 - + Lookup 查詢 - + Find 查找 - + Goto 跳轉 - - + + Encoding 編碼 - + FileInfo 檔資訊 - - + + Hex 十六進制 - + CutHex 剪切(十六進制) - + CopyHex 複製(十六進制) - + PasteHex 粘貼(十六進制) - - + + Fill 填充 - + FillZero 填充零 - - - - - + + + + + MetaData 標注 - + DeleteMetadata 刪除標注 - + ClearMetadata 清空標注 - + MetaDataEdit 編輯標注 - + DeleteMetaData 刪除標注 - + ClearMetaData 清空標注 - + Display 顯示 - + ViewText 文本預覽 - + Scale 縮放 @@ -1242,781 +1244,793 @@ 加載插件中: - + SetupConsole 啟動腳本控制臺 - + SetupScriptManager 啟動腳本管理器 - + SetupScriptService 啟動腳本服務 - + SetupScriptEditor 構建腳本編輯器 - + SetupSetDialog 構建設置窗體 - + SetupPlgWidgets 啟動插件組件 - + SetupDockingLayout 恢復 Dock 佈局 - + SetupWaiting 啟動即將完成 - + SetupFinished 啟動完畢 - + NoExtension 無擴展 - - + + ExportResult 導出結果 - + NothingToSave 沒有保存的數據 - + OpenExt 打開 - 拓展 - + ResetScale 重置縮放 - + ShowMetafg 標注前景色 - + ShowMetabg 標注背景色 - + ShowMetaComment 批註 - + MetaShowAll 顯示所有標注 - + MetaHideAll 隱藏所有標注 - + FileStatus 檔狀態 - + InfoSave 是否保存 - + ReadOnly 可讀寫 - + SetLocked 啟用/禁用鎖定編輯 - + ErrUnLock 鎖定編輯失敗 - + SetOver 啟用/禁用改變大小 - + + InputRequest + + + + UnsignedHex 無符號 Hex - + BgScriptOutput 後臺腳本輸出 - + ErrUnOver 鎖定檔大小失敗 - + Window 窗體 - + Editor 編輯器 - + Tools 工具 - + HexEditorLayout 編輯器佈局 - + SetBaseAddr 設置基址 - + addressBase 基址 - + inputAddressBase 請輸入基址 - + WarnBigBaseAddress 基址過大,你得到的地址將會不正確! - + ErrBaseAddress 非法基址輸入 - + SetColInfo 顯示/隱藏地址欄 - + SetHeaderInfo 顯示/隱藏表頭 - + SetAsciiString 顯示/隱藏解碼字串 - + Layout 佈局 - + Fullscreen 全屏 - + Default 默認 - - - + + + LayoutRestoring... 恢復佈局中... - + RestoreLayout 恢復佈局 - - + + SaveLayout 保存佈局 - + ExportLog 導出日誌 - + ClearLog 清空日誌 - + InsepctQt 監視 Qt - + ScriptEditor 腳本編輯器 - + Scripts 腳本倉庫 - + PluginFunctions 插件功能 - + ScriptSetting 腳本設置 - + PluginSettings 插件設置 - + Info 資訊 - + Software 軟體 - + Sponsor 贊助 - + CheckUpdate 檢查更新 - + Wiki 網頁 Wiki - + AboutQT 關於 QT - + SetPageIDEmptyTryUseName 設置頁 ID 為空,嘗試使用名稱作為 ID - + SetPageDupNameIgnored 設置頁重複的 ID 名稱,已忽略加載 - + Plugin %1 contains a duplicate ID (%2) that is already registered by plugin %3 插件 %1 包含重複 ID (%2),該 ID 已被插件 %3 註冊 - - + + ChooseFile 選擇檔 - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + Error 錯誤 - - + + FileNotExist 檔不存在! - - - - - + + + + + FilePermission 因檔許可權無法繼續! - + ProjectFile (*.wingpro) 專案檔 (*.wingpro) - + ReloadSuccessfully 檔重新加載成功! - + ReloadUnSuccessfully 檔重新加載失敗! - - - - + + + + ChooseSaveFile 請選擇保存檔路徑: - + NoMoreClone 克隆已到上限,無法繼續操作! - + FindFininishBusy 查找任務繁忙,請勿重複查找! - + MayTooMuchFindResult 搜索數量已到達上限,結果可能不全,建議請按區段搜索。 - + SaveLayoutSuccess 保存佈局成功 - + SaveLayoutError 保存佈局失敗 - + HasClonedView 該編輯頁已被克隆編輯,如果關閉,相關聯的頁也會被關閉,你確認繼續嗎? - + + + ReloadNeededYesOrNo + + + + SaveWorkSpace 保存工作區 - + WingHexWorkSpace (*.wingpro) 羽雲十六進制工作區 (*.wingpro) - + ConfirmSave 正在關閉未保存的檔或工作區,你確定保存嗎? - + [Info] 【資訊】 - + [Warn] 【警告】 - + [Error] 【錯誤】 - + ConfirmAPPSave 你嘗試關閉程式,但仍存在未保存的檔或工作區,你確定保存這些更改嗎? - - - + + + SaveSuccessfully 保存成功! - - + + SaveWSError 保存工作區錯誤! - - + + Warn 警告 - + Opening... 打開檔中... - + WorkSpaceOpening... 打開工作區中... - + Reloading... 重載檔中... - + Saving... 保存中... - + SaveNewFirst 請首先保存新建的檔 - + AlreadyWorkSpace 已經是工作區,無需轉化 - + ConvWorkSpaceFailed 轉化為工作區失敗 - + ConvWorkSpaceSuccess 轉化為工作區成功 - + SavingAs... 另存為中... - + SaveUnSuccessfully 保存失敗! - + Exporting... 導出中... - + ChooseExportFile 請選擇導出檔路徑: - + ExportSuccessfully 導出成功! - + ExportUnSuccessfully 導出失敗! - + SavingSel... 保存選中位元組中... - + SaveSelSuccess 保存選區位元組成功! - + SaveSelError 保存選區位元組失敗,因檔不具有可寫許可權! - - + + CutToClipBoard 數據已剪切到粘貼板! - - + + UnCutToClipBoard 由於保持大小限制,數據剪切到粘貼板失敗! - - + + UnCopyToClipBoard 由於保持大小限制,數據剪切到複製板失敗! - - + + Finding... 查找中... - + DeleteSuccess 刪除成功 - + DeleteFailed 刪除失敗 - + FindFininish 查找結果完畢! - + PleaseInputFill 請輸入填充位元組值 - + FillInputTruncWarn 填充輸入數值過大,將會被截斷填充 - + FillInputError 填充位元組輸入錯誤 - - + + InputComment 請輸入批註: - - + + BookmarkDelSuccess 刪除書簽成功 - + BookmarkDelNoItem 無書簽可刪除 - + BookmarkClearSuccess 書簽清空完畢 - - - + + + NoSelection 沒有選區,無法繼續的操作! - + NoMetaData 無可編輯標記 - + PleaseClearSel 請清空選擇 - + MetaDelSuccess 元數據刪除成功 - + MetaDelNoItem 無元數據可刪除 - + MetaClearSuccess 元數據清空完畢 - + FindResultExporting... 查找結果導出中... - - + + EmptyFindResult 沒有可導出的搜索結果! - + SaveFindResult 導出搜索結果成功! - + SaveFindResultError 導出結果失敗! - + TooManyBytesDecode 超出解碼位元組限制…… - + NoTextFileMayInvalid 該檔不是文本檔,以文本方式預覽並不是一個好的方式,你確認繼續嗎? - + LayoutSaving... 佈局保存中... - + + PleaseInput 請輸入 - + LogExporting... 日誌導出中... - + ExportLogError 導出日誌失敗! - + ExportLogSuccess 導出日誌成功,路徑: - + ClearLogSuccess 清空日誌成功! - + BadNetwork 無法與遠程伺服器的更新檢查建立連接,請檢查網路。 - + NewestVersion 當前軟體為最新版本 - - + + OlderVersion 你使用的軟體為老版本,建議到 Github 和 Gitee 的倉庫發行版下載更新。 - + CheckingUpdate 檢查更新中…… - + Too much opened files 打開的檔過多,無法繼續操作! - + FilePermissionSure2Quit 因檔許可權無法保存,你確認要退出嗎? - + UnknownErrorSure2Quit 因未知錯誤無法保存,你確認要退出嗎? - + WorkSpaceUnSavedSure2Quit 工作區檔無法保存,你確認要退出嗎? - + CopyLimit 拷貝位元組超出限制 - + ErrOpenFileBelow 打開檔出現錯誤(由於許可權不足),如下為打開錯誤的檔: diff --git a/src/class/angelobjstring.cpp b/src/class/angelobjstring.cpp index 2076f60..758c2dc 100644 --- a/src/class/angelobjstring.cpp +++ b/src/class/angelobjstring.cpp @@ -69,7 +69,7 @@ QString AngelObjString::dictionaryToString(void *obj, asDebugger *dbg) { auto engine = dic->GetEngine(); - s << " ["; + s << " {"; asUINT n = 0; for (CScriptDictionary::CIterator it = dic->begin(); it != dic->end(); it++, n++) { @@ -88,7 +88,7 @@ QString AngelObjString::dictionaryToString(void *obj, asDebugger *dbg) { if (n < dic->GetSize() - 1) s << ", "; } - s << "]"; + s << "}"; return str; } diff --git a/src/class/ascompletion.cpp b/src/class/ascompletion.cpp index 0eee59b..868c42b 100644 --- a/src/class/ascompletion.cpp +++ b/src/class/ascompletion.cpp @@ -154,11 +154,6 @@ bool AsCompletion::processTrigger(const QString &trigger, auto code = content.toUtf8(); QList nodes; - QList docNodes; - - if (m_parseDocument) { - docNodes = parseDocument(); - } if (!trigger.isEmpty() && trigger != *DOT_TRIGGER) { clearFunctionTip(); @@ -226,24 +221,35 @@ bool AsCompletion::processTrigger(const QString &trigger, return false; } - QString prefix; auto etoken = tokens.back(); + // it can not be any trigger, so take the last as prefix + QString prefix = etoken.content; if (etoken.type == asTC_VALUE || etoken.type == asTC_COMMENT || etoken.type == asTC_UNKNOWN) { popup()->hide(); return false; } + if (trigger.isEmpty() && popup()->isVisible()) { + setCompletionPrefix(prefix); + return true; + } + + QList docNodes; + if (m_parseDocument) { + docNodes = parseDocument(); + } + // if trigger is empty, it's making editing if (trigger.isEmpty()) { - // it can not be any trigger, so take the last as prefix - prefix = etoken.content; tokens.removeLast(); if (tokens.isEmpty()) { applyEmptyNsNode(nodes, docNodes); } else { etoken = tokens.back(); // checking later } + } else { + prefix.clear(); } if (nodes.isEmpty()) { @@ -266,8 +272,52 @@ bool AsCompletion::processTrigger(const QString &trigger, } if (trigger == *DOT_TRIGGER) { - // member guessing ? - applyClassNodes(nodes); + // member type guessing ? basic match is enough. (>n<) + auto isBasicType = [](const QString &type) { + static QStringList basicType{ + "int", "int8", "int16", "int32", "int64", + "uint", "uint8", "uint16", "uint32", "uint64", + "float", "double", "byte"}; + + return basicType.contains(type); + }; + + auto clsNodes = parser.headerNodes(); + + // filter the type we can use to auto-complete in docNodes + for (auto &item : docNodes) { + if (item.type == CodeInfoTip::Type::Class) { + auto name = item.nameSpace; + if (name.isEmpty()) { + name = item.name; + } + clsNodes.insert(name, item.children); + } + // a typedef can only be used to define an alias + // for primitive types, so NO NEED for auto-completing + } + + tokens.removeLast(); + auto ns = getNamespace(tokens); + for (auto &item : docNodes) { + if (etoken.content == item.name && ns == item.nameSpace) { + auto retType = item.addinfo.value(CodeInfoTip::RetType); + + // auto type inference is not supported. + // PRs will be welcomed !!! + if (isBasicType(retType)) { + popup()->hide(); + return false; + } + + nodes.append(clsNodes.value(retType)); + break; + } + } + + if (nodes.isEmpty()) { + applyClassNodes(nodes); + } } else if (etoken.content.length() >= triggerAmount()) { // completion for a.b.c or a::b.c or a::b::c.d or ::a::b.c if (trigger == *DBL_COLON_TRIGGER) { @@ -368,6 +418,7 @@ QList AsCompletion::parseDocument() { va.dontAddGlobal = true; va.name = var.name; va.nameSpace = QString::fromUtf8(var.scope.join("::")); + va.addinfo.insert(CodeInfoTip::RetType, var.type); va.type = CodeInfoTip::Type::Variable; ret.append(va); } @@ -389,17 +440,47 @@ QList AsCompletion::parseDocument() { } break; case QAsCodeParser::SymbolType::TypeDef: - tip.type = CodeInfoTip::Type::KeyWord; + tip.type = CodeInfoTip::Type::TypeDef; break; case QAsCodeParser::SymbolType::Variable: + tip.addinfo.insert(CodeInfoTip::RetType, sym.type); tip.type = CodeInfoTip::Type::Variable; break; case QAsCodeParser::SymbolType::Class: case QAsCodeParser::SymbolType::Interface: - tip.type = CodeInfoTip::Type::Class; for (auto &mem : sym.children) { - // TODO + if (mem.vis != QAsCodeParser::Visiblity::Public) { + continue; + } + CodeInfoTip ctip; + ctip.name = mem.name; + ctip.nameSpace = QString::fromUtf8(mem.scope.join("::")); + if (mem.symtype == QAsCodeParser::SymbolType::Function) { + ctip.type = CodeInfoTip::Type::Function; + ctip.addinfo.insert(CodeInfoTip::RetType, + QString::fromUtf8(mem.type)); + ctip.addinfo.insert( + CodeInfoTip::Args, + QString::fromUtf8(mem.additonalInfo)); + for (auto &var : mem.children) { + CodeInfoTip va; + va.dontAddGlobal = true; + va.name = var.name; + va.nameSpace = + QString::fromUtf8(var.scope.join("::")); + va.addinfo.insert(CodeInfoTip::RetType, var.type); + va.type = CodeInfoTip::Type::Variable; + tip.children.append(va); + } + tip.children.append(ctip); + } else if (mem.symtype == + QAsCodeParser::SymbolType::Variable) { + ctip.addinfo.insert(CodeInfoTip::RetType, mem.type); + ctip.type = CodeInfoTip::Type::Variable; + tip.children.append(ctip); + } } + tip.type = CodeInfoTip::Type::Class; break; case QAsCodeParser::SymbolType::Invalid: case QAsCodeParser::SymbolType::Import: diff --git a/src/class/codeinfotip.cpp b/src/class/codeinfotip.cpp index c8c494f..673471d 100644 --- a/src/class/codeinfotip.cpp +++ b/src/class/codeinfotip.cpp @@ -36,6 +36,7 @@ QIcon CodeInfoTip::getDisplayIcon(Type type, CodeInfoVisibility vis) { case Type::Group: return icon(ICON_NAMESPACE); case Type::Class: + case Type::TypeDef: return icon(ICON_CLASS); case Type::ClsFunction: case Type::Function: diff --git a/src/class/codeinfotip.h b/src/class/codeinfotip.h index 7c17167..c9f4176 100644 --- a/src/class/codeinfotip.h +++ b/src/class/codeinfotip.h @@ -36,6 +36,7 @@ public: Variable, Property = Variable, Enumerater, + TypeDef }; enum CacheIndex { diff --git a/src/class/ctypeparser.cpp b/src/class/ctypeparser.cpp index 742644a..22d23a1 100644 --- a/src/class/ctypeparser.cpp +++ b/src/class/ctypeparser.cpp @@ -151,6 +151,9 @@ void CTypeParser::initialize() { ADD_TYPE(longlong, QMetaType::LongLong); ADD_TYPE_U(ulonglong, QMetaType::ULongLong); + using uint = unsigned int; + ADD_TYPE_U(uint, QMetaType::UInt); + using BOOL = bool; using BYTE = byte; using WORD = uint16; @@ -242,6 +245,8 @@ void CTypeParser::initialize() { #undef ADD_TYPE #undef ADD_TYPE_S + + base_types_ = type_maps_.keys(); } void CTypeParser::setIncludePaths(const QStringList &paths) { @@ -627,7 +632,7 @@ TokenTypes CTypeParser::getTokenType(const QString &token) const { return keywords_.value(token); } else if (qualifiers_.contains(token)) { return kQualifier; - } else if (type_maps_.contains(token)) { + } else if (base_types_.contains(token)) { return kBasicDataType; } else if (struct_defs_.contains(token)) { return kStructName; diff --git a/src/class/ctypeparser.h b/src/class/ctypeparser.h index bce5f61..62430da 100644 --- a/src/class/ctypeparser.h +++ b/src/class/ctypeparser.h @@ -211,6 +211,9 @@ private: /// @note All enum types have fixed size, so they're not stored QHash> type_maps_; + /// basic types + QStringList base_types_; + /// unsigned types QStringList unsigned_types_; diff --git a/src/class/qascodeparser.cpp b/src/class/qascodeparser.cpp index 76bb720..0c34f32 100644 --- a/src/class/qascodeparser.cpp +++ b/src/class/qascodeparser.cpp @@ -119,12 +119,26 @@ QAsCodeParser::parseIntell(qsizetype offset, continue; } break; - case SymbolType::Class: - sym.children = parseClassContent(offset, sym.scope, seg.codes); - break; - case SymbolType::Interface: - sym.children = parseInterfaceContent(offset, sym.scope, seg.codes); - break; + case SymbolType::Class: { + auto syms = + parseClassContent(offset - seg.offset, sym.scope, seg.codes); + // TODO: PRS, 'cause i have no need to code-complete a class + sym.inherit = syms.first; + sym.children = syms.second; + if (offset > seg.offset && offset < seg.end()) { + ret.append(syms.second); + } + } break; + case SymbolType::Interface: { + auto syms = parseInterfaceContent(offset - seg.offset, sym.scope, + seg.codes); + // TODO: PRS, 'cause i have no need to code-complete an interface + sym.inherit = syms.first; + sym.children = syms.second; + if (offset > seg.offset && offset < seg.end()) { + ret.append(syms.second); + } + } break; case SymbolType::Invalid: case SymbolType::Import: continue; @@ -510,7 +524,8 @@ QAsCodeParser::parseStatementBlock(const QByteArrayList &ns, QList ret; for (auto &symlist : syms) { for (auto &sym : symlist) { - if (sym.symtype == SymbolType::Variable) { + if (sym.symtype == SymbolType::Variable && + !sym.type.isEmpty()) { auto var = sym.name; auto n = std::find_if( ret.begin(), ret.end(), @@ -940,13 +955,14 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFuncDef() { auto begin = t1.pos; skipCodeBlock(); getToken(&t1); + rewindTo(&t1); auto end = t1.pos; // seg.name is empty seg.scope = currentNs; seg.offset = begin; seg.type = SymbolType::FnDef; - seg.codes = _code.sliced(begin, end - begin + 1); + seg.codes = _code.sliced(begin, end - begin); return seg; } @@ -1027,6 +1043,7 @@ void QAsCodeParser::superficiallyParseVarInit() { } while (indentParan || indentBrace || (t.type != ttListSeparator && t.type != ttEndStatement && t.type != ttEndStatementBlock)); + rewindTo(&t); } else if (t.type == ttOpenParenthesis) { sToken start = t; @@ -1308,6 +1325,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseTypedef() { auto begin = token.pos; skipCodeBlock(); getToken(&token); + rewindTo(&token); auto end = token.pos; // seg.name is empty @@ -1423,22 +1441,27 @@ QAsCodeParser::parseGlobalVarDecls(const QByteArrayList &ns, return parseDeclaration(ns, false, true); } -QAsCodeParser::CodeSegment QAsCodeParser::parseFunctionMethod() { +QAsCodeParser::CodeSegment QAsCodeParser::parseFunctionMethod(Visiblity &vis) { CodeSegment seg; sToken t1; getToken(&t1); + vis = Visiblity::Public; + // A class method can start with 'private' or 'protected' if (t1.type == ttPrivate) { rewindTo(&t1); parseToken(ttPrivate); getToken(&t1); + vis = Visiblity::Private; } else if (t1.type == ttProtected) { rewindTo(&t1); parseToken(ttProtected); getToken(&t1); + vis = Visiblity::Protected; } + if (_isSyntaxError) return seg; @@ -1530,12 +1553,13 @@ QAsCodeParser::parseFuncDefContent(const QByteArrayList &ns, return parseFuncDefContent(ns); } -QList +QPair> QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns, const QByteArray &code) { reset(); _code = code; + QByteArrayList inhertSyms; QList syms; sToken t; @@ -1544,32 +1568,30 @@ QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns, // Optional list of interfaces that are being implemented and classes that // are being inherited if (t.type == ttColon) { - Symbol inhertSym; + QByteArray inhertSym; // assuming it as an interface - inhertSym.symtype = SymbolType::Interface; - - Symbol isym; - isym.scope = parseOptionalScope(); - isym.name = getSymbolString(parseIdentifier()); - isym.symtype = SymbolType::Class; // assuming it as a class - - inhertSym.children.append(isym); - + inhertSym = parseOptionalScope().join("::"); + if (!inhertSym.isEmpty()) { + inhertSym += "::"; + } + inhertSym += getSymbolString(parseIdentifier()); + inhertSyms.append(inhertSym); getToken(&t); while (t.type == ttListSeparator) { - isym.scope = parseOptionalScope(); - isym.name = getSymbolString(parseIdentifier()); - inhertSym.children.append(isym); + inhertSym = parseOptionalScope().join("::"); + if (!inhertSym.isEmpty()) { + inhertSym += "::"; + } + inhertSym += getSymbolString(parseIdentifier()); + inhertSyms.append(inhertSym); getToken(&t); } - - syms.append(inhertSym); } if (t.type != ttStartStatementBlock) { rewindErrorTo(&t); - return syms; + return {inhertSyms, syms}; } // Parse properties @@ -1581,11 +1603,11 @@ QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns, auto fndef = parseFuncDefContent(ns); syms.append(fndef); } else if (isFuncDecl(true)) { - auto fn = parseFunctionMethod(); + Symbol sym; + auto fn = parseFunctionMethod(sym.vis); // add function symbols - Symbol sym; - sym.symtype = fn.type; + sym.symtype = SymbolType::Function; sym.scope = fn.scope; sym.offset = fn.offset; sym.name = fn.name; @@ -1595,7 +1617,8 @@ QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns, // deep parsing if (offset >= fn.offset && offset < fn.end()) { - auto ss = parseStatementBlock(fn.scope, fn.codes, offset); + auto ss = + parseStatementBlock(fn.scope, fn.codes, offset - fn.offset); syms.append(ss); } } else if (isVirtualPropertyDecl()) { @@ -1609,11 +1632,11 @@ QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns, getToken(&t); else { rewindErrorTo(&t); - return syms; + return {inhertSyms, syms}; } if (_isSyntaxError) - return syms; + return {inhertSyms, syms}; getToken(&t); rewindTo(&t); @@ -1622,15 +1645,16 @@ QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns, getToken(&t); if (t.type != ttEndStatementBlock) { rewindErrorTo(&t); - return syms; + return {inhertSyms, syms}; } - return syms; + return {inhertSyms, syms}; } -QList +QPair> QAsCodeParser::parseInterfaceContent(qsizetype offset, const QByteArrayList &ns, const QByteArray &code) { + QByteArrayList inhertSyms; QList syms; sToken t; @@ -1638,12 +1662,22 @@ QAsCodeParser::parseInterfaceContent(qsizetype offset, const QByteArrayList &ns, getToken(&t); // Can optionally have a list of interfaces that are inherited if (t.type == ttColon) { - parseOptionalScope(); - parseIdentifier(); + QByteArray inhertSym; + + inhertSym = parseOptionalScope().join("::"); + if (!inhertSym.isEmpty()) { + inhertSym += "::"; + } + inhertSym += getSymbolString(parseIdentifier()); + inhertSyms.append(inhertSym); getToken(&t); while (t.type == ttListSeparator) { - parseOptionalScope(); - parseIdentifier(); + inhertSym = parseOptionalScope().join("::"); + if (!inhertSym.isEmpty()) { + inhertSym += "::"; + } + inhertSym += getSymbolString(parseIdentifier()); + inhertSyms.append(inhertSym); getToken(&t); } } @@ -1670,7 +1704,7 @@ QAsCodeParser::parseInterfaceContent(qsizetype offset, const QByteArrayList &ns, } if (_isSyntaxError) - return syms; + return {inhertSyms, syms}; getToken(&t); rewindTo(&t); @@ -1679,10 +1713,10 @@ QAsCodeParser::parseInterfaceContent(qsizetype offset, const QByteArrayList &ns, getToken(&t); if (t.type != ttEndStatementBlock) { rewindErrorTo(&t); - return syms; + return {inhertSyms, syms}; } - return syms; + return {inhertSyms, syms}; } QAsCodeParser::Symbol QAsCodeParser::parseInterfaceMethod() { diff --git a/src/class/qascodeparser.h b/src/class/qascodeparser.h index bfd6742..132dd2f 100644 --- a/src/class/qascodeparser.h +++ b/src/class/qascodeparser.h @@ -90,6 +90,7 @@ public: Visiblity vis = QAsCodeParser::Visiblity::Public; QByteArray additonalInfo; // for other additonal info + QByteArrayList inherit; QList children; }; @@ -134,7 +135,7 @@ private: CodeSegment parseInterface(); CodeSegment parseFuncDef(); CodeSegment parseFunction(); - CodeSegment parseFunctionMethod(); + CodeSegment parseFunctionMethod(Visiblity &vis); private: // parse tokens @@ -172,12 +173,13 @@ private: Symbol parseFuncDefContent(const QByteArrayList &ns); - QList parseClassContent(qsizetype offset, const QByteArrayList &ns, - const QByteArray &code); + QPair> + parseClassContent(qsizetype offset, const QByteArrayList &ns, + const QByteArray &code); - QList parseInterfaceContent(qsizetype offset, - const QByteArrayList &ns, - const QByteArray &code); + QPair> + parseInterfaceContent(qsizetype offset, const QByteArrayList &ns, + const QByteArray &code); QList parseStatementBlock(const QByteArrayList &ns, const QByteArray &code, qsizetype end); diff --git a/src/control/editorview.cpp b/src/control/editorview.cpp index e05b0ab..95b914d 100644 --- a/src/control/editorview.cpp +++ b/src/control/editorview.cpp @@ -121,6 +121,9 @@ EditorView::EditorView(QWidget *parent) m_metadata->setDocument(doc); }); + connect(&_watcher, &QFileSystemWatcher::fileChanged, this, + &EditorView::need2Reload); + applySettings(); // build up call tables @@ -284,6 +287,9 @@ ErrFile EditorView::newFile(size_t index) { if (isCloneFile()) { return ErrFile::ClonedFile; } + if (!m_fileName.isEmpty()) { + _watcher.removePath(m_fileName); + } auto istr = QString::number(index); m_fileName = tr("Untitled") + istr; this->setWindowTitle(m_fileName); @@ -320,6 +326,10 @@ ErrFile EditorView::openFile(const QString &filename) { return ErrFile::Permission; } + if (!m_fileName.isEmpty()) { + _watcher.removePath(m_fileName); + } + m_hex->setDocument(QSharedPointer(p)); m_hex->setLockedFile(readonly); m_hex->setKeepSize(true); @@ -335,6 +345,8 @@ ErrFile EditorView::openFile(const QString &filename) { auto tab = this->tabWidget(); tab->setIcon(Utilities::getIconFromFile(style(), m_fileName)); tab->setToolTip(m_fileName); + + _watcher.addPath(m_fileName); } return ErrFile::Success; @@ -372,6 +384,10 @@ ErrFile EditorView::openExtFile(const QString &ext, const QString &file) { return ErrFile::Error; } + if (!m_fileName.isEmpty()) { + _watcher.removePath(m_fileName); + } + m_hex->setDocument(QSharedPointer(p)); m_hex->setLockedFile(readonly); m_hex->setKeepSize(true); @@ -562,10 +578,14 @@ ErrFile EditorView::save(const QString &workSpaceName, const QString &path, file.close(); if (!isExport) { + if (!m_fileName.isEmpty()) { + _watcher.removePath(m_fileName); + } m_fileName = QFileInfo(fileName).absoluteFilePath(); m_isNewFile = false; m_docType = DocumentType::File; doc->setDocSaved(); + _watcher.addPath(m_fileName); } #ifdef Q_OS_LINUX adjustPermission(); diff --git a/src/control/editorview.h b/src/control/editorview.h index e382811..405884e 100644 --- a/src/control/editorview.h +++ b/src/control/editorview.h @@ -18,6 +18,7 @@ #ifndef EDITORVIEW_H #define EDITORVIEW_H +#include #include #include @@ -553,6 +554,8 @@ signals: void sigOnMetadata(); void sigOnBookMark(); + void need2Reload(); + protected: bool eventFilter(QObject *watched, QEvent *event) override; @@ -589,6 +592,7 @@ private: QReadWriteLock _rwlock; CallTable _viewFns; + QFileSystemWatcher _watcher; }; #endif // EDITORVIEW_H diff --git a/src/dialog/mainwindow.cpp b/src/dialog/mainwindow.cpp index 08df9d5..7648947 100644 --- a/src/dialog/mainwindow.cpp +++ b/src/dialog/mainwindow.cpp @@ -245,7 +245,8 @@ MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() { sm.registerCallBack(ScriptMachine::Interactive, callbacks); callbacks.getInputFn = [this]() -> QString { - return WingInputDialog::getText(this, tr(""), tr("")); + return WingInputDialog::getText(this, tr("InputRequest"), + tr("PleaseInput")); }; callbacks.clearFn = [this]() { m_bgScriptOutput->clear(); }; callbacks.printMsgFn = @@ -3162,6 +3163,22 @@ void MainWindow::connectEditorView(EditorView *editor) { connect(editor, &EditorView::sigOnPasteHex, this, &MainWindow::on_pastehex); connect(editor, &EditorView::sigOnPasteFile, this, &MainWindow::on_pastefile); + + editor->setProperty("__RELOAD__", false); + connect(editor, &EditorView::need2Reload, this, [editor, this]() { + if (editor->isBigFile()) { + editor->reload(); + } + if (currentEditor() == editor) { + auto ret = WingMessageBox::question(this, tr("Reload"), + tr("ReloadNeededYesOrNo")); + if (ret == QMessageBox::Yes) { + editor->reload(); + } + } else { + editor->setProperty("__RELOAD__", true); + } + }); } void MainWindow::swapEditor(EditorView *old, EditorView *cur) { @@ -3188,6 +3205,15 @@ void MainWindow::swapEditor(EditorView *old, EditorView *cur) { Q_ASSERT(cur); auto hexeditor = cur->hexEditor(); + auto needReload = cur->property("__RELOAD__").toBool(); + if (needReload) { + auto ret = WingMessageBox::question(this, tr("Reload"), + tr("ReloadNeededYesOrNo")); + if (ret == QMessageBox::Yes) { + cur->reload(); + } + cur->setProperty("__RELOAD__", false); + } connect(hexeditor, &QHexView::cursorLocationChanged, this, &MainWindow::on_locChanged); connect(hexeditor, &QHexView::cursorSelectionChanged, this,