def test_misbalanced(self): """Make sure we cleanly excise a tag pair from a pair of interleaved tags.""" # A _________ (2, 6) # B ____________ (5, 9) a = Ref('a') b = Ref('b') tags = [(2, True, a), (5, True, b), (6, False, a), (9, False, b)] with catch_warnings(): warnings.simplefilter('ignore') remove_overlapping_refs(tags) eq_(tags, [(2, True, a), (6, False, a)])
def _refs_from_view(self, menu_maker, views, tooltip=constantly(None)): """Return an iterable of (start, end, (menu, tooltip)), running ``menu_maker`` across each item that comes of applying ``view`` to ``self.condensed`` and adding "Jump to definition" where applicable. :arg menu_maker: A function that takes a tree and an item from ``view()`` and returns a ref menu :arg views: An iterable of functions that take self.condensed and return an iterable of things to call ``menu_maker()`` on :arg tooltip: A function that takes one of those things from the iterable and emits a value to be shown in the mouseover of the ref """ for prop in chain.from_iterable(v(self.condensed) for v in views): if 'span' in prop: # TODO: This used to be unconditional. Should we still try to do it sometime if span isn't in prop? Both cases in test_direct are examples of this. [Marcell says no.] definition = prop.get('defloc') # If we can look up the target of this ref and it's not # outside the source tree (which results in an absolute path # starting with "/")... if definition and not definition[0].startswith('/'): menu = definition_menu(self.tree, path=definition[0], row=definition[1].row) else: menu = [] menu.extend(menu_maker(self.tree, prop)) start, end = prop['span'] yield (self.char_offset(start.row, start.col), self.char_offset(end.row, end.col), Ref(menu, hover=tooltip(prop), qualname=prop.get('qualname')))
def function_ref_menu(tree, datum, tree_config): fn_def = None fn_decl = None if 'refid' in datum and datum['refid'] and datum[ 'refid'] in tree.data.functions: fn_def = tree.data.functions[datum['refid']] elif 'refid' in datum and datum['refid'] and datum[ 'refid'] in tree.data.types: # enum variant ctors fn_def = tree.data.types[datum['refid']] if 'declid' in datum and datum['declid'] and datum[ 'declid'] in tree.data.functions: fn_decl = tree.data.functions[datum['declid']] menu = [] name = None if fn_def: menu = function_menu_generic(tree, fn_def, tree_config) if fn_decl and (fn_def['file_name'] != fn_decl['file_name'] or fn_def['file_line'] != fn_decl['file_line']): add_jump_definition(tree, tree_config, menu, fn_decl, "Jump to trait method") add_jump_definition(tree, tree_config, menu, fn_def) name = fn_def['qualname'] elif fn_decl: menu = function_menu_generic(tree, fn_decl, tree_config) add_jump_definition(tree, tree_config, menu, fn_decl, "Jump to trait method") name = fn_decl['qualname'] # FIXME(#12) should have type, not name for title return Ref(menu, hover=name)
def function_menu(tree, datum, tree_config): menu = function_menu_generic(tree, datum, tree_config) if 'declid' in datum and datum['declid'] in tree.data.functions: # it's an implementation, find the decl decl = tree.data.functions[datum['declid']] add_jump_definition(tree, tree_config, menu, decl, "Jump to trait method") else: # it's a decl, find implementations impls = tree.data.index('functions', 'declid') count = len(impls[datum['id']]) if datum['id'] in impls else 0 if count > 0: menu.append({ 'html': "Find implementations (%d)" % count, 'title': "Find implementations of this trait method", 'href': search_url(tree_config, "+fn-impls:%s" % quote(datum['qualname'])), 'icon': 'method' }) return Ref(menu)
def variable_menu(tree, datum, tree_config): menu = variable_menu_generic(tree, datum, tree_config) typ = None if 'type' in datum: typ = datum['type'] else: print "no type for variable", datum['qualname'] return Ref(menu, hover=truncate_value("", typ))
def type_ref_menu(tree, datum, tree_config): if datum['refid'] and datum['refid'] in tree.data.types: typ = tree.data.types[datum['refid']] menu = type_menu_generic(tree, typ, tree_config) add_jump_definition(tree, tree_config, menu, typ) title = None if 'value' in typ: title = typ['value'] else: print "no value for", typ['kind'], typ['qualname'] return Ref(menu, hover=truncate_value("", title)) return None
def refs(self): for m in self.plugin_config.regex.finditer(self.contents): bug = m.group(1) yield m.start(0), m.end(0), Ref([{ 'html': cgi.escape("Bug %s" % bug), 'title': "Find this bug in %s" % self.plugin_config.name, 'href': self.plugin_config.url % bug, 'icon': 'buglink' }])
def test_horrors(self): """Try a fairly horrific scenario:: A _______________ (0, 7) B _________ (2, 6) C ____________ (5, 9) D _______ (8, 11) E __ (10, 11) 0 2 5 6 7 8 9 A contains B. B closes while C's still going on. D and E end at the same time. There's even a Region in there. """ a, b, c, d, e = Ref('a'), Region('b'), Ref('c'), Ref('d'), Ref('e') tags = [(0, True, a), (2, True, b), (5, True, c), (6, False, b), (7, False, a), (8, True, d), (9, False, c), (10, True, e), (11, False, e), (11, False, d)] eq_( spaced_tags(balanced_tags(tags)), '<L>\n' '<a>\n' ' <b>\n' ' <c>\n' ' </c>\n' ' </b>\n' ' <c>\n' ' </c>\n' ' </a>\n' ' <c>\n' ' <d>\n' ' </d>\n' ' </c>\n' ' <d>\n' ' <e>\n' ' </e>\n' ' </d>\n' ' </L>')
def test_overlapping_regions(self): """Regions (as opposed to refs) are allowed to overlap and shouldn't be disturbed:: A _________ (2, 6) B (region) ____________ (5, 9) """ a = Ref('a') b = Region('b') tags = [(2, True, a), (5, True, b), (6, False, a), (9, False, b)] original_tags = tags[:] remove_overlapping_refs(tags) eq_(tags, original_tags)
def unknown_ref_menu(tree, datum, tree_config): if datum['refid'] and datum['refid'] in tree.data.unknowns: unknown = tree.data.unknowns[datum['refid']] menu = [] add_find_references(tree_config, menu, str(datum['refid']), "extern-ref", "item") if unknown['crate'] in tree.locations: urls = tree.locations[unknown['crate']] std_lib_links(tree_config, menu, urls) return Ref(menu) print "unknown unknown!" return None
def variable_ref_menu(tree, datum, tree_config): if datum['refid'] and datum['refid'] in tree.data.variables: var = tree.data.variables[datum['refid']] menu = variable_menu_generic(tree, var, tree_config) add_jump_definition(tree, tree_config, menu, var) typ = None if 'type' in var: typ = var['type'] else: print "no type for variable ref", var['qualname'] return Ref(menu, hover=truncate_value(typ, var['value'])) # TODO what is the culprit here? #print "variable ref missing def" return None
def test_split_anchor_avoidance(self): """Don't split anchor tags when we can avoid it.""" eq_( text_to_html_lines('this that', [(0, 9, Ref({}))], [(0, 4, Region('k'))]), [u'<a data-menu="{}"><span class="k">this</span> that</a>'])
def module_alias_menu(tree, datum, tree_config): # Add straightforward aliases to modules if datum['refid'] and datum['refid'] in tree.data.modules: mod = tree.data.modules[datum['refid']] if mod['name'] != datum['name']: # Add module aliases. 'use' without an explicit alias and without any wildcards, # etc. introduces an implicit alias for the module. E.g, |use a::b::c| # introduces an alias |c|. In these cases, we make the alias transparent - # there is no link for the alias, but we add the alias menu stuff to the # module ref. menu = [] add_find_references(tree_config, menu, datum['qualname'], "module-alias-ref", "alias") add_jump_definition_to_line(tree, tree_config, menu, mod['def_file'], 1, "Jump to module defintion") return Ref(menu) # 'module' aliases to types if datum['refid'] and datum['refid'] in tree.data.types: typ = tree.data.types[datum['refid']] if typ['name'] != datum['name']: menu = [] add_find_references(tree_config, menu, datum['qualname'], "type-ref", "alias") add_jump_definition(tree, tree_config, menu, typ, "Jump to type declaration") return Ref(menu) # 'module' aliases to variables if datum['refid'] and datum['refid'] in tree.data.variables: var = tree.data.variables[datum['refid']] if var['name'] != datum['name']: menu = [] add_find_references(tree_config, menu, datum['qualname'], "var-ref", "alias") add_jump_definition(tree, tree_config, menu, var, "Jump to variable declaration") return Ref(menu) # 'module' aliases to functions if datum['refid'] and datum['refid'] in tree.data.functions: fn = tree.data.functions[datum['refid']] if fn['name'] != datum['name']: menu = [] add_find_references(tree_config, menu, datum['qualname'], "function-ref", "alias") add_jump_definition(tree, tree_config, menu, fn, "Jump to function declaration") return Ref(menu) # extern crates to known local crates if 'location' in datum and datum['location'] and datum[ 'location'] in tree.crates_by_name: crate = tree.crates_by_name[datum['location']] menu = [] add_find_references(tree_config, menu, datum['qualname'], "module-alias-ref", "alias") add_jump_definition_to_line(tree, tree_config, menu, crate['file_name'], 1, "Jump to crate") return Ref(menu) # extern crates to standard library crates if 'location' in datum and datum['location'] and datum[ 'location'] in tree.locations: urls = tree.locations[datum['location']] menu = [] add_find_references(tree_config, menu, datum['qualname'], "module-alias-ref", "alias") std_lib_links(tree_config, menu, urls) return Ref(menu) # other references to standard library items if datum['refid'] in tree.data.unknowns: # FIXME We could probably do better and link to the precise type or static in docs etc., rather than just the crate urls = tree.locations[tree.data.unknowns[datum['refid']]['crate']] menu = [] add_find_references(tree_config, menu, datum['qualname'], "module-alias-ref", "alias") std_lib_links(tree_config, menu, urls) return Ref(menu) # extern mods to unknown local crates menu = [] add_find_references(tree_config, menu, datum['qualname'], "module-alias-ref", "alias") return Ref(menu)
def module_ref_menu(tree, datum, tree_config): # Add straightforward aliases to modules if datum['refid']: mod = None if datum['refid'] in tree.data.modules: mod = tree.data.modules[datum['refid']] elif datum['refid'] in tree.data.extern_crate_mods: mod = tree.data.extern_crate_mods[datum['refid']] if mod: menu = module_menu_generic(tree, mod, tree_config) if datum['aliasid'] and datum[ 'aliasid'] in tree.data.module_aliases: alias = tree.data.module_aliases[datum['aliasid']] if 'location' in alias and alias[ 'location'] in tree.crates_by_name: # Add references to extern mods via aliases (known local crates) crate = tree.crates_by_name[alias['location']] menu = [] add_find_references(tree_config, menu, alias['qualname'], "module-alias-ref", "alias") add_jump_definition_to_line(tree, tree_config, menu, crate['file_name'], 1, "Jump to crate") elif 'location' in alias and alias[ 'location'] in tree.locations: # Add references to extern mods via aliases (standard library crates) urls = tree.locations[alias['location']] menu = [] add_find_references(tree_config, menu, alias['qualname'], "module-alias-ref", "alias") std_lib_links(tree_config, menu, urls) elif 'location' in alias: # Add references to extern mods via aliases (unknown local crates) menu = [] add_find_references(tree_config, menu, alias['qualname'], "module-alias-ref", "alias") elif 'file_name' in mod: add_jump_definition(tree, tree_config, menu, mod, "Jump to module defintion") if 'file_name' in mod: add_jump_definition(tree, tree_config, menu, mod, "Jump to alias defintion") else: if 'file_name' in mod and 'def_file' in mod and mod[ 'def_file'] == mod['file_name']: add_jump_definition(tree, tree_config, menu, mod) else: add_jump_definition_to_line(tree, tree_config, menu, mod['def_file'], 1, "Jump to module defintion") add_jump_definition(tree, tree_config, menu, mod, "Jump to module declaration") return Ref(menu) # types masquerading as modules if datum['refid'] in tree.data.types: typ = tree.data.types[datum['refid']] menu = type_menu_generic(tree, typ, tree_config) add_jump_definition(tree, tree_config, menu, typ) title = None if 'value' in typ: title = typ['value'] else: print "no value for", typ['kind'], typ['qualname'] return Ref(menu, hover=truncate_value("", title)) return None
def module_menu(tree, datum, tree_config): menu = module_menu_generic(tree, datum, tree_config) if datum['def_file'] != datum['file_name']: add_jump_definition_to_line(tree, tree_config, menu, datum['def_file'], 1, "Jump to module defintion") return Ref(menu)
def yield_ref(self, start, end, menus): self.refs.append((start, end, Ref(menus)))
def type_menu(tree, datum, tree_config): return Ref(type_menu_generic(tree, datum, tree_config))
def yield_ref(self, start, end, menu): self.refs.append(( self.file_to_index.char_offset(*start), self.file_to_index.char_offset(*end), Ref(menu), ))
def test_split_anchor_across_lines(self): """Support unavoidable splits of an anchor across lines.""" # We must preserve the \n in the output so that text within refs/regions keeps line breaks. eq_(text_to_html_lines('this\nthat', refs=[(0, 9, Ref({}))]), [u'<a data-menu="{}">this\n</a>', u'<a data-menu="{}">that</a>'])