Exemplo n.º 1
0
    def compile_gooutline(self, buf):
        go_exe = buf.langintel.get_go_exe(buf.env)
        if not go_exe:
            raise CodeIntelError("Unable to locate go executable")
        if self._gooutline_executable_and_error is None or go_exe != self._gooutline_executable_and_error[0]:
            self._gooutline_executable_and_error = (go_exe, None, "Unknown Error")
            
            import tempfile
            tempdir = tempfile.gettempdir()
            outline_exe = os.path.join(tempdir, "outline")
            if sys.platform.startswith("win"):
                outline_exe += ".exe"

            outline_src = os.path.join(self.golib_dir, "outline.go")
            cmd = [go_exe, "build", outline_src]
            cwd = tempdir
            env = buf.env.get_all_envvars()
            try:
                # Compile the executable.
                p = process.ProcessOpen(cmd, cwd=cwd, env=env, stdin=None)
                output, error = p.communicate()
                if error:
                    log.warn("'%s' stderr: [%s]", cmd, error)
                # Remember the executable.
                self._gooutline_executable_and_error = (go_exe, outline_exe, None)
            except Exception as ex:
                error_message = "Unable to compile 'outline.go'" + str(ex)
                self._gooutline_executable_and_error = (go_exe, None, error_message)
        if self._gooutline_executable_and_error[1]:
            return self._gooutline_executable_and_error[1]
        raise CodeIntelError(self._gooutline_executable_and_error[2])
Exemplo n.º 2
0
    def available_imports(self, buf, trg, ctlr):
        env = buf.env
        go_exe = self.get_go_exe(env)
        if not go_exe:
            raise CodeIntelError("Unable to locate go executable")

        if go_exe not in self._packages_from_exe:
            cmd = [go_exe, 'list', 'std']
            cwd = None
            if buf.path != "<Unsaved>":
                cwd = os.path.dirname(buf.path)
            env_vars = env.get_all_envvars()
            log.debug("running cmd %r", cmd)
            try:
                p = process.ProcessOpen(cmd, cwd=cwd, env=env_vars)
            except OSError as e:
                raise CodeIntelError("Error executing '%s': %s" % (cmd, e))
            output, error = p.communicate()
            if error:
                log.warn("cmd %r error [%s]", cmd, error)
                raise CodeIntelError(error)
            package_names = [x.strip() for x in output.splitlines() if x]
            log.debug("retrieved %d package names", len(package_names))
            self._packages_from_exe[go_exe] = package_names

        stdlib_imports = self._packages_from_exe.get(go_exe, [])
        ctlr.start(buf, trg)
        ctlr.set_cplns([("import", name) for name in stdlib_imports])
        ctlr.done("success")
Exemplo n.º 3
0
def guess_lang_from_path(path):
    lang_from_ext = {
        ".py": "Python",
        ".pl": "Perl",
        ".pm": "Perl",
        ".tcl": "Tcl",
        ".php": "PHP",
        ".inc": "PHP",
        ".rb": "Ruby",
        ".rhtml": "RHTML",
        ".html.erb": "RHTML",
        ".js": "JavaScript",
        ".java": "Java",
        ".css": "CSS",
        ".xul": "XUL",
        ".xbl": "XBL",
        ".html": "HTML",
        ".xml": "XML",
        ".tpl": "Smarty",
        ".django.html": "Django",
        ".mason.html": "Mason",
        ".ttkt.html": "TemplateToolkit",
        ".cxx": "C++",
    }
    idx = 0
    base = basename(path)
    while base.find('.', idx) != -1:
        idx = base.find('.', idx)
        if idx == -1:
            break
        ext = base[idx:]
        if ext in lang_from_ext:
            return lang_from_ext[ext]
        idx += 1
    raise CodeIntelError("couldn't guess lang for `%s'" % path)
Exemplo n.º 4
0
    def do_html(self, subcmd, opts, path):
        """Convert the given path to styled HTML.

        ${cmd_usage}
        ${cmd_option_list}
        
        The generated HTML provides a good tool for seeing how Komodo's
        lexer lexes the given content. This is the same tokenization that
        you get from "buf.accessor.*" methods -- which you can use for
        writing the CILE, trigger handling, and completion evaluation
        for this language.
        
        Use the "-t" and "-e" option to also exercise the current
        trigger handling and completion evaluation (i.e. determining
        the appropriate completions and calltips at a given trigger
        point).
        """
        extra_lang_module_dirs = []
        if koextlib.is_ext_dir() and exists("pylib"):
            sys.path.append(abspath("pylib"))
            extra_lang_module_dirs = [sys.path[-1]]

        mgr = Manager(extra_lang_module_dirs=extra_lang_module_dirs)
        try:
            if opts.browse:
                htmls = []
            buf = mgr.buf_from_path(path, lang=opts.lang)
            html = buf.to_html(True,
                               True,
                               title=path,
                               do_trg=opts.do_trg,
                               do_eval=opts.do_eval)
        finally:
            mgr.finalize()

        if opts.output == '-':
            output_path = None
            output_file = sys.stdout
        else:
            if opts.output:
                output_path = opts.output
            else:
                output_path = path + ".html"
            if exists(output_path):
                os.remove(output_path)
            output_file = open(output_path, 'w')
        if output_file:
            output_file.write(html)
        if output_path:
            output_file.close()

        if opts.browse:
            if not output_path:
                raise CodeIntelError("cannot open in browser if stdout "
                                     "used for output")
            import webbrowser
            url = _url_from_local_path(output_path)
            webbrowser.open_new(url)
Exemplo n.º 5
0
    def lookup_defn(self, buf, trg, ctlr):
        env = buf.env
        godef_path = self._get_gotool('godef', env)
        # We can't store the path and watch prefs because this isn't a
        # true xpcom object.
        if godef_path is None:
            godef_path = 'godef'
        cmd = [
            godef_path, '-i=true', '-t=true',
            '-f=%s' % buf.path,
            '-o=%s' % trg.pos
        ]
        log.debug("running [%s]", cmd)
        p = process.ProcessOpen(cmd, env=buf.env.get_all_envvars())

        output, error = p.communicate(buf.accessor.text)
        if error:
            log.debug("'gocode' stderr: [%s]", error)
            raise CodeIntelError(error)

        lines = output.splitlines()
        log.debug(output)

        defparts = lines[0].rsplit(":", 2)

        if len(defparts) == 2:
            # current file
            path = buf.path
            line = defparts[0]
        else:
            # other file
            path = defparts[0]
            line = defparts[1]
        name, typeDesc = lines[1].split(' ', 1)

        d = Definition(
            "Go",
            path,
            blobname=None,
            lpath=None,
            name=name,
            line=line,
            ilk='function' if typeDesc.startswith('func') else typeDesc,
            citdl=None,
            signature=typeDesc,
            doc='\n'.join(lines[1:]),
        )
        log.debug(d)
        ctlr.start(buf, trg)
        ctlr.set_defns([d])
        ctlr.done("success")
Exemplo n.º 6
0
    def _hit_from_tokens(self,
                         expr,
                         tokens,
                         scoperef,
                         variable=None,
                         defn_only=False):
        args_scoperef = scoperef

        # First part...
        hit, nconsumed = self._hit_from_first_part(tokens,
                                                   scoperef,
                                                   variable=variable,
                                                   defn_only=defn_only)
        if not hit:
            # TODO: Add the fallback Buffer-specific near-by hunt
            #      for a symbol for the first token. See my spiral-bound
            #      book for some notes.
            raise CodeIntelError("could not resolve first part of '%s'" % expr)
        self.debug("_hit_from_citdl: first part: %r -> %r", tokens[:nconsumed],
                   hit)

        # ...the remainder.
        remaining_tokens = tokens[nconsumed:]
        while remaining_tokens:
            elem, scoperef = hit
            self.debug("_hit_from_citdl: resolve %r on %r in %r",
                       remaining_tokens, elem, scoperef)
            if remaining_tokens[0][0] == "(":
                new_hit = self._hit_from_call(elem,
                                              scoperef,
                                              remaining_tokens[0],
                                              args_scoperef,
                                              defn_only=defn_only)
                nconsumed = 1
            else:
                new_hit, nconsumed = self._hit_from_getattr(
                    remaining_tokens, elem, scoperef, defn_only=defn_only)
            remaining_tokens = remaining_tokens[nconsumed:]
            hit = new_hit

        # Resolve any variable type inferences.
        elem, scoperef = hit
        while elem.tag == "variable" and (not defn_only
                                          or "__no_defn__" in elem.get(
                                              "attributes", "").split()):
            elem, scoperef = self._hit_from_variable_type_inference(
                elem, scoperef, defn_only=defn_only)

        self.info("'%s' is %s on %s", expr, elem, scoperef)
        return (elem, scoperef), len(tokens) - len(remaining_tokens)
Exemplo n.º 7
0
    def _hit_from_variable_type_inference(self,
                                          elem,
                                          scoperef,
                                          defn_only=False):
        """Resolve the type inference for 'elem' at 'scoperef'."""
        citdl = elem.get("citdl")
        if not citdl:
            raise CodeIntelError("no type-inference info for %r" % elem)
        self.log("resolve '%s' type inference for %r:", citdl, elem)

        return self._hit_from_type_inference(citdl,
                                             scoperef,
                                             variable=elem,
                                             defn_only=defn_only)
Exemplo n.º 8
0
    def _hit_from_call(self,
                       elem,
                       scoperef,
                       args,
                       args_scoperef,
                       defn_only=False):
        """Resolve the function call inference for 'elem' at 'scoperef'."""
        # This might be a variable, in that case we keep resolving the variable
        # until we get to the final function/class element that is to be called.
        while elem.tag == "variable":
            elem, scoperef = self._hit_from_variable_type_inference(
                elem, scoperef, defn_only=defn_only)

        ilk = elem.get("ilk")
        if ilk == "class":
            # Return the class element.
            self.log("_hit_from_call: resolved to class instance '%s'",
                     elem.get("name"))
            return (ClassInstance(elem), scoperef)

        if ilk == "function":
            citdl = elem.get("returns")
            if citdl:
                self.log("_hit_from_call: function with citdl %r", citdl)
                if citdl.startswith("__arg"):
                    args = args[1:-1].split(",")
                    try:
                        arg = args[int(citdl[5:]) - 1]
                        if not arg.startswith("__arg"):
                            citdl = arg
                            scoperef = args_scoperef
                    except (ValueError, IndexError):
                        pass
                return self._hit_from_type_inference(citdl,
                                                     scoperef,
                                                     defn_only=defn_only)

        raise CodeIntelError("no return type info for %r" % elem)
Exemplo n.º 9
0
    def do_scan(self, subcmd, opts, *path_patterns):
        """Scan and print the CIX for the given path(s).

        ${cmd_usage}
        ${cmd_option_list}
        """
        extra_module_dirs = []
        if koextlib.is_ext_dir() and exists("pylib"):
            sys.path.append(abspath("pylib"))
            extra_module_dirs = [sys.path[-1]]

        mgr = Manager(extra_module_dirs=extra_module_dirs)
        mgr.upgrade()
        mgr.initialize()
        try:
            tree = None
            for path in _paths_from_path_patterns(path_patterns):
                try:
                    lang = opts.lang or guess_lang_from_path(path)
                except CodeIntelError:
                    log.info(
                        "skip `%s': couldn't determine language "
                        "(use --lang option)", path)
                    continue
                buf = mgr.buf_from_path(path, lang=opts.lang)
                if not isinstance(buf, CitadelBuffer):
                    raise CodeIntelError("`%s' (%s) is not a language that "
                                         "uses CIX" % (path, buf.lang))
                buf.scan()  # force a fresh scan
                tree = buf.tree
                for severity, msg in check_tree(tree):
                    dump = {"warning": log.warn, "error": log.error}[severity]
                    dump(msg)
                if opts.pretty_print:
                    tree = pretty_tree_from_tree(tree)
                ET.dump(tree)
        finally:
            mgr.finalize()
Exemplo n.º 10
0
 def _hit_from_require(self,
                       tokens,
                       scoperef,
                       variable=None,
                       defn_only=False):
     # Node.js / CommonJS hack: try to resolve things via require()
     if len(tokens) > 1 and tokens[1][0] == "(":
         if variable is None:
             variable, _ = self._elem_from_scoperef(scoperef)
         requirename = variable.get(
             "required_library_name",
             getattr(self.trg, "required_library_name", None))
         if requirename:
             self.log(
                 "_hit_from_variable_type_inference: resolving require(%r)",
                 requirename)
             module_name = requirename.lstrip("./")
             if len(tokens) > 2:
                 symbol = tokens[2]
                 remaining_tokens = tokens[3:]
                 _nconsumed = 2
             else:
                 symbol = None
                 remaining_tokens = tokens[2:]
                 _nconsumed = 1
             require = FakeImport(variable,
                                  module=requirename,
                                  symbol=symbol,
                                  alias=None)
             hit, nconsumed = self._hit_from_elem_imports(
                 [module_name] + remaining_tokens,
                 require,
                 defn_only=defn_only)
             if hit is not None:
                 return hit, nconsumed + _nconsumed
         raise CodeIntelError("could not resolve require(%r)" % requirename)
     return None, None
Exemplo n.º 11
0
    def do_scan(self, subcmd, opts, *path_patterns):
        """Scan and print the CIX for the given path(s).

        ${cmd_usage}
        ${cmd_option_list}
        """
        import time
        import ciElementTree as ET
        from ci2 import _paths_from_path_patterns
        from codeintel2.manager import Manager
        from codeintel2.citadel import CitadelBuffer
        from codeintel2.common import CodeIntelError
        from codeintel2.tree import pretty_tree_from_tree
        from codeintel2.util import guess_lang_from_path

        mgr = Manager()
        mgr.upgrade()
        mgr.initialize()
        try:
            if opts.time_it:
                start = time.time()
            quiet = opts.quiet
            if opts.time_it or opts.time_details:
                opts.force = True

            scan_count = 0
            lang_warnings = set()
            tree = None
            for path in _paths_from_path_patterns(path_patterns,
                                                  recursive=opts.recursive,
                                                  includes=opts.includes):
                if opts.time_it:
                    sys.stderr.write(path + "\n")
                if opts.time_details:
                    start1 = time.time()

                try:
                    lang = opts.lang or guess_lang_from_path(path)
                except CodeIntelError:
                    self.log.info("skip `%s': couldn't determine language",
                                  path)
                    continue
                try:
                    buf = mgr.buf_from_path(path, lang=lang)
                except OSError as ex:
                    # Couldn't access the file.
                    if not opts.recursive:
                        raise
                    # Ignore files we don't really care about.
                    self.log.warn("%r - %r", ex, path)
                    continue
                if not isinstance(buf, CitadelBuffer):
                    if opts.recursive:
                        # Ignore files that scanning isn't provided for.
                        continue
                    raise CodeIntelError("`%s' (%s) is not a language that "
                                         "uses CIX" % (path, buf.lang))

                scan_count += 1
                if scan_count % 10 == 0:
                    self.log.info("%d scanning %r", scan_count, path)

                try:
                    if opts.force:
                        buf.scan()
                    if tree is None:
                        tree = ET.Element("codeintel", version="2.0")
                    file_elem = ET.SubElement(tree,
                                              "file",
                                              lang=buf.lang,
                                              mtime=str(int(time.time())),
                                              path=os.path.basename(path))
                    for lang, blob in sorted(buf.blob_from_lang.items()):
                        blob = buf.blob_from_lang[lang]
                        file_elem.append(blob)
                except KeyError as ex:
                    # Unknown cile language.
                    if not opts.recursive:
                        raise
                    message = str(ex)
                    if message not in lang_warnings:
                        lang_warnings.add(message)
                        self.log.warn("Skipping unhandled language %s",
                                      message)

                if opts.time_details:
                    delta = time.time() - start1
                    sys.stderr.write("%.3f %s\n" % (delta, path))
                    sys.stderr.flush()

            if tree is not None:
                if opts.stripfuncvars:
                    # For stdlibs, we don't care about variables inside of
                    # functions and they take up a lot of space.
                    for function in tree.getiterator('scope'):
                        if function.get('ilk') == 'function':
                            function[:] = [
                                child for child in function
                                if child.tag != 'variable'
                            ]
                if opts.pretty_print:
                    tree = pretty_tree_from_tree(tree)
                if not quiet:
                    sys.stdout.write(
                        '<?xml version="1.0" encoding="UTF-8"?>\n')
                    ET.dump(tree)
                if opts.time_it:
                    end = time.time()
                    sys.stderr.write("scan took %.3fs\n" % (end - start))
        finally:
            mgr.finalize()
Exemplo n.º 12
0
    def _hit_from_getattr(self,
                          tokens,
                          elem,
                          scoperef,
                          variable=None,
                          defn_only=False):
        """Return a hit for a getattr on the given element.

        Returns (<hit>, <num-tokens-consumed>) or raises an CodeIntelError.

        Typically this just does a getattr of tokens[0], but handling
        some multi-level imports can result in multiple tokens being
        consumed.
        """
        # TODO: On failure, call a hook to make an educated guess. Some
        #      attribute names are strong signals as to the object type
        #      -- typically those for common built-in classes.

        first_token = tokens[0]
        self.log("resolve getattr '%s' on %r in %r:", first_token, elem,
                 scoperef)

        ilk = elem.get("ilk")

        refs = {
            "blob": None,
            "block": None,
            "function": None,
            "class": "classrefs",
            "instance": "classrefs",
            "interface": "interfacerefs"
        }.get(ilk, "objectrefs")

        attr = elem.names.get(first_token)
        if attr is not None and attr is not variable:
            self.log("attr is %r in %r", attr, elem)
            if ilk != "blob":
                # update the scoperef, we are now inside the element.
                scoperef = (scoperef[0], scoperef[1] + [elem.get("name")])
            return (attr, scoperef), 1

        self.debug("look for %r from imports in %r", tokens, elem)
        hit, nconsumed = self._hit_from_elem_imports(tokens,
                                                     elem,
                                                     defn_only=defn_only)
        if hit is not None:
            return hit, nconsumed

        for ref in elem.get(refs, "").split():
            try:
                self.log("is '%s' from base %s: %r?", first_token, ilk
                         or elem.tag, ref)
                hit, nconsumed = self._hit_from_citdl(ref,
                                                      tokens,
                                                      scoperef,
                                                      variable=elem,
                                                      defn_only=defn_only)
                if hit:
                    return hit, nconsumed
            except CodeIntelError as ex:
                self.log("could not resolve ref '%s' on scoperef %r", ref,
                         scoperef)
                # Was not available, try the next object then.

        # If there's a citdl type:
        citdl = elem.get("citdl")
        if citdl:
            hit, nconsumed = self._hit_from_citdl(citdl,
                                                  tokens,
                                                  scoperef,
                                                  variable=elem,
                                                  defn_only=defn_only)
            if hit:
                return hit, nconsumed

        raise CodeIntelError("could not resolve '%s' getattr on %r in %r" %
                             (first_token, elem, scoperef))
Exemplo n.º 13
0
    def do_outline(self, subcmd, opts, path):
        """Scan and outline the structure of the given path.

        ${cmd_usage}
        ${cmd_option_list}
        """
        extra_lang_module_dirs = []
        if koextlib.is_ext_dir() and exists("pylib"):
            sys.path.append(abspath("pylib"))
            extra_lang_module_dirs = [sys.path[-1]]

        mgr = Manager(extra_lang_module_dirs=extra_lang_module_dirs)
        mgr.upgrade()
        mgr.initialize()
        try:
            if '#' in path:
                path, anchor = path.rsplit('#', 1)
            else:
                anchor = None

            tree = None
            try:
                lang = opts.lang or guess_lang_from_path(path)
            except CodeIntelError:
                log.info(
                    "skip `%s': couldn't determine language "
                    "(use --lang option)", path)
                return

            if path.endswith(".cix"):
                tree = tree_from_cix(open(path, 'r').read())
                #buf = mgr.buf_from_content("", tree[0].get("lang"), path=path)
            else:
                buf = mgr.buf_from_path(path, lang=opts.lang)
                if not isinstance(buf, CitadelBuffer):
                    raise CodeIntelError("`%s' (%s) is not a language that "
                                         "uses CIX" % (path, buf.lang))
                tree = buf.tree

            if anchor is not None:
                # Lookup the anchor in the codeintel CIX tree.
                lpath = re.split(r'\.|::', anchor)

                def blobs_from_tree(tree):
                    for file_elem in tree:
                        for blob in file_elem:
                            yield blob

                for elem in blobs_from_tree(tree):
                    # Generally have 3 types of codeintel trees:
                    # 1. single-lang file: one <file>, one <blob>
                    # 2. multi-lang file: one <file>, one or two <blob>'s
                    # 3. CIX stdlib/catalog file: possibly multiple
                    #    <file>'s, likely multiple <blob>'s
                    # Allow the first token to be the blob name or lang.
                    # (This can sometimes be weird, but seems the most
                    # convenient solution.)
                    if lpath[0] in (elem.get("name"), elem.get("lang")):
                        remaining_lpath = lpath[1:]
                    else:
                        remaining_lpath = lpath
                    for name in remaining_lpath:
                        try:
                            elem = elem.names[name]
                        except KeyError:
                            elem = None
                            break  # try next lang blob
                    if elem is not None:
                        break  # found one
                else:
                    log.error(
                        "could not find `%s' definition (or blob) in `%s'",
                        anchor, path)
                    return 1
            else:
                elem = tree

            try:
                _outline_ci_elem(mgr, elem, quiet=opts.quiet)
            except IOError, ex:
                if ex.errno == 0:
                    # Ignore this error from aborting 'less' of this
                    # command:
                    #    IOError: (0, 'Error')
                    pass
                else:
                    raise
        finally:
            mgr.finalize()