From 229e5248295b296f75594c345ef120b4454d4d33 Mon Sep 17 00:00:00 2001
From: stuartwang <3030078087@qq.com>
Date: Mon, 21 Oct 2019 17:29:25 +0800
Subject: [PATCH 001/331] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E7=9A=84?=
=?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=B7=AF=E5=BE=84=E7=9A=84=E5=A4=A7=E5=B0=8F?=
=?UTF-8?q?=E5=86=99=E6=95=8F=E6=84=9F=E6=8E=A7=E5=88=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/Tools.ts | 15 ++++++++++++++-
src/extension.ts | 3 ---
src/luaDebug.ts | 2 ++
3 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/src/Tools.ts b/src/Tools.ts
index f22a3a2..71b6dec 100644
--- a/src/Tools.ts
+++ b/src/Tools.ts
@@ -8,6 +8,7 @@ export class Tools {
public static extMap = new Object(); // 可处理的文件后缀列表
public static fileNameToPathMap; // 文件名-路径Map
public static useAutoPathMode = false;
+ public static pathCaseSensitivity = false;
// 把传入的路径标准路径
public static genUnifiedPath(beProcessPath) : string{
@@ -179,7 +180,19 @@ export class Tools {
let nameExtObject = this.getPathNameAndExt(shortPath);
let fileName = nameExtObject['name'];
- let fullPath = this.fileNameToPathMap[fileName];
+
+ let fullPath;
+ if(this.pathCaseSensitivity){
+ fullPath = this.fileNameToPathMap[fileName];
+ }else{
+ for (const keyPath in this.fileNameToPathMap) {
+ if(keyPath.toLowerCase() === fileName){
+ fullPath = this.fileNameToPathMap[keyPath];
+ break;
+ }
+ }
+ }
+
if(fullPath){
if(isArray(fullPath)){
// 存在同名文件
diff --git a/src/extension.ts b/src/extension.ts
index bd8d508..9802953 100755
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -109,12 +109,10 @@ class LuaConfigurationProvider implements vscode.DebugConfigurationProvider {
}
if (!config.request) {
- vscode.window.showInformationMessage("请在launch中配置request方式!");
config.request = 'launch';
}
if (!config.cwd) {
- vscode.window.showInformationMessage("请在launch中配置cwd工作路径!");
config.cwd = '${workspaceFolder}';
}
@@ -132,7 +130,6 @@ class LuaConfigurationProvider implements vscode.DebugConfigurationProvider {
}
if (config.stopOnEntry == undefined) {
- vscode.window.showInformationMessage("请在launch中配置是否stopOnEntry")
config.stopOnEntry = true;
}
diff --git a/src/luaDebug.ts b/src/luaDebug.ts
index fc088b6..70de590 100755
--- a/src/luaDebug.ts
+++ b/src/luaDebug.ts
@@ -136,6 +136,8 @@ export class LuaDebugSession extends LoggingDebugSession {
let path = require("path");
Tools.useAutoPathMode = !!args.autoPathMode;
+ Tools.pathCaseSensitivity = !!args.pathCaseSensitivity;
+
//1.1.生成文件map
if(Tools.useAutoPathMode === true){
Tools.rebuildAcceptExtMap(args.luaFileExtension);
From 352745cc17d79c286f9f347bc282a8275152e6ec Mon Sep 17 00:00:00 2001
From: stuartwang <3030078087@qq.com>
Date: Tue, 22 Oct 2019 16:01:16 +0800
Subject: [PATCH 002/331] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86lua=20code?=
=?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=A7=A3=E6=9E=90=E9=83=A8=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.vscode/launch.json | 23 +-
package-lock.json | 3003 ++-----------------------
package.json | 131 +-
res/lua/coroutine.lua | 49 +
res/lua/debug.lua | 92 +
res/lua/global.lua | 123 +
res/lua/io.lua | 124 +
res/lua/math.lua | 109 +
res/lua/os.lua | 75 +
res/lua/package.lua | 77 +
res/lua/string.lua | 133 ++
res/lua/table.lua | 55 +
res/lua/utf8.lua | 49 +
res/others/launch.json | 30 +
res/snippets/snippets.json | 99 +
res/web/settings.html | 249 ++
src/code/server/codeCompleting.ts | 401 ++++
src/code/server/codeDefinition.ts | 182 ++
src/code/server/codeEditor.ts | 30 +
src/code/server/codeHighlight.ts | 1 +
src/code/server/codeLinting.ts | 137 ++
src/code/server/codeLogManager.ts | 49 +
src/code/server/codeReference.ts | 27 +
src/code/server/codeSymbol.ts | 479 ++++
src/code/server/codeTools.ts | 524 +++++
src/code/server/docSymbolProcesser.ts | 1833 +++++++++++++++
src/code/server/server.ts | 411 ++++
src/code/server/typeInfer.ts | 246 ++
src/{ => common}/LogManager.ts | 0
src/{ => common}/StatusBarManager.ts | 13 +
src/{ => common}/Tools.ts | 59 +-
src/{ => debug}/BreakPoint.ts | 0
src/{ => debug}/dataProcesser.ts | 2 +-
src/{ => debug}/debugAdapter.ts | 0
src/{ => debug}/luaDebug.ts | 31 +-
src/{ => debug}/luaDebugRuntime.ts | 6 +-
src/debug/updateManager.ts | 49 +
src/debug/visualSetting.ts | 87 +
src/extension.ts | 126 +-
src/tsconfig.json | 7 +-
40 files changed, 6238 insertions(+), 2883 deletions(-)
create mode 100755 res/lua/coroutine.lua
create mode 100755 res/lua/debug.lua
create mode 100755 res/lua/global.lua
create mode 100755 res/lua/io.lua
create mode 100755 res/lua/math.lua
create mode 100755 res/lua/os.lua
create mode 100755 res/lua/package.lua
create mode 100755 res/lua/string.lua
create mode 100755 res/lua/table.lua
create mode 100755 res/lua/utf8.lua
create mode 100644 res/others/launch.json
create mode 100755 res/snippets/snippets.json
create mode 100644 res/web/settings.html
create mode 100644 src/code/server/codeCompleting.ts
create mode 100644 src/code/server/codeDefinition.ts
create mode 100644 src/code/server/codeEditor.ts
create mode 100644 src/code/server/codeHighlight.ts
create mode 100644 src/code/server/codeLinting.ts
create mode 100644 src/code/server/codeLogManager.ts
create mode 100644 src/code/server/codeReference.ts
create mode 100644 src/code/server/codeSymbol.ts
create mode 100644 src/code/server/codeTools.ts
create mode 100644 src/code/server/docSymbolProcesser.ts
create mode 100755 src/code/server/server.ts
create mode 100644 src/code/server/typeInfer.ts
rename src/{ => common}/LogManager.ts (100%)
rename src/{ => common}/StatusBarManager.ts (58%)
rename src/{ => common}/Tools.ts (82%)
rename src/{ => debug}/BreakPoint.ts (100%)
rename src/{ => debug}/dataProcesser.ts (99%)
rename src/{ => debug}/debugAdapter.ts (100%)
rename src/{ => debug}/luaDebug.ts (97%)
rename src/{ => debug}/luaDebugRuntime.ts (98%)
create mode 100644 src/debug/updateManager.ts
create mode 100644 src/debug/visualSetting.ts
diff --git a/.vscode/launch.json b/.vscode/launch.json
index c51acbd..5a355cd 100755
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -4,13 +4,24 @@
{
"type": "extensionHost",
"request": "launch",
- "name": "LuaPandaExtension",
+ "name": "Launch Client",
"runtimeExecutable": "${execPath}",
- "args": [
- "--extensionDevelopmentPath=${workspaceFolder}"
- ],
- "outFiles": [ "${workspaceFolder}/out/**/*.js" ]
-
+ "args": ["--extensionDevelopmentPath=${workspaceRoot}"],
+ "outFiles": ["${workspaceRoot}/out/**/*.js", "${workspaceRoot}/out/common/*.js"]
+ },
+ {
+ "type": "node",
+ "request": "attach",
+ "name": "Attach to Server",
+ "port": 6009,
+ "restart": true,
+ "outFiles": ["${workspaceRoot}/out/code/server/**/*.js"]
+ }
+ ],
+ "compounds": [
+ {
+ "name": "Client + Server",
+ "configurations": ["Launch Client", "Attach to Server"]
}
]
}
diff --git a/package-lock.json b/package-lock.json
index 80ea915..1ab7295 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,9 +1,30 @@
{
"name": "luapanda",
- "version": "2.2.3",
+ "version": "3.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+ "@types/commander": {
+ "version": "2.12.2",
+ "resolved": "https://registry.npmjs.org/@types/commander/-/commander-2.12.2.tgz",
+ "integrity": "sha512-0QEFiR8ljcHp9bAbWxecjVRuAMr16ivPiGOw6KFQBVrVd0RQIcM3xKdRisH2EDWgVWujiYtHwhSkSUoAAGzH7Q==",
+ "requires": {
+ "commander": "*"
+ }
+ },
+ "@types/diff": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/@types/diff/-/diff-3.5.3.tgz",
+ "integrity": "sha512-YrLagYnL+tfrgM7bQ5yW34pi5cg9pmh5Gbq2Lmuuh+zh0ZjmK2fU3896PtlpJT3IDG2rdkoG30biHJepgIsMnw=="
+ },
+ "@types/get-stdin": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/@types/get-stdin/-/get-stdin-5.0.1.tgz",
+ "integrity": "sha1-Rq+8rwnpT+Alr6B66ZSsMWitvfM=",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@types/mocha": {
"version": "2.2.48",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.48.tgz",
@@ -13,47 +34,13 @@
"@types/node": {
"version": "7.0.55",
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.55.tgz",
- "integrity": "sha512-diCxfWNT4g2UM9Y+BPgy4s3egcZ2qOXc0mXLauvbsBUq9SBKQfh0SmuEUEhJVFZt/p6UDsjg1s2EgfM6OSlp4g==",
- "dev": true
- },
- "ajv": {
- "version": "6.10.2",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
- "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^2.0.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "ansi-cyan": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz",
- "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=",
- "dev": true,
- "requires": {
- "ansi-wrap": "0.1.0"
- }
- },
- "ansi-gray": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz",
- "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=",
- "dev": true,
- "requires": {
- "ansi-wrap": "0.1.0"
- }
+ "integrity": "sha512-diCxfWNT4g2UM9Y+BPgy4s3egcZ2qOXc0mXLauvbsBUq9SBKQfh0SmuEUEhJVFZt/p6UDsjg1s2EgfM6OSlp4g=="
},
- "ansi-red": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz",
- "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=",
- "dev": true,
- "requires": {
- "ansi-wrap": "0.1.0"
- }
+ "@types/vscode": {
+ "version": "1.39.0",
+ "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.39.0.tgz",
+ "integrity": "sha512-rlg0okXDt7NjAyHXbZ2nO1I/VY/8y9w67ltLRrOxXQ46ayvrYZavD4A6zpYrGbs2+ZOEQzcUs+QZOqcVGQIxXQ==",
+ "dev": true
},
"ansi-regex": {
"version": "2.1.1",
@@ -67,21 +54,6 @@
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
- "ansi-wrap": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
- "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=",
- "dev": true
- },
- "append-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz",
- "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=",
- "dev": true,
- "requires": {
- "buffer-equal": "^1.0.0"
- }
- },
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -91,105 +63,11 @@
"sprintf-js": "~1.0.2"
}
},
- "arr-diff": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz",
- "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=",
- "dev": true,
- "requires": {
- "arr-flatten": "^1.0.1",
- "array-slice": "^0.2.3"
- }
- },
- "arr-flatten": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
- "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
- "dev": true
- },
- "arr-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz",
- "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=",
- "dev": true
- },
- "array-differ": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
- "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=",
- "dev": true
- },
- "array-slice": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
- "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=",
- "dev": true
- },
- "array-union": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
- "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
- "dev": true,
- "requires": {
- "array-uniq": "^1.0.1"
- }
- },
- "array-uniq": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
- "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
- "dev": true
- },
- "array-unique": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
- "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
- "dev": true
- },
- "arrify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
- "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
- "dev": true
- },
- "asn1": {
- "version": "0.2.4",
- "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
- "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
- "dev": true,
- "requires": {
- "safer-buffer": "~2.1.0"
- }
- },
- "assert-plus": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
- "dev": true
- },
- "asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
- "dev": true
- },
"await-notify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/await-notify/-/await-notify-1.0.1.tgz",
"integrity": "sha1-C0gTOyLlJBgeEVV2ZRhfKi885Hw="
},
- "aws-sign2": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
- "dev": true
- },
- "aws4": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
- "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
- "dev": true
- },
"babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@@ -227,30 +105,6 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
- "bcrypt-pbkdf": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
- "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
- "dev": true,
- "requires": {
- "tweetnacl": "^0.14.3"
- }
- },
- "beeper": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz",
- "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=",
- "dev": true
- },
- "block-stream": {
- "version": "0.0.9",
- "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
- "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
- "dev": true,
- "requires": {
- "inherits": "~2.0.0"
- }
- },
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -266,17 +120,6 @@
"concat-map": "0.0.1"
}
},
- "braces": {
- "version": "1.8.5",
- "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
- "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
- "dev": true,
- "requires": {
- "expand-range": "^1.8.1",
- "preserve": "^0.2.0",
- "repeat-element": "^1.1.2"
- }
- },
"browser-stdout": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz",
@@ -289,30 +132,12 @@
"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
"dev": true
},
- "buffer-equal": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz",
- "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=",
- "dev": true
- },
- "buffer-from": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
- "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
- "dev": true
- },
"builtin-modules": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
"dev": true
},
- "caseless": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
- "dev": true
- },
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@@ -364,67 +189,6 @@
"parse5": "^3.0.1"
}
},
- "clone": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
- "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=",
- "dev": true
- },
- "clone-buffer": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
- "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=",
- "dev": true
- },
- "clone-stats": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
- "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=",
- "dev": true
- },
- "cloneable-readable": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz",
- "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==",
- "dev": true,
- "requires": {
- "inherits": "^2.0.1",
- "process-nextick-args": "^2.0.0",
- "readable-stream": "^2.3.5"
- },
- "dependencies": {
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- }
- }
- },
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -440,55 +204,16 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
- "color-support": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
- "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
- "dev": true
- },
- "combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "dev": true,
- "requires": {
- "delayed-stream": "~1.0.0"
- }
- },
"commander": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
- "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
- "dev": true
+ "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ=="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
- "convert-source-map": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
- "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.1"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- }
- }
- },
- "core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
- "dev": true
- },
"css-select": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
@@ -507,21 +232,6 @@
"integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
"dev": true
},
- "dashdash": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
- "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
- "dev": true,
- "requires": {
- "assert-plus": "^1.0.0"
- }
- },
- "dateformat": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz",
- "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=",
- "dev": true
- },
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
@@ -531,30 +241,6 @@
"ms": "2.0.0"
}
},
- "deep-assign": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/deep-assign/-/deep-assign-1.0.0.tgz",
- "integrity": "sha1-sJJ0O+hCfcYh6gBnzex+cN0Z83s=",
- "dev": true,
- "requires": {
- "is-obj": "^1.0.0"
- }
- },
- "define-properties": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
- "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
- "dev": true,
- "requires": {
- "object-keys": "^1.0.12"
- }
- },
- "delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
- "dev": true
- },
"denodeify": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz",
@@ -564,8 +250,7 @@
"diff": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz",
- "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==",
- "dev": true
+ "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww=="
},
"dom-serializer": {
"version": "0.1.1",
@@ -602,110 +287,6 @@
"domelementtype": "1"
}
},
- "duplexer": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
- "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
- "dev": true
- },
- "duplexer2": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
- "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=",
- "dev": true,
- "requires": {
- "readable-stream": "~1.1.9"
- },
- "dependencies": {
- "isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
- "dev": true
- },
- "readable-stream": {
- "version": "1.1.14",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
- "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.1",
- "isarray": "0.0.1",
- "string_decoder": "~0.10.x"
- }
- },
- "string_decoder": {
- "version": "0.10.31",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
- "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
- "dev": true
- }
- }
- },
- "duplexify": {
- "version": "3.7.1",
- "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
- "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
- "dev": true,
- "requires": {
- "end-of-stream": "^1.0.0",
- "inherits": "^2.0.1",
- "readable-stream": "^2.0.0",
- "stream-shift": "^1.0.0"
- },
- "dependencies": {
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- }
- }
- },
- "ecc-jsbn": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
- "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
- "dev": true,
- "requires": {
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.1.0"
- }
- },
- "end-of-stream": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
- "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
- "dev": true,
- "requires": {
- "once": "^1.4.0"
- }
- },
"entities": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
@@ -730,850 +311,53 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
- "event-stream": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
- "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=",
+ "fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
"dev": true,
"requires": {
- "duplexer": "~0.1.1",
- "from": "~0",
- "map-stream": "~0.1.0",
- "pause-stream": "0.0.11",
- "split": "0.3",
- "stream-combiner": "~0.0.4",
- "through": "~2.3.1"
+ "pend": "~1.2.0"
}
},
- "expand-brackets": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
- "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
- "dev": true,
- "requires": {
- "is-posix-bracket": "^0.1.0"
- }
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "get-stdin": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz",
+ "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g="
},
- "expand-range": {
- "version": "1.8.2",
- "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
- "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+ "glob": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true,
"requires": {
- "fill-range": "^2.1.0"
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
}
},
- "extend": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "growl": {
+ "version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz",
+ "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==",
"dev": true
},
- "extend-shallow": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz",
- "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=",
- "dev": true,
- "requires": {
- "kind-of": "^1.1.0"
- }
- },
- "extglob": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
- "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
"dev": true,
"requires": {
- "is-extglob": "^1.0.0"
- },
- "dependencies": {
- "is-extglob": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
- "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
- "dev": true
- }
- }
- },
- "extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
- "dev": true
- },
- "fancy-log": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz",
- "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==",
- "dev": true,
- "requires": {
- "ansi-gray": "^0.1.1",
- "color-support": "^1.1.3",
- "parse-node-version": "^1.0.0",
- "time-stamp": "^1.0.0"
- }
- },
- "fast-deep-equal": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
- "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
- "dev": true
- },
- "fast-json-stable-stringify": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
- "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
- "dev": true
- },
- "fd-slicer": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
- "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
- "dev": true,
- "requires": {
- "pend": "~1.2.0"
- }
- },
- "filename-regex": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
- "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
- "dev": true
- },
- "fill-range": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
- "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
- "dev": true,
- "requires": {
- "is-number": "^2.1.0",
- "isobject": "^2.0.0",
- "randomatic": "^3.0.0",
- "repeat-element": "^1.1.2",
- "repeat-string": "^1.5.2"
- }
- },
- "first-chunk-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz",
- "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=",
- "dev": true
- },
- "flush-write-stream": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
- "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
- "dev": true,
- "requires": {
- "inherits": "^2.0.3",
- "readable-stream": "^2.3.6"
- },
- "dependencies": {
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- }
- }
- },
- "for-in": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
- "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
- "dev": true
- },
- "for-own": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
- "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
- "dev": true,
- "requires": {
- "for-in": "^1.0.1"
- }
- },
- "forever-agent": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
- "dev": true
- },
- "form-data": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
- "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
- "dev": true,
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- }
- },
- "from": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
- "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=",
- "dev": true
- },
- "fs-mkdirp-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz",
- "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.11",
- "through2": "^2.0.3"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
- "dev": true
- },
- "fstream": {
- "version": "1.0.12",
- "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
- "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.2",
- "inherits": "~2.0.0",
- "mkdirp": ">=0.5 0",
- "rimraf": "2"
- }
- },
- "function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
- },
- "getpass": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
- "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
- "dev": true,
- "requires": {
- "assert-plus": "^1.0.0"
- }
- },
- "glob": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
- "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "glob-base": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
- "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
- "dev": true,
- "requires": {
- "glob-parent": "^2.0.0",
- "is-glob": "^2.0.0"
- },
- "dependencies": {
- "glob-parent": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
- "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
- "dev": true,
- "requires": {
- "is-glob": "^2.0.0"
- }
- },
- "is-extglob": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
- "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
- "dev": true
- },
- "is-glob": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
- "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
- "dev": true,
- "requires": {
- "is-extglob": "^1.0.0"
- }
- }
- }
- },
- "glob-parent": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
- "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
- "dev": true,
- "requires": {
- "is-glob": "^3.1.0",
- "path-dirname": "^1.0.0"
- }
- },
- "glob-stream": {
- "version": "5.3.5",
- "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz",
- "integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=",
- "dev": true,
- "requires": {
- "extend": "^3.0.0",
- "glob": "^5.0.3",
- "glob-parent": "^3.0.0",
- "micromatch": "^2.3.7",
- "ordered-read-streams": "^0.3.0",
- "through2": "^0.6.0",
- "to-absolute-glob": "^0.1.1",
- "unique-stream": "^2.0.2"
- },
- "dependencies": {
- "glob": {
- "version": "5.0.15",
- "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
- "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
- "dev": true,
- "requires": {
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "2 || 3",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
- "dev": true
- },
- "readable-stream": {
- "version": "1.0.34",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
- "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.1",
- "isarray": "0.0.1",
- "string_decoder": "~0.10.x"
- }
- },
- "string_decoder": {
- "version": "0.10.31",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
- "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
- "dev": true
- },
- "through2": {
- "version": "0.6.5",
- "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
- "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
- "dev": true,
- "requires": {
- "readable-stream": ">=1.0.33-1 <1.1.0-0",
- "xtend": ">=4.0.0 <4.1.0-0"
- }
- }
- }
- },
- "glogg": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz",
- "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==",
- "dev": true,
- "requires": {
- "sparkles": "^1.0.0"
- }
- },
- "graceful-fs": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.1.tgz",
- "integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==",
- "dev": true
- },
- "growl": {
- "version": "1.10.3",
- "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz",
- "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==",
- "dev": true
- },
- "gulp-chmod": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/gulp-chmod/-/gulp-chmod-2.0.0.tgz",
- "integrity": "sha1-AMOQuSigeZslGsz2MaoJ4BzGKZw=",
- "dev": true,
- "requires": {
- "deep-assign": "^1.0.0",
- "stat-mode": "^0.2.0",
- "through2": "^2.0.0"
- }
- },
- "gulp-filter": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/gulp-filter/-/gulp-filter-5.1.0.tgz",
- "integrity": "sha1-oF4Rr/sHz33PQafeHLe2OsN4PnM=",
- "dev": true,
- "requires": {
- "multimatch": "^2.0.0",
- "plugin-error": "^0.1.2",
- "streamfilter": "^1.0.5"
- }
- },
- "gulp-gunzip": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/gulp-gunzip/-/gulp-gunzip-1.0.0.tgz",
- "integrity": "sha1-FbdBFF6Dqcb1CIYkG1fMWHHxUak=",
- "dev": true,
- "requires": {
- "through2": "~0.6.5",
- "vinyl": "~0.4.6"
- },
- "dependencies": {
- "isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
- "dev": true
- },
- "readable-stream": {
- "version": "1.0.34",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
- "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.1",
- "isarray": "0.0.1",
- "string_decoder": "~0.10.x"
- }
- },
- "string_decoder": {
- "version": "0.10.31",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
- "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
- "dev": true
- },
- "through2": {
- "version": "0.6.5",
- "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
- "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
- "dev": true,
- "requires": {
- "readable-stream": ">=1.0.33-1 <1.1.0-0",
- "xtend": ">=4.0.0 <4.1.0-0"
- }
- }
- }
- },
- "gulp-remote-src": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/gulp-remote-src/-/gulp-remote-src-0.4.4.tgz",
- "integrity": "sha512-mo7lGgZmNXyTbcUzfjSnUVkx1pnqqiwv/pPaIrYdTO77hq0WNTxXLAzQdoYOnyJ0mfVLNmNl9AGqWLiAzTPMMA==",
- "dev": true,
- "requires": {
- "event-stream": "3.3.4",
- "node.extend": "~1.1.2",
- "request": "^2.88.0",
- "through2": "~2.0.3",
- "vinyl": "~2.0.1"
- },
- "dependencies": {
- "clone": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
- "dev": true
- },
- "clone-stats": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
- "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
- "dev": true
- },
- "vinyl": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.0.2.tgz",
- "integrity": "sha1-CjcT2NTpIhxY8QyhbAEWyeJe2nw=",
- "dev": true,
- "requires": {
- "clone": "^1.0.0",
- "clone-buffer": "^1.0.0",
- "clone-stats": "^1.0.0",
- "cloneable-readable": "^1.0.0",
- "is-stream": "^1.1.0",
- "remove-trailing-separator": "^1.0.1",
- "replace-ext": "^1.0.0"
- }
- }
- }
- },
- "gulp-sourcemaps": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz",
- "integrity": "sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=",
- "dev": true,
- "requires": {
- "convert-source-map": "^1.1.1",
- "graceful-fs": "^4.1.2",
- "strip-bom": "^2.0.0",
- "through2": "^2.0.0",
- "vinyl": "^1.0.0"
- },
- "dependencies": {
- "clone": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
- "dev": true
- },
- "replace-ext": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
- "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=",
- "dev": true
- },
- "vinyl": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz",
- "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=",
- "dev": true,
- "requires": {
- "clone": "^1.0.0",
- "clone-stats": "^0.0.1",
- "replace-ext": "0.0.1"
- }
- }
- }
- },
- "gulp-symdest": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/gulp-symdest/-/gulp-symdest-1.1.1.tgz",
- "integrity": "sha512-UHd3MokfIN7SrFdsbV5uZTwzBpL0ZSTu7iq98fuDqBGZ0dlHxgbQBJwfd6qjCW83snkQ3Hz9IY4sMRMz2iTq7w==",
- "dev": true,
- "requires": {
- "event-stream": "3.3.4",
- "mkdirp": "^0.5.1",
- "queue": "^3.1.0",
- "vinyl-fs": "^2.4.3"
- }
- },
- "gulp-untar": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/gulp-untar/-/gulp-untar-0.0.6.tgz",
- "integrity": "sha1-1r3v3n6ajgVMnxYjhaB4LEvnQAA=",
- "dev": true,
- "requires": {
- "event-stream": "~3.3.4",
- "gulp-util": "~3.0.8",
- "streamifier": "~0.1.1",
- "tar": "^2.2.1",
- "through2": "~2.0.3"
- }
- },
- "gulp-util": {
- "version": "3.0.8",
- "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz",
- "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=",
- "dev": true,
- "requires": {
- "array-differ": "^1.0.0",
- "array-uniq": "^1.0.2",
- "beeper": "^1.0.0",
- "chalk": "^1.0.0",
- "dateformat": "^2.0.0",
- "fancy-log": "^1.1.0",
- "gulplog": "^1.0.0",
- "has-gulplog": "^0.1.0",
- "lodash._reescape": "^3.0.0",
- "lodash._reevaluate": "^3.0.0",
- "lodash._reinterpolate": "^3.0.0",
- "lodash.template": "^3.0.0",
- "minimist": "^1.1.0",
- "multipipe": "^0.1.2",
- "object-assign": "^3.0.0",
- "replace-ext": "0.0.1",
- "through2": "^2.0.0",
- "vinyl": "^0.5.0"
- },
- "dependencies": {
- "chalk": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- }
- },
- "clone": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
- "dev": true
- },
- "minimist": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
- "dev": true
- },
- "object-assign": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
- "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=",
- "dev": true
- },
- "replace-ext": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
- "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=",
- "dev": true
- },
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- },
- "vinyl": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
- "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=",
- "dev": true,
- "requires": {
- "clone": "^1.0.0",
- "clone-stats": "^0.0.1",
- "replace-ext": "0.0.1"
- }
- }
- }
- },
- "gulp-vinyl-zip": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/gulp-vinyl-zip/-/gulp-vinyl-zip-2.1.2.tgz",
- "integrity": "sha512-wJn09jsb8PyvUeyFF7y7ImEJqJwYy40BqL9GKfJs6UGpaGW9A+N68Q+ajsIpb9AeR6lAdjMbIdDPclIGo1/b7Q==",
- "dev": true,
- "requires": {
- "event-stream": "3.3.4",
- "queue": "^4.2.1",
- "through2": "^2.0.3",
- "vinyl": "^2.0.2",
- "vinyl-fs": "^3.0.3",
- "yauzl": "^2.2.1",
- "yazl": "^2.2.1"
- },
- "dependencies": {
- "clone": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
- "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
- "dev": true
- },
- "clone-stats": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
- "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
- "dev": true
- },
- "glob-stream": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz",
- "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=",
- "dev": true,
- "requires": {
- "extend": "^3.0.0",
- "glob": "^7.1.1",
- "glob-parent": "^3.1.0",
- "is-negated-glob": "^1.0.0",
- "ordered-read-streams": "^1.0.0",
- "pumpify": "^1.3.5",
- "readable-stream": "^2.1.5",
- "remove-trailing-separator": "^1.0.1",
- "to-absolute-glob": "^2.0.0",
- "unique-stream": "^2.0.2"
- }
- },
- "is-valid-glob": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz",
- "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=",
- "dev": true
- },
- "ordered-read-streams": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz",
- "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=",
- "dev": true,
- "requires": {
- "readable-stream": "^2.0.1"
- }
- },
- "queue": {
- "version": "4.5.1",
- "resolved": "https://registry.npmjs.org/queue/-/queue-4.5.1.tgz",
- "integrity": "sha512-AMD7w5hRXcFSb8s9u38acBZ+309u6GsiibP4/0YacJeaurRshogB7v/ZcVPxP5gD5+zIw6ixRHdutiYUJfwKHw==",
- "dev": true,
- "requires": {
- "inherits": "~2.0.0"
- }
- },
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- },
- "to-absolute-glob": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
- "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=",
- "dev": true,
- "requires": {
- "is-absolute": "^1.0.0",
- "is-negated-glob": "^1.0.0"
- }
- },
- "vinyl": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
- "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
- "dev": true,
- "requires": {
- "clone": "^2.1.1",
- "clone-buffer": "^1.0.0",
- "clone-stats": "^1.0.0",
- "cloneable-readable": "^1.0.0",
- "remove-trailing-separator": "^1.0.1",
- "replace-ext": "^1.0.0"
- }
- },
- "vinyl-fs": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz",
- "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==",
- "dev": true,
- "requires": {
- "fs-mkdirp-stream": "^1.0.0",
- "glob-stream": "^6.1.0",
- "graceful-fs": "^4.0.0",
- "is-valid-glob": "^1.0.0",
- "lazystream": "^1.0.0",
- "lead": "^1.0.0",
- "object.assign": "^4.0.4",
- "pumpify": "^1.3.5",
- "readable-stream": "^2.3.3",
- "remove-bom-buffer": "^3.0.0",
- "remove-bom-stream": "^1.2.0",
- "resolve-options": "^1.1.0",
- "through2": "^2.0.0",
- "to-through": "^2.0.0",
- "value-or-function": "^3.0.0",
- "vinyl": "^2.0.0",
- "vinyl-sourcemap": "^1.1.0"
- }
- }
- }
- },
- "gulplog": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
- "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=",
- "dev": true,
- "requires": {
- "glogg": "^1.0.0"
- }
- },
- "har-schema": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
- "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
- "dev": true
- },
- "har-validator": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
- "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
- "dev": true,
- "requires": {
- "ajv": "^6.5.5",
- "har-schema": "^2.0.0"
- }
- },
- "has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dev": true,
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-ansi": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
- "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
- "dev": true,
- "requires": {
- "ansi-regex": "^2.0.0"
+ "ansi-regex": "^2.0.0"
}
},
"has-flag": {
@@ -1582,21 +366,6 @@
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
"dev": true
},
- "has-gulplog": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
- "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=",
- "dev": true,
- "requires": {
- "sparkles": "^1.0.0"
- }
- },
- "has-symbols": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
- "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
- "dev": true
- },
"he": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
@@ -1617,463 +386,85 @@
"readable-stream": "^3.1.1"
}
},
- "http-signature": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
- "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
- "dev": true,
- "requires": {
- "assert-plus": "^1.0.0",
- "jsprim": "^1.2.2",
- "sshpk": "^1.7.0"
- }
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "dev": true,
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
- },
- "is": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz",
- "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==",
- "dev": true
- },
- "is-absolute": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
- "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
- "dev": true,
- "requires": {
- "is-relative": "^1.0.0",
- "is-windows": "^1.0.1"
- }
- },
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
- "dev": true
- },
- "is-dotfile": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
- "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
- "dev": true
- },
- "is-equal-shallow": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
- "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
- "dev": true,
- "requires": {
- "is-primitive": "^2.0.0"
- }
- },
- "is-extendable": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
- "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
- "dev": true
- },
- "is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
- "dev": true
- },
- "is-glob": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
- "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
- "dev": true,
- "requires": {
- "is-extglob": "^2.1.0"
- }
- },
- "is-negated-glob": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
- "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=",
- "dev": true
- },
- "is-number": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
- "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
- "dev": true,
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true,
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "is-obj": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
- "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
- "dev": true
- },
- "is-posix-bracket": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
- "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
- "dev": true
- },
- "is-primitive": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
- "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
- "dev": true
- },
- "is-relative": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
- "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
- "dev": true,
- "requires": {
- "is-unc-path": "^1.0.0"
- }
- },
- "is-stream": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
- "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
- "dev": true
- },
- "is-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
- "dev": true
- },
- "is-unc-path": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
- "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
- "dev": true,
- "requires": {
- "unc-path-regex": "^0.1.2"
- }
- },
- "is-utf8": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
- "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
- "dev": true
- },
- "is-valid-glob": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-0.3.0.tgz",
- "integrity": "sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=",
- "dev": true
- },
- "is-windows": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
- "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
- "dev": true
- },
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
- },
- "isobject": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
- "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
- "dev": true,
- "requires": {
- "isarray": "1.0.0"
- }
- },
- "isstream": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
- "dev": true
- },
- "js-tokens": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
- "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
- "dev": true
- },
- "js-yaml": {
- "version": "3.13.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
- "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
- "dev": true,
- "requires": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- }
- },
- "jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
- "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
- "dev": true
- },
- "json-schema": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
- "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
- "dev": true
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
- "dev": true
- },
- "json-stringify-safe": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
- "dev": true
- },
- "jsprim": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
- "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
- "dev": true,
- "requires": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.3.0",
- "json-schema": "0.2.3",
- "verror": "1.10.0"
- }
- },
- "kind-of": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
- "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=",
- "dev": true
- },
- "lazystream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
- "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
- "dev": true,
- "requires": {
- "readable-stream": "^2.0.5"
- },
- "dependencies": {
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- }
- }
- },
- "lead": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz",
- "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=",
- "dev": true,
- "requires": {
- "flush-write-stream": "^1.0.2"
- }
- },
- "linkify-it": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
- "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
- "dev": true,
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"requires": {
- "uc.micro": "^1.0.1"
+ "safer-buffer": ">= 2.1.2 < 3"
}
},
- "lodash": {
- "version": "4.17.15",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
- "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
- "dev": true
- },
- "lodash._basecopy": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
- "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=",
- "dev": true
- },
- "lodash._basetostring": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz",
- "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=",
- "dev": true
- },
- "lodash._basevalues": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz",
- "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=",
- "dev": true
- },
- "lodash._getnative": {
- "version": "3.9.1",
- "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
- "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=",
- "dev": true
- },
- "lodash._isiterateecall": {
- "version": "3.0.9",
- "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz",
- "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=",
- "dev": true
- },
- "lodash._reescape": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz",
- "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=",
- "dev": true
- },
- "lodash._reevaluate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz",
- "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=",
- "dev": true
- },
- "lodash._reinterpolate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
- "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=",
- "dev": true
- },
- "lodash._root": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz",
- "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=",
- "dev": true
- },
- "lodash.escape": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
- "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=",
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": {
- "lodash._root": "^3.0.0"
+ "once": "^1.3.0",
+ "wrappy": "1"
}
},
- "lodash.isarguments": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
- "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=",
- "dev": true
- },
- "lodash.isarray": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
- "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
- "lodash.isequal": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
- "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
+ "js-tokens": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
"dev": true
},
- "lodash.keys": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
- "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
+ "js-yaml": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"dev": true,
"requires": {
- "lodash._getnative": "^3.0.0",
- "lodash.isarguments": "^3.0.0",
- "lodash.isarray": "^3.0.0"
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
}
},
- "lodash.restparam": {
- "version": "3.6.1",
- "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",
- "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=",
- "dev": true
- },
- "lodash.template": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
- "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=",
+ "linkify-it": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
+ "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
"dev": true,
"requires": {
- "lodash._basecopy": "^3.0.0",
- "lodash._basetostring": "^3.0.0",
- "lodash._basevalues": "^3.0.0",
- "lodash._isiterateecall": "^3.0.0",
- "lodash._reinterpolate": "^3.0.0",
- "lodash.escape": "^3.0.0",
- "lodash.keys": "^3.0.0",
- "lodash.restparam": "^3.0.0",
- "lodash.templatesettings": "^3.0.0"
+ "uc.micro": "^1.0.1"
}
},
- "lodash.templatesettings": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz",
- "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=",
- "dev": true,
+ "lodash": {
+ "version": "4.17.15",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+ "dev": true
+ },
+ "lua-fmt": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/lua-fmt/-/lua-fmt-2.6.0.tgz",
+ "integrity": "sha1-75rAVz0dpzMNygnAIsOaM67TR6M=",
"requires": {
- "lodash._reinterpolate": "^3.0.0",
- "lodash.escape": "^3.0.0"
+ "@types/commander": "^2.3.31",
+ "@types/diff": "^3.2.0",
+ "@types/get-stdin": "^5.0.0",
+ "commander": "^2.9.0",
+ "diff": "^3.3.0",
+ "get-stdin": "^5.0.1",
+ "luaparse": "github:oxyc/luaparse#ac42a00ebf4020b8c9d3219e4b0f84bf7ce6e802"
+ },
+ "dependencies": {
+ "luaparse": {
+ "version": "github:oxyc/luaparse#ac42a00ebf4020b8c9d3219e4b0f84bf7ce6e802",
+ "from": "github:oxyc/luaparse#ac42a00ebf4020b8c9d3219e4b0f84bf7ce6e802"
+ }
}
},
- "map-stream": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
- "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=",
- "dev": true
+ "luaparse": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/luaparse/-/luaparse-0.2.1.tgz",
+ "integrity": "sha1-qo9WEysN6X0388mRqd9C4OF/ZWw="
},
"markdown-it": {
"version": "8.4.2",
@@ -2088,136 +479,18 @@
"uc.micro": "^1.0.5"
}
},
- "math-random": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
- "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
- "dev": true
- },
"mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
"dev": true
},
- "merge-stream": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz",
- "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=",
- "dev": true,
- "requires": {
- "readable-stream": "^2.0.1"
- },
- "dependencies": {
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- }
- }
- },
- "micromatch": {
- "version": "2.3.11",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
- "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
- "dev": true,
- "requires": {
- "arr-diff": "^2.0.0",
- "array-unique": "^0.2.1",
- "braces": "^1.8.2",
- "expand-brackets": "^0.1.4",
- "extglob": "^0.3.1",
- "filename-regex": "^2.0.0",
- "is-extglob": "^1.0.0",
- "is-glob": "^2.0.1",
- "kind-of": "^3.0.2",
- "normalize-path": "^2.0.1",
- "object.omit": "^2.0.0",
- "parse-glob": "^3.0.4",
- "regex-cache": "^0.4.2"
- },
- "dependencies": {
- "arr-diff": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
- "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
- "dev": true,
- "requires": {
- "arr-flatten": "^1.0.1"
- }
- },
- "is-extglob": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
- "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
- "dev": true
- },
- "is-glob": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
- "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
- "dev": true,
- "requires": {
- "is-extglob": "^1.0.0"
- }
- },
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true,
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"dev": true
},
- "mime-db": {
- "version": "1.40.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
- "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==",
- "dev": true
- },
- "mime-types": {
- "version": "2.1.24",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
- "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
- "dev": true,
- "requires": {
- "mime-db": "1.40.0"
- }
- },
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -2265,61 +538,12 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
- "multimatch": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz",
- "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=",
- "dev": true,
- "requires": {
- "array-differ": "^1.0.0",
- "array-union": "^1.0.1",
- "arrify": "^1.0.0",
- "minimatch": "^3.0.0"
- }
- },
- "multipipe": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
- "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=",
- "dev": true,
- "requires": {
- "duplexer2": "0.0.2"
- }
- },
"mute-stream": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
"dev": true
},
- "node.extend": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-1.1.8.tgz",
- "integrity": "sha512-L/dvEBwyg3UowwqOUTyDsGBU6kjBQOpOhshio9V3i3BMPv5YUb9+mWNN8MK0IbWqT0AqaTSONZf0aTuMMahWgA==",
- "dev": true,
- "requires": {
- "has": "^1.0.3",
- "is": "^3.2.1"
- }
- },
- "normalize-path": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
- "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
- "dev": true,
- "requires": {
- "remove-trailing-separator": "^1.0.1"
- }
- },
- "now-and-later": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz",
- "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==",
- "dev": true,
- "requires": {
- "once": "^1.3.2"
- }
- },
"nth-check": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
@@ -2329,46 +553,6 @@
"boolbase": "~1.0.0"
}
},
- "oauth-sign": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
- "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
- "dev": true
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
- },
- "object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
- "dev": true
- },
- "object.assign": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
- "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
- "dev": true,
- "requires": {
- "define-properties": "^1.1.2",
- "function-bind": "^1.1.1",
- "has-symbols": "^1.0.0",
- "object-keys": "^1.0.11"
- }
- },
- "object.omit": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
- "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
- "dev": true,
- "requires": {
- "for-own": "^0.1.4",
- "is-extendable": "^0.1.1"
- }
- },
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -2378,48 +562,6 @@
"wrappy": "1"
}
},
- "ordered-read-streams": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz",
- "integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=",
- "dev": true,
- "requires": {
- "is-stream": "^1.0.1",
- "readable-stream": "^2.0.1"
- },
- "dependencies": {
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- }
- }
- },
"os-homedir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
@@ -2442,41 +584,6 @@
"os-tmpdir": "^1.0.0"
}
},
- "parse-glob": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
- "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
- "dev": true,
- "requires": {
- "glob-base": "^0.3.0",
- "is-dotfile": "^1.0.0",
- "is-extglob": "^1.0.0",
- "is-glob": "^2.0.0"
- },
- "dependencies": {
- "is-extglob": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
- "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
- "dev": true
- },
- "is-glob": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
- "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
- "dev": true,
- "requires": {
- "is-extglob": "^1.0.0"
- }
- }
- }
- },
- "parse-node-version": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
- "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
- "dev": true
- },
"parse-semver": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
@@ -2495,12 +602,6 @@
"@types/node": "*"
}
},
- "path-dirname": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
- "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
- "dev": true
- },
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
@@ -2521,244 +622,37 @@
"minimatch": "^3.0.4"
}
},
- "pause-stream": {
- "version": "0.0.11",
- "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
- "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=",
- "dev": true,
- "requires": {
- "through": "~2.3"
- }
- },
"pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
"dev": true
},
- "performance-now": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
- "dev": true
- },
- "plugin-error": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz",
- "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=",
- "dev": true,
- "requires": {
- "ansi-cyan": "^0.1.1",
- "ansi-red": "^0.1.1",
- "arr-diff": "^1.0.1",
- "arr-union": "^2.0.1",
- "extend-shallow": "^1.1.2"
- }
- },
- "preserve": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
- "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
- "dev": true
- },
- "process-nextick-args": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
- "dev": true
- },
- "psl": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.3.0.tgz",
- "integrity": "sha512-avHdspHO+9rQTLbv1RO+MPYeP/SzsCoxofjVnHanETfQhTJrmB0HlDoW+EiN/R+C0BZ+gERab9NY0lPN2TxNag==",
- "dev": true
- },
- "pump": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
- "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
- "dev": true,
- "requires": {
- "end-of-stream": "^1.1.0",
- "once": "^1.3.1"
- }
- },
- "pumpify": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
- "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
- "dev": true,
- "requires": {
- "duplexify": "^3.6.0",
- "inherits": "^2.0.3",
- "pump": "^2.0.0"
- }
- },
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true
- },
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
- "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
- "dev": true
- },
- "qs": {
- "version": "6.5.2",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
- "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
- "dev": true
- },
- "querystringify": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
- "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==",
- "dev": true
- },
- "queue": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/queue/-/queue-3.1.0.tgz",
- "integrity": "sha1-bEnQHwCeIlZ4h4nyv/rGuLmZBYU=",
- "dev": true,
- "requires": {
- "inherits": "~2.0.0"
- }
- },
- "randomatic": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
- "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
- "dev": true,
- "requires": {
- "is-number": "^4.0.0",
- "kind-of": "^6.0.0",
- "math-random": "^1.0.1"
- },
- "dependencies": {
- "is-number": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
- "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
- "dev": true
- },
- "kind-of": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
- "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
- "dev": true
- }
- }
- },
- "read": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
- "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
- "dev": true,
- "requires": {
- "mute-stream": "~0.0.4"
- }
- },
- "readable-stream": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
- "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
- "dev": true,
- "requires": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- }
- },
- "regex-cache": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
- "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
- "dev": true,
- "requires": {
- "is-equal-shallow": "^0.1.3"
- }
- },
- "remove-bom-buffer": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",
- "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==",
- "dev": true,
- "requires": {
- "is-buffer": "^1.1.5",
- "is-utf8": "^0.2.1"
- }
- },
- "remove-bom-stream": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz",
- "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=",
- "dev": true,
- "requires": {
- "remove-bom-buffer": "^3.0.0",
- "safe-buffer": "^5.1.0",
- "through2": "^2.0.3"
- }
- },
- "remove-trailing-separator": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
- "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
- "dev": true
- },
- "repeat-element": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
- "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
- "dev": true
- },
- "repeat-string": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
- "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
- "dev": true
- },
- "replace-ext": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
- "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
+ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
"dev": true
},
- "request": {
- "version": "2.88.0",
- "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
- "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+ "read": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
+ "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
"dev": true,
"requires": {
- "aws-sign2": "~0.7.0",
- "aws4": "^1.8.0",
- "caseless": "~0.12.0",
- "combined-stream": "~1.0.6",
- "extend": "~3.0.2",
- "forever-agent": "~0.6.1",
- "form-data": "~2.3.2",
- "har-validator": "~5.1.0",
- "http-signature": "~1.2.0",
- "is-typedarray": "~1.0.0",
- "isstream": "~0.1.2",
- "json-stringify-safe": "~5.0.1",
- "mime-types": "~2.1.19",
- "oauth-sign": "~0.9.0",
- "performance-now": "^2.1.0",
- "qs": "~6.5.2",
- "safe-buffer": "^5.1.2",
- "tough-cookie": "~2.4.3",
- "tunnel-agent": "^0.6.0",
- "uuid": "^3.3.2"
+ "mute-stream": "~0.0.4"
}
},
- "requires-port": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
- "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
- "dev": true
+ "readable-stream": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
+ "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
},
"resolve": {
"version": "1.12.0",
@@ -2769,40 +663,6 @@
"path-parse": "^1.0.6"
}
},
- "resolve-options": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz",
- "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=",
- "dev": true,
- "requires": {
- "value-or-function": "^3.0.0"
- }
- },
- "rimraf": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
- "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- },
- "dependencies": {
- "glob": {
- "version": "7.1.4",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
- "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- }
- }
- },
"safe-buffer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
@@ -2812,45 +672,12 @@
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "dev": true
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"semver": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
- "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
- "dev": true
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true
- },
- "source-map-support": {
- "version": "0.5.13",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
- "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
- "dev": true,
- "requires": {
- "buffer-from": "^1.0.0",
- "source-map": "^0.6.0"
- }
- },
- "sparkles": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz",
- "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==",
- "dev": true
- },
- "split": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
- "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=",
- "dev": true,
- "requires": {
- "through": "2"
- }
+ "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
},
"sprintf-js": {
"version": "1.0.3",
@@ -2858,91 +685,6 @@
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
- "sshpk": {
- "version": "1.16.1",
- "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
- "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
- "dev": true,
- "requires": {
- "asn1": "~0.2.3",
- "assert-plus": "^1.0.0",
- "bcrypt-pbkdf": "^1.0.0",
- "dashdash": "^1.12.0",
- "ecc-jsbn": "~0.1.1",
- "getpass": "^0.1.1",
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.0.2",
- "tweetnacl": "~0.14.0"
- }
- },
- "stat-mode": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.2.tgz",
- "integrity": "sha1-5sgLYjEj19gM8TLOU480YokHJQI=",
- "dev": true
- },
- "stream-combiner": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
- "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=",
- "dev": true,
- "requires": {
- "duplexer": "~0.1.1"
- }
- },
- "stream-shift": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
- "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
- "dev": true
- },
- "streamfilter": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/streamfilter/-/streamfilter-1.0.7.tgz",
- "integrity": "sha512-Gk6KZM+yNA1JpW0KzlZIhjo3EaBJDkYfXtYSbOwNIQ7Zd6006E6+sCFlW1NDvFG/vnXhKmw6TJJgiEQg/8lXfQ==",
- "dev": true,
- "requires": {
- "readable-stream": "^2.0.2"
- },
- "dependencies": {
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- }
- }
- },
- "streamifier": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/streamifier/-/streamifier-0.1.1.tgz",
- "integrity": "sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8=",
- "dev": true
- },
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -2961,25 +703,6 @@
"ansi-regex": "^2.0.0"
}
},
- "strip-bom": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
- "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
- "dev": true,
- "requires": {
- "is-utf8": "^0.2.0"
- }
- },
- "strip-bom-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz",
- "integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=",
- "dev": true,
- "requires": {
- "first-chunk-stream": "^1.0.0",
- "strip-bom": "^2.0.0"
- }
- },
"supports-color": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
@@ -2989,81 +712,6 @@
"has-flag": "^2.0.0"
}
},
- "tar": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
- "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
- "dev": true,
- "requires": {
- "block-stream": "*",
- "fstream": "^1.0.12",
- "inherits": "2"
- }
- },
- "through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
- "dev": true
- },
- "through2": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
- "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
- "dev": true,
- "requires": {
- "readable-stream": "~2.3.6",
- "xtend": "~4.0.1"
- },
- "dependencies": {
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- }
- }
- },
- "through2-filter": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz",
- "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=",
- "dev": true,
- "requires": {
- "through2": "~2.0.0",
- "xtend": "~4.0.0"
- }
- },
- "time-stamp": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
- "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=",
- "dev": true
- },
"tmp": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz",
@@ -3073,53 +721,6 @@
"os-tmpdir": "~1.0.1"
}
},
- "to-absolute-glob": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz",
- "integrity": "sha1-HN+kcqnvUMI57maZm2YsoOs5k38=",
- "dev": true,
- "requires": {
- "extend-shallow": "^2.0.1"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "to-through": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz",
- "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=",
- "dev": true,
- "requires": {
- "through2": "^2.0.3"
- }
- },
- "tough-cookie": {
- "version": "2.4.3",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
- "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
- "dev": true,
- "requires": {
- "psl": "^1.1.24",
- "punycode": "^1.4.1"
- },
- "dependencies": {
- "punycode": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
- "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
- "dev": true
- }
- }
- },
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
@@ -3169,21 +770,6 @@
"integrity": "sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM=",
"dev": true
},
- "tunnel-agent": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
- "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
- "dev": true,
- "requires": {
- "safe-buffer": "^5.0.1"
- }
- },
- "tweetnacl": {
- "version": "0.14.5",
- "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
- "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
- "dev": true
- },
"typed-rest-client": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-0.9.0.tgz",
@@ -3214,63 +800,24 @@
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
"dev": true
},
- "unc-path-regex": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
- "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
- "dev": true
- },
"underscore": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz",
"integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==",
"dev": true
},
- "unique-stream": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
- "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==",
- "dev": true,
- "requires": {
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "through2-filter": "^3.0.0"
- },
- "dependencies": {
- "through2-filter": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz",
- "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==",
- "dev": true,
- "requires": {
- "through2": "~2.0.0",
- "xtend": "~4.0.0"
- }
- }
- }
- },
- "uri-js": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
- "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
- "dev": true,
- "requires": {
- "punycode": "^2.1.0"
- }
- },
"url-join": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz",
"integrity": "sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg=",
"dev": true
},
- "url-parse": {
- "version": "1.4.7",
- "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz",
- "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==",
- "dev": true,
+ "urlencode": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/urlencode/-/urlencode-1.1.0.tgz",
+ "integrity": "sha1-HyuibwE8hfATP3o61v8nMK33y7c=",
"requires": {
- "querystringify": "^2.1.1",
- "requires-port": "^1.0.0"
+ "iconv-lite": "~0.4.11"
}
},
"util-deprecate": {
@@ -3279,178 +826,6 @@
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true
},
- "uuid": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
- "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
- "dev": true
- },
- "vali-date": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz",
- "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=",
- "dev": true
- },
- "value-or-function": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
- "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=",
- "dev": true
- },
- "verror": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
- "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
- "dev": true,
- "requires": {
- "assert-plus": "^1.0.0",
- "core-util-is": "1.0.2",
- "extsprintf": "^1.2.0"
- }
- },
- "vinyl": {
- "version": "0.4.6",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
- "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=",
- "dev": true,
- "requires": {
- "clone": "^0.2.0",
- "clone-stats": "^0.0.1"
- }
- },
- "vinyl-fs": {
- "version": "2.4.4",
- "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz",
- "integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=",
- "dev": true,
- "requires": {
- "duplexify": "^3.2.0",
- "glob-stream": "^5.3.2",
- "graceful-fs": "^4.0.0",
- "gulp-sourcemaps": "1.6.0",
- "is-valid-glob": "^0.3.0",
- "lazystream": "^1.0.0",
- "lodash.isequal": "^4.0.0",
- "merge-stream": "^1.0.0",
- "mkdirp": "^0.5.0",
- "object-assign": "^4.0.0",
- "readable-stream": "^2.0.4",
- "strip-bom": "^2.0.0",
- "strip-bom-stream": "^1.0.0",
- "through2": "^2.0.0",
- "through2-filter": "^2.0.0",
- "vali-date": "^1.0.0",
- "vinyl": "^1.0.0"
- },
- "dependencies": {
- "clone": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
- "dev": true
- },
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "replace-ext": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
- "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=",
- "dev": true
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- },
- "vinyl": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz",
- "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=",
- "dev": true,
- "requires": {
- "clone": "^1.0.0",
- "clone-stats": "^0.0.1",
- "replace-ext": "0.0.1"
- }
- }
- }
- },
- "vinyl-source-stream": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-1.1.2.tgz",
- "integrity": "sha1-YrU6E1YQqJbpjKlr7jqH8Aio54A=",
- "dev": true,
- "requires": {
- "through2": "^2.0.3",
- "vinyl": "^0.4.3"
- }
- },
- "vinyl-sourcemap": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz",
- "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=",
- "dev": true,
- "requires": {
- "append-buffer": "^1.0.2",
- "convert-source-map": "^1.5.0",
- "graceful-fs": "^4.1.6",
- "normalize-path": "^2.1.1",
- "now-and-later": "^2.0.0",
- "remove-bom-buffer": "^3.0.0",
- "vinyl": "^2.0.0"
- },
- "dependencies": {
- "clone": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
- "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
- "dev": true
- },
- "clone-stats": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
- "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
- "dev": true
- },
- "vinyl": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
- "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
- "dev": true,
- "requires": {
- "clone": "^2.1.1",
- "clone-buffer": "^1.0.0",
- "clone-stats": "^1.0.0",
- "cloneable-readable": "^1.0.0",
- "remove-trailing-separator": "^1.0.1",
- "replace-ext": "^1.0.0"
- }
- }
- }
- },
"vsce": {
"version": "1.37.5",
"resolved": "https://registry.npmjs.org/vsce/-/vsce-1.37.5.tgz",
@@ -3476,48 +851,6 @@
"yazl": "^2.2.2"
}
},
- "vscode": {
- "version": "1.1.10",
- "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.10.tgz",
- "integrity": "sha512-MvFXXSGuhw0Q6GC6dQrnRc0ES+63wpttGIoYGBMQnoS9JFCCNC/rWfX0lBCHJyuKL2Q8CYg0ROsMEHbHVwEtVw==",
- "dev": true,
- "requires": {
- "glob": "^7.1.2",
- "gulp-chmod": "^2.0.0",
- "gulp-filter": "^5.0.1",
- "gulp-gunzip": "1.0.0",
- "gulp-remote-src": "^0.4.3",
- "gulp-symdest": "^1.1.0",
- "gulp-untar": "^0.0.6",
- "gulp-vinyl-zip": "^2.1.0",
- "mocha": "^4.0.1",
- "request": "^2.83.0",
- "semver": "^5.4.1",
- "source-map-support": "^0.5.0",
- "url-parse": "^1.1.9",
- "vinyl-source-stream": "^1.1.0"
- },
- "dependencies": {
- "mocha": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz",
- "integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==",
- "dev": true,
- "requires": {
- "browser-stdout": "1.3.0",
- "commander": "2.11.0",
- "debug": "3.1.0",
- "diff": "3.3.1",
- "escape-string-regexp": "1.0.5",
- "glob": "7.1.2",
- "growl": "1.10.3",
- "he": "1.1.1",
- "mkdirp": "0.5.1",
- "supports-color": "4.4.0"
- }
- }
- }
- },
"vscode-debugadapter": {
"version": "1.27.0",
"resolved": "https://registry.npmjs.org/vscode-debugadapter/-/vscode-debugadapter-1.27.0.tgz",
@@ -3540,6 +873,48 @@
"resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.27.0.tgz",
"integrity": "sha512-cg3lKqVwxNpO2pLBxSwkBvE7w06+bHfbA/s14u8izSWyhJtPgRu1lQwi5tEyTRuwfEugfoPwerYL4vtY6teQDw=="
},
+ "vscode-jsonrpc": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz",
+ "integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg=="
+ },
+ "vscode-languageclient": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-5.2.1.tgz",
+ "integrity": "sha512-7jrS/9WnV0ruqPamN1nE7qCxn0phkH5LjSgSp9h6qoJGoeAKzwKz/PF6M+iGA/aklx4GLZg1prddhEPQtuXI1Q==",
+ "requires": {
+ "semver": "^5.5.0",
+ "vscode-languageserver-protocol": "3.14.1"
+ }
+ },
+ "vscode-languageserver": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-5.2.1.tgz",
+ "integrity": "sha512-GuayqdKZqAwwaCUjDvMTAVRPJOp/SLON3mJ07eGsx/Iq9HjRymhKWztX41rISqDKhHVVyFM+IywICyZDla6U3A==",
+ "requires": {
+ "vscode-languageserver-protocol": "3.14.1",
+ "vscode-uri": "^1.0.6"
+ }
+ },
+ "vscode-languageserver-protocol": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz",
+ "integrity": "sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g==",
+ "requires": {
+ "vscode-jsonrpc": "^4.0.0",
+ "vscode-languageserver-types": "3.14.0"
+ }
+ },
+ "vscode-languageserver-types": {
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz",
+ "integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A=="
+ },
+ "vscode-uri": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.8.tgz",
+ "integrity": "sha512-obtSWTlbJ+a+TFRYGaUumtVwb+InIUVI0Lu0VBUAPmj2cU5JutEXg3xUE0c2J5Tcy7h2DEKVJBFi+Y9ZSFzzPQ=="
+ },
"vso-node-api": {
"version": "6.1.2-preview",
"resolved": "https://registry.npmjs.org/vso-node-api/-/vso-node-api-6.1.2-preview.tgz",
@@ -3558,12 +933,6 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
- "xtend": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
- "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
- "dev": true
- },
"yauzl": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
diff --git a/package.json b/package.json
index ae28c7e..a53ee67 100755
--- a/package.json
+++ b/package.json
@@ -1,9 +1,9 @@
{
"name": "luapanda",
"displayName": "LuaPanda",
- "version": "2.3.0",
+ "version": "3.0.0",
"publisher": "stuartwang",
- "description": "lua debug adapters for VS Code.",
+ "description": "lua debug and code tools for VS Code.",
"author": {
"name": "stuartwang",
"email": "3030078087@qq.com"
@@ -12,17 +12,17 @@
"keywords": [
"lua",
"debug",
- "panda",
"analyzer",
"luaanalyzer"
],
"engines": {
- "vscode": "^1.18.0",
+ "vscode": "^1.25.0",
"node": "^7.9.0"
},
"icon": "images/luapanda_logo.png",
"categories": [
- "Debuggers"
+ "Debuggers",
+ "Programming Languages"
],
"repository": {
"type": "git",
@@ -32,31 +32,36 @@
"url": "https://github.com/Tencent/LuaPanda.git"
},
"scripts": {
- "vscode:prepublish": "tsc -p ./src",
+ "vscode:prepublish": "npm run compile",
"compile": "tsc -p ./src",
+ "watch": "tsc -watch -p ./src",
"package": "vsce package",
- "publish": "vsce package",
- "postinstall": "node ./node_modules/vscode/bin/install"
+ "publish": "vsce package"
},
"dependencies": {
+ "lua-fmt": "^2.6.0",
+ "luaparse": "^0.2.1",
+ "path-reader": "^1.1.0",
+ "urlencode": "^1.1.0",
+ "vscode-languageserver": "^5.2.1",
"await-notify": "1.0.1",
"vscode-debugadapter": "1.27.0",
"vscode-debugprotocol": "1.27.0",
- "path-reader": "^1.1.0"
+ "vscode-languageclient": "^5.2.1"
},
"devDependencies": {
- "@types/node": "7.0.55",
"@types/mocha": "2.2.48",
- "typescript": "2.6.2",
+ "@types/node": "7.0.55",
+ "@types/vscode": "^1.39.0",
"mocha": "5.0.1",
- "vscode": "1.1.10",
- "vscode-debugadapter-testsupport": "1.27.0",
"tslint": "5.9.1",
- "vsce": "1.37.5"
+ "typescript": "2.6.2",
+ "vsce": "1.37.5",
+ "vscode-debugadapter-testsupport": "1.27.0"
},
"main": "./out/extension",
"activationEvents": [
- "onDebug"
+ "*"
],
"contributes": {
"breakpoints": [
@@ -72,13 +77,105 @@
{
"command": "luapanda.LuaGarbageCollect",
"title": "LuaGarbageCollect"
+ },
+ {
+ "command": "luapanda.openSettingsPage",
+ "title": "openSettingsPage"
+ }
+ ],
+ "configuration": {
+ "type": "object",
+ "title": "lua-analyzer configuration",
+ "properties": {
+ "lua_analyzer.codeLinting.enable": {
+ "scope": "resource",
+ "type": "boolean",
+ "default": true,
+ "description": "Enable/Disable code lingting. This is the master switch of code linting."
+ },
+ "lua_analyzer.codeLinting.luacheckPath": {
+ "scope": "resource",
+ "type": "string",
+ "default": "",
+ "description": "The laucheck executable file path, use plugin default config if not set."
+ },
+ "lua_analyzer.codeLinting.luaVersion": {
+ "scope": "resource",
+ "type": "string",
+ "enum": [
+ "5.1",
+ "5.3",
+ "5.1+5.3"
+ ],
+ "default": "5.1+5.3",
+ "description": "Set standard globals for luacheck."
+ },
+ "lua_analyzer.codeLinting.checkWhileTyping": {
+ "scope": "resource",
+ "type": "boolean",
+ "default": true,
+ "description": "Controls wether to check the syntax while typing."
+ },
+ "lua_analyzer.codeLinting.checkAfterSave": {
+ "scope": "resource",
+ "type": "boolean",
+ "default": true,
+ "description": "Controls wether to check the syntax after file saved."
+ },
+ "lua_analyzer.codeLinting.maxNumberOfProblems": {
+ "scope": "resource",
+ "type": "number",
+ "default": 100,
+ "description": "Controls the maximum number of problems produced by the luacheck."
+ },
+ "lua_analyzer.codeLinting.maxLineLength": {
+ "scope": "resource",
+ "type": "number",
+ "default": 120,
+ "description": "Set maximum allowed line length (default: 120)."
+ },
+ "lua_analyzer.codeLinting.ignoreFolderRegularExpression": {
+ "scope": "resource",
+ "type": "string",
+ "default": ".*/res/lua/\\w+\\.lua;",
+ "description": "The regular expressions used to ignore files in some specific folders. Use semicolons to separate different regular expressions."
+ },
+ "lua_analyzer.codeLinting.ignoreErrorCode": {
+ "scope": "resource",
+ "type": "string",
+ "default": "",
+ "description": "Used to ignore some warnings or errors. Use semicolons to separate different error codes. For example, 211 means \"unused local variable\", you will see \"unused variable 'xxx' lua-analyzer(211)\" in the problems window. View https://luacheck.readthedocs.io/en/stable/warnings.html for more information."
+ },
+ "lua_analyzer.codeLinting.ignoreGlobal": {
+ "scope": "resource",
+ "type": "string",
+ "default": "UnityEngine;com",
+ "description": "Used to ignore global variable for luacheck. Use semicolons to separate different variables."
+ },
+ "lua_analyzer.trace.server": {
+ "scope": "window",
+ "type": "string",
+ "enum": [
+ "off",
+ "messages",
+ "verbose"
+ ],
+ "default": "off",
+ "description": "Traces the communication between VS Code and the language server."
+ }
+ }
+ },
+ "snippets": [
+ {
+ "language": "lua",
+ "path": "./res/snippets/snippets.json"
}
],
"debuggers": [
{
"type": "lua",
"label": "LuaPanda",
- "program": "./out/debugAdapter.js",
+ "program": "./out/debug/debugAdapter.js",
"runtime": "node",
"configurationAttributes": {
"launch": {
@@ -174,7 +271,6 @@
"initialConfigurations": [
{
"type": "lua",
- "request": "launch",
"name": "LuaPanda",
"program": "",
"cwd": "${workspaceFolder}",
@@ -187,7 +283,6 @@
},
{
"type": "lua",
- "request": "launch",
"name": "LuaPanda-DebugFile",
"luaPath": "",
"packagePath": [],
diff --git a/res/lua/coroutine.lua b/res/lua/coroutine.lua
new file mode 100755
index 0000000..a2f4d39
--- /dev/null
+++ b/res/lua/coroutine.lua
@@ -0,0 +1,49 @@
+------------------------------------------------------------------------
+-- Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
+--
+-- Permission is hereby granted, free of charge, to any person obtaining
+-- a copy of this software and associated documentation files (the
+-- "Software"), to deal in the Software without restriction, including
+-- without limitation the rights to use, copy, modify, merge, publish,
+-- distribute, sublicense, and/or sell copies of the Software, and to
+-- permit persons to whom the Software is furnished to do so, subject to
+-- the following conditions:
+--
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------
+
+-- Coroutine Manipulation http://www.lua.org/manual/5.3/manual.html#6.2
+-- This library comprises the operations to manipulate coroutines, which come inside the table coroutine. See §2.6 for a general description of coroutines.
+coroutine = {}
+
+-- Creates a new coroutine, with body f. f must be a function. Returns this new coroutine, an object with type "thread".
+function coroutine.create(f) end
+
+-- Returns true when the running coroutine can yield.
+-- A running coroutine is yieldable if it is not the main thread and it is not inside a non-yieldable C function.
+function coroutine.isyieldable() end
+
+-- Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. The values val1, ... are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; the values val1, ... are passed as the results from the yield.
+-- If the coroutine runs without any errors, resume returns true plus any values passed to yield (when the coroutine yields) or any values returned by the body function (when the coroutine terminates). If there is any error, resume returns false plus the error message.
+function coroutine.resume(co, val1, ...) end
+
+-- Returns the running coroutine plus a boolean, true when the running coroutine is the main one.
+function coroutine.running() end
+
+-- Returns the status of coroutine co, as a string: "running", if the coroutine is running (that is, it called status); "suspended", if the coroutine is suspended in a call to yield, or if it has not started running yet; "normal" if the coroutine is active but not running (that is, it has resumed another coroutine); and "dead" if the coroutine has finished its body function, or if it has stopped with an error.
+function coroutine.status(co) end
+
+-- Creates a new coroutine, with body f. f must be a function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. Returns the same values returned by resume, except the first boolean. In case of error, propagates the error.
+function coroutine.wrap(f) end
+
+-- Suspends the execution of the calling coroutine. Any arguments to yield are passed as extra results to resume.
+function coroutine.yield(...) end
diff --git a/res/lua/debug.lua b/res/lua/debug.lua
new file mode 100755
index 0000000..6d1504d
--- /dev/null
+++ b/res/lua/debug.lua
@@ -0,0 +1,92 @@
+------------------------------------------------------------------------
+-- Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
+--
+-- Permission is hereby granted, free of charge, to any person obtaining
+-- a copy of this software and associated documentation files (the
+-- "Software"), to deal in the Software without restriction, including
+-- without limitation the rights to use, copy, modify, merge, publish,
+-- distribute, sublicense, and/or sell copies of the Software, and to
+-- permit persons to whom the Software is furnished to do so, subject to
+-- the following conditions:
+--
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------
+
+--- The Debug Library http://www.lua.org/manual/5.3/manual.html#6.10
+
+-- This library provides the functionality of the debug interface (§4.9) to Lua programs. You should exert care when using this library. Several of its functions violate basic assumptions about Lua code (e.g., that variables local to a function cannot be accessed from outside; that userdata metatables cannot be changed by Lua code; that Lua programs do not crash) and therefore can compromise otherwise secure code. Moreover, some functions in this library may be slow.
+-- All functions in this library are provided inside the debug table. All functions that operate over a thread have an optional first argument which is the thread to operate over. The default is always the current thread.
+debug = {}
+
+-- Enters an interactive mode with the user, running each string that the user enters. Using simple commands and other debug facilities, the user can inspect global and local variables, change their values, evaluate expressions, and so on. A line containing only the word cont finishes this function, so that the caller continues its execution.
+-- Note that commands for debug.debug are not lexically nested within any function and so have no direct access to local variables.
+function debug.debug() end
+
+-- Returns the current hook settings of the thread, as three values: the current hook function, the current hook mask, and the current hook count (as set by the debug.sethook function).
+function debug.gethook(thread) end
+
+-- Returns a table with information about a function. You can give the function directly or you can give a number as the value of f, which means the function running at level f of the call stack of the given thread: level 0 is the current function (getinfo itself); level 1 is the function that called getinfo (except for tail calls, which do not count on the stack); and so on. If f is a number larger than the number of active functions, then getinfo returns nil.
+-- The returned table can contain all the fields returned by lua_getinfo, with the string what describing which fields to fill in. The default for what is to get all information available, except the table of valid lines. If present, the option 'f' adds a field named func with the function itself. If present, the option 'L' adds a field named activelines with the table of valid lines.
+-- For instance, the expression debug.getinfo(1,"n").name returns a name for the current function, if a reasonable name can be found, and the expression debug.getinfo(print) returns a table with all available information about the print function.
+function debug.getinfo(thread, f, what) end
+
+-- This function returns the name and the value of the local variable with index local of the function at level f of the stack. This function accesses not only explicit local variables, but also parameters, temporaries, etc.
+-- The first parameter or local variable has index 1, and so on, following the order that they are declared in the code, counting only the variables that are active in the current scope of the function. Negative indices refer to vararg arguments; -1 is the first vararg argument. The function returns nil if there is no variable with the given index, and raises an error when called with a level out of range. (You can call debug.getinfo to check whether the level is valid.)
+-- Variable names starting with '(' (open parenthesis) represent variables with no known names (internal variables such as loop control variables, and variables from chunks saved without debug information).
+-- The parameter f may also be a function. In that case, getlocal returns only the name of function parameters.
+function debug.getlocal(thread, f, var) end
+
+-- Returns the metatable of the given value or nil if it does not have a metatable.
+function debug.getmetatable(value) end
+
+-- Returns the registry table (see §4.5).
+function debug.getregistry() end
+
+-- This function returns the name and the value of the upvalue with index up of the function f. The function returns nil if there is no upvalue with the given index.
+-- Variable names starting with '(' (open parenthesis) represent variables with no known names (variables from chunks saved without debug information).
+function debug.getupvalue(f, up) end
+
+-- Returns the Lua value associated to u. If u is not a full userdata, returns nil.
+function debug.getuservalue(u, n) end
+
+--Sets the given function as a hook. The string mask and the number count describe when the hook will be called. The string mask may have any combination of the following characters, with the given meaning:
+-- 'c': the hook is called every time Lua calls a function;
+-- 'r': the hook is called every time Lua returns from a function;
+-- 'l': the hook is called every time Lua enters a new line of code.
+-- Moreover, with a count different from zero, the hook is called also after every count instructions.
+-- When called without arguments, debug.sethook turns off the hook.
+-- When the hook is called, its first argument is a string describing the event that has triggered its call: "call" (or "tail call"), "return", "line", and "count". For line events, the hook also gets the new line number as its second parameter. Inside a hook, you can call getinfo with level 2 to get more information about the running function (level 0 is the getinfo function, and level 1 is the hook function).
+function debug.sethook(thread, hook, mask, count) end
+
+-- This function assigns the value value to the local variable with index local of the function at level level of the stack. The function returns nil if there is no local variable with the given index, and raises an error when called with a level out of range. (You can call getinfo to check whether the level is valid.) Otherwise, it returns the name of the local variable.
+-- See debug.getlocal for more information about variable indices and names.
+function debug.setlocal(thread, level, var, value) end
+
+-- Sets the metatable for the given value to the given table (which can be nil). Returns value.
+function debug.setmetatable(value, table) end
+
+-- This function assigns the value value to the upvalue with index up of the function f. The function returns nil if there is no upvalue with the given index. Otherwise, it returns the name of the upvalue.
+function debug.setupvalue(f, up, value) end
+
+-- Sets the given value as the Lua value associated to the given udata. udata must be a full userdata.
+-- Returns udata.
+function debug.setuservalue(udata, value, n) end
+
+-- If message is present but is neither a string nor nil, this function returns message without further processing. Otherwise, it returns a string with a traceback of the call stack. The optional message string is appended at the beginning of the traceback. An optional level number tells at which level to start the traceback (default is 1, the function calling traceback).
+function debug.traceback(thread, message, level) end
+
+-- Returns a unique identifier (as a light userdata) for the upvalue numbered n from the given function.
+-- These unique identifiers allow a program to check whether different closures share upvalues. Lua closures that share an upvalue (that is, that access a same external local variable) will return identical ids for those upvalue indices.
+function debug.upvalueid(f, n) end
+
+-- Make the n1-th upvalue of the Lua closure f1 refer to the n2-th upvalue of the Lua closure f2.
+function debug.upvaluejoin(f1, n1, f2, n2) end
diff --git a/res/lua/global.lua b/res/lua/global.lua
new file mode 100755
index 0000000..fbbc3a6
--- /dev/null
+++ b/res/lua/global.lua
@@ -0,0 +1,123 @@
+------------------------------------------------------------------------
+-- Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
+--
+-- Permission is hereby granted, free of charge, to any person obtaining
+-- a copy of this software and associated documentation files (the
+-- "Software"), to deal in the Software without restriction, including
+-- without limitation the rights to use, copy, modify, merge, publish,
+-- distribute, sublicense, and/or sell copies of the Software, and to
+-- permit persons to whom the Software is furnished to do so, subject to
+-- the following conditions:
+--
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------
+
+-- Basic Functions http://www.lua.org/manual/5.3/manual.html#6.1
+
+-- The basic library provides core functions to Lua. If you do not include this library in your application, you should check carefully whether you need to provide implementations for some of its facilities.
+function assert(v, message) end
+
+-- Calls error if the value of its argument v is false (i.e., nil or false); otherwise, returns all its arguments. In case of error, message is the error object; when absent, it defaults to "assertion failed!"
+function collectgarbage(opt, arg) end
+
+-- Opens the named file and executes its contents as a Lua chunk. When called without arguments, dofile executes the contents of the standard input (stdin). Returns all values returned by the chunk. In case of errors, dofile propagates the error to its caller (that is, dofile does not run in protected mode).
+function dofile(filename) end
+
+-- Terminates the last protected function called and returns message as the error object. Function error never returns.
+-- Usually, error adds some information about the error position at the beginning of the message, if the message is a string. The level argument specifies how to get the error position. With level 1 (the default), the error position is where the error function was called. Level 2 points the error to where the function that called error was called; and so on. Passing a level 0 avoids the addition of error position information to the message.
+function error(message, level) end
+
+-- A global variable (not a function) that holds the global environment (see §2.2). Lua itself does not use this variable; changing its value does not affect any environment, nor vice versa.
+_G = {}
+
+-- If object does not have a metatable, returns nil. Otherwise, if the object's metatable has a __metatable field, returns the associated value. Otherwise, returns the metatable of the given object.
+function getmetatable(object) end
+
+--Returns three values (an iterator function, the table t, and 0) so that the construction
+-- for i,v in ipairs(t) do body end
+-- will iterate over the key–value pairs (1,t[1]), (2,t[2]), ..., up to the first nil value.
+function ipairs(t) end
+
+-- Loads a chunk.
+-- If chunk is a string, the chunk is this string. If chunk is a function, load calls it repeatedly to get the chunk pieces. Each call to chunk must return a string that concatenates with previous results. A return of an empty string, nil, or no value signals the end of the chunk.
+-- If there are no syntactic errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message.
+-- If the resulting function has upvalues, the first upvalue is set to the value of env, if that parameter is given, or to the value of the global environment. Other upvalues are initialized with nil. (When you load a main chunk, the resulting function will always have exactly one upvalue, the _ENV variable (see §2.2). However, when you load a binary chunk created from a function (see string.dump), the resulting function can have an arbitrary number of upvalues.) All upvalues are fresh, that is, they are not shared with any other function.
+-- chunkname is used as the name of the chunk for error messages and debug information (see §4.9). When absent, it defaults to chunk, if chunk is a string, or to "=(load)" otherwise.
+-- The string mode controls whether the chunk can be text or binary (that is, a precompiled chunk). It may be the string "b" (only binary chunks), "t" (only text chunks), or "bt" (both binary and text). The default is "bt".
+-- Lua does not check the consistency of binary chunks. Maliciously crafted binary chunks can crash the interpreter.
+function load(chunk, chunkname, mode, env) end
+
+-- Similar to load, but gets the chunk from file filename or from the standard input, if no file name is given.
+function loadfile(filename, mode, env) end
+
+-- Allows a program to traverse all fields of a table. Its first argument is a table and its second argument is an index in this table. next returns the next index of the table and its associated value. When called with nil as its second argument, next returns an initial index and its associated value. When called with the last index, or with nil in an empty table, next returns nil. If the second argument is absent, then it is interpreted as nil. In particular, you can use next(t) to check whether a table is empty.
+-- The order in which the indices are enumerated is not specified, even for numeric indices. (To traverse a table in numerical order, use a numerical for.)
+-- The behavior of next is undefined if, during the traversal, you assign any value to a non-existent field in the table. You may however modify existing fields. In particular, you may clear existing fields.
+function next(table, index) end
+
+-- If t has a metamethod __pairs, calls it with t as argument and returns the first three results from the call.
+-- Otherwise, returns three values: the next function, the table t, and nil, so that the construction
+-- for k,v in pairs(t) do body end
+-- will iterate over all key–value pairs of table t.
+-- See function next for the caveats of modifying the table during its traversal.
+function pairs(t) end
+
+-- Calls function f with the given arguments in protected mode. This means that any error inside f is not propagated; instead, pcall catches the error and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In such case, pcall also returns all results from the call, after this first result. In case of any error, pcall returns false plus the error message.
+function pcall(f, arg1, ...) end
+
+-- Receives any number of arguments and prints their values to stdout, using the tostring function to convert each argument to a string. print is not intended for formatted output, but only as a quick way to show a value, for instance for debugging. For complete control over the output, use string.format and io.write.
+function print(...) end
+
+-- Checks whether v1 is equal to v2, without invoking the __eq metamethod. Returns a boolean.
+function rawequal(v1, v2) end
+
+-- Gets the real value of table[index], without invoking the __index metamethod. table must be a table; index may be any value.
+function rawget(table, index) end
+
+-- Returns the length of the object v, which must be a table or a string, without invoking the __len metamethod. Returns an integer.
+function rawlen(v) end
+
+-- Sets the real value of table[index] to value, without invoking the __newindex metamethod. table must be a table, index any value different from nil and NaN, and value any Lua value.
+-- This function returns table.
+function rawset(table, index, value) end
+
+-- If index is a number, returns all arguments after argument number index; a negative number indexes from the end (-1 is the last argument). Otherwise, index must be the string "#", and select returns the total number of extra arguments it received.
+function select(index, ...) end
+
+-- Sets the metatable for the given table. (To change the metatable of other types from Lua code, you must use the debug library (§6.10).) If metatable is nil, removes the metatable of the given table. If the original metatable has a __metatable field, raises an error.
+-- This function returns table.
+function setmetatable(table, metatable) end
+
+-- When called with no base, tonumber tries to convert its argument to a number. If the argument is already a number or a string convertible to a number, then tonumber returns this number; otherwise, it returns nil.
+-- The conversion of strings can result in integers or floats, according to the lexical conventions of Lua (see §3.1). (The string may have leading and trailing spaces and a sign.)
+-- When called with base, then e must be a string to be interpreted as an integer numeral in that base. The base may be any integer between 2 and 36, inclusive. In bases above 10, the letter 'A' (in either upper or lower case) represents 10, 'B' represents 11, and so forth, with 'Z' representing 35. If the string e is not a valid numeral in the given base, the function returns nil.
+function tonumber(e, base) end
+
+-- Receives a value of any type and converts it to a string in a human-readable format. (For complete control of how numbers are converted, use string.format.)
+-- If the metatable of v has a __tostring field, then tostring calls the corresponding value with v as argument, and uses the result of the call as its result.
+function tostring(v) end
+
+-- Returns the type of its only argument, coded as a string. The possible results of this function are "nil" (a string, not the value nil), "number", "string", "boolean", "table", "function", "thread", and "userdata".
+function type(v) end
+
+-- A global variable (not a function) that holds a string containing the running Lua version. The current value of this variable is "Lua 5.3".
+_VERSION = "Lua 5.3"
+
+-- This function is similar to pcall, except that it sets a new message handler msgh.
+function xpcall(f, msgh, arg1, ...) end
+
+-- Loads the given module. The function starts by looking into the package.loaded table to determine whether modname is already loaded. If it is, then require returns the value stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.
+-- To find a loader, require is guided by the package.searchers sequence. By changing this sequence, we can change how require looks for a module. The following explanation is based on the default configuration for package.searchers.
+-- First require queries package.preload[modname]. If it has a value, this value (which must be a function) is the loader. Otherwise require searches for a Lua loader using the path stored in package.path. If that also fails, it searches for a C loader using the path stored in package.cpath. If that also fails, it tries an all-in-one loader (see package.searchers).
+-- Once a loader is found, require calls the loader with two arguments: modname and an extra value dependent on how it got the loader. (If the loader came from a file, this extra value is the file name.) If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname]. If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname], then require assigns true to this entry. In any case, require returns the final value of package.loaded[modname].
+-- If there is any error loading or running the module, or if it cannot find any loader for the module, then require raises an error.
+function require(modname) end
\ No newline at end of file
diff --git a/res/lua/io.lua b/res/lua/io.lua
new file mode 100755
index 0000000..11acd88
--- /dev/null
+++ b/res/lua/io.lua
@@ -0,0 +1,124 @@
+------------------------------------------------------------------------
+-- Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
+--
+-- Permission is hereby granted, free of charge, to any person obtaining
+-- a copy of this software and associated documentation files (the
+-- "Software"), to deal in the Software without restriction, including
+-- without limitation the rights to use, copy, modify, merge, publish,
+-- distribute, sublicense, and/or sell copies of the Software, and to
+-- permit persons to whom the Software is furnished to do so, subject to
+-- the following conditions:
+--
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------
+-- Input and Output Facilities http://www.lua.org/manual/5.3/manual.html#6.8
+-- The I/O library provides two different styles for file manipulation. The first one uses implicit file handles; that is, there are operations to set a default input file and a default output file, and all input/output operations are over these default files. The second style uses explicit file handles.
+-- When using implicit file handles, all operations are supplied by table io. When using explicit file handles, the operation io.open returns a file handle and then all operations are supplied as methods of the file handle.
+-- The table io also provides three predefined file handles with their usual meanings from C: io.stdin, io.stdout, and io.stderr. The I/O library never closes these files.
+-- Unless otherwise stated, all I/O functions return nil on failure (plus an error message as a second result and a system-dependent error code as a third result) and some value different from nil on success. In non-POSIX systems, the computation of the error message and error code in case of errors may be not thread safe, because they rely on the global C variable errno.
+
+io = {}
+
+io.stderr = nil
+
+io.stdin = nil
+
+io.stdout = nil
+
+-- Equivalent to file:close(). Without a file, closes the default output file.
+function io.close(file) end
+
+-- Equivalent to io.output():flush().
+function io.flush() end
+
+-- When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. When called with a file handle, it simply sets this file handle as the default input file. When called without arguments, it returns the current default input file.
+-- In case of errors this function raises the error, instead of returning an error code.
+function io.input(file) end
+
+-- Opens the given file name in read mode and returns an iterator function that works like file:lines(···) over the opened file. When the iterator function detects the end of file, it returns no values (to finish the loop) and automatically closes the file.
+-- The call io.lines() (with no file name) is equivalent to io.input():lines("*l"); that is, it iterates over the lines of the default input file. In this case, the iterator does not close the file when the loop ends.
+-- In case of errors this function raises the error, instead of returning an error code.
+function io.lines(filename, ...) end
+
+-- This function opens a file, in the mode specified in the string mode. In case of success, it returns a new file handle.
+-- The mode string can be any of the following:
+-- "r": read mode (the default);
+-- "w": write mode;
+-- "a": append mode;
+-- "r+": update mode, all previous data is preserved;
+-- "w+": update mode, all previous data is erased;
+-- "a+": append update mode, previous data is preserved, writing is only allowed at the end of file.
+-- The mode string can also have a 'b' at the end, which is needed in some systems to open the file in binary mode.
+function io.open(filename, mode) return file end
+
+-- Similar to io.input, but operates over the default output file.
+function io.output(file) end
+
+--This function is system dependent and is not available on all platforms.
+-- Starts program prog in a separated process and returns a file handle that you can use to read data from this program (if mode is "r", the default) or to write data to this program (if mode is "w").
+function io.popen(prog, mode) end
+
+--Equivalent to io.input():read(···).
+function io.read(...) end
+
+-- In case of success, returns a handle for a temporary file. This file is opened in update mode and it is automatically removed when the program ends.
+function io.tmpfile() end
+
+-- Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, or nil if obj is not a file handle.
+function io.type(obj) end
+
+-- Equivalent to io.output():write(···).
+function io.write(...) end
+
+local file = {}
+
+-- Closes file. Note that files are automatically closed when their handles are garbage collected, but that takes an unpredictable amount of time to happen.
+-- When closing a file handle created with io.popen, file:close returns the same values returned by os.execute.
+function file:close() end
+
+-- Saves any written data to file.
+function file:flush() end
+
+-- Returns an iterator function that, each time it is called, reads the file according to the given formats. When no format is given, uses "l" as a default. As an example, the construction
+-- for c in file:lines(1) do body end
+-- will iterate over all characters of the file, starting at the current position. Unlike io.lines, this function does not close the file when the loop ends.
+-- In case of errors this function raises the error, instead of returning an error code.
+function file:lines(...) end
+
+-- Reads the file file, according to the given formats, which specify what to read. For each format, the function returns a string or a number with the characters read, or nil if it cannot read data with the specified format. (In this latter case, the function does not read subsequent formats.) When called without formats, it uses a default format that reads the next line (see below).
+-- The available formats are
+-- "n": reads a numeral and returns it as a float or an integer, following the lexical conventions of Lua. (The numeral may have leading spaces and a sign.) This format always reads the longest input sequence that is a valid prefix for a numeral; if that prefix does not form a valid numeral (e.g., an empty string, "0x", or "3.4e-"), it is discarded and the function returns nil.
+-- "a": reads the whole file, starting at the current position. On end of file, it returns the empty string.
+-- "l": reads the next line skipping the end of line, returning nil on end of file. This is the default format.
+-- "L": reads the next line keeping the end-of-line character (if present), returning nil on end of file.
+-- number: reads a string with up to this number of bytes, returning nil on end of file. If number is zero, it reads nothing and returns an empty string, or nil on end of file.
+-- The formats "l" and "L" should be used only for text files.
+function file:read(...) end
+
+-- Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence, as follows:
+-- "set": base is position 0 (beginning of the file);
+-- "cur": base is current position;
+-- "end": base is end of file;
+-- In case of success, seek returns the final file position, measured in bytes from the beginning of the file. If seek fails, it returns nil, plus a string describing the error.
+-- The default value for whence is "cur", and for offset is 0. Therefore, the call file:seek() returns the current file position, without changing it; the call file:seek("set") sets the position to the beginning of the file (and returns 0); and the call file:seek("end") sets the position to the end of the file, and returns its size.
+function file:seek(whence, offset) end
+
+-- Sets the buffering mode for an output file. There are three available modes:
+-- "no": no buffering; the result of any output operation appears immediately.
+-- "full": full buffering; output operation is performed only when the buffer is full or when you explicitly flush the file (see io.flush).
+-- "line": line buffering; output is buffered until a newline is output or there is any input from some special files (such as a terminal device).
+-- For the last two cases, size specifies the size of the buffer, in bytes. The default is an appropriate size.
+function file:setvbuf(mode, size) end
+
+-- Writes the value of each of its arguments to file. The arguments must be strings or numbers.
+-- In case of success, this function returns file. Otherwise it returns nil plus a string describing the error.
+function file:write(...) end
diff --git a/res/lua/math.lua b/res/lua/math.lua
new file mode 100755
index 0000000..11ab9c6
--- /dev/null
+++ b/res/lua/math.lua
@@ -0,0 +1,109 @@
+------------------------------------------------------------------------
+-- Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
+--
+-- Permission is hereby granted, free of charge, to any person obtaining
+-- a copy of this software and associated documentation files (the
+-- "Software"), to deal in the Software without restriction, including
+-- without limitation the rights to use, copy, modify, merge, publish,
+-- distribute, sublicense, and/or sell copies of the Software, and to
+-- permit persons to whom the Software is furnished to do so, subject to
+-- the following conditions:
+--
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------
+
+-- Mathematical Functions http://www.lua.org/manual/5.3/manual.html#6.7
+-- This library provides basic mathematical functions. It provides all its functions and constants inside the table math. Functions with the annotation "integer/float" give integer results for integer arguments and float results for float (or mixed) arguments. Rounding functions (math.ceil, math.floor, and math.modf) return an integer when the result fits in the range of an integer, or a float otherwise.
+math = {}
+
+-- The value of π.
+math.pi = 3.1415
+
+-- An integer with the minimum value for an integer.
+math.mininteger = nil
+
+-- Returns the absolute value of x. (integer/float)
+function math.abs(x) return 0 end
+
+-- Returns the arc cosine of x (in radians).
+function math.acos(x) return 0 end
+
+-- Returns the arc sine of x (in radians).
+function math.asin(x) return 0 end
+
+-- Returns the arc tangent of y/x (in radians), but uses the signs of both arguments to find the quadrant of the result. (It also handles correctly the case of x being zero.)
+-- The default value for x is 1, so that the call math.atan(y) returns the arc tangent of y.
+function math.atan(y, x) return 0 end
+
+-- Returns the smallest integral value larger than or equal to x.
+function math.ceil(x) return 0 end
+
+-- Returns the cosine of x (assumed to be in radians).
+function math.cos(x) return 0 end
+
+-- Converts the angle x from radians to degrees.
+function math.deg(x) return 0 end
+
+--- Returns the value e^x (where e is the base of natural logarithms).
+function math.exp(x) end
+
+-- Returns the largest integral value smaller than or equal to x.
+function math.floor(x) end
+
+-- Returns the remainder of the division of x by y that rounds the quotient towards zero. (integer/float)
+function math.fmod(x, y) end
+
+-- The float value HUGE_VAL, a value larger than any other numeric value.
+math.huge = nil
+
+-- Returns the logarithm of x in the given base. The default for base is e (so that the function returns the natural logarithm of x).
+function math.log(x, base) end
+
+-- Returns the argument with the maximum value, according to the Lua operator <. (integer/float)
+function math.max(x, ...) end
+
+-- An integer with the maximum value for an integer.
+math.maxinteger = nil
+
+-- Returns the argument with the minimum value, according to the Lua operator <. (integer/float)
+function math.min(x, ...) end
+
+-- Returns the integral part of x and the fractional part of x. Its second result is always a float.
+function math.modf(x) end
+
+-- Converts the angle x from degrees to radians.
+function math.rad(x) end
+
+-- When called without arguments, returns a pseudo-random float with uniform distribution in the range [0,1). When called with two integers m and n, math.random returns a pseudo-random integer with uniform distribution in the range [m, n]. (The value n-m cannot be negative and must fit in a Lua integer.) The call math.random(n) is equivalent to math.random(1,n).
+-- This function is an interface to the underling pseudo-random generator function provided by C.
+function math.random(m, n) end
+
+-- Sets x as the "seed" for the pseudo-random generator: equal seeds produce equal sequences of numbers.
+function math.randomseed(x) end
+
+-- Returns the sine of x (assumed to be in radians).
+function math.sin(x) return 0 end
+
+-- Returns the square root of x. (You can also use the expression x^0.5 to compute this value.)
+function math.sqrt(x) return 0 end
+
+-- Returns the tangent of x (assumed to be in radians).
+function math.tan(x) return 0 end
+
+-- If the value x is convertible to an integer, returns that integer. Otherwise, returns nil.
+function math.tointeger(x) end
+
+-- Returns "integer" if x is an integer, "float" if it is a float, or nil if x is not a number.
+function math.type(x) end
+
+-- Returns a boolean, true if and only if integer m is below integer n when they are compared as unsigned integers.
+function math.ult(m, n) end
\ No newline at end of file
diff --git a/res/lua/os.lua b/res/lua/os.lua
new file mode 100755
index 0000000..632f455
--- /dev/null
+++ b/res/lua/os.lua
@@ -0,0 +1,75 @@
+------------------------------------------------------------------------
+-- Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
+--
+-- Permission is hereby granted, free of charge, to any person obtaining
+-- a copy of this software and associated documentation files (the
+-- "Software"), to deal in the Software without restriction, including
+-- without limitation the rights to use, copy, modify, merge, publish,
+-- distribute, sublicense, and/or sell copies of the Software, and to
+-- permit persons to whom the Software is furnished to do so, subject to
+-- the following conditions:
+--
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------
+
+-- Operating System Facilities http://www.lua.org/manual/5.3/manual.html#pdf-os.clock
+-- This library is implemented through table os.
+os = {}
+
+-- os.clock Returns an approximation of the amount in seconds of CPU time used by the program.
+function os.clock() end
+
+-- os.date Returns a string or a table containing date and time, formatted according to the given string format.
+-- If the time argument is present, this is the time to be formatted (see the os.time function for a description of this value). Otherwise, date formats the current time.
+-- If format starts with '!', then the date is formatted in Coordinated Universal Time. After this optional character, if format is the string "*t", then date returns a table with the following fields: year, month (1–12), day (1–31), hour (0–23), min (0–59), sec (0–61), wday (weekday, 1–7, Sunday is 1), yday (day of the year, 1–366), and isdst (daylight saving flag, a boolean). This last field may be absent if the information is not available.
+-- If format is not "*t", then date returns the date as a string, formatted according to the same rules as the ISO C function strftime.
+-- When called without arguments, date returns a reasonable date and time representation that depends on the host system and on the current locale. (More specifically, os.date() is equivalent to os.date("%c").)
+-- In non-POSIX systems, this function may be not thread safe because of its reliance on C function gmtime and C function localtime.
+function os.date(format, time) end
+
+-- os.difftime Returns the difference, in seconds, from time t1 to time t2 (where the times are values returned by os.time). In POSIX, Windows, and some other systems, this value is exactly t2-t1.
+function os.difftime(t2, t1) end
+
+-- This function is equivalent to the ISO C function system. It passes command to be executed by an operating system shell. Its first result is true if the command terminated successfully, or nil otherwise. After this first result the function returns a string plus a number, as follows:
+-- "exit": the command terminated normally; the following number is the exit status of the command.
+-- "signal": the command was terminated by a signal; the following number is the signal that terminated the command.
+-- When called without a command, os.execute returns a boolean that is true if a shell is available.
+function os.execute(command) end
+
+-- Calls the ISO C function exit to terminate the host program. If code is true, the returned status is EXIT_SUCCESS; if code is false, the returned status is EXIT_FAILURE; if code is a number, the returned status is this number. The default value for code is true.
+-- If the optional second argument close is true, closes the Lua state before exiting.
+function os.exit(code, close) end
+
+-- Returns the value of the process environment variable varname, or nil if the variable is not defined.
+function os.getenv(varname) end
+
+-- Deletes the file (or empty directory, on POSIX systems) with the given name. If this function fails, it returns nil, plus a string describing the error and the error code. Otherwise, it returns true.
+function os.remove(filename) end
+
+-- Renames the file or directory named oldname to newname. If this function fails, it returns nil, plus a string describing the error and the error code. Otherwise, it returns true.
+function os.rename(oldname, newname) end
+
+-- Sets the current locale of the program. locale is a system-dependent string specifying a locale; category is an optional string describing which category to change: "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category is "all". The function returns the name of the new locale, or nil if the request cannot be honored.
+-- If locale is the empty string, the current locale is set to an implementation-defined native locale. If locale is the string "C", the current locale is set to the standard C locale.
+-- When called with nil as the first argument, this function only returns the name of the current locale for the given category.
+-- This function may be not thread safe because of its reliance on C function setlocale.
+function os.setlocale(locale, category) end
+
+-- Returns the current time when called without arguments, or a time representing the local date and time specified by the given table. This table must have fields year, month, and day, and may have fields hour (default is 12), min (default is 0), sec (default is 0), and isdst (default is nil). Other fields are ignored. For a description of these fields, see the os.date function.
+-- The values in these fields do not need to be inside their valid ranges. For instance, if sec is -10, it means -10 seconds from the time specified by the other fields; if hour is 1000, it means +1000 hours from the time specified by the other fields.
+-- The returned value is a number, whose meaning depends on your system. In POSIX, Windows, and some other systems, this number counts the number of seconds since some given start time (the "epoch"). In other systems, the meaning is not specified, and the number returned by time can be used only as an argument to os.date and os.difftime.
+function os.time(table) end
+
+-- Returns a string with a file name that can be used for a temporary file. The file must be explicitly opened before its use and explicitly removed when no longer needed.
+-- In POSIX systems, this function also creates a file with that name, to avoid security risks. (Someone else might create the file with wrong permissions in the time between getting the name and creating the file.) You still have to open the file to use it and to remove it (even if you do not use it).
+-- When possible, you may prefer to use io.tmpfile, which automatically removes the file when the program ends.
+function os.tmpname() end
\ No newline at end of file
diff --git a/res/lua/package.lua b/res/lua/package.lua
new file mode 100755
index 0000000..b61e8de
--- /dev/null
+++ b/res/lua/package.lua
@@ -0,0 +1,77 @@
+------------------------------------------------------------------------
+-- Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
+--
+-- Permission is hereby granted, free of charge, to any person obtaining
+-- a copy of this software and associated documentation files (the
+-- "Software"), to deal in the Software without restriction, including
+-- without limitation the rights to use, copy, modify, merge, publish,
+-- distribute, sublicense, and/or sell copies of the Software, and to
+-- permit persons to whom the Software is furnished to do so, subject to
+-- the following conditions:
+--
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------
+
+-- Modules http://www.lua.org/manual/5.3/manual.html#6.3
+-- The package library provides basic facilities for loading modules in Lua. It exports one function directly in the global environment: require. Everything else is exported in a table package.
+package = {}
+
+-- A string describing some compile-time configurations for packages. This string is a sequence of lines:
+-- The first line is the directory separator string. Default is '\' for Windows and '/' for all other systems.
+-- The second line is the character that separates templates in a path. Default is ';'.
+-- The third line is the string that marks the substitution points in a template. Default is '?'.
+-- The fourth line is a string that, in a path in Windows, is replaced by the executable's directory. Default is '!'.
+-- The fifth line is a mark to ignore all text after it when building the luaopen_ function name. Default is '-'.
+package.config = ""
+
+-- The path used by require to search for a C loader.
+-- Lua initializes the C path package.cpath in the same way it initializes the Lua path package.path, using the environment variable LUA_CPATH_5_3, or the environment variable LUA_CPATH, or a default path defined in luaconf.h.
+package.cpath = ""
+
+-- A table used by require to control which modules are already loaded. When you require a module modname and package.loaded[modname] is not false, require simply returns the value stored there.
+-- This variable is only a reference to the real table; assignments to this variable do not change the table used by require.
+package.loaded = {}
+
+-- Dynamically links the host program with the C library libname.
+-- If funcname is "*", then it only links with the library, making the symbols exported by the library available to other dynamically linked libraries. Otherwise, it looks for a function funcname inside the library and returns this function as a C function. So, funcname must follow the lua_CFunction prototype (see lua_CFunction).
+-- This is a low-level function. It completely bypasses the package and module system. Unlike require, it does not perform any path searching and does not automatically adds extensions. libname must be the complete file name of the C library, including if necessary a path and an extension. funcname must be the exact name exported by the C library (which may depend on the C compiler and linker used).
+-- This function is not supported by Standard C. As such, it is only available on some platforms (Windows, Linux, Mac OS X, Solaris, BSD, plus other Unix systems that support the dlfcn standard).
+function package.loadlib(libname, funcname) end
+
+-- The path used by require to search for a Lua loader.
+-- At start-up, Lua initializes this variable with the value of the environment variable LUA_PATH_5_3 or the environment variable LUA_PATH or with a default path defined in luaconf.h, if those environment variables are not defined. Any ";;" in the value of the environment variable is replaced by the default path.
+package.path = ""
+
+-- A table to store loaders for specific modules (see require).
+-- This variable is only a reference to the real table; assignments to this variable do not change the table used by require.
+package.preload = {}
+
+-- A table used by require to control how to load modules.
+-- Each entry in this table is a searcher function. When looking for a module, require calls each of these searchers in ascending order, with the module name (the argument given to require) as its sole parameter. The function can return another function (the module loader) plus an extra value that will be passed to that loader, or a string explaining why it did not find that module (or nil if it has nothing to say).
+-- Lua initializes this table with four searcher functions.
+-- The first searcher simply looks for a loader in the package.preload table.
+-- The second searcher looks for a loader as a Lua library, using the path stored at package.path. The search is done as described in function package.searchpath.
+-- The third searcher looks for a loader as a C library, using the path given by the variable package.cpath. Again, the search is done as described in function package.searchpath. For instance, if the C path is the string
+-- "./?.so;./?.dll;/usr/local/?/init.so"
+-- the searcher for module foo will try to open the files ./foo.so, ./foo.dll, and /usr/local/foo/init.so, in that order. Once it finds a C library, this searcher first uses a dynamic link facility to link the application with the library. Then it tries to find a C function inside the library to be used as the loader. The name of this C function is the string "luaopen_" concatenated with a copy of the module name where each dot is replaced by an underscore. Moreover, if the module name has a hyphen, its suffix after (and including) the first hyphen is removed. For instance, if the module name is a.b.c-v2.1, the function name will be luaopen_a_b_c.
+-- The fourth searcher tries an all-in-one loader. It searches the C path for a library for the root name of the given module. For instance, when requiring a.b.c, it will search for a C library for a. If found, it looks into it for an open function for the submodule; in our example, that would be luaopen_a_b_c. With this facility, a package can pack several C submodules into one single library, with each submodule keeping its original open function.
+-- All searchers except the first one (preload) return as the extra value the file name where the module was found, as returned by package.searchpath. The first searcher returns no extra value.
+package.searchers = {}
+
+-- Searches for the given name in the given path.
+-- A path is a string containing a sequence of templates separated by semicolons. For each template, the function replaces each interrogation mark (if any) in the template with a copy of name wherein all occurrences of sep (a dot, by default) were replaced by rep (the system's directory separator, by default), and then tries to open the resulting file name.
+-- For instance, if the path is the string
+-- "./?.lua;./?.lc;/usr/local/?/init.lua"
+-- the search for the name foo.a will try to open the files ./foo/a.lua, ./foo/a.lc, and /usr/local/foo/a/init.lua, in that order.
+-- Returns the resulting name of the first file that it can open in read mode (after closing the file), or nil plus an error message if none succeeds. (This error message lists all file names it tried to open.)
+function package.searchpath(name, path, sep, rep) end
+
diff --git a/res/lua/string.lua b/res/lua/string.lua
new file mode 100755
index 0000000..e2c9917
--- /dev/null
+++ b/res/lua/string.lua
@@ -0,0 +1,133 @@
+------------------------------------------------------------------------
+-- Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
+--
+-- Permission is hereby granted, free of charge, to any person obtaining
+-- a copy of this software and associated documentation files (the
+-- "Software"), to deal in the Software without restriction, including
+-- without limitation the rights to use, copy, modify, merge, publish,
+-- distribute, sublicense, and/or sell copies of the Software, and to
+-- permit persons to whom the Software is furnished to do so, subject to
+-- the following conditions:
+--
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------
+
+-- String Manipulation http://www.lua.org/manual/5.3/manual.html#6.4
+-- This library provides generic functions for string manipulation, such as finding and extracting substrings, and pattern matching. When indexing a string in Lua, the first character is at position 1 (not at 0, as in C). Indices are allowed to be negative and are interpreted as indexing backwards, from the end of the string. Thus, the last character is at position -1, and so on.
+-- The string library provides all its functions inside the table string. It also sets a metatable for strings where the __index field points to the string table. Therefore, you can use the string functions in object-oriented style. For instance, string.byte(s,i) can be written as s:byte(i).
+-- The string library assumes one-byte character encodings.
+string = {}
+
+-- Returns the internal numeric codes of the characters s[i], s[i+1], ..., s[j]. The default value for i is 1; the default value for j is i. These indices are corrected following the same rules of function string.sub.
+-- Numeric codes are not necessarily portable across platforms.
+function string.byte(s, i, j) end
+
+-- Receives zero or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numeric code equal to its corresponding argument.
+-- Numeric codes are not necessarily portable across platforms.
+function string.char(...) end
+
+-- Returns a string containing a binary representation (a binary chunk) of the given function, so that a later load on this string returns a copy of the function (but with new upvalues). If strip is a true value, the binary representation may not include all debug information about the function, to save space.
+-- Functions with upvalues have only their number of upvalues saved. When (re)loaded, those upvalues receive fresh instances containing nil. (You can use the debug library to serialize and reload the upvalues of a function in a way adequate to your needs.)
+function string.dump(func, strip) end
+
+-- Looks for the first match of pattern (see §6.4.1) in the string s. If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numeric argument init specifies where to start the search; its default value is 1 and can be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain "find substring" operation, with no characters in pattern being considered magic. Note that if plain is given, then init must be given as well.
+-- If the pattern has captures, then in a successful match the captured values are also returned, after the two indices.
+function string.find(s, pattern, init, plain) end
+
+-- Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the ISO C function sprintf. The only differences are that the options/modifiers *, h, L, l, n, and p are not supported and that there is an extra option, q.
+-- The q option formats a string between double quotes, using escape sequences when necessary to ensure that it can safely be read back by the Lua interpreter. For instance, the call
+-- string.format('%q', 'a string with "quotes" and \n new line')
+-- may produce the string:
+-- "a string with \"quotes\" and \
+-- new line"
+-- Options A, a, E, e, f, G, and g all expect a number as argument. Options c, d, i, o, u, X, and x expect an integer. When Lua is compiled with a C89 compiler, options A and a (hexadecimal floats) do not support any modifier (flags, width, length).
+-- Option s expects a string; if its argument is not a string, it is converted to one following the same rules of tostring. If the option has any modifier (flags, width, length), the string argument should not contain embedded zeros.
+function string.format(formatstring, ...) end
+
+-- Returns an iterator function that, each time it is called, returns the next captures from pattern (see §6.4.1) over the string s. If pattern specifies no captures, then the whole match is produced in each call.
+-- As an example, the following loop will iterate over all the words from string s, printing one per line:
+-- s = "hello world from Lua"
+-- for w in string.gmatch(s, "%a+") do
+-- print(w)
+-- end
+-- The next example collects all pairs key=value from the given string into a table:
+-- t = {}
+-- s = "from=world, to=Lua"
+-- for k, v in string.gmatch(s, "(%w+)=(%w+)") do
+-- t[k] = v
+-- end
+-- For this function, a caret '^' at the start of a pattern does not work as an anchor, as this would prevent the iteration.
+function string.gmatch(s, pattern) end
+
+-- Returns a copy of s in which all (or the first n, if given) occurrences of the pattern (see §6.4.1) have been replaced by a replacement string specified by repl, which can be a string, a table, or a function. gsub also returns, as its second value, the total number of matches that occurred. The name gsub comes from Global SUBstitution.
+-- If repl is a string, then its value is used for replacement. The character % works as an escape character: any sequence in repl of the form %d, with d between 1 and 9, stands for the value of the d-th captured substring. The sequence %0 stands for the whole match. The sequence %% stands for a single %.
+-- If repl is a table, then the table is queried for every match, using the first capture as the key.
+-- If repl is a function, then this function is called every time a match occurs, with all captured substrings passed as arguments, in order.
+-- In any case, if the pattern specifies no captures, then it behaves as if the whole pattern was inside a capture.
+-- If the value returned by the table query or by the function call is a string or a number, then it is used as the replacement string; otherwise, if it is false or nil, then there is no replacement (that is, the original match is kept in the string).
+-- Here are some examples:
+-- x = string.gsub("hello world", "(%w+)", "%1 %1")
+-- --> x="hello hello world world"
+--
+-- x = string.gsub("hello world", "%w+", "%0 %0", 1)
+-- --> x="hello hello world"
+--
+-- x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
+-- --> x="world hello Lua from"
+--
+-- x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
+-- --> x="home = /home/roberto, user = roberto"
+--
+-- x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
+-- return load(s)()
+-- end)
+-- --> x="4+5 = 9"
+--
+-- local t = {name="lua", version="5.3"}
+-- x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
+-- --> x="lua-5.3.tar.gz"
+function string.gsub(s, pattern, repl, n) end
+
+
+-- Receives a string and returns its length. The empty string "" has length 0. Embedded zeros are counted, so "a\000bc\000" has length 5.
+function string.len(s) end
+
+--- Receives a string and returns a copy of this string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale.
+function string.lower(s) end
+
+
+-- Looks for the first match of pattern (see §6.4.1) in the string s. If it finds one, then match returns the captures from the pattern; otherwise it returns nil. If pattern specifies no captures, then the whole match is returned. A third, optional numeric argument init specifies where to start the search; its default value is 1 and can be negative.
+function string.match(s, pattern, init) end
+
+
+-- Returns a binary string containing the values v1, v2, etc. packed (that is, serialized in binary form) according to the format string fmt (see §6.4.2).
+function string.pack(fmt, v1, v2, ...) end
+
+-- Returns the size of a string resulting from string.pack with the given format. The format string cannot have the variable-length options 's' or 'z'
+function string.packsize(fmt) end
+
+-- Returns a string that is the concatenation of n copies of the string s separated by the string sep. The default value for sep is the empty string (that is, no separator). Returns the empty string if n is not positive.
+-- (Note that it is very easy to exhaust the memory of your machine with a single call to this function.)
+function string.rep(s, n, sep) end
+
+-- Returns a string that is the string s reversed.
+function string.reverse(s) end
+
+-- Returns the substring of s that starts at i and continues until j; i and j can be negative. If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s, -i) (for a positive i) returns a suffix of s with length i.
+-- If, after the translation of negative indices, i is less than 1, it is corrected to 1. If j is greater than the string length, it is corrected to that length. If, after these corrections, i is greater than j, the function returns the empty string.
+function string.sub(s, i, j) end
+
+-- Returns the values packed in string s (see string.pack) according to the format string fmt (see §6.4.2). An optional pos marks where to start reading in s (default is 1). After the read values, this function also returns the index of the first unread byte in s.
+function string.unpack(fmt, s, pos) end
+
+-- Receives a string and returns a copy of this string with all lowercase letters changed to uppercase. All other characters are left unchanged. The definition of what a lowercase letter is depends on the current locale.
+function string.upper(s) end
diff --git a/res/lua/table.lua b/res/lua/table.lua
new file mode 100755
index 0000000..a0aea76
--- /dev/null
+++ b/res/lua/table.lua
@@ -0,0 +1,55 @@
+------------------------------------------------------------------------
+-- Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
+--
+-- Permission is hereby granted, free of charge, to any person obtaining
+-- a copy of this software and associated documentation files (the
+-- "Software"), to deal in the Software without restriction, including
+-- without limitation the rights to use, copy, modify, merge, publish,
+-- distribute, sublicense, and/or sell copies of the Software, and to
+-- permit persons to whom the Software is furnished to do so, subject to
+-- the following conditions:
+--
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------
+
+-- Table Manipulation http://www.lua.org/manual/5.3/manual.html#6.6
+-- This library provides generic functions for table manipulation. It provides all its functions inside the table table.
+-- Remember that, whenever an operation needs the length of a table, all caveats about the length operator apply (see §3.4.7). All functions ignore non-numeric keys in the tables given as arguments.
+table = {}
+
+-- Given a list where all elements are strings or numbers, returns the string list[i]..sep..list[i+1] ··· sep..list[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is #list. If i is greater than j, returns the empty string.
+function table.concat(list, sep, i, j) end
+
+-- Inserts element value at position pos in list, shifting up the elements list[pos], list[pos+1], ···, list[#list]. The default value for pos is #list+1, so that a call table.insert(t,x) inserts x at the end of list t.
+function table.insert(list, pos, value) end
+
+
+-- Moves elements from table a1 to table a2, performing the equivalent to the following multiple assignment: a2[t],··· = a1[f],···,a1[e]. The default for a2 is a1. The destination range can overlap with the source range. The number of elements to be moved must fit in a Lua integer.
+-- Returns the destination table a2.
+function table.move(a1, f, e, t, a2) end
+
+-- Returns a new table with all arguments stored into keys 1, 2, etc. and with a field "n" with the total number of arguments. Note that the resulting table may not be a sequence.
+function table.pack(...) end
+
+-- Removes from list the element at position pos, returning the value of the removed element. When pos is an integer between 1 and #list, it shifts down the elements list[pos+1], list[pos+2], ···, list[#list] and erases element list[#list]; The index pos can also be 0 when #list is 0, or #list + 1; in those cases, the function erases the element list[pos].
+-- The default value for pos is #list, so that a call table.remove(l) removes the last element of list l.
+function table.remove(list, pos) end
+
+-- Sorts list elements in a given order, in-place, from list[1] to list[#list]. If comp is given, then it must be a function that receives two list elements and returns true when the first element must come before the second in the final order (so that, after the sort, i < j implies not comp(list[j],list[i])). If comp is not given, then the standard Lua operator < is used instead.
+-- Note that the comp function must define a strict partial order over the elements in the list; that is, it must be asymmetric and transitive. Otherwise, no valid sort may be possible.
+-- The sort algorithm is not stable: elements considered equal by the given order may have their relative positions changed by the sort.
+function table.sort(list, comp) end
+
+-- Returns the elements from the given list. This function is equivalent to
+-- return list[i], list[i+1], ···, list[j]
+-- By default, i is 1 and j is #list.
+function table.unpack(list, i, j) end
diff --git a/res/lua/utf8.lua b/res/lua/utf8.lua
new file mode 100755
index 0000000..d8bbcb4
--- /dev/null
+++ b/res/lua/utf8.lua
@@ -0,0 +1,49 @@
+------------------------------------------------------------------------
+-- Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
+--
+-- Permission is hereby granted, free of charge, to any person obtaining
+-- a copy of this software and associated documentation files (the
+-- "Software"), to deal in the Software without restriction, including
+-- without limitation the rights to use, copy, modify, merge, publish,
+-- distribute, sublicense, and/or sell copies of the Software, and to
+-- permit persons to whom the Software is furnished to do so, subject to
+-- the following conditions:
+--
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------
+
+-- UTF-8 Support http://www.lua.org/manual/5.3/manual.html#6.5
+-- This library provides basic support for UTF-8 encoding. It provides all its functions inside the table utf8. This library does not provide any support for Unicode other than the handling of the encoding. Any operation that needs the meaning of a character, such as character classification, is outside its scope.
+-- Unless stated otherwise, all functions that expect a byte position as a parameter assume that the given position is either the start of a byte sequence or one plus the length of the subject string. As in the string library, negative indices count from the end of the string.
+utf8 = {}
+
+-- The pattern (a string, not a function) "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" (see §6.4.1), which matches exactly one UTF-8 byte sequence, assuming that the subject is a valid UTF-8 string.
+utf8.charpattern = ""
+
+-- Receives zero or more integers, converts each one to its corresponding UTF-8 byte sequence and returns a string with the concatenation of all these sequences.
+function utf8.char(...) end
+
+-- Returns values so that the construction
+-- for p, c in utf8.codes(s) do body end
+-- will iterate over all characters in string s, with p being the position (in bytes) and c the code point of each character. It raises an error if it meets any invalid byte sequence.
+function utf8.codes(s) end
+
+-- Returns the codepoints (as integers) from all characters in s that start between byte position i and j (both included). The default for i is 1 and for j is i. It raises an error if it meets any invalid byte sequence.
+function utf8.codepoint (s, i, j) end
+
+-- Returns the number of UTF-8 characters in string s that start between positions i and j (both inclusive). The default for i is 1 and for j is -1. If it finds any invalid byte sequence, returns a false value plus the position of the first invalid byte.
+function utf8.len(s, i, j) end
+
+-- Returns the position (in bytes) where the encoding of the n-th character of s (counting from position i) starts. A negative n gets characters before position i. The default for i is 1 when n is non-negative and #s + 1 otherwise, so that utf8.offset(s, -n) gets the offset of the n-th character from the end of the string. If the specified character is neither in the subject nor right after its end, the function returns nil.
+-- As a special case, when n is 0 the function returns the start of the encoding of the character that contains the i-th byte of s.
+-- This function assumes that s is a valid UTF-8 string.
+function utf8.offset (s, n, i) end
diff --git a/res/others/launch.json b/res/others/launch.json
new file mode 100644
index 0000000..1320e9e
--- /dev/null
+++ b/res/others/launch.json
@@ -0,0 +1,30 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "lua",
+ "request": "launch",
+ "name": "LuaPanda",
+ "cwd": "${workspaceFolder}",
+ "luaFileExtension": "lua",
+ "connectionPort": 8818,
+ "pathCaseSensitivity": true,
+ "stopOnEntry": true,
+ "useCHook": true,
+ "autoPathMode": false,
+ "logLevel": 1,
+ },
+ {
+ "type": "lua",
+ "request": "launch",
+ "name": "LuaPanda-DebugFile",
+ "luaPath": "",
+ "packagePath": [],
+ "luaFileExtension": "",
+ "connectionPort": 8818,
+ "stopOnEntry": true,
+ "useCHook": true,
+ "logLevel": 1
+ }
+ ]
+}
\ No newline at end of file
diff --git a/res/snippets/snippets.json b/res/snippets/snippets.json
new file mode 100755
index 0000000..068dfa9
--- /dev/null
+++ b/res/snippets/snippets.json
@@ -0,0 +1,99 @@
+{
+ "local": {
+ "prefix": "local",
+ "body": "local ${1:var} = ${0:nil}",
+ "description": "local variable = ..."
+ },
+ "if": {
+ "prefix": "if",
+ "body": "if ${1:condition} then\n\t${0:-- body}\nend",
+ "description": "if"
+ },
+ "else if": {
+ "prefix": "else if",
+ "body": "else if ${1:condition} then\n\t${0:-- body}",
+ "description": "else if"
+ },
+ "else": {
+ "prefix": "else",
+ "body": "else\n\t${0:-- body}",
+ "description": "else"
+ },
+ "for": {
+ "prefix": "for",
+ "body": "for ${1:index} = ${2:1}, ${3:10} do\n\t${0:-- body}\nend",
+ "description": "for index = 1, n do end"
+ },
+ "fori": {
+ "prefix": "for index, value in ipairs",
+ "body": "for ${1:index}, ${2:value} in ipairs(${3:Table}) do\n\t${0:-- body}\nend",
+ "description": "for index, value in ipairs(table) do end"
+ },
+ "forp": {
+ "prefix": "for key, value in pairs",
+ "body": "for ${1:key}, ${2:value} in pairs(${3:Table}) do\n\t${0:-- body}\nend",
+ "description": "for key, value in pairs(table) do end"
+ },
+ "do": {
+ "prefix": "do",
+ "body": "do\n\t${0:-- body}\nend",
+ "description": "do"
+ },
+ "while": {
+ "prefix": "while",
+ "body": "while ${1:condition} do\n\t${0:-- body}\nend",
+ "description": "while"
+ },
+ "repeat": {
+ "prefix": "repeat",
+ "body": "repeat\n\t${0:-- body}\nuntil ${1:condition}",
+ "description": "repeat"
+ },
+ "local function": {
+ "prefix": "local function",
+ "body": "local function ${1:func}(${2:})\n\t${0:-- body}\nend",
+ "description": "local function"
+ },
+ "function": {
+ "prefix": "function",
+ "body": "function ${1:func}(${2:})\n\t${0:-- body}\nend",
+ "description": "function"
+ },
+ "require": {
+ "prefix": "require",
+ "body": "require (\"${1:}\")\n${0:}",
+ "description": "function"
+ } ,
+ "true": {
+ "prefix": "true",
+ "body": "true"
+ },
+ "false": {
+ "prefix": "false",
+ "body": "false"
+ },
+ "nil": {
+ "prefix": "nil",
+ "body": "nil"
+ } ,
+ "and": {
+ "prefix": "and",
+ "body": "and"
+ },
+ "or": {
+ "prefix": "or",
+ "body": "or"
+ },
+ "not": {
+ "prefix": "not",
+ "body": "not"
+ },
+ "end": {
+ "prefix": "end",
+ "body": "end"
+ },
+ "then": {
+ "prefix": "then",
+ "body": "then"
+ }
+}
\ No newline at end of file
diff --git a/res/web/settings.html b/res/web/settings.html
new file mode 100644
index 0000000..5f4a36f
--- /dev/null
+++ b/res/web/settings.html
@@ -0,0 +1,249 @@
+
+
+
+
+
+
+ LuaPanda Setting
+
+
+
+
+ LuaPanda Settings
+ LuaPanda on github
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/code/server/codeCompleting.ts b/src/code/server/codeCompleting.ts
new file mode 100644
index 0000000..3a1726c
--- /dev/null
+++ b/src/code/server/codeCompleting.ts
@@ -0,0 +1,401 @@
+// 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.
+
+import { CodeEditor } from './codeEditor';
+import * as Tools from "./codeTools";
+import {
+ CompletionItem,
+ CompletionItemKind,
+ InsertTextFormat,
+ Position
+} from 'vscode-languageserver';
+// import { Logger } from './codeLogManager';
+import { CodeSymbol } from "./codeSymbol";
+import { CodeDefinition } from './codeDefinition';
+import { TypeInfer } from './typeInfer';
+
+export class CodeCompleting {
+ private static maxSearchLen = 100; //类型搜索时处理的最大数量
+ private static replaceDic; //记录用作替换的searchName ,保证搜索的tag最后能转回用户输入
+ private static alreadychkSymbol; //记录搜索过的关键字,防止循环搜索
+
+ private static fmtParamToSnippet(paramArray: string[]): string {
+ let snippet = '(' + paramArray.map((param, i) => `\${${i + 1}:${param}}`).join(', ') + ')';
+ return snippet;
+ }
+
+ private static getDocCommentInsertText(functionName: string, paramArray: string[]): string {
+ let docCommentSnippet = " " + functionName + " ${1:Description of the function}";
+
+ let maxParamLength = 0;
+ paramArray.forEach((param) => {
+ maxParamLength = Math.max(maxParamLength, param.length);
+ });
+
+ let i = 2;
+ paramArray.forEach((param) => {
+ param += Tools.getNSpace(maxParamLength - param.length);
+ docCommentSnippet += `\n-- @param ${param} \${${i++}:Describe the parameter}`;
+ });
+
+ return docCommentSnippet;
+ }
+
+ private static getDocCommentCompletingItem(uri: string, line: number): CompletionItem {
+ let functionInfo = CodeDefinition.getFunctionInfoByLine(uri, line);
+ if (functionInfo.functionName == "") {
+ return null;
+ }
+
+ let completeItem = {
+ label: functionInfo.functionName + " doc comment",
+ kind: CompletionItemKind.Snippet,
+ insertText: this.getDocCommentInsertText(functionInfo.functionName, functionInfo.functionParam),
+ detail: "Write some document comments for the function.",
+ insertTextFormat: InsertTextFormat.Snippet
+ };
+ return completeItem;
+ }
+
+ //把字符串按. 或者 : 分割成数组。若不含: . 则数组中只有一个元素
+ private static splitStringwithTrigger(str){
+ let userInputTxt_DotToBlank = str.replace(/[\.:]/g, ' ');
+ let userInputArr = userInputTxt_DotToBlank.split(' ');
+ return userInputArr;
+ }
+
+ // 根据tag类型修改查找值
+ private static searchTag( addElement, prefix, completingArray, uri) {
+ // 防止循环搜索
+ if(this.alreadychkSymbol[addElement.searchName]){
+ return;
+ }
+ this.alreadychkSymbol[addElement.searchName] = true;
+
+ //若 retSymb[idx] 有tag
+ let searchName = addElement.searchName ;
+ if(addElement.tagReason == Tools.TagReason.UserTag || addElement.tagReason == Tools.TagReason.Equal){
+ // 用户标记 / 等号标记
+ searchName = addElement.tagType;
+ this.realSearchTag(addElement, prefix, completingArray, uri, searchName)
+ }
+
+ if(addElement.tagReason == Tools.TagReason.MetaTable){
+ //元表标记
+ searchName = addElement.tagType + ".__index";
+ this.realSearchTag(addElement, prefix, completingArray, uri, searchName);
+ }
+
+ // 符号 = 文件返回值
+ if(addElement.requireFile && addElement.requireFile.length > 0){
+ let uri = Tools.transFileNameToUri(addElement.requireFile);
+ let retTag = CodeSymbol.getCertainDocReturnValue(uri);//类似于使用@type得到的类型
+ if(retTag && retTag.length > 0){
+ searchName = retTag;
+ }
+ this.realSearchTag(addElement, prefix, completingArray, uri, searchName);
+ }
+
+ //函数返回值
+ if(addElement.funcRets){
+ searchName = addElement.funcRets.name;
+ this.realSearchTag(addElement, prefix, completingArray, uri, searchName, true);
+ }
+ }
+
+ // 真正做tag查找的位置
+ private static realSearchTag(addElement, prefix, completingArray, uri, searchName, isAllowNoPrefixEQ?) {
+ let finalInsertText;
+ //如果有tagtype, 再去符号表中查找tagtype
+ let tagSearchRetSymb;
+ if( addElement.requireFile ){
+ //含有引用 tag,只搜索引用文件的符号
+ let uri = Tools.transFileNameToUri( addElement.requireFile );
+ tagSearchRetSymb = CodeSymbol.searchSymbolinDoc(uri, searchName, Tools.SearchMode.FirstLetterContinuousMatching);
+ }else if(addElement.funcRets){
+ //含有func 返回,搜索对应函数
+ let funcSearchRet = CodeSymbol.searchAllSymbolinRequireTreeforCompleting( uri , searchName, Tools.SearchMode.ExactlyEqual);
+ let retName = ''
+ for (let index = 0; index < funcSearchRet.length; index++) {
+ const element = funcSearchRet[index];
+ if( element['chunk'] && element['chunk']['returnSymbol']){
+ retName = element['chunk']['returnSymbol'];
+ break;
+ }
+ }
+
+ tagSearchRetSymb = CodeSymbol.searchSymbolinDoc(uri, retName, Tools.SearchMode.FirstLetterContinuousMatching);
+ if(tagSearchRetSymb && tagSearchRetSymb.length > 0){
+ searchName = retName;
+ }
+
+ }else{
+ tagSearchRetSymb = CodeSymbol.searchGlobalInRequireTree(searchName, uri, Tools.SearchMode.FirstLetterContinuousMatching );
+ }
+ if( !tagSearchRetSymb || tagSearchRetSymb.length < 1 ){
+ //当直接替换tag查不到的时候,用一次类型推导
+ tagSearchRetSymb = TypeInfer.processCompleting(searchName, uri);
+ if(tagSearchRetSymb && tagSearchRetSymb.length > 0){
+ //记录做了哪些替换,以便补回来
+ this.replaceDic[tagSearchRetSymb[0].searchName] = addElement.searchName;
+ searchName = tagSearchRetSymb[0].searchName;
+ //再做一次搜索
+ tagSearchRetSymb = CodeSymbol.searchGlobalInRequireTree(tagSearchRetSymb[0].searchName , uri, Tools.SearchMode.FirstLetterContinuousMatching );
+ }else{
+ // tag 符号没有查到,类型推导也没有找到。
+ return;
+ }
+ }
+
+ let srarchLen = tagSearchRetSymb.length;
+ if(tagSearchRetSymb.length > this.maxSearchLen){
+ srarchLen = this.maxSearchLen;
+ }
+
+ //遍历tag的搜索结果。这里的结果通过FirstLetterContinuousMatching搜索出来的。
+ //这里要做的工作就是。替换tag,替换用户prefix, 删除searchprefab
+ for (let j = 0; j < srarchLen; j++) {
+ //替换tag
+ const element = tagSearchRetSymb[j];
+ let SCHName = element.searchName;
+
+ if(searchName != addElement.searchName){
+ this.replaceDic[searchName] = addElement.searchName;
+ }
+ let ecee = addElement.searchName
+ while(this.replaceDic[ecee]){
+ if(this.replaceDic[ecee] == ecee) break;
+ ecee = this.replaceDic[ecee];
+ }
+ SCHName = SCHName.replace(searchName, ecee);
+ //替换用户prefix
+ let reg = new RegExp( /[\.:]/, 'g')
+ let prefix_dot = prefix.replace( reg , '[\.:]' );
+ let prefix_dot_list = prefix_dot.split('[\.:]');
+ prefix_dot_list.pop();
+ prefix_dot_list.push('');
+ prefix_dot = prefix_dot_list.join('[\.:]');
+ // 如果搜索到的匹配项无法覆盖用户输入,去除
+ let matRes = SCHName.match(RegExp( prefix_dot, 'i'));
+ if(matRes){
+ finalInsertText = SCHName.replace(RegExp( prefix_dot, 'i'), '');
+ }else{
+ // 未能匹配到用户输入. 性能消耗大,暂时去掉
+
+ //此时不代表有错误,比如函数的返回值一类
+ this.searchTag(element, prefix, completingArray, uri)
+
+ if(isAllowNoPrefixEQ){
+ finalInsertText = SCHName;
+ }else{
+ continue;
+ }
+ }
+
+ let reasionString;
+ if(addElement.tagReason == Tools.TagReason.UserTag){
+ reasionString = "---@type " + addElement.searchName + " = " + searchName;
+ }
+ if(addElement.tagReason == Tools.TagReason.MetaTable){
+ reasionString = "setmetatable(" + addElement.searchName + " , " + searchName + ")";
+ }
+
+ let completeKind : CompletionItemKind
+
+ let InsText = finalInsertText;
+ switch(element.kind){
+ case 12:
+ completeKind = CompletionItemKind.Function;
+ InsText = finalInsertText + this.fmtParamToSnippet(element.funcParamArray);
+ reasionString = element.name;
+ break;
+ default:
+ completeKind = CompletionItemKind.Text;
+ }
+
+ let completeItem = {
+ label: finalInsertText,
+ kind: completeKind,
+ insertText: InsText,
+ detail : reasionString, // 这里写明是元表还是标记
+ insertTextFormat: InsertTextFormat.Snippet
+ }
+ if(completeItem.label == undefined){
+ completeItem.label = "error undefined!";
+ }else{
+ completingArray.push(completeItem);
+ }
+ }
+ }
+
+ // 获取补全提示数组
+ public static getCompletingArray(uri : string, pos: Position): CompletionItem[]{
+ let completingArray = new Array();
+ let luaText = CodeEditor.getCode(uri);
+ // 取出用户输入的字符串
+ let prefix = Tools.getTextByPosition(luaText , pos);
+ // 文档注释
+ if (prefix == "---") {
+ if (Tools.isNextLineHasFunction(luaText, pos) == false) {
+ return completingArray;
+ }
+ completingArray.push(this.getDocCommentCompletingItem(uri, pos.line + 1));
+ return completingArray;
+ }
+
+ //prefix是用户输入的信息。searchPrefix替换用户的输入,用于FirstLetterContinuousMatching搜索
+ // 比如 local ff = aa, 用户输入ff.的时候,直接查是查不到的
+ //
+ let searchPrefix = prefix;
+ //判断用户输入是否含有分隔符
+ let userInputArr = this.splitStringwithTrigger(prefix);
+ let tagResSplitByBlank;
+ //有分隔符时
+ if (userInputArr && userInputArr.length > 1){
+ //因为tag是精确搜索,所以要把最后一项未写完的部分去掉。比如 aa.bb.c(未写完) => aa.bb
+ userInputArr.pop();
+ //进行tag搜索
+ let offlastprefix = userInputArr.join('.');
+ let tagResArr =TypeInfer.processCompleting(offlastprefix ,uri);
+
+ //搜到了tag
+ if( tagResArr && tagResArr.length > 0 ){
+ tagResSplitByBlank = tagResArr[0].searchName.replace(/[\.:]/g, ' ').split(' '); //把. 和 :转为空格
+ let L1 = userInputArr.length -1 ; //用户输入
+ let L2 = tagResSplitByBlank.length - 1; //tag搜索
+ while(L1 >=0 && L2>=0){
+ if(userInputArr[L1] == tagResSplitByBlank[L2]){
+ L1 --;
+ L2 --;
+ userInputArr.pop();
+ tagResSplitByBlank.pop();
+ }else{
+ break;
+ }
+ }
+
+ //替换掉后面用于FirstLetterContinuousMatching搜索的值。因为
+ // aa = {bb = { cc = {dd = 9}}}
+ // local ffffff = aa
+ // ffffff.bb.cc 会搜出来 aa.bb
+ searchPrefix = tagResArr[0].searchName;
+ }
+ }
+
+ //无分隔符
+ //在符号中搜索prefix开头的符号,组成提示内容。
+ let retSymb = CodeSymbol.searchAllSymbolinRequireTreeforCompleting(uri, searchPrefix, Tools.SearchMode.FirstLetterContinuousMatching);
+ if(!retSymb) return;
+ let srarchLen = retSymb.length;
+
+ for(let idx = 0 ; idx < srarchLen; idx ++){
+ if( !retSymb[idx] ) continue; //有错误
+ let finalInsertText; //最终的提示字符串
+ if(retSymb[idx].searchName != searchPrefix ){
+ //用户输入信息 < 当前搜索到的Symbol,把当前符号也加入补全列表
+ finalInsertText = retSymb[idx].searchName;
+ }
+ //搜索结果10以内才使用 类型推导,否则会卡顿
+ if( srarchLen < this.maxSearchLen && (retSymb[idx].tagType || retSymb[idx].requireFile || retSymb[idx].funcRets) ){
+ //如果当前搜索结果有tag,搜索一次tag
+ this.alreadychkSymbol = new Object();
+ this.replaceDic = new Object();
+ this.searchTag(retSymb[idx], prefix, completingArray, uri)
+ }else{
+ // retSymb[idx] 当前项目没有tag。
+ // 判断用户输入的前缀有没有. 如果没有不需要做[前缀替换] 和 [tag替换]
+ if(prefix.match(/[\.:]/)){
+ try{
+ //tag 替换
+ let beReplaceStr = retSymb[idx].searchName;
+ let beReplStr = tagResSplitByBlank.join('.');
+ let replStr = userInputArr.join('.');
+ beReplaceStr = beReplaceStr.replace(beReplStr, replStr);
+ //前缀替换
+ let reg = new RegExp( /[\.:]/, 'g')
+ let prefix_dot = prefix.replace( reg , '[\.:]' );
+ let prefix_dot_list = prefix_dot.split('[\.:]');
+ prefix_dot_list.pop(); //把最后一位去掉
+ prefix_dot_list.push('');
+ prefix_dot = prefix_dot_list.join('[\.:]');
+ // 用户已输入的前缀剔除
+ let matRes = beReplaceStr.match(RegExp( prefix_dot, 'i'));
+ if(matRes){
+ finalInsertText = beReplaceStr.replace(RegExp( prefix_dot, 'i'), '');
+ }else{
+ continue;
+ }
+ }catch{
+ finalInsertText = retSymb[idx].originalName;
+ }
+ }else{
+ //没有"." 不需要做[用户输入前缀替换]。使用搜索出来的searchName作为最终的结果
+ finalInsertText = retSymb[idx].searchName;
+ }
+ }
+
+ let completeKind : CompletionItemKind
+ let labelTxt = finalInsertText;
+ switch(retSymb[idx].kind){
+ case 12:
+ completeKind = CompletionItemKind.Function;
+ finalInsertText = finalInsertText + this.fmtParamToSnippet(retSymb[idx].funcParamArray);
+ break;
+ default:
+ completeKind = CompletionItemKind.Text;
+ }
+
+ let completeItem = {
+ label: labelTxt,
+ kind: completeKind,
+ insertText: finalInsertText,
+ detail : retSymb[idx].name,
+ insertTextFormat: InsertTextFormat.Snippet
+ }
+ if(completeItem.label == undefined){
+ completeItem.label = "error undefined!";
+ }else{
+ completingArray.push(completeItem);
+ }
+ }
+
+ // 符号去重
+ let retCompleteItem = this.completeItemDuplicateRemoval(completingArray);
+ return retCompleteItem;
+ }
+
+
+ //消除重复的符号
+ private static completeItemDuplicateRemoval(completingArray){
+ let retCompItemList = new Array();
+ for (let index = 0; index < completingArray.length; index++) {
+ let DuplicateFlag = false;
+ const completeItem = completingArray[index];
+ for (let retIdx = 0, len = retCompItemList.length; retIdx < len; retIdx++) {
+ if( this.ItemIsEq( completeItem, retCompItemList[retIdx] ) ){
+ DuplicateFlag = true;
+ break;
+ }
+ }
+ if(! DuplicateFlag ){
+ retCompItemList.push(completeItem);
+ }
+ }
+ return retCompItemList;
+ }
+
+ //判断CompleteItem是否相等
+ private static ItemIsEq(item1, item2):boolean{
+ if(item1.label === item2.label &&
+ item1.kind === item2.kind &&
+ item1.insertText === item2.insertText &&
+ item1.insertTextFormat === item2.insertTextFormat ){
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/src/code/server/codeDefinition.ts b/src/code/server/codeDefinition.ts
new file mode 100644
index 0000000..8f650c2
--- /dev/null
+++ b/src/code/server/codeDefinition.ts
@@ -0,0 +1,182 @@
+// 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.
+
+import {
+ Location,
+ TextDocumentPositionParams,
+ SymbolKind
+} from 'vscode-languageserver';
+import { Logger } from './codeLogManager';
+import { CodeSymbol } from "./codeSymbol";
+import { TypeInfer } from "./typeInfer"
+import * as Tools from "./codeTools";
+
+//查找定义的主函数
+export class CodeDefinition {
+ public static getSymbalDefine(info: TextDocumentPositionParams, isRetSymbol?) {
+ isRetSymbol = isRetSymbol || false;
+ Tools.transPosStartLineTo1(info.position);
+ //获取指定文件的doc信息容器
+ let uri = info.textDocument.uri;
+ let astContainer = CodeSymbol.docSymbolMap.get(uri);
+ if(!astContainer){
+ Logger.InfoLog("[Error] getSymbalDefine can’t find AST");
+ return null;
+ }
+ // 根据VSCode提供的符号位置查询查号名
+ let symbRet = astContainer.searchDocSymbolfromPosition(info.position);
+ //全局查找定义
+ if (symbRet != undefined && symbRet['sybinfo'] != undefined) {
+ let symbolInfo = symbRet['sybinfo'];
+ let containerList = symbRet['container'];
+ let symbInstance = TypeInfer.processDefineSymbolTag(symbolInfo, uri); // 查找定义
+ if(!symbInstance || symbInstance.length == 0) return; // 未能查到定义
+ Tools.transPosStartLineTo0(info.position);
+ if(symbolInfo.isLocal){
+ // 同级优先,上方最近
+ symbInstance = this.judgeLocalDefinition(symbInstance, containerList, info);
+ }else{
+ // 最远原则
+ symbInstance = symbInstance[symbInstance.length - 1];
+ }
+
+ // 此处应该保证 symbInstance是一个实例(不是数组)
+ if( !symbInstance ) return; //没找到,或过滤后没有适合的符号
+ if(isRetSymbol) return symbInstance; //回传符号,而不是位置信息
+ let retLoc = Location.create(symbInstance.containerURI, symbInstance.location.range);
+ return retLoc;
+ } else {
+ //没找到符号,判断require文件的情况
+ let reqFileName = astContainer.searchDocRequireFileNameFromPosition(info.position);
+ let uri = Tools.transFileNameToUri(reqFileName);
+ if(uri.length > 0){
+ return Tools.createEmptyLocation(uri);
+ }
+ return;
+ }
+ }
+
+
+//-----------------------------------------------------------------------------
+//-- 局部变量的处理
+//-----------------------------------------------------------------------------
+ // 得到了多个 symbInstance,要判断那个是目标。 这个函数只处理局部变量,全局变量按照引用树只搜索出一个结果,无需判断
+ // @symbArray match的symb数组
+ // @findoutSymbols 找到的定义信息
+ // @containerList 被查找信息的深度
+ // @docPosition vscode获取的位置
+ //函数要求,可能传入1到多个符号,返回最符合的1个符号. 先比较container , 查出所有本层/上层定义,之后找同层最近的,没有则向上
+ private static judgeLocalDefinition(findoutSymbols, containerList, docPosition) {
+ // let userClickLine = docPosition.position.line;
+ if( !findoutSymbols || findoutSymbols.length <= 0 || !docPosition || !containerList || containerList.length <= 0) return;
+
+
+ if(findoutSymbols.length == 1) return findoutSymbols[0];
+ //查出所有findoutSymbols的共同深度,数字越大共同深度越多,不在一个chunk中是-1
+ let commonDepth = this.findCommonDepth(containerList, findoutSymbols);
+ //找出共同深度最大值
+ let maxComDep = 0; //最大相同深度
+ for (let index = 0; index < commonDepth.length; index++) {
+ if (maxComDep < commonDepth[index]){
+ maxComDep = commonDepth[index];
+ }
+ }
+
+ let maxArray = new Array();
+ for (let index = 0; index < commonDepth.length; index++) {
+ if (maxComDep == commonDepth[index]){
+ maxArray.push(findoutSymbols[index]);
+ }
+ }
+ //此时maxArray中记录了共同深度最大的符号
+ if(maxArray.length == 1){
+ return maxArray[0];
+ }
+ //findUpNearestSymbol 的作用是寻找line在上方并最近的符号
+ return this.findUpNearestSymbol(docPosition.position, maxArray);
+ }
+
+ //查找上方最近的符号
+ public static findUpNearestSymbol(docPosition, maxArray){
+ let distanceLineNumber = new Array();
+ let standardLine = docPosition.line;
+ // 使用standardLine - upLine得到符号差值,这个值如果为负,忽略。
+ // 差值越小离得越近
+ for (const key in maxArray) {
+ const element = maxArray[key];
+ let upLine = element.location.range.start.line;
+ distanceLineNumber[key] = standardLine - upLine; //数值越小越好
+ }
+
+ //寻找最小差值
+ let minComDep = 99999;
+ for (let index = 0; index < distanceLineNumber.length; index++) {
+ if (distanceLineNumber[index] < minComDep && distanceLineNumber[index] >= 0){
+ minComDep = distanceLineNumber[index];
+ }
+ }
+
+ let minSymbolIdx;
+ for (let index = 0; index < distanceLineNumber.length; index++) {
+ if (minComDep == distanceLineNumber[index]){
+ minSymbolIdx = index;
+ break;
+ }
+ }
+
+ return maxArray[minSymbolIdx];
+ }
+
+ //查找符号的共同深度 , 当不在同一个chunk时返回-1 , 数字表示相同的chunk数
+ //standradDepth被查找的符号深度
+ //beFindSymbolList找到的定义深度
+ public static findCommonDepth( standradDepth , beFindSymbolList){
+ let retArray = new Array();
+
+ //评估各个符号和标准深度的相同深度
+ for (const key in beFindSymbolList) {
+ const element = beFindSymbolList[key];
+
+ //定义深度 > 被查找元素深度
+ if (standradDepth.length < element.containerList.length) {
+ retArray[key] = -1;
+ continue;
+ }
+ //遍历一个具体的待查找深度
+ for (let index = 0; index < standradDepth.length; index++) {
+ let standardChunk = standradDepth[index];
+ let beAnalyzeDepth = element.containerList[index];
+ if (standardChunk && beAnalyzeDepth &&standardChunk.chunkName == beAnalyzeDepth.chunkName && standardChunk.loc.start.line == beAnalyzeDepth.loc.start.line && standardChunk.loc.end.line == beAnalyzeDepth.loc.end.line){
+ retArray[key] = index + 1;
+ }else{
+ if(standardChunk && !beAnalyzeDepth){
+
+ }else{
+ retArray[key] = -1;
+ }
+ }
+ }
+ }
+ //如果有多个最大值,对比
+ return retArray;
+ }
+
+
+ // 按行号查询function
+ public static getFunctionInfoByLine(uri: string, line: number): { functionName: string, functionParam: string[] } {
+ let displaySymbolArray = CodeSymbol.getCertainDocSymbolsReturnArray(uri, null, Tools.SearchRange.AllSymbols);
+ let result = { functionName: "", functionParam: [] };
+ for (const key in displaySymbolArray) {
+ const docDisplaySymbol = displaySymbolArray[key];
+ if (docDisplaySymbol.kind == SymbolKind.Function && docDisplaySymbol.location.range.start.line == line) {
+ result.functionName = docDisplaySymbol.searchName;
+ result.functionParam = docDisplaySymbol.funcParamArray;
+ return result;
+ }
+ }
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/src/code/server/codeEditor.ts b/src/code/server/codeEditor.ts
new file mode 100644
index 0000000..e16473b
--- /dev/null
+++ b/src/code/server/codeEditor.ts
@@ -0,0 +1,30 @@
+// 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.
+
+import * as Tools from './codeTools';
+import { Logger } from './codeLogManager';
+
+// 保存Editor中的代码
+export class CodeEditor {
+ public static codeInEditor = new Map();
+
+ public static saveCode( uri : string , text : string) {
+ this.codeInEditor[uri] = text;
+ }
+
+ public static getCode( uri : string ): string {
+ if(this.codeInEditor[uri]){
+ return this.codeInEditor[uri];
+ }else{
+ let luatxt = Tools.getFileContent(Tools.uriToPath(uri));
+ if(!luatxt){
+ Logger.InfoLog("[Error] getCode can’t get file content. uri:" + uri);
+ return;
+ }
+ return luatxt;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/code/server/codeHighlight.ts b/src/code/server/codeHighlight.ts
new file mode 100644
index 0000000..77d07bd
--- /dev/null
+++ b/src/code/server/codeHighlight.ts
@@ -0,0 +1 @@
+//代码高亮
\ No newline at end of file
diff --git a/src/code/server/codeLinting.ts b/src/code/server/codeLinting.ts
new file mode 100644
index 0000000..11aa6bc
--- /dev/null
+++ b/src/code/server/codeLinting.ts
@@ -0,0 +1,137 @@
+// 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.
+
+// 语法检查
+import {
+ TextDocument,
+ // Connection,
+ DiagnosticSeverity,
+ Diagnostic,
+ Range
+} from 'vscode-languageserver';
+import * as Tools from "./codeTools";
+import { LuaAnalyzerSettings } from "./server";
+import { spawnSync } from 'child_process';
+
+let os = require('os');
+
+export class CodeLinting {
+ static luacheckResultRegExp = /^(.+):(\d+):(\d+)-(\d+): \(([EW])(\d+)\) (.+)$/;
+ public static processLinting(textDocument: TextDocument, settings: LuaAnalyzerSettings, globalVariables: string[]): Promise<{}> {
+ let fileName = Tools.uriToPath(Tools.urlDecode(textDocument.uri));
+ let luacheck: string = this.getLuacheck(settings);
+ let luacheckArgs: string[] = this.getLuacheckArgs(settings, fileName, globalVariables);
+ let fileContent = textDocument.getText();
+ let luacheckProcess = new Promise((resolve, reject) => {
+ let checkResult = spawnSync(luacheck, luacheckArgs, {input: fileContent});
+ // luacheck 错误码1或2表示检查到error或warning
+ if (checkResult.status == 1 || checkResult.status == 2) {
+ reject(checkResult.output.join('\n'));
+ }
+ else if (checkResult.status == 0) {
+ resolve();
+ }
+ else {
+ // error log
+ resolve();
+ }
+ });
+ return luacheckProcess;
+ }
+
+ private static getLuacheck(settings: LuaAnalyzerSettings): string {
+ let luacheck: string = settings.codeLinting.luacheckPath;
+ if ( luacheck != "") {
+ return luacheck;
+ }
+
+ // 如果用户未配置则使用默认配置
+ if (os.type() == "Windows_NT") {
+ luacheck = __dirname + "/../thirdparty/luacheck.exe";
+ }
+ else {
+ luacheck = '/usr/local/bin/luacheck';
+ }
+ return luacheck;
+ }
+
+ private static getLuacheckArgs(settings: LuaAnalyzerSettings, fileName: string, globalVariables: string[]): string[] {
+ let luacheckArgs: string[] = [];
+
+ let luaVersion = settings.codeLinting.luaVersion;
+ switch (luaVersion) {
+ case "5.1":
+ luacheckArgs.push("--std", "lua51");
+ break;
+ case "5.3":
+ luacheckArgs.push("--std", "lua53");
+ break;
+ case "5.1+5.3":
+ luacheckArgs.push("--std", "lua51+lua53");
+ break;
+ default:
+ }
+ let userIgnoreGlobals: string[] = settings.codeLinting.ignoreGlobal.split(";");
+ let ignoreGlobals: string[] = userIgnoreGlobals.concat(globalVariables);
+ if (ignoreGlobals.length > 0) {
+ luacheckArgs.push("--globals", ...ignoreGlobals);
+ }
+ let maxLineLength = settings.codeLinting.maxLineLength;
+ luacheckArgs.push("--max-line-length", maxLineLength.toString());
+ luacheckArgs.push("--allow-defined");
+ luacheckArgs.push("--ranges");
+ luacheckArgs.push("--codes");
+ luacheckArgs.push("--formatter", "plain");
+ luacheckArgs.push("--filename", fileName);
+ luacheckArgs.push("-");
+ return luacheckArgs;
+ }
+
+ public static parseLuacheckResult(luaErrorOrWarning, settings: LuaAnalyzerSettings) {
+ let diagnosticArray: Diagnostic[] = [];
+
+ // if (luaErrorOrWarning.stdout === undefined) {
+ // return diagnosticArray;
+ // }
+
+ let maxNumberOfProblems = settings.codeLinting.maxNumberOfProblems;
+ let ignoreErrorCode: string[] = settings.codeLinting.ignoreErrorCode.split(";");
+ const luaErrorOrWarningArray: string[] = luaErrorOrWarning.split(/\r\n|\r|\n/);
+ for (let i = 0, problems = 0; i < luaErrorOrWarningArray.length && problems < maxNumberOfProblems; i++) {
+ let regResult = this.luacheckResultRegExp.exec(luaErrorOrWarningArray[i]);
+ if (!regResult) {
+ continue;
+ }
+
+ let line = parseInt(regResult[2]);
+ let startCharacter = parseInt(regResult[3]);
+ let endCharacter = parseInt(regResult[4]);
+ let errorType = regResult[5];
+ let severity = errorType == "E"? DiagnosticSeverity.Error : DiagnosticSeverity.Warning;
+ let errorCode = parseInt(regResult[6]);
+ let message = regResult[7];
+ let range = Range.create(line - 1, startCharacter - 1, line - 1, endCharacter);
+
+ // 根据错误码忽略错误提示。luacheck ignore参数不能忽略error
+ if (ignoreErrorCode.includes(errorCode.toString())) {
+ continue;
+ }
+
+ let diagnosic: Diagnostic = {
+ range : range,
+ severity: severity,
+ code : errorCode,
+ message : message,
+ source : "lua-analyzer"
+ };
+
+ problems++;
+ diagnosticArray.push(diagnosic);
+ }
+
+ return diagnosticArray;
+ }
+}
diff --git a/src/code/server/codeLogManager.ts b/src/code/server/codeLogManager.ts
new file mode 100644
index 0000000..790048e
--- /dev/null
+++ b/src/code/server/codeLogManager.ts
@@ -0,0 +1,49 @@
+// 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.
+
+export enum LogLevel{
+ DEBUG = 0,
+ INFO = 1 ,
+ ERROR = 2,
+ RELEASE = 3
+}
+export class Logger {
+ public static currentLevel = LogLevel.DEBUG;
+ public static connection;
+ public static init() {
+ }
+
+ public static log(str: string, level?) {
+ if(! level){
+ level = LogLevel.DEBUG;
+ }
+
+ if (str != "" && str != null) {
+ if(level == LogLevel.ERROR) this.ErrorLog(str);
+ if(level == LogLevel.INFO) this.InfoLog(str);
+ if(level == LogLevel.DEBUG) this.DebugLog(str);
+ }
+ }
+
+ public static DebugLog(str: string){
+ if( this.currentLevel <= LogLevel.DEBUG){
+ this.connection.console.log(str);
+ }
+ }
+
+ public static InfoLog(str: string){
+ if( this.currentLevel <= LogLevel.INFO){
+ this.connection.console.log(str);
+ }
+ }
+
+ public static ErrorLog(str: string){
+ if( this.currentLevel <= LogLevel.ERROR){
+ this.connection.console.log(str);
+ }
+ }
+
+}
diff --git a/src/code/server/codeReference.ts b/src/code/server/codeReference.ts
new file mode 100644
index 0000000..5a5430b
--- /dev/null
+++ b/src/code/server/codeReference.ts
@@ -0,0 +1,27 @@
+//查找引用
+// import * as Tools from "./codeTools";
+import { CodeSymbol } from "./codeSymbol";
+// import { Logger } from './codeLogManager';
+import { CodeDefinition } from './codeDefinition';
+// import {
+// Location
+// } from 'vscode-languageserver-protocol';
+
+export class CodeReference {
+ public static getSymbalReferences(info){
+ let refRet = new Array()
+ // 此处getDefine应该直接搜索
+ let def = CodeDefinition.getSymbalDefine(info, true);
+
+ let findDocRes = CodeSymbol.searchSymbolReferenceinDoc(def);
+ refRet.concat(findDocRes);
+ //形式转换
+ for (let index = 0; index < findDocRes.length; index++) {
+ findDocRes[index].range.start.line = findDocRes[index].range.start.line -1;
+ findDocRes[index].range.start.character = findDocRes[index].range.start.column;
+ findDocRes[index].range.end.line = findDocRes[index].range.end.line -1;
+ findDocRes[index].range.end.character = findDocRes[index].range.end.column;
+ }
+ return findDocRes;
+ }
+}
\ No newline at end of file
diff --git a/src/code/server/codeSymbol.ts b/src/code/server/codeSymbol.ts
new file mode 100644
index 0000000..9c786e9
--- /dev/null
+++ b/src/code/server/codeSymbol.ts
@@ -0,0 +1,479 @@
+// 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.
+
+//创建并管理文件中的符号
+import * as Tools from './codeTools';
+import { CodeEditor } from './codeEditor';
+import { DocSymbolProcesser } from './docSymbolProcesser';
+import { Logger } from './codeLogManager';
+
+export class CodeSymbol {
+ // 用 kv 结构保存所有用户文件以及对应符号结构(包含定义符号和AST,以及方法)
+ public static docSymbolMap = new Map();
+ // 用 kv 结构保存所有预置文件以及对应符号结构(包含定义符号和AST,以及方法)
+ public static preLoadSymbolMap = new Map();
+ // 已处理文件列表,这里是防止循环引用
+ private static alreadyProcessFile;
+
+//-----------------------------------------------------------------------------
+//-- 创建单文件、工作区、预加载区、特定文件符号
+//-----------------------------------------------------------------------------
+ // 单文件内符号处理
+ // 指定文件的符号 [单文件创建] | 无返回 . 如文档的符号已建立则直接返回
+ public static createCertainDocSymbols(uri: string, luaText?: string) {
+ if ( ! this.docSymbolMap.has(uri)) {
+ this.refreshCertainDocSymbols(uri, luaText);
+ }
+ }
+
+ // 指定文件的符号 [单文件刷新] | 无返回, 强制刷新
+ public static refreshCertainDocSymbols(uri: string, luaText?: string) {
+ if(luaText == undefined){
+ luaText = CodeEditor.getCode(uri);
+ }
+ this.createDocSymbals(uri, luaText);
+ }
+
+ // 获取指定文件的所有符号 , 并返回Array形式
+ public static getCertainDocSymbolsReturnArray(uri: string, luaText?: string, range?:Tools.SearchRange): Tools.SymbolInformation[] {
+ let docSymbals: Tools.SymbolInformation[] = [];
+ this.createCertainDocSymbols(uri, luaText);
+ switch(range){
+ case Tools.SearchRange.GlobalSymbols:
+ docSymbals = this.docSymbolMap.get(uri).getGlobalSymbolsArray(); break;
+ case Tools.SearchRange.LocalSymbols:
+ docSymbals = this.docSymbolMap.get(uri).getLocalSymbolsArray(); break;
+ case Tools.SearchRange.AllSymbols:
+ docSymbals = this.docSymbolMap.get(uri).getAllSymbolsArray(); break;
+ }
+ return docSymbals;
+ }
+
+ // 获取指定文件的所有符号 , 并返回Dictionary形式
+ public static getCertainDocSymbolsReturnDic(uri: string, luaText?: string, range?:Tools.SearchRange): Tools.SymbolInformation[] {
+ let docSymbals: Tools.SymbolInformation[] = [];
+ this.createCertainDocSymbols(uri, luaText);
+ switch(range){
+ case Tools.SearchRange.GlobalSymbols:
+ docSymbals = this.docSymbolMap.get(uri).getGlobalSymbolsDic(); break;
+ case Tools.SearchRange.LocalSymbols:
+ docSymbals = this.docSymbolMap.get(uri).getLocalSymbolsDic(); break;
+ case Tools.SearchRange.AllSymbols:
+ docSymbals = this.docSymbolMap.get(uri).getAllSymbolsDic(); break;
+ }
+ return docSymbals;
+ }
+
+ // 获取指定文件的返回值,如无返回null
+ public static getCertainDocReturnValue(uri):string{
+ let docSymbals = this.docSymbolMap.get(uri);
+ if(docSymbals)
+ return docSymbals.getFileReturnArray();
+ else
+ return null;
+ }
+
+ // 指定文件夹中的符号处理
+ // 创建指定文件夹中所有文件的符号 [批量创建]
+ public static createFolderDocSymbols(path: string){
+ if(path === undefined || path === ''){
+ return;
+ }
+ let filesArray = Tools.getDirFiles( path );
+ filesArray.forEach(pathArray => {
+ let uri = Tools.pathToUri(pathArray);
+ if(!this.docSymbolMap.has(uri)){
+ this.createDocSymbals( uri , pathArray );
+ }
+ });
+ }
+
+ // 刷新指定文件夹中所有文件的符号 [批量刷新]
+ public static refreshFolderDocSymbols(path: string){
+ if(path === undefined || path === ''){
+ return;
+ }
+ let filesArray = Tools.getDirFiles( path );
+ filesArray.forEach(element => {
+ this.createDocSymbals( element );
+ });
+ }
+
+ // 刷新 PreLoad 所有文件的符号 [PreLoad批量刷新]
+ public static refreshPreLoadSymbals(path: string){
+ if(path === undefined || path === ''){
+ return;
+ }
+ let filesArray = Tools.getDirFiles( path );
+ filesArray.forEach(pathElement => {
+ this.createPreLoadSymbals( Tools.pathToUri(pathElement), pathElement );
+ });
+ }
+
+ // 获取 workspace 中的全局符号, 以dictionary的形式返回
+ public static getWorkspaceSymbols(range? : Tools.SearchRange){
+ range = range || Tools.SearchRange.AllSymbols;
+ let filesMap = Tools.get_FileName_Uri_Cache();
+ let g_symb = {};
+
+ for (const fileUri in filesMap) {
+ let g_s = this.getCertainDocSymbolsReturnDic( filesMap[fileUri], null, range);
+ for (const key in g_s) {
+ const element = g_s[key];
+ g_symb[key] = element;
+ }
+ }
+
+ return g_symb;
+ }
+
+ // 获取Require文件中的全局符号(本文件引用的其他文件), 以dictionary的形式返回
+ public static getRequireTreeGlobalSymbols(uri: string){
+ if(uri === undefined || uri === ''){
+ return;
+ }
+
+ let fileList = this.getRequireTreeList(uri);
+ let g_symb = {};
+ for (let index = 0; index < fileList.length; index++) {
+ let g_s = this.getCertainDocSymbolsReturnDic( fileList[index], null, Tools.SearchRange.GlobalSymbols);
+ for (const key in g_s) {
+ const element = g_s[key];
+ g_symb[key] = element;
+ }
+ }
+ return g_symb;
+ }
+
+ //reference处理
+ public static searchSymbolReferenceinDoc(searchSymbol) {
+ let uri = searchSymbol.containerURI;
+ let docSymbals = this.docSymbolMap.get(uri);
+ return docSymbals.searchDocSymbolReference(searchSymbol);
+ }
+
+
+//-----------------------------------------------------------------------------
+//-- 搜索符号
+//-----------------------------------------------------------------------------
+ // 在[工作空间]查找符号(模糊匹配,用作搜索符号)
+ public static searchSymbolinWorkSpace(symbolStr: string, searchMethod: Tools.SearchMode, searchRange?: Tools.SearchRange): Tools.SymbolInformation[] {
+ if (symbolStr === '') {
+ return null;
+ } else {
+ let retSymbols: Tools.SymbolInformation[] = [];
+ for (let [ , value] of this.docSymbolMap) {
+ let docSymbals = value.searchMatchSymbal(symbolStr, searchMethod, searchRange);
+ let preS = this.searchPreLoadSymbols(symbolStr, searchMethod);
+ retSymbols = retSymbols.concat(docSymbals);
+ retSymbols = retSymbols.concat(preS);
+ }
+ return retSymbols;
+ }
+ }
+
+ //在[指定文件]查找符号(模糊匹配,用作搜索符号)
+ // @return 返回值得到的排序:
+ // 如果是Equal搜索,从dic中检索,按照AST深度遍历顺序返回
+ public static searchSymbolinDoc(uri:string, symbolStr: string, searchMethod: Tools.SearchMode, range?:Tools.SearchRange): Tools.SymbolInformation[] {
+ if (symbolStr === '' || uri === '' ) {
+ return null;
+ }
+ let docSymbals = this.docSymbolMap.get(uri);
+ let retSymbols = docSymbals.searchMatchSymbal(symbolStr, searchMethod, range);
+ return retSymbols;
+ }
+
+ // 在[本文件引用的其他文件]上搜索所有符合的符号,用于 [代码提示 auto completion]
+ public static searchAllSymbolinRequireTreeforCompleting (uri:string, symbolStr: string, searchMethod: Tools.SearchMode): Tools.SymbolInformation[] {
+ if (symbolStr === '' || uri === '' ) {
+ return null;
+ }
+ //用户 > 系统
+ CodeSymbol.alreadyProcessFile = new Object();
+ let retS = this.recursiveSearchRequireTree(uri, symbolStr, searchMethod);
+ let preS = this.searchPreLoadSymbols(symbolStr, searchMethod);
+ if(retS){
+ retS = retS.concat(preS);
+ }else{
+ retS = preS;
+ }
+ Logger.log("ret len = "+ retS.length);
+ return retS;
+ }
+
+ /**
+ * 向上遍历引用树,搜索全局变量定义(引用本文件的文件) | 这个方法主要适用于在引用树上查找全局变量
+ * 搜索的原则为在引用树上优先搜索最近的定义,即先搜本文件,然后逆序搜索require的文件,再逆序搜索reference
+ * @param symbolInfo 要搜索的符号名
+ * @param uri 查找的文件
+ * @param searchedFiles 标记已经搜索过的文件,上层调用该方法时可以不传
+ * @return 搜索结果,SymbolInformation数组
+ */
+ public static searchGlobalInRequireTree(symbolName: string, uri: string , searchMethod: Tools.SearchMode , searchedFiles?: Map): Tools.SymbolInformation[] {
+ if (searchedFiles == undefined) {
+ searchedFiles = new Map();
+ }
+ let result: Tools.SymbolInformation[] = new Array();
+
+ // uri为空直接返回
+ if (uri == "") {
+ return result;
+ }
+
+ // 判断文件是否已搜索过
+ if (searchedFiles.get(uri) == true) {
+ return result;
+ }
+ // 在单个文件中搜索全局变量
+ let docSymbol = this.docSymbolMap.get(uri);
+ let searchResult = docSymbol.searchMatchSymbal(symbolName, searchMethod, Tools.SearchRange.GlobalSymbols);
+ result = result.concat(searchResult);
+ searchedFiles.set(uri, true);
+
+ let requireFiles = this.docSymbolMap.get(uri).getRequiresArray();
+ let references = this.docSymbolMap.get(uri).getReferencesArray();
+
+ // 搜索的原则为在引用树上优先搜索最近的定义,即先搜本文件,然后逆序搜索require的文件,再逆序搜索reference
+ // 搜索require的文件
+ for (let i = requireFiles.length - 1; i >= 0; i--) {
+ let searchResult = this.searchGlobalInRequireTree(symbolName, Tools.transFileNameToUri(requireFiles[i].reqName), searchMethod, searchedFiles);
+ result = result.concat(searchResult);
+ }
+ // 搜索require本文件的文件(references)
+ for (let i = references.length - 1; i >= 0; i--) {
+ let searchResult = this.searchGlobalInRequireTree(symbolName, references[i], searchMethod, searchedFiles);
+ result = result.concat(searchResult);
+ }
+
+ return result;
+ }
+
+ //在预制文档中搜索
+ public static searchPreLoadSymbols(symbolStr, searchMethod){
+ let retSymbols = new Array();
+ this.preLoadSymbolMap.forEach(element => {
+ let res = element.searchMatchSymbal(symbolStr, searchMethod, Tools.SearchRange.AllSymbols);
+ retSymbols = retSymbols.concat(res);
+ });
+ return retSymbols;
+ }
+
+ //查找符合某一深度的符号
+ public static selectSymbolinCertainContainer(symbolList, containerList){
+ if(!symbolList) return;
+ let retSymoblList = new Array();
+ for (let index = 0; index < symbolList.length; index++) {
+ const symbol = symbolList[index];
+ if(symbol.containerList.length == containerList.length){
+ for (let containerIdx = 0; containerIdx < containerList.length; containerIdx++) {
+ if(containerList[containerIdx] != symbol.containerList[containerIdx]){
+ //出现层级不相等
+ break;
+ }
+ if(containerIdx == containerList.length - 1){
+ //深度相等
+ retSymoblList.push(symbol);
+ }
+ }
+ }
+ }
+ return retSymoblList;
+ }
+//-----------------------------------------------------------------------------
+//-- 私有方法
+//-----------------------------------------------------------------------------
+
+ /**
+ * 重新分析文件后,根据require的文件的变动,更新本文件require的文件的reference,保留本文件的reference
+ * @param oldDocSymbol 上一次的docSymbol
+ * @param newDocSymbol 本次更新之后的docSymbol
+ */
+ private static updateReference(oldDocSymbol: DocSymbolProcesser, newDocSymbol: DocSymbolProcesser) {
+ if (!oldDocSymbol) {
+ // 初次处理无需更新
+ return;
+ }
+ // 保留本文件的reference(create的时候会被清空)
+ newDocSymbol.setReferences(oldDocSymbol.getReferencesArray());
+
+ let lastRequireFileArray = oldDocSymbol.getRequiresArray();
+ let currentRequireFiles = newDocSymbol.getRequiresArray();
+
+ // 以下requireFile的含义均为本文件require的其他文件
+ lastRequireFileArray.forEach((lastRequireFile) => {
+ // 本次代码改动删除之前的require语句,需要删除对应的reference关系
+ let needDeleteReference = true;
+ currentRequireFiles.forEach((currentRequireFile) => {
+ if (currentRequireFile.reqName == lastRequireFile.reqName) {
+ needDeleteReference = false;
+ return;
+ }
+ });
+ if (needDeleteReference) {
+ let lastRequireFileUri = Tools.transFileNameToUri(lastRequireFile.reqName);
+ let lastRequireFileDocSymbol = this.docSymbolMap.get(lastRequireFileUri);
+ let lastRequireFileReference = lastRequireFileDocSymbol.getReferencesArray();
+ let index = lastRequireFileReference.indexOf(newDocSymbol.getUri());
+ // 删除本文件require的文件对本文件的reference
+ lastRequireFileReference.splice(index, 1);
+ }
+ });
+ }
+ // 创建某个lua文件的符号
+ // @uri 文件uri
+ // @text 文件内容
+ private static createDocSymbals(uri: string, luaText?: string): Tools.SymbolInformation[] {
+ if(uri == null) return null;
+ if (luaText == undefined) {
+ luaText = Tools.getFileContent(Tools.uriToPath(uri));
+ }
+ let oldDocSymbol = this.docSymbolMap.get(uri);
+ let docSymbol: DocSymbolProcesser = DocSymbolProcesser.create(luaText, uri);
+ if(docSymbol){
+ if( !docSymbol.parseError){
+ //解析无误
+ this.docSymbolMap.set(uri, docSymbol);
+ this.updateReference(oldDocSymbol, docSymbol);
+ }else{
+ //解析过程有误
+ if ( !this.docSymbolMap.get(uri) ){
+ //map中还未解析过这个table
+ this.docSymbolMap.set(uri, docSymbol);
+ }else{
+ //map中已有
+ let oldLen = this.docSymbolMap.get(uri).getAllSymbolsArray().length;
+ let newLen = docSymbol.getAllSymbolsArray().length;
+ if (newLen > oldLen){
+ this.docSymbolMap.set(uri, docSymbol);
+ this.updateReference(oldDocSymbol, docSymbol);
+ }
+ }
+ }
+ }else{
+ return null;
+ }
+ }
+
+ // 创建前置搜索文件的所有符号
+ // @uri 文件uri
+ // @text 文件内容
+ private static createPreLoadSymbals(uri: string, path?:string){
+ if(!path){
+ path = Tools.uriToPath(uri);
+ }
+ let luaText = Tools.getFileContent(path);
+ let docSymbol: DocSymbolProcesser = DocSymbolProcesser.create(luaText, uri, path);
+ this.preLoadSymbolMap.set(uri, docSymbol);
+ }
+
+ // 获取某个文件的引用树列表
+ private static getRequireTreeList(uri: string){
+ if(uri === undefined || uri === ''){
+ return;
+ }
+
+ function recursiveGetRequireTreeList(uri: string, fileList: string[]){
+ if(uri === undefined || uri === ''){
+ return;
+ }
+ // 如果 uri 的符号列表不存在,创建
+ if (!CodeSymbol.docSymbolMap.has(uri)) {
+ Logger.log("createDocSymbals : "+ uri);
+ let luaText = CodeEditor.getCode(uri);
+ CodeSymbol.createDocSymbals(uri, luaText);
+ }
+
+ //如果uri所在文件存在错误,则无法创建成功。这里docProcesser == null
+ let docProcesser = CodeSymbol.docSymbolMap.get(uri);
+ if(docProcesser == null || docProcesser.getRequiresArray == null){
+ Logger.log("get docProcesser or getRequireFiles error!");
+ return;
+ }
+
+ //当前文件已经在递归处理过了
+ if(alreadyProcessFile[uri] == 1){
+ return;
+ }else{
+ alreadyProcessFile[uri] = 1;
+ }
+
+ let reqFiles = docProcesser.getRequiresArray();
+ for(let idx = 0, len = reqFiles.length ; idx < len ; idx++ ){
+ let newuri = Tools.transFileNameToUri(reqFiles[idx]['reqName'])
+ recursiveGetRequireTreeList(newuri, fileList);
+ }
+ fileList.push(uri);
+ return fileList;
+ }
+
+ let fileList = new Array();
+ let alreadyProcessFile = new Object(); //防止循环引用
+ recursiveGetRequireTreeList(uri, fileList);
+ return fileList;
+ }
+
+ // 递归搜索 引用树,查找符号
+ // @fileName 文件名
+ // @symbolStr 符号名
+ // @uri
+ private static recursiveSearchRequireTree(uri: string, symbolStr, searchMethod :Tools.SearchMode){
+ if(uri === undefined || uri === ''){
+ return;
+ }
+
+ let retSymbArray = new Array();
+ //如果 uri 的符号列表不存在,创建
+ if (!this.docSymbolMap.has(uri)) {
+ Logger.log("createDocSymbals : "+ uri);
+ let luaText = CodeEditor.getCode(uri);
+ this.createDocSymbals(uri, luaText);
+ }
+ //开始递归
+ //如果uri所在文件存在错误,则无法创建成功。这里docProcesser == null
+ let docProcesser = this.docSymbolMap.get(uri);
+ if(docProcesser == null || docProcesser.getRequiresArray == null){
+ Logger.log("get docProcesser or getRequireFiles error!");
+ return;
+ }
+
+ //当前文件已经在递归处理中了
+ if(this.alreadyProcessFile[uri] == 1){
+ return;
+ }else{
+ this.alreadyProcessFile[uri] = 1;
+ }
+
+ Logger.log("recursiveSearchRequireTree process :" + uri);
+ // 在引用树上搜索符号,搜索的原则为优先搜索最近的定义,即先搜本文件,然后逆序搜索require的文件,再逆序搜索reference
+ // 分析自身文件的符号. 本文件,要查找所有符号,引用文件,仅查找global符号。这里要求符号分析分清楚局部和全局符号
+ let docS = this.docSymbolMap.get(uri);
+ let retSymbols = docS.searchMatchSymbal(symbolStr, searchMethod, Tools.SearchRange.AllSymbols);
+ if(retSymbols.length > 0){
+ //找到了,查找全部符号,压入数组
+ retSymbArray = retSymbArray.concat(retSymbols);
+ }
+ // 逆序搜索require
+ let reqFiles = docProcesser.getRequiresArray();
+ for(let idx = reqFiles.length -1; idx >= 0; idx--){
+ let newuri = Tools.transFileNameToUri(reqFiles[idx]['reqName']);
+ let retSymbols = this.recursiveSearchRequireTree(newuri, symbolStr, searchMethod);
+ if(retSymbols != null && retSymbols.length > 0){
+ retSymbArray = retSymbArray.concat(retSymbols);
+ }
+ }
+ // 逆序搜索reference
+ let refFiles = docProcesser.getReferencesArray();
+ for(let idx = refFiles.length -1; idx >= 0; idx--){
+ let newuri = refFiles[idx];
+ let retSymbols = this.recursiveSearchRequireTree(newuri, symbolStr, searchMethod);
+ if (retSymbols != null && retSymbols.length > 0) {
+ retSymbArray = retSymbArray.concat(retSymbols);
+ }
+ }
+ return retSymbArray;
+ }
+}
diff --git a/src/code/server/codeTools.ts b/src/code/server/codeTools.ts
new file mode 100644
index 0000000..0b25767
--- /dev/null
+++ b/src/code/server/codeTools.ts
@@ -0,0 +1,524 @@
+// 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.
+
+import { Logger } from './codeLogManager';
+import URI from 'vscode-uri';
+let path = require('path');
+let dir = require('path-reader');
+let os = require('os');
+let urlencode = require('urlencode');
+
+import {
+ Location,
+ Position,
+ SymbolKind,
+ Range,
+ Connection,
+ DocumentSymbol
+} from 'vscode-languageserver';
+import * as fs from "fs";
+// import { isArray } from 'util';
+//-----------------------------------------------------------------------------
+//-- 暂存的数据
+//-----------------------------------------------------------------------------
+
+let initParameter; //初始化参数
+export function getInitPara(){
+ return initParameter;
+}
+export function setInitPara(para){
+ initParameter = para;
+}
+
+let loadedExt; // 已经过处理的文件后缀
+export function initLoadedExt(){
+ loadedExt = new Object();
+}
+
+export function getLoadedExt(){
+ return loadedExt;
+}
+
+export function setLoadedExt(key){
+ loadedExt[key] = true;
+}
+
+let connection: Connection; //保存一份connection
+export function setToolsConnection(conn: Connection) {
+ connection = conn;
+}
+
+let rootFiles;
+let fileName_Uri_Cache;
+
+//-----------------------------------------------------------------------------
+//-- 枚举
+//-----------------------------------------------------------------------------
+//搜索类型
+export enum SearchMode{
+ ContinuousMatching,
+ ExactlyEqual, //精确查找
+ FuzzyMatching, //模糊查找
+ FirstLetterContinuousMatching, //前序匹配查找
+}
+
+//搜索范围
+export enum SearchRange{
+ AllSymbols, //全体符号
+ GlobalSymbols,
+ LocalSymbols
+}
+
+// 记录tag的原因
+export enum TagReason{
+ UserTag,
+ Equal,
+ MetaTable
+}
+
+//-----------------------------------------------------------------------------
+//-- 常用结构体
+//-----------------------------------------------------------------------------
+
+// 生成的符号信息
+export interface SymbolInformation {
+ name: string; //展示名 local a.b.c | function mt:fcun(para1)
+ searchName: string; //搜索名 a.b.c | mt:func (searchName在保存的时候,:全都用 . )
+ originalName: string //符号原本名 c | func
+ kind: SymbolKind; //类型
+ location: Location; //位置
+ isLocal: boolean; // local / global
+ containerURI: string; // 所属的URI (file://)
+ containerPath: string; // 所属的文件路径
+ containerName?: string; // 所属的函数名(展示用)
+ containerList?: Array; // 容器列表array
+ funcParamArray?: Array; // 函数参数数组,生成注释用
+ tagType?: string; // 用户标记此符号的类型,用于处理 local a = require("xxx") 等接收返回值的形式
+ requireFile?:string; // 符号是require文件的返回
+ funcRets?; // 如果此符号是function的返回值,记录对应的function . 值是{ name; local }结构
+ tagReason?: TagReason; // 标记原因,有标记必须写原因
+ chunk?:chunkClass; // 如果此符号是一个function, 对应的chunk结构
+}
+
+// 搜索符号返回结构
+// 这个结构类似一个联合体,其中可能有搜索到的符号retSymbol, 也可以记录baseinfo信息。使用isFindout来指示是否搜索到符号
+export class searchRet {
+ isFindout: boolean; //是否找到
+ container?: string[]; //深度层级列表
+ retSymbol?: searchSymbolRet; //符号自身的信息
+ baseinfo?: baseInfo; //基础层级的信息
+ constructor(){
+ this.isFindout = false;
+ }
+}
+
+// 搜索结果(searchRet的子结构)
+export interface searchSymbolRet {
+ name: string; //展示名
+ isLocal: boolean; //是否local符号. 下面三个属性是找到才需要的
+ location?: Location;
+ containerURI: string | null; //所属的文件名
+}
+
+// base 基类(table)信息 (searchRet的子结构)
+export interface baseInfo {
+ name: string; //展示名
+ isLocal: boolean; //是否local符号. 下面三个属性是找到才需要的
+ identiferStr?:string;
+}
+
+// 注释的类型信息
+export interface commentTypeInfo {
+ reason: TagReason; //注释的原因
+ newType: string; //新类型
+ oldType?: string; //旧类型 setmetatable(旧,新)
+ location?: Location;
+ name?:string; //被注释的变量名
+}
+
+// 注释的类型信息
+export interface functionRetInfo {
+ functionName:string; // 如果是函数返回信息,要填充这个参数
+ loc: Location;
+}
+
+// 引用文件的信息, require保存文件名是为了实现点击文件名跳转
+export interface requireFileInfo{
+ reqName:string;
+ loc:Location;
+}
+
+//chunks 结构体
+export class chunkClass {
+ chunkName:string;
+ loc:Location;
+ returnSymbol; //返回的变量值
+ constructor(name, loc){
+ this.chunkName = name;
+ this.loc = loc;
+ }
+}
+
+// 一个lua文件中包含的所有信息
+export class docInformation {
+ // lua文本基础内容
+ docAST; //文本解析出的AST树
+ docUri:string; //文件URL
+ docPath :string; //文件路径
+ // 符号表
+ defineSymbols; //定义符号表
+ // 文件的引用和被引用情况
+ requires:requireFileInfo[]; //本文件引用的文件列表(require 是有序的,类型是array)
+ references: string[]; // require本文件的其他文件的uri(array)
+
+ constructor(docAST , docUri , docPath){
+ this.docAST = docAST;
+ this.docUri = docUri;
+ this.docPath = docPath;
+ this.defineSymbols = new Object();
+ this.defineSymbols["allSymbols"] = new Array();
+ this.defineSymbols["allSymbolsArray"] = new Array();
+ this.defineSymbols["globalSymbols"] = new Array();
+ this.defineSymbols["globalSymbolsArray"] = new Array();
+ this.defineSymbols["localSymbols"] = new Array();
+ this.defineSymbols["localSymbolsArray"] = new Array();
+ this.defineSymbols["chunks"] = new Array(); //记录每个chunk中的名字,位置,global/local,(文件/函数)返回信息
+ this.defineSymbols["chunksArray"] = new Array(); //记录每个chunk中的名字,位置,global/local,返回信息
+ this.requires = new Array();
+ this.references = new Array();
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-- 工具方法
+//-----------------------------------------------------------------------------
+
+// uri 中html编码转换为原字符
+export function urlDecode(url):string{
+ return urlencode.decode(url);
+}
+
+// 从URI分析出文件名和后缀
+export function getPathNameAndExt(UriOrPath): Object{
+ let name_and_ext = path.basename(UriOrPath).split('.');
+ let name = name_and_ext[0]; //文件名
+ let ext = name_and_ext[1]; //文件后缀
+ for (let index = 2; index < name_and_ext.length; index++) {
+ ext = ext + '.' + name_and_ext[index];
+ }
+ return { name, ext };
+}
+
+export function get_FileName_Uri_Cache(){
+ return fileName_Uri_Cache;
+}
+
+// 向cache中添加内容
+export function AddTo_FileName_Uri_Cache(name , uri){
+ fileName_Uri_Cache[name] = urlDecode(uri);
+}
+
+// 刷新Cache
+export function refresh_FileName_Uri_Cache(){
+ //Cache 中没有找到,遍历RootPath
+ // Logger.InfoLog("start refresh_FileName_Uri_Cache: ");
+ rootFiles = new Array();
+ fileName_Uri_Cache = new Array();
+ let processFilNum = 0;
+ let LuaPandaPath = '';
+ if(initParameter && initParameter.rootPath){
+ //rootFiles为空,构建rootFilesMap,这个步骤应该放在init时,或者打开首个文件时
+ //构建操作,只执行一次
+ if(rootFiles.length < 1){
+ rootFiles = dir.files(initParameter.rootPath, {sync:true});
+ let totalFileNum = rootFiles.length;
+ for(let idx = 0, len = rootFiles.length; idx < len ; idx++){
+ let currentFileIdx = idx + 1;
+ let name_and_ext = getPathNameAndExt(rootFiles[idx]);
+ let trname = name_and_ext['name'];
+ let ext = name_and_ext['ext'];
+ let validExt = getLoadedExt(); //可用的文件后缀
+ if(validExt[ext]){
+ let trUri = pathToUri(rootFiles[idx]); //uri
+ fileName_Uri_Cache[trname] = urlDecode(trUri);
+ // 文件信息
+ Logger.DebugLog(trUri);
+ processFilNum = processFilNum + 1;
+ // 显示进度
+ let rate = Math.floor(currentFileIdx / totalFileNum * 100);
+ showProgressMessage(rate, trUri);
+ if(trname === "LuaPanda"){
+ LuaPandaPath = rootFiles[idx];
+ }
+ }
+ }
+ }
+ }
+ Logger.InfoLog("文件Cache刷新完毕,共计"+ rootFiles.length +"个文件, 其中" + processFilNum + "个lua类型文件");
+ if(LuaPandaPath){
+ connection.sendNotification("setLuaPandaPath", LuaPandaPath);
+ }
+ showProgressMessage(100, "done!");
+}
+
+// 把文件名转换为 uri
+// @fileName 文件名
+// @return uri string
+export function transFileNameToUri(requireName : string): string{
+ //从fileMap中查找文件全路径
+ // Logger.InfoLog("transFileNameToUri find--" + requireName);
+ let cacheUri = fileName_Uri_Cache[requireName];
+ if(cacheUri){
+ return cacheUri;
+ }
+ return '';
+}
+
+//把win下盘符转换成大写
+export function transWinDiskToUpper(uri: string):string{
+ if (os.type() == "Windows_NT") {
+ let reg = /^file:\/\/\/(\w)/;
+ uri = uri.replace(reg,function(m){
+ let diskSymbol = m.charAt(8);
+ diskSymbol = 'file:///' + diskSymbol.toUpperCase()
+ return diskSymbol});
+ return uri;
+ }
+}
+
+// path -> uri string
+export function pathToUri(path : string): string{
+ return URI.file(path).toString();
+}
+
+// uri string -> path
+export function uriToPath(uri: string): string {
+ return URI.parse(uri).fsPath;
+}
+
+// 返回整个目录下的文件列表
+// @path 文件夹路径
+// @return string[] | 返回的文件列表
+export function getDirFiles(path : string){
+ if(path){
+ return dir.files(path, {sync:true});
+ }
+}
+
+// 读文本文件内容
+// @path 文件路径
+// @return 文件内容
+export function getFileContent(path: string): string {
+ if(path == '' || path == undefined){
+ return '';
+ }
+ let data = fs.readFileSync(path);
+ let dataStr = data.toString();
+ return dataStr;
+}
+
+// 把position中起始行号转换为1 (用户选择- > vacode)
+export function transPosStartLineTo1(position){
+ position.line = position.line + 1;
+}
+
+export function transPosStartLineTo0(position){
+ position.line = position.line - 1;
+}
+
+
+// 从给定文本中,读出pos位置处的信息
+// @luaText 文本
+// @pos 位置信息
+// @return 指定位置的lua字符串
+export function getTextByPosition(luaText : string, pos : Position): string{
+ if(luaText == null){
+ return '';
+ }
+ // 拆分luaText
+ let stringArr = luaText.split(/\r\n|\r|\n/);
+ let startStr = stringArr[pos.line].substring(0, pos.character);
+ //使用正则搜索最后一个出现的 符号或者空格 TODO 待完善
+ // let reg= /[~!#%&\*\(\)\|,<>\?"';\+\-\=\[\]\{\}]/g;
+ let reg= /[~!#%&\*\(\)\|,<>\?"';\+\=\[\]\{\}]/g; // 保留"-",用于触发文档注释
+ let blankStr = startStr.replace(reg, ' ');
+ let finalArr = blankStr.split(' ');
+ let retStr = finalArr.pop();
+ return retStr;
+}
+
+/**
+ * isNextLineHasFunction 使用正则判断下一行是否有function关键字,如果有返回true
+ * @param luaText 文件内容
+ * @param position 位置
+ */
+export function isNextLineHasFunction(luaText: string, position: Position): boolean {
+ let luaTextArray = luaText.split(/\r\n|\r|\n/);
+
+ // 溢出
+ if (luaTextArray.length <= position.line + 1) {
+ return false;
+ }
+
+ let nextLineText = luaTextArray[position.line + 1];
+ let regExp = /\bfunction\b/;
+ if (regExp.exec(nextLineText)) {
+ return true;
+ }
+ return false;
+}
+
+export function createEmptyLocation(uri) {
+ let pos = Position.create(0,0);
+ let rg = Range.create(pos, pos)
+ let retLoc = Location.create(uri, rg);
+ return retLoc;
+}
+
+// 根据uri判断文件是否在预设的忽略列表里
+// @param ignoreRegExp 要忽略的文件夹的正则表达式数组
+export function isMatchedIgnoreRegExp(uri: string, ignoreRegExp: string[]): boolean {
+ for (let i = 0; i < ignoreRegExp.length; i++) {
+ if (ignoreRegExp[i] === "") {
+ continue;
+ }
+ let regExp = new RegExp(ignoreRegExp[i]);
+ if (regExp.exec(uri)) {
+ return true;
+ }
+ }
+ return false;
+
+}
+
+export function getNSpace(n: number) {
+ let str = "";
+ for (let i = 0; i < n; i++) {
+ str += " ";
+ }
+ return str;
+}
+
+export function showProgressMessage(progress: number, message: string) {
+ connection.sendNotification("showProgress", progress + "% " + message);
+ if (progress == 100) {
+ connection.sendNotification("showProgress", "LuaPanda 👍");
+ }
+}
+
+// 新加入的方法,把dic转换为array
+export function changeDicSymboltoArray(dic){
+ let array = new Array();
+ for (const key in dic) {
+ const element = dic[key];
+ if(Array.isArray(element)){
+ for (const k in element) {
+ const ele = element[k];
+ array.push(ele);
+ }
+ }else{
+ array.push(element);
+ }
+ }
+ return array;
+}
+
+// 将原有的containerList和searchName用点和冒号切割,拼成新的containerList,用来处理层级
+function getVerboseSymbolContainer(verboseSymbolInfo: SymbolInformation): chunkClass[] {
+ let searchName = verboseSymbolInfo.searchName;
+ let searchNameArray = Array();
+ if (searchName != "...") {
+ searchName = searchName.replace(/\[/g, '.');
+ searchName = searchName.replace(/]/g, '');
+ searchNameArray = splitToArrayByDot(searchName);
+ }
+ let searchNameContainer: chunkClass[] = Array();
+ for (let i = 0; i < searchNameArray.length - 1; i++) {
+ searchNameContainer.push(new chunkClass(searchNameArray[i], undefined));
+ }
+
+ let containerList: chunkClass[] = Array();
+ containerList.push(verboseSymbolInfo.containerList[0]);
+ for (let i = 1; i < verboseSymbolInfo.containerList.length; i++) {
+ let chunkNameArray = splitToArrayByDot(verboseSymbolInfo.containerList[i].chunkName);
+ if (chunkNameArray.length > 1) {
+ for (let j = 0; j < chunkNameArray.length; j++) {
+ containerList.push(new chunkClass(chunkNameArray[j], undefined));
+ }
+ } else {
+ containerList.push(verboseSymbolInfo.containerList[i]);
+ }
+ }
+
+ let verboseSymbolContainer = containerList.concat(searchNameContainer);
+ return verboseSymbolContainer;
+}
+
+function handleDocumentSymbolChildren(symbolContainer: chunkClass[], documentSymbol: DocumentSymbol, outlineSymbolArray: DocumentSymbol[], chunkMap: Map) {
+ let index = chunkMap.get(symbolContainer[1].chunkName);
+ let parent: DocumentSymbol = outlineSymbolArray[index];
+ for (let i = 2; i < symbolContainer.length; i++) {
+ for (let j = 0; j < parent.children.length; j++) {
+ if (symbolContainer[i].chunkName == parent.children[j]["originalName"]) {
+ parent = parent.children[j];
+ break;
+ }
+ }
+ }
+ if(!parent.children){
+ parent.children = new Array();
+ }
+
+ parent.children.push(documentSymbol);
+}
+
+/**
+ * 列出本文件中的符号,用于在outline窗口中分层显示符号列表
+ * @param symbolInfoArray CodeSymbol.getCertainDocSymbolsArray返回的符号信息数组
+ * @return 本文件所有符号列表,DocumentSymbol数组,带有层次结构
+ */
+export function getOutlineSymbol(symbolInfoArray: SymbolInformation[]): DocumentSymbol[] {
+ let outlineSymbolArray = Array();
+
+ // 存储最外层SymbolInformation.name - outlineSymbolArray索引 的map
+ let chunkMap = new Map();
+
+ for (let i = 0; i < symbolInfoArray.length; i++) {
+ let symbolInfo: SymbolInformation = symbolInfoArray[i];
+ let documentSymbol: DocumentSymbol = {
+ name: symbolInfo.originalName,
+ kind: symbolInfo.kind,
+ range: symbolInfo.location.range,
+ selectionRange: symbolInfo.location.range,
+ children: Array()
+ };
+ documentSymbol["originalName"] = symbolInfo.originalName;
+ // 变量展示originalName,函数展示name
+ if (symbolInfo.kind == SymbolKind.Function) {
+ documentSymbol.name = symbolInfo.name;
+ }
+
+ let verboseSymbolContainer = getVerboseSymbolContainer(symbolInfoArray[i]);
+
+ if (verboseSymbolContainer.length > 1) {
+ handleDocumentSymbolChildren(verboseSymbolContainer, documentSymbol, outlineSymbolArray, chunkMap);
+ continue;
+ }
+
+ outlineSymbolArray.push(documentSymbol);
+
+ chunkMap.set(symbolInfo.searchName, outlineSymbolArray.length - 1);
+ }
+
+ return outlineSymbolArray;
+}
+
+// 使用: . 分割符号,并返回数组
+export function splitToArrayByDot(input) {
+ let userInputTxt_DotToBlank = input.replace(/[\.:]/g, ' '); //把.和:转为空格
+ let L = userInputTxt_DotToBlank.split(' ');
+ return L;
+}
diff --git a/src/code/server/docSymbolProcesser.ts b/src/code/server/docSymbolProcesser.ts
new file mode 100644
index 0000000..a7fd252
--- /dev/null
+++ b/src/code/server/docSymbolProcesser.ts
@@ -0,0 +1,1833 @@
+// 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.
+
+/* 本文件的作用是遍历一个文件url对应的AST树,并在遍历过程中记录一些信息
+ 通常在三种情况下会遍历AST。
+ 1 由AST构建定义符号表
+ 2 已经有一个符号位置,由AST中查找其对应的符号
+ 3 给定一个符号信息,由这个信息查询所有引用这个符号的位置
+
+ 本文件还提供在构建的定义表只能中搜索符号的能力searchMatchSymbal,支持各种搜索方式
+
+ 本文件的公有方法分为几部分:
+ + 静态创建方法
+ + 获取本url及对应AST信息
+ + 功能实现接口
+ + 符号查找(多种方式)
+
+ 私有方法
+ + 工具方法
+ + AST分析后的尾处理
+ + 遍历AST
+ + 时序处理:分析不完整的AST
+*/
+
+import * as luaparse from 'luaparse';
+import * as Tools from './codeTools';
+import { Logger } from './codeLogManager';
+import { CodeSymbol } from './codeSymbol';
+import { Location, Range, Position, SymbolKind } from 'vscode-languageserver';
+// import { isArray } from 'util';
+
+// 遍历AST模式
+enum travelMode {
+ BUILD = 0, //构建定义符号
+ GET_DEFINE = 1, //查找定义符号
+ FIND_REFS = 2 //查找引用符号
+}
+
+export class DocSymbolProcesser {
+ private docInfo: Tools.docInformation; // 记录.lua文本中的所有信息
+ // 下面是临时记录信息的变量
+ // refs 引用相关
+ private searchInfo; //记录被查找的符号信息
+ private refsLink; //引用符号队列
+ // 按位置查找符号
+ private searchPosition: Position; // 记录搜索符号所在的Position
+ private posSearchRet: Tools.searchRet; // 记录按配置查找的结果
+ //解析相关
+ public parseError = false; // 记录解析失败
+ public static tempSaveInstance; // 临时记录实例
+ //build 相关
+ private docCommentType; //注释(等号)类型表 | 符号标记类型 记录标记的类型信息。标记来源于 1.用户注释 2.元表 3. 等号
+ private funcReturnRecoder; // 用来记录每个函数符号的返回值,并放入符号列表的 chunk 结构中
+ private callFunctionRecoder; //用来记录函数调用
+
+ // 静态创建方法,创建文件的 定义符号列表(定义符号tools.docInformation 数组)
+ public static create(luaText: string, uri: string, path?: string) {
+ let instance: DocSymbolProcesser = new DocSymbolProcesser();
+ if(!path){
+ path = Tools.uriToPath(uri);
+ }
+ try {
+ let AST = luaparse.parse(luaText, { locations: true, scope: true, comments: true});
+ instance.docInfo = new Tools.docInformation(AST, uri, path);
+ instance.buildDocDefineSymbols();
+ instance.parseError = false;
+ return instance;
+ } catch (error) {
+ Logger.ErrorLog("[Error] 解析文件 " + uri + " AST的过程中出错:");
+ Logger.ErrorLog("[error stack]:" + error.stack );
+
+ //建立空文件(没有AST)
+ instance.docInfo = new Tools.docInformation(new Object, uri, path);
+ DocSymbolProcesser.tempSaveInstance = instance;
+ //解析
+ try {
+ luaparse.parse(luaText, { locations: true, scope: true, onCreateNode: instance.onCreateNode});
+ }catch{}
+ instance.parseError = true;
+ return instance;
+ }
+ }
+
+//-----------------------------------------------------------------------------
+//-- get/set 获取本文件的基础信息
+//-----------------------------------------------------------------------------
+
+ // 获取本文件uri
+ public getUri() {
+ return this.docInfo.docUri;
+ }
+
+ // 获取本文件 [所有符号列表] (kv)
+ public getAllSymbolsDic() {
+ return this.docInfo.defineSymbols.allSymbols;
+ }
+
+ // 获取本文件 [全局符号列表] (kv)
+ public getGlobalSymbolsDic() {
+ return this.docInfo.defineSymbols.globalSymbols;
+ }
+
+ // 获取本文件 [局部符号列表] (kv)
+ public getLocalSymbolsDic() {
+ return this.docInfo.defineSymbols.localSymbols;
+ }
+
+ // 获取本文件 [chunk信息列表] (kv)
+ public getChunksDic(){
+ return this.docInfo.defineSymbols.chunks;
+ }
+
+ // 因为符号kv dic中存在冲突,所以新增了返回array接口
+ public getAllSymbolsArray() {
+ return this.docInfo.defineSymbols.allSymbolsArray;
+ }
+
+ // 获取本文件 [全局符号列表] (array)
+ public getGlobalSymbolsArray() {
+ return this.docInfo.defineSymbols.globalSymbolsArray;
+ }
+
+ // 获取本文件 [局部符号列表] (array)
+ public getLocalSymbolsArray() {
+ return this.docInfo.defineSymbols.localSymbolsArray;
+ }
+
+ // 获取本文件 [chunk信息列表] (array)
+ public getChunksArray(){
+ return this.docInfo.defineSymbols.chunksArray;
+ }
+
+ // 获取本文件 [返回值列表] (array)
+ public getFileReturnArray(){
+ let chunks = this.docInfo.defineSymbols.chunks;
+ return chunks[this.docInfo.docPath].returnSymbol;
+ }
+
+ // 获取本文件 [require列表] (array)
+ public getRequiresArray(){
+ return this.docInfo.requires;
+ }
+
+ // 获取本文件的[被引用信息] (array)
+ public getReferencesArray() {
+ return this.docInfo.references;
+ }
+ // 设置本文件的被引用信息
+ public setReferences(references: string[]) {
+ return this.docInfo.references = references;
+ }
+
+//-----------------------------------------------------------------------------
+//-- 主要对外接口
+//-----------------------------------------------------------------------------
+ // 构建文件的 [定义符号表]
+ public buildDocDefineSymbols() {
+ let deepLayer: Array = new Array();
+ this.docCommentType = new Array();
+ this.callFunctionRecoder = new Array();
+ // 由AST建立符号表
+ this.traversalAST(this.docInfo["docAST"], travelMode.BUILD, deepLayer);
+ // 符号表后处理,记录comment和文件/函数返回值
+ this.buildSymbolTag();
+ this.buildSymbolReturns(); // 构建 B = require("A") , 记录B的类型
+ // Debug info 查看序列化的AST
+ // let tempStr = JSON.stringify(this.docInfo["docAST"]);
+ // DebugInfo
+ // console.log(tempStr)
+ }
+
+ // 根据 VSCode 传来的 Position 信息从文件 AST 中查找对应符号
+ // 这里可以考虑从AST中或者从luaText中查找。使用AST的优点是可以查询到更多的信息,包括isLocal,container。使用 text查找比较快,但只有文本信息。
+ // 使用luaText查找的好处是可以搜索未完成的代码
+ // 目前 定义查找使用 AST, 代码补全使用 luaText
+ public searchDocSymbolfromPosition(pos) {
+ this.searchPosition = pos;
+ let container = new Array();
+ this.posSearchRet = new Tools.searchRet();
+ this.traversalAST(this.docInfo["docAST"], travelMode.GET_DEFINE, container);
+ return { sybinfo: this.posSearchRet.retSymbol, container: container };
+ }
+
+ // 查找一个符号的引用
+ public searchDocSymbolReference(info) {
+ //先清空数组
+ this.searchInfo = info;
+ this.refsLink = new Array(); // 引用符号队列
+ this.traversalAST(this.docInfo["docAST"], travelMode.FIND_REFS, new Array());
+ return this.refsLink;
+ }
+
+ // 按 position 搜索符号是否是文件名(用于点击require文件名跳转)
+ public searchDocRequireFileNameFromPosition(pos):string {
+ let reqFiles = this.getRequiresArray();
+ for (let index = 0; index < reqFiles.length; index++) {
+ const element = reqFiles[index];
+ let res = this.isInASTLoc(element.loc, pos);
+ if(res){
+ return element.reqName;
+ }
+ }
+ }
+
+ // 在当前 文件的定义符号表中查找符号(提供多种查找方式,查找范围)
+ // @symbalName 符号名
+ // @matchMode 搜索方式
+ // @searchRange 0:all 1 global 2 display
+ public searchMatchSymbal(symbalName: string, matchMode: Tools.SearchMode, searchRange?: Tools.SearchRange ): Tools.SymbolInformation[] {
+ searchRange = searchRange || Tools.SearchRange.AllSymbols ;
+ let retSymbols = [];
+ let SymbolArrayForSearch;
+ if( searchRange == Tools.SearchRange.AllSymbols ){
+ SymbolArrayForSearch = this.getAllSymbolsDic();
+ }else if( searchRange == Tools.SearchRange.GlobalSymbols){
+ SymbolArrayForSearch = this.getGlobalSymbolsDic() ;
+ }else if( searchRange == Tools.SearchRange.LocalSymbols){
+ SymbolArrayForSearch = this.getLocalSymbolsDic();
+ }
+ var reg = /[A-Z]/;
+ //精确查找。直接使用字典匹配
+ if (matchMode === Tools.SearchMode.ExactlyEqual) {
+ //精确匹配 searchName
+ let tgtSymbol = SymbolArrayForSearch[symbalName];
+ if(tgtSymbol){
+ if(Array.isArray(tgtSymbol)){
+ retSymbols = tgtSymbol;
+ }else{
+ retSymbols.push(tgtSymbol);
+ }
+ }else{
+ //把: 替换成.尝试再次匹配
+ symbalName = symbalName.replace(/:/g,".");
+ let tgtSymbol = SymbolArrayForSearch[symbalName];
+ if(!tgtSymbol){
+ symbalName = symbalName.replace(/\./g,":");
+ tgtSymbol = SymbolArrayForSearch[symbalName];
+ }
+
+ if(tgtSymbol){
+ if(Array.isArray(tgtSymbol)){
+ retSymbols = tgtSymbol;
+ }else{
+ retSymbols.push(tgtSymbol);
+ }
+ }
+ }
+ }
+
+ // let hasUpper = symbalName.match(reg);
+ for (let idx in SymbolArrayForSearch){
+ let sym = SymbolArrayForSearch[idx];
+ if (matchMode === Tools.SearchMode.ContinuousMatching) {
+ //连续查找 name
+ let res = sym.name.match(symbalName);
+ if (res != null) {
+ retSymbols.push(sym);
+ }
+ } else if (matchMode === Tools.SearchMode.FuzzyMatching) {
+ //模糊查找 当前只用于 @ # 的符号查找,所以搜索 name
+ var inputArray = symbalName.split('');
+ var pattStr = inputArray.join('.*?');
+ var pattRegExp = new RegExp(pattStr, "i");
+ let res = sym.name.match(pattRegExp);
+ if (res != null) {
+ retSymbols.push(sym);
+ }
+ }else if (matchMode === Tools.SearchMode.FirstLetterContinuousMatching) {
+ //在这种模式中,如果用户输入的字符串中有大写字母,则大小写敏感。否则大小写不敏感
+ let searchName = sym.searchName;
+ if(searchName){
+ let reg1 = new RegExp( /[\.:]/, 'g')
+ let symbalName_dot = symbalName.replace( reg1 , '.' );
+ var reg = new RegExp( '^' + symbalName_dot ,'i');
+
+ let hit = searchName.match(reg);
+ if(hit){
+ retSymbols.push(sym);
+ }
+ //首字母起始连续查找 searchName
+ // searchName = searchName.replace(/:/g,".");
+ // symbalName = symbalName.replace(/:/g,".");
+ }else{
+ }
+
+ }
+ }
+ return retSymbols;
+ }
+
+//-----------------------------------------------------------------------------
+//-- 以下是遍历AST的私有方法
+//-- 工具方法
+//-----------------------------------------------------------------------------
+
+ // loc2是否在loc1之中
+ private isInLocation(loc1, loc2: Position): boolean {
+ if (loc1.range.start.line <= loc2.line && loc1.range.end.line >= loc2.line) {
+ if (loc1.range.start.line === loc2.line) {
+ let character = loc1.range.start.character || loc1.range.start.column;
+ //start > pos
+ if (character > loc2.character) return false;
+ }
+
+ if (loc1.range.end.line === loc2.line) {
+ let character = loc1.range.end.character || loc1.range.end.column;
+ if (character < loc2.character) return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ //list2是否是list1的子集
+ // private listContainer(list1, list2): boolean {
+ // if(list2.length > list1.length) return false;
+ // for(let idx = 0, len = list2.length ; idx < len; idx++){
+ // if(list1[idx] != list2[idx]){
+ // return false;
+ // }
+ // }
+ // return true;
+ // }
+
+ // 判断 loc2 是否被包含在 loc1 之中
+ private isInASTLoc(loc1, loc2: Position): boolean {
+ if (loc1["start"].line <= loc2.line && loc1["end"].line >= loc2.line) {
+ if (loc1.start.line === loc2.line) {
+ let character = loc1.start.character || loc1.start.column;
+ //start > pos
+ if (character > loc2.character) return false;
+ }
+
+ if (loc1.end.line === loc2.line) {
+ let character = loc1.end.character || loc1.end.column;
+ if (character < loc2.character) return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ // 创建一个符号的信息
+ private createSymbolInfo(name: string, searchName:string, originalName:string,
+ kind:SymbolKind, location:Location, isLocal:boolean,
+ containerName?:string, containerList?:Array, funcParamArray?:Array, tagType? :string, reason?: Tools.TagReason): Tools.SymbolInformation{
+ let showName = name;
+ if(isLocal){
+ showName = "local " + showName;
+ }
+ return{
+ name: showName,
+ searchName: searchName,
+ originalName: originalName,
+ kind: kind,
+ location: location,
+ isLocal: isLocal,
+ containerURI: this.docInfo["docUri"],
+ containerPath: this.docInfo["docPath"],
+ containerName: containerName,
+ containerList: containerList,
+ funcParamArray:funcParamArray,
+ // alreadyAddDisplay: false,
+ tagType:tagType,
+ tagReason:reason
+ };
+ }
+
+ // 检查符号是否已经在符号表中存在
+ // @name 符号名
+ private checkIsSymbolExist(name) {
+ if (this.getAllSymbolsDic()[name] != undefined){
+ return true;
+ }
+ return false;
+ }
+
+ //-------查到符号后的填充
+ private pushToAllList(symbol:Tools.SymbolInformation){
+ if(this.docInfo.defineSymbols.allSymbols[symbol.searchName]){
+ let travlSymbol = this.docInfo.defineSymbols.allSymbols[symbol.searchName];
+ //判断是否数组
+ if ( Array.isArray(travlSymbol) ){
+ travlSymbol.push(symbol);
+ }else{
+ //只有一个元素,还不是数组
+ let newArray = new Array();
+ newArray.push(travlSymbol);
+ newArray.push(symbol);
+ this.docInfo.defineSymbols.allSymbols[symbol.searchName] = newArray;
+ }
+ }else{
+ this.docInfo.defineSymbols.allSymbols[symbol.searchName] = symbol;
+ }
+ //放入array队列
+ this.docInfo.defineSymbols.allSymbolsArray.push(symbol);
+ }
+
+ private pushToLocalList(symbol:Tools.SymbolInformation){
+ if(this.docInfo.defineSymbols.localSymbols[symbol.searchName]){
+ let travlSymbol = this.docInfo.defineSymbols.localSymbols[symbol.searchName];
+ if ( Array.isArray(travlSymbol) ){
+ travlSymbol.push(symbol);
+ }else{
+ let newArray = new Array();
+ newArray.push(travlSymbol);
+ newArray.push(symbol);
+ this.docInfo.defineSymbols.localSymbols[symbol.searchName] = newArray;
+ }
+ }else{
+ this.docInfo.defineSymbols.localSymbols[symbol.searchName] = symbol;
+ }
+ //放入array队列
+ this.docInfo.defineSymbols.localSymbolsArray.push(symbol);
+ }
+
+ // 把symbol信息放入 docGlobalSymbols | 注意这里是 kv 形式
+ private pushToGlobalList(symbol:Tools.SymbolInformation){
+ if(this.docInfo.defineSymbols.globalSymbols[symbol.searchName]){
+ let travlSymbol = this.docInfo.defineSymbols.globalSymbols[symbol.searchName];
+ if ( Array.isArray(travlSymbol) ){
+ travlSymbol.push(symbol);
+ }else{
+ let newArray = new Array();
+ newArray.push(travlSymbol);
+ newArray.push(symbol);
+ this.docInfo.defineSymbols.globalSymbols[symbol.searchName] = newArray;
+ }
+ }else{
+ this.docInfo.defineSymbols.globalSymbols[symbol.searchName] = symbol;
+ }
+ //放入array队列
+ this.docInfo.defineSymbols.globalSymbolsArray.push(symbol);
+ }
+
+ // 根据符号自动识别应该放入哪个列表
+ private pushToAutoList(symbol:Tools.SymbolInformation){
+ if(symbol.isLocal){
+ this.pushToLocalList(symbol);
+ }else{
+ this.pushToGlobalList(symbol);
+ }
+ this.pushToAllList(symbol);
+ }
+
+ private pushToChunkList(name, chunk){
+ if(this.docInfo.defineSymbols["chunks"][name]){
+ let travlSymbol = this.docInfo.defineSymbols["chunks"][name];
+ if ( Array.isArray(travlSymbol) ){
+ travlSymbol.push(chunk);
+ }else{
+ let newArray = new Array();
+ newArray.push(travlSymbol);
+ newArray.push(chunk);
+ this.docInfo.defineSymbols["chunks"][name] = newArray;
+ }
+ }else{
+ this.docInfo.defineSymbols["chunks"][name] = chunk;
+ }
+ //放入array队列
+ this.docInfo.defineSymbols.chunksArray.push(chunk);
+ }
+
+ private pushToCommentList(cmt:Tools.commentTypeInfo){
+ this.docCommentType.push(cmt);
+ }
+
+ // 记录函数调用
+ private recordFuncCall(cmt:Tools.functionRetInfo){
+ this.callFunctionRecoder.push(cmt);
+ }
+ //------------
+
+//-----------------------------------------------------------------------------
+//-- 遍历AST
+//-----------------------------------------------------------------------------
+ // 遍历AST
+ // @node AST 当前节点
+ // @type : travelMode.BUILD / travelMode.FIND_DEFINE / travel.FIND_REFS
+ // @deepLayer 深度队列。用来指示当前symbol所在的chunk
+ // @prefix 前缀。用来指示当前symbol所在chunk (此信息直接展示给用户)
+ // @isBody ?
+ private traversalAST(node, type : travelMode, deepLayer: Array , prefix?: string, isBody?:boolean) {
+ //传入的node是一个数组的时候,traversalAST递归其中每一个元素
+ if (Array.isArray(node) === true) {
+ let ASTArray = Array.prototype.slice.call(node);
+ for (let idx = 0, len = ASTArray.length; idx < len; idx++) {
+ this.traversalAST(ASTArray[idx], type, deepLayer, prefix, isBody);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+ } else {
+ let nodeType = node["type"];
+ switch (nodeType) {
+ //container
+ case 'Chunk': this.processChunk(node, type, deepLayer, prefix); break;
+ case 'LocalStatement': this.LocalStatement(node, type, deepLayer, prefix); break;
+ case 'FunctionDeclaration': this.processFunction(node, type, deepLayer, prefix); break;
+ case 'AssignmentStatement': this.processAssignment(node, type, deepLayer, prefix); break;
+ case 'CallExpression': this.processCallExpression(node, type, deepLayer, prefix); break;
+ case 'StringCallExpression': this.processStringCallExpression(node, type, deepLayer, prefix); break;
+ case 'CallStatement': this.processCallStatement(node, type, deepLayer, prefix); break;
+ //循环结构,其中可能有定义,也可能有查找的符号
+ case 'WhileStatement': this.processWhileStatement(node, type, deepLayer, prefix); break;
+ case 'RepeatStatement': this.processRepeatStatement(node, type, deepLayer, prefix); break;
+ case 'IfStatement': this.processIfStatement(node, type, deepLayer, prefix); break;
+ case 'ReturnStatement': this.processReturnStatement(node, type, deepLayer, prefix, isBody); break;
+ case 'ForNumericStatement': this.processForNumericStatement(node, type, deepLayer, prefix); break;
+ case 'ForGenericStatement': this.processForGenericStatement(node, type, deepLayer, prefix); break;
+ //二进制表达式 a == b
+ case 'BinaryExpression': this.processBinaryExpression(node, type, deepLayer, prefix); break;
+ case 'UnaryExpression': this.processUnaryExpression(node, type, deepLayer, prefix); break;
+ // case 'TableConstructorExpression': retsyb = this.processTableConstructorExpression(ASTNode, type, deepLayer, prefix); break;
+ case 'MemberExpression': this.processMemberExpression(node, type, deepLayer, prefix); break;
+ // Terminal
+ case 'Identifier': this.processIdentifier(node, type, deepLayer, prefix); break;
+ }
+ }
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ // ------异常处理
+ //分析不完全AST时的回调,这里只处理有限的情况
+ // 把symbol信息放入docSymbols
+ // luaparse.parse 方法创建AST Node时的回调。这里只处理有限的接口
+ private onCreateNode(node){
+ //require
+ let deepLayer: Array = new Array();
+ if(node['type'] == 'CallExpression' || node['type'] == 'StringCallExpression'){
+ DocSymbolProcesser.tempSaveInstance.traversalAST(node, travelMode.BUILD, deepLayer);
+ }
+ //定义 | 可以处理,但是失去了深度信息
+ if(node['type'] == "LocalStatement"){
+ DocSymbolProcesser.tempSaveInstance.traversalAST(node, travelMode.BUILD, deepLayer);
+ }
+ //function 定义
+ if(node['type'] == "FunctionDeclaration"){
+ DocSymbolProcesser.tempSaveInstance.traversalAST(node, travelMode.BUILD, deepLayer);
+ }
+ }
+
+ //---------前处理和后处理
+ // 处理注释. 基本思路是在注释中查询 -@type
+ // 用一个结构体记录位置和类型,并放入CommentList中
+ private processComments(commentArray){
+ for (let idx = 0, len = commentArray.length; idx < len; idx++) {
+ let comValue = commentArray[idx].value;
+ let strArr = comValue.split(' ')
+ for (let j = 0; j < strArr.length; j++) {
+ const element = strArr[j];
+ if(element.match('-@type')){
+ let info = {
+ reason: Tools.TagReason.UserTag,
+ newType: strArr[j + 1],
+ location : commentArray[idx].loc
+ }
+ this.pushToCommentList(info);
+ }
+ }
+ }
+ }
+
+ /**
+ * 记录反向引用关系
+ * @param requireName require语句中的文件名
+ * @param fileUri 调用require语句的文件的uri
+ */
+ private recordReference(fileUri: string, requireName: string) {
+ let requireFileUri = Tools.transFileNameToUri(requireName);
+ if (requireFileUri == "") {
+ // 未找到require的文件
+ return;
+ }
+
+ // 被require的文件还没有处理,先创建符号
+ if (CodeSymbol.docSymbolMap.has(requireFileUri) == false) {
+ CodeSymbol.createCertainDocSymbols(requireFileUri);
+ }
+ let references = CodeSymbol.docSymbolMap.get(requireFileUri).getReferencesArray();
+ if (references.includes(fileUri)) {
+ return;
+ }
+ references.push(fileUri);
+ }
+
+
+ private createRetBase(baseName, baseLocal, identifer?): Tools.searchRet {
+ let retBase: Tools.baseInfo = {
+ name: baseName,
+ isLocal: baseLocal,
+ identiferStr:identifer
+ };
+ let ret: Tools.searchRet = { isFindout: false, baseinfo: retBase };
+ return ret;
+ }
+
+ private createRetSymbol(sybName, sybisLocal, sybLocation?, sybPath?){
+ sybPath = sybPath || this.docInfo["docPath"];
+ let retSymbol: Tools.searchSymbolRet = {
+ name: sybName,
+ isLocal: sybisLocal,
+ location: sybLocation,
+ containerURI: sybPath
+ };
+ let ret: Tools.searchRet = { isFindout: true, retSymbol: retSymbol };
+ return ret;
+ }
+
+ // 记录一个符号的标记和标记原因(准备删除)
+ private setTagTypeToSymbolInfo(symbol: Tools.SymbolInformation, tagType, tagReason){
+ symbol.tagType = tagType;
+ symbol.tagReason = tagReason;
+ }
+
+ //---文件尾处理(生成符号表后,对一些有注释类型的符号,进行添加tag信息)
+ // 根据docCommentType记录的信息,在符号中标记tag
+ private buildSymbolTag(){
+ let tagArray = this.docCommentType;
+ for(var key in tagArray) {
+ let tagInfo = tagArray[key];
+ let loc = tagInfo.location;
+ let reason = tagInfo.reason;
+ //从allSymbols中遍历location和tag相符合的符号
+ for (let index = 0; index < this.getAllSymbolsArray().length; index++) {
+ const elm = this.getAllSymbolsArray()[index];
+ //用户标记
+ if(reason == Tools.TagReason.UserTag && elm.location.range.start.line + 1 === loc['end'].line)
+ {
+ this.setTagTypeToSymbolInfo(elm, tagInfo.newType, tagInfo.reason);
+ break;
+ }
+ //相等符号
+ if(reason == Tools.TagReason.Equal && elm.location.range.start.line + 1 === loc['end'].line)
+ {
+ // name : 被赋值符号名
+ if(tagInfo.name && tagInfo.name == elm.searchName){
+ this.setTagTypeToSymbolInfo(elm, tagInfo.newType, tagInfo.reason);
+ break;
+ }
+ }
+
+ //元表标记
+ if(reason == Tools.TagReason.MetaTable && elm.searchName == tagInfo.oldType){
+ this.setTagTypeToSymbolInfo(elm, tagInfo.newType, tagInfo.reason);
+ break;
+ }
+ }
+ }
+ }
+
+ // 构建文件返回和函数返回
+ private buildSymbolReturns(){
+ //设置符号的 requireFile
+ let reqArray = this.getRequiresArray();
+ reqArray.forEach(element => {
+ let loc = element.loc;
+ let reqName = element.reqName;
+ for (let index = 0; index < this.getAllSymbolsArray().length; index++) {
+ const elm = this.getAllSymbolsArray()[index];
+ let aling = elm.location.range.start.line + 1;
+ let bling = loc['start'].line;
+ if(aling == bling )
+ {
+ elm.requireFile = reqName;
+ }
+ }
+ });
+
+ //设置符号的 function Return
+ // let retArray = this.callFunctionRecoder;
+ for (const key in this.callFunctionRecoder ) {
+ const element = this.callFunctionRecoder[key];
+ let loc = element.loc;
+ let funcName = element.functionName;
+ for (let index = 0; index < this.getAllSymbolsArray().length; index++) {
+ const elm = this.getAllSymbolsArray()[index];
+ //用户标记
+ let aling = elm.location.range.start.line + 1;
+ let bling = loc['start'].line;
+ if(aling == bling )
+ {
+ elm.funcRets = funcName;
+ }
+ }
+ }
+ }
+ //-------尾处理
+
+//-----------------------------------------------------------------------------
+//-- 遍历AST主方法
+//-----------------------------------------------------------------------------
+ //base处理,主要工作是拼接变量名 a.b.c.d,并返回base的isLocal (子元素的isLocal跟随base)
+ private baseProcess(baseNode) {
+ if (baseNode['type'] == 'MemberExpression') {
+ let ret = this.baseProcess(baseNode['base']);
+ if(!ret){
+ // console.log("ssdsd");
+ // let ret = this.baseProcess(baseNode['base']);
+ return;
+ }
+ let str = ret.name;
+ let isLocal = ret.isLocal;
+ let retStr = str + baseNode['indexer'] + baseNode['identifier']['name'];
+ let retObj = { name: retStr, isLocal: isLocal, origion: baseNode['identifier']['name'] };
+ return retObj;
+ }
+ else if (baseNode['type'] == 'Identifier') {
+ return { name: baseNode['name'], isLocal: baseNode['isLocal'] };
+ }
+ else if (baseNode['type'] == 'IndexExpression') {
+ let ret = this.baseProcess(baseNode['base']);
+ let str = ret.name;
+ let isLocal = ret.isLocal;
+ let retObj;
+ if(baseNode['index']['type'] == "NumericLiteral"){
+ let retStr = str + '[' + baseNode['index']['raw'] + ']';
+ retObj = { name: retStr, isLocal: isLocal, origion: baseNode['index']['raw'] };
+ }
+
+ if(baseNode['index']['type'] == "Identifier"){
+ let retStr = str + '[' + baseNode['index']['name'] + ']';
+ retObj = { name: retStr, isLocal: isLocal, origion: baseNode['index']['name'] };
+ }
+
+ if(baseNode['index']['type'] == "MemberExpression"){
+ let ret = this.baseProcess(baseNode['index']);
+ let retStr = str + '[' + ret.name + ']';
+ retObj = { name: retStr, isLocal: isLocal, origion: ret.name };
+ }
+
+ if(baseNode['index']['type'] == "IndexExpression"){
+ let ret = this.baseProcess(baseNode['index']);
+ let retStr = str + '[' + ret.name + ']';
+ retObj = { name: retStr, isLocal: isLocal, origion: ret.name };
+ }
+
+ return retObj;
+ }
+ return { name: '', isLocal: false };
+ }
+
+ //base处理,function a.b.c.d. 当用户点击b的时候返回a.b
+ private MemberExpressionFind(baseNode) {
+ if(baseNode == null){
+ Logger.log("baseNode == null");
+ }
+
+ if (baseNode['type'] == 'MemberExpression') {
+ //递归向内部取base
+ let ret = this.MemberExpressionFind(baseNode['base']);
+ // if(ret && ret.isFindout){
+ // return ret;
+ // }
+
+ if(ret == null || ret.isInStat == undefined){
+ ret.isInStat = 0;
+ }
+ //判断identifier是否符合?一旦符合,后面的基层及全部加上
+ let nodeLoc = Location.create(this.docInfo["docUri"], baseNode['identifier']['loc']);
+ let isIn = this.isInLocation(nodeLoc, this.searchPosition);
+
+ if (isIn === true && ret.isInStat === 0) {
+ ret.isInStat = 1;
+ }
+ if (isIn === false && ret.isInStat === 1) {
+ //stop
+ return ret;
+ }
+
+ let str = ret.name;
+ let isLocal = ret.isLocal;
+ let retStr = str + baseNode['indexer'] + baseNode['identifier']['name'];
+ return { name: retStr, isLocal: isLocal, isInStat: ret.isInStat };
+ }
+ else if (baseNode['type'] == 'IndexExpression') {
+ //getindex
+ let ret = this.MemberExpressionFind(baseNode['base']);
+ // if(ret && ret.isFindout){
+ // return ret;
+ // }
+
+ if(ret == null || ret.isInStat == undefined){
+ ret.isInStat = 0;
+ }
+ //判断identifier是否符合?一旦符合,后面的基层及全部加上
+ let nodeLoc = Location.create(this.docInfo["docUri"], baseNode['index']['loc']);
+ let isIn = this.isInLocation(nodeLoc, this.searchPosition);
+
+ if (isIn === true && ret.isInStat === 0) {
+ ret.isInStat = 1;
+ }
+ if (isIn === false && ret.isInStat === 1) {
+ //stop
+ return ret;
+ }
+
+ let str = ret.name;
+ let isLocal = ret.isLocal;
+ let retStr;
+ if(baseNode['index']['value']){
+ retStr = str + '.' + baseNode['index']['value'];
+ }
+ return { name: retStr, isLocal: isLocal, isInStat: ret.isInStat };
+
+ }
+ else if (baseNode['type'] == 'CallExpression') {
+ this.processCallExpression(baseNode, travelMode.GET_DEFINE , null, "call EXp");
+ if (this.posSearchRet && this.posSearchRet.isFindout) {
+ // return retSymbol;
+ return {name: this.posSearchRet.retSymbol.name, isLocal:this.posSearchRet.retSymbol.isLocal, isInStat:1}
+ }
+ else{
+ return { name: '', isLocal: true, isInStat: 0 };
+ }
+ }
+ else if (baseNode['type'] == 'Identifier') {
+ //base的基层级
+ let nodeLoc = Location.create(this.docInfo["docUri"], baseNode['loc']);
+
+ let isIn = this.isInLocation(nodeLoc, this.searchPosition);
+ if (isIn === true) {
+ return { name: baseNode['name'], isLocal: baseNode['isLocal'], isInStat: 1 };
+ }
+ else {
+ return { name: baseNode['name'], isLocal: baseNode['isLocal'], isInStat: 0 };
+ }
+ }
+ }
+
+ //处理chunk, 通常是遍历AST的第一步
+ private processChunk(node, type, deepLayer, prefix){
+ if (type === travelMode.BUILD) {
+ this.processComments(node['comments']); //整理记录comment(---@type)
+ // 把当前文件压入chunk
+ let newChunk = new Tools.chunkClass(this.docInfo["docPath"] , this.docInfo.docAST.loc);
+ this.pushToChunkList(this.docInfo["docPath"], newChunk);
+ // 压入deep layer
+ deepLayer.push( newChunk ); //记录chunk名(文件名和起始结束行)
+ this.traversalAST(node["body"], type, deepLayer, prefix, true); // 遍历body
+ }
+
+ if (type === travelMode.GET_DEFINE){
+ let newChunk = new Tools.chunkClass(this.docInfo["docPath"] , this.docInfo.docAST.loc);
+ deepLayer.push( newChunk ); //记录chunk名(文件名和起始结束行)
+ this.traversalAST(node["body"], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ if (type === travelMode.FIND_REFS){
+ this.traversalAST(node["body"], type, deepLayer, prefix);
+ }
+ }
+
+ // 处理function
+ private processFunction(node, type, deepLayer: Array, prefix?: string) {
+ let searchRes = false; //整体检查位置是否在 function 中
+ let paraRecoder = new Array();
+ // GET_DEFINE 先判断搜索位置是否在 函数location中
+ if (type === travelMode.GET_DEFINE) {
+ let nodeLoc = Location.create(this.docInfo["docUri"], node["loc"]);
+ searchRes = this.isInLocation(nodeLoc, this.searchPosition);
+ // 用户点搜索的位置不在本function范围内, 清空数据,返回
+ if(searchRes == false) {
+ this.posSearchRet = new Tools.searchRet();
+ }
+ }
+
+ // 1. 记录函数参数
+ let searchHitPara = false;
+ let searchHitParaIdx = 0;
+ let paramArray = new Array();
+ for (let idx = 0; idx < node["parameters"].length; idx++) {
+ let paraNode = node["parameters"][idx];
+ if(paraNode.type == 'VarargLiteral'){
+ //可变参数
+ paramArray.push(paraNode['value']);
+ }else{
+ paramArray.push(paraNode['name']);
+ }
+
+ //搜索模式,且之前未命中
+ if (type === travelMode.GET_DEFINE && searchRes === true && searchHitPara === false) {
+ let nodeLoc1 = Location.create(this.docInfo["docUri"], node["parameters"][idx]["loc"]);
+ searchHitPara = this.isInLocation(nodeLoc1, this.searchPosition);
+ if(searchHitPara === true){
+ searchHitParaIdx = idx;
+ continue;
+ }
+ }
+
+ if (type === travelMode.BUILD) {
+ let loc = paraNode["loc"];
+ let name;
+ if(paraNode.type == 'VarargLiteral'){
+ name = paraNode.value;
+ }else{
+ name = paraNode["name"];
+ }
+ let isLocal = true; //参数全部是local
+ let loct = Location.create(this.docInfo["docUri"], Range.create(Position.create(loc["start"]["line"] - 1, loc["start"]["column"]), Position.create(loc["end"]["line"] - 1, loc["end"]["column"])));
+ let smbInfo = this.createSymbolInfo(name, name, name, SymbolKind.Variable, loct, isLocal, prefix, deepLayer.concat());
+ paraRecoder.push(smbInfo);
+ }
+ }
+ let paramString = "(" + paramArray.join(", ") + ")";
+
+ // 2. 处理函数名,BUILD时记录 chunk 。 并把信息压入 deepLayer
+ let newChunk; // 临时记录保存在数据结构中的chunk
+ let functionName; //函数名(name)
+ let functionSearchName = "NONAME"; //函数searchName
+ // 有名函数 普通函数的情况 function a()
+ if (node["identifier"] && node["identifier"]['type'] == 'Identifier') {
+ let loc = node["identifier"]["loc"];
+ functionSearchName = node["identifier"]["name"];
+ functionName = "function " + functionSearchName + paramString;
+ if (type === travelMode.GET_DEFINE && searchRes === true) {
+ let nodeLoc1 = Location.create(this.docInfo["docUri"], loc);
+ let res1 = this.isInLocation(nodeLoc1, this.searchPosition);
+ if (res1 === true){
+ this.posSearchRet = this.createRetSymbol(node["identifier"].name, node["identifier"].isLocal);
+ return;
+ }
+ }
+ if (type === travelMode.FIND_REFS) {
+ if (functionSearchName == this.searchInfo.originalName){
+ let loc = node["identifier"]["loc"];
+ let nodeLoc1 = Location.create(this.docInfo["docUri"], loc);
+ this.refsLink.push(nodeLoc1);
+ }
+ }
+ if (type === travelMode.BUILD) {
+ let loct = Location.create(this.docInfo["docUri"], Range.create(Position.create(loc["start"]["line"] - 1, loc["start"]["column"]), Position.create(loc["end"]["line"] - 1, loc["end"]["column"])));
+ let pushObj = this.createSymbolInfo(functionSearchName, functionSearchName, functionSearchName, SymbolKind.Function, loct, node["identifier"]["isLocal"], prefix, deepLayer.concat(), paramArray);
+ newChunk = new Tools.chunkClass(functionSearchName, node.loc);
+ this.pushToChunkList(newChunk.chunkName, newChunk);
+ pushObj.chunk = newChunk;
+ this.pushToAutoList(pushObj);
+
+ }
+ //有名函数 成员函数的情况 function a.b()
+ } else if (node["identifier"] && node["identifier"]['type'] == 'MemberExpression') {
+ let baseInfo = this.baseProcess(node["identifier"]);
+ functionSearchName = baseInfo.name;
+ functionName = 'function ' + functionSearchName + paramString;
+ if (type === travelMode.GET_DEFINE && searchRes === true) {
+ let bname = this.MemberExpressionFind(node["identifier"]);
+ if (bname.isInStat && bname.isInStat > 0) {
+ this.posSearchRet = this.createRetSymbol(bname.name, bname.isLocal);
+ return;
+ }
+ }
+
+ if (type === travelMode.FIND_REFS) {
+ if (functionSearchName == this.searchInfo.originalName){
+ let loc = node["identifier"]["loc"];
+ let nodeLoc1 = Location.create(this.docInfo["docUri"], loc);
+ this.refsLink.push(nodeLoc1);
+ }
+ }
+
+ if (type === travelMode.BUILD) {
+ let bname = this.baseProcess(node["identifier"]);
+ let originalName = bname.origion;
+ let loc = node['identifier']['loc'];
+ let rg = Location.create(this.docInfo["docUri"], Range.create(Position.create(loc["start"]["line"] - 1, loc["start"]["column"]), Position.create(loc["end"]["line"] - 1, loc["end"]["column"])));
+ let symbInfo = this.createSymbolInfo(functionName, functionSearchName, originalName, SymbolKind.Function, rg , bname.isLocal, prefix, deepLayer.concat(), paramArray);
+ newChunk = new Tools.chunkClass(functionSearchName, node.loc);
+ this.pushToChunkList(newChunk.chunkName, newChunk);
+ symbInfo.chunk = newChunk;
+ this.pushToAutoList(symbInfo);
+
+ //a:b , 隐式的self
+ let sepArr = bname.name.split(':');
+ if(sepArr.length > 1){
+ let tagname = sepArr[0];
+ let funcself = "self";
+ let isLocal = true; //参数全部是local
+ // let rg = Location.create(this.docInfo["docUri"], Range.create(Position.create(-1, -1), Position.create(-1, -1)));
+ let posChunk = new Tools.chunkClass(functionSearchName, node.loc);
+ deepLayer.push(posChunk);
+ let selfInfo = this.createSymbolInfo(funcself, funcself, funcself, SymbolKind.Variable, rg, isLocal, prefix, deepLayer.concat(), null, tagname, Tools.TagReason.Equal);
+ this.pushToAutoList(selfInfo);
+ deepLayer.pop();
+
+ }
+ }
+ }
+
+ // 生成chunk信息放入layer
+ let posChunk = new Tools.chunkClass(functionSearchName, node.loc);
+ deepLayer.push(posChunk);
+
+ if (type === travelMode.BUILD ){
+ //BUILD 向符号列表中写入para信息
+ for(let idx = 0 , len = paraRecoder.length;idx < len ; idx++ ){
+ let parainfo = paraRecoder.pop();
+ parainfo.containerName = functionSearchName;
+ parainfo.containerList = deepLayer.concat();
+ this.pushToAllList(parainfo);
+ }
+ }
+
+ // 3. 搜索命中para, 拼完路径后返回
+ if (type === travelMode.GET_DEFINE ){
+ if (searchHitPara === true) {
+ this.posSearchRet = this.createRetSymbol(node["parameters"][searchHitParaIdx].name, node["parameters"][searchHitParaIdx].isLocal);
+ return;
+ }
+ }
+
+ //TODO: 暂不支持函数嵌套声明, 可以改为array保存返回值
+ this.funcReturnRecoder = null; //准备记录函数返回
+ //匿名函数不再加入符号,仅分析内部成员
+ this.traversalAST(node["body"], type, deepLayer, functionName);
+
+ // 4. 搜索命中para, 拼完路径后返回
+ if (type === travelMode.GET_DEFINE ){
+ if (this.posSearchRet && this.posSearchRet.isFindout) {
+ return;
+ }
+ }
+
+ if (type === travelMode.BUILD ){
+ //把返回值放入function chunk
+ if(this.funcReturnRecoder){
+ if(newChunk){
+ newChunk.returnSymbol = this.funcReturnRecoder;
+ }else{
+ // 无名函数,不会创建newChunk,则不记录返回值
+ }
+ }
+ }
+ deepLayer.pop();
+ }
+
+ //处理局部变量
+ private LocalStatement(node, type, deepLayer, prefix?: string) {
+ let searchRes = false;
+ let baseInfo: Tools.baseInfo;
+ if (type === travelMode.GET_DEFINE) {
+ //检查变量是否在loc中
+ searchRes = this.isInLocation(Location.create(this.docInfo["docUri"], node["loc"]), this.searchPosition);
+ }
+
+ for (let idx = 0, len = node["variables"].length; idx < len; idx++) {
+ if (type === travelMode.BUILD) {
+ baseInfo = this.buildLvalueSymbals(node["variables"][idx], type, deepLayer, prefix);
+ }
+
+ if (type === travelMode.GET_DEFINE) {
+ this.searchLvalueSymbals(node["variables"][idx], type, deepLayer, prefix, searchRes);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return ;
+ baseInfo = this.posSearchRet.baseinfo;
+ }
+
+ if (type === travelMode.FIND_REFS) {
+ this.searchLvalueSymbals(node["variables"][idx], type, deepLayer, prefix, searchRes);
+ }
+ }
+
+ //右值
+ for (let idx = 0, len = node['init'].length; idx < len; idx++) {
+ if (type === travelMode.BUILD) {
+ this.buildRvalueSymbals(node['init'][idx], type, deepLayer, prefix, baseInfo);
+ }
+
+ if (type === travelMode.GET_DEFINE) {
+ this.searchRvalueSymbals(node['init'][idx], type, deepLayer, prefix, baseInfo, searchRes);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ if (type === travelMode.FIND_REFS) {
+ this.searchRvalueSymbals(node['init'][idx], type, deepLayer, prefix, baseInfo, searchRes);
+ }
+ }
+ }
+
+ //检查是否metatable,如果是,记录tag & reason
+ private processCallExpisSetMetatable(node, type, arg){
+ if(type == travelMode.BUILD){
+ let len = arg.length;
+ if(node["base"].type == 'Identifier' && node["base"].name == 'setmetatable' && node["base"].isLocal === false && len == 2) {
+ //base
+ let oldName = this.baseProcess(arg[0]);
+ let newName = this.baseProcess(arg[1]);
+
+ let info = {
+ reason: Tools.TagReason.MetaTable,
+ newType: newName.name,
+ oldType: oldName.name,
+ location : null
+ }
+ this.pushToCommentList(info);
+ }
+ }
+ }
+
+ //检查是否是function call,如果是,记录 tag & reason
+ private processCallExpisFunctionCall(node, type, arg){
+ if(type == travelMode.BUILD){
+ // let len = arg.length;
+ //functionName
+ let functionName = this.baseProcess(node['base']);
+ let info = {
+ functionName: functionName,
+ loc : node['loc']
+ }
+ this.recordFuncCall(info);
+ }
+ }
+
+ //检查是否require,如果是,记录require的文件名
+ private processCallExpisRequire(node, type, arg){
+ if(type == travelMode.BUILD){
+ let len = arg.length;
+ if(node["base"].type == 'Identifier' && node["base"].name == 'require' && node["base"].isLocal === false && len == 1) {
+ //读取arg[0]
+ if(arg[0].type == 'StringLiteral' && arg[0].value){
+ //记录 arg[0].value
+ let info: Tools.requireFileInfo = { reqName: arg[0].value, loc: arg[0].loc };
+ // this.docInfo["requireFile"].push(info);
+ this.docInfo.requires.push(info)
+ // 记录引用关系
+ this.recordReference(this.docInfo["docUri"], arg[0].value);
+ }
+ }
+ }
+ }
+
+ //
+ private processStringCallExpisRequire(node, type, arg){
+ if(type == travelMode.BUILD){
+ if(arg.type == 'StringLiteral' && arg.value){
+ let info: Tools.requireFileInfo = { reqName: arg.value, loc: arg.loc };
+ this.docInfo["requires"].push(info);
+ // 记录引用关系
+ this.recordReference(this.docInfo["docUri"], arg.value);
+ }
+ }
+ }
+
+ //调用表达式
+ private processStringCallExpression(node, type, deepLayer, prefix?: string) {
+ this.processStringCallExpisRequire(node, type, node['argument']);
+ //base
+ // if (type === travelMode.FIND_DEFINE) {
+ // let bname = this.MemberExpressionFind(node["base"]);
+ // if (bname.isInStat > 0) {
+ // // let retSearch : Tools.searchSymbolRet = {
+ // // name: bname.name,
+ // // containerURI: this.docInfo["docUri"],
+ // // isLocal:bname.isLocal
+ // // }
+ // this.posSearchRet = this.createRetSymbol(bname.name, bname.isLocal);
+ // }
+ // }
+
+ }
+
+ //调用表达式
+ private processCallExpression(node, type, deepLayer, prefix?: string) {
+ let varArray = Array.prototype.slice.call(node['arguments']);
+ let len = varArray.length;
+ this.processCallExpisRequire(node, type, varArray);
+ this.processCallExpisSetMetatable(node, type, varArray);
+ this.processCallExpisFunctionCall(node, type, varArray);
+ //argument
+ for (let idx = 0; idx < len; idx++) {
+ this.traversalAST(node['arguments'][idx], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ //base
+ if (type === travelMode.GET_DEFINE) {
+ let bname = this.MemberExpressionFind(node["base"]);
+ if (bname.isInStat && bname.isInStat > 0) {
+ this.posSearchRet = this.createRetSymbol(bname.name, bname.isLocal);
+ }
+ }
+
+ //base
+ if (type === travelMode.FIND_REFS) {
+ let bname = this.MemberExpressionFind(node["base"]);
+ if (bname == this.searchInfo.name){
+ let loc = node["identifier"]["loc"];
+ let nodeLoc1 = Location.create(this.docInfo["docUri"], loc);
+ this.refsLink.push(nodeLoc1);
+ }
+ }
+ }
+
+ //调用语句
+ private processCallStatement(node, type, deepLayer, prefix?: string) {
+ this.traversalAST(node['expression'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ //saved[value] 可以用作定义, 也可以读取值
+ private processIndexExpression(node, type, deepLayer, prefix?: string){
+ //search
+ if (type === travelMode.GET_DEFINE) {
+ let loc = node['index']['loc'];
+ //search 不仅要search当前元素,还要单独search base. 另外搜多当前元素要把base带上
+ let nodeLoc1 = Location.create(this.docInfo["docUri"], loc);
+ let retBool = this.isInLocation(nodeLoc1, this.searchPosition);
+ if (retBool === true) {
+ //取得base
+ if(node['base'].type == 'MemberExpression'){
+ this.posSearchRet = this.processMemberExpression(node['base'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+
+ }else if(node['base'].type == 'Identifier'){
+ this.processIdentifier(node['base'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ this.processIdentifier(node['index'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout == true) return;
+ }
+ }
+ //递归search base index 不需要递归
+ let bname = this.MemberExpressionFind(node['base']);
+ if (bname.isInStat && bname.isInStat > 0) {
+ this.posSearchRet = this.createRetSymbol(bname.name, bname.isLocal);
+ }
+ //没找到
+ return this.createRetBase(bname.name, bname.isLocal, node['index']['value']);
+ }
+ }
+
+ //变量赋值, 这里要区分全局变量的赋值和定义
+ private processAssignment(node, type, deepLayer, prefix?: string) {
+ let searchRes = false;
+ let baseInfo: Tools.baseInfo;
+
+ if (type === travelMode.GET_DEFINE) {
+ //检查变量是否在loc中
+ let nodeLoc = Location.create(this.docInfo["docUri"], node["loc"]);
+ searchRes = this.isInLocation(nodeLoc, this.searchPosition);
+ }
+
+ //遍历variables
+ if (Array.isArray(node['variables']) === true) {
+ let varArray = Array.prototype.slice.call(node['variables']);
+ let len = varArray.length;
+ for (let idx = 0; idx < len; idx++) {
+ if (type === travelMode.BUILD) {
+ baseInfo = this.buildLvalueSymbals(node["variables"][idx], type, deepLayer, prefix, null, 1);
+ }
+
+ if (type === travelMode.GET_DEFINE) {
+ this.searchLvalueSymbals(node["variables"][idx], type, deepLayer, prefix, searchRes);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ if(this.posSearchRet.baseinfo) baseInfo = this.posSearchRet.baseinfo;
+ }
+
+ if (type === travelMode.FIND_REFS) {
+ this.searchLvalueSymbals(node["variables"][idx], type, deepLayer, prefix, searchRes);
+ }
+ }
+ }
+
+ //遍历init (右值)
+ if (Array.isArray(node['init']) === true) {
+ let varArray = Array.prototype.slice.call(node['init']);
+ let len = varArray.length;
+ for (let idx = 0; idx < len; idx++) {
+ if (type === travelMode.BUILD) {
+ //a.b.c = {x = 9} base是 a.b.c
+ this.buildRvalueSymbals(node['init'][idx], type, deepLayer, prefix, baseInfo);
+ }
+
+ if (type === travelMode.GET_DEFINE) {
+ this.searchRvalueSymbals(node['init'][idx], type, deepLayer, prefix, baseInfo, searchRes);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ if (type === travelMode.FIND_REFS) {
+ this.searchRvalueSymbals(node['init'][idx], type, deepLayer, prefix, baseInfo, searchRes);
+ }
+ }
+ }
+ }
+
+ //遇到table构建表达式
+ private processTableConstructorExpression(node: Object, type, deepLayer: Array, prefix?: string, baseInfo?) {
+ //遍历fields
+ for (let idx = 0, len = node['fields'].length; idx < len; idx++) {
+ let idxNode = node['fields'][idx];
+ if (type === travelMode.BUILD) {
+ if (idxNode['type'] === 'TableKeyString') {
+ //L
+ let retInfo = this.buildLvalueSymbals(idxNode['key'], type, deepLayer, prefix, baseInfo);
+ //R
+ this.buildRvalueSymbals(idxNode["value"], type, deepLayer, prefix, retInfo);
+ }
+ if (idxNode['type'] === 'TableKey') {
+ if(idxNode['key']['type'] === "StringLiteral"){
+ // L
+ let orgname = idxNode['key']['value'];
+ let displayName = baseInfo.name + '.' + orgname;
+ let rg = Location.create(this.docInfo["docUri"], Range.create(Position.create(idxNode['loc']["start"]["line"] - 1, idxNode['loc']["start"]["column"]), Position.create(idxNode['loc']["end"]["line"] - 1, idxNode['loc']["end"]["column"])));
+ let symb = this.createSymbolInfo( displayName, displayName, orgname, SymbolKind.Variable, rg, baseInfo.isLocal, prefix, deepLayer.concat());
+ this.pushToAutoList(symb);
+ let retInfo = {name: displayName, isLocal: baseInfo.isLocal};
+ // R
+ this.buildRvalueSymbals(idxNode["value"], type, deepLayer, prefix, retInfo);
+ }
+
+ if(idxNode['key']['type'] === "NumericLiteral"){
+ // L
+ let orgname = idxNode['key']['raw']; //TODO 【orgname】
+ let displayName = baseInfo.name + '[' + orgname + ']';
+ let rg = Location.create(this.docInfo["docUri"], Range.create(Position.create(idxNode['loc']["start"]["line"] - 1, idxNode['loc']["start"]["column"]), Position.create(idxNode['loc']["end"]["line"] - 1, idxNode['loc']["end"]["column"])));
+ let symb = this.createSymbolInfo( displayName, displayName, orgname, SymbolKind.Variable, rg, baseInfo.isLocal, prefix, deepLayer.concat());
+ this.pushToAutoList(symb);
+ let retInfo = {name: displayName, isLocal: baseInfo.isLocal};
+ // R
+ this.buildRvalueSymbals(idxNode["value"], type, deepLayer, prefix, retInfo);
+ }
+ }
+ }
+ if (type === travelMode.GET_DEFINE) {
+ if (idxNode['type'] === 'TableKeyString') {
+ // string key 的table构造式
+ let recBaseName = baseInfo.name;
+ //L
+ this.searchLvalueSymbals(idxNode['key'], type, deepLayer, prefix, true, baseInfo);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ //R
+ this.searchRvalueSymbals(idxNode["value"], type, deepLayer, prefix, this.posSearchRet.baseinfo, true);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ // 记录Base并还原,避免反复处理对Base造成干扰
+ //用例 RadioErrorCode ={ Success = 0, NotEnoughScore = 1000}
+ baseInfo.name = recBaseName;
+ }
+
+ if (idxNode['type'] === 'TableKey') {
+ // [] 形式key的table构造式
+ if(idxNode['key']['type'] === "NumericLiteral"){
+ let recBaseName = baseInfo.name;
+ baseInfo.name = baseInfo.name + '[' + idxNode['key']['value'] + ']';
+ this.searchRvalueSymbals(idxNode["value"], type, deepLayer, prefix, baseInfo, true);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+
+ baseInfo.name = recBaseName;
+ }
+ if(idxNode['key']['type'] === "StringLiteral"){
+ let recBaseName = baseInfo.name;
+ baseInfo.name = baseInfo.name + '.' + idxNode['key']['value'];
+ this.searchRvalueSymbals(idxNode["value"], type, deepLayer, prefix, baseInfo, true);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ baseInfo.name = recBaseName;
+ }
+ }
+
+ }
+
+ if (type === travelMode.FIND_REFS) {
+ if (idxNode['type'] === 'TableKeyString') {
+ //L
+ this.searchLvalueSymbals(idxNode['key'], type, deepLayer, prefix, true, baseInfo);
+ //R
+ this.searchRvalueSymbals(idxNode["value"], type, deepLayer, prefix, this.posSearchRet.baseinfo, true);
+ }
+ }
+ }
+ }
+
+ //while
+ private processWhileStatement(node: Object, type, deepLayer: Array, prefix?: string) {
+ this.traversalAST(node['body'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ private processRepeatStatement(node: Object, type, deepLayer: Array, prefix?: string) {
+ this.traversalAST(node['body'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ private processMemberExpression(node, type, deepLayer, prefix: string, baseInfo?, searchRes?) {
+ if (type === travelMode.GET_DEFINE) {
+ if (node['type'] === 'MemberExpression') {
+ let loc = node['identifier']['loc'];
+ //search 不仅要search当前元素,还要单独search base. 另外搜多当前元素要把base带上
+ let nodeLoc1 = Location.create(this.docInfo["docUri"], loc);
+ let retBool = this.isInLocation(nodeLoc1, this.searchPosition);
+ if (retBool === true) {
+ //findout
+ let bname = this.baseProcess(node);
+ this.posSearchRet = this.createRetSymbol(bname.name, bname.isLocal);
+ }
+ //递归search base
+ let bname = this.MemberExpressionFind(node['base']);
+ if (bname.isInStat && bname.isInStat > 0) {
+ this.posSearchRet = this.createRetSymbol(bname.name, bname.isLocal);
+ }
+ //没找到
+ return this.createRetBase(bname.name, bname.isLocal, node['identifier']['name']);
+ }
+ }
+ }
+ //
+ private processIdentifier(node, type, deepLayer, prefix: string, baseInfo?, searchRes?) {
+ if (type === travelMode.GET_DEFINE) {
+ if (node['type'] === 'Identifier') {
+ if (baseInfo == undefined || baseInfo.name == undefined || baseInfo.name === '') {
+ baseInfo = { name: node["name"], isLocal: node['isLocal'] };
+ } else {
+ if(baseInfo.identiferStr){
+ baseInfo.name = baseInfo.name + '.' + baseInfo.identiferStr + '.' + node["name"];
+ }else{
+ baseInfo.name = baseInfo.name + '.' + node["name"];
+ }
+ }
+ //搜索
+ let nodeLoc1 = Location.create(this.docInfo["docUri"], node["loc"]);
+ if ( this.isInLocation(nodeLoc1, this.searchPosition) ) {
+ this.posSearchRet = this.createRetSymbol(baseInfo.name, baseInfo.isLocal);
+ }else{
+ this.posSearchRet = this.createRetBase(baseInfo.name, baseInfo.isLocal);
+ }
+ }
+ }
+
+ if (type === travelMode.FIND_REFS) {
+ if (node['type'] === 'Identifier') {
+ if (baseInfo == undefined || baseInfo.name == undefined || baseInfo.name === '') {
+ baseInfo = { name: node["name"], isLocal: node['isLocal'] };
+ } else {
+ if(baseInfo.identiferStr){
+ baseInfo.name = baseInfo.name + '.' + baseInfo.identiferStr + '.' + node["name"];
+ }else{
+ baseInfo.name = baseInfo.name + '.' + node["name"];
+ }
+ }
+
+ if(baseInfo.name == this.searchInfo.searchName){
+ let nodeLoc1 = Location.create(this.docInfo["docUri"], node["loc"]);
+ this.refsLink.push(nodeLoc1);
+ }
+ }
+ }
+ }
+
+ //二进制表达式,比如 i == 10000
+ private processBinaryExpression(node: Object, type, deepLayer: Array, prefix?: string) {
+ //search
+ if (type === travelMode.GET_DEFINE) {
+ this.traversalAST(node['left'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+
+ this.traversalAST(node['right'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+ //search
+ if (type === travelMode.FIND_REFS) {
+ this.traversalAST(node['left'], type, deepLayer, prefix);
+ this.traversalAST(node['right'], type, deepLayer, prefix);
+ }
+ }
+
+ private processUnaryExpression(node: Object, type, deepLayer: Array, prefix?: string) {
+ if (type === travelMode.GET_DEFINE) {
+ let argumentType = node['argument']['type'];
+ switch (argumentType) {
+ case 'Identifier':
+ this.processIdentifier(node['argument'], type, deepLayer, prefix);
+ break;
+ case 'LogicalExpression':
+ this.searchRvalueSymbals(node['argument']['left'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) break;
+ this.searchRvalueSymbals(node['argument']['right'], type, deepLayer, prefix);
+ break;
+ case 'IndexExpression':
+ this.processIndexExpression(node['argument'], type, deepLayer, prefix);
+ break;
+ case 'BinaryExpression':
+ this.processBinaryExpression(node['argument'], type, deepLayer, prefix);
+ break;
+ case 'CallExpression':
+ this.processCallExpression(node['argument'], type, deepLayer, prefix);
+ break;
+ case 'MemberExpression':
+ this.processMemberExpression(node['argument'], type, deepLayer, prefix);
+ break;
+ case 'UnaryExpression':
+ this.processUnaryExpression(node['argument'], type, deepLayer, prefix);
+ break;
+ }
+ if (this.posSearchRet && this.posSearchRet.isFindout) {
+ return;
+ }
+ }
+ }
+
+ // if中应该不会存在定义(除了body)
+ private processIfStatement(ASTNode: Object, type, deepLayer: Array, prefix?: string) {
+ let node = ASTNode['clauses'];
+ if (Array.isArray(node) === true) {
+ let ASTArray = Array.prototype.slice.call(node);
+ for (let idx = 0, len = ASTArray.length; idx < len; idx++) {
+ if (ASTArray[idx].type == 'IfClause' || ASTArray[idx].type == 'ElseifClause') {
+ //if ty1 then
+ if(ASTArray[idx]['condition']['type'] === 'Identifier'){
+ this.processIdentifier(ASTArray[idx]['condition'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) {
+ return;
+ }
+ }
+
+ if(ASTArray[idx]['condition']['type'] === 'LogicalExpression'){
+ let node = ASTArray[idx]['condition'];
+ this.searchRvalueSymbals(node['left'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return ;
+ this.searchRvalueSymbals(node['right'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ if(ASTArray[idx]['condition']['type'] === 'IndexExpression'){
+ this.processIndexExpression(ASTArray[idx]['condition'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ //判断二进制表达式有没有符号
+ if (ASTArray[idx]['condition']['type'] === 'BinaryExpression') {
+ this.processBinaryExpression(ASTArray[idx]['condition'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) {
+ return;
+ }
+ }
+
+ if(ASTArray[idx]['condition']['type'] === 'CallExpression'){
+ this.processCallExpression(ASTArray[idx]['condition'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) {
+ return;
+ }
+ }
+
+ if(ASTArray[idx]['condition']['type'] === 'MemberExpression'){
+ this.processMemberExpression(ASTArray[idx]['condition'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) {
+ return;
+ }
+ }
+
+ if(ASTArray[idx]['condition']['type'] === 'UnaryExpression'){
+ this.processUnaryExpression(ASTArray[idx]['condition'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) {
+ return;
+ }
+ }
+
+ //if body
+ this.traversalAST(ASTArray[idx].body, type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) {
+ return;
+ }
+ }
+
+ if (ASTArray[idx].type == 'ElseClause') {
+ //if body
+ this.traversalAST(ASTArray[idx].body, type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ // 处理return结构
+ private processReturnStatement(ASTNode: Object, type, deepLayer: Array, prefix?: string, isBody?:boolean) {
+ if (type === travelMode.GET_DEFINE) {
+ let node = ASTNode;
+ let varArray = Array.prototype.slice.call(node['arguments']);
+ for (let idx = 0; idx < varArray.length; idx++) {
+ this.traversalAST(varArray[idx], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+ }
+
+ if(type === travelMode.BUILD){
+ if(isBody == true){
+ //file retSymbol
+ if(ASTNode['arguments'].length == 1){
+ if(ASTNode['arguments'][0]['type'] === 'Identifier' ){
+ let name = ASTNode['arguments'][0]['name'];
+ //记录文件的返回值,因为文件路径不可能重名,直接查找并放置
+ this.docInfo.defineSymbols.chunks[this.docInfo.docPath].returnSymbol = name;
+ }
+ }
+ }else{
+ //function retSymbol
+ if(ASTNode['arguments'].length == 1){
+ if(ASTNode['arguments'][0]['type'] === 'Identifier' ){
+ let name = ASTNode['arguments'][0]['name'];
+ this.funcReturnRecoder = name;
+ }
+ }
+ }
+ }
+ }
+
+ //for k, v in pairs / ipairs
+ private processForGenericStatement(node: Object, type, deepLayer: Array, prefix?: string) {
+ // Logger.log('processForGenericStatement');
+ //body
+ this.traversalAST(node['body'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ // for i = 9 ; i + +
+ private processForNumericStatement(node: Object, type, deepLayer: Array, prefix?: string) {
+ // Logger.log('processForNumericStatement');
+ //body
+ this.traversalAST(node['body'], type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ //构建左值. 主要是定义. 返回值是base信息
+ //source 来源,填写1是来自于assign
+ private buildLvalueSymbals(node: Object, type, deepLayer: Array, prefix?: string, baseInfo?, isAssign? : number) {
+ let baseName = '';
+ let baseLocal = true;
+ let displayName = '';
+ let searchName = '';
+ if (node['type'] === 'Identifier') {
+ if (baseInfo == undefined) {
+ baseName = node["name"];
+ baseLocal = node["isLocal"];
+ displayName = node["name"];
+ } else {
+ baseLocal = baseInfo.isLocal; //设置花括号内的成员函数global / local 随base
+ baseName = baseInfo.name + '.' + node["name"];
+ displayName = baseName;
+ }
+
+ //区分 a = 9 情况下到底是赋值还是定义
+ searchName = baseName;
+ let isPush = true; //判断是否压入符号列表,因为全局变量赋值也是定义,所以要在这里做一下判断
+ if(isAssign == 1){
+ //如果来源于赋值操作,而且baseLocal == true , 那么一定是赋值 (local 的assign一定是赋值)
+ if( baseLocal ){
+ isPush = false;
+ }else{
+ // 全局表中是否存在
+ if(this.getGlobalSymbolsDic()[searchName] != undefined){
+ isPush = false;
+ }
+ }
+ }
+
+ if(isPush === true){
+ let loct = Location.create(this.docInfo["docUri"], Range.create(Position.create(node['loc']["start"]["line"] - 1, node['loc']["start"]["column"]), Position.create(node['loc']["end"]["line"] - 1, node['loc']["end"]["column"])));
+ let symb = this.createSymbolInfo(displayName, baseName, node["name"], SymbolKind.Variable, loct, baseLocal, prefix, deepLayer.concat());
+ this.pushToAutoList(symb);
+ }
+ return { name: baseName, isLocal: baseLocal };
+ }
+
+ if ('MemberExpression' === node['type']) {
+ let bname = this.baseProcess(node);
+ let rg = Location.create(this.docInfo["docUri"], Range.create(Position.create(node['loc']["start"]["line"] - 1, node['loc']["start"]["column"]), Position.create(node['loc']["end"]["line"] - 1, node['loc']["end"]["column"])));
+ baseName = bname.name;
+ baseLocal = bname.isLocal;
+ //检查符号是否已经存在,如果已存在就不是定义
+ if (this.checkIsSymbolExist(bname.name) === false) {
+ let symb = this.createSymbolInfo( bname.name, bname.name, node['identifier']['name'], SymbolKind.Variable, rg, bname.isLocal, prefix, deepLayer.concat());
+ this.pushToAutoList(symb);
+
+ }
+ return { name: baseName, isLocal: baseLocal };
+ }
+ else if('IndexExpression' === node['type']) {
+ // saved[valu] = 9; ==> saved.valu
+ //valu是一个变量,目前并不知道其值,所以无法做build操作,只能查找。
+ let baseInfo = this.baseProcess( node['base'] );
+ if( node['index'].type == 'StringLiteral' ){
+ let rg = Location.create(this.docInfo["docUri"], Range.create(Position.create(node['loc']["start"]["line"] - 1, node['loc']["start"]["column"]), Position.create(node['loc']["end"]["line"] - 1, node['loc']["end"]["column"])));
+ let displayName = baseInfo.name + '.' + node['index'].value ;
+ if (this.checkIsSymbolExist(displayName) === false) {
+ let symb = this.createSymbolInfo( displayName, displayName, node['index'].value, SymbolKind.Variable, rg, baseInfo.isLocal, prefix, deepLayer.concat());
+ this.pushToAutoList(symb);
+ }
+ }
+ return { name: baseInfo.name, isLocal: baseInfo.isLocal };
+ }
+ }
+
+ // 构建右值 | 处理 变量定义,赋值.
+ // local a = function() end
+ // a = { b = "c" }
+ private buildRvalueSymbals(node: Object, type: number, deepLayer: Array, prefix?: string, baseInfo?) {
+ if (node == undefined) return;
+ //构造table a = { b = "c" }
+ if (node['type'] === 'TableConstructorExpression') {
+ this.processTableConstructorExpression(node, type, deepLayer, prefix, baseInfo);
+ }
+
+ // 在处理右值的时候,如果是Identifier或者MemberExpression. 标记tag
+ if(node['type'] === 'Identifier'){
+ let info = {
+ reason: Tools.TagReason.Equal,
+ newType: node['name'],
+ location : node['loc'],
+ name : baseInfo.name
+ }
+ this.pushToCommentList(info);
+ }
+
+ if(node['type'] === 'MemberExpression'){
+ let bname = this.baseProcess(node);
+ let info = {
+ reason: Tools.TagReason.Equal,
+ newType: bname.name,
+ location : node['loc'],
+ name:baseInfo.name
+ }
+ this.pushToCommentList(info);
+ }
+
+ this.traversalAST(node, type, deepLayer, prefix);
+ // if (this.posSearchRet && this.posSearchRet.isFindout) {
+ // return;
+ // }
+ }
+
+ //搜索左值
+ private searchLvalueSymbals(node: Object, type, deepLayer: Array, prefix?: string, searchRes?, baseInfo?) {
+ let localBaseInfo = baseInfo;
+ if (node['type'] === 'Identifier') {
+ this.processIdentifier(node, type, deepLayer, prefix, localBaseInfo, searchRes);
+ //找到,返回
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ //未找到,继承baseInfo
+ if (this.posSearchRet && this.posSearchRet.isFindout === false) localBaseInfo = this.posSearchRet.baseinfo;
+ }
+
+ if (node['type'] === 'MemberExpression') {
+ this.processMemberExpression(node, type, deepLayer, prefix, localBaseInfo, searchRes);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ //未找到,继承baseInfo
+ if (this.posSearchRet && this.posSearchRet.isFindout === false) localBaseInfo = this.posSearchRet.baseinfo;
+ }
+
+ if(node['type'] === 'CallExpression'){
+ this.processCallExpression(node, type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ //未找到,继承baseInfo
+ if (this.posSearchRet && this.posSearchRet.isFindout === false) localBaseInfo = this.posSearchRet.baseinfo;
+
+ }
+ if(node['type'] === 'BinaryExpression'){
+ this.processBinaryExpression(node, type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ if (this.posSearchRet && this.posSearchRet.isFindout === false) localBaseInfo = this.posSearchRet.baseinfo;
+ }
+
+ if(node['type'] === 'IndexExpression'){
+ this.processIndexExpression(node, type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ if (this.posSearchRet && this.posSearchRet.isFindout === false) localBaseInfo = this.posSearchRet.baseinfo;
+ }
+
+ }
+
+ //搜索右值
+ private searchRvalueSymbals(node, type, deepLayer: Array, prefix?: string, baseInfo?, searchRes?) {
+ //右侧如果是Identifier, 不需要base
+ if (node['type'] === 'Identifier') {
+ this.processIdentifier(node, type, deepLayer, prefix, null, searchRes);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ if(node['type'] === 'MemberExpression'){
+ this.processMemberExpression(node, type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) {
+ return;
+ }
+ }
+
+ //右侧如果是{ } , 构造table ,需要base
+ if (node['type'] === 'TableConstructorExpression') {
+ this.processTableConstructorExpression(node, type, deepLayer, prefix, baseInfo);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ if (node.type === 'CallExpression') {
+ this.traversalAST(node, type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ //traversalAST
+ if (node.type === 'FunctionDeclaration') {
+ this.traversalAST(node, type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ // indent = indent or ""
+ if(node.type === 'LogicalExpression'){
+ this.searchRvalueSymbals(node['left'], type, deepLayer, prefix, baseInfo, searchRes);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ this.searchRvalueSymbals(node['right'], type, deepLayer, prefix, baseInfo, searchRes);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ // cart = cart .. indent .. field
+ if(node.type === 'BinaryExpression'){
+ this.searchRvalueSymbals(node['left'], type, deepLayer, prefix, baseInfo, searchRes);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ this.searchRvalueSymbals(node['right'], type, deepLayer, prefix, baseInfo, searchRes);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ //a = b['index']
+ if(node['type'] === 'IndexExpression'){
+ this.processIndexExpression(node, type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) return;
+ }
+
+ // a = not b
+ if(node['type'] === 'UnaryExpression'){
+ this.processUnaryExpression(node, type, deepLayer, prefix);
+ if (this.posSearchRet && this.posSearchRet.isFindout) {
+ return;
+ }
+ }
+ }
+
+}
+
+
diff --git a/src/code/server/server.ts b/src/code/server/server.ts
new file mode 100755
index 0000000..5cca424
--- /dev/null
+++ b/src/code/server/server.ts
@@ -0,0 +1,411 @@
+// 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.
+
+//第三方npm引用
+import {
+ createConnection,
+ TextDocuments,
+ TextDocument,
+ // Diagnostic,
+ // DiagnosticSeverity,
+ ProposedFeatures,
+ InitializeParams,
+ DidChangeConfigurationNotification,
+ CompletionItem,
+ SymbolInformation,
+ TextDocumentPositionParams,
+ DocumentSymbolParams,
+ Definition, //定义跳转
+ WorkspaceSymbolParams,//folder 符号
+ DocumentHighlight,
+ ColorInformation,
+ DocumentColorParams,
+ ColorPresentationParams,
+ ColorPresentation,
+ // SignatureHelp,
+ ReferenceParams,
+ DocumentSymbol
+} from 'vscode-languageserver';
+let dir = require('path-reader');
+let path = require('path'); /*nodejs自带的模块*/
+import * as Tools from "./codeTools";
+import { Logger } from './codeLogManager';
+import { CodeSymbol } from './codeSymbol';
+import { CodeDefinition } from './codeDefinition';
+import { CodeCompleting } from './codeCompleting';
+import { CodeEditor } from './codeEditor';
+import { CodeLinting } from './codeLinting';
+import { CodeReference } from './codeReference';
+
+
+// Create a connection for the server. The connection uses Node's IPC as a transport.
+// Also include all preview / proposed LSP features.
+let connection = createConnection(ProposedFeatures.all);
+let documents: TextDocuments = new TextDocuments();
+let hasConfigurationCapability: boolean = false;
+let hasWorkspaceFolderCapability: boolean = false;
+// let hasDiagnosticRelatedInformationCapability: boolean = false;
+
+// The settings
+export interface LuaAnalyzerSettings {
+ codeLinting: {
+ enable : boolean;
+ luacheckPath : string;
+ luaVersion : string;
+ checkWhileTyping : boolean;
+ checkAfterSave : boolean,
+ maxNumberOfProblems : number;
+ maxLineLength : number;
+ ignoreFolderRegularExpression: string,
+ ignoreErrorCode : string,
+ ignoreGlobal : string;
+ };
+}
+
+// The global settings, used when the `workspace/configuration` request is not supported by the client.
+// Please note that this is not the case when using this server with the client provided in this example
+// but could happen with other clients.
+const defaultSettings: LuaAnalyzerSettings = {
+ codeLinting: {
+ enable : true,
+ luacheckPath : "",
+ luaVersion : "5.1",
+ checkWhileTyping : true,
+ checkAfterSave : true,
+ maxNumberOfProblems : 100,
+ maxLineLength : 120,
+ ignoreFolderRegularExpression: ".*/res/lua/\w+\.lua;",
+ ignoreErrorCode : "",
+ ignoreGlobal : "",
+ }
+};
+let globalSettings: LuaAnalyzerSettings = defaultSettings;
+// Cache the settings of all open documents
+let documentSettings: Map> = new Map();
+
+//-----------------------------------------------------------------------------
+//-- connection 时序
+//-----------------------------------------------------------------------------
+// 建立连接,初始化数据和设置能力项
+connection.onInitialize((initPara: InitializeParams) => {
+ let capabilities = initPara.capabilities;
+ Tools.setInitPara(initPara);
+ Tools.setToolsConnection(connection);
+ Logger.connection = connection;
+
+ Logger.DebugLog(Tools.getInitPara().rootPath);
+
+ // Does the client support the `workspace/configuration` request?
+ // If not, we will fall back using global settings
+ hasConfigurationCapability = !!(capabilities.workspace && !!capabilities.workspace.configuration);
+ hasWorkspaceFolderCapability = !!(capabilities.workspace && !!capabilities.workspace.workspaceFolders);
+ // hasDiagnosticRelatedInformationCapability =
+ // !!(capabilities.textDocument &&
+ // capabilities.textDocument.publishDiagnostics &&
+ // capabilities.textDocument.publishDiagnostics.relatedInformation);
+
+ // 清空loadedExt, 初始化 name - uri 对应 cache
+ Tools.initLoadedExt();
+ createSybwithExt('lua', Tools.getInitPara().rootPath);
+ createSybwithExt('lua.bytes', Tools.getInitPara().rootPath);
+ // 异步执行,建立uri -> 完整路径对应表
+ setTimeout(Tools.refresh_FileName_Uri_Cache, 0);
+ // 分析默认位置(扩展中)的lua文件
+ let resLuaPath = path.dirname(__dirname) + '/../../res/lua'; //安装插件后地址
+ CodeSymbol.refreshPreLoadSymbals(resLuaPath);
+
+ Logger.DebugLog("init success");
+ return {
+ capabilities: {
+ //符号分析
+ documentSymbolProvider: true,
+ workspaceSymbolProvider: true,
+ //定义分析
+ definitionProvider: true,
+ //引用分析
+ referencesProvider: false,
+ //代码格式化
+ documentFormattingProvider: true,
+ documentRangeFormattingProvider: false,
+ //代码选中高亮
+ documentHighlightProvider: false,
+ //文档同步
+ textDocumentSync: documents.syncKind,
+ //自动补全
+ completionProvider: {
+ triggerCharacters:['.', '-', ':'],
+ resolveProvider: false
+ },
+ //重命名
+ renameProvider : false,
+ //函数签名提示
+ // signatureHelpProvider:{
+ // triggerCharacters: [ '(' ],
+ // },
+ //代码上色
+ colorProvider : false,
+ }
+ };
+});
+
+connection.onInitialized(() => {
+ if (hasConfigurationCapability) {
+ connection.client.register(
+ DidChangeConfigurationNotification.type,
+ undefined
+ );
+ }
+ if (hasWorkspaceFolderCapability) {
+ connection.workspace.onDidChangeWorkspaceFolders(_event => {
+ Logger.DebugLog('Workspace folder change event received.');
+ });
+ }
+ connection.sendNotification("setRootFolder", Tools.getInitPara().rootPath);
+
+});
+
+//这是个干嘛的?
+connection.onDidChangeConfiguration(change => {
+ if (hasConfigurationCapability) {
+ // Reset all cached document settings
+ documentSettings.clear();
+ } else {
+ globalSettings = (
+ (change.settings.lua_analyzer || defaultSettings)
+ );
+ }
+ // Revalidate all open text documents
+ documents.all().forEach(validateTextDocument);
+});
+
+// Only keep settings for open documents
+documents.onDidClose(e => {
+ documentSettings.delete(e.document.uri);
+});
+
+// 代码自动补全
+connection.onCompletion(
+ (_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
+ let uri = Tools.urlDecode(_textDocumentPosition.textDocument.uri);
+ let pos = _textDocumentPosition.position;
+ // try{
+ return CodeCompleting.getCompletingArray(uri, pos);
+ // } catch (error) {
+ // Logger.InfoLog(error.stack);
+ // }
+ }
+);
+
+// 查找符号引用
+connection.onReferences(
+ (handler : ReferenceParams): any =>{
+ return CodeReference.getSymbalReferences(handler);
+ }
+);
+
+// 查找符号定义
+connection.onDefinition(
+ (handler: TextDocumentPositionParams): Definition => {
+ handler.textDocument.uri = Tools.urlDecode(handler.textDocument.uri);
+ // try{
+ return CodeDefinition.getSymbalDefine(handler);
+ // } catch (error) {
+ // Logger.InfoLog(error.stack);
+ // }
+ }
+);
+
+//获取单文件内的符号
+connection.onDocumentSymbol(
+ (handler: DocumentSymbolParams): DocumentSymbol[] => {
+ let uri = handler.textDocument.uri;
+ let decUri = Tools.urlDecode(uri);
+ let retSyms = CodeSymbol.getCertainDocSymbolsReturnArray(decUri, null, Tools.SearchRange.AllSymbols);
+ let retSymsArr: any[];
+ try {
+ retSymsArr = Tools.getOutlineSymbol(retSyms);
+ }
+ catch(error) {
+ // 处理层级关系出现错误时退化为原有的不分层显示
+ Logger.DebugLog("error detected while processing outline symbols, error: " + error + "\nstack:\n" + error.stack);
+ retSymsArr = Tools.changeDicSymboltoArray(retSyms);
+ }
+ return retSymsArr;
+ }
+);
+
+//获取整个工程文件夹的符号
+connection.onWorkspaceSymbol(
+ (handler: WorkspaceSymbolParams): SymbolInformation[] => {
+ // try{
+ return CodeSymbol.searchSymbolinWorkSpace(handler.query, Tools.SearchMode.FuzzyMatching, Tools.SearchRange.LocalSymbols);
+ // } catch (error) {
+ // Logger.InfoLog(error.stack);
+ // }
+ }
+);
+
+// 打开单文件
+documents.onDidOpen(file => {
+ // 异步分析工程中同后缀文件
+ if (file.document.languageId == "lua") { //本文件是lua形式
+ let uri = Tools.urlDecode(file.document.uri);
+ let luaExtname = Tools.getPathNameAndExt(uri);
+ let ext = luaExtname['ext'];
+ let loadedExt = Tools.getLoadedExt();
+ if (loadedExt && loadedExt[ext] === true) {
+ //把文件名和路径放入cache
+ // Tools.AddTo_FileName_Uri_Cache( luaExtname['name'], uri);
+ return;
+ }else{
+ // 处理新的后缀类型
+ createSybwithExt(ext, Tools.getInitPara().rootPath);
+ setTimeout(Tools.refresh_FileName_Uri_Cache, 0);
+ }
+ }
+});
+
+// 文件内容发生改变(首次打开文件时这个方法也会被调用)
+documents.onDidChangeContent(change => {
+ if(change.document.languageId == 'lua'){
+ const uri = Tools.urlDecode(change.document.uri);
+ const text = change.document.getText();
+ CodeEditor.saveCode(uri, text); //先保存代码
+ CodeSymbol.refreshCertainDocSymbols(uri, text);
+
+ // 运行语法检查
+ getDocumentSettings(uri).then(
+ (settings) => {
+ if (settings.codeLinting.checkWhileTyping == true) {
+ validateTextDocument(change.document);
+ }
+ }
+ );
+ }
+});
+
+// 保存文件
+documents.onDidSave(change => {
+ // try {
+ // 运行语法检查
+ getDocumentSettings(change.document.uri).then(
+ (settings) => {
+ if (settings.codeLinting.checkAfterSave == true) {
+ validateTextDocument(change.document);
+ }
+ }
+ );
+ // } catch (error) {
+ // Logger.InfoLog(error.stack);
+ // }
+});
+
+//-----------------------------------------------------------------------------
+//-- 未实现能力
+//-----------------------------------------------------------------------------
+// 代码着色
+connection.onDocumentColor(
+ (handler: DocumentColorParams): ColorInformation[] =>{
+ return new Array();
+ }
+);
+
+connection.onColorPresentation(
+ (handler: ColorPresentationParams):ColorPresentation[] =>{
+ return new Array();
+ }
+);
+
+//代码单击高亮
+connection.onDocumentHighlight (
+ (handler: TextDocumentPositionParams) : DocumentHighlight[] =>{
+ // console.log("onDocumentHighlight");
+ return new Array();
+ }
+);
+
+
+//-----------------------------------------------------------------------------
+//-- 工具方法
+//-----------------------------------------------------------------------------
+function getDocumentSettings(resource: string): Thenable {
+ if (!hasConfigurationCapability) {
+ return Promise.resolve(globalSettings);
+ }
+ let result = documentSettings.get(resource);
+ if (!result) {
+ result = connection.workspace.getConfiguration({
+ scopeUri: resource,
+ section: 'lua_analyzer'
+ });
+ documentSettings.set(resource, result);
+ }
+ return result;
+}
+
+async function validateTextDocument(textDocument: TextDocument): Promise {
+ let settings = await getDocumentSettings(textDocument.uri);
+
+ // 如果总开关未打开,无论从哪里调用validateTextDocument都不执行语法检查直接返回
+ if (settings.codeLinting.enable == false) {
+ // 清空诊断输出
+ connection.sendDiagnostics({ uri: textDocument.uri, diagnostics: [] });
+ return;
+ }
+
+ // 处理忽略文件
+ let ignoreFolderRegExpArray = settings.codeLinting.ignoreFolderRegularExpression.split(';');
+ if (ignoreFolderRegExpArray.length > 0) {
+ if (Tools.isMatchedIgnoreRegExp(textDocument.uri, ignoreFolderRegExpArray)) {
+ // 清空诊断输出
+ connection.sendDiagnostics({ uri: textDocument.uri, diagnostics: [] });
+ return;
+ }
+ }
+
+ // let globalSymbols = CodeSymbol.getRequireTreeGlobalSymbols(Tools.urlDecode(textDocument.uri));
+ let globalSymbols = CodeSymbol.getWorkspaceSymbols(Tools.SearchRange.GlobalSymbols);
+ let globalVariables: string[] = Object.keys(globalSymbols);
+
+ let luacheckProcess: Promise<{}> = CodeLinting.processLinting(textDocument, settings, globalVariables);
+ luacheckProcess.then(
+ () => {
+ connection.sendDiagnostics({ uri: textDocument.uri, diagnostics: [] });
+ },
+ luaErrorOrWaining => {
+ const diagnosticArray = CodeLinting.parseLuacheckResult(luaErrorOrWaining, settings);
+ connection.sendDiagnostics({ uri: textDocument.uri, diagnostics: diagnosticArray });
+ }
+ )
+ .catch(() => {
+ connection.sendDiagnostics({ uri: textDocument.uri, diagnostics: [] });
+ });
+}
+
+//创建指定后缀的lua文件的符号
+function createSybwithExt(luaExtname: string, rootpath: string) {
+ //记录此后缀代表lua
+ Tools.setLoadedExt(luaExtname);
+ //解析workSpace中同后缀文件
+ let exp = new RegExp(luaExtname + '$', "i");
+ dir.readFiles(rootpath, { match: exp }, function (err, content, filePath, next) {
+ if (!err) {
+ CodeSymbol.getCertainDocSymbolsReturnArray(Tools.pathToUri(filePath), content);
+ }
+ next();
+ }, (err) => {
+ if (err) {
+ return;
+ }
+ });
+}
+
+// Make the text document manager listen on the connection
+// for open, change and close text document events
+documents.listen(connection);
+
+// Listen on the connection
+connection.listen();
diff --git a/src/code/server/typeInfer.ts b/src/code/server/typeInfer.ts
new file mode 100644
index 0000000..8775cf1
--- /dev/null
+++ b/src/code/server/typeInfer.ts
@@ -0,0 +1,246 @@
+// 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.
+
+//这个文件中要处理的主要是tag类型查找
+//包含 前缀的去除 , 查找, 补回查找
+import * as Tools from './codeTools';
+import { CodeSymbol } from "./codeSymbol";
+// import { Logger } from './codeLogManager';
+
+//类型推断文件
+export class TypeInfer {
+//-----------------------------------------------------------------------------
+//-- 对外接口
+//-----------------------------------------------------------------------------
+ // 定义查找接口
+ public static processDefineSymbolTag(symbolInfo, uri){
+ return this.recursiveProcessSymbolTag(symbolInfo, uri, '', new Array());
+ }
+
+ // 自动补全接口
+ public static processCompleting(prefixStr, uri){
+ let sy = {
+ containerURI: uri,
+ isLocal: false,
+ location: null,
+ name: prefixStr
+ }
+ return this.recursiveProcessSymbolTag(sy, uri, '', new Array());
+ }
+
+//-----------------------------------------------------------------------------
+//-- 私有方法
+//-----------------------------------------------------------------------------
+ // 处理函数返回值 | element是赋值的符号 , a = func() element是a的符号
+ private static processFunctionReturn(element, symbolInfo, uri, prefixStrList, alreadySearchNameList, SCHName){
+ let returnFuncList = CodeSymbol.searchSymbolinDoc(uri , SCHName ,Tools.SearchMode.ExactlyEqual);
+ if (returnFuncList == null || ( returnFuncList && returnFuncList.length <= 0) ){
+ returnFuncList = CodeSymbol.searchAllSymbolinRequireTreeforCompleting(uri ,SCHName ,Tools.SearchMode.ExactlyEqual);
+ }
+
+ let retrunSymbol = new Array();
+ if(returnFuncList && returnFuncList.length > 0){
+ for (let index = 0; index < returnFuncList.length; index++) {
+ // 遍历所有的函数,并在函数中查找返回类型
+ const retFuncSymbol = returnFuncList[index];
+ if( retFuncSymbol['funcRets'] ){
+ let tag_type = retFuncSymbol['funcRets'];
+ //根据函数定义符号记录的返回类型,找到返回变量符号
+ // let tmpSymbol = CodeSymbol.searchSymbolinWorkSpace(tag_type, Tools.SearchMode.ExactlyEqual);
+ symbolInfo.name = tag_type.name + prefixStrList;
+ let tmpSymbol = this.recursiveProcessSymbolTag( symbolInfo, uri, '', alreadySearchNameList);
+ //找到了返回符号,但是要过滤深度(仅查找对应函数中的符号)
+ // tmpSymbol = CodeSymbol.selectSymbolinCertainContainer(tmpSymbol, retFuncSymbol.containerList);
+ if(tmpSymbol){
+ retrunSymbol = retrunSymbol.concat(tmpSymbol);
+ }
+ }
+ }
+ return retrunSymbol;
+ }else{
+ //等式右边的符号无法被直接搜索到
+ symbolInfo.name = element.funcRets['name'];
+ retrunSymbol = this.recursiveProcessSymbolTag( symbolInfo, uri, '', alreadySearchNameList);
+ if(prefixStrList){
+ symbolInfo.name = symbolInfo.name + prefixStrList;
+ retrunSymbol = this.recursiveProcessSymbolTag( symbolInfo, uri, '', alreadySearchNameList);
+ }
+
+ return retrunSymbol;
+ }
+ }
+
+ // 处理用户标记
+ private static processUserTag(element, symbolInfo, uri, prefixStrList, alreadySearchNameList, userInputTxt, SCHName){
+ let tag_type = element.tagType;
+ // let tag_reason = element.tagReason;
+ // let reqFile = element.requireFile;
+ let checkName = '';
+
+ checkName = tag_type.replace(/\s/g, '.');
+ symbolInfo.name = checkName;
+ let tx = this.recursiveProcessSymbolTag( symbolInfo, uri, prefixStrList, alreadySearchNameList);
+ return tx;
+ }
+
+ // 处理元表标记
+ private static processMetaTable(element, symbolInfo, uri, prefixStrList, alreadySearchNameList, userInputTxt, SCHName){
+ //含有tagType,在tagType中查
+ // let tag_type = element.tagType;
+ let tag_reason = element.tagReason;
+ // let reqFile = element.requireFile;
+ let checkName = '';
+
+ if(tag_reason == Tools.TagReason.MetaTable){
+ checkName = element.tagType + ".__index";
+ }
+
+ symbolInfo.name = checkName;
+ let indexDefList = this.recursiveProcessSymbolTag( symbolInfo, uri, prefixStrList, alreadySearchNameList);
+ if( indexDefList && indexDefList.length > 0 ){
+ //过滤
+ indexDefList = CodeSymbol.selectSymbolinCertainContainer(indexDefList, element.containerList);
+ let retrunSymbol = new Array();
+ for (let index = 0; index < indexDefList.length; index++) {
+ const indexSymbol = indexDefList[index];
+ if(indexSymbol.tagType){
+ symbolInfo.name = indexSymbol.tagType;
+ let tmpSymbol = this.recursiveProcessSymbolTag( symbolInfo, uri, prefixStrList, alreadySearchNameList);
+ if(tmpSymbol){
+ retrunSymbol = retrunSymbol.concat(tmpSymbol);
+ }
+ }
+ else if(indexSymbol.searchName.match(/__index/)){
+ //若查找的字符串中包含__index
+ retrunSymbol = retrunSymbol.concat(indexSymbol);
+
+ }
+ }
+ return retrunSymbol;
+ }
+ }
+
+ // 处理引用标记
+ private static processRequire(element, symbolInfo, uri, prefixStrList, alreadySearchNameList, checkName, SCHName){
+ //到对应的文件中查一下return,找到后当做 userTag处理
+ uri = Tools.transFileNameToUri(element.requireFile);
+ let retTag = CodeSymbol.getCertainDocReturnValue(uri);
+ if(retTag && retTag.length > 0){
+ let tag_type = retTag;
+ // let tag_reason = Tools.TagReason.UserTag;
+ let reqFile = element.requireFile;
+
+ checkName = tag_type; // a.b => tag
+ let uri = Tools.transFileNameToUri(reqFile);
+ let finalSymbs = CodeSymbol.searchSymbolinDoc(uri, checkName, Tools.SearchMode.ExactlyEqual);
+ return finalSymbs;
+ }
+ }
+
+ // 递归核心推导方法 | 处理符号的tag。要求:可以查找符号链。不要返回相同的符号
+ // symbInstance 保存最终结果,并返回给用户的符号
+ // symbolInfo 用户输入的(被查找的)符号信息
+ // prefixStr 搜索的前缀信息List
+ // alreadySearchNameList 以查找过的符号列表
+ private static recursiveProcessSymbolTag(symbolInfo, uri, prefixStrList, alreadySearchNameList){
+ // 防止循环遍历
+ // let alreadySearchLen = alreadySearchNameList.length;
+ // const element = alreadySearchNameList[alreadySearchLen - 1];
+ // if(element == symbolInfo.name ){
+ // return;
+ // }
+ // // Logger.ErrorLog("recursiveProcessSymbolTag : " + symbolInfo.name);
+ // alreadySearchNameList.push(symbolInfo.name);
+ //防止循环遍历--
+
+ let findTagRetSymbArray
+ findTagRetSymbArray = CodeSymbol.searchSymbolinDoc(uri , symbolInfo.name ,Tools.SearchMode.ExactlyEqual);
+ if (findTagRetSymbArray == null || (findTagRetSymbArray &&findTagRetSymbArray.length <= 0)){
+ findTagRetSymbArray = CodeSymbol.searchAllSymbolinRequireTreeforCompleting(uri ,symbolInfo.name, Tools.SearchMode.ExactlyEqual);
+ }
+ if(findTagRetSymbArray && findTagRetSymbArray.length > 0) return findTagRetSymbArray;
+
+ //切断用户输入
+ let userInputTxt = symbolInfo.name;
+ let DotToBlankArr = Tools.splitToArrayByDot(userInputTxt);
+ let preStr = ''
+ //a.b.c -> a.b -> a 查找tag 递减缩减查找tag
+ for (let index = DotToBlankArr.length - 1; index >= 0; index--) {
+ //先把第一个参数pop
+ preStr = "." + DotToBlankArr.pop() + preStr ;
+ //确定要查找的符号名
+ let SCHName = DotToBlankArr.join('.');
+
+ // 先搜索本文件,如果找不到再搜索调用树
+ let findTagRetSymbArray
+ findTagRetSymbArray = CodeSymbol.searchSymbolinDoc(uri , SCHName ,Tools.SearchMode.ExactlyEqual);
+ if (findTagRetSymbArray == null || (findTagRetSymbArray &&findTagRetSymbArray.length <= 0)){
+ findTagRetSymbArray = CodeSymbol.searchAllSymbolinRequireTreeforCompleting(uri ,SCHName, Tools.SearchMode.ExactlyEqual);
+ }
+
+ //没找到,继续pop
+ if(!findTagRetSymbArray || findTagRetSymbArray.length == 0) continue;
+
+ //找到了用户输入的符号
+ //没有找到需要的符号,遍历判断符号是否有 require, function ret, tag 标记
+ if(findTagRetSymbArray && findTagRetSymbArray.length > 0){
+ let MaxFor = findTagRetSymbArray.length > 10 ? 1: findTagRetSymbArray.length; //对搜索结果过多的保护
+ for (let ix = MaxFor - 1; ix >= 0 ; ix--) {
+ const element = findTagRetSymbArray[ix];
+ //搜索tag
+ let findoutSymbs;
+ if(element.tagType && (element.tagReason === Tools.TagReason.UserTag || element.tagReason === Tools.TagReason.Equal) ){ //USERTag
+ findoutSymbs = this.processUserTag(element, symbolInfo, uri, prefixStrList, alreadySearchNameList, userInputTxt, SCHName);
+ }else if(element.tagType && element.tagReason == Tools.TagReason.MetaTable ){
+ findoutSymbs = this.processMetaTable(element, symbolInfo, uri, prefixStrList, alreadySearchNameList, userInputTxt, SCHName);
+ }else if(element.requireFile && element.requireFile.length > 0){ //Require
+ let checkName = DotToBlankArr.join('.');
+ findoutSymbs = this.processRequire(element, symbolInfo, uri, prefixStrList, alreadySearchNameList, checkName, SCHName);
+ }else if(element.funcRets){
+ findoutSymbs = this.processFunctionReturn(element, symbolInfo, uri, preStr, alreadySearchNameList, SCHName)
+ //funcReturnSymbol 如果有prefix ,拼起来再找,没有prefix就找到了
+ }else if(element.chunk && element.chunk.returnSymbol){
+ let chunkRet = element.chunk.returnSymbol;
+ findoutSymbs = CodeSymbol.searchAllSymbolinRequireTreeforCompleting(uri ,chunkRet, Tools.SearchMode.ExactlyEqual);
+ }
+
+ //已经拿到了符号, 有preStr
+ if(findoutSymbs && findoutSymbs.length > 0 && preStr.length > 0){
+ let MaxFor2 = findoutSymbs.length > 10 ? 1: findoutSymbs.length;
+ for (let findoutSymIdx = 0; findoutSymIdx < MaxFor2; findoutSymIdx++) {
+ if(!findoutSymbs[findoutSymIdx]) continue;
+ let chkName = '';
+ if( !element.funcRets ){
+ chkName = findoutSymbs[findoutSymIdx].searchName + preStr ; //拼出完整的符号
+ }else{
+ if( element.funcRets.name == "require"){
+ chkName = findoutSymbs[findoutSymIdx].searchName + preStr ; //拼出完整的符号
+ }else{
+ chkName = findoutSymbs[findoutSymIdx].searchName;
+ }
+ }
+
+ //防止死循环
+ if(chkName == userInputTxt){
+ continue;
+ }
+
+ let sy = {
+ containerURI: findoutSymbs[findoutSymIdx].containerURI,
+ isLocal: findoutSymbs[findoutSymIdx].isLocal,
+ location: null,
+ name: chkName
+ }
+
+ let ret = this.recursiveProcessSymbolTag(sy , uri, '', alreadySearchNameList);
+ if(ret) return ret;
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/LogManager.ts b/src/common/LogManager.ts
similarity index 100%
rename from src/LogManager.ts
rename to src/common/LogManager.ts
diff --git a/src/StatusBarManager.ts b/src/common/StatusBarManager.ts
similarity index 58%
rename from src/StatusBarManager.ts
rename to src/common/StatusBarManager.ts
index 938495f..fd175f9 100644
--- a/src/StatusBarManager.ts
+++ b/src/common/StatusBarManager.ts
@@ -3,10 +3,17 @@ import * as vscode from 'vscode';
export class StatusBarManager {
private static MemStateBar;
+ private static Setting;
+
public static init() {
this.MemStateBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 5.0);
this.MemStateBar.tooltip = "Click to collect garbage";
this.MemStateBar.command = 'luapanda.LuaGarbageCollect';
+
+ this.Setting = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 6.0);
+ this.Setting.tooltip = "Click open setting page";
+ this.Setting.command = 'luapanda.openSettingsPage';
+ this.Setting.hide();
}
//刷新内存数据显示区的值
@@ -15,6 +22,12 @@ export class StatusBarManager {
this.MemStateBar.show();
}
+ //刷新内存数据显示区的值
+ public static showSetting(message: string) {
+ this.Setting.text = message;
+ this.Setting.show();
+ }
+
//按钮恢复到初始状态
public static reset() {
diff --git a/src/Tools.ts b/src/common/Tools.ts
similarity index 82%
rename from src/Tools.ts
rename to src/common/Tools.ts
index 71b6dec..6d83809 100644
--- a/src/Tools.ts
+++ b/src/common/Tools.ts
@@ -1,16 +1,56 @@
import * as vscode from 'vscode';
+import { DebugLogger } from './logManager';
+import * as fs from "fs";
import { isArray } from 'util';
let path = require("path");
let pathReader = require('path-reader');
-import { DebugLogger } from './LogManager';
export class Tools {
public static extMap = new Object(); // 可处理的文件后缀列表
- public static fileNameToPathMap; // 文件名-路径Map
+ public static fileNameToPathMap; // 文件名-路径 Map
public static useAutoPathMode = false;
public static pathCaseSensitivity = false;
+ public static adapterVersion; //赋值放在了插件初始化时
+ public static VSCodeOpenedFolder; // VSCode当前打开的用户工程路径。打开文件夹后,由languageServer赋值
+ public static luapandaPathInUserProj; // 用户工程中luapanda文件所在的路径,它在调试器启动时赋值。但也可能工程中不存在luapanda文件导致路径为空
+ public static VSCodeExtensionPath; // VSCode插件所在路径,插件初始化时就会被赋值
+
+ // 路径相关函数
+ // 获取扩展中预置的lua文件位置
+ public static getLuaPathInExtension() : string{
+ let luaPathInVSCodeExtension = this.VSCodeExtensionPath + "/Debugger/LuaPanda.lua";
+ return luaPathInVSCodeExtension;
+ }
+
+ // 获取扩展中预置的lua文件位置
+ public static getClibPathInExtension() : string{
+ let ClibPathInVSCodeExtension = this.VSCodeExtensionPath + "/Debugger/debugger_lib/plugins/";
+ return ClibPathInVSCodeExtension;
+ }
+
+ // 读文本文件内容
+ // @path 文件路径
+ // @return 文件内容
+ public static readFileContent(path: string): string {
+ if(path === '' || path == undefined){
+ return '';
+ }
+ let data = fs.readFileSync(path);
+ let dataStr = data.toString();
+ return dataStr;
+ }
+
+ // 写文件内容
+ // @path 文件路径
+ // @return 文件内容
+ public static writeFileContent(path: string, content:string) {
+ if(path === '' || path == undefined){
+ return;
+ }
+ fs.writeFileSync(path, content);
+ }
- // 把传入的路径标准路径
+ // 把传入的路径转为标准路径
public static genUnifiedPath(beProcessPath) : string{
//全部使用 /
beProcessPath = beProcessPath.replace(/\\/g, '/');
@@ -76,8 +116,7 @@ export class Tools {
}
}
- //建立/刷新 工程下 文件名-路径Map
- // 评估执行效率,这个函数可以考虑应该区分同步,以优化体验
+ // 建立/刷新 工程下文件名-路径Map
public static rebuildWorkspaceNamePathMap(rootPath : string){
let beginMS = this.getCurrentMS();//启动时毫秒数
let _fileNameToPathMap = new Array(); // 文件名-路径 cache
@@ -128,13 +167,13 @@ export class Tools {
this.fileNameToPathMap = _fileNameToPathMap;
}
- //获取当前毫秒数
+ // 获取当前毫秒数
public static getCurrentMS(){
- var currentMS = new Date();//获取当前时间
+ let currentMS = new Date();//获取当前时间
return currentMS.getTime();
}
- // 检查同名文件
+ // 检查同名文件, 如果存在,通过日志输出
public static checkSameNameFile(){
let sameNameFileStr;
for (const nameKey in this.fileNameToPathMap) {
@@ -159,7 +198,7 @@ export class Tools {
// 从URI分析出文件名和后缀
public static getPathNameAndExt(UriOrPath): Object{
let name_and_ext = path.basename(UriOrPath).split('.');
- let name = name_and_ext[0]; //文件名
+ let name = name_and_ext[0]; //文件名
let ext = name_and_ext[1] || ''; //文件后缀
for (let index = 2; index < name_and_ext.length; index++) {
ext = ext + '.' + name_and_ext[index];
@@ -210,4 +249,4 @@ export class Tools {
DebugLogger.showTips("调试器没有找到文件 " + shortPath + " 。 请检查launch.json文件中lua后缀是否配置正确, 以及VSCode打开的工程是否正确", 2);
return shortPath;
}
-}
+}
\ No newline at end of file
diff --git a/src/BreakPoint.ts b/src/debug/BreakPoint.ts
similarity index 100%
rename from src/BreakPoint.ts
rename to src/debug/BreakPoint.ts
diff --git a/src/dataProcesser.ts b/src/debug/dataProcesser.ts
similarity index 99%
rename from src/dataProcesser.ts
rename to src/debug/dataProcesser.ts
index 3f5ee1e..fd3e9a7 100644
--- a/src/dataProcesser.ts
+++ b/src/debug/dataProcesser.ts
@@ -1,6 +1,6 @@
import { LuaDebugRuntime } from './luaDebugRuntime';
import { Socket } from 'net';
-import { DebugLogger } from './LogManager';
+import { DebugLogger } from '../common/logManager';
import { LuaDebugSession } from './luaDebug';
//网络收发消息,记录回调
diff --git a/src/debugAdapter.ts b/src/debug/debugAdapter.ts
similarity index 100%
rename from src/debugAdapter.ts
rename to src/debug/debugAdapter.ts
diff --git a/src/luaDebug.ts b/src/debug/luaDebug.ts
similarity index 97%
rename from src/luaDebug.ts
rename to src/debug/luaDebug.ts
index 70de590..2ace210 100755
--- a/src/luaDebug.ts
+++ b/src/debug/luaDebug.ts
@@ -17,10 +17,12 @@ import { LuaDebugRuntime, LuaBreakpoint } from './luaDebugRuntime';
const { Subject } = require('await-notify');
import * as Net from 'net';
import { DataProcesser } from './dataProcesser';
-import { DebugLogger } from './LogManager';
-import { StatusBarManager } from './StatusBarManager';
-import { LineBreakpoint, ConditionBreakpoint, LogPoint } from './BreakPoint';
-import { Tools } from './Tools';
+import { DebugLogger } from '../common/logManager';
+import { StatusBarManager } from '../common/statusBarManager';
+import { LineBreakpoint, ConditionBreakpoint, LogPoint } from './breakpoint';
+import { Tools } from '../common/tools';
+import { UpdateManager } from './updateManager';
+
export class LuaDebugSession extends LoggingDebugSession {
public static isNeedB64EncodeStr: boolean = true;
private static THREAD_ID = 1; //调试器不支持多线程,硬编码THREAD_ID为1
@@ -138,15 +140,18 @@ export class LuaDebugSession extends LoggingDebugSession {
Tools.useAutoPathMode = !!args.autoPathMode;
Tools.pathCaseSensitivity = !!args.pathCaseSensitivity;
- //1.1.生成文件map
if(Tools.useAutoPathMode === true){
Tools.rebuildAcceptExtMap(args.luaFileExtension);
Tools.rebuildWorkspaceNamePathMap(args.cwd);
Tools.checkSameNameFile();
}
- //去除out, Debugger/debugger_lib/plugins/Darwin/ libpdebug_版本号.so
- let clibPath = path.dirname(__dirname) + '/Debugger/debugger_lib/plugins/'
+ // 普通模式下才需要检查升级,单文件调试不用
+ if(args.name === 'LuaPanda'){
+ UpdateManager.checkIfLuaPandaNeedUpdate();
+ }
+
+ // 去除out, Debugger/debugger_lib/plugins/Darwin/ libpdebug_版本号.so
let sendArgs = new Array();
sendArgs["stopOnEntry"] = !!args.stopOnEntry;
sendArgs["luaFileExtension"] = args.luaFileExtension;
@@ -157,11 +162,9 @@ export class LuaDebugSession extends LoggingDebugSession {
sendArgs["debugMode"] = args.DebugMode;
sendArgs["pathCaseSensitivity"] = args.pathCaseSensitivity;
sendArgs["OSType"] = os.type();
- sendArgs["clibPath"] = clibPath;
+ sendArgs["clibPath"] = Tools.getClibPathInExtension();
sendArgs["useCHook"] = args.useCHook;
- let pkg = require("../package.json");
- let adapterVersion = pkg.version;
- sendArgs["adapterVersion"] = String(adapterVersion);
+ sendArgs["adapterVersion"] = String(Tools.adapterVersion);
sendArgs["autoPathMode"] = Tools.useAutoPathMode;
if(args.docPathReplace instanceof Array && args.docPathReplace.length === 2 ){
@@ -189,7 +192,7 @@ export class LuaDebugSession extends LoggingDebugSession {
if (typeof info.debuggerVer == "string"){
//转数字
let DVerArr = info.debuggerVer.split(".");
- let AVerArr = String(adapterVersion).split(".");
+ let AVerArr = String(Tools.adapterVersion).split(".");
if (DVerArr.length === AVerArr.length && DVerArr.length === 3 ){
//在adapter和debugger版本号长度相等的前提下,比较大版本,大版本 <2 或者 小版本 < 1 就提示. 2.1.0以下会提示
if ( parseInt(DVerArr[0]) < 2 || parseInt(DVerArr[1]) < 1 ){
@@ -270,8 +273,8 @@ export class LuaDebugSession extends LoggingDebugSession {
// 把路径加入package.path
let pathCMD = "'";
- let pathArr = path.dirname(__dirname).split( path.sep );
- let stdPath = pathArr.join('/');
+ let pathArr = Tools.VSCodeExtensionPath.split( path.sep );
+ let stdPath = pathArr.join('/');
pathCMD = pathCMD + stdPath + "/Debugger/?.lua;"
pathCMD = pathCMD + args.packagePath.join(';')
pathCMD = pathCMD + "'";
diff --git a/src/luaDebugRuntime.ts b/src/debug/luaDebugRuntime.ts
similarity index 98%
rename from src/luaDebugRuntime.ts
rename to src/debug/luaDebugRuntime.ts
index 00bd7ae..217fd78 100755
--- a/src/luaDebugRuntime.ts
+++ b/src/debug/luaDebugRuntime.ts
@@ -2,9 +2,9 @@ import * as vscode from 'vscode';
import { EventEmitter } from 'events';
import { DataProcesser } from './dataProcesser';
import { DebugProtocol } from 'vscode-debugprotocol';
-import { DebugLogger } from './LogManager';
-import { StatusBarManager } from './StatusBarManager';
-import { Tools } from './Tools';
+import { DebugLogger } from '../common/logManager';
+import { StatusBarManager } from '../common/statusBarManager';
+import { Tools } from '../common/tools';
export interface LuaBreakpoint {
diff --git a/src/debug/updateManager.ts b/src/debug/updateManager.ts
new file mode 100644
index 0000000..255c9c9
--- /dev/null
+++ b/src/debug/updateManager.ts
@@ -0,0 +1,49 @@
+import { Tools } from '../common/tools';
+import { DebugLogger } from '../common/logManager';
+import * as vscode from 'vscode';
+import * as fs from "fs";
+
+export class UpdateManager{
+ // 获取调试器lua文件的版本号,并提示用户升级
+ public static checkIfLuaPandaNeedUpdate(){
+ // 从列表中找到文件
+ if(Tools.fileNameToPathMap && typeof(Tools.fileNameToPathMap["LuaPanda"]) === 'string'){
+ Tools.luapandaPathInUserProj = Tools.fileNameToPathMap["LuaPanda"];
+ }
+
+ if(!Tools.luapandaPathInUserProj){
+ return;
+ }
+
+ let luapandaTxt = Tools.readFileContent(Tools.luapandaPathInUserProj);
+ let dver = luapandaTxt.match(/(?<=local debuggerVer = )("(.*?)")/);
+ if(dver && dver.length === 3){
+ let DVerArr = dver[2].split('.');
+ let AVerArr = String(Tools.adapterVersion).split(".");
+ if (DVerArr.length === AVerArr.length && DVerArr.length === 3 ){
+ if ( parseInt(DVerArr[0]) < parseInt(AVerArr[0]) || parseInt(DVerArr[1]) < parseInt(AVerArr[1]) || parseInt(DVerArr[2]) < parseInt(AVerArr[2]) ){
+ vscode.window.showInformationMessage('当前工程中 LuaPanda 文件版本比较低,是否自动升级为新版本?', 'Yes', 'No').then(value => {
+ if(value === "Yes"){ this.updateLuaPandaFile(Tools.luapandaPathInUserProj) };
+ })
+ }
+ }else{
+ //版本号异常,不做处理
+ }
+ }
+ }
+
+ // 更新调试器lua文件(读取预置文件,写入工程的目标文件中)
+ public static updateLuaPandaFile(pandaPath) {
+ if(!pandaPath){
+ pandaPath = Tools.luapandaPathInUserProj;
+ }
+ //文件替换
+ let luapandaContent = fs.readFileSync(Tools.getLuaPathInExtension());
+ fs.writeFile(pandaPath, luapandaContent , function(err: NodeJS.ErrnoException){
+ if(err){
+ DebugLogger.showTips("升级失败,", 1);
+ }
+ DebugLogger.showTips("升级成功", 0);
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/debug/visualSetting.ts b/src/debug/visualSetting.ts
new file mode 100644
index 0000000..f839fc5
--- /dev/null
+++ b/src/debug/visualSetting.ts
@@ -0,0 +1,87 @@
+// 可视化配置部分
+import { Tools } from '../common/tools';
+import * as fs from "fs";
+
+export class VisualSetting {
+
+ private static readLaunchjson(){
+ let launchPath = Tools.VSCodeOpenedFolder + "/.vscode/launch.json";
+ //如果文件不存在,就创建一个
+ let launchExist = fs.existsSync(launchPath);
+ let jsonStr;
+ if(!launchExist){
+ // 文件不存在,读取预制文件,创建launch
+ let launchTemplate = Tools.readFileContent(Tools.VSCodeExtensionPath + "/res/others/launch.json");
+ Tools.writeFileContent(Tools.VSCodeOpenedFolder + "/.vscode/launch.json" ,launchTemplate);
+ jsonStr = launchTemplate;
+ }else{
+ // 文件存在,读取launch.json的信息
+ jsonStr = Tools.readFileContent(launchPath);
+ }
+
+ if(jsonStr == null || jsonStr == ''){
+ // 没有找到launch.json 文件,生成一份(读取预制内容,拷贝到其中)
+ return null;
+ }
+
+ //去除注释行
+ let reg = /(\/\/.*)|(\/\*[\s\S]*?\*\/)/g;// 正则表达式
+ jsonStr = jsonStr.replace(reg, '');
+ let launchSettings = JSON.parse(jsonStr);
+ return launchSettings;
+ }
+
+ // 处理配置文件launch.json
+ public static setLaunchToWeb(webview){
+ let settings = this.readLaunchjson();
+
+ let obj = new Object();
+ obj["command"] = "init_setting";
+ for (const key in settings.configurations) {
+ const v = settings.configurations[key];
+
+ if(v["name"] === "LuaPanda"){
+ obj["LuaPanda"] = v;
+ }
+ if(v["name"] === "LuaPanda-DebugFile"){
+ obj["LuaPanda-DebugFile"] = v;
+ }
+ }
+ //setting反馈到html中
+ let newJson = JSON.stringify(obj);
+ webview.postMessage(newJson);
+ }
+
+ public static getWebMessage(message) {
+ let messageObj = JSON.parse(message.webInfo);
+ switch (messageObj.command) {
+ case 'save_settings':
+ this.processSaveSettings(messageObj);
+ break;
+ }
+ }
+
+ private static processSaveSettings(messageObj) {
+ // 再读取一次launch.json , 序列化,用传来的obj替换之前的
+ let settings = this.readLaunchjson();
+ for (const keyLaunch in settings.configurations) {
+ let valueLaunch = settings.configurations[keyLaunch]
+ if(valueLaunch["name"] === "LuaPanda"){
+ for (const keyWeb of Object.keys(messageObj["LuaPanda"])) {
+ valueLaunch[keyWeb] = messageObj["LuaPanda"][keyWeb];
+ }
+ }
+
+ if(valueLaunch["name"] === "LuaPanda-DebugFile"){
+ for (const keyWeb of Object.keys(messageObj["LuaPanda-DebugFile"])) {
+ valueLaunch[keyWeb] = messageObj["LuaPanda-DebugFile"][keyWeb];
+ }
+ }
+
+ }
+ //序列化并写入
+ let launchJson = JSON.stringify(settings, null, 4);
+ // console.log(launchJson);
+ Tools.writeFileContent(Tools.VSCodeOpenedFolder + "/.vscode/launch.json" ,launchJson);
+ }
+}
\ No newline at end of file
diff --git a/src/extension.ts b/src/extension.ts
index 9802953..bd737b3 100755
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -2,36 +2,127 @@
import * as vscode from 'vscode';
import * as Net from 'net';
-import { LuaDebugSession } from './luaDebug';
-import { DebugLogger } from './LogManager';
-import { StatusBarManager } from './StatusBarManager';
-import { Tools } from './Tools';
+import * as path from 'path';
+import { LuaDebugSession } from './debug/luaDebug';
+import { DebugLogger } from './common/logManager';
+import { StatusBarManager } from './common/statusBarManager';
+import { Tools } from './common/tools';
+import {
+ LanguageClient,
+ LanguageClientOptions,
+ ServerOptions,
+ TransportKind
+} from 'vscode-languageclient';
+import { workspace, ExtensionContext } from 'vscode';
+import { VisualSetting } from './debug/visualSetting'
+let client: LanguageClient;
-export function activate(context: vscode.ExtensionContext) {
- //reloadWindow
+export function activate(context: ExtensionContext) {
+ // reloadWindow
let reloadWindow = vscode.commands.registerCommand('luapanda.reloadLuaDebug', function () {
vscode.commands.executeCommand("workbench.action.reloadWindow")
});
context.subscriptions.push(reloadWindow);
- //force garbage collect
+ // force garbage collect
let LuaGarbageCollect = vscode.commands.registerCommand('luapanda.LuaGarbageCollect', function () {
LuaDebugSession.getInstance().LuaGarbageCollect();
vscode.window.showInformationMessage('Lua Garbage Collect!');
});
context.subscriptions.push(LuaGarbageCollect);
+ let openSettingsPage = vscode.commands.registerCommand('luapanda.openSettingsPage', function () {
+ // 和VSCode的交互
+ let panel: vscode.WebviewPanel = vscode.window.createWebviewPanel(
+ 'LuaPanda Setting',
+ 'LuaPanda 项目配置',
+ vscode.ViewColumn.One,
+ {
+ retainContextWhenHidden: true,
+ enableScripts: true
+ }
+ );
+
+ panel.webview.html = Tools.readFileContent(Tools.VSCodeExtensionPath + '/res/web/settings.html');
+ // Handle messages from the webview
+ panel.webview.onDidReceiveMessage(message => {
+ VisualSetting.getWebMessage(message)
+ },
+ undefined,
+ context.subscriptions
+ );
+ // 读入配置
+ VisualSetting.setLaunchToWeb(panel.webview);
+ });
+ context.subscriptions.push(openSettingsPage);
+
const provider = new LuaConfigurationProvider()
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('lua', provider));
context.subscriptions.push(provider);
- //init log
+
+ // 公共变量赋值
+ let pkg = require( context.extensionPath + "/package.json");
+ Tools.adapterVersion = pkg.version;
+ Tools.VSCodeExtensionPath = context.extensionPath;
+ // init log
DebugLogger.init();
StatusBarManager.init();
+
+ // language server 相关
+ // The server is implemented in node
+ let serverModule = context.asAbsolutePath(
+ path.join('out', 'code', 'server', 'server.js')
+ );
+ // The debug options for the server
+ // --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging
+ let debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] };
+
+ // If the extension is launched in debug mode then the debug server options are used
+ // Otherwise the run options are used
+ let serverOptions: ServerOptions = {
+ run: { module: serverModule, transport: TransportKind.ipc },
+ debug: {
+ module: serverModule,
+ transport: TransportKind.ipc,
+ options: debugOptions
+ }
+ };
+
+ // Options to control the language client
+ let clientOptions: LanguageClientOptions = {
+ // Register the server for plain text documents
+ documentSelector: [{ scheme: 'file', language: 'lua' }],
+ synchronize: {
+ // Notify the server about file changes to '.clientrc files contained in the workspace
+ fileEvents: workspace.createFileSystemWatcher('**/.clientrc')
+ }
+ };
+
+ // Create the language client and start the client.
+ client = new LanguageClient(
+ 'lua_analyzer',
+ 'Lua Analyzer',
+ serverOptions,
+ clientOptions
+ );
+
+ // Start the client. This will also launch the server
+ client.start();
+ client.onReady().then(() => {
+ client.onNotification("showProgress", showProgress);
+ client.onNotification("setRootFolder", setRootFolder);
+ client.onNotification("setLuaPandaPath", setLuaPandaPath);
+ });
+
}
export function deactivate() {
- // nothing to do
+ if (!client) {
+ return undefined;
+ }
+ return client.stop();
}
+// debug启动时的配置项处理
class LuaConfigurationProvider implements vscode.DebugConfigurationProvider {
private _server?: Net.Server;
resolveDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration, token?: vscode.CancellationToken): vscode.ProviderResult {
@@ -64,8 +155,8 @@ class LuaConfigurationProvider implements vscode.DebugConfigurationProvider {
// 把路径加入package.path
let path = require("path");
let pathCMD = "'";
- let pathArr = path.dirname(__dirname).split( path.sep );
- let stdPath = pathArr.join('/');
+ let pathArr = Tools.VSCodeExtensionPath.split( path.sep );
+ let stdPath = pathArr.join('/');
pathCMD = pathCMD + stdPath + "/Debugger/?.lua;"
pathCMD = pathCMD + config.packagePath.join(';')
pathCMD = pathCMD + "'";
@@ -186,3 +277,16 @@ class LuaConfigurationProvider implements vscode.DebugConfigurationProvider {
}
}
}
+
+// code server端消息回调函数
+function showProgress(message: string) {
+ StatusBarManager.showSetting(message);
+}
+
+function setRootFolder(message: string) {
+ Tools.VSCodeOpenedFolder = message;
+}
+
+function setLuaPandaPath(message: string) {
+ Tools.luapandaPathInUserProj = message;
+}
diff --git a/src/tsconfig.json b/src/tsconfig.json
index d5421db..fd4441a 100755
--- a/src/tsconfig.json
+++ b/src/tsconfig.json
@@ -1,8 +1,8 @@
{
"compilerOptions": {
"module": "commonjs",
+ "lib": ["es6", "dom", "es2017"],
"target": "es6",
-
"noImplicitAny": false,
"removeComments": false,
"noUnusedLocals": true,
@@ -11,7 +11,8 @@
"sourceMap": true,
"outDir": "../out",
"preserveConstEnums": true,
- "strictNullChecks": true,
- "noUnusedParameters": false
+ "strictNullChecks": false,
+ "noUnusedParameters": false,
+ "strict": false /* enable all strict type-checking options */
}
}
From 831f7a78011f578639410ea5ad56465219575b4d Mon Sep 17 00:00:00 2001
From: stuartwang <3030078087@qq.com>
Date: Tue, 29 Oct 2019 10:14:48 +0800
Subject: [PATCH 003/331] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=A1=A5=E5=85=A8?=
=?UTF-8?q?=E5=92=8C=E8=B7=AF=E5=BE=84=E8=B7=B3=E8=BD=ACbugfix?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/code/server/codeCompleting.ts | 4 +-
src/code/server/codeSymbol.ts | 182 ++++++++++++++++--------------
src/code/server/codeTools.ts | 5 +-
src/code/server/server.ts | 2 +-
4 files changed, 106 insertions(+), 87 deletions(-)
diff --git a/src/code/server/codeCompleting.ts b/src/code/server/codeCompleting.ts
index 3a1726c..069cda8 100644
--- a/src/code/server/codeCompleting.ts
+++ b/src/code/server/codeCompleting.ts
@@ -133,7 +133,7 @@ export class CodeCompleting {
}
}else{
- tagSearchRetSymb = CodeSymbol.searchGlobalInRequireTree(searchName, uri, Tools.SearchMode.FirstLetterContinuousMatching );
+ tagSearchRetSymb = CodeSymbol.searchAllSymbolinRequireTreeforCompleting(uri, searchName, Tools.SearchMode.FirstLetterContinuousMatching);
}
if( !tagSearchRetSymb || tagSearchRetSymb.length < 1 ){
//当直接替换tag查不到的时候,用一次类型推导
@@ -143,7 +143,7 @@ export class CodeCompleting {
this.replaceDic[tagSearchRetSymb[0].searchName] = addElement.searchName;
searchName = tagSearchRetSymb[0].searchName;
//再做一次搜索
- tagSearchRetSymb = CodeSymbol.searchGlobalInRequireTree(tagSearchRetSymb[0].searchName , uri, Tools.SearchMode.FirstLetterContinuousMatching );
+ tagSearchRetSymb = CodeSymbol.searchAllSymbolinRequireTreeforCompleting(uri, tagSearchRetSymb[0].searchName , Tools.SearchMode.FirstLetterContinuousMatching);
}else{
// tag 符号没有查到,类型推导也没有找到。
return;
diff --git a/src/code/server/codeSymbol.ts b/src/code/server/codeSymbol.ts
index 9c786e9..1be2592 100644
--- a/src/code/server/codeSymbol.ts
+++ b/src/code/server/codeSymbol.ts
@@ -4,7 +4,10 @@
// 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.
-//创建并管理文件中的符号
+// CodeSymbol 管理AST中的符号, 对上提供各种接口。
+// 获取/刷新文件符号
+//
+
import * as Tools from './codeTools';
import { CodeEditor } from './codeEditor';
import { DocSymbolProcesser } from './docSymbolProcesser';
@@ -34,7 +37,7 @@ export class CodeSymbol {
if(luaText == undefined){
luaText = CodeEditor.getCode(uri);
}
- this.createDocSymbals(uri, luaText);
+ this.createDocSymbol(uri, luaText);
}
// 获取指定文件的所有符号 , 并返回Array形式
@@ -69,11 +72,14 @@ export class CodeSymbol {
// 获取指定文件的返回值,如无返回null
public static getCertainDocReturnValue(uri):string{
+ this.createCertainDocSymbols(uri);
let docSymbals = this.docSymbolMap.get(uri);
- if(docSymbals)
+ if(docSymbals){
return docSymbals.getFileReturnArray();
- else
+ }
+ else{
return null;
+ }
}
// 指定文件夹中的符号处理
@@ -86,7 +92,7 @@ export class CodeSymbol {
filesArray.forEach(pathArray => {
let uri = Tools.pathToUri(pathArray);
if(!this.docSymbolMap.has(uri)){
- this.createDocSymbals( uri , pathArray );
+ this.createDocSymbol( uri , pathArray );
}
});
}
@@ -98,7 +104,7 @@ export class CodeSymbol {
}
let filesArray = Tools.getDirFiles( path );
filesArray.forEach(element => {
- this.createDocSymbals( element );
+ this.createDocSymbol( element );
});
}
@@ -130,23 +136,23 @@ export class CodeSymbol {
return g_symb;
}
- // 获取Require文件中的全局符号(本文件引用的其他文件), 以dictionary的形式返回
- public static getRequireTreeGlobalSymbols(uri: string){
- if(uri === undefined || uri === ''){
- return;
- }
-
- let fileList = this.getRequireTreeList(uri);
- let g_symb = {};
- for (let index = 0; index < fileList.length; index++) {
- let g_s = this.getCertainDocSymbolsReturnDic( fileList[index], null, Tools.SearchRange.GlobalSymbols);
- for (const key in g_s) {
- const element = g_s[key];
- g_symb[key] = element;
- }
- }
- return g_symb;
- }
+ // 获取Require文件中的全局符号(本文件引用的其他文件), 以dictionary的形式返回
+ // public static getRequireTreeGlobalSymbols(uri: string){
+ // if(uri === undefined || uri === ''){
+ // return;
+ // }
+
+ // let fileList = this.getRequireTreeList(uri);
+ // let g_symb = {};
+ // for (let index = 0; index < fileList.length; index++) {
+ // let g_s = this.getCertainDocSymbolsReturnDic( fileList[index], null, Tools.SearchRange.GlobalSymbols);
+ // for (const key in g_s) {
+ // const element = g_s[key];
+ // g_symb[key] = element;
+ // }
+ // }
+ // return g_symb;
+ // }
//reference处理
public static searchSymbolReferenceinDoc(searchSymbol) {
@@ -213,10 +219,15 @@ export class CodeSymbol {
* @param searchedFiles 标记已经搜索过的文件,上层调用该方法时可以不传
* @return 搜索结果,SymbolInformation数组
*/
- public static searchGlobalInRequireTree(symbolName: string, uri: string , searchMethod: Tools.SearchMode , searchedFiles?: Map): Tools.SymbolInformation[] {
+ public static searchGlobalInRequireTree(symbolName: string, uri: string , searchMethod: Tools.SearchMode , searchedFiles?: Map, isFirstEntry?: boolean): Tools.SymbolInformation[] {
if (searchedFiles == undefined) {
searchedFiles = new Map();
}
+
+ if(isFirstEntry == undefined){
+ isFirstEntry = true;
+ }
+
let result: Tools.SymbolInformation[] = new Array();
// uri为空直接返回
@@ -230,7 +241,12 @@ export class CodeSymbol {
}
// 在单个文件中搜索全局变量
let docSymbol = this.docSymbolMap.get(uri);
- let searchResult = docSymbol.searchMatchSymbal(symbolName, searchMethod, Tools.SearchRange.GlobalSymbols);
+ let searchResult;
+ if(isFirstEntry){
+ searchResult = docSymbol.searchMatchSymbal(symbolName, searchMethod, Tools.SearchRange.AllSymbols);
+ }else{
+ searchResult = docSymbol.searchMatchSymbal(symbolName, searchMethod, Tools.SearchRange.GlobalSymbols);
+ }
result = result.concat(searchResult);
searchedFiles.set(uri, true);
@@ -240,12 +256,12 @@ export class CodeSymbol {
// 搜索的原则为在引用树上优先搜索最近的定义,即先搜本文件,然后逆序搜索require的文件,再逆序搜索reference
// 搜索require的文件
for (let i = requireFiles.length - 1; i >= 0; i--) {
- let searchResult = this.searchGlobalInRequireTree(symbolName, Tools.transFileNameToUri(requireFiles[i].reqName), searchMethod, searchedFiles);
+ let searchResult = this.searchGlobalInRequireTree(symbolName, Tools.transFileNameToUri(requireFiles[i].reqName), searchMethod, searchedFiles, false);
result = result.concat(searchResult);
}
// 搜索require本文件的文件(references)
for (let i = references.length - 1; i >= 0; i--) {
- let searchResult = this.searchGlobalInRequireTree(symbolName, references[i], searchMethod, searchedFiles);
+ let searchResult = this.searchGlobalInRequireTree(symbolName, references[i], searchMethod, searchedFiles, false);
result = result.concat(searchResult);
}
@@ -323,33 +339,35 @@ export class CodeSymbol {
}
});
}
+
// 创建某个lua文件的符号
// @uri 文件uri
// @text 文件内容
- private static createDocSymbals(uri: string, luaText?: string): Tools.SymbolInformation[] {
+ private static createDocSymbol(uri: string, luaText?: string): Tools.SymbolInformation[] {
if(uri == null) return null;
if (luaText == undefined) {
luaText = Tools.getFileContent(Tools.uriToPath(uri));
}
+
let oldDocSymbol = this.docSymbolMap.get(uri);
- let docSymbol: DocSymbolProcesser = DocSymbolProcesser.create(luaText, uri);
- if(docSymbol){
- if( !docSymbol.parseError){
+ let newDocSymbol: DocSymbolProcesser = DocSymbolProcesser.create(luaText, uri);
+ if(newDocSymbol){
+ if( !newDocSymbol.parseError){
//解析无误
- this.docSymbolMap.set(uri, docSymbol);
- this.updateReference(oldDocSymbol, docSymbol);
+ this.docSymbolMap.set(uri, newDocSymbol);
+ this.updateReference(oldDocSymbol, newDocSymbol);
}else{
//解析过程有误
if ( !this.docSymbolMap.get(uri) ){
//map中还未解析过这个table
- this.docSymbolMap.set(uri, docSymbol);
+ this.docSymbolMap.set(uri, newDocSymbol);
}else{
//map中已有
let oldLen = this.docSymbolMap.get(uri).getAllSymbolsArray().length;
- let newLen = docSymbol.getAllSymbolsArray().length;
+ let newLen = newDocSymbol.getAllSymbolsArray().length;
if (newLen > oldLen){
- this.docSymbolMap.set(uri, docSymbol);
- this.updateReference(oldDocSymbol, docSymbol);
+ this.docSymbolMap.set(uri, newDocSymbol);
+ this.updateReference(oldDocSymbol, newDocSymbol);
}
}
}
@@ -371,50 +389,50 @@ export class CodeSymbol {
}
// 获取某个文件的引用树列表
- private static getRequireTreeList(uri: string){
- if(uri === undefined || uri === ''){
- return;
- }
-
- function recursiveGetRequireTreeList(uri: string, fileList: string[]){
- if(uri === undefined || uri === ''){
- return;
- }
- // 如果 uri 的符号列表不存在,创建
- if (!CodeSymbol.docSymbolMap.has(uri)) {
- Logger.log("createDocSymbals : "+ uri);
- let luaText = CodeEditor.getCode(uri);
- CodeSymbol.createDocSymbals(uri, luaText);
- }
-
- //如果uri所在文件存在错误,则无法创建成功。这里docProcesser == null
- let docProcesser = CodeSymbol.docSymbolMap.get(uri);
- if(docProcesser == null || docProcesser.getRequiresArray == null){
- Logger.log("get docProcesser or getRequireFiles error!");
- return;
- }
-
- //当前文件已经在递归处理过了
- if(alreadyProcessFile[uri] == 1){
- return;
- }else{
- alreadyProcessFile[uri] = 1;
- }
-
- let reqFiles = docProcesser.getRequiresArray();
- for(let idx = 0, len = reqFiles.length ; idx < len ; idx++ ){
- let newuri = Tools.transFileNameToUri(reqFiles[idx]['reqName'])
- recursiveGetRequireTreeList(newuri, fileList);
- }
- fileList.push(uri);
- return fileList;
- }
-
- let fileList = new Array();
- let alreadyProcessFile = new Object(); //防止循环引用
- recursiveGetRequireTreeList(uri, fileList);
- return fileList;
- }
+ // private static getRequireTreeList(uri: string){
+ // if(uri === undefined || uri === ''){
+ // return;
+ // }
+
+ // function recursiveGetRequireTreeList(uri: string, fileList: string[]){
+ // if(uri === undefined || uri === ''){
+ // return;
+ // }
+ // // 如果 uri 的符号列表不存在,创建
+ // if (!CodeSymbol.docSymbolMap.has(uri)) {
+ // Logger.log("createDocSymbals : "+ uri);
+ // let luaText = CodeEditor.getCode(uri);
+ // CodeSymbol.createDocSymbol(uri, luaText);
+ // }
+
+ // //如果uri所在文件存在错误,则无法创建成功。这里docProcesser == null
+ // let docProcesser = CodeSymbol.docSymbolMap.get(uri);
+ // if(docProcesser == null || docProcesser.getRequiresArray == null){
+ // Logger.log("get docProcesser or getRequireFiles error!");
+ // return;
+ // }
+
+ // //当前文件已经在递归处理过了
+ // if(alreadyProcessFile[uri] == 1){
+ // return;
+ // }else{
+ // alreadyProcessFile[uri] = 1;
+ // }
+
+ // let reqFiles = docProcesser.getRequiresArray();
+ // for(let idx = 0, len = reqFiles.length ; idx < len ; idx++ ){
+ // let newuri = Tools.transFileNameToUri(reqFiles[idx]['reqName'])
+ // recursiveGetRequireTreeList(newuri, fileList);
+ // }
+ // fileList.push(uri);
+ // return fileList;
+ // }
+
+ // let fileList = new Array();
+ // let alreadyProcessFile = new Object(); //防止循环引用
+ // recursiveGetRequireTreeList(uri, fileList);
+ // return fileList;
+ // }
// 递归搜索 引用树,查找符号
// @fileName 文件名
@@ -430,7 +448,7 @@ export class CodeSymbol {
if (!this.docSymbolMap.has(uri)) {
Logger.log("createDocSymbals : "+ uri);
let luaText = CodeEditor.getCode(uri);
- this.createDocSymbals(uri, luaText);
+ this.createDocSymbol(uri, luaText);
}
//开始递归
//如果uri所在文件存在错误,则无法创建成功。这里docProcesser == null
diff --git a/src/code/server/codeTools.ts b/src/code/server/codeTools.ts
index 0b25767..2b380e8 100644
--- a/src/code/server/codeTools.ts
+++ b/src/code/server/codeTools.ts
@@ -268,9 +268,10 @@ export function refresh_FileName_Uri_Cache(){
// @fileName 文件名
// @return uri string
export function transFileNameToUri(requireName : string): string{
+ //从路径中提取文件名
+ let parseName = path.parse(requireName);
//从fileMap中查找文件全路径
- // Logger.InfoLog("transFileNameToUri find--" + requireName);
- let cacheUri = fileName_Uri_Cache[requireName];
+ let cacheUri = fileName_Uri_Cache[parseName.name];
if(cacheUri){
return cacheUri;
}
diff --git a/src/code/server/server.ts b/src/code/server/server.ts
index 5cca424..6c4f5a1 100755
--- a/src/code/server/server.ts
+++ b/src/code/server/server.ts
@@ -128,7 +128,7 @@ connection.onInitialize((initPara: InitializeParams) => {
//引用分析
referencesProvider: false,
//代码格式化
- documentFormattingProvider: true,
+ documentFormattingProvider: false,
documentRangeFormattingProvider: false,
//代码选中高亮
documentHighlightProvider: false,
From 630efb02c87f4a730b2be036b28bb08124310e46 Mon Sep 17 00:00:00 2001
From: stuartwang <3030078087@qq.com>
Date: Tue, 29 Oct 2019 10:54:13 +0800
Subject: [PATCH 004/331] bugfix
---
src/code/server/codeTools.ts | 3 +++
src/code/server/docSymbolProcesser.ts | 9 +++++++++
2 files changed, 12 insertions(+)
diff --git a/src/code/server/codeTools.ts b/src/code/server/codeTools.ts
index 2b380e8..d3b9b0c 100644
--- a/src/code/server/codeTools.ts
+++ b/src/code/server/codeTools.ts
@@ -268,6 +268,9 @@ export function refresh_FileName_Uri_Cache(){
// @fileName 文件名
// @return uri string
export function transFileNameToUri(requireName : string): string{
+ if(requireName == null){
+ return '';
+ }
//从路径中提取文件名
let parseName = path.parse(requireName);
//从fileMap中查找文件全路径
diff --git a/src/code/server/docSymbolProcesser.ts b/src/code/server/docSymbolProcesser.ts
index a7fd252..45136f4 100644
--- a/src/code/server/docSymbolProcesser.ts
+++ b/src/code/server/docSymbolProcesser.ts
@@ -709,6 +709,9 @@ export class DocSymbolProcesser {
else if (baseNode['type'] == 'Identifier') {
return { name: baseNode['name'], isLocal: baseNode['isLocal'] };
}
+ else if (baseNode['type'] == 'StringLiteral') {
+ return { name: baseNode['value'], isLocal: false };
+ }
else if (baseNode['type'] == 'IndexExpression') {
let ret = this.baseProcess(baseNode['base']);
let str = ret.name;
@@ -736,6 +739,12 @@ export class DocSymbolProcesser {
retObj = { name: retStr, isLocal: isLocal, origion: ret.name };
}
+ if(baseNode['index']['type'] == "StringLiteral"){
+ let ret = this.baseProcess(baseNode['index']);
+ let retStr = str + '["' + ret.name + '"]';
+ retObj = { name: retStr, isLocal: isLocal, origion: ret.name };
+ }
+
return retObj;
}
return { name: '', isLocal: false };
From 3071f0396031a4b0dff7b9700ddd380603c8ba8b Mon Sep 17 00:00:00 2001
From: stuartwang <3030078087@qq.com>
Date: Tue, 29 Oct 2019 11:47:51 +0800
Subject: [PATCH 005/331] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=8D=87=E7=BA=A7?=
=?UTF-8?q?=E6=8F=90=E7=A4=BA=EF=BC=8C=E5=8A=A0=E5=85=A5=E4=BA=8C=E6=AC=A1?=
=?UTF-8?q?=E7=A1=AE=E8=AE=A4=E9=80=BB=E8=BE=91=E5=92=8C=E6=9C=AC=E6=AC=A1?=
=?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=9C=9F=E9=97=B4=E4=B8=8D=E5=86=8D=E6=8F=90?=
=?UTF-8?q?=E7=A4=BA=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/debug/luaDebug.ts | 2 +-
src/debug/updateManager.ts | 31 +++++++++++++++++++++++++++----
2 files changed, 28 insertions(+), 5 deletions(-)
diff --git a/src/debug/luaDebug.ts b/src/debug/luaDebug.ts
index 2ace210..a4f6539 100755
--- a/src/debug/luaDebug.ts
+++ b/src/debug/luaDebug.ts
@@ -147,7 +147,7 @@ export class LuaDebugSession extends LoggingDebugSession {
}
// 普通模式下才需要检查升级,单文件调试不用
- if(args.name === 'LuaPanda'){
+ if( args.name === 'LuaPanda' ){
UpdateManager.checkIfLuaPandaNeedUpdate();
}
diff --git a/src/debug/updateManager.ts b/src/debug/updateManager.ts
index 255c9c9..88afb62 100644
--- a/src/debug/updateManager.ts
+++ b/src/debug/updateManager.ts
@@ -4,8 +4,18 @@ import * as vscode from 'vscode';
import * as fs from "fs";
export class UpdateManager{
+ private static checkUpdate = true;
+
+ public static setCheckUpdate(state){
+ this.checkUpdate = state;
+ }
+
// 获取调试器lua文件的版本号,并提示用户升级
public static checkIfLuaPandaNeedUpdate(){
+ if(!this.checkUpdate){
+ return;
+ }
+
// 从列表中找到文件
if(Tools.fileNameToPathMap && typeof(Tools.fileNameToPathMap["LuaPanda"]) === 'string'){
Tools.luapandaPathInUserProj = Tools.fileNameToPathMap["LuaPanda"];
@@ -23,8 +33,19 @@ export class UpdateManager{
if (DVerArr.length === AVerArr.length && DVerArr.length === 3 ){
if ( parseInt(DVerArr[0]) < parseInt(AVerArr[0]) || parseInt(DVerArr[1]) < parseInt(AVerArr[1]) || parseInt(DVerArr[2]) < parseInt(AVerArr[2]) ){
vscode.window.showInformationMessage('当前工程中 LuaPanda 文件版本比较低,是否自动升级为新版本?', 'Yes', 'No').then(value => {
- if(value === "Yes"){ this.updateLuaPandaFile(Tools.luapandaPathInUserProj) };
- })
+ if(value === "Yes"){
+ vscode.window.showInformationMessage('已准备好更新 ' + Tools.luapandaPathInUserProj+ ' 如用户对此文件有修改, 建议备份后升级。是否现在升级?', '确认升级', '稍后再试').then(value => {
+ if(value === "确认升级"){
+ UpdateManager.updateLuaPandaFile(Tools.luapandaPathInUserProj)
+ }
+ });
+ }
+ else{
+ // 本次插件运行期间不再提示
+ UpdateManager.setCheckUpdate(false);
+ };
+
+ });
}
}else{
//版本号异常,不做处理
@@ -41,9 +62,11 @@ export class UpdateManager{
let luapandaContent = fs.readFileSync(Tools.getLuaPathInExtension());
fs.writeFile(pandaPath, luapandaContent , function(err: NodeJS.ErrnoException){
if(err){
- DebugLogger.showTips("升级失败,", 1);
+ DebugLogger.showTips("升级失败, " + Tools.luapandaPathInUserProj + "写入失败! 可以手动替换此文件到github最新版", 1);
+ }else{
+ DebugLogger.showTips("升级成功, " + Tools.luapandaPathInUserProj + "版本已升级为 " + Tools.adapterVersion , 0);
}
- DebugLogger.showTips("升级成功", 0);
+ UpdateManager.setCheckUpdate(false);
});
}
}
\ No newline at end of file
From e6569b473c95d0369dc23c956c4dc44039d9c8c1 Mon Sep 17 00:00:00 2001
From: stuartwang <3030078087@qq.com>
Date: Tue, 29 Oct 2019 15:46:28 +0800
Subject: [PATCH 006/331] =?UTF-8?q?=E5=90=88=E5=B9=B6=E4=BA=86=20luapanda.?=
=?UTF-8?q?lua=20=E4=BB=85=E4=BF=9D=E7=95=99=E4=B8=80=E4=B8=AA=E6=96=87?=
=?UTF-8?q?=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Debugger/DebugTools.lua | 584 ---------------------------------------
Debugger/LuaPanda.lua | 589 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 586 insertions(+), 587 deletions(-)
delete mode 100644 Debugger/DebugTools.lua
diff --git a/Debugger/DebugTools.lua b/Debugger/DebugTools.lua
deleted file mode 100644
index bf3143f..0000000
--- a/Debugger/DebugTools.lua
+++ /dev/null
@@ -1,584 +0,0 @@
---工具函数
-local DebugTools = {};
-local this = DebugTools;
-
-function this.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 this.printTable(t, name ,indent)
- local str = (this.show(t, name, indent));
- print(str);
-end
-
---序列化并返回table
-function this.serializeTable(t, name, indent)
- local str = (this.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 this.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 this.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
--- licensed under the terms of the LGPL2
-
--- character table string
-local base64CharTable='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
-
--- encoding
-function this.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 this.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
-return this;
diff --git a/Debugger/LuaPanda.lua b/Debugger/LuaPanda.lua
index 8161ce6..2995222 100644
--- a/Debugger/LuaPanda.lua
+++ b/Debugger/LuaPanda.lua
@@ -47,14 +47,14 @@ local consoleLogLevel = 2; --打印在控制台(print)的日志等级
local connectTimeoutSec = 0.005; --等待连接超时时间, 单位s. 时间过长等待attach时会造成卡顿,时间过短可能无法连接。建议值0.005 - 0.05
--用户设置项END
-local debuggerVer = "2.3.0"; --debugger版本号
+local debuggerVer = "2.8.0"; --debugger版本号
LuaPanda = {};
local this = LuaPanda;
-local tools = require("DebugTools"); --引用的开源工具,包括json解析和table展开工具等
+local tools = {}; --引用的开源工具,包括json解析和table展开工具等
this.tools = tools;
this.curStackId = 0;
--json处理
-local json = tools.createJson()
+local json;
--hook状态列表
local hookState = {
DISCONNECT_HOOK = 0, --断开连接
@@ -2592,5 +2592,588 @@ function this.processWatchedExp(msgTable)
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
+-- 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);
return this;
From c637985d256a14d9ec0fc135193470e1f09af2d6 Mon Sep 17 00:00:00 2001
From: stuartwang <3030078087@qq.com>
Date: Tue, 29 Oct 2019 16:07:46 +0800
Subject: [PATCH 007/331] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86=E8=B5=84?=
=?UTF-8?q?=E6=BA=90=E6=96=87=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
package.json | 1 +
res/others/launch.json | 2 +-
res/web/settings.html | 47 ++++++++++++++----------------------------
3 files changed, 18 insertions(+), 32 deletions(-)
diff --git a/package.json b/package.json
index a53ee67..e6f6b8d 100755
--- a/package.json
+++ b/package.json
@@ -276,6 +276,7 @@
"cwd": "${workspaceFolder}",
"luaFileExtension": "",
"connectionPort": 8818,
+ "pathCaseSensitivity": true,
"stopOnEntry": true,
"useCHook": true,
"autoPathMode": true,
diff --git a/res/others/launch.json b/res/others/launch.json
index 1320e9e..fab00b5 100644
--- a/res/others/launch.json
+++ b/res/others/launch.json
@@ -12,7 +12,7 @@
"stopOnEntry": true,
"useCHook": true,
"autoPathMode": false,
- "logLevel": 1,
+ "logLevel": 1
},
{
"type": "lua",
diff --git a/res/web/settings.html b/res/web/settings.html
index 5f4a36f..394f567 100644
--- a/res/web/settings.html
+++ b/res/web/settings.html
@@ -15,26 +15,26 @@ LuaPanda Settings