{"action":"created","comment":{"url":"https://api.github.com/repos/mozilla/dxr/pulls/comments/35893176","id":35893176,"diff_hunk":"@@ -0,0 +1,252 @@\n+from cStringIO import StringIO\n+from itertools import ifilter\n+from os.path import relpath, join, basename, dirname, exists\n+\n+from flask import url_for\n+from xpidl.header import (idl_basename, header, include, jsvalue_include,\n+                          infallible_includes, header_end, forward_decl,\n+                          write_interface, printComments)\n+from xpidl.xpidl import Attribute\n+\n+from dxr.indexers import Ref, Extent, Position\n+from dxr.plugins.xpidl.filters import PLUGIN_NAME\n+from dxr.utils import search_url\n+\n+\n+def start_pos(name, location):\n+    \"\"\"Return the last byte position on which we can find name in the\n+    location's line, resolving if necessary.\"\"\"\n+\n+    location.resolve()\n+    return location._line.rfind(name) - location._colno + location._lexpos\n+\n+\n+def header_line_numbers(idl, filename):\n+    \"\"\"Map each production to its line number in the header.\"\"\"\n+    # Basically I replace all fd.write in print_header with line increments\n+    def number_lines(text):\n+        return len(text.splitlines())\n+\n+    production_map = {}\n+    line = number_lines(header % {'filename': filename,\n+                                  'basename': idl_basename(filename)}) + 1\n+\n+    foundinc = False\n+    for inc in idl.includes():\n+        if not foundinc:\n+            foundinc = True\n+            line += 1\n+        line += number_lines(include % {'basename': idl_basename(inc.filename)})\n+\n+    if idl.needsJSTypes():\n+        line += number_lines(jsvalue_include)\n+\n+    # Include some extra files if any attributes are infallible.\n+    for iface in [p for p in idl.productions if p.kind == 'interface']:\n+        for attr in [m for m in iface.members if isinstance(m, Attribute)]:\n+            if attr.infallible:\n+                line += number_lines(infallible_includes)\n+                break\n+\n+    line += number_lines(header_end) + 1\n+\n+    for p in idl.productions:\n+        production_map[p] = line\n+        if p.kind == 'cdata':\n+            line += number_lines(p.data)\n+        elif p.kind == 'forward':\n+            line += number_lines(forward_decl % {'name': p.name})\n+        elif p.kind == 'interface':\n+            # write_interface inserts a blank line at the start.\n+            production_map[p] += 1\n+            # Eh....\n+            fd = StringIO()\n+            write_interface(p, fd)\n+            line += len(fd.readlines())\n+        elif p.kind == 'typedef':\n+            fd = StringIO()\n+            printComments(fd, p.doccomments, '')\n+            line += len(fd.readlines())\n+            line += number_lines(\"typedef %s %s;\\n\\n\" % (p.realtype.nativeType('in'),\n+                                                         p.name))\n+\n+    return production_map\n+\n+\n+class IdlVisitor(object):\n+    \"\"\"Traverse an IDL syntax tree and collect refs and needles.\"\"\"\n+\n+    def __init__(self, parser, contents, rel_path, abs_path, include_folders, header_bucket,\n+                 tree_config):\n+        \"\"\"\n+        Parse an IDL file and visit the productions of its AST.\n+\n+        :arg parser: IdlParser to use to parse the file\n+        :arg contents: the contents of the file, as a string\n+        :arg rel_path: relative path to the file from tree root\n+        :arg abs_path: absolute path to the file\n+        :arg include_folders: list of folders to use to resolve include directives\n+        :arg header_bucket: folder in which the generated header would be placed to make links\n+        :arg tree_config: A :class:`TreeConfig` object for the current tree\n+        \"\"\"\n+        self.tree = tree_config\n+        # Hold on to the URL so we do not have to regenerate it everywhere.\n+        self.header_filename = basename(rel_path.replace('.idl', '.h'))\n+        header_path = relpath(join(header_bucket, self.header_filename),\n+                              self.tree.source_folder)\n+        self.generated_url = url_for('.browse',\n+                                     tree=self.tree.name,\n+                                     path=header_path)\n+        ast = parser.parse(contents, basename(rel_path))\n+        # Might raise IdlError\n+        self.search_paths = [dirname(abs_path)] + include_folders\n+        ast.resolve(self.search_paths, parser)\n+        self.line_map = header_line_numbers(ast, self.header_filename)\n+        self.line_list = contents.splitlines()\n+        # List of (start, end, Ref) where start and end are byte offsets into the file.\n+        self.refs = []\n+        self.needles = []\n+\n+        # Initiate visitations.\n+        for item in ast.productions:\n+            try:\n+                getattr(self, 'visit_' + item.kind)(item)\n+            except AttributeError:\n+                # TODO: can we do something useful for these?\n+                # Unhandled: {'builtin', 'cdata', 'native', 'attribute'}\n+                pass\n+\n+    def check_lineno(self, needle, line):\n+        \"\"\"Check whether needle string appears on line; if it doesn't then try the one above and\n+        below.\n+\n+        Return the line number (0-offset) where the needle appears nearest input line,\n+        None if needle not found nearby.\n+\n+        \"\"\"\n+        for lineno in [line, line - 1, line + 1]:\n+            # Make sure we stay in bounds.\n+            if 0 <= lineno < len(self.line_list):\n+                if needle in self.line_list[lineno]:\n+                    return lineno\n+\n+    def make_extent(self, name, location):\n+        \"\"\"Return an Extent for the given name in this Location, None if we cannot construct it.\"\"\"\n+\n+        # Remark: sometimes the location's line number is off by one (in either\n+        # direction), so we check the surroundings to make sure it's there.\n+        location.resolve()\n+        start_col = location._line.rfind(name)\n+        lineno = self.check_lineno(name, location._lineno)\n+        if lineno:\n+            return Extent(Position(lineno + 1, start_col),\n+                          Position(lineno + 1, start_col + len(name)))\n+\n+    def yield_needle(self, name, mapping, extent):\n+        self.needles.append((PLUGIN_NAME + '_' + name, mapping, extent))\n+\n+    def yield_name_needle(self, filter_name, name, location):","path":"dxr/plugins/xpidl/visitor.py","position":148,"original_position":148,"commit_id":"742a6d9bd407a35907fa60a7efea458eb316b179","original_commit_id":"742a6d9bd407a35907fa60a7efea458eb316b179","user":{"login":"erikrose","id":295816,"avatar_url":"https://avatars.githubusercontent.com/u/295816?v=3","gravatar_id":"","url":"https://api.github.com/users/erikrose","html_url":"https://github.com/erikrose","followers_url":"https://api.github.com/users/erikrose/followers","following_url":"https://api.github.com/users/erikrose/following{/other_user}","gists_url":"https://api.github.com/users/erikrose/gists{/gist_id}","starred_url":"https://api.github.com/users/erikrose/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/erikrose/subscriptions","organizations_url":"https://api.github.com/users/erikrose/orgs","repos_url":"https://api.github.com/users/erikrose/repos","events_url":"https://api.github.com/users/erikrose/events{/privacy}","received_events_url":"https://api.github.com/users/erikrose/received_events","type":"User","site_admin":false},"body":"I wouldn't mind a docstring.","created_at":"2015-07-30T16:58:48Z","updated_at":"2015-07-30T16:58:48Z","html_url":"https://github.com/mozilla/dxr/pull/456#discussion_r35893176","pull_request_url":"https://api.github.com/repos/mozilla/dxr/pulls/456","_links":{"self":{"href":"https://api.github.com/repos/mozilla/dxr/pulls/comments/35893176"},"html":{"href":"https://github.com/mozilla/dxr/pull/456#discussion_r35893176"},"pull_request":{"href":"https://api.github.com/repos/mozilla/dxr/pulls/456"}}},"pull_request":{"url":"https://api.github.com/repos/mozilla/dxr/pulls/456","id":40147911,"html_url":"https://github.com/mozilla/dxr/pull/456","diff_url":"https://github.com/mozilla/dxr/pull/456.diff","patch_url":"https://github.com/mozilla/dxr/pull/456.patch","issue_url":"https://api.github.com/repos/mozilla/dxr/issues/456","number":456,"state":"open","locked":false,"title":"XPIDL support","user":{"login":"pelmers","id":2406051,"avatar_url":"https://avatars.githubusercontent.com/u/2406051?v=3","gravatar_id":"","url":"https://api.github.com/users/pelmers","html_url":"https://github.com/pelmers","followers_url":"https://api.github.com/users/pelmers/followers","following_url":"https://api.github.com/users/pelmers/following{/other_user}","gists_url":"https://api.github.com/users/pelmers/gists{/gist_id}","starred_url":"https://api.github.com/users/pelmers/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pelmers/subscriptions","organizations_url":"https://api.github.com/users/pelmers/orgs","repos_url":"https://api.github.com/users/pelmers/repos","events_url":"https://api.github.com/users/pelmers/events{/privacy}","received_events_url":"https://api.github.com/users/pelmers/received_events","type":"User","site_admin":false},"body":"Add plugin for XPIDL files.\r\n\r\nRiding along is syntax highlighting for IDL, XUL, and moz.build files.","created_at":"2015-07-16T16:22:45Z","updated_at":"2015-07-30T16:58:48Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7ff04542a8744f818758b134f7725908f442986a","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/mozilla/dxr/pulls/456/commits","review_comments_url":"https://api.github.com/repos/mozilla/dxr/pulls/456/comments","review_comment_url":"https://api.github.com/repos/mozilla/dxr/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mozilla/dxr/issues/456/comments","statuses_url":"https://api.github.com/repos/mozilla/dxr/statuses/742a6d9bd407a35907fa60a7efea458eb316b179","head":{"label":"pelmers:xpidls-rebased","ref":"xpidls-rebased","sha":"742a6d9bd407a35907fa60a7efea458eb316b179","user":{"login":"pelmers","id":2406051,"avatar_url":"https://avatars.githubusercontent.com/u/2406051?v=3","gravatar_id":"","url":"https://api.github.com/users/pelmers","html_url":"https://github.com/pelmers","followers_url":"https://api.github.com/users/pelmers/followers","following_url":"https://api.github.com/users/pelmers/following{/other_user}","gists_url":"https://api.github.com/users/pelmers/gists{/gist_id}","starred_url":"https://api.github.com/users/pelmers/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pelmers/subscriptions","organizations_url":"https://api.github.com/users/pelmers/orgs","repos_url":"https://api.github.com/users/pelmers/repos","events_url":"https://api.github.com/users/pelmers/events{/privacy}","received_events_url":"https://api.github.com/users/pelmers/received_events","type":"User","site_admin":false},"repo":{"id":15886083,"name":"dxr","full_name":"pelmers/dxr","owner":{"login":"pelmers","id":2406051,"avatar_url":"https://avatars.githubusercontent.com/u/2406051?v=3","gravatar_id":"","url":"https://api.github.com/users/pelmers","html_url":"https://github.com/pelmers","followers_url":"https://api.github.com/users/pelmers/followers","following_url":"https://api.github.com/users/pelmers/following{/other_user}","gists_url":"https://api.github.com/users/pelmers/gists{/gist_id}","starred_url":"https://api.github.com/users/pelmers/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pelmers/subscriptions","organizations_url":"https://api.github.com/users/pelmers/orgs","repos_url":"https://api.github.com/users/pelmers/repos","events_url":"https://api.github.com/users/pelmers/events{/privacy}","received_events_url":"https://api.github.com/users/pelmers/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/pelmers/dxr","description":"An intelligent source code browser","fork":true,"url":"https://api.github.com/repos/pelmers/dxr","forks_url":"https://api.github.com/repos/pelmers/dxr/forks","keys_url":"https://api.github.com/repos/pelmers/dxr/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pelmers/dxr/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pelmers/dxr/teams","hooks_url":"https://api.github.com/repos/pelmers/dxr/hooks","issue_events_url":"https://api.github.com/repos/pelmers/dxr/issues/events{/number}","events_url":"https://api.github.com/repos/pelmers/dxr/events","assignees_url":"https://api.github.com/repos/pelmers/dxr/assignees{/user}","branches_url":"https://api.github.com/repos/pelmers/dxr/branches{/branch}","tags_url":"https://api.github.com/repos/pelmers/dxr/tags","blobs_url":"https://api.github.com/repos/pelmers/dxr/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pelmers/dxr/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pelmers/dxr/git/refs{/sha}","trees_url":"https://api.github.com/repos/pelmers/dxr/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pelmers/dxr/statuses/{sha}","languages_url":"https://api.github.com/repos/pelmers/dxr/languages","stargazers_url":"https://api.github.com/repos/pelmers/dxr/stargazers","contributors_url":"https://api.github.com/repos/pelmers/dxr/contributors","subscribers_url":"https://api.github.com/repos/pelmers/dxr/subscribers","subscription_url":"https://api.github.com/repos/pelmers/dxr/subscription","commits_url":"https://api.github.com/repos/pelmers/dxr/commits{/sha}","git_commits_url":"https://api.github.com/repos/pelmers/dxr/git/commits{/sha}","comments_url":"https://api.github.com/repos/pelmers/dxr/comments{/number}","issue_comment_url":"https://api.github.com/repos/pelmers/dxr/issues/comments{/number}","contents_url":"https://api.github.com/repos/pelmers/dxr/contents/{+path}","compare_url":"https://api.github.com/repos/pelmers/dxr/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pelmers/dxr/merges","archive_url":"https://api.github.com/repos/pelmers/dxr/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pelmers/dxr/downloads","issues_url":"https://api.github.com/repos/pelmers/dxr/issues{/number}","pulls_url":"https://api.github.com/repos/pelmers/dxr/pulls{/number}","milestones_url":"https://api.github.com/repos/pelmers/dxr/milestones{/number}","notifications_url":"https://api.github.com/repos/pelmers/dxr/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pelmers/dxr/labels{/name}","releases_url":"https://api.github.com/repos/pelmers/dxr/releases{/id}","created_at":"2014-01-13T23:50:59Z","updated_at":"2015-01-02T15:41:27Z","pushed_at":"2015-07-30T16:54:30Z","git_url":"git://github.com/pelmers/dxr.git","ssh_url":"git@github.com:pelmers/dxr.git","clone_url":"https://github.com/pelmers/dxr.git","svn_url":"https://github.com/pelmers/dxr","homepage":"","size":10929,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"mozilla:es","ref":"es","sha":"31d4b18de327a71e27a9a7ab472c287aff3c066e","user":{"login":"mozilla","id":131524,"avatar_url":"https://avatars.githubusercontent.com/u/131524?v=3","gravatar_id":"","url":"https://api.github.com/users/mozilla","html_url":"https://github.com/mozilla","followers_url":"https://api.github.com/users/mozilla/followers","following_url":"https://api.github.com/users/mozilla/following{/other_user}","gists_url":"https://api.github.com/users/mozilla/gists{/gist_id}","starred_url":"https://api.github.com/users/mozilla/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mozilla/subscriptions","organizations_url":"https://api.github.com/users/mozilla/orgs","repos_url":"https://api.github.com/users/mozilla/repos","events_url":"https://api.github.com/users/mozilla/events{/privacy}","received_events_url":"https://api.github.com/users/mozilla/received_events","type":"Organization","site_admin":false},"repo":{"id":1795049,"name":"dxr","full_name":"mozilla/dxr","owner":{"login":"mozilla","id":131524,"avatar_url":"https://avatars.githubusercontent.com/u/131524?v=3","gravatar_id":"","url":"https://api.github.com/users/mozilla","html_url":"https://github.com/mozilla","followers_url":"https://api.github.com/users/mozilla/followers","following_url":"https://api.github.com/users/mozilla/following{/other_user}","gists_url":"https://api.github.com/users/mozilla/gists{/gist_id}","starred_url":"https://api.github.com/users/mozilla/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mozilla/subscriptions","organizations_url":"https://api.github.com/users/mozilla/orgs","repos_url":"https://api.github.com/users/mozilla/repos","events_url":"https://api.github.com/users/mozilla/events{/privacy}","received_events_url":"https://api.github.com/users/mozilla/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mozilla/dxr","description":"An intelligent source code browser","fork":false,"url":"https://api.github.com/repos/mozilla/dxr","forks_url":"https://api.github.com/repos/mozilla/dxr/forks","keys_url":"https://api.github.com/repos/mozilla/dxr/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mozilla/dxr/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mozilla/dxr/teams","hooks_url":"https://api.github.com/repos/mozilla/dxr/hooks","issue_events_url":"https://api.github.com/repos/mozilla/dxr/issues/events{/number}","events_url":"https://api.github.com/repos/mozilla/dxr/events","assignees_url":"https://api.github.com/repos/mozilla/dxr/assignees{/user}","branches_url":"https://api.github.com/repos/mozilla/dxr/branches{/branch}","tags_url":"https://api.github.com/repos/mozilla/dxr/tags","blobs_url":"https://api.github.com/repos/mozilla/dxr/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mozilla/dxr/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mozilla/dxr/git/refs{/sha}","trees_url":"https://api.github.com/repos/mozilla/dxr/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mozilla/dxr/statuses/{sha}","languages_url":"https://api.github.com/repos/mozilla/dxr/languages","stargazers_url":"https://api.github.com/repos/mozilla/dxr/stargazers","contributors_url":"https://api.github.com/repos/mozilla/dxr/contributors","subscribers_url":"https://api.github.com/repos/mozilla/dxr/subscribers","subscription_url":"https://api.github.com/repos/mozilla/dxr/subscription","commits_url":"https://api.github.com/repos/mozilla/dxr/commits{/sha}","git_commits_url":"https://api.github.com/repos/mozilla/dxr/git/commits{/sha}","comments_url":"https://api.github.com/repos/mozilla/dxr/comments{/number}","issue_comment_url":"https://api.github.com/repos/mozilla/dxr/issues/comments{/number}","contents_url":"https://api.github.com/repos/mozilla/dxr/contents/{+path}","compare_url":"https://api.github.com/repos/mozilla/dxr/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mozilla/dxr/merges","archive_url":"https://api.github.com/repos/mozilla/dxr/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mozilla/dxr/downloads","issues_url":"https://api.github.com/repos/mozilla/dxr/issues{/number}","pulls_url":"https://api.github.com/repos/mozilla/dxr/pulls{/number}","milestones_url":"https://api.github.com/repos/mozilla/dxr/milestones{/number}","notifications_url":"https://api.github.com/repos/mozilla/dxr/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mozilla/dxr/labels{/name}","releases_url":"https://api.github.com/repos/mozilla/dxr/releases{/id}","created_at":"2011-05-24T18:52:38Z","updated_at":"2015-07-29T02:34:05Z","pushed_at":"2015-07-30T16:54:31Z","git_url":"git://github.com/mozilla/dxr.git","ssh_url":"git@github.com:mozilla/dxr.git","clone_url":"https://github.com/mozilla/dxr.git","svn_url":"https://github.com/mozilla/dxr","homepage":"https://dxr.readthedocs.org/","size":15120,"stargazers_count":321,"watchers_count":321,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":133,"mirror_url":null,"open_issues_count":33,"forks":133,"open_issues":33,"watchers":321,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mozilla/dxr/pulls/456"},"html":{"href":"https://github.com/mozilla/dxr/pull/456"},"issue":{"href":"https://api.github.com/repos/mozilla/dxr/issues/456"},"comments":{"href":"https://api.github.com/repos/mozilla/dxr/issues/456/comments"},"review_comments":{"href":"https://api.github.com/repos/mozilla/dxr/pulls/456/comments"},"review_comment":{"href":"https://api.github.com/repos/mozilla/dxr/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mozilla/dxr/pulls/456/commits"},"statuses":{"href":"https://api.github.com/repos/mozilla/dxr/statuses/742a6d9bd407a35907fa60a7efea458eb316b179"}}}}