diff scripts/ycm_extra_conf.py @ 0:5d2c0db51914

Initial commit
author Ludovic Chabant <ludovic@chabant.com>
date Tue, 17 Sep 2019 13:24:24 -0700
parents
children f444739dd8af
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/ycm_extra_conf.py	Tue Sep 17 13:24:24 2019 -0700
@@ -0,0 +1,215 @@
+import argparse
+import logging
+import os.path
+import sys
+
+
+if True: # 'vim' in sys.modules:
+    sys.path.append(os.path.dirname(__file__))
+
+
+from logutil import setup_logging
+from vsutil import SolutionCache
+
+
+logger = logging.getLogger(__name__)
+
+
+def _build_cflags(filename, solution, buildenv=None, slncache=None):
+    # Load the solution.
+    if not solution:
+        raise Exception(
+            "No solution path was provided in the client data!")
+
+    cache, loaded = SolutionCache.load_or_rebuild(solution, slncache)
+    if not loaded:
+        cache.build_cache()
+
+    # Find the current file in the solution.
+    filename_lower = filename.lower()
+    projpath = None
+    for pp, pi in cache.index.items():
+        if filename_lower in pi:
+            projpath = pp
+            break
+    else:
+        raise Exception("File doesn't belong to the solution: %s" % filename)
+
+    # Find the project that our file belongs to.
+    proj = cache.slnobj.find_project_by_path(projpath)
+    if not proj:
+        raise Exception("Can't find project in solution: %s" % projpath)
+    logger.debug("Found project %s: %s" % (proj.name, proj.abspath))
+
+    # Get the provided config/platform combo, which represent a solution
+    # configuration, and find the corresponding project configuration.
+    # For instance, a solution configuration of "Debug|Win64" could map
+    # to a "MyDebug|AnyCPU" configuration on a specific project.
+    sln_config_platform = '%s|%s' % (buildenv['Configuration'],
+                                     buildenv['Platform'])
+    proj_config_platform = cache.slnobj.find_project_configuration(
+        proj.guid, sln_config_platform)
+    if not proj_config_platform:
+        raise Exception("Can't find project configuration and platform for "
+                        "solution configuration and platform: %s" %
+                        sln_config_platform)
+
+    # Make a build environment for the project, and figure out what
+    # kind of project it is.
+    proj_config, proj_platform = proj_config_platform.split('|')
+
+    proj_buildenv = buildenv.copy()
+    proj_buildenv['Configuration'] = proj_config
+    proj_buildenv['Platform'] = proj_platform
+
+    cfggroup = proj.propertygroup('Configuration', proj_buildenv)
+    cfgtype = cfggroup.get('ConfigurationType')
+    if not cfgtype:
+        raise Exception("Can't find configuration type. Did you specify a "
+                        "configuration name and platform? Got: %s" %
+                        proj_buildenv)
+    logger.debug("Found configuration type: %s" % cfgtype)
+
+    # Let's prepare a list of standard stuff for C++.
+    preproc = []
+    incpaths = []
+    projdir = os.path.dirname(proj.abspath)
+
+    if cfgtype == 'Makefile':
+        # It's a 'Makefile' project, which means we know as little about
+        # compiler flags as whatever information was given to VS. As
+        # such, if the solution setup doesn't give enough info, VS
+        # intellisense won't work, and neither will YouCompleteMe.
+        defaultpropgroup = proj.defaultpropertygroup(proj_buildenv)
+
+        nmake_preproc = defaultpropgroup.get('NMakePreprocessorDefinitions')
+        preproc += nmake_preproc.strip(';').split(';')
+
+        nmake_incpaths = defaultpropgroup.get('NMakeIncludeSearchPath')
+        incpaths += [os.path.abspath(os.path.join(projdir, p))
+                     for p in nmake_incpaths.strip(';').split(';')]
+
+    else:
+        # We should definitely support standard VC++ projects here but
+        # I don't need it yet :)
+        raise Exception("Don't know how to handle configuration type: %s" %
+                        cfgtype)
+
+    # Build the clang/YCM flags with what we found.
+    flags = ['-x', 'c++']  # TODO: check language type from project file.
+
+    for symbol in preproc:
+        flags.append('-D%s' % symbol)
+    for path in incpaths:
+        if path.startswith("C:\\Program Files"):
+            flags.append('-isystem')
+        else:
+            flags.append('-I')
+        flags.append(path)
+
+    return {'flags': flags}
+
+
+def _build_env_from_vim(client_data):
+    buildenv = {}
+    buildenv['Configuration'] = client_data.get('g:vimcrosoft_current_config', '')
+    buildenv['Platform'] = client_data.get('g:vimcrosoft_current_platform', '')
+    return buildenv
+
+
+def Settings(**kwargs):
+    language = kwargs.get('language')
+    filename = kwargs.get('filename')
+
+    client_data = kwargs.get('client_data', {})
+    from_cli = kwargs.get('from_cli', False)
+    if from_cli:
+        solution = client_data.get('solution')
+        slncache = client_data.get('slncache')
+        buildenv = client_data.get('env', {})
+    else:
+        solution = client_data.get('g:vimcrosoft_current_sln')
+        slncache = client_data.get('g:vimcrosoft_current_sln_cache')
+        buildenv = _build_env_from_vim(client_data)
+
+    flags = None
+
+    if language == 'cfamily':
+        try:
+            flags = _build_cflags(filename, solution,
+                                  buildenv=buildenv, slncache=slncache)
+        except Exception as exc:
+            if from_cli:
+                raise
+            flags = {'error': str(exc)}
+    else:
+        flags = {'error': f"Unknown language: {language}"}
+
+    with open("D:\\P4\\DevEditor\\debug.txt", 'w') as fp:
+        fp.write("kwargs:")
+        fp.write(str(kwargs))
+        fp.write("client_data:")
+        fp.write(str(list(kwargs['client_data'].items())))
+        fp.write("flags:")
+        fp.write(str(flags))
+    return flags
+
+
+languages = {
+    'cfamily': ['h', 'c', 'hpp', 'cpp', 'inl']
+}
+
+
+def _get_language(filename):
+    _, ext = os.path.splitext(filename)
+    ext = ext.lstrip('.')
+    for lang, exts in languages.items():
+        if ext in exts:
+            return lang
+    return None
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('solution',
+                        help="The solution file")
+    parser.add_argument('filename',
+                        help="The filename for which to get flags")
+    parser.add_argument('-p', '--property',
+                        action="append",
+                        help="Specifies a build property")
+    parser.add_argument('-c', '--cache',
+                        help="The solution cache to use")
+    parser.add_argument('-v', '--verbose',
+                        action='store_true',
+                        help="Show debugging information")
+    args = parser.parse_args()
+    setup_logging(args.verbose)
+
+    lang = _get_language(args.filename)
+    logger.debug(f"Got language {lang} for {args.filename}")
+
+    build_env = {}
+    if args.property:
+        for p in args.property:
+            pname, pval = p.split('=', 1)
+            build_env[pname] = pval
+    logger.debug(f"Got build environment: {build_env}")
+    client_data = {'solution': args.solution,
+                   'slncache': args.cache,
+                   'env': build_env}
+
+    params = {'from_cli': True,
+              'language': lang,
+              'filename': args.filename,
+              'client_data': client_data
+              }
+    flags = Settings(**params)
+    logger.info("Flags:")
+    import pprint
+    pp = pprint.PrettyPrinter(indent=2)
+    pp.pprint(flags)
+
+
+if __name__ == '__main__':
+    main()