diff options
author | sumneko <sumneko@hotmail.com> | 2021-12-21 22:49:59 +0800 |
---|---|---|
committer | sumneko <sumneko@hotmail.com> | 2021-12-21 22:49:59 +0800 |
commit | b7344640a0ab9a07551ee5ebc435657b45659553 (patch) | |
tree | 0fef08a7dbb0a115e0e1249b6123fd529cf1fc58 | |
parent | c47baf932309a05673b7931fdf6a1be207fb7bc4 (diff) | |
parent | ec4f497aa2624d9dce29e1de0cfd28ecd85e7df3 (diff) | |
download | lua-language-server-b7344640a0ab9a07551ee5ebc435657b45659553.zip |
Merge remote-tracking branch 'origin/master' into multi-workspace
45 files changed, 885 insertions, 297 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 946e7490..31c8d7f8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,20 +1,124 @@ name: build -on: push + +on: + push: + branches: + - master + tags: + - "*" + pull_request: + branches: + - master + +env: + PROJECT: lua-language-server + BIN_DIR: bin + jobs: compile: - runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - os: [windows-latest, ubuntu-18.04, macos-latest] + include: + - { os: ubuntu-18.04, target: linux, platform: linux-x64 } + - { os: macos-11, target: darwin, platform: darwin-x64 } + - { os: macos-11, target: darwin, platform: darwin-arm64 } + - { os: windows-latest, target: windows, platform: win32-ia32 } + - { os: windows-latest, target: windows, platform: win32-x64 } + runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v1 - with: - ref: refs/heads/master - submodules : recursive - - uses: actboy168/setup-luamake@master - - run: luamake - - uses: actions/upload-artifact@v1.0.0 - with: - name: lua-language-server - path: bin + - uses: actions/checkout@v2 + with: + submodules: recursive + - uses: actboy168/setup-luamake@master + - run: luamake -platform ${{ matrix.platform }} + + - name: Setting up workflow variables + id: vars + shell: bash + run: | + # Package version + if [[ $GITHUB_REF = refs/tags/* ]]; then + PKG_VERSION=${GITHUB_REF##*/} + else + PKG_VERSION=${GITHUB_SHA:0:7} + fi + + # Package suffix relative to the platform + if [[ "${{ matrix.target }}" = windows ]]; then + PKG_SUFFIX="zip" + else + PKG_SUFFIX="tar.gz" + fi + + # Package name w/ version + PKG_BASENAME="${{ env.PROJECT }}-${PKG_VERSION}-${{ matrix.platform }}" + + # Full name of the tarball asset + PKG_NAME="${PKG_BASENAME}.${PKG_SUFFIX}" + + # Staging area for tarballs + PKG_STAGING="ci_staging/$PKG_BASENAME" + + echo ::set-output name=PKG_VERSION::${PKG_VERSION} + echo ::set-output name=PKG_BASENAME::${PKG_BASENAME} + echo ::set-output name=PKG_NAME::${PKG_NAME} + echo ::set-output name=PKG_PATH::"${PKG_STAGING}/${PKG_NAME}" + echo ::set-output name=PKG_STAGING::${PKG_STAGING} + + - uses: actions/upload-artifact@v2 + with: + name: ${{ steps.vars.outputs.PKG_BASENAME }} + path: | + ${{ env.BIN_DIR }} + main.lua + debugger.lua + LICENSE + changelog.md + locale + meta + script + + - name: Package tarballs + if: startsWith(github.ref, 'refs/tags/') + shell: bash + run: | + STAGING=${{ steps.vars.outputs.PKG_STAGING }} + NAME=${{ steps.vars.outputs.PKG_NAME }} + + # Making the staging area + mkdir -p ${STAGING} + + # Copying binary and runtime files to staging area + cp -r main.lua debugger.lua LICENSE changelog.md locale meta script ${{ env.BIN_DIR }} ${STAGING} + + # Creating release assets + pushd "${STAGING}/" >/dev/null + if [[ "${{ matrix.target }}" = windows ]]; then + 7z -y a ${NAME} * | tail -2 + else + tar czf ${NAME} * + fi + popd >/dev/null + + # Packaging submodules for homebrew distribution + - name: Package submodules + id: submodules + if: ${{ startsWith(github.ref, 'refs/tags/') && matrix.platform == 'darwin-x64' }} + run: | + STAGING=${{ steps.vars.outputs.PKG_STAGING }} + PKG_SUBMOD_NAME="${{ env.PROJECT }}-${{ steps.vars.outputs.PKG_VERSION }}-submodules.zip" + PKG_SUBMOD_PATH="${STAGING}/$PKG_SUBMOD_NAME" + + zip -r $PKG_SUBMOD_PATH ./ -x "*.git*" -x "*.vscode*" -x "build*" -x "${{ env.BIN_DIR }}*" -x "${STAGING}*" + + echo ::set-output name=PKG_SUBMOD_PATH::${PKG_SUBMOD_PATH} + + - name: Publish release assets + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + generate_release_notes: true + files: | + ${{ steps.vars.outputs.PKG_PATH }} + ${{ steps.submodules.outputs.PKG_SUBMOD_PATH }} diff --git a/.github/workflows/checkPR.yml b/.github/workflows/checkPR.yml deleted file mode 100644 index c83bf3ab..00000000 --- a/.github/workflows/checkPR.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: checkPR -on: pull_request -jobs: - compile: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [windows-latest, ubuntu-18.04, macos-latest] - steps: - - uses: actions/checkout@v1 - with: - ref: ${{ github.event.pull_request.head.sha }} - submodules : recursive - - uses: actboy168/setup-luamake@master - - run: luamake @@ -1,9 +1,10 @@ /log /build -/bin -!*.exe /test/temp.lua /meta/* !/meta/template !/meta/3rd -/bin2 +/bin-Windows +/bin-Linux +/bin-macOS +/bin diff --git a/.vscode/launch.json b/.vscode/launch.json index 671a0662..bfb5c94c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,7 +8,7 @@ "request": "launch", "stopOnEntry": false, "program": "${workspaceRoot}/test.lua", - "luaexe": "${workspaceFolder}/bin/Windows/lua-language-server.exe", + "luaexe": "${workspaceFolder}/bin/lua-language-server.exe", "cpath": null, "arg": [ ], @@ -40,9 +40,9 @@ "type": "lua", "request": "launch", "stopOnEntry": false, - "luaexe": "${workspaceFolder}/bin/Windows/lua-language-server.exe", + "luaexe": "${workspaceFolder}/bin/lua-language-server", "program": "${workspaceRoot}/tools/build-3rd-meta.lua", - "cpath": "${workspaceFolder}/bin/Windows/?.dll", + "cpath": "${workspaceFolder}/bin/?.dll", "arg": [ ], "luaVersion": "latest", diff --git a/3rd/bee.lua b/3rd/bee.lua -Subproject 1794c607d3c16533a0d117da38ed15e6be2d6ba +Subproject 9132c7ecb4a68c40d52a6d750308237bf054feb diff --git a/3rd/lovr-api b/3rd/lovr-api -Subproject 58580f0f8ba3852fa7fe1b31a275e0d2a657ec3 +Subproject 92d3742eb6c3f4999a0c575984c82a75652e2b7 diff --git a/3rd/luamake b/3rd/luamake -Subproject 0aa2dbeaf7606db71718f17bcea489b0ff846e6 +Subproject 637ca44922ac125ceaebfb53650e4d7c6ae9247 @@ -141,6 +141,7 @@ If you need to compile by yourself, please refer to [here](https://github.com/su * [CppCXY](https://github.com/CppCXY) * [Ketho](https://github.com/Ketho) * [Folke Lemaitre](https://github.com/folke) +* [Vikas Raj](https://github.com/numToStr) ## Telemetry diff --git a/changelog.md b/changelog.md index af0ea081..92465e50 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,26 @@ # changelog +## 2.5.6 +* `CHG` diagnostic: now syntax errors in `LuaDoc` are shown as `Warning` +* `FIX` return type of `math.floor` +* `FIX` runtime errors + +## 2.5.5 +`2021-12-16` +* `FIX` dose not work in VSCode + +## 2.5.4 +`2021-12-16` +* `FIX` [#847](https://github.com/sumneko/lua-language-server/issues/847) +* `FIX` [#848](https://github.com/sumneko/lua-language-server/issues/848) +* `FIX` completion: incorrect cache +* `FIX` hover: always view string + +## 2.5.3 +`2021-12-6` +* `FIX` [#842](https://github.com/sumneko/lua-language-server/issues/844) +* `FIX` [#844](https://github.com/sumneko/lua-language-server/issues/844) + ## 2.5.2 `2021-12-2` * `FIX` [#815](https://github.com/sumneko/lua-language-server/issues/815) @@ -2,9 +2,30 @@ local lm = require 'luamake' local platform = require 'bee.platform' local exe = platform.OS == 'Windows' and ".exe" or "" -lm.bindir = "bin/"..platform.OS +lm.bindir = "bin" lm.EXE_DIR = "" + +if platform.OS == 'macOS' then + if lm.platform == nil then + elseif lm.platform == "darwin-arm64" then + lm.target = "arm64-apple-macos11" + elseif lm.platform == "darwin-x64" then + lm.target = "x86_64-apple-macos10.12" + else + error "unknown platform" + end +elseif platform.OS == 'Windows' then + if lm.platform == nil then + elseif lm.platform == "win32-ia32" then + lm.arch = "x86" + elseif lm.platform == "win32-x64" then + lm.arch = "x86_64" + else + error "unknown platform" + end +end + lm:import "3rd/bee.lua/make.lua" lm:source_set 'lpeglabel' { @@ -33,18 +54,16 @@ lm:executable "lua-language-server" { } } -lm:build 'copy_vcrt' { - '$luamake', 'lua', 'make/copy_vcrt.lua', lm.bindir, -} - lm:copy "copy_bootstrap" { input = "make/bootstrap.lua", output = lm.bindir.."/main.lua", } -lm:build "bee-test" { - lm.bindir.."/lua-language-server"..exe, "3rd/bee.lua/test/test.lua", - pool = "console", +lm:build 'copy_vcrt' { + '$luamake', 'lua', 'make/copy_vcrt.lua', lm.bindir, lm.arch, +} + +lm:phony "all" { deps = { "lua-language-server", "copy_bootstrap", @@ -56,6 +75,54 @@ lm:build "bee-test" { } } +local function detectWindowsArch() + if os.getenv "PROCESSOR_ARCHITECTURE" == "ARM64" then + return "arm64" + end + if os.getenv "PROCESSOR_ARCHITECTURE" == "AMD64" or os.getenv "PROCESSOR_ARCHITEW6432" == "AMD64" then + return "x64" + end + return "ia32" +end + +local function detectPosixArch() + local f <close> = assert(io.popen("uname -m", 'r')) + return f:read 'l':lower() +end + +local function detectArch() + if platform.OS == 'Windows' then + return detectWindowsArch() + end + return detectPosixArch() +end + +local function targetPlatformArch() + if lm.platform == nil then + return detectArch() + end + return lm.platform:match "^[^-]*-(.*)$" +end + +local notest = platform.OS == 'macOS' + and targetPlatformArch() == "arm64" + and detectArch() == "x86_64" + +if notest then + lm:default { + "all", + } + return +end + +lm:build "bee-test" { + lm.bindir.."/lua-language-server"..exe, "3rd/bee.lua/test/test.lua", + pool = "console", + deps = { + "all", + } +} + lm:build 'unit-test' { lm.bindir.."/lua-language-server"..exe, 'test.lua', pool = "console", diff --git a/make/bootstrap.lua b/make/bootstrap.lua index e9e61c77..36b9ce96 100644 --- a/make/bootstrap.lua +++ b/make/bootstrap.lua @@ -49,7 +49,7 @@ local root; do sep = '/\\'
end
local pattern = "["..sep.."][^"..sep.."]+"
- root = package.cpath:match("([^;]+)"..pattern..pattern..pattern.."$")
+ root = package.cpath:match("([^;]+)"..pattern..pattern.."$")
arg[0] = root .. package.config:sub(1,1) .. 'main.lua'
end
root = root:gsub('[/\\]', package.config:sub(1,1))
diff --git a/make/copy_vcrt.lua b/make/copy_vcrt.lua index b1eb3cf5..bd08a9fa 100644 --- a/make/copy_vcrt.lua +++ b/make/copy_vcrt.lua @@ -1,3 +1,6 @@ -local output = ... +local output, arch = ... local fs = require 'bee.filesystem' -require 'msvc'.copy_vcrt('x64', fs.current_path() / output) +require 'msvc'.copy_vcrt( + arch == "x86" and 'x86' or 'x64', + fs.current_path() / output +) diff --git a/meta/3rd/OpenResty/library/resty.websocket.client.lua b/meta/3rd/OpenResty/library/resty.websocket.client.lua index f933c941..c722faf9 100644 --- a/meta/3rd/OpenResty/library/resty.websocket.client.lua +++ b/meta/3rd/OpenResty/library/resty.websocket.client.lua @@ -1,16 +1,63 @@ ---@meta -resty_websocket_client={} -function resty_websocket_client.send_text(self, data) end -function resty_websocket_client.new(self, opts) end -function resty_websocket_client.send_ping(self, data) end -function resty_websocket_client.connect(self, uri, opts) end -function resty_websocket_client.set_timeout(self, time) end -function resty_websocket_client.set_keepalive(self, ...) end -function resty_websocket_client.send_binary(self, data) end -function resty_websocket_client.send_close() end -function resty_websocket_client.send_frame() end -function resty_websocket_client.recv_frame(self) end -function resty_websocket_client.close(self) end -resty_websocket_client._VERSION="0.07" -function resty_websocket_client.send_pong(self, data) end + +---@class resty.websocket.client : resty.websocket +resty_websocket_client = { + _VERSION = "0.09" +} + +---Instantiates a WebSocket client object. +--- +---In case of error, it returns nil and a string describing the error. +--- +---An optional options table can be specified. +--- +---@param opts? resty.websocket.new.opts +---@return resty.websocket.client? client +---@return string? error +function resty_websocket_client:new(opts) end + +---Connects to the remote WebSocket service port and performs the websocket +---handshake process on the client side. +--- +---Before actually resolving the host name and connecting to the remote backend, +---this method will always look up the connection pool for matched idle +---connections created by previous calls of this method. +--- +---@param url string +---@param opts? resty.websocket.client.connect.opts +---@return boolean ok +---@return string? error +function resty_websocket_client:connect(uri, opts) end + +--- Puts the current WebSocket connection immediately into the ngx_lua cosocket connection pool. +--- +--- You can specify the max idle timeout (in ms) when the connection is in the pool and the maximal size of the pool every nginx worker process. +--- +--- In case of success, returns 1. In case of errors, returns nil with a string describing the error. +--- +--- Only call this method in the place you would have called the close method instead. Calling this method will immediately turn the current WebSocket object into the closed state. Any subsequent operations other than connect() on the current object will return the closed error. +---- +---@param max_idle_timeout number +---@param pool_size integer +---@return boolean ok +---@return string? error +function resty_websocket_client:set_keepalive(max_idle_timeout, pool_size) end + +---Closes the current WebSocket connection. +--- +---If no close frame is sent yet, then the close frame will be automatically sent. +--- +---@return boolean ok +---@return string? error +function resty_websocket_client:close() end + +---@class resty.websocket.client.connect.opts : table +--- +---@field protocols string|string[] subprotocol(s) used for the current WebSocket session +---@field origin string the value of the Origin request header +---@field pool string custom name for the connection pool being used. If omitted, then the connection pool name will be generated from the string template <host>:<port>. +---@field ssl_verify boolean whether to perform SSL certificate verification during the SSL handshake if the wss:// scheme is used. +---@field headers string[] custom headers to be sent in the handshake request. The table is expected to contain strings in the format {"a-header: a header value", "another-header: another header value"}. + + return resty_websocket_client
\ No newline at end of file diff --git a/meta/3rd/OpenResty/library/resty.websocket.lua b/meta/3rd/OpenResty/library/resty.websocket.lua new file mode 100644 index 00000000..9ddd4921 --- /dev/null +++ b/meta/3rd/OpenResty/library/resty.websocket.lua @@ -0,0 +1,116 @@ +---@meta + +--- websocket object +--- https://github.com/openresty/lua-resty-websocket +--- +---@class resty.websocket : table +---@field sock tcpsock +---@field fatal boolean +---@field max_payload_len number +---@field send_masked boolean +resty_websocket = {} + +---@param ms integer sets the timeout delay (in milliseconds) for the network-related operations +function resty_websocket:set_timeout(ms) end + +---Sends the text argument out as an unfragmented data frame of the text type. +--- +---Returns the number of bytes that have actually been sent on the TCP level. +--- +---In case of errors, returns nil and a string describing the error. +--- +---@param text string +---@return integer? bytes +---@return string? error +function resty_websocket:send_text(text) end + +---Sends the data argument out as an unfragmented data frame of the binary type. +--- +---Returns the number of bytes that have actually been sent on the TCP level. +--- +---In case of errors, returns nil and a string describing the error. +--- +---@param data string +---@return integer? bytes +---@return string? error +function resty_websocket:send_binary(data) end + +---Sends out a ping frame with an optional message specified by the msg argument. +---Returns the number of bytes that have actually been sent on the TCP level. +--- +---In case of errors, returns nil and a string describing the error. +--- +---Note that this method does not wait for a pong frame from the remote end. +--- +---@param msg? string +---@return integer? bytes +---@return string? error +function resty_websocket:send_ping(msg) end + +---Sends out a pong frame with an optional message specified by the msg argument. +---Returns the number of bytes that have actually been sent on the TCP level. +--- +---In case of errors, returns nil and a string describing the error. +---@param msg? string +---@return integer? bytes +---@return string? error +function resty_websocket:send_pong(msg) end + +---Sends out a close frame with an optional status code and a message. +--- +---In case of errors, returns nil and a string describing the error. +--- +---For a list of valid status code, see the following document: +--- +---http://tools.ietf.org/html/rfc6455#section-7.4.1 +--- +---Note that this method does not wait for a close frame from the remote end. +---@param code? integer +---@param msg? string +---@return integer? bytes +---@return string? error +function resty_websocket:send_close(code, msg) end + +---Sends out a raw websocket frame by specifying the fin field (boolean value), the opcode, and the payload. +--- +---For a list of valid opcode, see +--- +---http://tools.ietf.org/html/rfc6455#section-5.2 +--- +---In case of errors, returns nil and a string describing the error. +--- +---To control the maximal payload length allowed, you can pass the max_payload_len option to the new constructor. +--- +---To control whether to send masked frames, you can pass true to the send_masked option in the new constructor method. By default, unmasked frames are sent. +---@param fin boolean +---@param opcode resty.websocket.protocol.opcode +---@param payload string +---@return integer? bytes +---@return string? error +function resty_websocket:send_frame(fin, opcode, payload) end + +---Receives a WebSocket frame from the wire. +--- +---In case of an error, returns two nil values and a string describing the error. +--- +---The second return value is always the frame type, which could be one of continuation, text, binary, close, ping, pong, or nil (for unknown types). +--- +---For close frames, returns 3 values: the extra status message (which could be an empty string), the string "close", and a Lua number for the status code (if any). For possible closing status codes, see +--- +---http://tools.ietf.org/html/rfc6455#section-7.4.1 +--- +---For other types of frames, just returns the payload and the type. +--- +---For fragmented frames, the err return value is the Lua string "again". +--- +---@return string? data +---@return resty.websocket.protocol.type? typ +---@return string|integer? error_or_status_code +function resty_websocket:recv_frame() end + +---@class resty.websocket.new.opts : table +---@field max_payload_len integer maximal length of payload allowed when sending and receiving WebSocket frames +---@field send_masked boolean whether to send out masked WebSocket frames +---@field timeout integer network timeout threshold in milliseconds + +return resty_websocket diff --git a/meta/3rd/OpenResty/library/resty.websocket.protocol.lua b/meta/3rd/OpenResty/library/resty.websocket.protocol.lua index 9ef52bbb..c3455969 100644 --- a/meta/3rd/OpenResty/library/resty.websocket.protocol.lua +++ b/meta/3rd/OpenResty/library/resty.websocket.protocol.lua @@ -1,8 +1,59 @@ ---@meta -resty_websocket_protocol={} -function resty_websocket_protocol.build_frame() end -function resty_websocket_protocol.new_tab() end + +---@class resty.websocket.protocol +resty_websocket_protocol = { + _VERSION = "0.09", +} + +--- Websocket op code +--- +--- Defines the interpretation of the payload data. +--- +--- See RFC 6455 section 5.2 +--- +---@alias resty.websocket.protocol.opcode +---| '0x0' # continuation +---| '0x1' # text +---| '0x2' # binary +---| '0x8' # close +---| '0x9' # ping +---| '0xa' # pong + +---@alias resty.websocket.protocol.type +---| '"continuation"' +---| '"text"' +---| '"binary"' +---| '"close"' +---| '"ping"' +---| '"pong"' + +--- Builds a raw WebSocket frame. +---@param fin boolean +---@param opcode resty.websocket.protocol.opcode +---@param payload_len integer +---@param payload string +---@param masking boolean +---@return string +function resty_websocket_protocol.build_frame(fin, opcode, payload_len, payload, masking) end + +--- Sends a raw WebSocket frame. +---@param sock tcpsock +---@param fin boolean +---@param opcode resty.websocket.protocol.opcode +---@param payload string +---@param max_payload_len interger +---@param masking boolean +---@return bytes? number +---@return string? error function resty_websocket_protocol.send_frame(sock, fin, opcode, payload, max_payload_len, masking) end -resty_websocket_protocol._VERSION="0.07" + +--- Receives a WebSocket frame from the wire. +---@param sock tcpsock +---@param max_payload_len interger +---@param force_masking boolean +---@return string? data +---@return resty.websocket.protocol.type? typ +---@return string? error function resty_websocket_protocol.recv_frame(sock, max_payload_len, force_masking) end + return resty_websocket_protocol
\ No newline at end of file diff --git a/meta/3rd/OpenResty/library/resty.websocket.server.lua b/meta/3rd/OpenResty/library/resty.websocket.server.lua index c9041a96..f590fcc8 100644 --- a/meta/3rd/OpenResty/library/resty.websocket.server.lua +++ b/meta/3rd/OpenResty/library/resty.websocket.server.lua @@ -1,13 +1,16 @@ ---@meta -resty_websocket_server={} -function resty_websocket_server.send_text(self, data) end -function resty_websocket_server.new(self, opts) end -function resty_websocket_server.send_ping(self, data) end -function resty_websocket_server.set_timeout(self, time) end -function resty_websocket_server.send_binary(self, data) end -function resty_websocket_server.send_frame() end -function resty_websocket_server.recv_frame(self) end -function resty_websocket_server.send_close(self, code, msg) end -resty_websocket_server._VERSION="0.07" -function resty_websocket_server.send_pong(self, data) end + +---@class resty.websocket.server : resty.websocket +resty_websocket_server = { + _VERSION = "0.09" +} + +---Performs the websocket handshake process on the server side and returns a WebSocket server object. +--- +---In case of error, it returns nil and a string describing the error. +---@param opts? resty.websocket.new.opts +---@return resty.websocket.server? server +---@return string? error +function resty_websocket_server:new(opts) end + return resty_websocket_server
\ No newline at end of file diff --git a/meta/template/math.lua b/meta/template/math.lua index f987eb0b..d9837424 100644 --- a/meta/template/math.lua +++ b/meta/template/math.lua @@ -87,7 +87,7 @@ function math.exp(x) end ---#DES 'math.floor' ---@param x number ----@return number +---@return integer ---@nodiscard function math.floor(x) end diff --git a/script/core/completion/completion.lua b/script/core/completion/completion.lua index dc005b52..d0bf5164 100644 --- a/script/core/completion/completion.lua +++ b/script/core/completion/completion.lua @@ -1064,14 +1064,14 @@ local function tryLabelInString(label, source) if not source or source.type ~= 'string' then return label end - local str = parser.grammar(label, 'String') - if not str then + local state = parser.parse(label, 'String') + if not state or not state.ast then return label end - if not matchKey(source[1], str[1]) then + if not matchKey(source[1], state.ast[1]) then return nil end - return util.viewString(str[1], source[2]) + return util.viewString(state.ast[1], source[2]) end local function mergeEnums(a, b, source) @@ -1354,20 +1354,6 @@ local function getCallEnumsAndFuncs(source, index, oop, call) end end if source.type == 'doc.type.function' then - --[[ - always use literal index, that is: - ``` - ---@class Class - ---@field f(x: number, y: boolean) - local c - - c.f(1, true) -- correct - c:f(1, true) -- also correct - ``` - --]] - if oop then - index = index - 1 - end local arg = source.args[index] if arg and arg.extends then return pushCallEnumsAndFuncs(vm.getDefs(arg.extends)) @@ -1959,6 +1945,7 @@ local function makeCache(uri, position, results) cache.position= position cache.word = word:lower() cache.length = #word + cache.uri = uri end local function isValidCache(word, result) @@ -1983,6 +1970,9 @@ local function getCache(uri, position) if not cache.results then return nil end + if cache.uri ~= uri then + return nil + end local text = files.getText(uri) local state = files.getState(uri) local word = lookBackward.findWord(text, guide.positionToOffset(state, position)) @@ -2058,6 +2048,9 @@ local function completion(uri, position, triggerCharacter) await.delay() tracy.ZoneBeginN 'completion #1' local state = files.getState(uri) + if not state then + return nil + end results = {} clearStack() tracy.ZoneEnd() diff --git a/script/core/definition.lua b/script/core/definition.lua index a1f46afc..eadae30f 100644 --- a/script/core/definition.lua +++ b/script/core/definition.lua @@ -4,6 +4,7 @@ local files = require 'files' local vm = require 'vm' local findSource = require 'core.find-source' local guide = require 'parser.guide' +local rpath = require 'workspace.require-path' local function sortResults(results) -- 先按照顺序排序 @@ -74,7 +75,7 @@ local function checkRequire(source, offset) return nil end if libName == 'require' then - return workspace.findUrisByRequirePath(literal) + return rpath.findUrisByRequirePath(literal) elseif libName == 'dofile' or libName == 'loadfile' then return workspace.findUrisByFilePath(literal) diff --git a/script/core/diagnostics/different-requires.lua b/script/core/diagnostics/different-requires.lua index fd7415b6..3a49ceef 100644 --- a/script/core/diagnostics/different-requires.lua +++ b/script/core/diagnostics/different-requires.lua @@ -3,7 +3,7 @@ local guide = require 'parser.guide' local lang = require 'language' local config = require 'config' local vm = require 'vm' -local ws = require 'workspace' +local rpath = require 'workspace.require-path' return function (uri, callback) local state = files.getState(uri) @@ -21,7 +21,7 @@ return function (uri, callback) return end local literal = arg1[1] - local results = ws.findUrisByRequirePath(literal) + local results = rpath.findUrisByRequirePath(literal) if not results or #results ~= 1 then return end diff --git a/script/core/diagnostics/unused-local.lua b/script/core/diagnostics/unused-local.lua index 072cbd31..7e7bd9d7 100644 --- a/script/core/diagnostics/unused-local.lua +++ b/script/core/diagnostics/unused-local.lua @@ -2,6 +2,7 @@ local files = require 'files' local guide = require 'parser.guide' local define = require 'proto.define' local lang = require 'language' +local vm = require 'vm.vm' local function hasGet(loc) if not loc.ref then @@ -96,7 +97,7 @@ return function (uri, callback) if isDocClass(source) then return end - if isDocParam(source) then + if vm.isMetaFile(uri) and isDocParam(source) then return end local data = hasGet(source) diff --git a/script/core/hint.lua b/script/core/hint.lua index b3aec88e..82c7371b 100644 --- a/script/core/hint.lua +++ b/script/core/hint.lua @@ -100,7 +100,7 @@ end ---@async local function paramName(uri, results, start, finish) local paramConfig = config.get(nil, 'Lua.hint.paramName') - if not paramConfig or paramConfig == 'None' then + if not paramConfig or paramConfig == 'Disable' then return end local state = files.getState(uri) diff --git a/script/core/hover/arg.lua b/script/core/hover/arg.lua index 4e6a1ace..d03f55f2 100644 --- a/script/core/hover/arg.lua +++ b/script/core/hover/arg.lua @@ -55,7 +55,7 @@ local function asFunction(source, oop) end end -local function asDocFunction(source) +local function asDocFunction(source, oop) if not source.args then return '' end @@ -69,7 +69,11 @@ local function asDocFunction(source) arg.extends and infer.searchAndViewInfers(arg.extends) or 'any' ) end - return table.concat(args, ', ') + if oop then + return table.concat(args, ', ', 2) + else + return table.concat(args, ', ') + end end return function (source, oop) @@ -77,7 +81,7 @@ return function (source, oop) return asFunction(source, oop) end if source.type == 'doc.type.function' then - return asDocFunction(source) + return asDocFunction(source, oop) end return '' end diff --git a/script/core/hover/description.lua b/script/core/hover/description.lua index 51027aed..59605f0d 100644 --- a/script/core/hover/description.lua +++ b/script/core/hover/description.lua @@ -9,12 +9,13 @@ local lang = require 'language' local util = require 'utility' local guide = require 'parser.guide' local noder = require 'core.noder' +local rpath = require 'workspace.require-path' local function collectRequire(mode, literal) local rootPath = ws.rootPath or '' local result, searchers if mode == 'require' then - result, searchers = ws.findUrisByRequirePath(literal) + result, searchers = rpath.findUrisByRequirePath(literal) elseif mode == 'dofile' or mode == 'loadfile' then result = ws.findUrisByFilePath(literal) @@ -63,7 +64,7 @@ end local function asStringView(source, literal) -- 内部包含转义符? - local rawLen = source.finish - source.start - 2 * #source[2] + 1 + local rawLen = source.finish - source.start - 2 * #source[2] if config.get(nil, 'Lua.hover.viewString') and (source[2] == '"' or source[2] == "'") and rawLen > #literal then diff --git a/script/core/hover/init.lua b/script/core/hover/init.lua index 7d99a006..baa24139 100644 --- a/script/core/hover/init.lua +++ b/script/core/hover/init.lua @@ -6,6 +6,7 @@ local util = require 'utility' local findSource = require 'core.find-source' local markdown = require 'provider.markdown' local infer = require 'core.infer' +local guide = require 'parser.guide' ---@async local function getHover(source) @@ -15,14 +16,14 @@ local function getHover(source) local descMark = {} ---@async - local function addHover(def, checkLable) + local function addHover(def, checkLable, oop) if defMark[def] then return end defMark[def] = true if checkLable then - local label = getLabel(def) + local label = getLabel(def, oop) if not labelMark[tostring(label)] then labelMark[tostring(label)] = true md:add('lua', label) @@ -38,27 +39,34 @@ local function getHover(source) end end + local oop if infer.searchAndViewInfers(source) == 'function' then local hasFunc for _, def in ipairs(vm.getDefs(source)) do + if guide.isOOP(def) then + oop = true + end if def.type == 'function' or def.type == 'doc.type.function' then hasFunc = true - addHover(def, true) + addHover(def, true, oop) end end if not hasFunc then - addHover(source, true) + addHover(source, true, oop) end else - addHover(source, true) + addHover(source, true, oop) for _, def in ipairs(vm.getDefs(source)) do + if guide.isOOP(def) then + oop = true + end local isFunction if def.type == 'function' or def.type == 'doc.type.function' then isFunction = true end - addHover(def, isFunction) + addHover(def, isFunction, oop) end end diff --git a/script/core/hover/label.lua b/script/core/hover/label.lua index f797d520..436ff913 100644 --- a/script/core/hover/label.lua +++ b/script/core/hover/label.lua @@ -11,30 +11,20 @@ local files = require 'files' local guide = require 'parser.guide' local function asFunction(source, oop) - local name - name, oop = buildName(source, oop) + local name = buildName(source, oop) local arg = buildArg(source, oop) local rtn = buildReturn(source) local lines = {} - lines[1] = ('%s%s %s(%s)'):format( - vm.isAsync(source) and 'async ' or '', - oop and 'method' or 'function', - name or '', arg + lines[1] = string.format('%s%s %s(%s)' + , vm.isAsync(source) and 'async ' or '' + , oop and 'method' or 'function' + , name or '' + , arg ) lines[2] = rtn return table.concat(lines, '\n') end -local function asDocFunction(source) - local name = buildName(source) - local arg = buildArg(source) - local rtn = buildReturn(source) - local lines = {} - lines[1] = ('function %s(%s)'):format(name or '', arg) - lines[2] = rtn - return table.concat(lines, '\n') -end - local function asDocTypeName(source) local defs = vm.getDefs(source) for _, doc in ipairs(defs) do @@ -188,7 +178,8 @@ end ---@async return function (source, oop) - if source.type == 'function' then + if source.type == 'function' + or source.type == 'doc.type.function' then return asFunction(source, oop) elseif source.type == 'local' or source.type == 'getlocal' @@ -210,8 +201,6 @@ return function (source, oop) elseif source.type == 'number' or source.type == 'integer' then return asNumber(source) - elseif source.type == 'doc.type.function' then - return asDocFunction(source) elseif source.type == 'doc.type.name' then return asDocTypeName(source) elseif source.type == 'doc.field.name' then diff --git a/script/core/hover/name.lua b/script/core/hover/name.lua index 0de13c9a..5d8f0b3d 100644 --- a/script/core/hover/name.lua +++ b/script/core/hover/name.lua @@ -46,14 +46,14 @@ local function asGlobal(source) return guide.getKeyName(source) end -local function asDocFunction(source) +local function asDocFunction(source, oop) local doc = guide.getParentType(source, 'doc.type') or guide.getParentType(source, 'doc.overload') if not doc or not doc.bindSources then return '' end for _, src in ipairs(doc.bindSources) do - local name = buildName(src) + local name = buildName(src, oop) if name ~= '' then return name end @@ -66,11 +66,6 @@ local function asDocField(source) end function buildName(source, oop) - if oop == nil then - oop = source.type == 'setmethod' - or source.type == 'getmethod' - or nil - end if source.type == 'local' then return asLocal(source) or '', oop end @@ -94,7 +89,7 @@ function buildName(source, oop) return asTableField(source) or '', oop end if source.type == 'doc.type.function' then - return asDocFunction(source), oop + return asDocFunction(source, oop), oop end if source.type == 'doc.field' then return asDocField(source), oop diff --git a/script/core/infer.lua b/script/core/infer.lua index 9166168b..9bb1e447 100644 --- a/script/core/infer.lua +++ b/script/core/infer.lua @@ -28,6 +28,7 @@ local function mergeTable(a, b) for v in pairs(b) do a[v] = true end + a[CACHE] = nil end local function isBaseType(source, mark) @@ -519,6 +520,9 @@ end ---@param mark? table ---@return table function m.searchLiterals(source, field, mark) + if not source then + return nil + end local defs = vm.getDefs(source, field) local literals = {} mark = mark or {} @@ -540,6 +544,9 @@ function m.searchAndViewLiterals(source, field, mark) return nil end local literals = m.searchLiterals(source, field, mark) + if not literals then + return nil + end local view = m.viewLiterals(literals) return view end @@ -558,10 +565,12 @@ function m.isTrue(source, mark) if mark.isTrue[source] == nil then mark.isTrue[source] = false local literals = m.searchLiterals(source, nil, mark) - for literal in pairs(literals) do - if literal ~= false then - mark.isTrue[source] = true - break + if literals then + for literal in pairs(literals) do + if literal ~= false then + mark.isTrue[source] = true + break + end end end end diff --git a/script/core/searcher.lua b/script/core/searcher.lua index 1f4091b3..8e4873aa 100644 --- a/script/core/searcher.lua +++ b/script/core/searcher.lua @@ -2,7 +2,7 @@ local noder = require 'core.noder' local guide = require 'parser.guide' local files = require 'files' local generic = require 'core.generic' -local ws = require 'workspace' +local rpath = require 'workspace.require-path' local vm = require 'vm.vm' local collector = require 'core.collector' local util = require 'utility' @@ -796,7 +796,7 @@ function m.searchRefsByID(status, suri, expect, mode) if not requireName then return end - local uris = ws.findUrisByRequirePath(requireName) + local uris = rpath.findUrisByRequirePath(requireName) footprint(status, 'require:', requireName) for i = 1, #uris do local ruri = uris[i] diff --git a/script/core/type-definition.lua b/script/core/type-definition.lua index dee07c61..e9cf3e47 100644 --- a/script/core/type-definition.lua +++ b/script/core/type-definition.lua @@ -5,6 +5,7 @@ local vm = require 'vm' local findSource = require 'core.find-source' local guide = require 'parser.guide' local infer = require 'core.infer' +local rpath = require 'workspace.require-path' local function sortResults(results) -- 先按照顺序排序 @@ -75,7 +76,7 @@ local function checkRequire(source, offset) return nil end if libName == 'require' then - return workspace.findUrisByRequirePath(literal) + return rpath.findUrisByRequirePath(literal) elseif libName == 'dofile' or libName == 'loadfile' then return workspace.findUrisByFilePath(literal) diff --git a/script/encoder/utf16.lua b/script/encoder/utf16.lua index 744da174..7b08e082 100644 --- a/script/encoder/utf16.lua +++ b/script/encoder/utf16.lua @@ -92,6 +92,8 @@ local function utf8next(s, n) return n+3, utf8byte(s, n) elseif strmatch(s, "^[\xED][\x80-\x9F][\x80-\xBF]", n) then return n+3, utf8byte(s, n) + elseif strmatch(s, "^[\xEE-\xEF][\x80-\xBF][\x80-\xBF]", n) then + return n+3, utf8byte(s, n) elseif strmatch(s, "^[\xF0][\x90-\xBF][\x80-\xBF][\x80-\xBF]", n) then return n+4, utf8byte(s, n) elseif strmatch(s, "^[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]", n) then diff --git a/script/library.lua b/script/library.lua index ef62ceab..cddb19fd 100644 --- a/script/library.lua +++ b/script/library.lua @@ -221,8 +221,13 @@ local function initBuiltIn() end m.metaPath = metaPath:string() m.metaPaths = {} - if not fs.exists(metaPath) then - fs.create_directories(metaPath) + local suc = xpcall(function () + if not fs.exists(metaPath) then + fs.create_directories(metaPath) + end + end, log.error) + if not suc then + return end local out = fsu.dummyFS() local templateDir = ROOT / 'meta' / 'template' @@ -462,7 +467,9 @@ local function check3rd(uri) if checkedUri(uri) then if files.isLua(uri) then local text = files.getText(uri) - check3rdByWords(text, thirdConfigs) + if text then + check3rdByWords(text, thirdConfigs) + end end check3rdByFileName(uri, thirdConfigs) end diff --git a/script/log.lua b/script/log.lua index c3bf02d4..90de895a 100644 --- a/script/log.lua +++ b/script/log.lua @@ -12,8 +12,6 @@ local mathModf = math.modf local debugGetInfo = debug.getinfo local ioStdErr = io.stderr -_ENV = nil - local m = {} m.file = nil @@ -91,9 +89,6 @@ function m.raw(thd, level, msg, source, currentline, clock) return end init_log_file() - if not m.file then - return '' - end local sec, ms = mathModf((m.startTime + clock) / 1000) local timestr = osDate('%H:%M:%S', sec) local agl = '' @@ -107,11 +102,13 @@ function m.raw(thd, level, msg, source, currentline, clock) buf = ('[%s.%03.f][%s]%s[#%d:%s:%s]: %s\n'):format(timestr, ms * 1000, level, agl, thd, trimSrc(source), currentline, msg) end m.size = m.size + #buf - if m.size > m.maxSize then - m.file:write(buf:sub(1, m.size - m.maxSize)) - m.file:write('[REACH MAX SIZE]') - else - m.file:write(buf) + if m.file then + if m.size > m.maxSize then + m.file:write(buf:sub(1, m.size - m.maxSize)) + m.file:write('[REACH MAX SIZE]') + else + m.file:write(buf) + end end return buf end @@ -130,9 +127,11 @@ function m.init(root, path) m.path = path:string() m.prefixLen = #root:string() m.size = 0 - if not fs.exists(path:parent_path()) then - fs.create_directories(path:parent_path()) - end + pcall(function () + if not fs.exists(path:parent_path()) then + fs.create_directories(path:parent_path()) + end + end) if lastBuf then init_log_file() if m.file then diff --git a/script/parser/guide.lua b/script/parser/guide.lua index 54e61e7f..d55ba099 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -1160,5 +1160,17 @@ function m.isInString(ast, position) end) end +function m.isOOP(source) + if source.type == 'setmethod' + or source.type == 'getmethod' then + return true + end + if source.type == 'method' + or source.type == 'field' + or source.type == 'function' then + return m.isOOP(source.parent) + end + return false +end return m diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index bfadcf8a..4d46d674 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -4,7 +4,7 @@ local guide = require 'parser.guide' local parser = require 'parser.newparser' local TokenTypes, TokenStarts, TokenFinishs, TokenContents, TokenMarks -local Ci, Offset, pushError, NextComment, Lines +local Ci, Offset, pushWarning, NextComment, Lines local parseType local Parser = re.compile([[ Main <- (Token / Sp)* @@ -204,7 +204,7 @@ local function nextSymbolOrError(symbol) nextToken() return true end - pushError { + pushWarning { type = 'LUADOC_MISS_SYMBOL', start = getFinish(), finish = getFinish(), @@ -229,7 +229,7 @@ local function parseIndexField(tp, parent) local indexTP, index = nextToken() if indexTP ~= 'integer' and indexTP ~= 'string' then - pushError { + pushWarning { type = 'LUADOC_INDEX_MUST_INT', start = getStart(), finish = getFinish(), @@ -249,7 +249,7 @@ local function parseClass(parent) } result.class = parseName('doc.class.name', result) if not result.class then - pushError { + pushWarning { type = 'LUADOC_MISS_CLASS_NAME', start = getFinish(), finish = getFinish(), @@ -268,7 +268,7 @@ local function parseClass(parent) while true do local extend = parseName('doc.extends.name', result) if not extend then - pushError { + pushWarning { type = 'LUADOC_MISS_CLASS_EXTENDS_NAME', start = getFinish(), finish = getFinish(), @@ -371,7 +371,7 @@ local function parseTypeUnitFunction() arg.name = parseName('doc.type.name', arg) or parseDots('doc.type.name', arg) if not arg.name then - pushError { + pushWarning { type = 'LUADOC_MISS_ARG_NAME', start = getFinish(), finish = getFinish(), @@ -443,7 +443,7 @@ local function parseTypeUnitLiteralTable() field.name = parseName('doc.field.name', field) or parseIndexField('doc.field.name', field) if not field.name then - pushError { + pushWarning { type = 'LUADOC_MISS_FIELD_NAME', start = getFinish(), finish = getFinish(), @@ -480,7 +480,9 @@ local function parseTypeUnitLiteralTable() return typeUnit end -local function parseTypeUnit(parent, content) +local parseTypeUnit + +local function parseDocFunction(parent, content) if content == 'async' then local tp, cont = peekToken() if tp == 'name' then @@ -494,12 +496,17 @@ local function parseTypeUnit(parent, content) end end end - local result if content == 'fun' then - result = parseTypeUnitFunction() + return parseTypeUnitFunction() end - if content == '{' then - result = parseTypeUnitLiteralTable() +end + +function parseTypeUnit(parent, content) + local result = parseDocFunction(parent, content) + if not result then + if content == '{' then + result = parseTypeUnitLiteralTable() + end end if not result then result = { @@ -542,7 +549,7 @@ local function parseResume(parent) local tp = peekToken() if tp ~= 'string' then - pushError { + pushWarning { type = 'LUADOC_MISS_STRING', start = getFinish(), finish = getFinish(), @@ -709,7 +716,7 @@ function parseType(parent) end if #result.types == 0 and #result.enums == 0 and #result.resumes == 0 then - pushError { + pushWarning { type = 'LUADOC_MISS_TYPE_NAME', start = getFinish(), finish = getFinish(), @@ -725,7 +732,7 @@ local function parseAlias() } result.alias = parseName('doc.alias.name', result) if not result.alias then - pushError { + pushWarning { type = 'LUADOC_MISS_ALIAS_NAME', start = getFinish(), finish = getFinish(), @@ -735,7 +742,7 @@ local function parseAlias() result.start = getStart() result.extends = parseType(result) if not result.extends then - pushError { + pushWarning { type = 'LUADOC_MISS_ALIAS_EXTENDS', start = getFinish(), finish = getFinish(), @@ -753,7 +760,7 @@ local function parseParam() result.param = parseName('doc.param.name', result) or parseDots('doc.param.name', result) if not result.param then - pushError { + pushWarning { type = 'LUADOC_MISS_PARAM_NAME', start = getFinish(), finish = getFinish(), @@ -768,7 +775,7 @@ local function parseParam() result.finish = getFinish() result.extends = parseType(result) if not result.extends then - pushError { + pushWarning { type = 'LUADOC_MISS_PARAM_EXTENDS', start = getFinish(), finish = getFinish(), @@ -831,7 +838,7 @@ local function parseField() result.field = parseName('doc.field.name', result) or parseIndexField('doc.field.name', result) if not result.field then - pushError { + pushWarning { type = 'LUADOC_MISS_FIELD_NAME', start = getFinish(), finish = getFinish(), @@ -847,7 +854,7 @@ local function parseField() end result.extends = parseType(result) if not result.extends then - pushError { + pushWarning { type = 'LUADOC_MISS_FIELD_EXTENDS', start = getFinish(), finish = getFinish(), @@ -870,7 +877,7 @@ local function parseGeneric() } object.generic = parseName('doc.generic.name', object) if not object.generic then - pushError { + pushWarning { type = 'LUADOC_MISS_GENERIC_NAME', start = getFinish(), finish = getFinish(), @@ -902,7 +909,7 @@ local function parseVararg() } result.vararg = parseType(result) if not result.vararg then - pushError { + pushWarning { type = 'LUADOC_MISS_VARARG_TYPE', start = getFinish(), finish = getFinish(), @@ -916,8 +923,9 @@ end local function parseOverload() local tp, name = peekToken() - if tp ~= 'name' or name ~= 'fun' then - pushError { + if tp ~= 'name' + or (name ~= 'fun' and name ~= 'async') then + pushWarning { type = 'LUADOC_MISS_FUN_AFTER_OVERLOAD', start = getFinish(), finish = getFinish(), @@ -928,7 +936,7 @@ local function parseOverload() local result = { type = 'doc.overload', } - result.overload = parseTypeUnitFunction() + result.overload = parseDocFunction(result, name) if not result.overload then return nil end @@ -962,7 +970,7 @@ local function parseVersion() while true do local tp, text = nextToken() if not tp then - pushError { + pushWarning { type = 'LUADOC_MISS_VERSION', start = getFinish(), finish = getFinish(), @@ -985,7 +993,7 @@ local function parseVersion() tp, text = nextToken() end if tp ~= 'name' then - pushError { + pushWarning { type = 'LUADOC_MISS_VERSION', start = getStart(), finish = getFinish(), @@ -1031,7 +1039,7 @@ local function parseDiagnostic() } local nextTP, mode = nextToken() if nextTP ~= 'name' then - pushError { + pushWarning { type = 'LUADOC_MISS_DIAG_MODE', start = getFinish(), finish = getFinish(), @@ -1045,7 +1053,7 @@ local function parseDiagnostic() and mode ~= 'disable-line' and mode ~= 'disable' and mode ~= 'enable' then - pushError { + pushWarning { type = 'LUADOC_ERROR_DIAG_MODE', start = result.start, finish = result.finish, @@ -1058,7 +1066,7 @@ local function parseDiagnostic() while true do local name = parseName('doc.diagnostic.name', result) if not name then - pushError { + pushWarning { type = 'LUADOC_MISS_DIAG_NAME', start = getFinish(), finish = getFinish(), @@ -1092,7 +1100,7 @@ local function parseModule() result.finish = getFinish() result.smark = getMark() else - pushError { + pushWarning { type = 'LUADOC_MISS_MODULE_NAME', start = getFinish(), finish = getFinish(), @@ -1123,7 +1131,7 @@ local function convertTokens() return end if tp ~= 'name' then - pushError { + pushWarning { type = 'LUADOC_MISS_CATE_NAME', start = getStart(), finish = getFinish(), @@ -1420,8 +1428,11 @@ return function (state) groups = {}, } - pushError = state.pushError - Lines = state.lines + pushWarning = function (err) + err.level = err.level or 'Warning' + state.pushError(err) + end + Lines = state.lines local ci = 1 NextComment = function (offset, peek) diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 187de9b3..15d2d600 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -942,7 +942,7 @@ local function parseShortString() end if not token then stringIndex = stringIndex + 1 - stringPool[stringIndex] = ssub(Lua, currentOffset) + stringPool[stringIndex] = ssub(Lua, currentOffset or -1) missSymbol(mark) break end @@ -1649,11 +1649,13 @@ local function parseTable() wantSep = true local tindex = parseIndex() skipSpace() + tindex.type = 'tableindex' + tindex.parent = tbl + index = index + 1 + tbl[index] = tindex if expectAssign() then skipSpace() local ivalue = parseExp() - tindex.type = 'tableindex' - tindex.parent = tbl if ivalue then ivalue.parent = tindex tindex.finish = ivalue.finish @@ -1661,8 +1663,6 @@ local function parseTable() else missExp() end - index = index + 1 - tbl[index] = tindex else missSymbol '=' end @@ -3714,7 +3714,7 @@ local function initState(lua, version, options) return end end - err.level = err.level or 'error' + err.level = err.level or 'Error' errs[#errs+1] = err return err end diff --git a/script/provider/diagnostic.lua b/script/provider/diagnostic.lua index a6724a29..fb9a745e 100644 --- a/script/provider/diagnostic.lua +++ b/script/provider/diagnostic.lua @@ -58,7 +58,7 @@ local function buildSyntaxError(uri, err) return { code = err.type:lower():gsub('_', '-'), range = converter.packRange(uri, err.start, err.finish), - severity = define.DiagnosticSeverity.Error, + severity = define.DiagnosticSeverity[err.level], source = lang.script.DIAG_SYNTAX_CHECK, message = message, relatedInformation = relatedInformation, diff --git a/script/vm/getLinks.lua b/script/vm/getLinks.lua index b245bdaa..77d869f8 100644 --- a/script/vm/getLinks.lua +++ b/script/vm/getLinks.lua @@ -2,9 +2,9 @@ local guide = require 'parser.guide' ---@class vm local vm = require 'vm.vm' local files = require 'files' +local rpath = require 'workspace.require-path' local function getFileLinks(uri) - local ws = require 'workspace' local links = {} local state = files.getState(uri) if not state then @@ -20,7 +20,7 @@ local function getFileLinks(uri) if not args or not args[1] or args[1].type ~= 'string' then return end - local uris = ws.findUrisByRequirePath(args[1][1]) + local uris = rpath.findUrisByRequirePath(args[1][1]) for _, u in ipairs(uris) do if not links[u] then links[u] = {} diff --git a/script/workspace/require-path.lua b/script/workspace/require-path.lua index e6bb6c78..04c8abf8 100644 --- a/script/workspace/require-path.lua +++ b/script/workspace/require-path.lua @@ -30,7 +30,7 @@ end function m.getVisiblePath(path) local searchers = config.get(nil, 'Lua.runtime.path') local strict = config.get(nil, 'Lua.runtime.pathStrict') - path = path:gsub('^[/\\]+', '') + path = workspace.normalize(path) local uri = furi.encode(path) local libraryPath = files.getLibraryPath(uri) if not m.cache[path] then @@ -42,6 +42,7 @@ function m.getVisiblePath(path) for _, searcher in ipairs(searchers) do local isAbsolute = searcher:match '^[/\\]' or searcher:match '^%a+%:' + searcher = workspace.normalize(searcher) local cutedPath = path local currentPath = path local head @@ -59,10 +60,8 @@ function m.getVisiblePath(path) pos = currentPath:match('[/\\]+()', pos) if platform.OS == 'Windows' then searcher = searcher :gsub('[/\\]+', '\\') - :gsub('^[/\\]+', '') else searcher = searcher :gsub('[/\\]+', '/') - :gsub('^[/\\]+', '') end local expect = getOnePath(cutedPath, searcher) if expect then @@ -81,6 +80,50 @@ function m.getVisiblePath(path) return m.cache[path] end +--- 查找符合指定require path的所有uri +---@param path string +function m.findUrisByRequirePath(path) + if type(path) ~= 'string' then + return {} + end + local separator = config.get 'Lua.completion.requireSeparator' + local fspath = path:gsub('%' .. separator, '/') + local vm = require 'vm' + local cache = vm.getCache 'findUrisByRequirePath' + if cache[path] then + return cache[path].results, cache[path].searchers + end + tracy.ZoneBeginN('findUrisByRequirePath') + local results = {} + local searchers = {} + for uri in files.eachDll() do + local opens = files.getDllOpens(uri) or {} + for _, open in ipairs(opens) do + if open == fspath then + results[#results+1] = uri + end + end + end + + for uri in files.eachFile() do + local infos = m.getVisiblePath(furi.decode(uri)) + for _, info in ipairs(infos) do + local fsexpect = info.expect:gsub('%' .. separator, '/') + if fsexpect == fspath then + results[#results+1] = uri + searchers[uri] = info.searcher + end + end + end + + tracy.ZoneEnd() + cache[path] = { + results = results, + searchers = searchers, + } + return results, searchers +end + function m.flush() m.cache = {} end diff --git a/script/workspace/workspace.lua b/script/workspace/workspace.lua index 12971ae5..a2f99b3e 100644 --- a/script/workspace/workspace.lua +++ b/script/workspace/workspace.lua @@ -262,89 +262,20 @@ function m.findUrisByFilePath(path) if type(path) ~= 'string' then return {} end - local lpath = furi.encode(path):gsub('^file:///', '') + local myUri = furi.encode(path) local vm = require 'vm' local resultCache = vm.getCache 'findUrisByRequirePath.result' if resultCache[path] then - return resultCache[path].results, resultCache[path].posts + return resultCache[path] end - tracy.ZoneBeginN('findUrisByFilePath #1') - local strict = config.get(nil, 'Lua.runtime.pathStrict') local results = {} - local posts = {} for uri in files.eachFile() do - if not uri:find(lpath, 1, true) then - goto CONTINUE - end - local relat = m.getRelativePath(uri) - local pathLen = #path - local curPath = relat - local curLen = #curPath - local seg = curPath:sub(curLen - pathLen, curLen - pathLen) - if seg == '/' or seg == '\\' or seg == '' then - if strict and seg ~= '' then - goto CONTINUE - end - local see = curPath:sub(curLen - pathLen + 1, curLen) - if see == path then - results[#results+1] = uri - local post = curPath:sub(1, curLen - pathLen) - posts[uri] = post:gsub('^[/\\]+', '') - end - end - ::CONTINUE:: - end - tracy.ZoneEnd() - resultCache[path] = { - results = results, - posts = posts, - } - return results, posts -end - ---- 查找符合指定require path的所有uri ----@param path string -function m.findUrisByRequirePath(path) - if type(path) ~= 'string' then - return {} - end - local vm = require 'vm' - local cache = vm.getCache 'findUrisByRequirePath' - if cache[path] then - return cache[path].results, cache[path].searchers - end - tracy.ZoneBeginN('findUrisByRequirePath') - local results = {} - local mark = {} - local searchers = {} - for uri in files.eachDll() do - local opens = files.getDllOpens(uri) or {} - for _, open in ipairs(opens) do - if open == path then - results[#results+1] = uri - end - end - end - - local input = path:gsub('%.', '/') - :gsub('%%', '%%%%') - for _, luapath in ipairs(config.get(nil, 'Lua.runtime.path')) do - local part = m.normalize(luapath:gsub('%?', input)) - local uris, posts = m.findUrisByFilePath(part) - for _, uri in ipairs(uris) do - if not mark[uri] then - mark[uri] = true - results[#results+1] = uri - searchers[uri] = posts[uri] .. luapath - end + if uri == myUri then + results[#results+1] = uri end end - tracy.ZoneEnd() - cache[path] = { - results = results, - searchers = searchers, - } - return results, searchers + resultCache[path] = results + return results end function m.normalize(path) @@ -361,6 +292,7 @@ function m.normalize(path) end end) path = util.expandPath(path) + path = path:gsub('^%.[/\\]+', '') if platform.OS == 'Windows' then path = path:gsub('[/\\]+', '\\') :gsub('[/\\]+$', '') @@ -2,7 +2,7 @@ package.path = package.path .. ';./test/?.lua' .. ';./test/?/init.lua' local fs = require 'bee.filesystem' -local rootPath = fs.exe_path():parent_path():parent_path():parent_path():string() +local rootPath = fs.exe_path():parent_path():parent_path():string() ROOT = fs.path(rootPath) TEST = true DEVELOP = true diff --git a/test/completion/common.lua b/test/completion/common.lua index 94b55514..b03d55ca 100644 --- a/test/completion/common.lua +++ b/test/completion/common.lua @@ -2593,7 +2593,7 @@ c:<??> TEST [[ ---@class Class ----@field on fun(x: "'aaa'"|"'bbb'") +---@field on fun(self, x: "'aaa'"|"'bbb'") local c c:on(<??>) @@ -2605,7 +2605,7 @@ TEST [[ ---@field on fun(x: "'aaa'"|"'bbb'") local c -c:on('<??>') +c.on('<??>') ]] (EXISTS) @@ -3037,3 +3037,26 @@ end) } }, } + +TEST [[ +---@meta + +---@alias testAlias +---| "'test1'" +---| "'test2'" +---| "'test3'" + +---@class TestClass +local TestClass = {} + +---@overload fun(self: TestClass, arg2: testAlias) +---@param arg1 integer +---@param arg2 testAlias +function TestClass:testFunc2(arg1, arg2) end + +---@type TestClass +local t + +t:testFunc2(<??>) +]] +(EXISTS) diff --git a/test/crossfile/definition.lua b/test/crossfile/definition.lua index 8f4dd7e8..c9a95658 100644 --- a/test/crossfile/definition.lua +++ b/test/crossfile/definition.lua @@ -867,3 +867,93 @@ print(t.<?x?>) ]] } } + +local originRuntimePath = config.get 'Lua.runtime.path' + +config.set('Lua.runtime.path', { + './?.lua' +}) +TEST { + { + path = 'a.lua', + content = [[ +return { + <!x!> = 1, +} +]], + }, + { + path = 'b.lua', + content = [[ +local t = require 'a' +print(t.<?x?>) + ]] + } +} + +config.set('Lua.runtime.path', { + '/home/?.lua' +}) +TEST { + { + path = '/home/a.lua', + content = [[ +return { + <!x!> = 1, +} +]], + }, + { + path = 'b.lua', + content = [[ +local t = require 'a' +print(t.<?x?>) + ]] + } +} + +config.set('Lua.runtime.pathStrict', true) +config.set('Lua.runtime.path', { + './?.lua' +}) +TEST { + { + path = 'a.lua', + content = [[ +return { + <!x!> = 1, +} +]], + }, + { + path = 'b.lua', + content = [[ +local t = require 'a' +print(t.<?x?>) + ]] + } +} + +config.set('Lua.runtime.path', { + '/home/?.lua' +}) +TEST { + { + path = '/home/a.lua', + content = [[ +return { + <!x!> = 1, +} +]], + }, + { + path = 'b.lua', + content = [[ +local t = require 'a' +print(t.<?x?>) + ]] + } +} + +config.set('Lua.runtime.pathStrict', false) +config.set('Lua.runtime.path', originRuntimePath) diff --git a/test/crossfile/hover.lua b/test/crossfile/hover.lua index 86471936..492efe43 100644 --- a/test/crossfile/hover.lua +++ b/test/crossfile/hover.lua @@ -41,20 +41,17 @@ end function TEST(expect) files.removeAll() - local targetScript, targetList = catch(expect[1].content, '?') - local targetUri = furi.encode(expect[1].path) - - local sourceScript, sourceList = catch(expect[2].content, '?') - local sourceUri = furi.encode(expect[2].path) - - files.setText(targetUri, targetScript) - files.setText(sourceUri, sourceScript) - - if targetList['?'] then - local targetPos = (targetList['?'][1][1] + targetList['?'][1][2]) // 2 - core.byUri(targetUri, targetPos) + local sourcePos, sourceUri + for _, file in ipairs(expect) do + local script, list = catch(file.content, '?') + local uri = furi.encode(file.path) + files.setText(uri, script) + if list['?'] then + sourceUri = uri + sourcePos = (list['?'][1][1] + list['?'][1][2]) // 2 + end end - local sourcePos = (sourceList['?'][1][1] + sourceList['?'][1][2]) // 2 + local hover = core.byUri(sourceUri, sourcePos) assert(hover) hover = tostring(hover):gsub('\r\n', '\n') @@ -1075,3 +1072,64 @@ global G: A { } ```]] } + +TEST { + { + path = 'a.lua', + content = [[ + ---@overload fun(self, a) + function C:<?f?>(a, b) end + ]] + }, + hover = [[ +```lua +method C:f(a: any, b: any) +``` + +--- + +```lua +method C:f(a: any) +```]] +} + +TEST { + { + path = 'a.lua', + content = [[ + ---@overload fun(self, a) + function C.<?f?>(a, b) end + ]] + }, + hover = [[ +```lua +function C.f(a: any, b: any) +``` + +--- + +```lua +function C.f(self: any, a: any) +```]] +} + +TEST { + { + path = 'a.lua', + content = [[ + ---@async + ---@overload async fun(self, a) + function C:<?f?>(a, b) end + ]] + }, + hover = [[ +```lua +async method C:f(a: any, b: any) +``` + +--- + +```lua +async method C:f(a: any) +```]] +} diff --git a/test/diagnostics/init.lua b/test/diagnostics/init.lua index f95c0bad..16c85a63 100644 --- a/test/diagnostics/init.lua +++ b/test/diagnostics/init.lua @@ -975,6 +975,14 @@ end TEST [[ ---@param a number +return function (<!a!>) +end +]] + +TEST [[ +---@meta + +---@param a number return function (a) end ]] @@ -1154,6 +1162,7 @@ TEST [[ local emit = {} ]] +config.get 'Lua.diagnostics.neededFileStatus' ['unused-local'] = 'None' TEST [[ ---@param table table ---@param metatable table @@ -1292,6 +1301,8 @@ trim('str', 'left') trim('str', nil) ]] +config.get 'Lua.diagnostics.neededFileStatus' ['unused-local'] = 'Any' + ---不完整的函数参数定义,会跳过检查 TEST [[ ---@param mode string |