diff --git a/changelog.md b/changelog.md index c9375a4cd..ffd57db7b 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,7 @@ * `FIX` Deduplicate documentation bindings for parameters * `FIX` Correct `math.type` meta return annotation to use `nil` instead of the string literal `'nil'` * `FIX` Fix initial `nameStyle.config` not getting loaded in the appropriate workspace. +* `FIX` Fix invalid LSP responses in files containing string literals with escaped bytes. ## 3.18.2 * `CHG` `duplicate-set-field` diagnostic now supports linked suppression: when any occurrence of a duplicate field is suppressed with `---@diagnostic disable` or `---@diagnostic disable-next-line`, all warnings for that field name will be suppressed diff --git a/script/utility.lua b/script/utility.lua index 0b4b0ab62..74bf05c80 100644 --- a/script/utility.lua +++ b/script/utility.lua @@ -469,7 +469,26 @@ local esc = { ['\n'] = '\\\n', } +local function escapeInvalidUtf8(str) + local result = {} + local start = 1 + while true do + local _, invalid = utf8Len(str, start) + if not invalid then + result[#result+1] = str:sub(start) + break + end + result[#result+1] = str:sub(start, invalid - 1) + result[#result+1] = ('\\%03d'):format(stringByte(str, invalid)) + start = invalid + 1 + end + return tableConcat(result) +end + function m.viewString(str, quo) + if not utf8Len(str) then + str = escapeInvalidUtf8(str) + end if not quo then if str:find('[\r\n]') then quo = '[[' diff --git a/test/other/init.lua b/test/other/init.lua index fbe9d923b..51b085164 100644 --- a/test/other/init.lua +++ b/test/other/init.lua @@ -1 +1,2 @@ --require 'other.filewatch' +require 'other.view-string' diff --git a/test/other/view-string.lua b/test/other/view-string.lua new file mode 100644 index 000000000..86b2e3373 --- /dev/null +++ b/test/other/view-string.lua @@ -0,0 +1,15 @@ +local util = require 'utility' + +local function assertView(value, expected) + local literal = util.viewString(value) + assert(utf8.len(literal)) + assert(literal == expected, ('expected %q, got %q'):format(expected, literal)) +end + +assertView('plain text', '"plain text"') +assertView('é中文', '"é中文"') +assertView('\x80', '"\\128"') +assertView('\xff', '"\\255"') +assertView('\xc2A', '"\\194A"') +assertView('\xe2\x82', '"\\226\\130"') +assertView('[^%w_\x80-\xff]', '"[^%w_\\128-\\255]"')