--▽▽UTF-8▽▽ --[[ copyleft by jinzhongjie(xjinzhongjie@hotmail.com).anyone who want change the code please tell writer. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. ]] --[[ This will make a menu item in your "Tools" menu, that can be used with Control+9 shortcut scite_Command { 'Function Tree|localTree|Ctrl+9', 'All reference|allReference|Ctrl+8', --'ALL Function Tree|AllFunctionTree|Ctrl+8', --'Analysis Files|AnalysisFiles|Ctrl+7', } ]]-- --local path='D:/DO_WORK/source/AGW/agw_ngn_trunk/src/tsw' --local path='D:/DO_WORK/source/AGW/agw_ngn_trunk/src/mng' --local path='D:/DO_WORK/source/AGW/agw_ngn_trunk/src/xml' --local path='D:/DO_WORK/source/AGW/fe_sp_trunk/src/apl/racoon2/iked' local analysis = {} local not_analysis = {} --local path='E:/tmp/aplsrc/src/mng' --local path='E:/tmp/aplsrc/src/tsw' --local path='E:/tmp/racoon2/iked' --not output the functions local exclude_func = { plog = 1, printf = 1, memset = 1, memcmp = 1, memcpy = 1, htonl = 1, strcpy = 1, strcat = 1, strlen = 1, agwMngLogDebug = 1, strtoul = 1, c_str = 1, strtok = 1, strncmp = 1, sprintf = 1, agwMngLogError = 1, agwMngOpeSysLogError = 1, fopen = 1, fwrite = 1, fclose = 1, agwTswMessageInfo = 1, agwTswMessageWarning = 1, agwTswMessageError = 1, agwTswLogInit = 1, agwTswLogOutPutDebug = 1, agwTswLogOutPutInfo = 1, agwTswLogOutPutWarn = 1, agwTswLogOutPutError = 1, agwTswLogOutPutSys = 1, agwTswLogOutPutUsec = 1, agwMngOpeSysLogInfo = 1, agwXmlMessageInfo = 1, agwXmlMessageWarning = 1, agwXmlMessageError = 1, agwXmlLogInit = 1, agwXmlLogDebug = 1, agwXmlLogInfo = 1, agwXmlLogWarning = 1, agwXmlLogError = 1, agwXmlLogSys = 1, print_so_cnf = 1, print_setting = 1, print_gretap_conf = 1, } --not output under the functions local notRecursion_func = { agwMngWriteBackup = 1, agwMngShmDetach = 1, agwMngFlowEngineIoctlHa = 1, agwMngIpsecRlyDel = 1, agwMngIpsecRlyAdd = 1, agwMngWriteBackupSlice = 1, agwMngIpcSendResp = 1, } local sub = string.sub local find = string.find local len = string.len local gsub = string.gsub local indent_var --local fucList --local fucTable local funcPath = {} --local classList local funcTreeDirectory local classTable = {} local recursion_func = {} local noPrintAlreadyOutput = true local alreadyOutput_func = {} local line_pos = {} line_pos[1] = 0 local allFuncList = {} local rootFile local func_pos_start = -1 local funcLinestart local func_pos_end = -1 local location = {} local alreadyLocation = {} local active_already = nil local active_location = nil local active_location1 = nil local active_location2 = nil local active_now = nil local active_before1 = nil local active_before2 = nil local function TreeAdjust(diff) func_pos_start = func_pos_start + diff func_pos_end = func_pos_end + diff --funcLinestart=output:LineFromPosition(func_pos_start) end local function clearTreeParam() func_pos_start = -1 func_pos_end = -1 end scite_outputChange(function(pane, bPos, length) --print('start:'..output.SelectionStart..',end:'..output.SelectionEnd) if pane == output then --print("---"..keyval) RoutineAdjustChange(bPos, length, func_pos_start, func_pos_end, TreeAdjust, clearTreeParam) end return false end) ------------------------------------------------------------------- local function absolute_path(relative_path) local absPath if funcTreeDirectory~= "" then absPath = funcTreeDirectory.."\\"..relative_path else absPath = relative_path end return absPath end local function remove_tree() if func_pos_start>0 and func_pos_start < func_pos_end then local filePath = props['FilePath'] if active_now then output:MarkerDelete(active_now+funcLinestart-1, 9) active_now = nil end if active_already then output:MarkerDelete(active_already+funcLinestart, 8) active_already = nil end if active_before2 then output:MarkerDelete(active_before2+funcLinestart-1, 11) active_before2 = nil end if active_before1 then output:MarkerDelete(active_before1+funcLinestart-1, 10) active_before1 = nil end if active_location2 then scite.Open(absolute_path(active_location2[1])) editor:MarkerDelete(active_location2[2], 9) active_location2 = nil end if active_location1 then scite.Open(absolute_path(active_location1[1])) editor:MarkerDelete(active_location1[2], 10) active_location1 = nil end if active_location then scite.Open(absolute_path(active_location[1])) editor:MarkerDelete(active_location[2], 11) active_location = nil end outputRemove(output, func_pos_start, func_pos_end) func_pos_start = -1 func_pos_end = -1 scite.Open(filePath) end end local function fuction_locate(Location) if Location[1] and Location[2] then if active_location2 then scite.Open(absolute_path(active_location2[1])) editor:MarkerDelete(active_location2[2], 9) active_location2 = nil end if active_location1 then scite.Open(absolute_path(active_location1[1])) editor:MarkerDelete(active_location1[2], 10) active_location2 = active_location1 editor:MarkerDefine(9, SC_MARK_FULLRECT) editor:MarkerSetBack(9, colour_parse('pink')) editor:MarkerAdd(active_location1[2], 9) end if active_location then scite.Open(absolute_path(active_location[1])) editor:MarkerDelete(active_location[2], 11) active_location1 = active_location editor:MarkerDefine(10, SC_MARK_FULLRECT) editor:MarkerSetBack(10, colour_parse('green')) editor:MarkerAdd(active_location[2], 10) end editor:MarkerDefine(11, SC_MARK_FULLRECT) editor:MarkerSetBack(11, colour_parse('blue')) scite.Open(absolute_path(Location[1])) editor:GotoPos(Location[2]) editor:MarkerAdd(Location[2], 11) active_location = Location ctags_center_pos(Location[2]) end end local function readfunctree(filename, checkpaths) --print( '@@@'..filename) local f = io.open(filename) if not f then return nil end local clsTable = {} allFuncList = {} for line in f:lines()do local claname, memtype, remain = line:match('^([^:]+):([^:]+):(.*)$') if claname == '0' then claname = 0 end if not clsTable[claname] then clsTable[claname] = {} clsTable[claname].memS = {} end if remain == '' then --[[ elseif memtype=='o' then if not clsTable[claname].otherMemS then clsTable[claname].otherMemS={} end local l = 1 local pos=string.find(remain, ",", l) while pos do local field = string.sub(remain, l, pos - 1) local member,typ=field:match('^([^=]+)=([^=]+)$') clsTable[claname].otherMemS[member]=typ l = pos + 1 pos = string.find(remain, ",", l) end ]]-- elseif memtype == 'm' then local l = 1 local pos = string.find(remain, ",", l) while pos do local field = string.sub(remain, l, pos - 1) local member, typ = field:match('^([^=]+)=([^=]+)$') clsTable[claname].memS[member] = typ l = pos + 1 pos = string.find(remain, ",", l) end elseif memtype == 'f' then if not clsTable[claname].funcS then clsTable[claname].funcS = {} end local funcname, path, spos, epos, remain1 = remain:match('^([^,]+),([^,]+),([^,]+),([^:]+):([^:]*)$') clsTable[claname].funcS[funcname] = {name = funcname, root = 1, Type = 'f', path = path, lineS = tonumber(spos), lineE = tonumber(epos), funcS = {} } table.insert(allFuncList, {claname, funcname, tonumber(spos)}) local l = 1 local pos = string.find(remain1, ";", l) while pos do local field = string.sub(remain1, l, pos - 1) local cls, func, num = field:match('^([^,]+),([^,]+),([^,]+)$') if cls == '0' then cls = 0 end table.insert(clsTable[claname].funcS[funcname].funcS, {cls, func, tonumber(num)}) l = pos + 1 pos = string.find(remain1, ";", l) end end end f:close() return clsTable end local function loadfunctree(file, force) if file and(force or not funcPath[file])then --print( '%%%'..file) funcPath[file] = readfunctree(file, true) end return funcPath[file] end local function locatefunctree(dir, filename) local filepath while dir do filepath = dir .. '/' .. (filename or 'functree') --print( '$$$'..filepath) if loadfunctree(filepath, nil)then return dir end dir = dir:match('(.+)/[^/]+$') end return nil end local clsSelect local ParseName function classAndFunction() local FileDir = props['FileDir']:gsub('\\', '/') local tree_dir = locatefunctree(FileDir, 'functree') if tree_dir then funcTreeDirectory = tree_dir classTable = funcPath[tree_dir..'/functree'] else funcTreeDirectory = "" ParseFile() end local filePath = props['FilePath'] if filePath~= ParseName then clsSelect = ParseFile('cls') ParseName = filePath end local cls = 0 for k, name in pairs(clsSelect)do if editor.CurrentPosname[3] then cls = name[1] break end end local startPos = editor:WordStartPosition(editor.CurrentPos, true) local endPos = editor:WordEndPosition(editor.CurrentPos, true) local funcProperty = getFunctionProperty(startPos, endPos) local parent_type = funcProperty[1] local parent = funcProperty[2] local func = funcProperty[3] if not parent_type then if not parent then if func and classTable[cls].funcS[func] then parent_type = cls else parent_type = 0 end elseif classTable[cls].memS then parent_type = classTable[cls].memS[parent] else parent_type = nil end if not parent_type and parent then parent_type = classTable[0].memS[parent] end end return parent_type, func end scite_OnDoubleClick(function() local sta = command_status() if output.Focus and output.CurrentPos >= func_pos_start and output.CurrentPos <= func_pos_end then funcLinestart = output:LineFromPosition(func_pos_start) local linePos = output:LineFromPosition(output.CurrentPos)+1-funcLinestart if location[linePos] then fuction_locate(location[linePos]) elseif alreadyLocation[linePos] then output:MarkerDefine(12, SC_MARK_FULLRECT) output:MarkerSetBack(12, colour_parse('vYellow')) if active_already then output:MarkerDelete(active_already+funcLinestart, 12) end active_already = alreadyLocation[linePos] output:MarkerAdd(active_already+funcLinestart, 12) end if active_before2 then output:MarkerDelete(active_before2+funcLinestart-1, 9) active_before2 = nil end if active_before1 then output:MarkerDelete(active_before1+funcLinestart-1, 10) active_before2 = active_before1 output:MarkerDefine(9, SC_MARK_FULLRECT) output:MarkerSetBack(9, colour_parse('vPink')) output:MarkerAdd(active_before2+funcLinestart-1, 9) end if active_now then output:MarkerDelete(active_now+funcLinestart-1, 11) active_before1 = active_now output:MarkerDefine(10, SC_MARK_FULLRECT) output:MarkerSetBack(10, colour_parse('vGreen')) output:MarkerAdd(active_before1+funcLinestart-1, 10) end output:MarkerDefine(11, SC_MARK_FULLRECT) output:MarkerSetBack(11, colour_parse('vBlue')) active_now = linePos output:MarkerAdd(active_now+funcLinestart-1, 11) return true elseif editor.Focus and sta == 'functree' then local cls, func = classAndFunction() functionTree(cls, func, 'click') return true end return false end) dir_cmd = 'dir /b /s /a:-d ' function AnalysisFiles() for i, dirname in pairs(analysis)do funcTreeDirectory = dirname local FilePathTable = {} classTable = {} classTable[0] = {} classTable[0].memS = {} local content = scite_Popen(dir_cmd..'"'..dirname..'"') for line in content:lines()do local filePath = gsub(line, '\\', '/') --print('@@'..filePath) local _, val for path, var in pairs(not_analysis)do --print('=='..path) _, _, val = find(filePath, path, 0, true) if _ then break end end if not _ then FilePathTable[line] = {dirname, true, } --print ('--'..line) end end content:close() local remainFiles = {} for filename, flag in pairs(FilePathTable)do local isHead = string.match(filename, "^(.*%.[hH])$") if isHead then scite.Open(filename) local fList = ParseFile() for k, name in pairs(fList)do table.insert(allFuncList, name) end scite.MenuCommand(IDM_CLOSE) else table.insert(remainFiles, filename) end end for i, filename in pairs(remainFiles)do scite.Open(filename) local fList = ParseFile() for k, name in pairs(fList)do table.insert(allFuncList, name) end scite.MenuCommand(IDM_CLOSE) end funcPath[dirname.."/functree"] = classTable end for dirname, clsTable in pairs(funcPath)do local f = io.open(dirname, "w") if not f then return false end for cls, member in pairs(clsTable)do local line = cls..":".."m"..":" for var, typ in pairs(member.memS)do line = line..var.."="..typ.."," end f:write(line..'\n') --[[ if member.otherMemS then line=cls..":".."o"..":" for var,typ in pairs(member.otherMemS) do line=line..var.."="..typ.."," end f:write(line..'\n') end ]]-- if member.funcS then for func, property in pairs(member.funcS)do line = cls..":".."f"..":" line = line..property.name..","..property.path..","..property.lineS..","..property.lineE..":" for i, funcs in pairs(property.funcS)do line = line..funcs[1]..","..funcs[2]..","..funcs[3]..";" end f:write(line..'\n') end end end f:close() end print('Analysis Finished') end function AllFunctionTree() --[[ remove_tree() output:BeginUndoAction() print("------------------------------------") func_pos_start=output.CurrentPos indent_var=1 for k, name in pairs(allFuncList) do if classTable[ name[1] ].funcS[name[2] ].root == 1 then recursion_func={} local parent='' if name[1]~=0 then parent=name[1]..'::' end print('=='..parent..name[2]) local linePos= output:LineFromPosition(output.CurrentPos) local path=classTable[ name[1] ].funcS[name[2] ].path local line=classTable[name[1] ].funcS[name[2] ].lineS location[linePos]={path,line} print_func(name) end end func_pos_end=output.CurrentPos output:EndUndoAction() ]]-- end function allReference() local cls, func = classAndFunction() print("--all reference for"..":"..cls.."::"..func) for clsName, member in pairs(classTable)do if member.funcS then for funcName, property in pairs(member.funcS)do for i, funcs in pairs(property.funcS)do if cls == funcs[1] and func == funcs[2] then print(funcTreeDirectory..'\\'..property.path..":"..(funcs[3]+1)..":"..cls.."::"..func) end end end end end --functionTree(nil,nil,'oneFile') end function localTree() local cls, func = classAndFunction() functionTree(cls, func, 'command') --functionTree(nil,nil,'oneFile') end --stat=click,command,all,oneFile function functionTree(className, funcName, stat) remove_tree() --fucTable={} --classList={} local fList = {} rootFile = {} local doParseFlag = false local funcTable = {} if stat == 'click' or stat == 'command' then if #allFuncList == 0 then doParseFlag = true else funcTable = allFuncList doParseFlag = false end elseif stat == 'oneFile' then doParseFlag = true elseif stat == 'all' then fList = allFuncList doParseFlag = false end if doParseFlag then funcTreeDirectory = "" if editor.Lexer == SCLEX_TTL then classTable = {} end ParseFile() local sourceFilename = props["FilePath"] local ctagsFilename = sourceFilename .. '.ctags' local makeCtagsCommand = '""'.. lua_Path()..'/ctags" --fields=kn -u -f ' .. ctagsFilename .. ' ' .. sourceFilename ..' && type '..ctagsFilename..'"' local f = scite_Popen(makeCtagsCommand) for line in f:lines()do if not isCommentLine(line)then local cls, func = getLine(line) if func.Type == 'f' then table.insert(funcTable, {cls, func.name}) end end end f:close() os.remove(ctagsFilename) end if stat == 'click' or stat == 'command' then for k, name in pairs(funcTable)do local same = false if className then if className == name[1] and funcName == name[2] then same = true end else if funcName == name[2] then same = true end end if same then fList = {} table.insert(fList, {className, funcName}) break end end elseif doParseFlag then fList = funcTable end for k, name in pairs(fList)do if not rootFile[name[1]] then rootFile[name[1]] = {} end rootFile[name[1]][name[2]] = 1 end for k, name in pairs(fList)do recursion_func = {} recursion_func[name[1]] = {} recursion_func[name[1]][name[2]] = 1 isRootFile(classTable[name[1]].funcS[name[2]].funcS) end location = {} output:BeginUndoAction() func_pos_start = output.Length funcLinestart = output:LineFromPosition(func_pos_start) print("------------------------------------") indent_var = 1 alreadyOutput_func = {} for k, name in pairs(fList)do if rootFile[name[1]][name[2]] == 1 then recursion_func = {} local parent = '' if name[1]~= 0 then parent = name[1]..'::' end print('=='..parent..name[2]) local linePos = output:LineFromPosition(output.CurrentPos)-funcLinestart local path = classTable[name[1]].funcS[name[2]].path local line = classTable[name[1]].funcS[name[2]].lineS location[linePos] = {path, line} print_func(name) end end func_pos_end = output.CurrentPos output:EndUndoAction() end function isRootFile(fList) for k, name in pairs(fList)do if recursion_func[name[1]] and recursion_func[name[1]][name[2]] == 1 then recursion_func[name[1]][name[2]] = 0 return end if rootFile[name[1]] and rootFile[name[1]][name[2]] then rootFile[name[1]][name[2]] = 0 end if not recursion_func[name[1]] then recursion_func[name[1]] = {} end recursion_func[name[1]][name[2]] = 1 if classTable[name[1]] and classTable[name[1]].funcS and classTable[name[1]].funcS[name[2]] and classTable[name[1]].funcS[name[2]].funcS then isRootFile(classTable[name[1]].funcS[name[2]].funcS) end end end function ParseFile(option) local fucList = {} local fucList2 = {} editor:Colourise(0, -1) local sourceFilename = props["FilePath"] local ctagsFilename = sourceFilename .. '.ctags' local makeCtagsCommand = '""'.. lua_Path()..'/ctags" --fields=kn -u -f ' .. ctagsFilename .. ' ' .. sourceFilename ..' && type '..ctagsFilename..'"' local f = scite_Popen(makeCtagsCommand) local funcName_old local isCls = nil local clsName = nil for line in f:lines()do if not isCommentLine(line)then --print(getFunctionName(line)) local cls, func = getLine(line) local flag = nil if editor.Lexer == SCLEX_CPP then flag = true elseif editor.Lexer == SCLEX_TTL and func.Type == 'f' then flag = true end if funcName_old and flag then classTable[funcName_old[1]].funcS[funcName_old[2]].lineE = func.lineS funcName_old = nil end if func.Type == 'c' then isCls = true clsName = func.name if not classTable[clsName] then classTable[clsName] = {} classTable[clsName].funcS = {} end classTable[clsName].memS = {} elseif func.Type == 'm' then if isCls then classTable[clsName].memS[func.name] = cls end elseif func.Type == 'd' then elseif func.Type == 'v' then isCls = nil --classTable[0].memS[func.name]=cls elseif func.Type == 'f' then isCls = nil local set_func = nil if classTable[cls] then if func.Type == 'f' then if not classTable[cls].funcS then set_func = true classTable[cls].funcS = {} elseif not classTable[cls].funcS[func.name] then set_func = true end end elseif func.Type == 'f' then classTable[cls] = {} classTable[cls].funcS = {} set_func = true end if set_func then classTable[cls].funcS[func.name] = func --table.insert(classTable[cls].funcS[func.name], func) table.insert(fucList, {cls, func.name, func.lineS}) funcName_old = {cls, func.name} end table.insert(fucList2, {cls, func.name}) else isCls = nil end end end f:close() os.remove(ctagsFilename) if option == 'cls' then local classFuncList = {} ParseName = sourceFilename for k, name in pairs(fucList2)do local startPos = editor:PositionFromLine(classTable[name[1]].funcS[name[2]].lineS-1) local endPos if classTable[name[1]].funcS[name[2]].lineE == 0 then endPos = editor.TextLength else endPos = editor.LineEndPosition[classTable[name[1]].funcS[name[2]].lineE-1] end table.insert(classFuncList, {name[1], name[2], startPos, endPos}) end return classFuncList end for k, name in pairs(fucList)do --print(name..fucTable[name].num) Parse(name) end return fucList end function getLine(line) local t = splitCtagsLine(line) local functionName = t[1] local cls = string.match(t[3], "([%w_]+)%s*::%s*~?[%w_]+%s*%(") if not cls then cls = 0 end local funType = t[4] if funType == 'm' or funType == 'v' then cls = string.match(t[3], "([%w_]+)[^%w_]+[%w_]+") end --exg line:6646 local filePath = props['FilePath'] if not funcTreeDirectory then funcTreeDirectory = "" end local dirLen = funcTreeDirectory:len() if dirLen >0 then filePath = "."..filePath:sub(dirLen+1) end if editor.Lexer == SCLEX_TTL and funType == 'l' then funType = 'f' cls = 0 end local lineNumber = string.sub(t[5], 6, #t[5]) return cls, {name = functionName, root = 1, Type = funType, path = filePath, lineS = tonumber(lineNumber), lineE = 0, funcS = {} } end function Parse(name) local cls = name[1] local func_name = name[2] if notRecursion_func[func_name] then return end if classTable[cls].funcS[func_name].lineE == 0 then pos_end = editor.TextLength else pos_end = editor:PositionFromLine(classTable[cls].funcS[func_name].lineE-1) end local next_s local next_e = editor.LineEndPosition[classTable[cls].funcS[func_name].lineS-1] if editor.Lexer == SCLEX_TTL then next_s, next_e = editor:findtext('[cC][aA][lL][lL]\\s+\\w+\\s*$', SCFIND_MATCHCASE+SCFIND_REGEXP, next_e) else next_s, next_e = editor:findtext('\\w+\\s*(', SCFIND_MATCHCASE+SCFIND_REGEXP, next_e) end while next_e and next_e < pos_end do local style = editor.StyleAt[next_s] local flag = nil if editor.Lexer == SCLEX_CPP and style == SCE_C_IDENTIFIER then flag = true elseif editor.Lexer == SCLEX_TTL and style == SCE_TTL_KEYWORD then flag = true end if flag then style = editor.StyleAt[next_e-1] flag = nil if editor.Lexer == SCLEX_CPP and style == SCE_C_OPERATOR then flag = true elseif editor.Lexer == SCLEX_TTL and style == SCE_TTL_IDENTIFIER then flag = true end if flag then --local sel = editor:textrange(next_s,next_e) local funcProperty = getFunctionProperty(next_s, next_e) local parent_type = funcProperty[1] local parent = funcProperty[2] local func = funcProperty[3] if not exclude_func[func] then if not parent_type then if not parent then if classTable[cls].funcS[func] then parent_type = cls else parent_type = 0 end else if cls ~= 0 then if classTable[cls].memS then parent_type = classTable[cls].memS[parent] end if not parent_type then if classTable[cls].otherMemS then parent_type = classTable[cls].otherMemS[parent] end end else if classTable[0].otherMemS and classTable[0].otherMemS[func_name] then parent_type = classTable[0].otherMemS[func_name][parent] end end if not parent_type then parent_type = research_type(parent) if cls ~= 0 then if not classTable[cls].otherMemS then classTable[cls].otherMemS = {} classTable[cls].otherMemS[parent] = parent_type end else if not classTable[0].otherMemS then classTable[0].otherMemS = {} end if not classTable[0].otherMemS[func_name] then classTable[0].otherMemS[func_name] = {} classTable[0].otherMemS[func_name][parent] = parent_type end end end end end local lineNum = editor:LineFromPosition(next_e) table.insert(classTable[cls].funcS[func_name].funcS, {parent_type, func, lineNum}) if classTable[parent_type] and classTable[parent_type].funcS and classTable[parent_type].funcS[func] then classTable[parent_type].funcS[func].root = 0 end end end end if editor.Lexer == SCLEX_TTL then next_s, next_e = editor:findtext('[cC][aA][lL][lL]\\s+\\w+\\s*$', SCFIND_MATCHCASE+SCFIND_REGEXP, next_e) else next_s, next_e = editor:findtext('\\w+\\s*(', SCFIND_MATCHCASE+SCFIND_REGEXP, next_e) end end end function print_func(func) local cls = func[1] local func_name = func[2] if recursion_func[cls] and recursion_func[cls][func_name] == 1 then indent_var = indent_var+1 line_pos[indent_var] = 0 local inde = print_inde() print(inde..'|---'..'★Recursive') indent_var = indent_var-1 return end if not recursion_func[cls] then recursion_func[cls] = {} end recursion_func[cls][func_name] = 1 indent_var = indent_var+1 --local inde=string.rep("\t", indent_var) if classTable[cls] and classTable[cls].funcS and classTable[cls].funcS[func_name] then local tab_size = #classTable[cls].funcS[func_name].funcS if noPrintAlreadyOutput and tab_size>0 and alreadyOutput_func[cls] and alreadyOutput_func[cls][func_name] then line_pos[indent_var] = 0 local inde = print_inde() print(inde..'|---'..'◎Already') recursion_func[cls][func_name] = 0 indent_var = indent_var-1 local linePos = output:LineFromPosition(output.CurrentPos)-funcLinestart alreadyLocation[linePos] = alreadyOutput_func[cls][func_name] return end local alreadyLinePos = output:LineFromPosition(output.CurrentPos)-funcLinestart for k, name in pairs(classTable[cls].funcS[func_name].funcS)do if k == tab_size then line_pos[indent_var] = 0 else line_pos[indent_var] = 1 end local inde = print_inde() --print(inde..'|---'..name) local parent = '' if name[1]~= 0 then parent = name[1]..'::' end print(inde..'|---'..parent..name[2]) local linePos = output:LineFromPosition(output.CurrentPos)-funcLinestart local path = classTable[cls].funcS[func_name].path local line = name[3] location[linePos] = {path, line} if name[1]~= '?' and classTable[name[1]] and classTable[name[1]].funcS and classTable[name[1]].funcS[name[2]] then classTable[name[1]].funcS[name[2]].root = 0 end print_func(name) end if tab_size == 0 then line_pos[indent_var] = 0 local inde = print_inde() print(inde..'|---'..'(...)') local linePos = output:LineFromPosition(output.CurrentPos)-funcLinestart local path = classTable[cls].funcS[func_name].path local line = classTable[cls].funcS[func_name].lineS location[linePos] = {path, line} else if not alreadyOutput_func[cls] then alreadyOutput_func[cls] = {} end alreadyOutput_func[cls][func_name] = alreadyLinePos local inde = print_inde() print(inde) end end indent_var = indent_var-1 recursion_func[cls][func_name] = 0 end function print_inde() local inde = "" for i = 1, indent_var-1, 1 do if line_pos[i] == 0 then inde = inde.." " else inde = inde.."| " end end return inde end function research_type(var) local pattern = { '\\w+[ *]+', '\\w+\\s*<.+>\\s*' } local style = SCE_C_OPERATOR local s, e for k, name in pairs(pattern)do local pat = name..var e = 1 while e and style~= SCE_C_IDENTIFIER do s, e = editor:findtext(pat, SCFIND_MATCHCASE+SCFIND_REGEXP, e) if s then style = editor.StyleAt[s] end end if e then local def = editor:textrange(s, e) return string.match(def, "([%w_]+)[^%w_]+") end end return '?' end --[[ new class() class::func() point->func() ]]-- function getFunctionProperty(next_s, next_e) local parent_typ = nil local sel = editor:textrange(next_s, next_e) local func if editor.Lexer == SCLEX_TTL then func = string.match(sel, "%w+%s+([%w_]+)") if not func then func = sel end return {0, 0, func} end func = string.match(sel, "([%w_]+)%s*%(") if not func then func = sel end local lineNum = editor:LineFromPosition(next_s) local pos_s = editor:PositionFromLine(lineNum) sel = editor:textrange(pos_s, next_e) local pattern = '([%w_]+)([^%w_]+)'..func local parent, typ = string.match(sel, pattern) if parent then typ = string.match(typ, "(%S+)") if not typ then if parent == 'new' then parent_typ = func parent = nil elseif parent == 'return' then parent_typ = nil parent = nil else parent_typ = 0 parent = nil end elseif typ == '::' then parent_typ = parent elseif typ == '.' or typ == '->' then parent_typ = nil else parent = nil end end return {parent_typ, parent, func} end --/////////////////////////////////////////////////////////////////////////////////////////////////////////////// funcTree_prompt = '(function_tree)' local function functionTree_help() print("----[help for function tree]-----") print("clear -------clear all setting") print("del -------delete function tree") print("include path -------add directory for analysis files") print("except path -------add directory for unanalysis files") print("repeat [on|off] ------print function already outputed or not") print("status -------list all setting") print("read -------- running analysis ") print("tree [function] -------- ") print("[exit|quit] -- for exit function tree") print("-------------------------------") end local functree_status = 'dead' scite_OnOutputLine(function(line) local line = strip_prompt(line) local dir = string.match(line, "^%S+%s+(%S.+)$") local _, _, val = find(line, '^%s*([^=%s]+)%s*') local sta = command_status() if sta == 'dead' then if val == 'functree' then sta = command_status(val) set_prompt(funcTree_prompt) end elseif sta == 'functree' then if val == 'exit' or val == 'quit' then command_status('dead') return true elseif val == 'del' then remove_tree() elseif val == 'clear' then remove_tree() classTable = {} classTable[0] = {} classTable[0].memS = {} allFuncList = {} analysis = {} not_analysis = {} elseif val == 'repeat' then if dir == 'on' then noPrintAlreadyOutput = false else noPrintAlreadyOutput = true end elseif val == 'help' then functionTree_help() elseif val == 'status' then print("-------------------------------") if #allFuncList == 0 then print("-status:analysing not yet finished") else print("-status:analysing already finished") end if noPrintAlreadyOutput then print("-repeat off") else print("-repeat on") end if #funcPath ~= 0 then print("-read file:") end for filename, tbl in pairs(funcPath)do print(filename) end if #analysis ~= 0 then print("-directories for anallysis:") end for i, dirname in pairs(analysis)do print(dirname) end print() if #not_analysis ~= 0 then print("-directories for not anallysis:") end for dirname, val in pairs(not_analysis)do print(dirname) end print("-------------------------------") elseif val == 'include' then local path = gsub(dir, '/', '\\') local endChr = path:sub(-1) --print(endChr) if endChr == "\\" then path = path:sub(1, -2) --print(path) end table.insert(analysis, path) elseif val == 'except' then local path = gsub(dir, '\\', '/') not_analysis[path] = true elseif val == 'read' then allow_buffer_list(false) AnalysisFiles() allow_buffer_list(true) elseif val == 'tree' then local FileDir = props['FileDir']:gsub('\\', '/') local tree_dir = locatefunctree(FileDir, 'functree') classTable = funcPath[tree_dir..'/functree'] if dir then local cls, func = string.match(dir, "^([%w_]+)::([%w_]+)%s*$") if not cls then func = string.match(dir, "^([%w_]+)%s*$") end if not cls and not func then functionTree(nil, nil, 'oneFile') elseif not cls and func then functionTree(0, func, 'command') else functionTree(cls, func, 'command') end else functionTree(nil, nil, 'oneFile') end end else return false end if sta == 'functree' then print_prompt() return true end return false end)