# # # The Nim Compiler # (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## This file implements features required for IDE support. ## ## Due to Nim's nature and the fact that ``system.nim`` is always imported, ## there are lots of potential symbols. Furthermore thanks to templates and ## macros even context based analysis does not help much: In a context like ## ``let x: |`` where a type has to follow, that type might be constructed from ## a template like ``extractField(MyObject, fieldName)``. We deal with this ## problem by smart sorting so that the likely symbols come first. This sorting ## is done this way: ## ## - If there is a prefix (foo|), symbols starting with this prefix come first. ## - If the prefix is part of the name (but the name doesn't start with it), ## these symbols come second. ## - If we have a prefix, only symbols matching this prefix are returned and ## nothing else. ## - If we have no prefix, consider the context. We currently distinguish ## between type and non-type contexts. ## - Finally, sort matches by relevance. The relevance is determined by the ## number of usages, so ``strutils.replace`` comes before ## ``strutils.wordWrap``. ## - In any case, sorting also considers scoping information. Local variables ## get high priority. # included from sigmatch.nim import algorithm, prefixmatches when defined(nimsuggest): import passes, tables # importer const sep = '\t' type Suggest* = ref object section*: IdeCmd qualifiedPath*: seq[string] name*: PIdent # not used beyond sorting purposes; name is also # part of 'qualifiedPath' filePath*: string line*: int # Starts at 1 column*: int # Starts at 0 doc*: string # Not escaped (yet) symkind*: TSymKind forth*: string # type quality*: range[0..100] # matching quality isGlobal*: bool # is a global variable contextFits*: bool # type/non-type context matches prefix*: PrefixMatch scope*, localUsages*, globalUsages*: int # more usages is better tokenLen*: int Suggestions* = seq[Suggest] var suggestionResultHook*: proc (result: Suggest) {.closure.} suggestVersion*: int suggestMaxResults* = 10_000 #template sectionSuggest(): expr = "##begin\n" & getStackTrace() & "##end\n" template origModuleName(m: PSym): string = m.name.s proc findDocComment(n: PNode): PNode = if n == nil: return nil if not isNil(n.comment): return n if n.kind in {nkStmtList, nkStmtListExpr, nkObjectTy, nkRecList} and n.len > 0: result = findDocComment(n.sons[0]) if result != nil: return if n.len > 1: result = findDocComment(n.sons[1]) elif n.kind in {nkAsgn, nkFastAsgn} and n.len == 2: result = findDocComment(n.sons[1]) proc extractDocComment(s: PSym): string = var n = findDocComment(s.ast) if n.isNil and s.kind in routineKinds and s.ast != nil: n = findDocComment(s.ast[bodyPos]) if not n.isNil: result = n.comment.replace("\n##", "\n").strip else: result = "" proc cmpSuggestions(a, b: Suggest): int = template cf(field) {.dirty.} = result = b.field.int - a.field.int if result != 0: return result cf scope cf prefix # when the first type matches, it's better when it's a generic match: cf quality cf contextFits cf localUsages cf globalUsages # if all is equal, sort alphabetically for deterministic output, # independent of hashing order: result = cmp(a.name.s, b.name.s) proc symToSuggest(s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo; quality: range[0..100]; prefix: PrefixMatch; inTypeContext: bool; scope: int): Suggest = new(result) result.section = section result.quality = quality result.isGlobal = sfGlobal in s.flags result.tokenLen = s.name.s.len result.prefix = prefix result.contextFits = inTypeContext == (s.kind in {skType, skGenericParam}) result.scope = scope result.name = s.name when defined(nimsuggest): result.globalUsages = s.allUsages.len var c = 0 for u in s.allUsages: if u.fileIndex == info.fileIndex: inc c result.localUsages = c result.symkind = s.kind if optIdeTerse notin gGlobalOptions: result.qualifiedPath = @[] if not isLocal and s.kind != skModule: let ow = s.owner if ow != nil and ow.kind != skModule and ow.owner != nil: let ow2 = ow.owner result.qualifiedPath.add(ow2.origModuleName) if ow != nil: result.qualifiedPath.add(ow.origModuleName) result.qualifiedPath.add(s.name.s) if s.typ != nil: result.forth = typeToString(s.typ) else: result.forth = "" when not defined(noDocgen): result.doc = s.extractDocComment let infox = if section in {ideUse, ideHighlight, ideOutline}: info else: s.info result.filePath = toFullPath(infox) result.line = toLinenumber(infox) result.column = toColumn(infox) proc `$`*(suggest: Suggest): string = result = $suggest.section result.add(sep) if suggest.section == ideHighlight: if suggest.symkind == skVar and suggest.isGlobal: result.add("skGlobalVar") elif suggest.symkind == skLet and suggest.isGlobal: result.add("skGlobalLet") else: result.add($suggest.symkind) result.add(sep) result.add($suggest.line) result.add(sep) result.add($suggest.column) result.add(sep) result.add($suggest.tokenLen) else: result.add($suggest.symkind) result.add(sep) if suggest.qualifiedPath != nil: 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) if suggestVersion == 0: result.add(sep) result.add($suggest.quality) if suggest.section == ideSug: result.add(sep) result.add($suggest.prefix) proc suggestResult(s: Suggest) = if not isNil(suggestionResultHook): suggestionResultHook(s) else: suggestWriteln($s) proc produceOutput(a: var Suggestions) = if gIdeCmd in {ideSug, ideCon}: a.sort cmpSuggestions when defined(debug): # debug code writeStackTrace() if a.len > suggestMaxResults: a.setLen(suggestMaxResults) if not isNil(suggestionResultHook): for s in a: suggestionResultHook(s) else: for s in a: suggestWriteln($s) proc filterSym(s: PSym; prefix: PNode; res: var PrefixMatch): bool {.inline.} = proc prefixMatch(s: PSym; n: PNode): PrefixMatch = case n.kind of nkIdent: result = n.ident.s.prefixMatch(s.name.s) of nkSym: result = n.sym.name.s.prefixMatch(s.name.s) of nkOpenSymChoice, nkClosedSymChoice, nkAccQuoted: if n.len > 0: result = prefixMatch(s, n[0]) else: discard if s.kind != skModule: if prefix != nil: res = prefixMatch(s, prefix) result = res != PrefixMatch.None else: result = true proc filterSymNoOpr(s: PSym; prefix: PNode; res: var PrefixMatch): bool {.inline.} = result = filterSym(s, prefix, res) and s.name.s[0] in lexer.SymChars and not isKeyword(s.name) proc fieldVisible*(
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: module ranger.ext.openstruct</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head><body bgcolor="#f0f0f8">
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="ranger.html"><font color="#ffffff">ranger</font></a>.<a href="ranger.ext.html"><font color="#ffffff">ext</font></a>.openstruct</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/hut/code/ranger/ranger/ext/openstruct.py">/home/hut/code/ranger/ranger/ext/openstruct.py</a></font></td></tr></table>
<p><tt># Copyright (C) 2009, 2010 Roman Zimbelmann <romanz@lavabit.com><br>
#<br>
# This program is free software: you can redistribute it and/or modify<br>
# it under the terms of the GNU General Public License as published by<br>
# the Free Software Foundation, either version 3 of the License, or<br>
# (at your option) any later version.<br>
#<br>
# This program is distributed in the hope that it&am