diff --git a/.gitmodules b/.gitmodules index 0a1d17a88..454056b0c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "3rd/lovr-api"] path = 3rd/lovr-api url = https://github.com/bjornbytes/lovr-docs +[submodule "3rd/EmmyLuaCodeStyle"] + path = 3rd/EmmyLuaCodeStyle + url = https://github.com/CppCXY/EmmyLuaCodeStyle diff --git a/3rd/EmmyLuaCodeStyle b/3rd/EmmyLuaCodeStyle new file mode 160000 index 000000000..ec5766196 --- /dev/null +++ b/3rd/EmmyLuaCodeStyle @@ -0,0 +1 @@ +Subproject commit ec576619643cdb70a8ffc7711bd57aa4d311f765 diff --git a/make.lua b/make.lua index 25e9d38df..466fe4a46 100644 --- a/make.lua +++ b/make.lua @@ -37,6 +37,7 @@ elseif platform.OS == 'Linux' then end lm:import "3rd/bee.lua/make.lua" +lm:import "make/code_format.lua" lm:source_set 'lpeglabel' { rootdir = '3rd', @@ -48,7 +49,7 @@ lm:source_set 'lpeglabel' { } lm:executable "lua-language-server" { - deps = {"lpeglabel", "source_bootstrap"}, + deps = {"lpeglabel", "source_bootstrap", "code_format"}, includes = { "3rd/bee.lua", "3rd/bee.lua/3rd/lua", diff --git a/make/code_format.lua b/make/code_format.lua new file mode 100644 index 000000000..17007fdda --- /dev/null +++ b/make/code_format.lua @@ -0,0 +1,27 @@ +local lm = require 'luamake' + +lm:source_set 'code_format' { + rootdir = '../3rd/EmmyLuaCodeStyle', + includes = { + "include", + "../bee.lua/3rd/lua" + }, + sources = { + -- codeFormatLib + "CodeFormatLib/src/*.cpp", + -- LuaParser + "LuaParser/src/*.cpp", + "LuaParser/src/LuaAstNode/LuaAstNode.cpp", + -- Util + "Util/src/StringUtil.cpp", + "Util/src/Utf8.cpp", + --CodeService + "CodeService/src/*.cpp", + "CodeService/src/FormatElement/*.cpp", + "CodeService/src/NameStyle/*.cpp" + }, + macos = { + -- macosx10.12不支持完整的std filesystem,只好砍功能 + defines = "NOT_SURPPORT_FILE_SYSTEM", + }, +} diff --git a/make/modules.cpp b/make/modules.cpp index f72fc058f..8fe065a8d 100644 --- a/make/modules.cpp +++ b/make/modules.cpp @@ -2,3 +2,7 @@ extern "C" int luaopen_lpeglabel (lua_State *L); static ::bee::lua::callfunc _init(::bee::lua::register_module, "lpeglabel", luaopen_lpeglabel); + +extern "C" int luaopen_code_format(lua_State *L); +static ::bee::lua::callfunc _init_code_format(::bee::lua::register_module, "code_format", + luaopen_code_format); diff --git a/script/core/diagnostics/codestyle-check.lua b/script/core/diagnostics/codestyle-check.lua new file mode 100644 index 000000000..16623ecab --- /dev/null +++ b/script/core/diagnostics/codestyle-check.lua @@ -0,0 +1,34 @@ +local files = require("files") +local codeFormat = require "code_format" +local converter = require("proto.converter") +local log = require("log") +local config = require("config") + + +---@async +return function(uri, callback) + local text = files.getText(uri) + if not text then + return + end + + local status, diagnosticInfos = codeFormat.diagnose_file(uri, text) + + if not status then + if diagnosticInfos ~= nil then + log.error(diagnosticInfos) + end + + return + end + + if diagnosticInfos then + for _, diagnosticInfo in pairs(diagnosticInfos) do + callback { + start = converter.unpackPosition(uri, diagnosticInfo.range.start), + finish = converter.unpackPosition(uri, diagnosticInfo.range["end"]), + message = diagnosticInfo.message + } + end + end +end diff --git a/script/core/formatting.lua b/script/core/formatting.lua new file mode 100644 index 000000000..6c57b8c23 --- /dev/null +++ b/script/core/formatting.lua @@ -0,0 +1,25 @@ +local codeFormat = require("code_format") +local files = require("files") +local log = require("log") + +return function(uri) + local text = files.getText(uri) + local ast = files.getState(uri) + local status, formattedText = codeFormat.format(uri, text) + + if not status then + if formattedText ~= nil then + log.error(formattedText) + end + + return + end + + return { + { + start = ast.ast.start, + finish = ast.ast.finish, + text = formattedText, + } + } +end diff --git a/script/core/rangeformatting.lua b/script/core/rangeformatting.lua new file mode 100644 index 000000000..de9516c11 --- /dev/null +++ b/script/core/rangeformatting.lua @@ -0,0 +1,26 @@ +local codeFormat = require("code_format") +local files = require("files") +local log = require("log") +local converter = require("proto.converter") + +return function(uri, range) + local text = files.getText(uri) + local status, formattedText, startLine, endLine = codeFormat.range_format( + uri, text, range.start.line, range["end"].line) + + if not status then + if formattedText ~= nil then + log.error(formattedText) + end + + return + end + + return { + { + start = converter.unpackPosition(uri, { line = startLine, character = 0 }), + finish = converter.unpackPosition(uri, { line = endLine + 1, character = 0 }), + text = formattedText, + } + } +end diff --git a/script/core/type-formatting.lua b/script/core/type-formatting.lua index b946184bc..cc3059825 100644 --- a/script/core/type-formatting.lua +++ b/script/core/type-formatting.lua @@ -46,6 +46,7 @@ local function checkSplitOneLine(results, uri, position, ch) if ch ~= '\n' then return end + local fPosition, fSymbol = findForward(uri, position, 'end', '}') if not fPosition then return @@ -77,7 +78,7 @@ local function checkSplitOneLine(results, uri, position, ch) end return function (uri, position, ch) - local ast = files.getState(uri) + local ast = files.getState(uri) if not ast then return nil end diff --git a/script/proto/define.lua b/script/proto/define.lua index dbb6ba85d..b4a0da0ce 100644 --- a/script/proto/define.lua +++ b/script/proto/define.lua @@ -58,6 +58,7 @@ m.DiagnosticDefaultSeverity = { ['doc-field-no-class'] = 'Warning', ['duplicate-doc-field'] = 'Warning', ['unknown-diag-code'] = 'Waiting', + ['codestyle-check'] = "Warning", } ---@alias DiagnosticDefaultNeededFileStatus diff --git a/script/provider/capability.lua b/script/provider/capability.lua index 8a1424ca8..e13e11e01 100644 --- a/script/provider/capability.lua +++ b/script/provider/capability.lua @@ -112,9 +112,8 @@ function m.getIniter() range = true, full = false, }, - --documentOnTypeFormattingProvider = { - -- firstTriggerCharacter = '}', - --}, + documentFormattingProvider = true, + documentRangeFormattingProvider = true } --testFileEvents() diff --git a/script/provider/provider.lua b/script/provider/provider.lua index 4b22cb473..329bc66bd 100644 --- a/script/provider/provider.lua +++ b/script/provider/provider.lua @@ -101,6 +101,19 @@ m.register 'initialize' { workspace.create(params.rootUri) end + if params.initializationOptions then + if params.initializationOptions.editorConfigFiles then + local codeFormat = require "code_format" + for _, config in pairs(params.initializationOptions.editorConfigFiles) do + local status, err = codeFormat.update_config(1, config.workspace, config.path) + + if not status and err ~= nil then + log.error(err) + end + end + end + end + return { capabilities = cap.getIniter(), serverInfo = { @@ -911,6 +924,79 @@ m.register '$/status/click' { end } +m.register 'textDocument/formatting' { + abortByFileUpdate = true, + ---@async + function(params) + local uri = files.getRealUri(params.textDocument.uri) + workspace.awaitReady(uri) + local _ = progress.create(workspace.getScope(uri), lang.script.WINDOW_PROCESSING_TYPE_FORMATTING, 0.5) + + if not files.exists(uri) then + return nil + end + + local core = require 'core.formatting' + local edits = core(uri) + if not edits or #edits == 0 then + return nil + end + + local results = {} + for i, edit in ipairs(edits) do + results[i] = { + range = converter.packRange(uri, edit.start, edit.finish), + newText = edit.text, + } + end + + return results + end +} + +m.register 'textDocument/rangeFormatting' { + abortByFileUpdate = true, + ---@async + function(params) + local uri = files.getRealUri(params.textDocument.uri) + workspace.awaitReady(uri) + local _ = progress.create(workspace.getScope(uri), lang.script.WINDOW_PROCESSING_TYPE_FORMATTING, 0.5) + + if not files.exists(uri) then + return nil + end + + local core = require 'core.rangeformatting' + local edits = core(uri, params.range) + if not edits or #edits == 0 then + return nil + end + + local results = {} + for i, edit in ipairs(edits) do + results[i] = { + range = converter.packRange(uri, edit.start, edit.finish), + newText = edit.text, + } + end + + return results + end +} + +m.register 'config/editorconfig/update' { + abortByFileUpdate = true, + ---@async + function(params) + local codeFormat = require "code_format" + local status, err = codeFormat.update_config(params.type, params.source.workspace, params.source.path) + + if not status and err ~= nil then + log.error(err) + end + end +} + m.register 'textDocument/onTypeFormatting' { abortByFileUpdate = true, ---@async diff --git a/test/crossfile/diagnostic.lua b/test/crossfile/diagnostic.lua index 43028744f..dd06351fd 100644 --- a/test/crossfile/diagnostic.lua +++ b/test/crossfile/diagnostic.lua @@ -5,8 +5,10 @@ local config = require 'config' local platform = require 'bee.platform' local catch = require 'catch' + config.get(nil, 'Lua.diagnostics.neededFileStatus')['deprecated'] = 'Any' config.get(nil, 'Lua.diagnostics.neededFileStatus')['type-check'] = 'Any' +config.get(nil, 'Lua.diagnostics.neededFileStatus')['codestyle-check'] = 'None' rawset(_G, 'TEST', true)