| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 | #=============================================================================# CMake - Cross Platform Makefile Generator# Copyright 2000-2013 Kitware, Inc., Insight Software Consortium## Distributed under the OSI-approved BSD License (the "License");# see accompanying file Copyright.txt for details.## This software is distributed WITHOUT ANY WARRANTY; without even the# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.# See the License for more information.#=============================================================================import osimport re# Monkey patch for pygments reporting an error when generator expressions are# used.# https://bitbucket.org/birkenfeld/pygments-main/issue/942/cmake-generator-expressions-not-handledfrom pygments.lexers import CMakeLexerfrom pygments.token import Name, Operatorfrom pygments.lexer import bygroupsCMakeLexer.tokens["args"].append(('(\\$<)(.+?)(>)',                                  bygroups(Operator, Name.Variable, Operator)))from docutils.parsers.rst import Directive, directivesfrom docutils.transforms import Transformtry:    from docutils.utils.error_reporting import SafeString, ErrorStringexcept ImportError:    # error_reporting was not in utils before version 0.11:    from docutils.error_reporting import SafeString, ErrorStringfrom docutils import io, nodesfrom sphinx.directives import ObjectDescriptionfrom sphinx.domains import Domain, ObjTypefrom sphinx.roles import XRefRolefrom sphinx.util.nodes import make_refnodefrom sphinx import addnodesclass CMakeModule(Directive):    required_arguments = 1    optional_arguments = 0    final_argument_whitespace = True    option_spec = {'encoding': directives.encoding}    def __init__(self, *args, **keys):        self.re_start = re.compile(r'^#\[(?P<eq>=*)\[\.rst:$')        Directive.__init__(self, *args, **keys)    def run(self):        settings = self.state.document.settings        if not settings.file_insertion_enabled:            raise self.warning('"%s" directive disabled.' % self.name)        env = self.state.document.settings.env        rel_path, path = env.relfn2path(self.arguments[0])        path = os.path.normpath(path)        encoding = self.options.get('encoding', settings.input_encoding)        e_handler = settings.input_encoding_error_handler        try:            settings.record_dependencies.add(path)            f = io.FileInput(source_path=path, encoding=encoding,                             error_handler=e_handler)        except UnicodeEncodeError, error:            raise self.severe('Problems with "%s" directive path:\n'                              'Cannot encode input file path "%s" '                              '(wrong locale?).' %                              (self.name, SafeString(path)))        except IOError, error:            raise self.severe('Problems with "%s" directive path:\n%s.' %                      (self.name, ErrorString(error)))        raw_lines = f.read().splitlines()        f.close()        rst = None        lines = []        for line in raw_lines:            if rst is not None and rst != '#':                # Bracket mode: check for end bracket                pos = line.find(rst)                if pos >= 0:                    if line[0] == '#':                        line = ''                    else:                        line = line[0:pos]                    rst = None            else:                # Line mode: check for .rst start (bracket or line)                m = self.re_start.match(line)                if m:                    rst = ']%s]' % m.group('eq')                    line = ''                elif line == '#.rst:':                    rst = '#'                    line = ''                elif rst == '#':                    if line == '#' or line[:2] == '# ':                        line = line[2:]                    else:                        rst = None                        line = ''                elif rst is None:                    line = ''            lines.append(line)        if rst is not None and rst != '#':            raise self.warning('"%s" found unclosed bracket "#[%s[.rst:" in %s' %                               (self.name, rst[1:-1], path))        self.state_machine.insert_input(lines, path)        return []class _cmake_index_entry:    def __init__(self, desc):        self.desc = desc    def __call__(self, title, targetid):        return ('pair', u'%s ; %s' % (self.desc, title), targetid, 'main')_cmake_index_objs = {    'command':    _cmake_index_entry('command'),    'generator':  _cmake_index_entry('generator'),    'manual':     _cmake_index_entry('manual'),    'module':     _cmake_index_entry('module'),    'policy':     _cmake_index_entry('policy'),    'prop_cache': _cmake_index_entry('cache property'),    'prop_dir':   _cmake_index_entry('directory property'),    'prop_gbl':   _cmake_index_entry('global property'),    'prop_sf':    _cmake_index_entry('source file property'),    'prop_test':  _cmake_index_entry('test property'),    'prop_tgt':   _cmake_index_entry('target property'),    'variable':   _cmake_index_entry('variable'),    }def _cmake_object_inventory(env, document, line, objtype, targetid):    inv = env.domaindata['cmake']['objects']    if targetid in inv:        document.reporter.warning(            'CMake object "%s" also described in "%s".' %            (targetid, env.doc2path(inv[targetid][0])), line=line)    inv[targetid] = (env.docname, objtype)class CMakeTransform(Transform):    # Run this transform early since we insert nodes we want    # treated as if they were written in the documents.    default_priority = 210    def __init__(self, document, startnode):        Transform.__init__(self, document, startnode)        self.titles = {}    def parse_title(self, docname):        """Parse a document title as the first line starting in [A-Za-z0-9<]           or fall back to the document basename if no such line exists.           The cmake --help-*-list commands also depend on this convention.           Return the title or False if the document file does not exist.        """        env = self.document.settings.env        title = self.titles.get(docname)        if title is None:            fname = os.path.join(env.srcdir, docname+'.rst')            try:                f = open(fname, 'r')            except IOError:                title = False            else:                for line in f:                    if len(line) > 0 and (line[0].isalnum() or line[0] == '<'):                        title = line.rstrip()                        break                f.close()                if title is None:                    title = os.path.basename(docname)            self.titles[docname] = title        return title    def apply(self):        env = self.document.settings.env        # Treat some documents as cmake domain objects.        objtype, sep, tail = env.docname.rpartition('/')        make_index_entry = _cmake_index_objs.get(objtype)        if make_index_entry:            title = self.parse_title(env.docname)            # Insert the object link target.            targetid = '%s:%s' % (objtype, title)            targetnode = nodes.target('', '', ids=[targetid])            self.document.insert(0, targetnode)            # Insert the object index entry.            indexnode = addnodes.index()            indexnode['entries'] = [make_index_entry(title, targetid)]            self.document.insert(0, indexnode)            # Add to cmake domain object inventory            _cmake_object_inventory(env, self.document, 1, objtype, targetid)class CMakeObject(ObjectDescription):    def handle_signature(self, sig, signode):        # called from sphinx.directives.ObjectDescription.run()        signode += addnodes.desc_name(sig, sig)        return sig    def add_target_and_index(self, name, sig, signode):        targetid = '%s:%s' % (self.objtype, name)        if targetid not in self.state.document.ids:            signode['names'].append(targetid)            signode['ids'].append(targetid)            signode['first'] = (not self.names)            self.state.document.note_explicit_target(signode)            _cmake_object_inventory(self.env, self.state.document,                                    self.lineno, self.objtype, targetid)        make_index_entry = _cmake_index_objs.get(self.objtype)        if make_index_entry:            self.indexnode['entries'].append(make_index_entry(name, targetid))class CMakeXRefRole(XRefRole):    # See sphinx.util.nodes.explicit_title_re; \x00 escapes '<'.    _re = re.compile(r'^(.+?)(\s*)(?<!\x00)<(.*?)>$', re.DOTALL)    _re_sub = re.compile(r'^([^()\s]+)\s*\(([^()]*)\)$', re.DOTALL)    def __call__(self, typ, rawtext, text, *args, **keys):        # Translate CMake command cross-references of the form:        #  `command_name(SUB_COMMAND)`        # to have an explicit target:        #  `command_name(SUB_COMMAND) <command_name>`        if typ == 'cmake:command':            m = CMakeXRefRole._re_sub.match(text)            if m:                text = '%s <%s>' % (text, m.group(1))        # CMake cross-reference targets frequently contain '<' so escape        # any explicit `<target>` with '<' not preceded by whitespace.        while True:            m = CMakeXRefRole._re.match(text)            if m and len(m.group(2)) == 0:                text = '%s\x00<%s>' % (m.group(1), m.group(3))            else:                break        return XRefRole.__call__(self, typ, rawtext, text, *args, **keys)class CMakeDomain(Domain):    """CMake domain."""    name = 'cmake'    label = 'CMake'    object_types = {        'command':    ObjType('command',    'command'),        'generator':  ObjType('generator',  'generator'),        'variable':   ObjType('variable',   'variable'),        'module':     ObjType('module',     'module'),        'policy':     ObjType('policy',     'policy'),        'prop_cache': ObjType('prop_cache', 'prop_cache'),        'prop_dir':   ObjType('prop_dir',   'prop_dir'),        'prop_gbl':   ObjType('prop_gbl',   'prop_gbl'),        'prop_sf':    ObjType('prop_sf',    'prop_sf'),        'prop_test':  ObjType('prop_test',  'prop_test'),        'prop_tgt':   ObjType('prop_tgt',   'prop_tgt'),        'manual':     ObjType('manual',     'manual'),    }    directives = {        'command':    CMakeObject,        'variable':   CMakeObject,        # Other object types cannot be created except by the CMakeTransform        # 'generator':  CMakeObject,        # 'module':     CMakeObject,        # 'policy':     CMakeObject,        # 'prop_cache': CMakeObject,        # 'prop_dir':   CMakeObject,        # 'prop_gbl':   CMakeObject,        # 'prop_sf':    CMakeObject,        # 'prop_test':  CMakeObject,        # 'prop_tgt':   CMakeObject,        # 'manual':     CMakeObject,    }    roles = {        'command':    CMakeXRefRole(fix_parens = True, lowercase = True),        'generator':  CMakeXRefRole(),        'variable':   CMakeXRefRole(),        'module':     CMakeXRefRole(),        'policy':     CMakeXRefRole(),        'prop_cache': CMakeXRefRole(),        'prop_dir':   CMakeXRefRole(),        'prop_gbl':   CMakeXRefRole(),        'prop_sf':    CMakeXRefRole(),        'prop_test':  CMakeXRefRole(),        'prop_tgt':   CMakeXRefRole(),        'manual':     CMakeXRefRole(),    }    initial_data = {        'objects': {},  # fullname -> docname, objtype    }    def clear_doc(self, docname):        for fullname, (fn, _) in self.data['objects'].items():            if fn == docname:                del self.data['objects'][fullname]    def resolve_xref(self, env, fromdocname, builder,                     typ, target, node, contnode):        targetid = '%s:%s' % (typ, target)        obj = self.data['objects'].get(targetid)        if obj is None:            # TODO: warn somehow?            return None        return make_refnode(builder, fromdocname, obj[0], targetid,                            contnode, target)    def get_objects(self):        for refname, (docname, type) in self.data['objects'].iteritems():            yield (refname, refname, type, docname, refname, 1)def setup(app):    app.add_directive('cmake-module', CMakeModule)    app.add_transform(CMakeTransform)    app.add_domain(CMakeDomain)
 |