diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 6b168670ca..072145a704 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -20,52 +20,119 @@ const sectionContext = "con" sectionUsage = "use" +type + Section = enum sug, def, con, use + Suggest = object + section: Section + qualifiedPath: seq[string] + filePath: string + line: int # Starts at 1 + column: int # Starts at 0 + doc: string # Not escaped (yet) + symkind: TSymKind + forth: string # XXX TODO object on symkind + +var + suggestionResultHook*: proc (result: Suggest) {.closure.} + #template sectionSuggest(): expr = "##begin\n" & getStackTrace() & "##end\n" template origModuleName(m: PSym): string = m.name.s -proc symToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string = - result = section - result.add(sep) +proc parseSection(s: string): Section = + case s: + of "sug": result = sug + of "con": result = con + of "use": result = use + of "def": result = def + else: raise newException(ERecoverableError, "Answer type incorrect") + +proc parseSymKind(s: string): TSymKind = + case s: + of "skDynLib": result = skDynLib + of "skParam": result = skParam + of "skGenericParam": result = skGenericParam + of "skTemp": result = skTemp + of "skModule": result = skModule + of "skType": result = skType + of "skVar": result = skVar + of "skLet": result = skLet + of "skConst": result = skConst + of "skResult": result = skResult + of "skProc": result = skProc + of "skMethod": result = skMethod + of "skIterator": result = skIterator + of "skClosureIterator": result = skClosureIterator + of "skConverter": result = skConverter + of "skMacro": result = skMacro + of "skTemplate": result = skTemplate + of "skField": result = skField + of "skEnumField": result = skEnumField + of "skForVar": result = skForVar + of "skLabel": result = skLabel + of "skStub": result = skStub + of "skPackage": result = skPackage + of "skAlias": result = skAlias + else: raise newException(ERecoverableError, "TSymKind not found") + +proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo): Suggest = + result.section = parseSection(section) if optIdeTerse in gGlobalOptions: if s.kind in routineKinds: - result.add renderTree(s.ast, {renderNoBody, renderNoComments, - renderDocComments, renderNoPragmas}) + result.symkind = parseSymKind(renderTree(s.ast, {renderNoBody, renderNoComments, + renderDocComments, renderNoPragmas})) else: - result.add s.name.s - result.add(sep) - result.add(toFullPath(li)) - result.add(sep) - result.add($toLinenumber(li)) - result.add(sep) - result.add($toColumn(li)) + result.symkind = parseSymKind(s.name.s) + result.filePath = toFullPath(li) + result.line = toLinenumber(li) + result.column = toColumn(li) else: - result.add($s.kind) - result.add(sep) + result.symkind = s.kind + result.qualifiedPath = @[] if not isLocal and s.kind != skModule: let ow = s.owner if ow.kind != skModule and ow.owner != nil: let ow2 = ow.owner - result.add(ow2.origModuleName) - result.add('.') - result.add(ow.origModuleName) - result.add('.') - result.add(s.name.s) - result.add(sep) - if s.typ != nil: - result.add(typeToString(s.typ)) - result.add(sep) - result.add(toFullPath(li)) - result.add(sep) - result.add($toLinenumber(li)) - result.add(sep) - result.add($toColumn(li)) - result.add(sep) - when not defined(noDocgen): - result.add(s.extractDocComment.escape) + result.qualifiedPath.add(ow2.origModuleName) + result.qualifiedPath.add(ow.origModuleName) + result.qualifiedPath.add(s.name.s) -proc symToStr(s: PSym, isLocal: bool, section: string): string = - result = symToStr(s, isLocal, section, s.info) + if s.typ != nil: + result.forth = typeToString(s.typ) + else: + result.forth = "" + result.filePath = toFullPath(li) + result.line = toLinenumber(li) + result.column = toColumn(li) + when not defined(noDocgen): + result.doc = s.extractDocComment + +proc `$`(suggest: Suggest): string = + result = $suggest.section + result.add(sep) + result.add($suggest.symkind) + result.add(sep) + result.add(suggest.qualifiedPath.join(".")) + result.add(sep) + result.add(suggest.forth) + result.add(sep) + result.add(suggest.filePath) + result.add(sep) + result.add($suggest.line) + result.add(sep) + result.add($suggest.column) + result.add(sep) + when not defined(noDocgen): + result.add(suggest.doc.escape) + +proc symToSuggest(s: PSym, isLocal: bool, section: string): Suggest = + result = symToSuggest(s, isLocal, section, s.info) + +proc suggestResult(s: Suggest) = + if not isNil(suggestionResultHook): + suggestionResultHook(s) + else: + suggestWriteln($(s)) proc filterSym(s: PSym): bool {.inline.} = result = s.kind != skModule @@ -84,7 +151,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = proc suggestField(c: PContext, s: PSym, outputs: var int) = if filterSym(s) and fieldVisible(c, s): - suggestWriteln(symToStr(s, isLocal=true, sectionSuggest)) + suggestResult(symToSuggest(s, isLocal=true, sectionSuggest)) inc outputs template wholeSymTab(cond, section: expr) {.immediate.} = @@ -97,7 +164,7 @@ template wholeSymTab(cond, section: expr) {.immediate.} = for item in entries: let it {.inject.} = item if cond: - suggestWriteln(symToStr(it, isLocal = isLocal, section)) + suggestResult(symToSuggest(it, isLocal = isLocal, section)) inc outputs proc suggestSymList(c: PContext, list: PNode, outputs: var int) = @@ -166,7 +233,7 @@ proc suggestEverything(c: PContext, n: PNode, outputs: var int) = if scope == c.topLevelScope: isLocal = false for it in items(scope.symbols): if filterSym(it): - suggestWriteln(symToStr(it, isLocal = isLocal, sectionSuggest)) + suggestResult(symToSuggest(it, isLocal = isLocal, sectionSuggest)) inc outputs if scope == c.topLevelScope: break @@ -181,12 +248,12 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) = # all symbols accessible, because we are in the current module: for it in items(c.topLevelScope.symbols): if filterSym(it): - suggestWriteln(symToStr(it, isLocal=false, sectionSuggest)) + suggestResult(symToSuggest(it, isLocal=false, sectionSuggest)) inc outputs else: for it in items(n.sym.tab): if filterSym(it): - suggestWriteln(symToStr(it, isLocal=false, sectionSuggest)) + suggestResult(symToSuggest(it, isLocal=false, sectionSuggest)) inc outputs else: # fallback: @@ -263,16 +330,16 @@ var proc findUsages(info: TLineInfo; s: PSym) = if usageSym == nil and isTracked(info, s.name.s.len): usageSym = s - suggestWriteln(symToStr(s, isLocal=false, sectionUsage)) + suggestResult(symToSuggest(s, isLocal=false, sectionUsage)) elif s == usageSym: if lastLineInfo != info: - suggestWriteln(symToStr(s, isLocal=false, sectionUsage, info)) + suggestResult(symToSuggest(s, isLocal=false, sectionUsage, info)) lastLineInfo = info proc findDefinition(info: TLineInfo; s: PSym) = if s.isNil: return if isTracked(info, s.name.s.len): - suggestWriteln(symToStr(s, isLocal=false, sectionDef)) + suggestResult(symToSuggest(s, isLocal=false, sectionDef)) suggestQuit() proc ensureIdx[T](x: var T, y: int) =