summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2021-10-19 02:21:47 +0800
committerchai <chaifix@163.com>2021-10-19 02:21:47 +0800
commit8446078851f5430e8315d6618d8d5dd9d6e3d1ab (patch)
treeecbbd9ae71367eebf3a4e414373f92a3f0a2cd44
parent45c05ac5610416e75a123995af649681d43adf7f (diff)
+LuaPanda
-rw-r--r--.gitignore1
-rw-r--r--Editor/EditorMain.cpp42
-rw-r--r--Editor/Path.cpp0
-rw-r--r--Editor/Path.h0
-rw-r--r--Editor/Win/Win.cpp18
-rw-r--r--Editor/Win/Win.h14
-rw-r--r--Projects/VisualStudio/Editor/Editor.vcxproj4
-rw-r--r--Projects/VisualStudio/Editor/Editor.vcxproj.filters15
-rw-r--r--Projects/VisualStudio/Editor/Editor.vcxproj.user2
-rw-r--r--Projects/VisualStudio/GameLab.sln11
-rw-r--r--Projects/VisualStudio/ImGUI/ImGUI.vcxproj122
-rw-r--r--Projects/VisualStudio/ImGUI/ImGUI.vcxproj.filters2
-rw-r--r--Projects/VisualStudio/ImGUI/ImGUI.vcxproj.user4
-rw-r--r--Resources/Libraries/LuaPanda.lua3606
-rw-r--r--Resources/Libraries/socket/core.dllbin0 -> 104448 bytes
-rw-r--r--Resources/Scripts/EditorApplication.lua6
-rw-r--r--Resources/readme.txt8
17 files changed, 3684 insertions, 171 deletions
diff --git a/.gitignore b/.gitignore
index 6e267df..5116dc2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
/Projects/VisualStudio/.vs
/Projects/VisualStudio/x64
/Projects/VisualStudio/*/x64
+/Resources/.vscode \ No newline at end of file
diff --git a/Editor/EditorMain.cpp b/Editor/EditorMain.cpp
index f8ee4ef..5e0cf99 100644
--- a/Editor/EditorMain.cpp
+++ b/Editor/EditorMain.cpp
@@ -1,40 +1,15 @@
#include <windows.h>
#include <vector>
+
#include "GUI/EditorWindows.h"
#include "Runtime/Lua/LuaBind/LuaBind.h"
#include "EditorManager.h"
#include "Runtime/Graphics/OpenGL.h"
#include "Editor/Scripting/EditorScripting.h"
+#include "Editor/Win/Win.h"
using namespace LuaBind;
-static int MainLoop()
-{
- BOOL returnValue;
- MSG msg, lastMsg;
- msg.message = WM_NULL;
- std::vector<MSG> messages;
- PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE);
- bool isQuitSignaled = msg.message == WM_QUIT;
-
- while (!isQuitSignaled)
- {
- MSG msg;
- while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) != 0)
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
-
- if (msg.message == WM_QUIT)
- isQuitSignaled = true;
-
- }
-
- }
-
- return (INT)msg.wParam;
-}
-
void ErrorHandle(cc8* msg)
{
log_error(std::string("[Lua] ") + msg);
@@ -50,7 +25,18 @@ void InitLuaState()
log_error("Can't setup scripting.");
}
LuaBind::State state = vm.GetMainState();
- state.DoFile("./Scripts/EditorApplication.lua", ErrorHandle);
+
+ // https://stackoverflow.com/questions/21495901/loadlibrarya-and-relative-path/21495971
+ // ll_load装载dll,路径需要设置搜索路径
+ //log_info(Win::GetCurrentWorkingDirectory());
+ std::string workingDir = Win::GetCurrentWorkingDirectory();
+ Win::SetDllSearchDirectory(workingDir);
+
+ // set cpath
+ state.DoString(R"(package.path=package.path .. ";" .. ".\\Libraries\\?.lua")");
+ state.DoString(R"(package.cpath=package.cpath .. ";" .. ".\\Libraries\\?.dll")");
+
+ state.DoFile(".\\Scripts\\EditorApplication.lua", ErrorHandle);
}
#ifdef GAMELAB_DEBUG
diff --git a/Editor/Path.cpp b/Editor/Path.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Editor/Path.cpp
diff --git a/Editor/Path.h b/Editor/Path.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Editor/Path.h
diff --git a/Editor/Win/Win.cpp b/Editor/Win/Win.cpp
new file mode 100644
index 0000000..f6310e2
--- /dev/null
+++ b/Editor/Win/Win.cpp
@@ -0,0 +1,18 @@
+#include "win.h"
+
+namespace Win
+{
+
+ std::string GetCurrentWorkingDirectory()
+ {
+ char path[MAX_PATH];
+ GetCurrentDirectory(MAX_PATH, path);
+ return path;
+ }
+
+ void SetDllSearchDirectory(std::string path)
+ {
+ SetDllDirectory(path.c_str());
+ }
+
+} \ No newline at end of file
diff --git a/Editor/Win/Win.h b/Editor/Win/Win.h
new file mode 100644
index 0000000..cbbba4c
--- /dev/null
+++ b/Editor/Win/Win.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <windows.h>
+#include <string>
+
+// windows 辅助函数
+
+namespace Win
+{
+
+ std::string GetCurrentWorkingDirectory();
+ void SetDllSearchDirectory(std::string path);
+
+}
diff --git a/Projects/VisualStudio/Editor/Editor.vcxproj b/Projects/VisualStudio/Editor/Editor.vcxproj
index 8dfc5c6..ab1a930 100644
--- a/Projects/VisualStudio/Editor/Editor.vcxproj
+++ b/Projects/VisualStudio/Editor/Editor.vcxproj
@@ -156,6 +156,7 @@
<ClCompile Include="..\..\..\Editor\GUI\WindowUtil.cpp" />
<ClCompile Include="..\..\..\Editor\GUI\WinUtils.cpp" />
<ClCompile Include="..\..\..\Editor\IMGUI\GUIButton.cpp" />
+ <ClCompile Include="..\..\..\Editor\Path.cpp" />
<ClCompile Include="..\..\..\Editor\Resource\ResourceManager.cpp" />
<ClCompile Include="..\..\..\Editor\Scripting\EditorGUI\ContainerWindow.bind.cpp" />
<ClCompile Include="..\..\..\Editor\Scripting\EditorGUI\EditorGUI.bind.cpp" />
@@ -167,6 +168,7 @@
<ClCompile Include="..\..\..\Editor\Scripting\IMGUI\GUIButton.bind.cpp" />
<ClCompile Include="..\..\..\Editor\Shaders\BuiltinShaders.cpp" />
<ClCompile Include="..\..\..\Editor\Utils\HelperFuncs.cpp" />
+ <ClCompile Include="..\..\..\Editor\Win\Win.cpp" />
<ClCompile Include="..\..\..\Runtime\Debug\Log.cpp" />
<ClCompile Include="..\..\..\Runtime\Graphics\OpenGL.cpp" />
<ClCompile Include="..\..\..\Runtime\Lua\LuaBind\LuaBindCFunctions.cpp" />
@@ -195,10 +197,12 @@
<ClInclude Include="..\..\..\Editor\GUI\MenuManager.h" />
<ClInclude Include="..\..\..\Editor\GUI\Rect.h" />
<ClInclude Include="..\..\..\Editor\GUI\WinUtils.h" />
+ <ClInclude Include="..\..\..\Editor\Path.h" />
<ClInclude Include="..\..\..\Editor\Resource\ResourceManager.h" />
<ClInclude Include="..\..\..\Editor\Scripting\EditorScripting.h" />
<ClInclude Include="..\..\..\Editor\Shaders\BuiltinShaders.h" />
<ClInclude Include="..\..\..\Editor\Utils\HelperFuncs.h" />
+ <ClInclude Include="..\..\..\Editor\Win\Win.h" />
<ClInclude Include="..\..\..\Runtime\Debug\Log.h" />
<ClInclude Include="..\..\..\Runtime\Graphics\OpenGL.h" />
<ClInclude Include="..\..\..\Runtime\Lua\LuaBind\LuaBind.h" />
diff --git a/Projects/VisualStudio/Editor/Editor.vcxproj.filters b/Projects/VisualStudio/Editor/Editor.vcxproj.filters
index 5062a9f..df356e4 100644
--- a/Projects/VisualStudio/Editor/Editor.vcxproj.filters
+++ b/Projects/VisualStudio/Editor/Editor.vcxproj.filters
@@ -73,6 +73,9 @@
<Filter Include="Runtime\Lua\LuaBind">
<UniqueIdentifier>{f9573ff2-4a53-4953-806e-f0ce0c586910}</UniqueIdentifier>
</Filter>
+ <Filter Include="Editor\Win">
+ <UniqueIdentifier>{c2d9fa5b-8087-48e3-90b7-b5e6d02be909}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\Editor\GUI\Dock.cpp">
@@ -204,6 +207,12 @@
<ClCompile Include="..\..\..\Runtime\Lua\LuaHelper.cpp">
<Filter>Runtime\Lua</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\Editor\Win\Win.cpp">
+ <Filter>Editor\Win</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\Editor\Path.cpp">
+ <Filter>Editor</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\Editor\GUI\Dock.h">
@@ -335,6 +344,12 @@
<ClInclude Include="..\..\..\Runtime\Lua\LuaHelper.h">
<Filter>Runtime\Lua</Filter>
</ClInclude>
+ <ClInclude Include="..\..\..\Editor\Win\Win.h">
+ <Filter>Editor\Win</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\Editor\Path.h">
+ <Filter>Editor</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\Runtime\Lua\LuaBind\LuaBindClass.inc">
diff --git a/Projects/VisualStudio/Editor/Editor.vcxproj.user b/Projects/VisualStudio/Editor/Editor.vcxproj.user
index f86de5d..d353c78 100644
--- a/Projects/VisualStudio/Editor/Editor.vcxproj.user
+++ b/Projects/VisualStudio/Editor/Editor.vcxproj.user
@@ -5,6 +5,6 @@
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup>
- <ShowAllFiles>true</ShowAllFiles>
+ <ShowAllFiles>false</ShowAllFiles>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/Projects/VisualStudio/GameLab.sln b/Projects/VisualStudio/GameLab.sln
index aac6292..27e8383 100644
--- a/Projects/VisualStudio/GameLab.sln
+++ b/Projects/VisualStudio/GameLab.sln
@@ -23,8 +23,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stb", "stb\stb.vcxproj", "{
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib.vcxproj", "{49F29C84-8A46-4421-9F93-CA96A9292716}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImGUI", "ImGUI\ImGUI.vcxproj", "{A93844EE-1BF4-42A9-B58C-27192721A063}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -105,14 +103,6 @@ Global
{49F29C84-8A46-4421-9F93-CA96A9292716}.Release|x64.Build.0 = Release|x64
{49F29C84-8A46-4421-9F93-CA96A9292716}.Release|x86.ActiveCfg = Release|Win32
{49F29C84-8A46-4421-9F93-CA96A9292716}.Release|x86.Build.0 = Release|Win32
- {A93844EE-1BF4-42A9-B58C-27192721A063}.Debug|x64.ActiveCfg = Debug|x64
- {A93844EE-1BF4-42A9-B58C-27192721A063}.Debug|x64.Build.0 = Debug|x64
- {A93844EE-1BF4-42A9-B58C-27192721A063}.Debug|x86.ActiveCfg = Debug|Win32
- {A93844EE-1BF4-42A9-B58C-27192721A063}.Debug|x86.Build.0 = Debug|Win32
- {A93844EE-1BF4-42A9-B58C-27192721A063}.Release|x64.ActiveCfg = Release|x64
- {A93844EE-1BF4-42A9-B58C-27192721A063}.Release|x64.Build.0 = Release|x64
- {A93844EE-1BF4-42A9-B58C-27192721A063}.Release|x86.ActiveCfg = Release|Win32
- {A93844EE-1BF4-42A9-B58C-27192721A063}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -125,7 +115,6 @@ Global
{AD09415F-4BF9-4FCE-901F-7AB22D429CFC} = {0F6EE105-E1FF-4770-8314-06F9F98FB68F}
{BFAA8A26-DE6F-4B71-8851-3FF3CF0C8B9F} = {0F6EE105-E1FF-4770-8314-06F9F98FB68F}
{49F29C84-8A46-4421-9F93-CA96A9292716} = {0F6EE105-E1FF-4770-8314-06F9F98FB68F}
- {A93844EE-1BF4-42A9-B58C-27192721A063} = {0F6EE105-E1FF-4770-8314-06F9F98FB68F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C78D376C-9B0B-4EF0-A7D1-0F612F43E793}
diff --git a/Projects/VisualStudio/ImGUI/ImGUI.vcxproj b/Projects/VisualStudio/ImGUI/ImGUI.vcxproj
deleted file mode 100644
index 615e945..0000000
--- a/Projects/VisualStudio/ImGUI/ImGUI.vcxproj
+++ /dev/null
@@ -1,122 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
- <ProjectGuid>{A93844EE-1BF4-42A9-B58C-27192721A063}</ProjectGuid>
- <RootNamespace>ImGUI</RootNamespace>
- <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>MultiByte</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>MultiByte</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>MultiByte</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>MultiByte</CharacterSet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <SDLCheck>true</SDLCheck>
- <ConformanceMode>true</ConformanceMode>
- </ClCompile>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <SDLCheck>true</SDLCheck>
- <ConformanceMode>true</ConformanceMode>
- </ClCompile>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <SDLCheck>true</SDLCheck>
- <ConformanceMode>true</ConformanceMode>
- </ClCompile>
- <Link>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <SDLCheck>true</SDLCheck>
- <ConformanceMode>true</ConformanceMode>
- </ClCompile>
- <Link>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- </Link>
- </ItemDefinitionGroup>
- <ItemGroup>
- </ItemGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
- <ImportGroup Label="ExtensionTargets">
- </ImportGroup>
-</Project> \ No newline at end of file
diff --git a/Projects/VisualStudio/ImGUI/ImGUI.vcxproj.filters b/Projects/VisualStudio/ImGUI/ImGUI.vcxproj.filters
deleted file mode 100644
index 9cd8510..0000000
--- a/Projects/VisualStudio/ImGUI/ImGUI.vcxproj.filters
+++ /dev/null
@@ -1,2 +0,0 @@
-锘<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" /> \ No newline at end of file
diff --git a/Projects/VisualStudio/ImGUI/ImGUI.vcxproj.user b/Projects/VisualStudio/ImGUI/ImGUI.vcxproj.user
deleted file mode 100644
index be25078..0000000
--- a/Projects/VisualStudio/ImGUI/ImGUI.vcxproj.user
+++ /dev/null
@@ -1,4 +0,0 @@
-锘<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup />
-</Project> \ No newline at end of file
diff --git a/Resources/Libraries/LuaPanda.lua b/Resources/Libraries/LuaPanda.lua
new file mode 100644
index 0000000..c5c307c
--- /dev/null
+++ b/Resources/Libraries/LuaPanda.lua
@@ -0,0 +1,3606 @@
+-- Tencent is pleased to support the open source community by making LuaPanda available.
+-- Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+-- Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+-- https://opensource.org/licenses/BSD-3-Clause
+-- Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+
+-- API:
+-- LuaPanda.printToVSCode(logStr, printLevel, type)
+-- 鎵撳嵃鏃ュ織鍒癡SCode Output涓 LuaPanda Debugger 涓
+-- @printLevel: debug(0)/info(1)/error(2) 杩欓噷鐨勬棩蹇楃瓑绾ч渶楂樹簬launch.json涓厤缃瓑绾ф棩蹇楁墠鑳借緭鍑 (鍙夊弬鏁帮紝榛樿0)
+-- @type(鍙夊弬鏁帮紝榛樿0): 0:VSCode output console 1:VSCode tip 2:VSCode debug console
+
+-- LuaPanda.BP()
+-- 寮哄埗鎵撴柇鐐癸紝鍙互鍦ㄥ崗绋嬩腑浣跨敤銆傚缓璁娇鐢ㄤ互涓嬪啓娉:
+-- local ret = LuaPanda and LuaPanda.BP and LuaPanda.BP();
+-- 濡傛灉鎴愬姛鍔犲叆鏂偣ret杩斿洖true锛屽惁鍒欐槸nil
+
+-- LuaPanda.getInfo()
+-- 杩斿洖鑾峰彇璋冭瘯鍣ㄤ俊鎭傚寘鎷増鏈彿锛屾槸鍚︿娇鐢╨ib搴擄紝绯荤粺鏄惁鏀寔loadstring(load鏂规硶)銆傝繑鍥炲肩被鍨媠tring, 鎺ㄨ崘鍦ㄨ皟璇曟帶鍒跺彴涓娇鐢ㄣ
+
+-- LuaPanda.testBreakpoint()
+-- 娴嬭瘯鏂偣锛岀敤浜庡垎鏋愯矾寰勯敊璇鑷存柇鐐规棤娉曞仠姝㈢殑鎯呭喌銆傛祴璇曟柟娉曟槸
+-- 1. launch.json 涓紑鍚 stopOnEntry, 鎴栬呭湪浠g爜涓姞鍏uaPanda.BP()銆
+-- 2. 杩愯璋冭瘯鍣ㄥ拰 lua 杩涚▼锛屽綋鍋滄鍦 stopOnEntry 鎴栬 LuaPanda.BP() 鏃跺湪璋冭瘯鎺у埗鍙拌緭鍏 LuaPanda.testBreakpoint()
+-- 3. 鏍规嵁鎻愮ず鏇存柊鏂偣鍚庡啀娆¤緭鍏 LuaPanda.testBreakpoint()銆傛鏃剁郴缁熶細杈撳嚭涓浜涙彁绀猴紝甯姪鐢ㄦ埛鍒嗘瀽鏂偣鍙兘鏃犳硶鍋滄鐨勫師鍥犮
+
+-- LuaPanda.doctor()
+-- 杩斿洖瀵瑰綋鍓嶇幆澧冪殑璇婃柇淇℃伅锛屾彁绀哄彲鑳藉瓨鍦ㄧ殑闂銆傝繑鍥炲肩被鍨媠tring, 鎺ㄨ崘鍦ㄨ皟璇曟帶鍒跺彴涓娇鐢ㄣ
+
+-- LuaPanda.getBreaks()
+-- 鑾峰彇鏂偣淇℃伅锛屾帹鑽愬湪璋冭瘯鎺у埗鍙颁腑浣跨敤銆
+
+-- LuaPanda.serializeTable(table)
+-- 鎶妕able搴忓垪鍖栦负瀛楃涓诧紝杩斿洖鍊肩被鍨嬫槸string銆
+
+-- LuaPanda.stopAttach()
+-- 鏂紑杩炴帴锛屽仠姝ttach锛屾湰娆¤璋冭瘯绋嬪簭杩愯杩囩▼鏃犳硶鍐嶆杩涜attach杩炴帴銆
+
+-- 鍏朵粬璇存槑锛
+-- 鍏充簬鐪熸満璋冭瘯锛岄娆′娇鐢ㄧ湡鏈鸿皟璇曟椂瑕佹敞鎰忎笅鏂"鐢ㄦ埛璁剧疆椤"涓殑閰嶇疆
+-- 1. 纭畾 attach 寮鍏虫墦寮: openAttachMode = true; 杩欐牱鍙互閬垮厤鍏堝惎鍔ㄦ墜鏈篴pp涔嬪悗鍚姩璋冭瘯鍣ㄦ棤娉曡繛鎺ャ
+-- 2. 鎶婅繛鎺ユ椂闂存斁闀: connectTimeoutSec 璁剧疆涓 0.5 鎴栬 1銆傞娆″皾璇曠湡鏈鸿皟璇曟椂杩欎釜鍊煎彲浠ヨ缃ぇ涓鐐癸紝涔嬪悗鍐嶆牴鎹嚜宸辩殑缃戠粶鐘跺喌鍚戜笅璋冩暣銆
+-- 璋冭瘯鏂规硶鍙互鍙傝 github 鏂囨。
+
+--鐢ㄦ埛璁剧疆椤
+local openAttachMode = true; --鏄惁寮鍚痑ttach妯″紡銆俛ttach妯″紡寮鍚悗鍙互鍦ㄤ换鎰忔椂鍒诲惎鍔╲scode杩炴帴璋冭瘯銆傜己鐐规槸娌℃湁杩炴帴璋冭瘯鏃朵篃浼氱暐闄嶄綆lua鎵ц鏁堢巼(浼氫笉鏂繘琛宎ttach璇锋眰)
+local attachInterval = 1; --attach闂撮殧鏃堕棿(s)
+local connectTimeoutSec = 0.005; --lua杩涚▼浣滀负Client鏃, 杩炴帴瓒呮椂鏃堕棿, 鍗曚綅s. 鏃堕棿杩囬暱绛夊緟attach鏃朵細閫犳垚鍗¢】锛屾椂闂磋繃鐭彲鑳芥棤娉曡繛鎺ャ傚缓璁0.005 - 0.05
+local listeningTimeoutSec = 0.5; -- lua杩涚▼浣滀负Server鏃,杩炴帴瓒呮椂鏃堕棿, 鍗曚綅s. 鏃堕棿杩囬暱绛夊緟attach鏃朵細閫犳垚鍗¢】锛屾椂闂磋繃鐭彲鑳芥棤娉曡繛鎺ャ傚缓璁0.1 - 1
+local userDotInRequire = true; --鍏煎require涓娇鐢 require(a.b) 鍜 require(a/b) 鐨勫舰寮忓紩鐢ㄦ枃浠跺す涓殑鏂囦欢锛岄粯璁ゆ棤闇淇敼
+local traversalUserData = false; --濡傛灉鍙互鐨勮瘽(鍙栧喅浜巙serdata鍘熻〃涓殑__pairs)锛屽睍绀簎serdata涓殑鍏冪礌銆 濡傛灉鍦ㄨ皟璇曞櫒涓睍寮userdata鏃舵湁閿欒锛岃鍏抽棴姝ら」.
+local customGetSocketInstance = nil; --鏀寔鐢ㄦ埛瀹炵幇涓涓嚜瀹氫箟璋冪敤luasocket鐨勫嚱鏁帮紝鍑芥暟杩斿洖鍊煎繀椤绘槸涓涓猻ocket瀹炰緥銆備緥: function() return require("socket.core").tcp() end;
+local consoleLogLevel = 2; --鎵撳嵃鍦ㄦ帶鍒跺彴(print)鐨勬棩蹇楃瓑绾 0 : all/ 1: info/ 2: error.
+--鐢ㄦ埛璁剧疆椤笶ND
+
+local debuggerVer = "3.2.0"; --debugger鐗堟湰鍙
+LuaPanda = {};
+local this = LuaPanda;
+local tools = {}; --寮曠敤鐨勫紑婧愬伐鍏凤紝鍖呮嫭json瑙f瀽鍜宼able灞曞紑宸ュ叿绛
+this.tools = tools;
+this.curStackId = 0;
+--json澶勭悊
+local json;
+--hook鐘舵佸垪琛
+local hookState = {
+ DISCONNECT_HOOK = 0, --鏂紑杩炴帴
+ LITE_HOOK = 1, --鍏ㄥ眬鏃犳柇鐐
+ MID_HOOK = 2, --鍏ㄥ眬鏈夋柇鐐癸紝鏈枃浠舵棤鏂偣
+ ALL_HOOK = 3, --鏈枃浠舵湁鏂偣
+};
+--杩愯鐘舵佸垪琛
+local runState = {
+ DISCONNECT = 0, --鏈繛鎺
+ WAIT_CMD = 1, --宸茶繛鎺ワ紝绛夊緟鍛戒护
+ STOP_ON_ENTRY = 2, --鍒濆鐘舵
+ RUN = 3,
+ STEPOVER = 4,
+ STEPIN = 5,
+ STEPOUT = 6,
+ STEPOVER_STOP = 7,
+ STEPIN_STOP = 8,
+ STEPOUT_STOP = 9,
+ HIT_BREAKPOINT = 10
+};
+
+local TCPSplitChar = "|*|"; --json鍗忚鍒嗛殧绗︼紝璇蜂笉瑕佷慨鏀
+local MAX_TIMEOUT_SEC = 3600 * 24; --缃戠粶鏈澶ц秴鏃剁瓑寰呮椂闂
+--褰撳墠杩愯鐘舵
+local currentRunState;
+local currentHookState;
+--鏂偣淇℃伅
+local breaks = {}; --淇濆瓨鏂偣鐨勬暟缁
+this.breaks = breaks; --渚沨ookLib璋冪敤
+local recCallbackId = "";
+--VSCode绔紶杩囨潵鐨勯厤缃紝鍦╒SCode绔殑launch閰嶇疆锛屼紶杩囨潵骞惰祴鍊
+local luaFileExtension = ""; --vscode浼犺繃鏉ョ殑鑴氭湰鍚庣紑
+local cwd = ""; --宸ヤ綔璺緞
+local DebuggerFileName = ""; --Debugger鏂囦欢鍚(鍘熷,鏈粡path澶勭悊), 鍑芥暟涓細鑷姩鑾峰彇
+local DebuggerToolsName = "";
+local lastRunFunction = {}; --涓婁竴涓墽琛岃繃鐨勫嚱鏁般傚湪鏈変簺澶嶆潅鍦烘櫙涓(find,getcomponent)涓琛屼細鎸轰袱娆
+local currentCallStack = {}; --鑾峰彇褰撳墠璋冪敤鍫嗘爤淇℃伅
+local hitBP = false; --BP()涓殑寮哄埗鏂偣鍛戒腑鏍囪
+local TempFilePath_luaString = ""; --VSCode绔厤缃殑涓存椂鏂囦欢瀛樻斁璺緞
+local recordHost; --璁板綍杩炴帴绔疘P
+local recordPort; --璁板綍杩炴帴绔彛鍙
+local sock; --lua socket 鏂囦欢鎻忚堪绗
+local server; --server 鎻忚堪绗
+local OSType; --VSCode璇嗗埆鍑虹殑绯荤粺绫诲瀷锛屼篃鍙互鑷璁剧疆銆俉indows_NT | Linux | Darwin
+local clibPath; --chook搴撳湪VScode绔殑璺緞锛屼篃鍙嚜琛岃缃
+local hookLib; --chook搴撶殑寮曠敤瀹炰緥
+local adapterVer; --VScode浼犳潵鐨刟dapter鐗堟湰鍙
+local truncatedOPath; --VScode涓敤鎴疯缃殑鐢ㄤ簬鎴柇opath璺緞鐨勬爣蹇楋紝娉ㄦ剰杩欓噷鍙互鎺ュ彈lua榄旀硶瀛楃
+local distinguishSameNameFile = false; --鏄惁鍖哄垎lua鍚屽悕鏂囦欢涓殑鏂偣锛屽湪VScode launch.json 涓 distinguishSameNameFile 鎺у埗
+--鏍囪浣
+local logLevel = 1; --鏃ュ織绛夌骇all/info/error. 姝よ缃搴旂殑鏄疺SCode绔缃殑鏃ュ織绛夌骇.
+local variableRefIdx = 1; --鍙橀噺绱㈠紩
+local variableRefTab = {}; --鍙橀噺璁板綍table
+local lastRunFilePath = ""; --鏈鍚庢墽琛岀殑鏂囦欢璺緞
+local pathCaseSensitivity = true; --璺緞鏄惁鍙戝ぇ灏忓啓鏁忔劅锛岃繖涓夐」鎺ユ敹VScode璁剧疆锛岃鍕垮湪姝ゅ鏇存敼
+local recvMsgQueue = {}; --鎺ユ敹鐨勬秷鎭槦鍒
+local coroutinePool = setmetatable({}, {__mode = "v"}); --淇濆瓨鐢ㄦ埛鍗忕▼鐨勯槦鍒
+local winDiskSymbolUpper = false;--璁剧疆win涓嬬洏绗︾殑澶у皬鍐欍備互姝ょ‘淇濅粠VSCode涓紶鍏ョ殑鏂偣璺緞,cwd鍜屼粠lua铏氭嫙鏈鸿幏寰楃殑鏂囦欢璺緞鐩樼澶у皬鍐欎竴鑷
+local isNeedB64EncodeStr = false;-- 璁板綍鏄惁浣跨敤base64缂栫爜瀛楃涓
+local loadclibErrReason = 'launch.json鏂囦欢鐨勯厤缃」useCHook琚缃负false.';
+local OSTypeErrTip = "";
+local pathErrTip = ""
+local winDiskSymbolTip = "";
+local isAbsolutePath = false;
+local stopOnEntry; --鐢ㄦ埛鍦╒SCode绔缃殑鏄惁鎵撳紑stopOnEntry
+local userSetUseClib; --鐢ㄦ埛鍦╒SCode绔缃殑鏄惁鏄敤clib搴
+local autoPathMode = false;
+local autoExt; --璋冭瘯鍣ㄥ惎鍔ㄦ椂鑷姩鑾峰彇鍒扮殑鍚庣紑, 鐢ㄤ簬妫娴媗ua铏氭嫙鏈鸿繑鍥炵殑璺緞鏄惁甯︽湁鏂囦欢鍚庣紑銆備粬鍙互鏄┖鍊兼垨鑰".lua"绛
+local luaProcessAsServer;
+local testBreakpointFlag = false; -- 娴嬭瘯鏂偣鐨勬爣蹇椾綅銆傜粨鍚 LuaPanda.testBreakpoint() 娴嬭瘯鏂偣鏃犳硶鍋滄鐨勫師鍥
+--Step鎺у埗鏍囪浣
+local stepOverCounter = 0; --STEPOVER over璁℃暟鍣
+local stepOutCounter = 0; --STEPOVER out璁℃暟鍣
+local HOOK_LEVEL = 3; --璋冪敤鏍堝亸绉婚噺锛屼娇鐢╟lib鏃朵负3锛宭ua涓笉鍐嶄娇鐢ㄦ鍙橀噺锛岃屾槸閫氳繃鍑芥暟getSpecificFunctionStackLevel鑾峰彇
+local isUseLoadstring = 0;
+local debugger_loadString;
+--涓存椂鍙橀噺
+local recordBreakPointPath; --璁板綍鏈鍚庝竴涓猍鍙兘鍛戒腑]鐨勬柇鐐癸紝鐢ㄤ簬getInfo浠ュ強doctor鐨勬柇鐐规祴璇
+local coroutineCreate; --鐢ㄦ潵璁板綍lua鍘熷鐨刢oroutine.create鍑芥暟
+local stopConnectTime = 0; --鐢ㄦ潵涓存椂璁板綍stop鏂紑杩炴帴鐨勬椂闂
+local isInMainThread;
+local receiveMsgTimer = 0;
+local isUserSetClibPath = false; --鐢ㄦ埛鏄惁鍦ㄦ湰鏂囦欢涓嚜璁句簡clib璺緞
+local hitBpTwiceCheck; -- 鍛戒腑鏂偣鐨刅scode鏍¢獙缁撴灉锛岄粯璁rue (true鏄懡涓紝false鏄湭鍛戒腑)
+local formatPathCache = {}; -- getinfo -> format
+function this.formatPathCache() return formatPathCache; end
+local fakeBreakPointCache = {}; --鍏朵腑鐢 璺緞-{琛屽彿鍒楄〃} 褰㈠紡淇濆瓨閿欒鍛戒腑淇℃伅
+function this.fakeBreakPointCache() return fakeBreakPointCache; end
+--5.1/5.3鍏煎
+if _VERSION == "Lua 5.1" then
+ debugger_loadString = loadstring;
+else
+ debugger_loadString = load;
+end
+
+--鐢ㄦ埛鍦ㄦ帶鍒跺彴杈撳叆淇℃伅鐨勭幆澧冨彉閲
+local env = setmetatable({ }, {
+ __index = function( _ , varName )
+ local ret = this.getWatchedVariable( varName, _G.LuaPanda.curStackId , false);
+ return ret;
+ end,
+
+ __newindex = function( _ , varName, newValue )
+ this.setVariableValue( varName, _G.LuaPanda.curStackId, newValue);
+ end
+});
+
+-----------------------------------------------------------------------------
+-- 娴佺▼
+-----------------------------------------------------------------------------
+
+---this.bindServer 褰搇ua杩涚▼浣滀负Server鏃讹紝server缁戝畾鍑芥暟
+--- server 鍦╞ind鏃跺垱寤, 杩炴帴鎴愬姛鍚庡叧闂璴isten , disconnect鏃剁疆绌恒俽econnect鏃朵細鏌ヨserver锛屾病鏈夌殑璇濋噸鏂扮粦瀹氾紝濡傛灉宸插瓨鍦ㄧ洿鎺ccept
+function this.bindServer(host, port)
+ server = sock
+ server:settimeout(listeningTimeoutSec);
+ assert(server:bind(host, port));
+ server:setoption("reuseaddr", true); --闃叉宸茶繛鎺ョ姸鎬佷笅鏂扮殑杩炴帴杩涘叆锛屼笉鍐峳euse
+ assert(server:listen(0));
+end
+
+-- 浠ua浣滀负鏈嶅姟绔殑褰㈠紡鍚姩璋冭瘯鍣
+-- @host 缁戝畾ip , 榛樿 0.0.0.0
+-- @port 缁戝畾port, 榛樿 8818
+function this.startServer(host, port)
+ host = tostring(host or "0.0.0.0") ;
+ port = tonumber(port) or 8818;
+ luaProcessAsServer = true;
+ this.printToConsole("Debugger start as SERVER. bind host:" .. host .. " port:".. tostring(port), 1);
+ if sock ~= nil then
+ this.printToConsole("[Warning] 璋冭瘯鍣ㄥ凡缁忓惎鍔紝璇蜂笉瑕佸啀娆¤皟鐢╯tart()" , 1);
+ return;
+ end
+
+ --灏濊瘯鍒濇杩炴帴
+ this.changeRunState(runState.DISCONNECT);
+ if not this.reGetSock() then
+ this.printToConsole("[Error] LuaPanda debugger start success , but get Socket fail , please install luasocket!", 2);
+ return;
+ end
+ recordHost = host;
+ recordPort = port;
+
+ this.bindServer(recordHost, recordPort);
+ local connectSuccess = server:accept();
+ sock = connectSuccess;
+
+ if connectSuccess then
+ this.printToConsole("First connect success!");
+ this.connectSuccess();
+ else
+ this.printToConsole("First connect failed!");
+ this.changeHookState(hookState.DISCONNECT_HOOK);
+ end
+end
+
+-- 鍚姩璋冭瘯鍣
+-- @host adapter绔痠p, 榛樿127.0.0.1
+-- @port adapter绔痯ort ,榛樿8818
+function this.start(host, port)
+ host = tostring(host or "127.0.0.1") ;
+ port = tonumber(port) or 8818;
+ this.printToConsole("Debugger start as CLIENT. connect host:" .. host .. " port:".. tostring(port), 1);
+ if sock ~= nil then
+ this.printToConsole("[Warning] 璋冭瘯鍣ㄥ凡缁忓惎鍔紝璇蜂笉瑕佸啀娆¤皟鐢╯tart()" , 1);
+ return;
+ end
+
+ --灏濊瘯鍒濇杩炴帴
+ this.changeRunState(runState.DISCONNECT);
+ if not this.reGetSock() then
+ this.printToConsole("[Error] Start debugger but get Socket fail , please install luasocket!", 2);
+ return;
+ end
+ recordHost = host;
+ recordPort = port;
+
+ sock:settimeout(connectTimeoutSec);
+ local connectSuccess = this.sockConnect(sock);
+
+ if connectSuccess then
+ this.printToConsole("First connect success!");
+ this.connectSuccess();
+ else
+ this.printToConsole("First connect failed!");
+ this.changeHookState(hookState.DISCONNECT_HOOK);
+ end
+end
+
+function this.sockConnect(sock)
+ if sock then
+ local connectSuccess, status = sock:connect(recordHost, recordPort);
+ if status == "connection refused" or (not connectSuccess and status == "already connected") then
+ this.reGetSock();
+ end
+
+ return connectSuccess
+ end
+ return nil;
+end
+
+-- 杩炴帴鎴愬姛锛屽紑濮嬪垵濮嬪寲
+function this.connectSuccess()
+ if server then
+ server:close(); -- 鍋滄listen
+ end
+
+ this.changeRunState(runState.WAIT_CMD);
+ this.printToConsole("connectSuccess", 1);
+ --璁剧疆鍒濆鐘舵
+ local ret = this.debugger_wait_msg();
+
+ --鑾峰彇debugger鏂囦欢璺緞
+ if DebuggerFileName == "" then
+ local info = debug.getinfo(1, "S")
+ for k,v in pairs(info) do
+ if k == "source" then
+ DebuggerFileName = tostring(v);
+ -- 浠庝唬鐮佷腑鍘诲悗缂
+ autoExt = DebuggerFileName:gsub('.*[Ll][Uu][Aa][Pp][Aa][Nn][Dd][Aa]', '');
+
+ if hookLib ~= nil then
+ hookLib.sync_debugger_path(DebuggerFileName);
+ end
+ end
+ end
+ end
+ if DebuggerToolsName == "" then
+ DebuggerToolsName = tools.getFileSource();
+ if hookLib ~= nil then
+ hookLib.sync_tools_path(DebuggerToolsName);
+ end
+ end
+
+ if ret == false then
+ this.printToVSCode("[debugger error]鍒濆鍖栨湭瀹屾垚, 寤虹珛杩炴帴浣嗘帴鏀跺垵濮嬪寲娑堟伅澶辫触銆傝鏇存崲绔彛閲嶈瘯", 2);
+ return;
+ end
+ this.printToVSCode("debugger init success", 1);
+
+ this.changeHookState(hookState.ALL_HOOK);
+ if hookLib == nil then
+ --鍗忕▼璋冭瘯
+ this.changeCoroutinesHookState();
+ end
+
+end
+
+--閲嶇疆鏁版嵁
+function this.clearData()
+ OSType = nil;
+ clibPath = nil;
+ -- reset breaks
+ breaks = {};
+ formatPathCache = {};
+ fakeBreakPointCache = {};
+ this.breaks = breaks;
+ if hookLib ~= nil then
+ hookLib.sync_breakpoints(); --娓呯┖鏂偣淇℃伅
+ hookLib.clear_pathcache(); --娓呯┖璺緞缂撳瓨
+ end
+end
+
+-- 鏈杩炴帴杩囩▼涓仠姝ttach ,浠ユ彁楂樿繍琛屾晥鐜
+function this.stopAttach()
+ openAttachMode = false;
+ this.printToConsole("Debugger stopAttach", 1);
+ this.clearData()
+ this.changeHookState( hookState.DISCONNECT_HOOK );
+ stopConnectTime = os.time();
+ this.changeRunState(runState.DISCONNECT);
+ if sock ~= nil then
+ sock:close();
+ if luaProcessAsServer and server then server = nil; end;
+ end
+end
+
+--鏂紑杩炴帴
+function this.disconnect()
+ this.printToConsole("Debugger disconnect", 1);
+ this.clearData()
+ this.changeHookState( hookState.DISCONNECT_HOOK );
+ stopConnectTime = os.time();
+ this.changeRunState(runState.DISCONNECT);
+
+ if sock ~= nil then
+ sock:close();
+ sock = nil;
+ server = nil;
+ end
+
+ if recordHost == nil or recordPort == nil then
+ --寮傚父鎯呭喌澶勭悊, 鍦ㄨ皟鐢↙uaPanda.start()鍓嶉鍏堣皟鐢ㄤ簡LuaPanda.disconnect()
+ this.printToConsole("[Warning] User call LuaPanda.disconnect() before set debug ip & port, please call LuaPanda.start() first!", 2);
+ return;
+ end
+
+ this.reGetSock();
+end
+
+function this.replaceCoroutineFuncs()
+ if hookLib == nil then
+ if coroutineCreate == nil and type(coroutine.create) == "function" then
+ this.printToConsole("change coroutine.create");
+ coroutineCreate = coroutine.create;
+ coroutine.create = function(...)
+ local co = coroutineCreate(...)
+ table.insert(coroutinePool, co);
+ --杩愯鐘舵佷笅锛屽垱寤哄崗绋嬪嵆鍚姩hook
+ this.changeCoroutineHookState(co, currentHookState);
+ return co;
+ end
+ end
+ end
+end
+
+-----------------------------------------------------------------------------
+-- 璋冭瘯鍣ㄩ氱敤鏂规硶
+-----------------------------------------------------------------------------
+-- 杩斿洖鏂偣淇℃伅
+function this.getBreaks()
+ return breaks;
+end
+
+---testBreakpoint 娴嬭瘯鏂偣
+function this.testBreakpoint()
+ if recordBreakPointPath and recordBreakPointPath ~= "" then
+ -- testBreakpointFlag = false;
+ return this.breakpointTestInfo();
+ else
+ local strTable = {};
+ strTable[#strTable + 1] = "姝e湪鍑嗗杩涜鏂偣娴嬭瘯锛岃鎸夌収濡備笅姝ラ鎿嶄綔\n"
+ strTable[#strTable + 1] = "1. 璇穂鍒犻櫎]褰撳墠椤圭洰涓墍鏈夋柇鐐;\n"
+ strTable[#strTable + 1] = "2. 鍦ㄥ綋鍓嶅仠姝㈣鎵撲竴涓柇鐐;\n"
+ strTable[#strTable + 1] = "3. 鍐嶆杩愯 'LuaPanda.testBreakpoint()'"
+ testBreakpointFlag = true;
+
+ return table.concat(strTable);
+ end
+end
+
+-- 杩斿洖璺緞鐩稿叧淇℃伅
+-- cwd:閰嶇疆鐨勫伐绋嬭矾寰 | info["source"]:閫氳繃 debug.getinfo 鑾峰緱鎵ц鏂囦欢鐨勮矾寰 | format锛氭牸寮忓寲鍚庣殑鏂囦欢璺緞
+function this.breakpointTestInfo()
+ local ly = this.getSpecificFunctionStackLevel(lastRunFunction.func);
+ if type(ly) ~= "number" then
+ ly = 2;
+ end
+ local runSource = lastRunFunction["source"];
+ if runSource == nil and hookLib ~= nil then
+ runSource = this.getPath(tostring(hookLib.get_last_source()));
+ end
+ local info = debug.getinfo(ly, "S");
+ local NormalizedPath = this.formatOpath(info["source"]);
+ NormalizedPath = this.truncatedPath(NormalizedPath, truncatedOPath);
+
+ local strTable = {}
+ local FormatedPath = tostring(runSource);
+ strTable[#strTable + 1] = "\n- BreakPoint Test:"
+ strTable[#strTable + 1] = "\nUser set lua extension: ." .. tostring(luaFileExtension);
+ strTable[#strTable + 1] = "\nAuto get lua extension: " .. tostring(autoExt);
+ if truncatedOPath and truncatedOPath ~= '' then
+ strTable[#strTable + 1] = "\nUser set truncatedOPath: " .. truncatedOPath;
+ end
+ strTable[#strTable + 1] = "\nGetInfo: ".. info["source"];
+ strTable[#strTable + 1] = "\nNormalized: " .. NormalizedPath;
+ strTable[#strTable + 1] = "\nFormated: " .. FormatedPath;
+ if recordBreakPointPath and recordBreakPointPath ~= "" then
+ strTable[#strTable + 1] = "\nBreakpoint: " .. recordBreakPointPath;
+ end
+
+ if not autoPathMode then
+ if isAbsolutePath then
+ strTable[#strTable + 1] = "\n璇存槑:浠巐ua铏氭嫙鏈鸿幏鍙栧埌鐨勬槸缁濆璺緞锛孎ormated浣跨敤GetInfo璺緞銆" .. winDiskSymbolTip;
+ else
+ strTable[#strTable + 1] = "\n璇存槑:浠巐ua铏氭嫙鏈鸿幏鍙栧埌鐨勮矾寰(GetInfo)鏄浉瀵硅矾寰勶紝璋冭瘯鍣ㄨ繍琛屼緷璧栫殑缁濆璺緞(Formated)鏄潵婧愪簬cwd+GetInfo鎷兼帴銆傚Formated璺緞閿欒璇峰皾璇曡皟鏁碿wd鎴栨敼鍙榁SCode鎵撳紑鏂囦欢澶圭殑浣嶇疆銆備篃鍙互鍦‵ormated瀵瑰簲鐨勬枃浠朵笅鎵撲竴涓柇鐐癸紝璋冩暣鐩村埌Formated鍜孊reaks Info涓柇鐐硅矾寰勫畬鍏ㄤ竴鑷淬" .. winDiskSymbolTip;
+ end
+ else
+ strTable[#strTable + 1] = "\n璇存槑:鑷姩璺緞(autoPathMode)妯″紡宸插紑鍚";
+ if recordBreakPointPath and recordBreakPointPath ~= "" then
+ if string.find(recordBreakPointPath , FormatedPath, (-1) * string.len(FormatedPath) , true) then
+ -- 鐭矾寰勬柇鐐瑰懡涓
+ if distinguishSameNameFile == false then
+ strTable[#strTable + 1] = "鏈枃浠朵腑鏂偣鍙甯稿懡涓"
+ strTable[#strTable + 1] = "鍚屽悕鏂囦欢涓殑鏂偣璇嗗埆(distinguishSameNameFile) 鏈紑鍚紝璇风‘淇 VSCode 鏂偣涓嶈瀛樺湪浜庡悓鍚 lua 鏂囦欢涓";
+ else
+ strTable[#strTable + 1] = "鍚屽悕鏂囦欢涓殑鏂偣璇嗗埆(distinguishSameNameFile) 宸插紑鍚";
+ if string.find(recordBreakPointPath, NormalizedPath, 1, true) then
+ strTable[#strTable + 1] = "鏈枃浠朵腑鏂偣鍙姝e父鍛戒腑"
+ else
+ strTable[#strTable + 1] = "鏂偣鍙兘鏃犳硶琚懡涓紝鍥犱负 lua 铏氭嫙鏈轰腑鑾峰緱鐨勮矾寰 Normalized 涓嶆槸鏂偣璺緞 Breakpoint 鐨勫瓙涓层 濡傛湁闇瑕侊紝鍙互鍦 launch.json 涓缃 truncatedOPath 鏉ュ幓闄 Normalized 閮ㄥ垎璺緞銆"
+ end
+ end
+ else
+ strTable[#strTable + 1] = "鏂偣鏈鍛戒腑锛屽師鍥犳槸 Formated 涓嶆槸 Breakpoint 璺緞鐨勫瓙涓诧紝鎴栬 Formated 鍜 Breakpoint 鏂囦欢鍚庣紑涓嶄竴鑷"
+ end
+ else
+ strTable[#strTable + 1] = "濡傛灉瑕佽繘琛屾柇鐐规祴璇曪紝璇蜂娇鐢 LuaPanda.testBreakpoint()銆"
+ end
+ end
+ return table.concat(strTable)
+end
+
+--杩斿洖鐗堟湰鍙风瓑閰嶇疆
+function this.getBaseInfo()
+ local strTable = {};
+ local jitVer = "";
+ if jit and jit.version then
+ jitVer = "," .. tostring(jit.version);
+ end
+
+ strTable[#strTable + 1] = "Lua Ver:" .. _VERSION .. jitVer .." | Adapter Ver:" .. tostring(adapterVer) .. " | Debugger Ver:" .. tostring(debuggerVer);
+ local moreInfoStr = "";
+ if hookLib ~= nil then
+ local clibVer, forluaVer = hookLib.sync_getLibVersion();
+ local clibStr = forluaVer ~= nil and tostring(clibVer) .. " for " .. tostring(math.ceil(forluaVer)) or tostring(clibVer);
+ strTable[#strTable + 1] = " | hookLib Ver:" .. clibStr;
+ moreInfoStr = moreInfoStr .. "璇存槑: 宸插姞杞 libpdebug 搴.";
+ else
+ moreInfoStr = moreInfoStr .. "璇存槑: 鏈兘鍔犺浇 libpdebug 搴撱傚師鍥犺浣跨敤 LuaPanda.doctor() 鏌ョ湅";
+ end
+
+ local outputIsUseLoadstring = false
+ if type(isUseLoadstring) == "number" and isUseLoadstring == 1 then
+ outputIsUseLoadstring = true;
+ end
+
+ strTable[#strTable + 1] = " | supportREPL:".. tostring(outputIsUseLoadstring);
+ strTable[#strTable + 1] = " | useBase64EncodeString:".. tostring(isNeedB64EncodeStr);
+ strTable[#strTable + 1] = " | codeEnv:" .. tostring(OSType);
+ strTable[#strTable + 1] = " | distinguishSameNameFile:" .. tostring(distinguishSameNameFile) .. '\n';
+
+ strTable[#strTable + 1] = moreInfoStr;
+ if OSTypeErrTip ~= nil and OSTypeErrTip ~= '' then
+ strTable[#strTable + 1] = '\n' ..OSTypeErrTip;
+ end
+ return table.concat(strTable);
+end
+
+--鑷姩璇婃柇褰撳墠鐜鐨勯敊璇紝骞惰緭鍑轰俊鎭
+function this.doctor()
+ local strTable = {};
+ if debuggerVer ~= adapterVer then
+ strTable[#strTable + 1] = "\n- 寤鸿鏇存柊鐗堟湰\nLuaPanda VSCode鎻掍欢鐗堟湰鏄" .. adapterVer .. ", LuaPanda.lua鏂囦欢鐗堟湰鏄" .. debuggerVer .. "銆傚缓璁鏌ュ苟鏇存柊鍒版渶鏂扮増鏈";
+ strTable[#strTable + 1] = "\n鏇存柊鏂瑰紡 : https://github.com/Tencent/LuaPanda/blob/master/Docs/Manual/update.md";
+ strTable[#strTable + 1] = "\nRelease鐗堟湰: https://github.com/Tencent/LuaPanda/releases";
+ end
+ --plibdebug
+ if hookLib == nil then
+ strTable[#strTable + 1] = "\n\n- libpdebug 搴撴病鏈夊姞杞絓n";
+ if userSetUseClib then
+ --鐢ㄦ埛鍏佽浣跨敤clib鎻掍欢
+ if isUserSetClibPath == true then
+ --鐢ㄦ埛鑷浜哻lib鍦板潃
+ strTable[#strTable + 1] = "鐢ㄦ埛浣跨敤 LuaPanda.lua 涓 clibPath 鍙橀噺鎸囧畾浜 plibdebug 鐨勪綅缃: " .. clibPath;
+ if this.tryRequireClib("libpdebug", clibPath) then
+ strTable[#strTable + 1] = "\n寮曠敤鎴愬姛";
+ else
+ strTable[#strTable + 1] = "\n寮曠敤閿欒:" .. loadclibErrReason;
+ end
+ else
+ --浣跨敤榛樿clib鍦板潃
+ local clibExt, platform;
+ if OSType == "Darwin" then clibExt = "/?.so;"; platform = "mac";
+ elseif OSType == "Linux" then clibExt = "/?.so;"; platform = "linux";
+ else clibExt = "/?.dll;"; platform = "win"; end
+ local lua_ver;
+ if _VERSION == "Lua 5.1" then
+ lua_ver = "501";
+ else
+ lua_ver = "503";
+ end
+ local x86Path = clibPath .. platform .."/x86/".. lua_ver .. clibExt;
+ local x64Path = clibPath .. platform .."/x86_64/".. lua_ver .. clibExt;
+
+ strTable[#strTable + 1] = "灏濊瘯寮曠敤x64搴: ".. x64Path;
+ if this.tryRequireClib("libpdebug", x64Path) then
+ strTable[#strTable + 1] = "\n寮曠敤鎴愬姛";
+ else
+ strTable[#strTable + 1] = "\n寮曠敤閿欒:" .. loadclibErrReason;
+ strTable[#strTable + 1] = "\n灏濊瘯寮曠敤x86搴: ".. x86Path;
+ if this.tryRequireClib("libpdebug", x86Path) then
+ strTable[#strTable + 1] = "\n寮曠敤鎴愬姛";
+ else
+ strTable[#strTable + 1] = "\n寮曠敤閿欒:" .. loadclibErrReason;
+ end
+ end
+ end
+ else
+ strTable[#strTable + 1] = "鍘熷洜鏄" .. loadclibErrReason;
+ end
+ end
+
+ --path
+ --灏濊瘯鐩存帴璇诲綋鍓峠etinfo鎸囧悜鐨勬枃浠讹紝鐪嬭兘鍚︽壘鍒般傚鏋滆兘锛屾彁绀烘纭紝濡傛灉鎵句笉鍒帮紝缁欏嚭鎻愮ず锛屽缓璁帺瀹跺湪杩欎釜鏂囦欢涓墦涓涓柇鐐
+ --妫鏌ユ柇鐐癸紝鏂囦欢鍜屽綋鍓嶆枃浠剁殑涓嶅悓锛岀粰鍑哄缓璁
+ local runSource = lastRunFilePath;
+ if hookLib ~= nil then
+ runSource = this.getPath(tostring(hookLib.get_last_source()));
+ end
+
+ -- 鍦ㄧ簿纭矾寰勬ā寮忎笅鐨勮矾寰勯敊璇娴
+ if not autoPathMode and runSource and runSource ~= "" then
+ -- 璇绘枃浠
+ local isFileExist = this.fileExists(runSource);
+ if not isFileExist then
+ strTable[#strTable + 1] = "\n\n- 璺緞瀛樺湪闂\n";
+ --瑙f瀽璺緞锛屽緱鍒版枃浠跺悕锛屽埌鏂偣璺緞涓煡杩欎釜鏂囦欢鍚
+ local pathArray = this.stringSplit(runSource, '/');
+ --濡傛灉pathArray鍜屾柇鐐硅兘鍖归厤涓
+ local fileMatch= false;
+ for key, _ in pairs(this.getBreaks()) do
+ if string.find(key, pathArray[#pathArray], 1, true) then
+ --鍜屾柇鐐瑰尮閰嶄簡
+ fileMatch = true;
+ -- retStr = retStr .. "\n璇峰姣斿涓嬭矾寰:\n";
+ strTable[#strTable + 1] = this.breakpointTestInfo();
+ strTable[#strTable + 1] = "\nfilepath: " .. key;
+ if isAbsolutePath then
+ strTable[#strTable + 1] = "\n璇存槑:浠巐ua铏氭嫙鏈鸿幏鍙栧埌鐨勬槸缁濆璺緞锛宖ormat浣跨敤getinfo璺緞銆";
+ else
+ strTable[#strTable + 1] = "\n璇存槑:浠巐ua铏氭嫙鏈鸿幏鍙栧埌鐨勬槸鐩稿璺緞锛岃皟璇曞櫒杩愯渚濊禆鐨勭粷瀵硅矾寰(format)鏄潵婧愪簬cwd+getinfo鎷兼帴銆";
+ end
+ strTable[#strTable + 1] = "\nfilepath鏄疺SCode閫氳繃鑾峰彇鍒扮殑鏂囦欢姝g‘璺緞 , 瀵规瘮format鍜宖ilepath锛岃皟鏁磍aunch.json涓瑿WD锛屾垨鏀瑰彉VSCode鎵撳紑鏂囦欢澶圭殑浣嶇疆銆備娇format鍜宖ilepath涓鑷村嵆鍙俓n濡傛灉format鍜宖ilepath璺緞浠呭ぇ灏忓啓涓嶄竴鑷达紝璁剧疆launch.json涓 pathCaseSensitivity:false 鍙拷鐣ヨ矾寰勫ぇ灏忓啓";
+ end
+ end
+
+ if fileMatch == false then
+ --鏈兘鍜屾柇鐐瑰尮閰
+ strTable[#strTable + 1] = "\n鎵句笉鍒版枃浠:" .. runSource .. ", 璇锋鏌ヨ矾寰勬槸鍚︽纭俓n鎴栬呭湪VSCode鏂囦欢" .. pathArray[#pathArray] .. "涓墦涓涓柇鐐瑰悗锛屽啀鎵ц涓娆octor鍛戒护锛屾煡鐪嬭矾寰勫垎鏋愮粨鏋溿";
+ end
+ end
+ end
+
+ --鏃ュ織绛夌骇瀵规ц兘鐨勫奖鍝
+ if logLevel < 1 or consoleLogLevel < 1 then
+ strTable[#strTable + 1] = "\n\n- 鏃ュ織绛夌骇\n";
+ if logLevel < 1 then
+ strTable[#strTable + 1] = "褰撳墠鏃ュ織绛夌骇鏄" .. logLevel .. ", 浼氫骇鐢熷ぇ閲忔棩蹇楋紝闄嶄綆璋冭瘯閫熷害銆傚缓璁皟鏁磍aunch.json涓璴ogLevel:1";
+ end
+ if consoleLogLevel < 1 then
+ strTable[#strTable + 1] = "褰撳墠console鏃ュ織绛夌骇鏄" .. consoleLogLevel .. ", 杩囦綆鐨勬棩蹇楃瓑绾т細闄嶄綆璋冭瘯閫熷害锛屽缓璁皟鏁碙uaPanda.lua鏂囦欢澶撮儴consoleLogLevel=2";
+ end
+ end
+
+ if #strTable == 0 then
+ strTable[#strTable + 1] = "鏈娴嬪嚭闂";
+ end
+ return table.concat(strTable);
+end
+
+function this.fileExists(path)
+ local f=io.open(path,"r");
+ if f~= nil then io.close(f) return true else return false end
+ end
+
+--杩斿洖涓浜涗俊鎭紝甯姪鐢ㄦ埛瀹氫綅闂
+function this.getInfo()
+ --鐢ㄦ埛璁剧疆椤
+ local strTable = {};
+ strTable[#strTable + 1] = "\n- Base Info: \n";
+ strTable[#strTable + 1] = this.getBaseInfo();
+ --宸茬粡鍔犺浇C搴擄紝x86/64 鏈兘鍔犺浇锛屽師鍥
+ strTable[#strTable + 1] = "\n\n- User Setting: \n";
+ strTable[#strTable + 1] = "stopOnEntry:" .. tostring(stopOnEntry) .. ' | ';
+ -- strTable[#strTable + 1] = "luaFileExtension:" .. luaFileExtension .. ' | ';
+ strTable[#strTable + 1] = "logLevel:" .. logLevel .. ' | ' ;
+ strTable[#strTable + 1] = "consoleLogLevel:" .. consoleLogLevel .. ' | ';
+ strTable[#strTable + 1] = "pathCaseSensitivity:" .. tostring(pathCaseSensitivity) .. ' | ';
+ strTable[#strTable + 1] = "attachMode:".. tostring(openAttachMode).. ' | ';
+ strTable[#strTable + 1] = "autoPathMode:".. tostring(autoPathMode).. ' | ';
+
+ if userSetUseClib then
+ strTable[#strTable + 1] = "useCHook:true";
+ else
+ strTable[#strTable + 1] = "useCHook:false";
+ end
+
+ if logLevel == 0 or consoleLogLevel == 0 then
+ strTable[#strTable + 1] = "\n璇存槑:鏃ュ織绛夌骇杩囦綆锛屼細褰卞搷鎵ц鏁堢巼銆傝璋冩暣logLevel鍜宑onsoleLogLevel鍊 >= 1";
+ end
+
+ strTable[#strTable + 1] = "\n\n- Path Info: \n";
+ strTable[#strTable + 1] = "clibPath: " .. tostring(clibPath) .. '\n';
+ strTable[#strTable + 1] = "debugger: " .. DebuggerFileName .. " | " .. this.getPath(DebuggerFileName) .. '\n';
+ strTable[#strTable + 1] = "cwd : " .. cwd .. '\n';
+ strTable[#strTable + 1] = this.breakpointTestInfo();
+
+ if pathErrTip ~= nil and pathErrTip ~= '' then
+ strTable[#strTable + 1] = '\n' .. pathErrTip;
+ end
+
+ strTable[#strTable + 1] = "\n\n- Breaks Info: \nUse 'LuaPanda.getBreaks()' to watch.";
+ return table.concat(strTable);
+end
+
+--鍒ゆ柇鏄惁鍦ㄥ崗绋嬩腑
+function this.isInMain()
+ return isInMainThread;
+end
+
+--娣诲姞璺緞锛屽皾璇曞紩鐢ㄥ簱銆傚畬鎴愬悗鎶奵path杩樺師锛岃繑鍥炲紩鐢ㄧ粨鏋渢rue/false
+-- @libName 搴撳悕
+-- path lib鐨刢path璺緞
+function this.tryRequireClib(libName , libPath)
+ this.printToVSCode("tryRequireClib search : [" .. libName .. "] in "..libPath);
+ local savedCpath = package.cpath;
+ package.cpath = package.cpath .. ';' .. libPath;
+ this.printToVSCode("package.cpath:" .. package.cpath);
+ local status, err = pcall(function() hookLib = require(libName) end);
+ if status then
+ if type(hookLib) == "table" and this.getTableMemberNum(hookLib) > 0 then
+ this.printToVSCode("tryRequireClib success : [" .. libName .. "] in "..libPath);
+ package.cpath = savedCpath;
+ return true;
+ else
+ loadclibErrReason = "tryRequireClib fail : require success, but member function num <= 0; [" .. libName .. "] in "..libPath;
+ this.printToVSCode(loadclibErrReason);
+ hookLib = nil;
+ package.cpath = savedCpath;
+ return false;
+ end
+ else
+ -- 姝ゅ鑰冭檻鍒皌ryRequireClib浼氳璋冪敤涓ゆ锛屾棩蹇楃骇鍒缃负0锛岄槻姝㈣緭鍑轰笉蹇呰鐨勪俊鎭
+ loadclibErrReason = err;
+ this.printToVSCode("[Require clib error]: " .. err, 0);
+ end
+ package.cpath = savedCpath;
+ return false
+end
+------------------------瀛楃涓插鐞-------------------------
+-- 鍊掑簭鏌ユ壘瀛楃涓 a.b/c鏌ユ壘/ , 杩斿洖4
+-- @str 琚煡鎵剧殑闀夸覆
+-- @subPattern 鏌ユ壘鐨勫瓙涓, 涔熷彲浠ユ槸pattern
+-- @plain plane text / pattern
+-- @return 鏈壘鍒扮洰鏍囦覆杩斿洖nil. 鍚﹀垯杩斿洖鍊掑簭鎵惧埌鐨勫瓧涓蹭綅缃
+function this.revFindString(str, subPattern, plain)
+ local revStr = string.reverse(str);
+ local _, idx = string.find(revStr, subPattern, 1, plain);
+ if idx == nil then return nil end;
+ return string.len(revStr) - idx + 1;
+end
+
+-- 鍙嶅簭瑁佸壀瀛楃涓 濡:print(subString("a.b/c", "/"))杈撳嚭c
+-- @return 鏈壘鍒扮洰鏍囦覆杩斿洖nil. 鍚﹀垯杩斿洖琚鍓悗鐨勫瓧绗︿覆
+function this.revSubString(str, subStr, plain)
+ local idx = this.revFindString(str, subStr, plain)
+ if idx == nil then return nil end;
+ return string.sub(str, idx + 1, str.length)
+end
+
+-- 鎶婂瓧绗︿覆鎸塺eps鍒嗗壊鎴愬苟鏀惧叆table
+-- @str 鐩爣涓
+-- @reps 鍒嗗壊绗︺傛敞鎰忚繖涓垎闅旂鏄竴涓猵attern
+function this.stringSplit( str, separator )
+ local retStrTable = {}
+ string.gsub(str, '[^' .. separator ..']+', function ( word )
+ table.insert(retStrTable, word)
+ end)
+ return retStrTable;
+end
+
+-- 淇濆瓨CallbackId(閫氫俊搴忓垪鍙)
+function this.setCallbackId( id )
+ if id ~= nil and id ~= "0" then
+ recCallbackId = tostring(id);
+ end
+end
+
+-- 璇诲彇CallbackId(閫氫俊搴忓垪鍙)銆傝鍙栧悗璁板綍鍊煎皢琚疆绌
+function this.getCallbackId()
+ if recCallbackId == nil then
+ recCallbackId = "0";
+ end
+ local id = recCallbackId;
+ recCallbackId = "0";
+ return id;
+end
+
+-- reference from https://www.lua.org/pil/20.1.html
+function this.trim (s)
+ return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
+end
+
+--杩斿洖table涓垚鍛樻暟閲(鏁板瓧key鍜岄潪鏁板瓧key涔嬪拰)
+-- @t 鐩爣table
+-- @return 鍏冪礌鏁伴噺
+function this.getTableMemberNum(t)
+ local retNum = 0;
+ if type(t) ~= "table" then
+ this.printToVSCode("[debugger Error] getTableMemberNum get "..tostring(type(t)), 2)
+ return retNum;
+ end
+ for k,v in pairs(t) do
+ retNum = retNum + 1;
+ end
+ return retNum;
+end
+
+-- 鐢熸垚涓涓秷鎭疶able
+function this.getMsgTable(cmd ,callbackId)
+ callbackId = callbackId or 0;
+ local msgTable = {};
+ msgTable["cmd"] = cmd;
+ msgTable["callbackId"] = callbackId;
+ msgTable["info"] = {};
+ return msgTable;
+end
+
+function this.serializeTable(tab, name)
+ local sTable = tools.serializeTable(tab, name);
+ return sTable;
+end
+------------------------鏃ュ織鎵撳嵃鐩稿叧-------------------------
+-- 鎶婃棩蹇楁墦鍗板湪VSCode绔
+-- @str: 鏃ュ織鍐呭
+-- @printLevel: all(0)/info(1)/error(2)
+-- @type: 0:vscode console 1:vscode tip
+function this.printToVSCode(str, printLevel, type)
+ type = type or 0;
+ printLevel = printLevel or 0;
+ if currentRunState == runState.DISCONNECT or logLevel > printLevel then
+ return;
+ end
+
+ local sendTab = {};
+ sendTab["callbackId"] = "0";
+ if type == 0 then
+ sendTab["cmd"] = "output";
+ elseif type == 1 then
+ sendTab["cmd"] = "tip";
+ else -- type == 2
+ sendTab["cmd"] = "debug_console";
+ end
+ sendTab["info"] = {};
+ sendTab["info"]["logInfo"] = tostring(str);
+ this.sendMsg(sendTab);
+end
+
+-- 鎶婃棩蹇楁墦鍗板湪鎺у埗鍙
+-- @str: 鏃ュ織鍐呭
+-- @printLevel: all(0)/info(1)/error(2)
+function this.printToConsole(str, printLevel)
+ printLevel = printLevel or 0;
+ if consoleLogLevel > printLevel then
+ return;
+ end
+ print("[LuaPanda] ".. tostring(str));
+end
+
+-----------------------------------------------------------------------------
+-- 鎻愬崌鍏煎鎬ф柟娉
+-----------------------------------------------------------------------------
+--鐢熸垚骞冲彴鏃犲叧鐨勮矾寰勩
+--return:nil(error)/path
+function this.genUnifiedPath(path)
+ if path == "" or path == nil then
+ return "";
+ end
+ --澶у皬鍐欎笉鏁忔劅鏃讹紝璺緞鍏ㄩ儴杞负灏忓啓
+ if pathCaseSensitivity == false then
+ path = string.lower(path);
+ end
+ --缁熶竴璺緞鍏ㄩ儴鏇挎崲鎴/
+ path = string.gsub(path, [[\]], "/");
+ --澶勭悊 /../ /./
+ local pathTab = this.stringSplit(path, '/');
+ local newPathTab = {};
+ for k, v in ipairs(pathTab) do
+ if v == '.' then
+ --continue
+ elseif v == ".." and #newPathTab >= 1 and newPathTab[#newPathTab]:sub(2,2) ~= ':' then
+ --newPathTab鏈夊厓绱狅紝鏈鍚庝竴椤逛笉鏄疿:
+ table.remove(newPathTab);
+ else
+ table.insert(newPathTab, v);
+ end
+ end
+ --閲嶆柊鎷煎悎鍚庡鏋滄槸mac璺緞绗竴浣嶆槸/
+ local newpath = table.concat(newPathTab, '/');
+ if path:sub(1,1) == '/' then
+ newpath = '/'.. newpath;
+ end
+
+ --win涓嬫寜鐓inDiskSymbolUpper鐨勮缃慨鏀圭洏绗﹀ぇ灏
+ if "Windows_NT" == OSType then
+ if winDiskSymbolUpper then
+ newpath = newpath:gsub("^%a:", string.upper);
+ winDiskSymbolTip = "璺緞涓璚indows鐩樼宸茶浆涓哄ぇ鍐欍"
+ else
+ newpath = newpath:gsub("^%a:", string.lower);
+ winDiskSymbolTip = "璺緞涓璚indows鐩樼宸茶浆涓哄皬鍐欍"
+ end
+ end
+
+ return newpath;
+end
+
+function this.getCacheFormatPath(source)
+ if source == nil then return formatPathCache end;
+ return formatPathCache[source];
+end
+
+function this.setCacheFormatPath(source, dest)
+ formatPathCache[source] = dest;
+end
+
+-- 澶勭悊 opath(info.source) 鐨勫嚱鏁, 鐢熸垚涓涓鑼冪殑璺緞鍑芥暟(鍜孷Scode绔痗heckRightPath閫昏緫瀹屽叏涓鑷)
+function this.formatOpath(opath)
+ -- delete @
+ if opath:sub(1,1) == '@' then
+ opath = opath:sub(2);
+ end
+ -- change ./ to /
+ if opath:sub(1,2) == './' then
+ opath = opath:sub(2);
+ end
+
+ opath = this.genUnifiedPath(opath);
+
+ -- lower
+ if pathCaseSensitivity == false then
+ opath = string.lower(opath);
+ end
+ --鎶奻ilename鍘婚櫎鍚庣紑
+ if autoExt == nil or autoExt == '' then
+ -- 鍦ㄨ櫄鎷熸満杩斿洖璺緞娌℃湁鍚庣紑鐨勬儏鍐典笅锛岀敤鎴峰繀椤昏嚜璁惧悗缂
+ -- 纭畾filePath涓渶鍚庝竴涓.xxx 涓嶇瓑浜庣敤鎴烽厤缃殑鍚庣紑, 鍒欐妸鎵鏈夌殑. 杞负 /
+ if not opath:find(luaFileExtension , (-1) * luaFileExtension:len(), true) then
+ -- getinfo 璺緞娌℃湁鍚庣紑锛屾妸 . 鍏ㄩ儴鏇挎崲鎴 / 锛屾垜浠笉鍏佽鐢ㄦ埛鍦ㄦ枃浠讹紙鎴栨枃浠跺す锛夊悕绉颁腑鍑虹幇"." , 鍥犱负鏃犳硶鍖哄垎
+ opath = string.gsub(opath, "%.", "/");
+ else
+ -- 鏈夊悗缂锛岄偅涔堟妸闄ゅ悗缂澶栫殑閮ㄥ垎涓殑. 杞负 /
+ opath = this.changePotToSep(opath, luaFileExtension);
+ end
+ else
+ -- 铏氭嫙鏈鸿矾寰勬湁鍚庣紑
+ opath = this.changePotToSep(opath, autoExt);
+ end
+
+ -- 鎴彇 璺緞+鏂囦欢鍚 (涓嶅甫鍚庣紑)
+ -- change pot to /
+ -- opath = string.gsub(opath, "%.", "/");
+ return opath;
+end
+
+-----------------------------------------------------------------------------
+-- 鍐呭瓨鐩稿叧
+-----------------------------------------------------------------------------
+function this.sendLuaMemory()
+ local luaMem = collectgarbage("count");
+ local sendTab = {};
+ sendTab["callbackId"] = "0";
+ sendTab["cmd"] = "refreshLuaMemory";
+ sendTab["info"] = {};
+ sendTab["info"]["memInfo"] = tostring(luaMem);
+ this.sendMsg(sendTab);
+end
+
+-----------------------------------------------------------------------------
+-- 缃戠粶鐩稿叧鏂规硶
+-----------------------------------------------------------------------------
+-- 鍒锋柊socket
+-- @return true/false 鍒锋柊鎴愬姛/澶辫触
+function this.reGetSock()
+ if server then return true end
+
+ if sock ~= nil then
+ pcall(function() sock:close() end);
+ end
+
+ --call slua-unreal luasocket
+ sock = lua_extension and lua_extension.luasocket and lua_extension.luasocket().tcp();
+ if sock == nil then
+ --call normal luasocket
+ if pcall(function() sock = require("socket.core").tcp(); end) then
+ this.printToConsole("reGetSock success");
+ else
+ --call custom function to get socket
+ if customGetSocketInstance and pcall( function() sock = customGetSocketInstance(); end ) then
+ this.printToConsole("reGetSock custom success");
+ else
+ this.printToConsole("[Error] reGetSock fail", 2);
+ return false;
+ end
+ end
+ else
+ --set ue4 luasocket
+ this.printToConsole("reGetSock ue4 success");
+ end
+ return true;
+end
+
+-- 瀹氭椂(浠ュ嚱鏁皉eturn涓烘椂鏈) 杩涜attach杩炴帴
+-- 杩斿洖鍊 hook 鍙互缁х画寰涓嬭蛋鏃惰繑鍥1 锛屾棤闇缁х画鏃惰繑鍥0
+function this.reConnect()
+ if currentHookState == hookState.DISCONNECT_HOOK then
+ if os.time() - stopConnectTime < attachInterval then
+ -- 鏈埌閲嶈繛鏃堕棿
+ -- this.printToConsole("Reconnect time less than 1s");
+ -- this.printToConsole("os.time:".. os.time() .. " | stopConnectTime:" ..stopConnectTime);
+ return 0;
+ end
+ this.printToConsole("Reconnect !");
+ if sock == nil then
+ this.reGetSock();
+ end
+
+ local connectSuccess;
+ if luaProcessAsServer == true and currentRunState == runState.DISCONNECT then
+ -- 鍦 Server 妯″紡涓嬶紝浠ュ強褰撳墠澶勪簬鏈繛鎺ョ姸鎬佷笅锛屾墠灏濊瘯accept鏂伴摼鎺ャ傚鏋滀笉鍒ゆ柇鍙兘浼氬嚭鐜板娆¤繛鎺ワ紝瀵艰嚧sock琚鐩
+ if server == nil then
+ this.bindServer(recordHost, recordPort);
+ end
+
+ sock = server:accept();
+ connectSuccess = sock;
+ else
+ sock:settimeout(connectTimeoutSec);
+ connectSuccess = this.sockConnect(sock);
+ end
+
+ if connectSuccess then
+ this.printToConsole("reconnect success");
+ this.connectSuccess();
+ return 1;
+ else
+ this.printToConsole("reconnect failed" );
+ stopConnectTime = os.time();
+ return 0;
+ end
+ end
+ -- 涓嶅繀閲嶈繛锛屾甯哥户缁繍琛
+ return 1;
+end
+
+-- 鍚慳dapter鍙戞秷鎭
+-- @sendTab 娑堟伅浣搕able
+function this.sendMsg( sendTab )
+ if isNeedB64EncodeStr and sendTab["info"] ~= nil then
+ for _, v in ipairs(sendTab["info"]) do
+ if v["type"] == "string" then
+ v["value"] = tools.base64encode(v["value"])
+ end
+ end
+ end
+
+ local sendStr = json.encode(sendTab);
+ if currentRunState == runState.DISCONNECT then
+ this.printToConsole("[debugger error] disconnect but want sendMsg:" .. sendStr, 2);
+ this.disconnect();
+ return;
+ end
+
+ local succ,err;
+ if pcall(function() succ,err = sock:send(sendStr..TCPSplitChar.."\n"); end) then
+ if succ == nil then
+ if err == "closed" then
+ this.disconnect();
+ end
+ end
+ end
+end
+
+-- 澶勭悊 鏀跺埌鐨勬秷鎭
+-- @dataStr 鎺ユ敹鐨勬秷鎭痡son
+function this.dataProcess( dataStr )
+ this.printToVSCode("debugger get:"..dataStr);
+ local dataTable = json.decode(dataStr);
+ if dataTable == nil then
+ this.printToVSCode("[error] Json is error", 2);
+ return;
+ end
+
+ if dataTable.callbackId ~= "0" then
+ this.setCallbackId(dataTable.callbackId);
+ end
+
+ if dataTable.cmd == "continue" then
+ local info = dataTable.info;
+ if info.isFakeHit == "true" and info.fakeBKPath and info.fakeBKLine then
+ -- 璁剧疆鏍¢獙缁撴灉鏍囧織浣嶏紝浠ヤ究hook娴佺▼鐭ラ亾缁撴灉
+ hitBpTwiceCheck = false;
+ if hookLib ~= nil and hookLib.set_bp_twice_check_res then
+ -- 鎶婄粨鏋滃悓姝ョ粰C
+ hookLib.set_bp_twice_check_res(0);
+ end
+ -- 鎶婂亣鏂偣鐨勪俊鎭姞鍏ache
+ if nil == fakeBreakPointCache[info.fakeBKPath] then
+ fakeBreakPointCache[info.fakeBKPath] = {};
+ end
+ table.insert(fakeBreakPointCache[info.fakeBKPath] ,info.fakeBKLine);
+ else
+ this.changeRunState(runState.RUN);
+ end
+ local msgTab = this.getMsgTable("continue", this.getCallbackId());
+ this.sendMsg(msgTab);
+
+ elseif dataTable.cmd == "stopOnStep" then
+ this.changeRunState(runState.STEPOVER);
+ local msgTab = this.getMsgTable("stopOnStep", this.getCallbackId());
+ this.sendMsg(msgTab);
+ this.changeHookState(hookState.ALL_HOOK);
+
+ elseif dataTable.cmd == "stopOnStepIn" then
+ this.changeRunState(runState.STEPIN);
+ local msgTab = this.getMsgTable("stopOnStepIn", this.getCallbackId());
+ this.sendMsg(msgTab);
+ this.changeHookState(hookState.ALL_HOOK);
+
+ elseif dataTable.cmd == "stopOnStepOut" then
+ this.changeRunState(runState.STEPOUT);
+ local msgTab = this.getMsgTable("stopOnStepOut", this.getCallbackId());
+ this.sendMsg(msgTab);
+ this.changeHookState(hookState.ALL_HOOK);
+
+ elseif dataTable.cmd == "setBreakPoint" then
+ this.printToVSCode("dataTable.cmd == setBreakPoint");
+ -- 璁剧疆鏂偣鏃讹紝鎶 fakeBreakPointCache 娓呯┖銆傝繖鏄竴涓畝鍗曠殑鍋氭硶锛屼篃鍙互娓呴櫎鍏蜂綋鐨勬潯鐩
+ fakeBreakPointCache = {}
+ local bkPath = dataTable.info.path;
+ bkPath = this.genUnifiedPath(bkPath);
+ if testBreakpointFlag then
+ recordBreakPointPath = bkPath;
+ end
+ if autoPathMode then
+ -- 鑷姩璺緞妯″紡涓嬶紝浠呬繚鐣欐枃浠跺悕
+ -- table[鏂囦欢鍚.鍚庣紑] -- [fullpath] -- [line , type]
+ -- | - [fullpath] -- [line , type]
+
+ local bkShortPath = this.getFilenameFromPath(bkPath);
+ if breaks[bkShortPath] == nil then
+ breaks[bkShortPath] = {};
+ end
+ breaks[bkShortPath][bkPath] = dataTable.info.bks;
+ -- 褰搗涓虹┖鏃讹紝浠庢柇鐐瑰垪琛ㄤ腑鍘婚櫎鏂囦欢
+ for k, v in pairs(breaks[bkShortPath]) do
+ if next(v) == nil then
+ breaks[bkShortPath][k] = nil;
+ end
+ end
+ else
+ if breaks[bkPath] == nil then
+ breaks[bkPath] = {};
+ end
+ -- 涓ょ骇 bk path 鏄负浜嗗拰鑷姩璺緞妯″紡缁撴瀯淇濇寔涓鑷
+ breaks[bkPath][bkPath] = dataTable.info.bks;
+ -- 褰搗涓虹┖鏃讹紝浠庢柇鐐瑰垪琛ㄤ腑鍘婚櫎鏂囦欢
+ for k, v in pairs(breaks[bkPath]) do
+ if next(v) == nil then
+ breaks[bkPath][k] = nil;
+ end
+ end
+ end
+
+ -- 褰搗涓虹┖鏃讹紝浠庢柇鐐瑰垪琛ㄤ腑鍘婚櫎鏂囦欢
+ for k, v in pairs(breaks) do
+ if next(v) == nil then
+ breaks[k] = nil;
+ end
+ end
+
+ --sync breaks to c
+ if hookLib ~= nil then
+ hookLib.sync_breakpoints();
+ end
+
+ if currentRunState ~= runState.WAIT_CMD then
+ if hookLib == nil then
+ local fileBP, G_BP =this.checkHasBreakpoint(lastRunFilePath);
+ if fileBP == false then
+ if G_BP == true then
+ this.changeHookState(hookState.MID_HOOK);
+ else
+ this.changeHookState(hookState.LITE_HOOK);
+ end
+ else
+ this.changeHookState(hookState.ALL_HOOK);
+ end
+ end
+ else
+ local msgTab = this.getMsgTable("setBreakPoint", this.getCallbackId());
+ this.sendMsg(msgTab);
+ return;
+ end
+ --鍏朵粬鏃舵満鏀跺埌breaks娑堟伅
+ local msgTab = this.getMsgTable("setBreakPoint", this.getCallbackId());
+ this.sendMsg(msgTab);
+ -- 鎵撳嵃璋冭瘯淇℃伅
+ this.printToVSCode("LuaPanda.getInfo()\n" .. this.getInfo())
+ this.debugger_wait_msg();
+ elseif dataTable.cmd == "setVariable" then
+ if currentRunState == runState.STOP_ON_ENTRY or
+ currentRunState == runState.HIT_BREAKPOINT or
+ currentRunState == runState.STEPOVER_STOP or
+ currentRunState == runState.STEPIN_STOP or
+ currentRunState == runState.STEPOUT_STOP then
+ local msgTab = this.getMsgTable("setVariable", this.getCallbackId());
+ local varRefNum = tonumber(dataTable.info.varRef);
+ local newValue = tostring(dataTable.info.newValue);
+ local needFindVariable = true; --濡傛灉鍙橀噺鏄熀纭绫诲瀷锛岀洿鎺ヨ祴鍊硷紝needFindVariable = false; 濡傛灉鍙橀噺鏄紩鐢ㄧ被鍨嬶紝needFindVariable = true
+ local varName = tostring(dataTable.info.varName);
+ -- 鏍规嵁棣栨湯鍚湁" ' 鍒ゆ柇 newValue 鏄惁鏄瓧绗︿覆
+ local first_chr = string.sub(newValue, 1, 1);
+ local end_chr = string.sub(newValue, -1, -1);
+ if first_chr == end_chr then
+ if first_chr == "'" or first_chr == '"' then
+ newValue = string.sub(newValue, 2, -2);
+ needFindVariable = false;
+ end
+ end
+ --鏁板瓧锛宯il锛宖alse锛宼rue鐨勫鐞
+ if newValue == "nil" and needFindVariable == true then newValue = nil; needFindVariable = false;
+ elseif newValue == "true" and needFindVariable == true then newValue = true; needFindVariable = false;
+ elseif newValue == "false" and needFindVariable == true then newValue = false; needFindVariable = false;
+ elseif tonumber(newValue) and needFindVariable == true then newValue = tonumber(newValue); needFindVariable = false;
+ end
+
+ -- 濡傛灉鏂板兼槸鍩虹绫诲瀷锛屽垯涓嶉渶閬嶅巻
+ if dataTable.info.stackId ~= nil and tonumber(dataTable.info.stackId) ~= nil and tonumber(dataTable.info.stackId) > 1 then
+ this.curStackId = tonumber(dataTable.info.stackId);
+ else
+ this.printToVSCode("鏈兘鑾峰彇鍒板爢鏍堝眰绾э紝榛樿浣跨敤 this.curStackId;")
+ end
+
+ if varRefNum < 10000 then
+ -- 濡傛灉淇敼鐨勬槸涓涓 寮曠敤鍙橀噺锛岄偅涔堝彲鐩存帴璧嬪笺備絾杩樻槸瑕佽蛋鍙橀噺鏌ヨ杩囩▼銆傛煡鎵惧拰璧嬪艰繃绋嬮兘闇瑕乻teakId銆 鐩墠缁欏紩鐢ㄥ彉閲忚祴鍊糘bject锛宻teak鍙兘鏈夐棶棰
+ msgTab.info = this.createSetValueRetTable(varName, newValue, needFindVariable, this.curStackId, variableRefTab[varRefNum]);
+ else
+ -- 濡傛灉淇敼鐨勬槸涓涓熀纭绫诲瀷
+ local setLimit; --璁剧疆妫绱㈠彉閲忕殑闄愬畾鍖哄煙
+ if varRefNum >= 10000 and varRefNum < 20000 then setLimit = "local";
+ elseif varRefNum >= 20000 and varRefNum < 30000 then setLimit = "global";
+ elseif varRefNum >= 30000 then setLimit = "upvalue";
+ end
+ msgTab.info = this.createSetValueRetTable(varName, newValue, needFindVariable, this.curStackId, nil, setLimit);
+ end
+
+ this.sendMsg(msgTab);
+ this.debugger_wait_msg();
+ end
+
+ elseif dataTable.cmd == "getVariable" then
+ --浠呭湪鍋滄鏃跺鐞嗘秷鎭紝鍏朵粬鏃跺埢鏀跺埌姝ゆ秷鎭紝涓㈠純
+ if currentRunState == runState.STOP_ON_ENTRY or
+ currentRunState == runState.HIT_BREAKPOINT or
+ currentRunState == runState.STEPOVER_STOP or
+ currentRunState == runState.STEPIN_STOP or
+ currentRunState == runState.STEPOUT_STOP then
+ --鍙戦佸彉閲忕粰娓告垙锛屽苟淇濇寔涔嬪墠鐨勭姸鎬,绛夊緟鍐嶆鎺ユ敹鏁版嵁
+ --dataTable.info.varRef 10000~20000灞閮ㄥ彉閲
+ -- 20000~30000鍏ㄥ眬鍙橀噺
+ -- 30000~ upvalue
+ -- 1000~2000灞閮ㄥ彉閲忕殑鏌ヨ锛2000~3000鍏ㄥ眬锛3000~4000upvalue
+ local msgTab = this.getMsgTable("getVariable", this.getCallbackId());
+ local varRefNum = tonumber(dataTable.info.varRef);
+ if varRefNum < 10000 then
+ --鏌ヨ鍙橀噺, 姝ゆ椂蹇界暐 stackId
+ local varTable = this.getVariableRef(dataTable.info.varRef, true);
+ msgTab.info = varTable;
+ elseif varRefNum >= 10000 and varRefNum < 20000 then
+ --灞閮ㄥ彉閲
+ if dataTable.info.stackId ~= nil and tonumber(dataTable.info.stackId) > 1 then
+ this.curStackId = tonumber(dataTable.info.stackId);
+ if type(currentCallStack[this.curStackId - 1]) ~= "table" or type(currentCallStack[this.curStackId - 1].func) ~= "function" then
+ local str = "getVariable getLocal currentCallStack " .. this.curStackId - 1 .. " Error\n" .. this.serializeTable(currentCallStack, "currentCallStack");
+ this.printToVSCode(str, 2);
+ msgTab.info = {};
+ else
+ local stackId = this.getSpecificFunctionStackLevel(currentCallStack[this.curStackId - 1].func); --鍘婚櫎鍋忕Щ閲
+ local varTable = this.getVariable(stackId, true);
+ msgTab.info = varTable;
+ end
+ end
+
+ elseif varRefNum >= 20000 and varRefNum < 30000 then
+ --鍏ㄥ眬鍙橀噺
+ local varTable = this.getGlobalVariable();
+ msgTab.info = varTable;
+ elseif varRefNum >= 30000 then
+ --upValue
+ if dataTable.info.stackId ~= nil and tonumber(dataTable.info.stackId) > 1 then
+ this.curStackId = tonumber(dataTable.info.stackId);
+ if type(currentCallStack[this.curStackId - 1]) ~= "table" or type(currentCallStack[this.curStackId - 1].func) ~= "function" then
+ local str = "getVariable getUpvalue currentCallStack " .. this.curStackId - 1 .. " Error\n" .. this.serializeTable(currentCallStack, "currentCallStack");
+ this.printToVSCode(str, 2);
+ msgTab.info = {};
+ else
+ local varTable = this.getUpValueVariable(currentCallStack[this.curStackId - 1 ].func, true);
+ msgTab.info = varTable;
+ end
+ end
+ end
+ this.sendMsg(msgTab);
+ this.debugger_wait_msg();
+ end
+ elseif dataTable.cmd == "initSuccess" then
+ --鍒濆鍖栦細浼犺繃鏉ヤ竴浜涘彉閲忥紝杩欓噷璁板綍杩欎簺鍙橀噺
+ --Base64
+ if dataTable.info.isNeedB64EncodeStr == "true" then
+ isNeedB64EncodeStr = true;
+ else
+ isNeedB64EncodeStr = false;
+ end
+ --path
+ luaFileExtension = dataTable.info.luaFileExtension;
+ local TempFilePath = dataTable.info.TempFilePath;
+ if TempFilePath:sub(-1, -1) == [[\]] or TempFilePath:sub(-1, -1) == [[/]] then
+ TempFilePath = TempFilePath:sub(1, -2);
+ end
+ TempFilePath_luaString = TempFilePath;
+ cwd = this.genUnifiedPath(dataTable.info.cwd);
+ --logLevel
+ logLevel = tonumber(dataTable.info.logLevel) or 1;
+ --autoPathMode
+ if dataTable.info.autoPathMode == "true" then
+ autoPathMode = true;
+ else
+ autoPathMode = false;
+ end
+
+ if dataTable.info.pathCaseSensitivity == "true" then
+ pathCaseSensitivity = true;
+ truncatedOPath = dataTable.info.truncatedOPath or "";
+ else
+ pathCaseSensitivity = false;
+ truncatedOPath = string.lower(dataTable.info.truncatedOPath or "");
+ end
+
+ if dataTable.info.distinguishSameNameFile == "true" then
+ distinguishSameNameFile = true;
+ else
+ distinguishSameNameFile = false;
+ end
+
+ --OS type
+ if nil == OSType then
+ --鐢ㄦ埛鏈富鍔ㄨ缃甇SType, 鎺ユ敹VSCode浼犳潵鐨勬暟鎹
+ if type(dataTable.info.OSType) == "string" then
+ OSType = dataTable.info.OSType;
+ else
+ OSType = "Windows_NT";
+ OSTypeErrTip = "鏈兘妫娴嬪嚭OSType, 鍙兘鏄痭ode os搴撴湭鑳藉姞杞斤紝绯荤粺浣跨敤榛樿璁剧疆Windows_NT"
+ end
+ else
+ --鐢ㄦ埛鑷OSType, 浣跨敤鐢ㄦ埛鐨勮缃
+ end
+
+ --妫娴嬬敤鎴锋槸鍚﹁嚜璁句簡clib璺緞
+ isUserSetClibPath = false;
+ if nil == clibPath then
+ --鐢ㄦ埛鏈缃甤libPath, 鎺ユ敹VSCode浼犳潵鐨勬暟鎹
+ if type(dataTable.info.clibPath) == "string" then
+ clibPath = dataTable.info.clibPath;
+ else
+ clibPath = "";
+ pathErrTip = "鏈兘姝g‘鑾峰彇libpdebug搴撴墍鍦ㄤ綅缃, 鍙兘鏃犳硶鍔犺浇libpdebug搴撱";
+ end
+ else
+ --鐢ㄦ埛鑷clibPath
+ isUserSetClibPath = true;
+ end
+
+ --鏌ユ壘c++鐨刪ook搴撴槸鍚﹀瓨鍦. 褰搇ua5.4鏃堕粯璁や笉浣跨敤c搴
+ if tostring(dataTable.info.useCHook) == "true" and "Lua 5.4" ~= _VERSION then
+ userSetUseClib = true; --鐢ㄦ埛纭畾浣跨敤clib
+ if isUserSetClibPath == true then --濡傛灉鐢ㄦ埛鑷浜哻lib璺緞
+ if luapanda_chook ~= nil then
+ hookLib = luapanda_chook;
+ else
+ if not(this.tryRequireClib("libpdebug", clibPath)) then
+ this.printToVSCode("Require clib failed, use Lua to continue debug, use LuaPanda.doctor() for more information.", 1);
+ end
+ end
+ else
+ local clibExt, platform;
+ if OSType == "Darwin" then clibExt = "/?.so;"; platform = "mac";
+ elseif OSType == "Linux" then clibExt = "/?.so;"; platform = "linux";
+ else clibExt = "/?.dll;"; platform = "win"; end
+
+ local lua_ver;
+ if _VERSION == "Lua 5.1" then
+ lua_ver = "501";
+ else
+ lua_ver = "503";
+ end
+
+ local x86Path = clibPath.. platform .."/x86/".. lua_ver .. clibExt;
+ local x64Path = clibPath.. platform .."/x86_64/".. lua_ver .. clibExt;
+
+ if luapanda_chook ~= nil then
+ hookLib = luapanda_chook;
+ else
+ if not(this.tryRequireClib("libpdebug", x64Path) or this.tryRequireClib("libpdebug", x86Path)) then
+ this.printToVSCode("Require clib failed, use Lua to continue debug, use LuaPanda.doctor() for more information.", 1);
+ end
+ end
+ end
+ else
+ userSetUseClib = false;
+ end
+
+ --adapter鐗堟湰淇℃伅
+ adapterVer = tostring(dataTable.info.adapterVersion);
+ local msgTab = this.getMsgTable("initSuccess", this.getCallbackId());
+ --鍥炰紶鏄惁浣跨敤浜唋ib锛屾槸鍚︽湁loadstring鍑芥暟
+ local isUseHookLib = 0;
+ if hookLib ~= nil then
+ isUseHookLib = 1;
+ --鍚屾鏁版嵁缁檆 hook
+ local luaVerTable = this.stringSplit(debuggerVer , '%.');
+ local luaVerNum = luaVerTable[1] * 10000 + luaVerTable[2] * 100 + luaVerTable[3];
+ if hookLib.sync_lua_debugger_ver then
+ hookLib.sync_lua_debugger_ver(luaVerNum);
+ end
+ -- hookLib.sync_config(logLevel, pathCaseSensitivity and 1 or 0, autoPathMode and 1 or 0);
+ hookLib.sync_config(logLevel, pathCaseSensitivity and 1 or 0);
+ hookLib.sync_tempfile_path(TempFilePath_luaString);
+ hookLib.sync_cwd(cwd);
+ hookLib.sync_file_ext(luaFileExtension);
+ end
+ --detect LoadString
+ isUseLoadstring = 0;
+ if debugger_loadString ~= nil and type(debugger_loadString) == "function" then
+ if(pcall(debugger_loadString("return 0"))) then
+ isUseLoadstring = 1;
+ end
+ end
+ local tab = { debuggerVer = tostring(debuggerVer) , UseHookLib = tostring(isUseHookLib) , UseLoadstring = tostring(isUseLoadstring), isNeedB64EncodeStr = tostring(isNeedB64EncodeStr) };
+ msgTab.info = tab;
+ this.sendMsg(msgTab);
+ --涓婇潰getBK涓細鍒ゆ柇褰撳墠鐘舵佹槸鍚AIT_CMD, 鎵浠ユ渶鍚庡啀鍒囨崲鐘舵併
+ stopOnEntry = dataTable.info.stopOnEntry;
+ if dataTable.info.stopOnEntry == "true" then
+ this.changeRunState(runState.STOP_ON_ENTRY); --鍋滄鍦⊿TOP_ON_ENTRY鍐嶆帴鏀禸reaks娑堟伅
+ else
+ this.debugger_wait_msg(1); --绛夊緟1s bk娑堟伅 濡傛灉鏀跺埌鎴栬秴鏃(娌℃湁鏂偣)灏卞紑濮嬭繍琛
+ this.changeRunState(runState.RUN);
+ end
+
+ elseif dataTable.cmd == "getWatchedVariable" then
+ local msgTab = this.getMsgTable("getWatchedVariable", this.getCallbackId());
+ local stackId = tonumber(dataTable.info.stackId);
+ --loadstring绯荤粺鍑芥暟, watch鎻掍欢鍔犺浇
+ if isUseLoadstring == 1 then
+ --浣跨敤loadstring
+ this.curStackId = stackId;
+ local retValue = this.processWatchedExp(dataTable.info);
+ msgTab.info = retValue
+ this.sendMsg(msgTab);
+ this.debugger_wait_msg();
+ return;
+ else
+ --鏃х殑鏌ユ壘鏂瑰紡
+ local wv = this.getWatchedVariable(dataTable.info.varName, stackId, true);
+ if wv ~= nil then
+ msgTab.info = wv;
+ end
+ this.sendMsg(msgTab);
+ this.debugger_wait_msg();
+ end
+ elseif dataTable.cmd == "stopRun" then
+ --鍋滄hook锛屽凡涓嶅湪澶勭悊浠讳綍鏂偣淇℃伅锛屼篃灏变笉浼氫骇鐢熸棩蹇楃瓑銆傚彂閫佹秷鎭悗绛夊緟鍓嶇涓诲姩鏂紑杩炴帴
+ local msgTab = this.getMsgTable("stopRun", this.getCallbackId());
+ this.sendMsg(msgTab);
+ if not luaProcessAsServer then
+ this.disconnect();
+ end
+ elseif "LuaGarbageCollect" == dataTable.cmd then
+ this.printToVSCode("collect garbage!");
+ collectgarbage("collect");
+ --鍥炴敹鍚庡埛涓涓嬪唴瀛
+ this.sendLuaMemory();
+ this.debugger_wait_msg();
+ elseif "runREPLExpression" == dataTable.cmd then
+ this.curStackId = tonumber(dataTable.info.stackId);
+ local retValue = this.processExp(dataTable.info);
+ local msgTab = this.getMsgTable("runREPLExpression", this.getCallbackId());
+ msgTab.info = retValue
+ this.sendMsg(msgTab);
+ this.debugger_wait_msg();
+ else
+ end
+end
+
+-- 鍙橀噺璧嬪肩殑澶勭悊鍑芥暟銆傚熀鏈昏緫鏄厛浠庡綋鍓嶆爤甯э紙curStackId锛変腑鍙 newValue 浠h〃鐨勫彉閲忥紝鎵惧埌涔嬪悗鍐嶆妸鎵惧埌鐨勫奸氳繃setVariableValue鍐欏洖銆
+-- @varName 琚缃肩殑鍙橀噺鍚
+-- @newValue 鏂板肩殑鍚嶅瓧锛屽畠鏄竴涓猻tring
+-- @needFindVariable 鏄惁闇瑕佹煡鎵惧紩鐢ㄥ彉閲忋傦紙鐢ㄦ埛杈撳叆鐨勬槸鍚︽槸涓涓狾bject锛
+-- @curStackId 褰撳墠鏍堝抚锛堟煡鎵惧拰鍙橀噺璧嬪肩敤锛
+-- @assigndVar 琚洿鎺ヨ祴鍊硷紙鐪佸幓鏌ユ壘杩囩▼锛
+-- @setLimit 璧嬪兼椂鐨勯檺鍒惰寖鍥达紙local upvalue global锛
+function this.createSetValueRetTable(varName, newValue, needFindVariable, curStackId, assigndVar , setLimit)
+ local info;
+ local getVarRet;
+ -- needFindVariable == true锛屽垯浣跨敤getWatchedVariable澶勭悊锛堝彲閫, 鐢ㄦ潵鏀寔 a = b (b涓哄彉閲忕殑鎯呭喌)锛夈
+ if needFindVariable == false then
+ getVarRet = {};
+ getVarRet[1] = {variablesReference = 0, value = newValue, name = varName, type = type(newValue)};
+ else
+ getVarRet = this.getWatchedVariable( tostring(newValue), curStackId, true);
+ end
+ if getVarRet ~= nil then
+ -- newValue璧嬪彉閲忕湡瀹炲
+ local realVarValue;
+ local displayVarValue = getVarRet[1].value;
+ if needFindVariable == true then
+ if tonumber(getVarRet[1].variablesReference) > 0 then
+ realVarValue = variableRefTab[tonumber(getVarRet[1].variablesReference)];
+ else
+ if getVarRet[1].type == 'number' then realVarValue = tonumber(getVarRet[1].value) end
+ if getVarRet[1].type == 'string' then
+ realVarValue = tostring(getVarRet[1].value);
+ local first_chr = string.sub(realVarValue, 1, 1);
+ local end_chr = string.sub(realVarValue, -1, -1);
+ if first_chr == end_chr then
+ if first_chr == "'" or first_chr == '"' then
+ realVarValue = string.sub(realVarValue, 2, -2);
+ displayVarValue = realVarValue;
+ end
+ end
+ end
+ if getVarRet[1].type == 'boolean' then
+ if getVarRet[1].value == "true" then
+ realVarValue = true;
+ else
+ realVarValue = false;
+ end
+ end
+ if getVarRet[1].type == 'nil' then realVarValue = nil end
+ end
+ else
+ realVarValue = getVarRet[1].value;
+ end
+
+ local setVarRet;
+ if type(assigndVar) ~= table then
+ setVarRet = this.setVariableValue( varName, curStackId, realVarValue, setLimit );
+ else
+ assigndVar[varName] = realVarValue;
+ setVarRet = true;
+ end
+
+ if getVarRet[1].type == "string" then
+ displayVarValue = '"' .. displayVarValue .. '"';
+ end
+
+ if setVarRet ~= false and setVarRet ~= nil then
+ local retTip = "鍙橀噺 ".. varName .." 璧嬪兼垚鍔";
+ info = { success = "true", name = getVarRet[1].name , type = getVarRet[1].type , value = displayVarValue, variablesReference = tostring(getVarRet[1].variablesReference), tip = retTip};
+ else
+ info = { success = "false", type = type(realVarValue), value = displayVarValue, tip = "鎵句笉鍒拌璁剧疆鐨勫彉閲"};
+ end
+
+ else
+ info = { success = "false", type = nil, value = nil, tip = "杈撳叆鐨勫兼棤鎰忎箟"};
+ end
+ return info
+end
+
+--鎺ユ敹娑堟伅
+--杩欓噷缁存姢涓涓帴鏀舵秷鎭槦鍒楋紝鍥犱负Lua绔湭鍋氶殧鏂淇濇姢锛屽彉閲忚祴鍊兼椂璇锋敞鎰忓叾涓笉瑕佸寘鍚殧鏂 |*|
+-- @timeoutSec 瓒呮椂鏃堕棿
+-- @return boolean 鎴愬姛/澶辫触
+function this.receiveMessage( timeoutSec )
+ timeoutSec = timeoutSec or MAX_TIMEOUT_SEC;
+ sock:settimeout(timeoutSec);
+ --濡傛灉闃熷垪涓繕鏈夋秷鎭紝鐩存帴鍙栧嚭鏉ヤ氦缁檇ataProcess澶勭悊
+ if #recvMsgQueue > 0 then
+ local saved_cmd = recvMsgQueue[1];
+ table.remove(recvMsgQueue, 1);
+ this.dataProcess(saved_cmd);
+ return true;
+ end
+
+ if currentRunState == runState.DISCONNECT then
+ this.disconnect();
+ return false;
+ end
+
+ if sock == nil then
+ this.printToConsole("[debugger error]鎺ユ敹淇℃伅澶辫触 | reason: socket == nil", 2);
+ return;
+ end
+ local response, err = sock:receive();
+ if response == nil then
+ if err == "closed" then
+ this.printToConsole("[debugger error]鎺ユ敹淇℃伅澶辫触 | reason:"..err, 2);
+ this.disconnect();
+ end
+ return false;
+ else
+
+ --鍒ゆ柇鏄惁鏄竴鏉℃秷鎭紝鍒嗘媶
+ local proc_response = string.sub(response, 1, -1 * (TCPSplitChar:len() + 1 ));
+ local match_res = string.find(proc_response, TCPSplitChar, 1, true);
+ if match_res == nil then
+ --鍗曟潯
+ this.dataProcess(proc_response);
+ else
+ --鏈夌矘鍖
+ repeat
+ --寰呭鐞嗗懡浠
+ local str1 = string.sub(proc_response, 1, match_res - 1);
+ table.insert(recvMsgQueue, str1);
+ --鍓╀綑鍖归厤
+ local str2 = string.sub(proc_response, match_res + TCPSplitChar:len() , -1);
+ match_res = string.find(str2, TCPSplitChar, 1, true);
+ until not match_res
+ this.receiveMessage();
+ end
+ return true;
+ end
+end
+
+--杩欓噷涓嶇敤寰幆锛屽湪澶栭潰澶勭悊瀹屾秷鎭細鍦ㄨ皟鐢ㄥ洖鏉
+-- @timeoutSec 绛夊緟鏃堕棿s
+-- @entryFlag 鍏ュ彛鏍囪锛岀敤鏉ユ爣璇嗘槸浠庡摢閲岃皟鍏ョ殑
+function this.debugger_wait_msg(timeoutSec)
+ timeoutSec = timeoutSec or MAX_TIMEOUT_SEC;
+
+ if currentRunState == runState.WAIT_CMD then
+ local ret = this.receiveMessage(timeoutSec);
+ return ret;
+ end
+
+ if currentRunState == runState.STEPOVER or
+ currentRunState == runState.STEPIN or
+ currentRunState == runState.STEPOUT or
+ currentRunState == runState.RUN then
+ this.receiveMessage(0);
+ return
+ end
+
+ if currentRunState == runState.STEPOVER_STOP or
+ currentRunState == runState.STEPIN_STOP or
+ currentRunState == runState.STEPOUT_STOP or
+ currentRunState == runState.HIT_BREAKPOINT or
+ currentRunState == runState.STOP_ON_ENTRY
+ then
+ this.sendLuaMemory();
+ this.receiveMessage(MAX_TIMEOUT_SEC);
+ return
+ end
+end
+
+-----------------------------------------------------------------------------
+-- 璋冭瘯鍣ㄦ牳蹇冩柟娉
+-----------------------------------------------------------------------------
+
+------------------------鍫嗘爤绠$悊-------------------------
+
+
+--getStackTable闇瑕佸缓绔媠tackTable锛屼繚瀛樻瘡灞傜殑lua鍑芥暟瀹炰緥(鐢ㄦ潵鍙杣pvalue)锛屼繚瀛樺嚱鏁板睍绀哄眰绾у拰ly鐨勫叧绯(渚夸簬鏍规嵁鍓嶇浼犳潵鐨剆tackId鏌ュ眬閮ㄥ彉閲)
+-- @level 瑕佽幏鍙栫殑灞傜骇
+function this.getStackTable( level )
+ local functionLevel = 0
+ if hookLib ~= nil then
+ functionLevel = level or HOOK_LEVEL;
+ else
+ functionLevel = level or this.getSpecificFunctionStackLevel(lastRunFunction.func);
+ end
+ local stackTab = {};
+ local userFuncSteakLevel = 0; --鐢ㄦ埛鍑芥暟鐨剆teaklevel
+ local clevel = 0
+ repeat
+ local info = debug.getinfo(functionLevel, "SlLnf")
+ if info == nil then
+ break;
+ end
+ if info.source ~= "=[C]" then
+ local ss = {};
+ ss.file = this.getPath(info);
+ local oPathFormated = this.formatOpath(info.source) ; --浠巐ua铏氭嫙鏈鸿幏寰楃殑鍘熷璺緞, 瀹冪敤浜庡府鍔╁畾浣峍Scode绔師濮媗ua鏂囦欢鐨勪綅缃(瀛樺湪閲嶅悕鏂囦欢鐨勬儏鍐)銆
+ ss.oPath = this.truncatedPath(oPathFormated, truncatedOPath);
+ ss.name = "鏂囦欢鍚"; --杩欓噷瑕佸仛鎴彇
+ ss.line = tostring(info.currentline);
+ --浣跨敤hookLib鏃讹紝鍫嗘爤鏈夊亸绉婚噺锛岃繖閲岀粺涓璋冪敤鏍堥《缂栧彿2
+ local ssindex = functionLevel - 3;
+ if hookLib ~= nil then
+ ssindex = ssindex + 2;
+ end
+ ss.index = tostring(ssindex);
+ table.insert(stackTab,ss);
+ --鎶婃暟鎹瓨鍏urrentCallStack
+ local callStackInfo = {};
+ callStackInfo.name = ss.file;
+ callStackInfo.line = ss.line;
+ callStackInfo.func = info.func; --淇濆瓨鐨刦unction
+ callStackInfo.realLy = functionLevel; --鐪熷疄鍫嗘爤灞俧unctionLevel(浠卍ebug鏃剁敤)
+ table.insert(currentCallStack, callStackInfo);
+
+ --level璧嬪
+ if userFuncSteakLevel == 0 then
+ userFuncSteakLevel = functionLevel;
+ end
+ else
+ local callStackInfo = {};
+ callStackInfo.name = info.source;
+ callStackInfo.line = info.currentline; --C鍑芥暟琛屽彿
+ callStackInfo.func = info.func; --淇濆瓨鐨刦unction
+ callStackInfo.realLy = functionLevel; --鐪熷疄鍫嗘爤灞俧unctionLevel(浠卍ebug鏃剁敤)
+ table.insert(currentCallStack, callStackInfo);
+ clevel = clevel + 1
+ end
+ functionLevel = functionLevel + 1;
+ until info == nil
+ return stackTab, userFuncSteakLevel;
+end
+
+-- 鎶婅矾寰勪腑鍘婚櫎鍚庣紑閮ㄥ垎鐨.鍙樹负/,
+-- @filePath 琚浛鎹㈢殑璺緞
+-- @ext 鍚庣紑(鍚庣紑鍓嶇殑 . 涓嶄細琚浛鎹)
+function this.changePotToSep(filePath, ext)
+ local idx = filePath:find(ext, (-1) * ext:len() , true)
+ if idx then
+ local tmp = filePath:sub(1, idx - 1):gsub("%.", "/");
+ filePath = tmp .. ext;
+ end
+ return filePath;
+end
+
+--- this.truncatedPath 浠 beTruncatedPath 瀛楃涓蹭腑鍘婚櫎 rep 鍖归厤鍒扮殑閮ㄥ垎
+function this.truncatedPath(beTruncatedPath, rep)
+ if beTruncatedPath and beTruncatedPath ~= '' and rep and rep ~= "" then
+ local _, lastIdx = string.find(beTruncatedPath , rep);
+ if lastIdx then
+ beTruncatedPath = string.sub(beTruncatedPath, lastIdx + 1);
+ end
+ end
+ return beTruncatedPath;
+end
+
+--杩欎釜鏂规硶鏄牴鎹殑cwd鍜宭uaFileExtension瀵筭etInfo鑾峰彇鍒扮殑璺緞杩涜鏍囧噯鍖
+-- @info getInfo鑾峰彇鐨勫寘鍚皟鐢ㄤ俊鎭痶able
+function this.getPath( info )
+ local filePath = info;
+ if type(info) == "table" then
+ filePath = info.source;
+ end
+ --灏濊瘯浠嶤ache涓幏鍙栬矾寰
+ local cachePath = this.getCacheFormatPath(filePath);
+ if cachePath~= nil and type(cachePath) == "string" then
+ return cachePath;
+ end
+
+ -- originalPath鏄痝etInfo鐨勫師濮嬭矾寰勶紝鍚庨潰鐢ㄦ潵濉厖璺緞缂撳瓨鐨刱ey
+ local originalPath = filePath;
+
+ --濡傛灉璺緞澶撮儴鏈堾,鍘婚櫎
+ if filePath:sub(1,1) == '@' then
+ filePath = filePath:sub(2);
+ end
+
+ --濡傛灉璺緞澶撮儴鏈./,鍘婚櫎
+ if filePath:sub(1,2) == './' then
+ filePath = filePath:sub(3);
+ end
+ -- getPath鐨勫弬鏁拌矾寰勫彲鑳芥潵鑷簬hook, 涔熷彲鑳芥槸涓涓凡鏍囧噯鐨勮矾寰
+ if userDotInRequire then
+ if autoExt == nil or autoExt == '' then
+ -- 鍦ㄨ櫄鎷熸満杩斿洖璺緞娌℃湁鍚庣紑鐨勬儏鍐典笅锛岀敤鎴峰繀椤昏嚜璁惧悗缂
+ -- 纭畾filePath涓渶鍚庝竴涓.xxx 涓嶇瓑浜庣敤鎴烽厤缃殑鍚庣紑, 鍒欐妸鎵鏈夌殑. 杞负 /
+ if not filePath:find(luaFileExtension , (-1) * luaFileExtension:len(), true) then
+ -- getinfo 璺緞娌℃湁鍚庣紑锛屾妸 . 鍏ㄩ儴鏇挎崲鎴 / 锛屾垜浠笉鍏佽鐢ㄦ埛鍦ㄦ枃浠讹紙鎴栨枃浠跺す锛夊悕绉颁腑鍑虹幇"." , 鍥犱负鏃犳硶鍖哄垎
+ filePath = string.gsub(filePath, "%.", "/");
+ else
+ -- 鏈夊悗缂锛岄偅涔堟妸闄ゅ悗缂澶栫殑閮ㄥ垎涓殑. 杞负 /
+ filePath = this.changePotToSep(filePath, luaFileExtension);
+ end
+
+ else
+ -- 铏氭嫙鏈鸿矾寰勬湁鍚庣紑
+ filePath = this.changePotToSep(filePath, autoExt);
+ end
+ end
+
+ --鍚庣紑澶勭悊
+ if luaFileExtension ~= "" then
+ --鍒ゆ柇鍚庣紑涓槸鍚﹀寘鍚%1绛夐瓟娉曞瓧绗.鐢ㄤ簬浠巐ua铏氭嫙鏈鸿幏鍙栧埌鐨勮矾寰勫惈.鐨勬儏鍐
+ if string.find(luaFileExtension, "%%%d") then
+ filePath = string.gsub(filePath, "%.[%w%.]+$", luaFileExtension);
+ else
+ filePath = string.gsub(filePath, "%.[%w%.]+$", "");
+ filePath = filePath .. "." .. luaFileExtension;
+ end
+ end
+
+
+ if not autoPathMode then
+ --缁濆璺緞鍜岀浉瀵硅矾寰勭殑澶勭悊 | 鑻ュ湪Mac涓嬩互/寮澶达紝鎴栬呭湪Win涓嬩互*:寮澶达紝璇存槑鏄粷瀵硅矾寰勶紝涓嶉渶瑕佸啀鎷笺
+ if filePath:sub(1,1) == [[/]] or filePath:sub(1,2):match("^%a:") then
+ isAbsolutePath = true;
+ else
+ isAbsolutePath = false;
+ if cwd ~= "" then
+ --鏌ョ湅filePath涓槸鍚﹀寘鍚玞wd
+ local matchRes = string.find(filePath, cwd, 1, true);
+ if matchRes == nil then
+ filePath = cwd.."/"..filePath;
+ end
+ end
+ end
+ end
+ filePath = this.genUnifiedPath(filePath);
+
+ if autoPathMode then
+ -- 鑷姩璺緞妯″紡涓嬶紝鍙繚鐣欐枃浠跺悕
+ filePath = this.getFilenameFromPath(filePath)
+ end
+ --鏀惧叆Cache涓紦瀛
+ this.setCacheFormatPath(originalPath, filePath);
+ return filePath;
+end
+
+--浠庤矾寰勪腑鑾峰彇[鏂囦欢鍚.鍚庣紑]
+function this.getFilenameFromPath(path)
+ if path == nil then
+ return '';
+ end
+
+ return string.match(path, "([^/]*)$");
+end
+
+--鑾峰彇褰撳墠鍑芥暟鐨勫爢鏍堝眰绾
+--鍘熺悊鏄悜涓婃煡鎵撅紝閬囧埌DebuggerFileName灏辫皟杩囥備絾鏄彲鑳藉瓨鍦ㄤ唬鐮佹鍜孋瀵艰嚧涓嶇‘瀹氭с傜洰鍓嶄娇鐢╣etSpecificFunctionStackLevel浠f浛銆
+function this.getCurrentFunctionStackLevel()
+ -- print(debug.traceback("===getCurrentFunctionStackLevel Stack trace==="))
+ local funclayer = 2;
+ repeat
+ local info = debug.getinfo(funclayer, "S"); --閫氳繃name鏉ュ垽鏂
+ if info ~= nil then
+ local matchRes = ((info.source == DebuggerFileName) or (info.source == DebuggerToolsName));
+ if matchRes == false then
+ return (funclayer - 1);
+ end
+ end
+ funclayer = funclayer + 1;
+ until not info
+ return 0;
+end
+
+--鑾峰彇鎸囧畾鍑芥暟鐨勫爢鏍堝眰绾
+--閫氬父鐢ㄦ潵鑾峰彇鏈鍚庝竴涓敤鎴峰嚱鏁扮殑灞傜骇锛岀敤娉曟槸浠巆urrentCallStack鍙栫敤鎴风偣鍑荤殑鏍堬紝鍐嶄娇鐢ㄦ湰鍑芥暟鍙栧搴斿眰绾с
+-- @func 琚幏鍙栧眰绾х殑function
+function this.getSpecificFunctionStackLevel( func )
+ local funclayer = 2;
+ repeat
+ local info = debug.getinfo(funclayer, "f"); --閫氳繃name鏉ュ垽鏂
+ if info ~= nil then
+ if info.func == func then
+ return (funclayer - 1);
+ end
+ end
+ funclayer = funclayer + 1;
+ until not info
+ return 0;
+end
+
+--妫鏌ュ綋鍓嶅爢鏍堟槸鍚︽槸Lua
+-- @checkLayer 鎸囧畾鐨勬爤灞
+function this.checkCurrentLayerisLua( checkLayer )
+ local info = debug.getinfo(checkLayer, "S");
+ if info == nil then
+ return nil;
+ end
+ info.source = this.genUnifiedPath(info.source);
+ if info ~= nil then
+ for k,v in pairs(info) do
+ if k == "what" then
+ if v == "C" then
+ return false;
+ else
+ return true;
+ end
+ end
+ end
+ end
+ return nil;
+end
+
+-- 鍦 fakeBreakPointCache 涓煡璇㈡鏂偣鏄惁鐪熷疄瀛樺湪
+-- 鍥犱负鍚屽悕鏂囦欢鐨勫奖鍝嶏紝 鏈変簺鏂偣鏄懡涓敊璇殑銆傜粡杩嘨Scode鏍¢獙鍚庯紝杩欎簺閿欒鍛戒腑鐨勬柇鐐逛俊鎭瀛樺湪fakeBreakPointCache涓
+function this.checkRealHitBreakpoint( oPath, line )
+ -- 鍦ㄥ亣鍛戒腑鍒楄〃涓悳绱紝濡傛灉鏈鏈夎繃鍋囧懡涓褰曪紝杩斿洖 false
+ if oPath and fakeBreakPointCache[oPath] then
+ for _, value in ipairs(fakeBreakPointCache[oPath]) do
+ if tonumber(value) == tonumber(line) then
+ this.printToVSCode("cache hit bp in same name file. source:" .. tostring(oPath) .. " line:" .. tostring(line));
+ return false;
+ end
+ end
+ end
+ return true;
+end
+
+------------------------鏂偣澶勭悊-------------------------
+--- this.isHitBreakpoint 鍒ゆ柇鏂偣鏄惁鍛戒腑銆傝繖涓柟娉曞湪c mod浠ュ強lua涓兘鏈夎皟鐢
+-- @param breakpointPath 鏂囦欢鍚+鍚庣紑
+-- @param opath getinfo path
+-- @param curLine 褰撳墠鎵ц琛屽彿
+function this.isHitBreakpoint(breakpointPath, opath, curLine)
+ if breaks[breakpointPath] then
+ local oPathFormated;
+ for fullpath, fullpathNode in pairs(breaks[breakpointPath]) do
+ recordBreakPointPath = fullpath; --杩欓噷鏄负浜嗗吋瀹圭敤鎴锋柇鐐硅鍙锋病鏈夋墦瀵圭殑鎯呭喌
+ local line_hit,cur_node = false,{};
+ for _, node in ipairs(fullpathNode) do
+ if tonumber(node["line"]) == tonumber(curLine) then
+ line_hit = true; -- fullpath 鏂囦欢涓 鏈夎鍙峰懡涓
+ cur_node = node;
+ recordBreakPointPath = fullpath; --琛屽彿鍛戒腑鍚庯紝鍐嶈缃竴娆★紝淇濊瘉璺緞鍑嗙‘
+ break;
+ end
+ end
+
+ -- 鍦╨ua绔笉鐭ラ亾鏄惁鏈夊悓鍚嶆枃浠讹紝鍩烘湰鎬濊矾鏄厛鍙栨枃浠跺悕锛岀敤鏂囦欢鍚嶅拰breakpointArray 杩涜鍖归厤銆
+ -- 褰撴枃浠跺悕鍖归厤涓婃椂锛屽彲鑳藉瓨鍦ㄥ涓悓鍚嶆枃浠朵腑瀛樺湪鏂偣鐨勬儏鍐点傝繖鏃跺欓渶瑕佺敤 oPath 鍜 fullpath 杩涜瀵规瘮锛屽彇鍑烘纭殑銆
+ -- 褰撴湰鍦版枃浠朵腑鏈夋柇鐐癸紝lua鍋氫簡鍒濇鍛戒腑鍚庯紝鍙兘瀛樺湪 stack , 鏂偣鏂囦欢鏈夊悓鍚嶇殑鎯呭喌銆傝繖灏遍渶瑕乿scode绔篃闇瑕乧heckfullpath鍑芥暟锛屼娇鐢╫path杩涜鏂囦欢鏍¢獙銆
+ if line_hit then
+ if oPathFormated == nil then
+ -- 涓轰簡閬垮厤鎬ц兘娑堣楋紝浠呭湪琛屽彿鍛戒腑鏃舵墠澶勭悊 opath 鍒版爣鍑嗗寲璺緞
+ oPathFormated = this.formatOpath(opath);
+ -- 鎴彇
+ oPathFormated = this.truncatedPath(oPathFormated, truncatedOPath);
+ end
+
+ if (not distinguishSameNameFile) or (string.match(fullpath, oPathFormated ) and this.checkRealHitBreakpoint(opath, curLine)) then
+ -- type鏄疶S涓殑鏋氫妇绫诲瀷锛屽叾瀹氫箟鍦˙reakPoint.tx鏂囦欢涓
+ -- enum BreakpointType {
+ -- conditionBreakpoint = 0,
+ -- logPoint,
+ -- lineBreakpoint
+ -- }
+
+ -- 澶勭悊鏂偣
+ if cur_node["type"] == "0" then
+ -- condition breakpoint
+ -- 娉ㄦ剰姝ゅ涓嶈浣跨敤灏捐皟鐢紝鍚﹀垯浼氬奖鍝嶈皟鐢ㄦ爤锛屽鑷碙ua5.3鍜孡ua5.1涓皟鐢ㄦ爤灞傜骇涓嶅悓
+ local conditionRet = this.IsMeetCondition(cur_node["condition"]);
+ -- this.printToVSCode("Condition BK: condition:" .. cur_node["condition"] .. " conditionRet " .. tostring(conditionRet));
+ return conditionRet;
+ elseif cur_node["type"] == "1" then
+ -- log point
+ this.printToVSCode("[LogPoint Output]: " .. cur_node["logMessage"], 2, 2);
+ return false;
+ else
+ -- line breakpoint
+ return true;
+ end
+ end
+ end
+ end
+ else
+ testBreakpointFlag = false; --濡傛灉鐢ㄦ埛鎵撳紑浜嗘祴璇曟柇鐐圭殑鏍囧織浣嶈屾湭涓诲姩鍏抽棴锛屼細鍦╨ua缁х画杩愯鏃跺叧闂
+ recordBreakPointPath = ''; --褰撳垏鎹㈡枃浠舵椂缃┖锛岄伩鍏嶆彁绀虹粰鐢ㄦ埛閿欒淇℃伅
+ end
+ return false;
+end
+
+-- 鏉′欢鏂偣澶勭悊鍑芥暟
+-- 杩斿洖true琛ㄧず鏉′欢鎴愮珛
+-- @conditionExp 鏉′欢琛ㄨ揪寮
+function this.IsMeetCondition(conditionExp)
+ -- 鍒ゆ柇鏉′欢涔嬪墠鏇存柊鍫嗘爤淇℃伅
+ currentCallStack = {};
+ variableRefTab = {};
+ variableRefIdx = 1;
+ if hookLib then
+ this.getStackTable(4);
+ else
+ this.getStackTable();
+ end
+
+ this.curStackId = 2; --鍦ㄧ敤鎴风┖闂存渶涓婂眰鎵ц
+
+ local conditionExpTable = {["varName"] = conditionExp}
+ local retTable = this.processWatchedExp(conditionExpTable)
+
+ local isMeetCondition = false;
+ local function HandleResult()
+ if retTable[1]["isSuccess"] == "true" then
+ if retTable[1]["value"] == "nil" or (retTable[1]["value"] == "false" and retTable[1]["type"] == "boolean") then
+ isMeetCondition = false;
+ else
+ isMeetCondition = true;
+ end
+ else
+ isMeetCondition = false;
+ end
+ end
+
+ xpcall(HandleResult, function() isMeetCondition = false; end)
+ return isMeetCondition;
+end
+
+--鍔犲叆鏂偣鍑芥暟
+function this.BP()
+ this.printToConsole("BP()");
+ if hookLib == nil then
+ if currentHookState == hookState.DISCONNECT_HOOK then
+ this.printToConsole("BP() but NO HOOK");
+ return;
+ end
+
+ local co, isMain = coroutine.running();
+ if _VERSION == "Lua 5.1" then
+ if co == nil then
+ isMain = true;
+ else
+ isMain = false;
+ end
+ end
+
+ if isMain == true then
+ this.printToConsole("BP() in main");
+ else
+ this.printToConsole("BP() in coroutine");
+ debug.sethook(co, this.debug_hook, "lrc");
+ end
+ hitBP = true;
+ else
+ if hookLib.get_libhook_state() == hookState.DISCONNECT_HOOK then
+ this.printToConsole("BP() but NO C HOOK");
+ return;
+ end
+
+ --clib, set hitBP
+ hookLib.sync_bp_hit(1);
+ end
+ this.changeHookState(hookState.ALL_HOOK);
+ return true;
+end
+
+-- 妫鏌ュ綋鍓嶆枃浠朵腑鏄惁鏈夋柇鐐
+-- 濡傛灉濉啓鍙傛暟fileName 杩斿洖fileName涓湁鏃犳柇鐐癸紝 鍏ㄥ眬鏈夋棤鏂偣
+-- fileName涓虹┖锛岃繑鍥炲叏灞鏄惁鏈夋柇鐐
+function this.checkHasBreakpoint(fileName)
+ local hasBk = false;
+ --鏈夋棤鍏ㄥ眬鏂偣
+ if next(breaks) == nil then
+ hasBk = false;
+ else
+ hasBk = true;
+ end
+ --褰撳墠鏂囦欢涓槸鍚︽湁鏂偣
+ if fileName ~= nil then
+ return breaks[fileName] ~= nil, hasBk;
+ else
+ return hasBk;
+ end
+end
+
+function this.checkfuncHasBreakpoint(sLine, eLine, fileName)
+ if breaks[fileName] == nil then
+ return false;
+ end
+ sLine = tonumber(sLine);
+ eLine = tonumber(eLine);
+
+ --璧峰琛屽彿>缁撴潫琛屽彿锛屾垨鑰卻Line = eLine = 0
+ if sLine >= eLine then
+ return true;
+ end
+
+ if this.getTableMemberNum(breaks[fileName]) <= 0 then
+ return false;
+ else
+ for k,v in pairs(breaks[fileName]) do
+ for _, node in ipairs(v) do
+ if tonumber(node.line) > sLine and tonumber(node.line) <= eLine then
+ return true;
+ end
+ end
+ end
+ end
+ return false;
+end
+------------------------HOOK妯″潡-------------------------
+-- 閽╁瓙鍑芥暟
+-- @event 鎵ц鐘舵(call,return,line)
+-- @line 琛屽彿
+function this.debug_hook(event, line)
+ if this.reConnect() == 0 then return; end
+
+ if logLevel == 0 then
+ local logTable = {"-----enter debug_hook-----\n", "event:", event, " line:", tostring(line), " currentHookState:",currentHookState," currentRunState:", currentRunState};
+ local logString = table.concat(logTable);
+ this.printToVSCode(logString);
+ end
+
+ --litehook 浠呴潪闃诲鎺ユ敹鏂偣
+ if currentHookState == hookState.LITE_HOOK then
+ local ti = os.time();
+ if ti - receiveMsgTimer > 1 then
+ this.debugger_wait_msg(0);
+ receiveMsgTimer = ti;
+ end
+ return;
+ end
+
+ --杩愯涓
+ local info;
+ local co, isMain = coroutine.running();
+ if _VERSION == "Lua 5.1" then
+ if co == nil then
+ isMain = true;
+ else
+ isMain = false;
+ end
+ end
+ isInMainThread = isMain;
+ if isMain == true then
+ info = debug.getinfo(2, "Slf")
+ else
+ info = debug.getinfo(co, 2, "Slf")
+ end
+ info.event = event;
+
+ this.real_hook_process(info);
+end
+
+function this.real_hook_process(info)
+ local jumpFlag = false;
+ local event = info.event;
+
+ --濡傛灉褰撳墠琛屽湪Debugger涓紝涓嶅仛澶勭悊
+ local matchRes = ((info.source == DebuggerFileName) or (info.source == DebuggerToolsName));
+ if matchRes == true then
+ return;
+ end
+
+ --鍗充娇MID hook鍦–涓, 鎴栬呮槸Run鎴栬呭崟姝ユ椂涔熸帴鏀舵秷鎭
+ if currentRunState == runState.RUN or
+ currentRunState == runState.STEPOVER or
+ currentRunState == runState.STEPIN or
+ currentRunState == runState.STEPOUT then
+ local ti = os.time();
+ if ti - receiveMsgTimer > 1 then
+ this.debugger_wait_msg(0);
+ receiveMsgTimer = ti;
+ end
+ end
+
+ --涓嶅鐞咰鍑芥暟
+ if info.source == "=[C]" then
+ this.printToVSCode("current method is C");
+ return;
+ end
+
+ --涓嶅鐞 slua "temp buffer"
+ if info.source == "temp buffer" then
+ this.printToVSCode("current method is in temp buffer");
+ return;
+ end
+
+ --涓嶅鐞 xlua "chunk"
+ if info.source == "chunk" then
+ this.printToVSCode("current method is in chunk");
+ return;
+ end
+
+ --lua 浠g爜娈电殑澶勭悊锛岀洰鍓嶆殏涓嶈皟璇曚唬鐮佹銆
+ if info.short_src:match("%[string \"") then
+ --褰搒hortSrc涓嚭鐜癧string鏃禲銆傝妫鏌ヤ竴涓媠ource, 鍖哄埆鏄矾寰勮繕鏄唬鐮佹. 鏂规硶鏄湅璺緞涓湁娌℃湁\t \n ;
+ if info.source:match("[\n;=]") then
+ --鏄唬鐮佹锛岃皟杩
+ this.printToVSCode("hook jump Code String!");
+ jumpFlag = true;
+ end
+ end
+
+ --鏍囧噯璺緞澶勭悊
+ if jumpFlag == false then
+ info.orininal_source = info.source; --浣跨敤 info.orininal_source 璁板綍lua铏氭嫙鏈轰紶鏉ョ殑鍘熷璺緞
+ info.source = this.getPath(info);
+ end
+ --鏈鎵ц鐨勫嚱鏁板拰涓婃鎵ц鐨勫嚱鏁颁綔瀵规瘮锛岄槻姝㈠湪涓琛屽仠鐣欎袱娆
+ if lastRunFunction["currentline"] == info["currentline"] and lastRunFunction["source"] == info["source"] and lastRunFunction["func"] == info["func"] and lastRunFunction["event"] == event then
+ this.printToVSCode("run twice");
+ end
+ --璁板綍鏈鍚庝竴娆¤皟鐢ㄤ俊鎭
+ if jumpFlag == false then
+ lastRunFunction = info;
+ lastRunFunction["event"] = event;
+ lastRunFilePath = info.source;
+ end
+ --杈撳嚭鍑芥暟淇℃伅鍒板墠鍙
+ if logLevel == 0 and jumpFlag == false then
+ local logTable = {"[lua hook] event:", tostring(event), " currentRunState:",tostring(currentRunState)," currentHookState:",tostring(currentHookState)," jumpFlag:", tostring(jumpFlag)};
+ for k,v in pairs(info) do
+ table.insert(logTable, tostring(k));
+ table.insert(logTable, ":");
+ table.insert(logTable, tostring(v));
+ table.insert(logTable, " ");
+ end
+ local logString = table.concat(logTable);
+ this.printToVSCode(logString);
+ end
+
+ --浠呭湪line鏃跺仛鏂偣鍒ゆ柇銆傝繘浜嗘柇鐐逛箣鍚庝笉鍐嶈繘鍏ユ湰娆TEP绫诲瀷鐨勫垽鏂紝鐢ˋflag鍋氭爣璁
+ local isHit = false;
+ if tostring(event) == "line" and jumpFlag == false then
+ if currentRunState == runState.RUN or currentRunState == runState.STEPOVER or currentRunState == runState.STEPIN or currentRunState == runState.STEPOUT then
+ --鏂偣鍒ゆ柇
+ isHit = this.isHitBreakpoint(info.source, info.orininal_source, info.currentline) or hitBP;
+ if isHit == true then
+ this.printToVSCode("HitBreakpoint!");
+ --澶囦唤淇℃伅
+ local recordStepOverCounter = stepOverCounter;
+ local recordStepOutCounter = stepOutCounter;
+ local recordCurrentRunState = currentRunState;
+ --璁℃暟鍣ㄦ竻0
+ stepOverCounter = 0;
+ stepOutCounter = 0;
+ this.changeRunState(runState.HIT_BREAKPOINT);
+ hitBpTwiceCheck = true; -- 鍛戒腑鏍囧織榛樿璁剧疆涓簍rue, 濡傛灉鏍¢獙閫氳繃锛屼細淇濈暀杩欎釜鏍囪锛屾牎楠屽け璐ヤ細淇敼
+ if hitBP then
+ hitBP = false; --hitBP鏄柇鐐圭‖鎬у懡涓爣璁
+ --鍙戞秷鎭苟绛夊緟
+ this.SendMsgWithStack("stopOnCodeBreakpoint");
+ else
+ --鍙戞秷鎭苟绛夊緟
+ this.SendMsgWithStack("stopOnBreakpoint");
+ --鑻ヤ簩娆℃牎楠屾湭鍛戒腑锛屾仮澶嶇姸鎬
+ if hitBpTwiceCheck == false then
+ isHit = false;
+ -- 纭鏈懡涓紝鎶婄姸鎬佹仮澶嶏紝缁х画杩愯
+ this.changeRunState(recordCurrentRunState);
+ stepOverCounter = recordStepOverCounter;
+ stepOutCounter = recordStepOutCounter;
+ end
+ end
+ end
+ end
+ end
+
+ if isHit == true then
+ return;
+ end
+
+ if currentRunState == runState.STEPOVER then
+ -- line stepOverCounter!= 0 涓嶄綔鎿嶄綔
+ -- line stepOverCounter == 0 鍋滄
+ if event == "line" and stepOverCounter <= 0 and jumpFlag == false then
+ stepOverCounter = 0;
+ this.changeRunState(runState.STEPOVER_STOP)
+ this.SendMsgWithStack("stopOnStep");
+ elseif event == "return" or event == "tail return" then
+ --5.1涓槸tail return
+ if stepOverCounter ~= 0 then
+ stepOverCounter = stepOverCounter - 1;
+ end
+ elseif event == "call" then
+ stepOverCounter = stepOverCounter + 1;
+ end
+ elseif currentRunState == runState.STOP_ON_ENTRY then
+ --鍦↙ua鍏ュ彛鐐瑰鐩存帴鍋滀綇
+ if event == "line" and jumpFlag == false then
+ --鍒濆鍖栧唴瀛樺垎鏋愮殑鍙橀噺
+ -- MemProfiler.getSystemVar();
+ --杩欓噷瑕佸垽鏂竴涓嬫槸Lua鐨勫叆鍙g偣锛屽惁鍒欏仠鍒
+ this.SendMsgWithStack("stopOnEntry");
+ end
+ elseif currentRunState == runState.STEPIN then
+ if event == "line" and jumpFlag == false then
+ this.changeRunState(runState.STEPIN_STOP)
+ this.SendMsgWithStack("stopOnStepIn");
+ end
+ elseif currentRunState == runState.STEPOUT then
+ --line 涓嶅仛鎿嶄綔
+ --in 璁℃暟鍣+1
+ --out 璁℃暟鍣-1
+ if jumpFlag == false then
+ if stepOutCounter <= -1 then
+ stepOutCounter = 0;
+ this.changeRunState(runState.STEPOUT_STOP)
+ this.SendMsgWithStack("stopOnStepOut");
+ end
+ end
+
+ if event == "return" or event == "tail return" then
+ stepOutCounter = stepOutCounter - 1;
+ elseif event == "call" then
+ stepOutCounter = stepOutCounter + 1;
+ end
+ end
+
+ --鍦≧UN鏃舵鏌ュ苟鏀瑰彉鐘舵
+ if hookLib == nil then
+ if currentRunState == runState.RUN and jumpFlag == false and currentHookState ~= hookState.DISCONNECT_HOOK then
+ local fileBP, G_BP = this.checkHasBreakpoint(lastRunFilePath);
+ if fileBP == false then
+ --鏂囦欢鏃犳柇鐐
+ if G_BP == true then
+ this.changeHookState(hookState.MID_HOOK);
+ else
+ this.changeHookState(hookState.LITE_HOOK);
+ end
+ else
+ --鏂囦欢鏈夋柇鐐, 鍒ゆ柇鍑芥暟鍐呮槸鍚︽湁鏂偣
+ local funHasBP = this.checkfuncHasBreakpoint(lastRunFunction.linedefined, lastRunFunction.lastlinedefined, lastRunFilePath);
+ if funHasBP then
+ --鍑芥暟瀹氫箟鑼冨洿鍐
+ this.changeHookState(hookState.ALL_HOOK);
+ else
+ this.changeHookState(hookState.MID_HOOK);
+ end
+ end
+
+ --MID_HOOK鐘舵佷笅锛宺eturn闇瑕佸湪涓嬩竴娆ook妫鏌ユ枃浠讹紙return鏃讹紝杩樻槸褰撳墠鏂囦欢锛屾鏌ユ枃浠舵椂鐘舵佹棤娉曡浆鎹級
+ if (event == "return" or event == "tail return") and currentHookState == hookState.MID_HOOK then
+ this.changeHookState(hookState.ALL_HOOK);
+ end
+ end
+ end
+end
+
+-- 鍚慥scode鍙戦佹爣鍑嗛氱煡娑堟伅锛宑mdStr鏄秷鎭被鍨
+-- @cmdStr 鍛戒护瀛
+function this.SendMsgWithStack(cmdStr)
+ local msgTab = this.getMsgTable(cmdStr);
+ local userFuncLevel = 0;
+ msgTab["stack"] , userFuncLevel= this.getStackTable();
+ if userFuncLevel ~= 0 then
+ lastRunFunction["func"] = debug.getinfo( (userFuncLevel - 1) , 'f').func;
+ end
+ this.sendMsg(msgTab);
+ this.debugger_wait_msg();
+end
+
+-- hook鐘舵佹敼鍙
+-- @s 鐩爣鐘舵
+function this.changeHookState( s )
+ if hookLib == nil and currentHookState == s then
+ return;
+ end
+
+ this.printToConsole("change hook state :"..s)
+ if s ~= hookState.DISCONNECT_HOOK then
+ this.printToVSCode("change hook state : "..s)
+ end
+
+ currentHookState = s;
+ if s == hookState.DISCONNECT_HOOK then
+ --涓轰簡瀹炵幇閫氱敤attach妯″紡锛宺equire鍗冲紑濮媓ook锛屽埄鐢╮浣滀负鏃舵満鍙戣捣杩炴帴
+ if openAttachMode == true then
+ if hookLib then hookLib.lua_set_hookstate(hookState.DISCONNECT_HOOK); else debug.sethook(this.debug_hook, "r", 1000000); end
+ else
+ if hookLib then hookLib.endHook(); else debug.sethook(); end
+ end
+ elseif s == hookState.LITE_HOOK then
+ if hookLib then hookLib.lua_set_hookstate(hookState.LITE_HOOK); else debug.sethook(this.debug_hook, "r"); end
+ elseif s == hookState.MID_HOOK then
+ if hookLib then hookLib.lua_set_hookstate(hookState.MID_HOOK); else debug.sethook(this.debug_hook, "rc"); end
+ elseif s == hookState.ALL_HOOK then
+ if hookLib then hookLib.lua_set_hookstate(hookState.ALL_HOOK); else debug.sethook(this.debug_hook, "lrc");end
+ end
+ --coroutine
+ if hookLib == nil then
+ this.changeCoroutinesHookState();
+ end
+end
+
+-- 杩愯鐘舵佹満锛岀姸鎬佸彉鏇
+-- @s 鐩爣鐘舵
+-- @isFromHooklib 1:浠巐ibc搴撲腑鍙戞潵鐨勭姸鎬佹敼鍙 | 0:lua鍙戞潵鐨勭姸鎬佹敼鍙
+function this.changeRunState(s , isFromHooklib)
+ local msgFrom;
+ if isFromHooklib == 1 then
+ msgFrom = "libc";
+ else
+ msgFrom = "lua";
+ end
+
+ --WAIT_CMD鐘舵佷細绛夊緟鎺ユ敹娑堟伅锛屼互涓嬩袱涓姸鎬佷笅涓嶈兘鍙戞秷鎭
+ this.printToConsole("changeRunState :"..s.. " | from:"..msgFrom);
+ if s ~= runState.DISCONNECT and s ~= runState.WAIT_CMD then
+ this.printToVSCode("changeRunState :"..s.." | from:"..msgFrom);
+ end
+
+ if hookLib ~= nil and isFromHooklib ~= 1 then
+ hookLib.lua_set_runstate(s);
+ end
+ currentRunState = s;
+ --鐘舵佸垏鎹㈡椂锛屾竻闄よ褰曟爤淇℃伅鐨勭姸鎬
+ currentCallStack = {};
+ variableRefTab = {};
+ variableRefIdx = 1;
+end
+
+-- 淇敼鍗忕▼鐘舵
+-- @s hook鏍囧織浣
+function this.changeCoroutinesHookState(s)
+ s = s or currentHookState;
+ this.printToConsole("change [Coroutine] HookState: "..tostring(s));
+ for k ,co in pairs(coroutinePool) do
+ if coroutine.status(co) == "dead" then
+ coroutinePool[k] = nil
+ else
+ this.changeCoroutineHookState(co, s)
+ end
+ end
+end
+
+function this.changeCoroutineHookState(co, s)
+ if s == hookState.DISCONNECT_HOOK then
+ if openAttachMode == true then
+ debug.sethook(co, this.debug_hook, "r", 1000000);
+ else
+ debug.sethook(co, this.debug_hook, "");
+ end
+ elseif s == hookState.LITE_HOOK then
+ debug.sethook(co , this.debug_hook, "r");
+ elseif s == hookState.MID_HOOK then
+ debug.sethook(co , this.debug_hook, "rc");
+ elseif s == hookState.ALL_HOOK then
+ debug.sethook(co , this.debug_hook, "lrc");
+ end
+end
+-------------------------鍙橀噺澶勭悊鐩稿叧-----------------------------
+
+--娓呯┖REPL鐨別nv鐜
+function this.clearEnv()
+ if this.getTableMemberNum(env) > 0 then
+ --娓呯┖env table
+ env = setmetatable({}, getmetatable(env));
+ end
+end
+
+--杩斿洖REPL鐨別nv鐜
+function this.showEnv()
+ return env;
+end
+
+-- 鐢ㄦ埛瑙傚療table鐨勬煡鎵惧嚱鏁般傜敤tableVarName浣滀负key鍘绘煡閫愬眰绾ф煡鎵緍ealVar鏄惁鍖归厤
+-- @tableVarName 鏄敤鎴疯瀵熺殑鍙橀噺鍚嶏紝宸茬粡鎸夊眰绾ц瑙f瀽鎴恡able銆傛瘮濡傜敤鎴疯緭鍑篴.b.c锛宼ableVarName鏄 a = { b = { c } }
+-- @realVar 鏄緟鏌ヨ table
+-- @return 杩斿洖鏌ュ埌鐨則able銆傛病鏌ュ埌杩斿洖nil
+function this.findTableVar( tableVarName, realVar)
+ if type(tableVarName) ~= "table" or type(realVar) ~= "table" then
+ return nil;
+ end
+
+ local layer = 2;
+ local curVar = realVar;
+ local jumpOutFlag = false;
+ repeat
+ if tableVarName[layer] ~= nil then
+ --杩欓噷浼樺厛灞曠ず鏁板瓧key锛屾瘮濡俛{"1" = "aa", [1] = "bb"} 浼氬睍绀篬1]鐨勫
+ local tmpCurVar = nil;
+ xpcall(function() tmpCurVar = curVar[tonumber(tableVarName[layer])]; end , function() tmpCurVar = nil end );
+ if tmpCurVar == nil then
+ xpcall(function() curVar = curVar[tostring(tableVarName[layer])]; end , function() curVar = nil end );
+ else
+ curVar = tmpCurVar;
+ end
+ layer = layer + 1;
+ if curVar == nil then
+ return nil;
+ end
+ else
+ --鎵惧埌
+ jumpOutFlag = true;
+ end
+ until(jumpOutFlag == true)
+ return curVar;
+end
+
+-- 鏍规嵁浼犲叆淇℃伅鐢熸垚杩斿洖鐨勫彉閲忎俊鎭
+-- @variableName 鍙橀噺鍚
+-- @variableIns 鍙橀噺瀹炰緥
+-- @return 鍖呭惈鍙橀噺淇℃伅鐨勬牸寮忓寲table
+function this.createWatchedVariableInfo(variableName, variableIns)
+ local var = {};
+ var.name = variableName;
+ var.type = tostring(type(variableIns));
+ xpcall(function() var.value = tostring(variableIns) end , function() var.value = tostring(type(variableIns)) .. " [value can't trans to string]" end );
+ var.variablesReference = "0"; --杩欎釜鍦版柟蹇呴』鐢ㄢ0鈥濓紝 浠ュ厤variableRefTab[0]鍑洪敊
+
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = variableIns;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(variableIns);
+ var.value = memberNum .." Members ".. var.value;
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..variableIns.. '"';
+ end
+ return var;
+end
+
+-- 璁剧疆 global 鍙橀噺
+-- @varName 琚慨鏀圭殑鍙橀噺鍚
+-- @newValue 鏂扮殑鍊
+function this.setGlobal(varName, newValue)
+ _G[varName] = newValue;
+ this.printToVSCode("[setVariable success] 宸茶缃 _G.".. varName .. " = " .. tostring(newValue) );
+ return true;
+end
+
+-- 璁剧疆 upvalue 鍙橀噺
+-- @varName 琚慨鏀圭殑鍙橀噺鍚
+-- @newValue 鏂扮殑鍊
+-- @stackId 鍙橀噺鎵鍦╯tack鏍堝眰
+-- @tableVarName 鍙橀噺鍚嶆媶鍒嗘垚鐨勬暟缁
+function this.setUpvalue(varName, newValue, stackId, tableVarName)
+ local ret = false;
+ local upTable = this.getUpValueVariable(currentCallStack[stackId - 1 ].func, true);
+ for i, realVar in ipairs(upTable) do
+ if realVar.name == varName then
+ if #tableVarName > 0 and type(realVar) == "table" then
+ --澶勭悊a.b.c鐨則able绫诲瀷
+ local findRes = this.findTableVar(tableVarName, variableRefTab[realVar.variablesReference]);
+ if findRes ~= nil then
+ --鍛戒腑
+ local setVarRet = debug.setupvalue (currentCallStack[stackId - 1 ].func, i, newValue);
+ if setVarRet == varName then
+ this.printToConsole("[setVariable success1] 宸茶缃 upvalue ".. varName .. " = " .. tostring(newValue) );
+ ret = true;
+ else
+ this.printToConsole("[setVariable error1] 鏈兘璁剧疆 upvalue ".. varName .. " = " .. tostring(newValue).." , 杩斿洖缁撴灉: ".. tostring(setVarRet));
+ end
+ return ret;
+ end
+ else
+ --鍛戒腑
+ local setVarRet = debug.setupvalue (currentCallStack[stackId - 1 ].func, i, newValue);
+ if setVarRet == varName then
+ this.printToConsole("[setVariable success] 宸茶缃 upvalue ".. varName .. " = " .. tostring(newValue) );
+ ret = true;
+ else
+ this.printToConsole("[setVariable error] 鏈兘璁剧疆 upvalue ".. varName .. " = " .. tostring(newValue).." , 杩斿洖缁撴灉: ".. tostring(setVarRet));
+ end
+ return ret;
+ end
+ end
+ end
+ return ret;
+end
+
+-- 璁剧疆local 鍙橀噺
+-- @varName 琚慨鏀圭殑鍙橀噺鍚
+-- @newValue 鏂扮殑鍊
+-- @tableVarName 鍙橀噺鍚嶆媶鍒嗘垚鐨勬暟缁
+function this.setLocal( varName, newValue, tableVarName, stackId)
+ local istackId = tonumber(stackId);
+ local offset = (istackId and istackId - 2) or 0;
+ local layerVarTab, ly = this.getVariable(nil , true, offset);
+ local ret = false;
+ for i, realVar in ipairs(layerVarTab) do
+ if realVar.name == varName then
+ if #tableVarName > 0 and type(realVar) == "table" then
+ --澶勭悊a.b.c鐨則able绫诲瀷
+ local findRes = this.findTableVar(tableVarName, variableRefTab[realVar.variablesReference]);
+ if findRes ~= nil then
+ --鍛戒腑
+ local setVarRet = debug.setlocal(ly , layerVarTab[i].index, newValue);
+ if setVarRet == varName then
+ this.printToConsole("[setVariable success1] 宸茶缃 local ".. varName .. " = " .. tostring(newValue) );
+ ret = true;
+ else
+ this.printToConsole("[setVariable error1] 鏈兘璁剧疆 local ".. varName .. " = " .. tostring(newValue).." , 杩斿洖缁撴灉: ".. tostring(setVarRet));
+ end
+ return ret;
+ end
+ else
+
+ local setVarRet = debug.setlocal(ly , layerVarTab[i].index, newValue);
+
+ if setVarRet == varName then
+ this.printToConsole("[setVariable success] 宸茶缃 local ".. varName .. " = " .. tostring(newValue) );
+ ret = true;
+ else
+ this.printToConsole("[setVariable error] 鏈兘璁剧疆 local ".. varName .. " = " .. tostring(newValue) .." , 杩斿洖缁撴灉: ".. tostring(setVarRet));
+ end
+ return ret;
+ end
+ end
+ end
+ return ret;
+end
+
+
+-- 璁剧疆鍙橀噺鐨勫
+-- @varName 琚慨鏀圭殑鍙橀噺鍚
+-- @curStackId 璋冪敤鏍堝眰绾(浠呭湪鍥哄畾鏍堝眰鏌ユ壘)
+-- @newValue 鏂扮殑鍊
+-- @limit 闄愬埗绗︼紝 10000琛ㄧず浠呭湪灞閮ㄥ彉閲忔煡鎵 锛20000 global, 30000 upvalue
+function this.setVariableValue (varName, stackId, newValue , limit)
+ this.printToConsole("setVariableValue | varName:" .. tostring(varName) .. " stackId:".. tostring(stackId) .." newValue:" .. tostring(newValue) .." limit:"..tostring(limit) )
+ if tostring(varName) == nil or tostring(varName) == "" then
+ --璧嬪奸敊璇
+ this.printToConsole("[setVariable Error] 琚祴鍊肩殑鍙橀噺鍚嶄负绌", 2 );
+ this.printToVSCode("[setVariable Error] 琚祴鍊肩殑鍙橀噺鍚嶄负绌", 2 );
+ return false;
+ end
+
+ --鏀寔a.b.c褰㈠紡銆傚垏鍓瞯arName
+ local tableVarName = {};
+ if varName:match('%.') then
+ tableVarName = this.stringSplit(varName , '%.');
+ if type(tableVarName) ~= "table" or #tableVarName < 1 then
+ return false;
+ end
+ varName = tableVarName[1];
+ end
+
+ if limit == "local" then
+ local ret = this.setLocal( varName, newValue, tableVarName, stackId);
+ return ret;
+ elseif limit == "upvalue" then
+ local ret = this.setUpvalue(varName, newValue, stackId, tableVarName);
+ return ret
+ elseif limit == "global" then
+ local ret = this.setGlobal(varName, newValue);
+ return ret;
+ else
+ local ret = this.setLocal( varName, newValue, tableVarName, stackId) or this.setUpvalue(varName, newValue, stackId, tableVarName) or this.setGlobal(varName, newValue);
+ this.printToConsole("set Value res :".. tostring(ret));
+ return ret;
+ end
+end
+
+-- 鎸夌収local -> upvalue -> _G 椤哄簭鏌ユ壘瑙傚療鍙橀噺
+-- @varName 鐢ㄦ埛杈撳叆鐨勫彉閲忓悕
+-- @stackId 璋冪敤鏍堝眰绾(浠呭湪鍥哄畾鏍堝眰鏌ユ壘)
+-- @isFormatVariable 鏄惁鎶婂彉閲忔牸寮忓寲涓篤SCode鎺ユ敹鐨勫舰寮
+-- @return 鏌ュ埌杩斿洖淇℃伅锛屾煡涓嶅埌杩斿洖nil
+function this.getWatchedVariable( varName , stackId , isFormatVariable )
+ this.printToConsole("getWatchedVariable | varName:" .. tostring(varName) .. " stackId:".. tostring(stackId) .." isFormatVariable:" .. tostring(isFormatVariable) )
+ if tostring(varName) == nil or tostring(varName) == "" then
+ return nil;
+ end
+
+ if type(currentCallStack[stackId - 1]) ~= "table" or type(currentCallStack[stackId - 1].func) ~= "function" then
+ local str = "getWatchedVariable currentCallStack " .. stackId - 1 .. " Error\n" .. this.serializeTable(currentCallStack, "currentCallStack");
+ this.printToVSCode(str, 2);
+ return nil;
+ end
+
+ --orgname 璁板綍鍘熷悕瀛. 鐢ㄦ潵澶勭悊a.b.c鐨勫舰寮
+ local orgname = varName;
+ --鏀寔a.b.c褰㈠紡銆傚垏鍓瞯arName
+ local tableVarName = {};
+ if varName:match('%.') then
+ tableVarName = this.stringSplit(varName , '%.');
+ if type(tableVarName) ~= "table" or #tableVarName < 1 then
+ return nil;
+ end
+ varName = tableVarName[1];
+ end
+ --鐢ㄦ潵杩斿洖锛屽甫鏈夋煡鍒板彉閲忕殑table
+ local varTab = {};
+ local ly = this.getSpecificFunctionStackLevel(currentCallStack[stackId - 1].func);
+
+ local layerVarTab = this.getVariable(ly, isFormatVariable);
+ local upTable = this.getUpValueVariable(currentCallStack[stackId - 1 ].func, isFormatVariable);
+ local travelTab = {};
+ table.insert(travelTab, layerVarTab);
+ table.insert(travelTab, upTable);
+ for _, layerVarTab in ipairs(travelTab) do
+ for i,realVar in ipairs(layerVarTab) do
+ if realVar.name == varName then
+ if #tableVarName > 0 and type(realVar) == "table" then
+ --澶勭悊a.b.c鐨則able绫诲瀷
+ local findRes = this.findTableVar(tableVarName, variableRefTab[realVar.variablesReference]);
+ if findRes ~= nil then
+ --鍛戒腑
+ if isFormatVariable then
+ local var = this.createWatchedVariableInfo( orgname , findRes );
+ table.insert(varTab, var);
+ return varTab;
+ else
+ return findRes.value;
+ end
+ end
+ else
+ --鍛戒腑
+ if isFormatVariable then
+ table.insert(varTab, realVar);
+ return varTab;
+ else
+ return realVar.value;
+ end
+ end
+ end
+ end
+ end
+
+ --鍦ㄥ叏灞鍙橀噺_G涓煡鎵
+ if _G[varName] ~= nil then
+ --鍛戒腑
+ if #tableVarName > 0 and type(_G[varName]) == "table" then
+ local findRes = this.findTableVar(tableVarName, _G[varName]);
+ if findRes ~= nil then
+ if isFormatVariable then
+ local var = this.createWatchedVariableInfo( orgname , findRes );
+ table.insert(varTab, var);
+ return varTab;
+ else
+ return findRes;
+ end
+ end
+ else
+ if isFormatVariable then
+ local var = this.createWatchedVariableInfo( varName , _G[varName] );
+ table.insert(varTab, var);
+ return varTab;
+ else
+ return _G[varName];
+ end
+ end
+ end
+ this.printToConsole("getWatchedVariable not find variable");
+ return nil;
+end
+
+-- 鏌ヨ寮曠敤鍙橀噺
+-- @refStr 鍙橀噺璁板綍id(variableRefTab绱㈠紩)
+-- @return 鏍煎紡鍖栫殑鍙橀噺淇℃伅table
+function this.getVariableRef( refStr )
+ local varRef = tonumber(refStr);
+ local varTab = {};
+
+ if tostring(type(variableRefTab[varRef])) == "table" then
+ for n,v in pairs(variableRefTab[varRef]) do
+ local var = {};
+ if type(n) == "string" then
+ var.name = '"' .. tostring(n) .. '"';
+ else
+ var.name = tostring(n);
+ end
+ var.type = tostring(type(v));
+ xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .. " [value can't trans to string]" end );
+ var.variablesReference = "0";
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = v;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(v);
+ var.value = memberNum .." Members ".. ( var.value or '' );
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..v.. '"';
+ end
+ table.insert(varTab, var);
+ end
+ --鑾峰彇涓涓媘tTable
+ local mtTab = getmetatable(variableRefTab[varRef]);
+ if mtTab ~= nil and type(mtTab) == "table" then
+ local var = {};
+ var.name = "_Metatable_";
+ var.type = tostring(type(mtTab));
+ xpcall(function() var.value = "鍏冭〃 "..tostring(mtTab); end , function() var.value = "鍏冭〃 [value can't trans to string]" end );
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = mtTab;
+ variableRefIdx = variableRefIdx + 1;
+ table.insert(varTab, var);
+ end
+ elseif tostring(type(variableRefTab[varRef])) == "function" then
+ --鍙杣pvalue
+ varTab = this.getUpValueVariable(variableRefTab[varRef], true);
+ elseif tostring(type(variableRefTab[varRef])) == "userdata" then
+ --鍙杕t table
+ local udMtTable = getmetatable(variableRefTab[varRef]);
+ if udMtTable ~= nil and type(udMtTable) == "table" then
+ local var = {};
+ var.name = "_Metatable_";
+ var.type = tostring(type(udMtTable));
+ xpcall(function() var.value = "鍏冭〃 "..tostring(udMtTable); end , function() var.value = "鍏冭〃 [value can't trans to string]" end );
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = udMtTable;
+ variableRefIdx = variableRefIdx + 1;
+ table.insert(varTab, var);
+
+ if traversalUserData and udMtTable.__pairs ~= nil and type(udMtTable.__pairs) == "function" then
+ for n,v in pairs(variableRefTab[varRef]) do
+ local var = {};
+ var.name = tostring(n);
+ var.type = tostring(type(v));
+ xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .. " [value can't trans to string]" end );
+ var.variablesReference = "0";
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = v;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(v);
+ var.value = memberNum .." Members ".. ( var.value or '' );
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..v.. '"';
+ end
+ table.insert(varTab, var);
+ end
+ end
+ end
+ end
+ return varTab;
+end
+
+-- 鑾峰彇鍏ㄥ眬鍙橀噺銆傛柟娉曞拰鍐呭瓨绠$悊涓幏鍙栧叏灞鍙橀噺鐨勬柟娉曚竴鏍
+-- @return 鏍煎紡鍖栫殑淇℃伅, 鑻ユ湭鎵惧埌杩斿洖绌簍able
+function this.getGlobalVariable( ... )
+ --鎴愭湰姣旇緝楂橈紝杩欓噷鍙兘閬嶅巻_G涓殑鎵鏈夊彉閲忥紝骞跺幓闄ょ郴缁熷彉閲忥紝鍐嶈繑鍥炵粰瀹㈡埛绔
+ local varTab = {};
+ for k,v in pairs(_G) do
+ local var = {};
+ var.name = tostring(k);
+ var.type = tostring(type(v));
+ xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .." [value can't trans to string]" end );
+ var.variablesReference = "0";
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = v;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(v);
+ var.value = memberNum .." Members ".. ( var.value or '' );
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..v.. '"';
+ end
+ table.insert(varTab, var);
+ end
+ return varTab;
+end
+
+-- 鑾峰彇upValues
+-- @isFormatVariable true杩斿洖[鍊糫 true杩斿洖[鏍煎紡鍖栫殑鏁版嵁]
+function this.getUpValueVariable( checkFunc , isFormatVariable)
+ local isGetValue = true;
+ if isFormatVariable == true then
+ isGetValue = false;
+ end
+
+ --閫氳繃Debug鑾峰彇褰撳墠鍑芥暟鐨凢unc
+ checkFunc = checkFunc or lastRunFunction.func;
+
+ local varTab = {};
+ if checkFunc == nil then
+ return varTab;
+ end
+ local i = 1
+ repeat
+ local n, v = debug.getupvalue(checkFunc, i)
+ if n then
+
+ local var = {};
+ var.name = n;
+ var.type = tostring(type(v));
+ var.variablesReference = "0";
+
+ if isGetValue == false then
+ xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .. " [value can't trans to string]" end );
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = v;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(v);
+ var.value = memberNum .." Members ".. ( var.value or '' );
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..v.. '"';
+ end
+ else
+ var.value = v;
+ end
+
+ table.insert(varTab, var);
+ i = i + 1
+ end
+ until not n
+ return varTab;
+end
+
+-- 鑾峰彇灞閮ㄥ彉閲 checkLayer鏄鏌ヨ鐨勫眰绾э紝濡傛灉涓嶈缃垯鏌ヨ褰撳墠灞傜骇
+-- @isFormatVariable 鏄惁鍙栧硷紝true:鍙栧肩殑tostring
+function this.getVariable( checkLayer, isFormatVariable , offset)
+ local isGetValue = true;
+ if isFormatVariable == true then
+ isGetValue = false;
+ end
+
+ local ly = 0;
+ if checkLayer ~= nil and type(checkLayer) == "number" then ly = checkLayer + 1;
+ else ly = this.getSpecificFunctionStackLevel(lastRunFunction.func); end
+
+ if ly == 0 then
+ this.printToVSCode("[error]鑾峰彇灞傛澶辫触锛", 2);
+ return;
+ end
+ local varTab = {};
+ local stacklayer = ly;
+ local k = 1;
+
+ if type(offset) == 'number' then
+ stacklayer = stacklayer + offset;
+ end
+
+ repeat
+ local n, v = debug.getlocal(stacklayer, k)
+ if n == nil then
+ break;
+ end
+
+ --(*temporary)鏄郴缁熷彉閲忥紝杩囨护鎺夈傝繖閲屽亣璁(*temporary)浠呭嚭鐜板湪鏈鍚
+ if "(*temporary)" ~= tostring(n) then
+ local var = {};
+ var.name = n;
+ var.type = tostring(type(v));
+ var.variablesReference = "0";
+ var.index = k;
+
+ if isGetValue == false then
+ xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .. " [value can't trans to string]" end );
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ var.variablesReference = variableRefIdx;
+ variableRefTab[variableRefIdx] = v;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(v);
+ var.value = memberNum .." Members ".. ( var.value or '' );
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..v.. '"';
+ end
+ else
+ var.value = v;
+ end
+
+ local sameIdx = this.checkSameNameVar(varTab, var);
+ if sameIdx ~= 0 then
+ varTab[sameIdx] = var;
+ else
+ table.insert(varTab, var);
+ end
+ end
+ k = k + 1
+ until n == nil
+ return varTab, stacklayer - 1;
+end
+
+--妫鏌ュ彉閲忓垪琛ㄤ腑鐨勫悓鍚嶅彉閲
+function this.checkSameNameVar(varTab, var)
+ for k , v in pairs(varTab) do
+ if v.name == var.name then
+ return k;
+ end
+ end
+ return 0;
+end
+
+-- 鎵ц琛ㄨ揪寮
+function this.processExp(msgTable)
+ local retString;
+ local var = {};
+ var.isSuccess = "true";
+ if msgTable ~= nil then
+ local expression = this.trim(tostring(msgTable.Expression));
+ local isCmd = false;
+ if isCmd == false then
+ --鍏煎鏃х増p 鍛戒护
+ if expression:find("p ", 1, true) == 1 then
+ expression = expression:sub(3);
+ end
+
+ local expressionWithReturn = "return " .. expression;
+ local f = debugger_loadString(expressionWithReturn) or debugger_loadString(expression);
+ --鍒ゆ柇缁撴灉锛屽鏋滆〃杈惧紡閿欒浼氳繑鍥瀗il
+ if type(f) == "function" then
+ if _VERSION == "Lua 5.1" then
+ setfenv(f , env);
+ else
+ debug.setupvalue(f, 1, env);
+ end
+ --琛ㄨ揪寮忚鏈夐敊璇鐞
+ xpcall(function() retString = f() end , function() retString = "杈撳叆閿欒鎸囦护銆俓n + 璇锋鏌ユ寚浠ゆ槸鍚︽纭甛n + 鎸囦护浠呰兘鍦╗鏆傚仠鍦ㄦ柇鐐规椂]杈撳叆, 璇蜂笉瑕佸湪绋嬪簭鎸佺画杩愯鏃惰緭鍏"; var.isSuccess = false; end)
+ else
+ retString = "鎸囦护鎵ц閿欒銆俓n + 璇锋鏌ユ寚浠ゆ槸鍚︽纭甛n + 鍙互鐩存帴杈撳叆琛ㄨ揪寮忥紝鎵ц鍑芥暟鎴栧彉閲忓悕锛屽苟瑙傚療鎵ц缁撴灉";
+ var.isSuccess = false;
+ end
+ end
+ end
+
+ var.name = "Exp";
+ var.type = tostring(type(retString));
+ xpcall(function() var.value = tostring(retString) end , function(e) var.value = tostring(type(retString)) .. " [value can't trans to string] ".. e; var.isSuccess = false; end);
+ var.variablesReference = "0";
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ variableRefTab[variableRefIdx] = retString;
+ var.variablesReference = variableRefIdx;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(retString);
+ var.value = memberNum .." Members ".. var.value;
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..retString.. '"';
+ end
+ --string鎵ц瀹屾瘯鍚庢竻绌篹nv鐜
+ this.clearEnv();
+ local retTab = {}
+ table.insert(retTab ,var);
+ return retTab;
+end
+
+--鎵ц鍙橀噺瑙傚療琛ㄨ揪寮
+function this.processWatchedExp(msgTable)
+ local retString;
+ local expression = "return ".. tostring(msgTable.varName)
+ this.printToConsole("processWatchedExp | expression: " .. expression);
+ local f = debugger_loadString(expression);
+ local var = {};
+ var.isSuccess = "true";
+ --鍒ゆ柇缁撴灉锛屽鏋滆〃杈惧紡閿欒浼氳繑鍥瀗il
+ if type(f) == "function" then
+ --琛ㄨ揪寮忔纭
+ if _VERSION == "Lua 5.1" then
+ setfenv(f , env);
+ else
+ debug.setupvalue(f, 1, env);
+ end
+ xpcall(function() retString = f() end , function() retString = "杈撳叆浜嗛敊璇殑鍙橀噺淇℃伅"; var.isSuccess = "false"; end)
+ else
+ retString = "鏈兘鎵惧埌鍙橀噺鐨勫";
+ var.isSuccess = "false";
+ end
+
+ var.name = msgTable.varName;
+ var.type = tostring(type(retString));
+ xpcall(function() var.value = tostring(retString) end , function() var.value = tostring(type(retString)) .. " [value can't trans to string]"; var.isSuccess = "false"; end );
+ var.variablesReference = "0";
+
+ if var.type == "table" or var.type == "function" or var.type == "userdata" then
+ variableRefTab[variableRefIdx] = retString;
+ var.variablesReference = variableRefIdx;
+ variableRefIdx = variableRefIdx + 1;
+ if var.type == "table" then
+ local memberNum = this.getTableMemberNum(retString);
+ var.value = memberNum .." Members ".. var.value;
+ end
+ elseif var.type == "string" then
+ var.value = '"' ..retString.. '"';
+ end
+
+ local retTab = {}
+ table.insert(retTab ,var);
+ return retTab;
+end
+
+
+function tools.getFileSource()
+ local info = debug.getinfo(1, "S")
+ for k,v in pairs(info) do
+ if k == "source" then
+ return v;
+ end
+ end
+end
+
+--搴忓垪鍖栧苟鎵撳嵃table
+function tools.printTable(t, name ,indent)
+ local str = (tools.show(t, name, indent));
+ print(str);
+end
+
+--搴忓垪鍖栧苟杩斿洖table
+function tools.serializeTable(t, name, indent)
+ local str = (tools.show(t, name, indent))
+ return str
+end
+
+--[[
+Author: Julio Manuel Fernandez-Diaz
+Date: January 12, 2007
+Modified slightly by RiciLake to avoid the unnecessary table traversal in tablecount()
+Formats tables with cycles recursively to any depth.
+The output is returned as a string.
+References to other tables are shown as values.
+Self references are indicated.
+The string returned is "Lua code", which can be procesed
+(in the case in which indent is composed by spaces or "--").
+Userdata and function keys and values are shown as strings,
+which logically are exactly not equivalent to the original code.
+This routine can serve for pretty formating tables with
+proper indentations, apart from printing them:
+print(table.show(t, "t")) -- a typical use
+Heavily based on "Saving tables with cycles", PIL2, p. 113.
+Arguments:
+t is the table.
+name is the name of the table (optional)
+indent is a first indentation (optional).
+--]]
+function tools.show(t, name, indent)
+ local cart -- a container
+ local autoref -- for self references
+
+ local function isemptytable(t) return next(t) == nil end
+
+ local function basicSerialize (o)
+ local so = tostring(o)
+ if type(o) == "function" then
+ local info = debug.getinfo(o, "S")
+ -- info.name is nil because o is not a calling level
+ if info.what == "C" then
+ return string.format("%q", so .. ", C function")
+ else
+ -- the information is defined through lines
+ return string.format("%q", so .. ", defined in (" ..
+ info.linedefined .. "-" .. info.lastlinedefined ..
+ ")" .. info.source)
+ end
+ elseif type(o) == "number" or type(o) == "boolean" then
+ return so
+ else
+ return string.format("%q", so)
+ end
+ end
+
+ local function addtocart (value, name, indent, saved, field)
+ indent = indent or ""
+ saved = saved or {}
+ field = field or name
+
+ cart = cart .. indent .. field
+
+ if type(value) ~= "table" then
+ cart = cart .. " = " .. basicSerialize(value) .. ";\n"
+ else
+ if saved[value] then
+ cart = cart .. " = {}; -- " .. saved[value]
+ .. " (self reference)\n"
+ autoref = autoref .. name .. " = " .. saved[value] .. ";\n"
+ else
+ saved[value] = name
+ --if tablecount(value) == 0 then
+ if isemptytable(value) then
+ cart = cart .. " = {};\n"
+ else
+ cart = cart .. " = {\n"
+ for k, v in pairs(value) do
+ k = basicSerialize(k)
+ local fname = string.format("%s[%s]", name, k)
+ field = string.format("[%s]", k)
+ -- three spaces between levels
+ addtocart(v, fname, indent .. " ", saved, field)
+ end
+ cart = cart .. indent .. "};\n"
+ end
+ end
+ end
+ end
+
+ name = name or "PRINT_Table"
+ if type(t) ~= "table" then
+ return name .. " = " .. basicSerialize(t)
+ end
+ cart, autoref = "", ""
+ addtocart(t, name, indent)
+ return cart .. autoref
+end
+
+-----------------------------------------------------------------------------
+-- JSON4Lua: JSON encoding / decoding support for the Lua language.
+-- json Module.
+-- Author: Craig Mason-Jones
+-- Homepage: http://github.com/craigmj/json4lua/
+-- Version: 1.0.0
+-- This module is released under the MIT License (MIT).
+-- Please see LICENCE.txt for details.
+--
+-- USAGE:
+-- This module exposes two functions:
+-- json.encode(o)
+-- Returns the table / string / boolean / number / nil / json.null value as a JSON-encoded string.
+-- json.decode(json_string)
+-- Returns a Lua object populated with the data encoded in the JSON string json_string.
+--
+-- REQUIREMENTS:
+-- compat-5.1 if using Lua 5.0
+--
+-- CHANGELOG
+-- 0.9.20 Introduction of local Lua functions for private functions (removed _ function prefix).
+-- Fixed Lua 5.1 compatibility issues.
+-- Introduced json.null to have null values in associative arrays.
+-- json.encode() performance improvement (more than 50%) through table.concat rather than ..
+-- Introduced decode ability to ignore /**/ comments in the JSON string.
+-- 0.9.10 Fix to array encoding / decoding to correctly manage nil/null values in arrays.
+-----------------------------------------------------------------------------
+
+function tools.createJson()
+ -----------------------------------------------------------------------------
+ -- Imports and dependencies
+ -----------------------------------------------------------------------------
+ local math = require('math')
+ local string = require("string")
+ local table = require("table")
+
+ -----------------------------------------------------------------------------
+ -- Module declaration
+ -----------------------------------------------------------------------------
+ local json = {} -- Public namespace
+ local json_private = {} -- Private namespace
+
+ -- Public constants
+ json.EMPTY_ARRAY={}
+ json.EMPTY_OBJECT={}
+
+ -- Public functions
+
+ -- Private functions
+ local decode_scanArray
+ local decode_scanComment
+ local decode_scanConstant
+ local decode_scanNumber
+ local decode_scanObject
+ local decode_scanString
+ local decode_scanWhitespace
+ local encodeString
+ local isArray
+ local isEncodable
+
+ -----------------------------------------------------------------------------
+ -- PUBLIC FUNCTIONS
+ -----------------------------------------------------------------------------
+ --- Encodes an arbitrary Lua object / variable.
+ -- @param v The Lua object / variable to be JSON encoded.
+ -- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode)
+ function json.encode (v)
+ -- Handle nil values
+ if v==nil then
+ return "null"
+ end
+
+ local vtype = type(v)
+
+ -- Handle strings
+ if vtype=='string' then
+ return '"' .. json_private.encodeString(v) .. '"' -- Need to handle encoding in string
+ end
+
+ -- Handle booleans
+ if vtype=='number' or vtype=='boolean' then
+ return tostring(v)
+ end
+
+ -- Handle tables
+ if vtype=='table' then
+ local rval = {}
+ -- Consider arrays separately
+ local bArray, maxCount = isArray(v)
+ if bArray then
+ for i = 1,maxCount do
+ table.insert(rval, json.encode(v[i]))
+ end
+ else -- An object, not an array
+ for i,j in pairs(v) do
+ if isEncodable(i) and isEncodable(j) then
+ table.insert(rval, '"' .. json_private.encodeString(i) .. '":' .. json.encode(j))
+ end
+ end
+ end
+ if bArray then
+ return '[' .. table.concat(rval,',') ..']'
+ else
+ return '{' .. table.concat(rval,',') .. '}'
+ end
+ end
+
+ -- Handle null values
+ if vtype=='function' and v==json.null then
+ return 'null'
+ end
+
+ assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. tostring(v))
+ end
+
+
+ --- Decodes a JSON string and returns the decoded value as a Lua data structure / value.
+ -- @param s The string to scan.
+ -- @param [startPos] Optional starting position where the JSON string is located. Defaults to 1.
+ -- @param Lua object, number The object that was scanned, as a Lua table / string / number / boolean or nil,
+ -- and the position of the first character after
+ -- the scanned JSON object.
+ function json.decode(s, startPos)
+ startPos = startPos and startPos or 1
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']')
+ local curChar = string.sub(s,startPos,startPos)
+ -- Object
+ if curChar=='{' then
+ return decode_scanObject(s,startPos)
+ end
+ -- Array
+ if curChar=='[' then
+ return decode_scanArray(s,startPos)
+ end
+ -- Number
+ if string.find("+-0123456789.e", curChar, 1, true) then
+ return decode_scanNumber(s,startPos)
+ end
+ -- String
+ if curChar==[["]] or curChar==[[']] then
+ return decode_scanString(s,startPos)
+ end
+ if string.sub(s,startPos,startPos+1)=='/*' then
+ return json.decode(s, decode_scanComment(s,startPos))
+ end
+ -- Otherwise, it must be a constant
+ return decode_scanConstant(s,startPos)
+ end
+
+ --- The null function allows one to specify a null value in an associative array (which is otherwise
+ -- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null }
+ function json.null()
+ return json.null -- so json.null() will also return null ;-)
+ end
+ -----------------------------------------------------------------------------
+ -- Internal, PRIVATE functions.
+ -- Following a Python-like convention, I have prefixed all these 'PRIVATE'
+ -- functions with an underscore.
+ -----------------------------------------------------------------------------
+
+ --- Scans an array from JSON into a Lua object
+ -- startPos begins at the start of the array.
+ -- Returns the array and the next starting position
+ -- @param s The string being scanned.
+ -- @param startPos The starting position for the scan.
+ -- @return table, int The scanned array as a table, and the position of the next character to scan.
+ function decode_scanArray(s,startPos)
+ local array = {} -- The return value
+ local stringLen = string.len(s)
+ assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\n'..s )
+ startPos = startPos + 1
+ -- Infinite loop for array elements
+ local index = 1
+ repeat
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.')
+ local curChar = string.sub(s,startPos,startPos)
+ if (curChar==']') then
+ return array, startPos+1
+ end
+ if (curChar==',') then
+ startPos = decode_scanWhitespace(s,startPos+1)
+ end
+ assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.')
+ local object
+ object, startPos = json.decode(s,startPos)
+ array[index] = object
+ index = index + 1
+ until false
+ end
+
+ --- Scans a comment and discards the comment.
+ -- Returns the position of the next character following the comment.
+ -- @param string s The JSON string to scan.
+ -- @param int startPos The starting position of the comment
+ function decode_scanComment(s, startPos)
+ assert( string.sub(s,startPos,startPos+1)=='/*', "decode_scanComment called but comment does not start at position " .. startPos)
+ local endPos = string.find(s,'*/',startPos+2)
+ assert(endPos~=nil, "Unterminated comment in string at " .. startPos)
+ return endPos+2
+ end
+
+ --- Scans for given constants: true, false or null
+ -- Returns the appropriate Lua type, and the position of the next character to read.
+ -- @param s The string being scanned.
+ -- @param startPos The position in the string at which to start scanning.
+ -- @return object, int The object (true, false or nil) and the position at which the next character should be
+ -- scanned.
+ function decode_scanConstant(s, startPos)
+ local consts = { ["true"] = true, ["false"] = false, ["null"] = nil }
+ local constNames = {"true","false","null"}
+
+ for i,k in pairs(constNames) do
+ if string.sub(s,startPos, startPos + string.len(k) -1 )==k then
+ return consts[k], startPos + string.len(k)
+ end
+ end
+ assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos)
+ end
+
+ --- Scans a number from the JSON encoded string.
+ -- (in fact, also is able to scan numeric +- eqns, which is not
+ -- in the JSON spec.)
+ -- Returns the number, and the position of the next character
+ -- after the number.
+ -- @param s The string being scanned.
+ -- @param startPos The position at which to start scanning.
+ -- @return number, int The extracted number and the position of the next character to scan.
+ function decode_scanNumber(s,startPos)
+ local endPos = startPos+1
+ local stringLen = string.len(s)
+ local acceptableChars = "+-0123456789.e"
+ while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true)
+ and endPos<=stringLen
+ ) do
+ endPos = endPos + 1
+ end
+ -- local stringValue = 'return ' .. string.sub(s, startPos, endPos - 1)
+ -- local stringEval = loadstring(stringValue)
+ -- assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos)
+ local numberValue = string.sub(s, startPos, endPos - 1)
+ return numberValue, endPos
+ end
+
+ --- Scans a JSON object into a Lua object.
+ -- startPos begins at the start of the object.
+ -- Returns the object and the next starting position.
+ -- @param s The string being scanned.
+ -- @param startPos The starting position of the scan.
+ -- @return table, int The scanned object as a table and the position of the next character to scan.
+ function decode_scanObject(s,startPos)
+ local object = {}
+ local stringLen = string.len(s)
+ local key, value
+ assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\n' .. s)
+ startPos = startPos + 1
+ repeat
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.')
+ local curChar = string.sub(s,startPos,startPos)
+ if (curChar=='}') then
+ return object,startPos+1
+ end
+ if (curChar==',') then
+ startPos = decode_scanWhitespace(s,startPos+1)
+ end
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.')
+ -- Scan the key
+ key, startPos = json.decode(s,startPos)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
+ startPos = decode_scanWhitespace(s,startPos)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
+ assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos)
+ startPos = decode_scanWhitespace(s,startPos+1)
+ assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
+ value, startPos = json.decode(s,startPos)
+ object[key]=value
+ until false -- infinite loop while key-value pairs are found
+ end
+
+ -- START SoniEx2
+ -- Initialize some things used by decode_scanString
+ -- You know, for efficiency
+ local escapeSequences = {
+ ["\\t"] = "\t",
+ ["\\f"] = "\f",
+ ["\\r"] = "\r",
+ ["\\n"] = "\n",
+ ["\\b"] = "\b"
+ }
+ setmetatable(escapeSequences, {__index = function(t,k)
+ -- skip "\" aka strip escape
+ return string.sub(k,2)
+ end})
+ -- END SoniEx2
+
+ --- Scans a JSON string from the opening inverted comma or single quote to the
+ -- end of the string.
+ -- Returns the string extracted as a Lua string,
+ -- and the position of the next non-string character
+ -- (after the closing inverted comma or single quote).
+ -- @param s The string being scanned.
+ -- @param startPos The starting position of the scan.
+ -- @return string, int The extracted string as a Lua string, and the next character to parse.
+ function decode_scanString(s,startPos)
+ assert(startPos, 'decode_scanString(..) called without start position')
+ local startChar = string.sub(s,startPos,startPos)
+ -- START SoniEx2
+ -- PS: I don't think single quotes are valid JSON
+ assert(startChar == [["]] or startChar == [[']],'decode_scanString called for a non-string')
+ --assert(startPos, "String decoding failed: missing closing " .. startChar .. " for string at position " .. oldStart)
+ local t = {}
+ local i,j = startPos,startPos
+ while string.find(s, startChar, j+1) ~= j+1 do
+ local oldj = j
+ i,j = string.find(s, "\\.", j+1)
+ local x,y = string.find(s, startChar, oldj+1)
+ if not i or x < i then
+ i,j = x,y-1
+ end
+ table.insert(t, string.sub(s, oldj+1, i-1))
+ if string.sub(s, i, j) == "\\u" then
+ local a = string.sub(s,j+1,j+4)
+ j = j + 4
+ local n = tonumber(a, 16)
+ assert(n, "String decoding failed: bad Unicode escape " .. a .. " at position " .. i .. " : " .. j)
+ -- math.floor(x/2^y) == lazy right shift
+ -- a % 2^b == bitwise_and(a, (2^b)-1)
+ -- 64 = 2^6
+ -- 4096 = 2^12 (or 2^6 * 2^6)
+ local x
+ if n < 0x80 then
+ x = string.char(n % 0x80)
+ elseif n < 0x800 then
+ -- [110x xxxx] [10xx xxxx]
+ x = string.char(0xC0 + (math.floor(n/64) % 0x20), 0x80 + (n % 0x40))
+ else
+ -- [1110 xxxx] [10xx xxxx] [10xx xxxx]
+ x = string.char(0xE0 + (math.floor(n/4096) % 0x10), 0x80 + (math.floor(n/64) % 0x40), 0x80 + (n % 0x40))
+ end
+ table.insert(t, x)
+ else
+ table.insert(t, escapeSequences[string.sub(s, i, j)])
+ end
+ end
+ table.insert(t,string.sub(j, j+1))
+ assert(string.find(s, startChar, j+1), "String decoding failed: missing closing " .. startChar .. " at position " .. j .. "(for string at position " .. startPos .. ")")
+ return table.concat(t,""), j+2
+ -- END SoniEx2
+ end
+
+ --- Scans a JSON string skipping all whitespace from the current start position.
+ -- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached.
+ -- @param s The string being scanned
+ -- @param startPos The starting position where we should begin removing whitespace.
+ -- @return int The first position where non-whitespace was encountered, or string.len(s)+1 if the end of string
+ -- was reached.
+ function decode_scanWhitespace(s,startPos)
+ local whitespace=" \n\r\t"
+ local stringLen = string.len(s)
+ while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true) and startPos <= stringLen) do
+ startPos = startPos + 1
+ end
+ return startPos
+ end
+
+ --- Encodes a string to be JSON-compatible.
+ -- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-)
+ -- @param s The string to return as a JSON encoded (i.e. backquoted string)
+ -- @return The string appropriately escaped.
+
+ local escapeList = {
+ ['"'] = '\\"',
+ ['\\'] = '\\\\',
+ ['/'] = '\\/',
+ ['\b'] = '\\b',
+ ['\f'] = '\\f',
+ ['\n'] = '\\n',
+ ['\r'] = '\\r',
+ ['\t'] = '\\t'
+ }
+
+ function json_private.encodeString(s)
+ local s = tostring(s)
+ return s:gsub(".", function(c) return escapeList[c] end) -- SoniEx2: 5.0 compat
+ end
+
+ -- Determines whether the given Lua type is an array or a table / dictionary.
+ -- We consider any table an array if it has indexes 1..n for its n items, and no
+ -- other data in the table.
+ -- I think this method is currently a little 'flaky', but can't think of a good way around it yet...
+ -- @param t The table to evaluate as an array
+ -- @return boolean, number True if the table can be represented as an array, false otherwise. If true,
+ -- the second returned value is the maximum
+ -- number of indexed elements in the array.
+ function isArray(t)
+ -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable
+ -- (with the possible exception of 'n')
+ if (t == json.EMPTY_ARRAY) then return true, 0 end
+ if (t == json.EMPTY_OBJECT) then return false end
+
+ local maxIndex = 0
+ for k,v in pairs(t) do
+ if (type(k)=='number' and math.floor(k)==k and 1<=k) then -- k,v is an indexed pair
+ if (not isEncodable(v)) then return false end -- All array elements must be encodable
+ maxIndex = math.max(maxIndex,k)
+ else
+ if (k=='n') then
+ if v ~= (t.n or #t) then return false end -- False if n does not hold the number of elements
+ else -- Else of (k=='n')
+ if isEncodable(v) then return false end
+ end -- End of (k~='n')
+ end -- End of k,v not an indexed pair
+ end -- End of loop across all pairs
+ return true, maxIndex
+ end
+
+ --- Determines whether the given Lua object / table / variable can be JSON encoded. The only
+ -- types that are JSON encodable are: string, boolean, number, nil, table and json.null.
+ -- In this implementation, all other types are ignored.
+ -- @param o The object to examine.
+ -- @return boolean True if the object should be JSON encoded, false if it should be ignored.
+ function isEncodable(o)
+ local t = type(o)
+ return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or
+ (t=='function' and o==json.null)
+ end
+ return json
+end
+
+-- Sourced from http://lua-users.org/wiki/BaseSixtyFour
+
+-- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de>
+-- licensed under the terms of the LGPL2
+
+-- character table string
+local base64CharTable='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+
+-- encoding
+function tools.base64encode(data)
+ return ((data:gsub('.', function(x)
+ local r,b='',x:byte()
+ for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
+ return r;
+ end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
+ if (#x < 6) then return '' end
+ local c=0
+ for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
+ return base64CharTable:sub(c+1,c+1)
+ end)..({ '', '==', '=' })[#data%3+1])
+end
+
+-- decoding
+function tools.base64decode(data)
+ data = string.gsub(data, '[^'..base64CharTable..'=]', '')
+ return (data:gsub('.', function(x)
+ if (x == '=') then return '' end
+ local r,f='',(base64CharTable:find(x)-1)
+ for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
+ return r;
+ end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
+ if (#x ~= 8) then return '' end
+ local c=0
+ for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
+ return string.char(c)
+ end))
+end
+
+-- tools鍙橀噺
+json = tools.createJson(); --json澶勭悊
+this.printToConsole("load LuaPanda success", 1);
+this.replaceCoroutineFuncs()
+return this;
diff --git a/Resources/Libraries/socket/core.dll b/Resources/Libraries/socket/core.dll
new file mode 100644
index 0000000..9febf20
--- /dev/null
+++ b/Resources/Libraries/socket/core.dll
Binary files differ
diff --git a/Resources/Scripts/EditorApplication.lua b/Resources/Scripts/EditorApplication.lua
index c8438cf..c4d9389 100644
--- a/Resources/Scripts/EditorApplication.lua
+++ b/Resources/Scripts/EditorApplication.lua
@@ -1,4 +1,4 @@
-require "./Scripts/Utils/Utils"
+require("LuaPanda").start("127.0.0.1",8818);
local Debug = GameLab.Debug
local GUI = GameLab.Editor.GUI
@@ -20,8 +20,10 @@ local guiWindow = GUI.GUIWindow.New()
guiWindow:SetContainnerWindow(mainWindow)
guiWindow:SetPosition({0,0, 500, 400})
+Debug.Log(package.cpath)
+
while true do
app:PullMessage()
-end \ No newline at end of file
+end \ No newline at end of file
diff --git a/Resources/readme.txt b/Resources/readme.txt
index e3b0dc5..f45359b 100644
--- a/Resources/readme.txt
+++ b/Resources/readme.txt
@@ -1 +1,7 @@
-缂栬緫鍣ㄧ敤鐨勮祫婧 \ No newline at end of file
+缂栬緫鍣ㄨ祫婧
+* DefaultContent 杩愯鏃剁浉鍏崇殑鑴氭湰鍜岃祫婧
+* Icon 鍥炬爣鏂囦欢
+* Images 鍥剧墖璧勬簮
+* Libraries 缂栬緫鍣ㄧ敤鍒扮殑妯″潡
+* Scripts 缂栬緫鍣ㄨ剼鏈
+* Shaders 缂栬緫鍣ㄧ敤鍒扮殑鐫鑹插櫒 \ No newline at end of file