PageRenderTime 74ms CodeModel.GetById 28ms app.highlight 41ms RepoModel.GetById 1ms app.codeStats 0ms

/Packages/SublimeCodeIntel/libs/codeintel2/gencix_utils.py

https://bitbucket.org/luobailiang/sublime-config
Python | 364 lines | 316 code | 4 blank | 44 comment | 1 complexity | 91f3a532d5c6548c17c3a47be1f2cc3a MD5 | raw file
  1#!/usr/bin/env python
  2# ***** BEGIN LICENSE BLOCK *****
  3# Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4# 
  5# The contents of this file are subject to the Mozilla Public License
  6# Version 1.1 (the "License"); you may not use this file except in
  7# compliance with the License. You may obtain a copy of the License at
  8# http://www.mozilla.org/MPL/
  9# 
 10# Software distributed under the License is distributed on an "AS IS"
 11# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 12# License for the specific language governing rights and limitations
 13# under the License.
 14# 
 15# The Original Code is Komodo code.
 16# 
 17# The Initial Developer of the Original Code is ActiveState Software Inc.
 18# Portions created by ActiveState Software Inc are Copyright (C) 2000-2007
 19# ActiveState Software Inc. All Rights Reserved.
 20# 
 21# Contributor(s):
 22#   ActiveState Software Inc
 23# 
 24# Alternatively, the contents of this file may be used under the terms of
 25# either the GNU General Public License Version 2 or later (the "GPL"), or
 26# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 27# in which case the provisions of the GPL or the LGPL are applicable instead
 28# of those above. If you wish to allow use of your version of this file only
 29# under the terms of either the GPL or the LGPL, and not to allow others to
 30# use your version of this file under the terms of the MPL, indicate your
 31# decision by deleting the provisions above and replace them with the notice
 32# and other provisions required by the GPL or the LGPL. If you do not delete
 33# the provisions above, a recipient may use your version of this file under
 34# the terms of any one of the MPL, the GPL or the LGPL.
 35# 
 36# ***** END LICENSE BLOCK *****
 37
 38"""Shared CIX tools for Code Intelligence
 39
 40    CIX helpers for codeintel creation. Code Intelligence XML format. See:
 41        http://specs.tl.activestate.com/kd/kd-0100.html#xml-based-import-export-syntax-cix
 42"""
 43
 44import os
 45import sys
 46import re
 47import shutil
 48from cStringIO import StringIO
 49import warnings
 50
 51from ciElementTree import Element, ElementTree, SubElement
 52from codeintel2.util import parseDocSummary
 53
 54# Dictionary of known js types and what they map to
 55known_javascript_types = {
 56    "object":       "Object",
 57    "obj":          "Object",
 58    "function":     "Function",
 59    "array":        "Array",
 60    "string":       "String",
 61    "text":         "String",
 62    "int":          "Number",
 63    "integer":      "Number",
 64    "number":       "Number",
 65    "numeric":      "Number",
 66    "decimal":      "Number",
 67    "short":        "Number",
 68    "unsigned short": "Number",
 69    "long":         "Number",
 70    "unsigned long":"Number",
 71    "float":        "Number",
 72    "bool":         "Boolean",
 73    "boolean":      "Boolean",
 74    "true":         "Boolean",
 75    "false":        "Boolean",
 76    "date":         "Date",
 77    "regexp":       "RegExp",
 78    # Dom elements
 79    "element":      "Element",
 80    "node":         "Node",
 81    "domnode":      "DOMNode",
 82    "domstring":    "DOMString",
 83    "widget":       "Widget",
 84    "domwidget":    "DOMWidget",
 85    "htmlelement":  "HTMLElement",
 86    "xmldocument":  "XMLDocument",
 87    "htmldocument": "HTMLDocument",
 88    # Special
 89    "xmlhttprequest": "XMLHttpRequest",
 90    "void":          "",
 91    # Mozilla special
 92    "UTF8String":    "String",
 93    "AString":       "String",
 94}
 95
 96def standardizeJSType(vartype):
 97    """Return a standardized name for the given type if it is a known type.
 98
 99    Example1: given vartype of "int", returns "Number"
100    Example2: given vartype of "YAHOO.tool", returns "YAHOO.tool"
101    """
102
103    if vartype:
104        typename = known_javascript_types.get(vartype.lower(), None)
105        if typename is None:
106            #print "Unknown type: %s" % (vartype)
107            return vartype
108        return typename
109
110spacere = re.compile(r'\s+')
111def condenseSpaces(s):
112    """Remove any line enedings and condense multiple spaces"""
113
114    s = s.replace("\n", " ")
115    s = spacere.sub(' ', s)
116    return s.strip()
117
118def remove_directory(dirpath):
119    """ Recursively remove the directory path given """
120
121    if os.path.exists(dirpath):
122        shutil.rmtree(dirpath, ignore_errors=True)
123
124def getText(elem):
125    """Return the internal text for the given ElementTree node"""
126
127    l = []
128    for element in elem.getiterator():
129        if element.text:
130            l.append(element.text)
131        if element.tail:
132            l.append(element.tail)
133    return " ".join(l)
134
135def getAllTextFromSubElements(elem, subelementname):
136    descnodes = elem.findall(subelementname)
137    if len(descnodes) == 1:
138        return getText(descnodes[0])
139    return None
140
141_invalid_char_re = re.compile(u'[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD]')
142def strip_invalid_xml_chars(s):
143    """Return the string with any invalid XML characters removed.
144
145    The valid characters are listed here:
146        http://www.w3.org/TR/REC-xml/#charsets
147        #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
148    """
149    return _invalid_char_re.sub("", s)
150
151def setCixDoc(cixelement, doctext, parse=False):
152    if parse:
153        doclines = parseDocSummary(doctext.splitlines(0))
154        doctext = "\n".join(doclines)
155    elif sys.platform.startswith("win"):
156        doctext = doctext.replace("\r\n", "\n")
157    #TODO: By default clip doc content down to a smaller set -- just
158    #      enough for a good calltip. By then also want an option to
159    #      *not* clip, for use in documentation generation.
160    #if len(doctext) > 1000:
161    #    warnings.warn("doctext for cixelement: %r has length: %d" % (
162    #                    cixelement.get("name"), len(doctext)))
163    cixelement.attrib["doc"] = strip_invalid_xml_chars(doctext)
164
165def setCixDocFromNodeChildren(cixelement, node, childnodename):
166    doctext = getAllTextFromSubElements(node, childnodename)
167    if doctext:
168        setCixDoc(cixelement, condenseSpaces(doctext), parse=True)
169
170def addCixArgument(cixelement, argname, argtype=None, doc=None):
171    cixarg = SubElement(cixelement, "variable", ilk="argument", name=argname)
172    if argtype:
173        addCixType(cixarg, argtype)
174    if doc:
175        setCixDoc(cixarg, doc)
176    return cixarg
177
178def addCixReturns(cixelement, returntype=None):
179    if returntype and returntype != "void":
180        cixelement.attrib["returns"] = returntype
181
182def addCixType(cixobject, vartype):
183    if vartype:
184        cixobject.attrib["citdl"] = vartype
185
186def addCixAttribute(cixobject, attribute):
187    attrs = cixobject.get("attributes")
188    if attrs:
189        sp = attrs.split()
190        if attribute not in sp:
191            attrs = "%s %s" % (attrs, attribute)
192    else:
193        attrs = attribute
194    cixobject.attrib["attributes"] = attrs
195
196def addClassRef(cixclass, name):
197    refs = cixclass.get("classrefs", None)
198    if refs:
199        if name not in refs.split(" "):
200            cixclass.attrib["classrefs"] = "%s %s" % (refs, name)
201    else:
202        cixclass.attrib["classrefs"] = "%s" % (name)
203
204def addInterfaceRef(cixinterface, name):
205    refs = cixinterface.get("interfacerefs", None)
206    if refs:
207        if name not in refs.split(" "):
208            cixinterface.attrib["interfacerefs"] = "%s %s" % (refs, name)
209    else:
210        cixinterface.attrib["interfacerefs"] = "%s" % (name)
211
212def setCixSignature(cixelement, signature):
213    cixelement.attrib["signature"] = signature
214
215def createCixVariable(cixobject, name, vartype=None, attributes=None):
216    if attributes:
217        v = SubElement(cixobject, "variable", name=name,
218                       attributes=attributes)
219    else:
220        v = SubElement(cixobject, "variable", name=name)
221    if vartype:
222        addCixType(v, vartype)
223    return v
224
225def createCixFunction(cixmodule, name, attributes=None):
226    if attributes:
227        return SubElement(cixmodule, "scope", ilk="function", name=name,
228                          attributes=attributes)
229    else:
230        return SubElement(cixmodule, "scope", ilk="function", name=name)
231
232def createCixInterface(cixmodule, name):
233    return SubElement(cixmodule, "scope", ilk="interface", name=name)
234
235def createCixClass(cixmodule, name):
236    return SubElement(cixmodule, "scope", ilk="class", name=name)
237
238def createCixNamespace(cixmodule, name):
239    return SubElement(cixmodule, "scope", ilk="namespace", name=name)
240
241def createCixModule(cixfile, name, lang, src=None):
242    if src is None:
243        return SubElement(cixfile, "scope", ilk="blob", name=name, lang=lang)
244    else:
245        return SubElement(cixfile, "scope", ilk="blob", name=name, lang=lang, src=src)
246
247def createOrFindCixModule(cixfile, name, lang, src=None):
248    for module in cixfile.findall("./scope"):
249        if module.get("ilk") == "blob" and module.get("name") == name and \
250           module.get("lang") == lang:
251            return module
252    return createCixModule(cixfile, name, lang, src)
253
254def createCixFile(cix, path, lang="JavaScript", mtime="1102379523"):
255    return SubElement(cix, "file",
256                        lang=lang,
257                        #mtime=mtime,
258                        path=path)
259
260def createCixRoot(version="2.0", name=None, description=None):
261    cixroot = Element("codeintel", version=version)
262    if name is not None:
263        cixroot.attrib["name"] = name
264    if description is not None:
265        cixroot.attrib["description"] = description
266    return cixroot
267
268# Add .text and .tail values to make the CIX output pretty. (Only have
269# to avoid "doc" tags: they are the only ones with text content.)
270def prettify(elem, level=0, indent='  ', youngestsibling=0):
271    if elem and elem.tag != "doc":
272        elem.text = '\n' + (indent*(level+1))
273    for i in range(len(elem)):
274        prettify(elem[i], level+1, indent, i==len(elem)-1)
275    elem.tail = '\n' + (indent*(level-youngestsibling))
276
277def get_cix_string(cix, prettyFormat=True):
278    # Get the CIX.
279    if prettyFormat:
280        prettify(cix)
281    cixstream = StringIO()
282    cixtree = ElementTree(cix)
283    cixstream.write('<?xml version="1.0" encoding="UTF-8"?>\n')
284    cixtree.write(cixstream)
285    cixcontent = cixstream.getvalue()
286    cixstream.close()
287    return cixcontent
288
289def outline_ci_elem(elem, _lvl=0, brief=False, doSort=False, includeLineNos=False):
290    """Return an outline of the given codeintel tree element."""
291    indent = '  '
292    result = []
293
294    def _dump(s):
295        if includeLineNos:
296            startline = elem.get("line")
297            lineend = elem.get("lineend")
298            line_str = ""
299            if startline or lineend:
300                line_str = " (%r-%r)" % (startline, lineend)
301            result.append(indent*_lvl + s + line_str + '\n')
302        else:
303            result.append(indent*_lvl + s + '\n')
304
305    if elem.tag == "codeintel":
306        _lvl -= 1 # don't count this one
307    elif brief:
308        name = elem.get("name")
309        if name:
310            _dump(name)
311    elif elem.tag == "file":
312        lang = elem.get("lang")
313        _dump("file %(path)s [%(lang)s]" % elem.attrib)
314    elif elem.tag == "variable":
315        if elem.get("ilk") == "argument":
316            s = "arg "+elem.get("name") # skip?
317        else:
318            s = "var "+elem.get("name")
319        if elem.get("citdl"):
320            s += " [%s]" % elem.get("citdl")
321        _dump(s)
322    elif elem.tag == "scope" and elem.get("ilk") == "function" \
323         and elem.get("signature"):
324        _dump("function %s" % elem.get("signature").split('\n')[0])
325    elif elem.tag == "scope" and elem.get("ilk") == "blob":
326        lang = elem.get("lang")
327        _dump("blob %(name)s [%(lang)s]" % elem.attrib)
328    elif elem.tag == "scope" and elem.get("ilk") == "class" \
329         and elem.get("classrefs"):
330        _dump("%s %s(%s)" % (elem.get("ilk"), elem.get("name"),
331                             ', '.join(elem.get("classrefs").split())))
332    elif elem.tag == "scope":
333        _dump("%s %s" % (elem.get("ilk"), elem.get("name")))
334    elif elem.tag == "import":
335        module = elem.get("module")
336        symbol = elem.get("symbol")
337        alias = elem.get("alias")
338        value = "import '%s" % (module, )
339        if symbol:
340            value += ".%s" % (symbol, )
341        value += "'"
342        if alias:
343            value +" as %r" % (alias, )
344        _dump(value)
345    else:
346        raise ValueError("unknown tag: %r (%r)" % (elem.tag, elem))
347
348    if doSort and hasattr(elem, "names") and elem.names:
349        for name in sorted(elem.names.keys()):
350            child = elem.names[name]
351            result.append(outline_ci_elem(child, _lvl=_lvl+1,
352                                          brief=brief, doSort=doSort,
353                                          includeLineNos=includeLineNos))
354    else:
355        for child in elem:
356            result.append(outline_ci_elem(child, _lvl=_lvl+1,
357                                          brief=brief, doSort=doSort,
358                                          includeLineNos=includeLineNos))
359    return "".join(result)
360
361def remove_cix_line_numbers_from_tree(tree):
362    for node in tree.getiterator():
363        node.attrib.pop("line", None)
364        node.attrib.pop("lineend", None)