diff --git a/lua/entities/gmod_wire_expression2/base/compiler.lua b/lua/entities/gmod_wire_expression2/base/compiler.lua index d3fe921333..fd6cb1d6f9 100644 --- a/lua/entities/gmod_wire_expression2/base/compiler.lua +++ b/lua/entities/gmod_wire_expression2/base/compiler.lua @@ -125,8 +125,9 @@ end ---@param message string ---@param trace Trace -function Compiler:Error(message, trace) - error( Error.new(message, trace), 0) +---@param quick_fix { replace: string, at: Trace }[]? +function Compiler:Error(message, trace, quick_fix) + error( Error.new(message, trace, nil, quick_fix), 0) end ---@generic T @@ -152,12 +153,13 @@ end ---@param message string ---@param trace Trace -function Compiler:Warning(message, trace) +---@param quick_fix { replace: string, at: Trace }[]? +function Compiler:Warning(message, trace, quick_fix) if self.include then local tbl = self.warnings[self.include] - tbl[#tbl + 1] = Warning.new(message, trace) + tbl[#tbl + 1] = Warning.new(message, trace, quick_fix) else - self.warnings[#self.warnings + 1] = Warning.new(message, trace) + self.warnings[#self.warnings + 1] = Warning.new(message, trace, quick_fix) end end @@ -229,11 +231,11 @@ local CompileVisitors = { stmts[i], traces[i] = stmt, trace if node:isExpr() and node.variant ~= NodeVariant.ExprDynCall and node.variant ~= NodeVariant.ExprCall and node.variant ~= NodeVariant.ExprMethodCall then - self:Warning("This expression has no effect", node.trace) + self:Warning("This expression has no effect", node.trace, { { replace = "", at = node.trace } }) end end else - self:Warning("Unreachable code detected", node.trace) + self:Warning("Unreachable code detected", node.trace, { { replace = "", at = node.trace } }) break end end @@ -608,7 +610,7 @@ local CompileVisitors = { if err_ty then self:Assert(err_ty.value == "string", "Error type can only be string, for now", err_ty.trace) else - self:Warning("You should explicitly annotate the error type as :string", err_var.trace) + self:Warning("You should explicitly annotate the error type as :string", err_var.trace, { { replace = err_var.value .. ":string", at = err_var.trace } }) end self:Scope(function (scope) @@ -665,7 +667,7 @@ local CompileVisitors = { self:Error("Variadic parameter requires explicit type", param.name.trace) else param_types[i] = "n" - self:Warning("Use of implicit parameter type is deprecated (add :number)", param.name.trace) + self:Warning("Use of implicit parameter type is deprecated (add :number)", param.name.trace, { { replace = param.name.value .. ":number", at = param.name.trace } }) end if param.name.value ~= "_" and existing[param.name.value] then @@ -1615,6 +1617,11 @@ local CompileVisitors = { ---@param data { [1]: Token, [2]: Node[] } [NodeVariant.ExprCall] = function (self, trace, data, used_as_stmt) local name, args, types = data[1], {}, {} + + if name.value == "changed" and data[2][1].variant == NodeVariant.ExprIdent and self.inputs[3][data[2][1].data.value] then + self:Warning("Use ~ instead of changed() for inputs", trace, { { replace = "~" .. data[2][1].data.value, at = trace } }) + end + for k, arg in ipairs(data[2]) do args[k], types[k] = self:CompileExpr(arg) end @@ -1903,7 +1910,7 @@ local CompileVisitors = { for i, param in ipairs(data[2]) do local type = param.type and self:CheckType(param.type) if not type then - self:Warning("Use of implicit parameter type is deprecated (add :number)", param.name.trace) + self:Warning("Use of implicit parameter type is deprecated", param.name.trace, { { replace = param.name.value .. ":number", at = param.name.trace } }) type = "n" end params[i] = { param.name.value, type } diff --git a/lua/entities/gmod_wire_expression2/base/debug.lua b/lua/entities/gmod_wire_expression2/base/debug.lua index 3535260465..94c1b8935c 100644 --- a/lua/entities/gmod_wire_expression2/base/debug.lua +++ b/lua/entities/gmod_wire_expression2/base/debug.lua @@ -38,14 +38,15 @@ end ---@class Warning ---@field message string ---@field trace Trace +---@field quick_fix { replace: string, at: Trace }[]? # Replacements to be made for quick fix local Warning = {} Warning.__index = Warning ---@param message string ---@param trace Trace ----@return Warning -function Warning.new(message, trace) - return setmetatable({ message = message, trace = trace }, Warning) +---@param quick_fix { replace: string, at: Trace }[]? # Replacements for quick fix +function Warning.new(message, trace, quick_fix) + return setmetatable({ message = message, trace = trace, quick_fix = quick_fix }, Warning) end function Warning:debug() @@ -64,15 +65,16 @@ Warning.__tostring = Warning.debug ---@field message string ---@field trace Trace ---@field userdata ErrorUserdata +---@field quick_fix { replace: string, at: Trace }[]? # Replacements to be made for quick fix local Error = {} Error.__index = Error ---@param message string ---@param trace Trace? ---@param userdata ErrorUserdata? ----@return Error -function Error.new(message, trace, userdata) - return setmetatable({ message = message, trace = trace, userdata = userdata }, Error) +---@param quick_fix { replace: string, at: Trace }[]? # Replacements to be made for quick fix +function Error.new(message, trace, userdata, quick_fix) + return setmetatable({ message = message, trace = trace, userdata = userdata, quick_fix = quick_fix }, Error) end function Error:debug() diff --git a/lua/entities/gmod_wire_expression2/base/parser.lua b/lua/entities/gmod_wire_expression2/base/parser.lua index c5ffa7578a..869a019deb 100644 --- a/lua/entities/gmod_wire_expression2/base/parser.lua +++ b/lua/entities/gmod_wire_expression2/base/parser.lua @@ -178,14 +178,16 @@ end ---@param message string ---@param trace Trace? -function Parser:Error(message, trace) - error( Error.new( message, trace or self:Prev().trace ), 2 ) +---@param quick_fix { replace: string, at: Trace }[]? +function Parser:Error(message, trace, quick_fix) + error( Error.new( message, trace or self:Prev().trace, nil, quick_fix ), 2 ) end ---@param message string ---@param trace Trace? -function Parser:Warning(message, trace) - self.warnings[#self.warnings + 1] = Warning.new( message, trace or self:Prev().trace ) +---@param quick_fix { replace: string, at: Trace }[]? +function Parser:Warning(message, trace, quick_fix) + self.warnings[#self.warnings + 1] = Warning.new( message, trace or self:Prev().trace, quick_fix ) end ---@generic T @@ -542,6 +544,7 @@ function Parser:Type() local type = self:Consume(TokenVariant.LowerIdent) if type then if type.value == "normal" then + self:Warning("Use of deprecated type [normal]", type.trace, { { at = type.trace, replace = "number" } }) type.value = "number" end else -- workaround to allow "function" as type while also being a keyword diff --git a/lua/entities/gmod_wire_expression2/base/preprocessor.lua b/lua/entities/gmod_wire_expression2/base/preprocessor.lua index 38e4c46334..9b4fe67d2d 100644 --- a/lua/entities/gmod_wire_expression2/base/preprocessor.lua +++ b/lua/entities/gmod_wire_expression2/base/preprocessor.lua @@ -30,14 +30,27 @@ function PreProcessor.Execute(buffer, directives, ent) return ok, ok and directives or instance.errors, newcode, instance end -function PreProcessor:Error(message, column) - self.errors[#self.errors + 1] = Error.new(message, Trace.new(self.readline, column or 1, self.readline, column or 1)) +---@param message string +---@param trace Trace? +---@param quick_fix { replace: string, at: Trace }[]? +function PreProcessor:Error(message, trace, quick_fix) + self.errors[#self.errors + 1] = Error.new( + message, + trace or Trace.new(self.readline, 1, self.readline, 1), + nil, + quick_fix + ) end ---@param message string ----@param column integer? -function PreProcessor:Warning(message, column) - self.warnings[#self.warnings + 1] = Warning.new(message, Trace.new(self.readline, self.readline, column or 1, column or 1)) +---@param trace Trace? +---@param quick_fix { replace: string, at: Trace }[]? +function PreProcessor:Warning(message, trace, quick_fix) + self.warnings[#self.warnings + 1] = Warning.new( + message, + trace or Trace.new(self.readline, 1, self.readline, 1), + quick_fix + ) end local type_map = { @@ -50,12 +63,12 @@ local type_map = { number = "n", } -function PreProcessor:GetType(tp, column) +function PreProcessor:GetType(tp, trace) tp = tp:Trim():lower() local up = tp:upper() if tp == "normal" then - self:Warning("Use of deprecated type [normal]", column) + self:Warning("Use of deprecated type [normal]", trace, { { at = trace, replace = "number" } }) end return type_map[tp] or (wire_expression_types[up] and wire_expression_types[up][1]) or tp @@ -63,8 +76,11 @@ end function PreProcessor:HandlePPCommand(comment, col) local command, args = comment:match("^([^ ]*) ?(.*)$") + local handler = self["PP_" .. command] - if handler then return handler(self, args, col) end + if handler then + return handler(self, args, Trace.new(self.readline, col, self.readline, col + 1 + #command)) + end end function PreProcessor:FindComments(line) @@ -199,18 +215,20 @@ local function handleIO(name) local retval, columns, lines = self:ParsePorts(value, #name + 2) for i, key in ipairs(retval[1]) do + local tr = Trace.new(lines[i], columns[i], lines[i], columns[i]) + if ports[3][key] then if ports[3][key] ~= retval[2][i] then - self:Error("Directive (@" .. name .. ") contains multiple definitions of the same variable with differing types", columns[i]) + self:Error("Directive (@" .. name .. ") contains multiple definitions of the same variable with differing types", tr) else - self:Warning("Directive (@" .. name .. ") contains multiple definitions of the same variable", columns[i]) + self:Warning("Directive (@" .. name .. ") contains multiple definitions of the same variable", tr) end else local index = #ports[1] + 1 ports[1][index] = key -- Index: Name ports[2][index] = retval[2][i] -- Index: Type ports[3][key] = retval[2][i] -- Name: Type - ports[5][key] = Trace.new(lines[i], columns[i], lines[i], columns[i]) -- Name: Trace + ports[5][key] = tr -- Name: Trace end end end @@ -227,7 +245,7 @@ local directive_handlers = { end end, - ["model"] = function(self, value) + ["model"] = function(self, value, trace) if not self.ignorestuff then if self.directives.model == nil then if not util.IsValidModel(value) then @@ -245,29 +263,29 @@ local directive_handlers = { ["outputs"] = handleIO("outputs"), ["persist"] = handleIO("persist"), - ["trigger"] = function(self, value) + ["trigger"] = function(self, value, trace) local trimmed = string.Trim(value) if trimmed == "all" then if self.directives.trigger[1] ~= nil then - self:Error("Directive (@trigger) conflicts with previous directives") + self:Error("Directive (@trigger) conflicts with previous directives", trace) end self.directives.trigger[1] = true elseif trimmed == "none" then if self.directives.trigger[1] ~= nil then - self:Error("Directive (@trigger) conflicts with previous directives") + self:Error("Directive (@trigger) conflicts with previous directives", trace) end self.directives.trigger[1] = false elseif trimmed ~= "" then if self.directives.trigger[1] ~= nil and #self.directives.trigger[2] == 0 then - self:Error("Directive (@trigger) conflicts with previous directives") + self:Error("Directive (@trigger) conflicts with previous directives", trace) end self.directives.trigger[1] = false - local retval, columns = self:ParsePorts(value, 9) + local retval, columns, lines = self:ParsePorts(value, 9) for i, key in ipairs(retval[1]) do if self.directives.trigger[2][key] then - self:Error("Directive (@trigger) contains multiple definitions of the same variable", columns[i]) + self:Error("Directive (@trigger) contains multiple definitions of the same variable", Trace.new(lines[i], columns[i], lines[i], columns[i])) else self.directives.trigger[2][key] = true end @@ -287,12 +305,12 @@ local directive_handlers = { end } -function PreProcessor:HandleDirective(name, value) +function PreProcessor:HandleDirective(name, value, trace --[[@param trace Trace]]) local handler = directive_handlers[name] if handler then - return handler(self, value) + return handler(self, value, trace) else - self:Error("Unknown directive found (@" .. E2Lib.limitString(name, 10) .. ")", 2) + self:Error("Unknown directive found (@" .. E2Lib.limitString(name, 10) .. ")", trace) end end @@ -312,12 +330,19 @@ function PreProcessor:ParseDirectives(line) return line end - local col = directive:find("[A-Z]") - if col then self:Error("Directive (@" .. E2Lib.limitString(directive, 10) .. ") must be lowercase", col + 1) end - if self.incode then self:Error("Directive (@" .. E2Lib.limitString(directive, 10) .. ") must appear before code") end + if directive:lower() ~= directive then + local tr = Trace.new(self.readline, 2, self.readline, 2 + #directive) + self:Error("Directive (@" .. E2Lib.limitString(directive, 10) .. ") must be lowercase", tr, { { at = tr, replace = string.lower(directive) } }) + end + + local tr = Trace.new(self.readline, 1, self.readline, #directive + 1) + + if self.incode then + self:Error("Directive (@" .. E2Lib.limitString(directive, 10) .. ") must appear before code", tr) + end -- evaluate directive - self:HandleDirective(directive, value) + self:HandleDirective(directive, value, tr) -- remove line from output return "" @@ -386,6 +411,7 @@ function PreProcessor:ParsePorts(ports, startoffset) ---@cast key string column = startoffset + column + local tr = Trace.new(self.readline, column, self.readline, column + #key) -------------------------------- variable names -------------------------------- @@ -399,23 +425,25 @@ function PreProcessor:ParsePorts(ports, startoffset) _, i, namestring = key:find("^%[([^]]+)%]") if not i then -- no -> malformed variable name - self:Error("Variable name (" .. E2Lib.limitString(key, 10) .. ") must start with an uppercase letter", column) + self:Error("Variable name (" .. E2Lib.limitString(key, 10) .. ") must start with an uppercase letter", tr, { { at = tr, replace = key:sub(1, 1):upper() .. key:sub(2) } }) goto cont else -- yes -> add all variables. for column2, var in namestring:gmatch("()([^,]+)") do column2 = column + column2 + local tr = Trace.new(self.readline, column2, self.readline, column2 + #var) + var = string.Trim(var) -- skip empty entries if var ~= "" then -- error on malformed variable names if not var:match("^[A-Z]") then - self:Error("Variable name (" .. E2Lib.limitString(var, 10) .. ") must start with an uppercase letter", column2) + self:Error("Variable name (" .. E2Lib.limitString(var, 10) .. ") must start with an uppercase letter", tr, { { at = tr, replace = var:sub(1, 1):upper() .. var:sub(2) } }) goto cont else local errcol = var:find("[^A-Za-z0-9_]") if errcol then - self:Error("Variable declaration (" .. E2Lib.limitString(var, 10) .. ") contains invalid characters", column2 + errcol - 1) + self:Error("Variable declaration (" .. E2Lib.limitString(var, 10) .. ") contains invalid characters", Trace.new(self.readline, column2 + errcol - 1, self.readline, column2 + errcol - 1)) goto cont else -- and finally add the variable. @@ -435,20 +463,22 @@ function PreProcessor:ParsePorts(ports, startoffset) -- type is specified -> check for validity vtype = key:sub(i + 2) + local tr = Trace.new(self.readline, column + i + 1, self.readline, column + i + 1 + #vtype) + if vtype ~= vtype:lower() then - self:Error("Variable type [" .. E2Lib.limitString(vtype, 10) .. "] must be lowercase", column + i + 1) + self:Error("Variable type [" .. E2Lib.limitString(vtype, 10) .. "] must be lowercase", tr, { { at = tr, replace = vtype:lower() } }) goto cont elseif vtype == "number" then vtype = "normal" elseif vtype == "normal" then - self:Warning("Variable type [normal] is deprecated (use number instead)", column + i + 1) + self:Warning("Variable type [normal] is deprecated", tr, { { at = tr, replace = "number" } }) end elseif character == "" then -- type is not specified -> default to number vtype = "normal" else -- invalid -> raise an error - self:Error("Variable declaration (" .. E2Lib.limitString(key, 10) .. ") contains invalid characters", column + i) + self:Error("Variable declaration (" .. E2Lib.limitString(key, 10) .. ") contains invalid characters", tr) goto cont end @@ -460,7 +490,7 @@ function PreProcessor:ParsePorts(ports, startoffset) columns[i] = column lines[i] = self.readline else - self:Error("Unknown variable type [" .. E2Lib.limitString(vtype, 10) .. "]", column + i + 1) + self:Error("Unknown variable type [" .. E2Lib.limitString(vtype, 10) .. "]", Trace.new(self.readline, column + i + 1, self.readline, column + i + 1 + #vtype)) end end @@ -489,23 +519,43 @@ function PreProcessor:Disabled() return self.ifdefStack[#self.ifdefStack] == false end -function PreProcessor:GetFunction(args, type) +function PreProcessor:GetFunction(args, type, trace --[[@param trace Trace]]) local thistype, colon, name, argtypes = args:match("([^:]-)(:?)([^:(]+)%(([^)]*)%)") - if not thistype or (thistype ~= "") ~= (colon ~= "") then self:Error("Malformed " .. type .. " argument " .. args) return end - thistype = self:GetType(thistype) + local col, line = trace.end_col + 1, trace.end_line + + if thistype and (thistype ~= "") == (colon ~= "") then + local start = col + col = col + #thistype + + thistype = self:GetType(thistype, Trace.new(line, start, line, col)) + col = col + 1 -- skip colon + else + self:Error("Malformed " .. type .. " argument " .. args, trace) + return + end + + col = col + #name -- skip name and paren local tps = {thistype .. colon} - for _, argtype in ipairs(string.Explode(",", argtypes)) do - argtype = self:GetType(argtype) + + argtypes = string.Explode(",", argtypes) + local last = #argtypes + + for l, argtype in ipairs(argtypes) do + local start = col + col = col + #argtype + (l ~= last and 1 or 0) + + argtype = self:GetType(argtype, Trace.new(line, start, line, col)) table.insert(tps, argtype) end + local pars = table.concat(tps) return wire_expression2_funcs[name .. "(" .. pars .. ")"] end -function PreProcessor:PP_ifdef(args, col) - local func = self:GetFunction(args, "#ifdef") +function PreProcessor:PP_ifdef(args, trace) + local func = self:GetFunction(args, "#ifdef", trace) if self:Disabled() then table.insert(self.ifdefStack, false) @@ -514,8 +564,8 @@ function PreProcessor:PP_ifdef(args, col) end end -function PreProcessor:PP_ifndef(args, col) - local func = self:GetFunction(args, "#ifndef") +function PreProcessor:PP_ifndef(args, trace) + local func = self:GetFunction(args, "#ifndef", trace) if self:Disabled() then table.insert(self.ifdefStack, false) @@ -524,11 +574,11 @@ function PreProcessor:PP_ifndef(args, col) end end -function PreProcessor:PP_else(args, col) +function PreProcessor:PP_else(args, trace) local state = table.remove(self.ifdefStack) - if state == nil then self:Error("Found #else outside #ifdef/#ifndef block", col) end + if state == nil then self:Error("Found #else outside #ifdef/#ifndef block", trace) end - if args:Trim() ~= "" then self:Error("Must not pass an argument to #else", col) end + if args:Trim() ~= "" then self:Error("Must not pass an argument to #else", trace) end if self:Disabled() then table.insert(self.ifdefStack, false) @@ -537,21 +587,21 @@ function PreProcessor:PP_else(args, col) end end -function PreProcessor:PP_endif(args, col) +function PreProcessor:PP_endif(args, trace) local state = table.remove(self.ifdefStack) - if state == nil then self:Error("Found #endif outside #ifdef/#ifndef block", col) end + if state == nil then self:Error("Found #endif outside #ifdef/#ifndef block", trace) end - if args:Trim() ~= "" then self:Error("Must not pass an argument to #endif", col) end + if args:Trim() ~= "" then self:Error("Must not pass an argument to #endif", trace) end end -function PreProcessor:PP_error(args, col) +function PreProcessor:PP_error(args, trace) if not self:Disabled() then - self:Error(args, col) + self:Error(args, trace) end end -function PreProcessor:PP_warning(args, col) +function PreProcessor:PP_warning(args, trace) if not self:Disabled() then - self:Warning(args, col) + self:Warning(args, trace) end end diff --git a/lua/entities/gmod_wire_expression2/base/tokenizer.lua b/lua/entities/gmod_wire_expression2/base/tokenizer.lua index c300334583..d5c7367a20 100644 --- a/lua/entities/gmod_wire_expression2/base/tokenizer.lua +++ b/lua/entities/gmod_wire_expression2/base/tokenizer.lua @@ -132,16 +132,17 @@ end ---@param message string ---@param trace Trace? ----@return boolean false -function Tokenizer:Error(message, trace) - self.errors[#self.errors + 1] = Error.new( message, trace or self:GetTrace() ) +---@param quick_fix { replace: string, at: Trace }[]? +function Tokenizer:Error(message, trace, quick_fix) + self.errors[#self.errors + 1] = Error.new( message, trace or self:GetTrace(), nil, quick_fix ) return false end ---@param message string ---@param trace Trace? -function Tokenizer:Warning(message, trace) - self.warnings[#self.warnings + 1] = Warning.new( message, trace or self:GetTrace() ) +---@param quick_fix { replace: string, at: Trace }[]? +function Tokenizer:Warning(message, trace, quick_fix) + self.warnings[#self.warnings + 1] = Warning.new( message, trace or self:GetTrace(), quick_fix ) end local escapes = { @@ -346,11 +347,11 @@ function Tokenizer:Next() if not esc then err = "Hexadecimal escape expects 2 hex digits" else - esc = string.char(tonumber(esc, 16) or 0) + esc = string_char(tonumber(esc, 16) or 0) end else esc = "\\" - self:Warning("Invalid escape " .. "\\" .. string_gsub(char, "%G", " "), Trace.new(line, col, self.line, self.col)) + self:Warning("Invalid escape " .. "\\" .. string_gsub(char, "%G", " "), Trace.new(line, col, self.line, self.col), { { at = Trace.new(self.line, self.col - 1, self.line, self.col), replace = "" } }) end ::_err:: diff --git a/lua/wire/client/text_editor/issue_viewer.lua b/lua/wire/client/text_editor/issue_viewer.lua index 23225bc9fe..b806c9652c 100644 --- a/lua/wire/client/text_editor/issue_viewer.lua +++ b/lua/wire/client/text_editor/issue_viewer.lua @@ -161,13 +161,22 @@ function PANEL:Init() function self.IssuesView:DoRightClick(node) local menu = DermaMenu() - local copy = menu:AddOption( + menu:AddOption( "Copy to clipboard", function() SetClipboardText(node.Label:GetText()) end ) + if node.quick_fix then + menu:AddOption( + "Quick fix", + function() + base:OnQuickFix(node) + end + ) + end + menu:Open() end @@ -266,23 +275,23 @@ function PANEL:Update(errors, warnings, header_text, header_color) local failed = false if warnings ~= nil and not table.IsEmpty(warnings) then - for k, v in ipairs(warnings) do + for _, v in ipairs(warnings) do if v.message ~= nil then - local node = tree:AddNode(v.message .. (v.trace ~= nil and string.format(" [line %u, char %u]", v.trace.start_line, v.trace.start_col) or "")) + local node = tree:AddNode(v.message .. (v.trace ~= nil and string.format(" [line %u, char %u]", v.trace.start_line, v.trace.start_col) or "") .. (v.quick_fix and " (Quick fix available)" or "")) node:SetIcon("icon16/error.png") - node.line = v.trace and v.trace.start_line - node.char = v.trace and v.trace.start_col + node.trace = v.trace + node.quick_fix = v.quick_fix end end failed = true end if errors ~= nil and not table.IsEmpty(errors) then - for k, v in ipairs(errors) do - local node = tree:AddNode(v.message .. (v.trace ~= nil and string.format(" [line %u, char %u]", v.trace.start_line, v.trace.start_col) or "")) + for _, v in ipairs(errors) do + local node = tree:AddNode(v.message .. (v.trace ~= nil and string.format(" [line %u, char %u]", v.trace.start_line, v.trace.start_col) or "") .. (v.quick_fix and " (Quick fix available)" or "")) node:SetIcon("icon16/cancel.png") - node.line = v.trace and v.trace.start_line - node.char = v.trace and v.trace.start_col + node.trace = v.trace + node.quick_fix = v.quick_fix end failed = true end diff --git a/lua/wire/client/text_editor/wire_expression2_editor.lua b/lua/wire/client/text_editor/wire_expression2_editor.lua index 7a90db9e1d..38b8e5ef27 100644 --- a/lua/wire/client/text_editor/wire_expression2_editor.lua +++ b/lua/wire/client/text_editor/wire_expression2_editor.lua @@ -903,10 +903,28 @@ function Editor:InitComponents() end end self.C.Val.OnIssueClicked = function(panel, issue) - if issue.line ~= nil and issue.char ~= nil then - self:GetCurrentEditor():SetCaret({issue.line, issue.char}) + if issue.trace ~= nil then + self:GetCurrentEditor():SetCaret({issue.trace.start_line, issue.trace.start_col}) end end + + self.C.Val.OnQuickFix = function(panel, issue) + local editor = self:GetCurrentEditor() + + for _, fix in ipairs(issue.quick_fix) do + local trace = fix.at + editor:SetArea( + { + { trace.start_line, trace.start_col }, + { trace.end_line, trace.end_col } + }, + fix.replace + ) + end + + self:Validate() + end + self.C.Btoggle:SetImage("icon16/application_side_contract.png") function self.C.Btoggle.DoClick(button) if button.hide then