diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2019-11-17 22:22:52 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2019-11-17 22:22:52 +0800 |
commit | 54907f010415d179a435c37cd2f354315a424f08 (patch) | |
tree | 831493b251a777cb0958a4a8d8b6856bcaaf77f4 /server-beta/src/core/rename.lua | |
parent | a139003e6f239650baaef69f747c7ee9558d0170 (diff) | |
download | lua-language-server-54907f010415d179a435c37cd2f354315a424f08.zip |
跟细致的 rename
Diffstat (limited to 'server-beta/src/core/rename.lua')
-rw-r--r-- | server-beta/src/core/rename.lua | 202 |
1 files changed, 151 insertions, 51 deletions
diff --git a/server-beta/src/core/rename.lua b/server-beta/src/core/rename.lua index a2b1b3fc..65010e0d 100644 --- a/server-beta/src/core/rename.lua +++ b/server-beta/src/core/rename.lua @@ -2,52 +2,151 @@ local files = require 'files' local searcher = require 'searcher' local guide = require 'parser.guide' -local function checkSource(source) - if source.type == 'field' - or source.type == 'method' - or source.type == 'tablefield' - or source.type == 'string' - or source.type == 'local' - or source.type == 'setlocal' - or source.type == 'getlocal' - or source.type == 'setglobal' - or source.type == 'getglobal' - or source.type == 'label' - or source.type == 'goto' then - return true +local function isValidName(str) + return str:match '^[%a_][%w_]*$' +end + +local function forceReplace(name) + return true +end + +local function ofLocal(source, newname, callback) + if not isValidName(newname) and not forceReplace(newname) then + return false + end + callback(source, source.start, source.finish, newname) + if source.ref then + for _, ref in ipairs(source.ref) do + callback(ref, ref.start, ref.finish, newname) + end end - return false end -local function rename(source) - if source.type == 'field' - or source.type == 'method' - or source.type == 'tablefield' - or source.type == 'string' - or source.type == 'local' - or source.type == 'setlocal' - or source.type == 'getlocal' - or source.type == 'setglobal' - or source.type == 'getglobal' - or source.type == 'label' - or source.type == 'goto' then - return source +local esc = { + ["'"] = [[\']], + ['"'] = [[\"]], + ['\r'] = [[\r]], + ['\n'] = [[\n]], +} + +local function toString(quo, newstr) + if quo == "'" then + return quo .. newstr:gsub([=[['\r\n]]=], esc) .. quo + elseif quo == '"' then + return quo .. newstr:gsub([=[["\r\n]]=], esc) .. quo + else + if newstr:find([[\r]], 1, true) then + return toString('"', newstr) + end + local eqnum = #quo - 2 + local fsymb = ']' .. ('='):rep(eqnum) .. ']' + if not newstr:find(fsymb, 1, true) then + return quo .. newstr .. fsymb + end + for i = 0, 100 do + local fsymb = ']' .. ('='):rep(i) .. ']' + if not newstr:find(fsymb, 1, true) then + local ssymb = '[' .. ('='):rep(i) .. '[' + return ssymb .. newstr .. fsymb + end + end + return toString('"', newstr) end - if source.type == 'setfield' - or source.type == 'getfield' - or source.type == 'tablefield' then - return source.field +end + +local function renameField(source, newname, callback) + if isValidName(newname) then + callback(source, source.start, source.finish, newname) + return true + end + local parent = source.parent + if parent.type == 'setfield' + or parent.type == 'getfield' then + local dot = parent.dot + local newstr = '[' .. toString('"', newname) .. ']' + callback(source, dot.start, source.finish, newstr) + elseif parent.type == 'tablefield' then + local newstr = '[' .. toString('"', newname) .. ']' + callback(source, source.start, source.finish, newstr) + else + if not forceReplace(newname) then + return false + end + callback(source, source.start, source.finish, newname) + end + return true +end + +local function renameGlobal(source, newname, callback) + if isValidName(newname) then + callback(source, source.start, source.finish, newname) + return false end - if source.type == 'setindex' - or source.type == 'getindex' - or source.type == 'tableindex' then - return source.index + local newstr = '_ENV[' .. toString('"', newname) .. ']' + callback(source, source.start, source.finish, newstr) + return true +end + +local function ofField(source, newname, callback) + return searcher.eachRef(source, function (info) + local src = info.source + if src.type == 'tablefield' + or src.type == 'getfield' + or src.type == 'setfield' then + src = src.field + elseif src.type == 'tableindex' + or src.type == 'getindex' + or src.type == 'setindex' then + src = src.index + elseif src.type == 'getmethod' + or src.type == 'setmethod' then + src = src.method + end + if src.type == 'string' then + local quo = src[2] + local text = toString(quo, newname) + callback(src, src.start, src.finish, text) + return + elseif src.type == 'field' + or src.type == 'method' then + local suc = renameField(src, newname, callback) + if not suc then + return false + end + elseif src.type == 'setglobal' + or src.type == 'getglobal' then + local suc = renameGlobal(src, newname, callback) + if not suc then + return false + end + end + end) +end + +local function rename(source, newname, callback) + if source.type == 'label' + or source.type == 'goto' then + if not isValidName(newname) and not forceReplace(newname)then + return false + end + searcher.eachRef(source, function (info) + callback(info.source, info.source.start, info.source.finish, newname) + end) end - if source.type == 'setmethod' - or source.type == 'getmethod' then - return source.method + if source.type == 'local' then + return ofLocal(source, newname, callback) + elseif source.type == 'setlocal' + or source.type == 'getlocal' then + return ofLocal(source.node, newname, callback) + elseif source.type == 'field' + or source.type == 'method' + or source.type == 'tablefield' + or source.type == 'string' + or source.type == 'setglobal' + or source.type == 'getglobal' then + return ofField(source, newname, callback) end - return nil + return true end return function (uri, pos, newname) @@ -56,23 +155,24 @@ return function (uri, pos, newname) return nil end local results = {} + + local ok = true guide.eachSourceContain(ast.ast, pos, function(source) - if not checkSource(source) then - return - end - searcher.eachRef(source, function (info) - local src = rename(info.source) - if not src then - return - end + local suc = rename(source, newname, function (target, start, finish, text) results[#results+1] = { - start = src.start, - finish = src.finish, - text = newname, - uri = guide.getRoot(src).uri, + start = start, + finish = finish, + text = text, + uri = guide.getRoot(target).uri, } end) + if suc == false then + ok = false + end end) + if not ok then + return nil + end if #results == 0 then return nil end |