Adding a .ycm_extra_conf file for webkitGtk
authormrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Dec 2013 08:16:37 +0000 (08:16 +0000)
committermrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Dec 2013 08:16:37 +0000 (08:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=119618

Patch by Martin Robinson  <mrobinson@igalia.com> and Danilo Cesar Lemes de Paula <danilo.cesar@collabora.co.uk> on 2013-12-11
Reviewed by Gustavo Noronha Silva.

Added a YouCompleteMe flag discovery script for Vim and the GTK+ port. The script
read the GTK+ build files to determine dynamically what flags to compile a source
file with. This allows Vim to provide auto-complete for C++/C language. See
https://github.com/Valloric/YouCompleteMe for how to use this file.

.:

* .gitignore: Ignore the YCM symlinks in the tree.

Tools:

* gtk/common.py:
(get_build_path): Added a fatal argument to build_path to avoid crashing YCM on failure.
* gtk/ycm_extra_conf.py: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@160531 268f45cc-cd09-0410-ab3c-d52691b4dbfc

.gitignore
ChangeLog
Tools/ChangeLog
Tools/gtk/common.py
Tools/gtk/ycm_extra_conf.py [new file with mode: 0644]

index f45a975..c5ac0cb 100644 (file)
@@ -117,3 +117,6 @@ tags
 .project
 .cproject
 .settings
+
+# Ignore YouCompleteMe symlinks
+.ycm_extra_conf.py
index 233a90a..ee18db1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2013-12-11  Martin Robinson  <mrobinson@igalia.com> and Danilo Cesar Lemes de Paula  <danilo.cesar@collabora.co.uk>
+
+        Adding a .ycm_extra_conf file for webkitGtk
+        https://bugs.webkit.org/show_bug.cgi?id=119618
+
+        Reviewed by Gustavo Noronha Silva.
+
+        Added a YouCompleteMe flag discovery script for Vim and the GTK+ port. The script
+        read the GTK+ build files to determine dynamically what flags to compile a source
+        file with. This allows Vim to provide auto-complete for C++/C language. See
+        https://github.com/Valloric/YouCompleteMe for how to use this file.
+
+        * .gitignore: Ignore the YCM symlinks in the tree.
+
 2013-12-12  Zan Dobersek  <zdobersek@igalia.com>
 
         Use of ar T option not supported by older binutils
index c7372a7..bd0daed 100644 (file)
@@ -1,3 +1,19 @@
+2013-12-11  Martin Robinson  <mrobinson@igalia.com> and Danilo Cesar Lemes de Paula  <danilo.cesar@collabora.co.uk>
+
+        Adding a .ycm_extra_conf file for webkitGtk
+        https://bugs.webkit.org/show_bug.cgi?id=119618
+
+        Reviewed by Gustavo Noronha Silva.
+
+        Added a YouCompleteMe flag discovery script for Vim and the GTK+ port. The script
+        read the GTK+ build files to determine dynamically what flags to compile a source
+        file with. This allows Vim to provide auto-complete for C++/C language. See
+        https://github.com/Valloric/YouCompleteMe for how to use this file.
+
+        * gtk/common.py:
+        (get_build_path): Added a fatal argument to build_path to avoid crashing YCM on failure.
+        * gtk/ycm_extra_conf.py: Added.
+
 2013-12-12  Tim Horton  <timothy_horton@apple.com>
 
         [wk2] Handle pinch-to-zoom gesture
index 92b6cf8..4255c9b 100644 (file)
@@ -36,7 +36,7 @@ def top_level_path(*args):
     return os.path.join(*((os.path.join(os.path.dirname(__file__), '..', '..'),) + args))
 
 
-def get_build_path(build_types=('Release', 'Debug')):
+def get_build_path(build_types=('Release', 'Debug'), fatal=True):
     global build_dir
     if build_dir:
         return build_dir
@@ -76,7 +76,8 @@ def get_build_path(build_types=('Release', 'Debug')):
         return build_dir
 
     print('Could not determine build directory.')
-    sys.exit(1)
+    if fatal:
+        sys.exit(1)
 
 
 def build_path_for_build_types(build_types, *args):
diff --git a/Tools/gtk/ycm_extra_conf.py b/Tools/gtk/ycm_extra_conf.py
new file mode 100644 (file)
index 0000000..2275917
--- /dev/null
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+# Copyright (C) 2013 Danilo Cesar Lemes de Paula <danilo.eu@gmail.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+import os
+import re
+import subprocess
+import sys
+
+# It's very likely that this script is a symlink somewhere in the WebKit directory,
+# so we try to find the actual script location so that we can locate the tools
+# directory.
+if os.path.islink(__file__):
+    __tools_directory = os.path.dirname(os.readlink(__file__))
+else:
+    __tools_directory = os.path.dirname(__file__)
+sys.path.insert(0, os.path.abspath(__tools_directory))
+import common
+
+MAKE_TRACE_FILE_NAME = "ycm-make-trace"
+FLAGS_PRECEDING_PATHS = ['-isystem', '-I', '-iquote', '--sysroot=']
+
+
+def transform_relative_paths_to_absolute_paths(arguments, build_path):
+    result = []
+
+    make_next_absolute = False
+    for argument in arguments:
+        if make_next_absolute:
+            make_next_absolute = False
+            if not argument.startswith('/'):
+                argument = os.path.join(build_path, argument)
+        elif flag in FLAGS_PRECEDING_PATHS:
+            # Some flags precede the path in the list. For those we make the
+            # next argument absolute.
+            if argument == flag:
+                make_next_absolute = True
+        else:
+            # Some argument contain the flag and the path together. For these
+            # we parse the argument out of the path.
+            for flag in FLAGS_PRECEDING_PATHS:
+                if argument.startswith(flag):
+                    argument = flag + os.path.join(build_path, argument[len(flag):])
+                    break
+
+        result.append(argument)
+    return result
+
+
+def create_make_trace_file(build_path):
+    print "Creating make trace file for YouCompleteMe, might take a few seconds"
+    os.chdir(build_path)
+    subprocess.call("make -n -s > %s" % MAKE_TRACE_FILE_NAME, shell=True)
+
+
+def make_trace_file_up_to_date(build_path):
+    trace_file = os.path.join(build_path, MAKE_TRACE_FILE_NAME)
+    if not os.path.isfile(trace_file):
+        return False
+
+    makefile = os.path.join(build_path, 'GNUmakefile')
+    if os.path.getmtime(trace_file) < os.path.getctime(makefile):
+        return False
+
+    return True
+
+
+def ensure_make_trace_file(build_path):
+    if make_trace_file_up_to_date(build_path):
+        return True
+    create_make_trace_file(build_path)
+    return make_trace_file_up_to_date(build_path)
+
+
+def get_compilation_flags_from_build_commandline(command_line, build_path):
+    flags = re.findall("-[I,D,p,O][\w,\.,/,-]*(?:=\"?\w*\"?)?", command_line)
+    return transform_relative_paths_to_absolute_paths(flags, build_path)
+
+
+def get_compilation_flags_for_file(build_path, filename):
+    trace_file_path = os.path.join(build_path, MAKE_TRACE_FILE_NAME)
+
+    try:
+        trace_file = open(trace_file_path)
+        lines = trace_file.readlines()
+        trace_file.close()
+    except:
+        print "==== Error reading %s file", trace_file_path
+        return []
+
+    basename = os.path.basename(filename)
+    for line in lines:
+        if line.find(basename) != -1 and line.find("CC") != -1 or line.find("CXX") != -1:
+            return get_compilation_flags_from_build_commandline(line, build_path)
+
+    print "Could not find flags for %s" % filename
+    return []
+
+
+def FlagsForFile(filename, **kwargs):
+    """This is the main entry point for YCM. Its interface is fixed.
+
+    Args:
+      filename: (String) Path to source file being edited.
+
+    Returns:
+      (Dictionary)
+        'flags': (List of Strings) Command line flags.
+        'do_cache': (Boolean) True if the result should be cached.
+    """
+
+    result = {'flags': ['-std=c++11', '-x', 'c++'], 'do_cache': True}
+
+    # Headers can't be built, so we get the source file flags instead.
+    if filename.endswith('.h'):
+        filename = filename[:-2] + ".cpp"
+        if not os.path.exists(filename):
+            return result
+
+        # Force config.h file inclusion, for GLib macros.
+        result['flags'].append("-includeconfig.h")
+
+    build_path = common.get_build_path(fatal=False)
+    if not build_path:
+        print "Could not find WebKit build path."
+        return result
+
+    if not ensure_make_trace_file(build_path):
+        print "Could not create make trace file"
+        return result
+
+    result['flags'].extend(get_compilation_flags_for_file(build_path, filename))
+    return result
+
+if __name__ == "__main__":
+    import sys
+    if len(sys.argv) >= 2:
+        print FlagsForFile(sys.argv[1])