diff --git a/utils/YouCompleteMe.py b/utils/YouCompleteMe.py
new file mode 100644
index 00000000000..f51000f34f0
--- /dev/null
+++ b/utils/YouCompleteMe.py
@@ -0,0 +1,180 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2015 Universite Pierre et marie Curie (UPMC)
+#
+# You should have received a copy of the GNU General Public License
+# along with ns3. If not, see .
+#
+# Author: Matthieu Coudron
+#
+
+import os
+import ycm_core
+import logging
+import subprocess
+
+# This script allows to use YouCompleteMe to provide completion in (neo)vim for the ns3
+# source files.
+# To enable it, hard symlink (symbolic won't work) or copy this file into the ns3 root folder and rename it to
+# .ycm_extra_conf.py
+# The script needs ns3 to be compiled with clang, in order to produce
+# the "build/compile_commands.json"
+# The script should work out of the box, otherwise try changing the
+# compilation_database_folder variable
+
+def DirectoryOfThisScript():
+ return os.path.dirname( os.path.abspath( __file__ ) )
+
+# Set this to the absolute path to the folder (NOT the file!) containing the
+# compile_commands.json file to use that instead of 'flags'. See here for
+# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
+compilation_database_folder = os.path.join(DirectoryOfThisScript(),'build/')
+
+# uncomment the file handler a few lines below to create the logfile
+LOG_FILENAME = '/tmp/ns_ycm.log'
+
+
+# Set up a specific logger with our desired output level
+log = logging.getLogger(__name__)
+log.setLevel(logging.DEBUG)
+
+# Add the log message handler to the logger
+handler = logging.FileHandler(LOG_FILENAME)
+log.addHandler(handler)
+
+
+def GetClangStandardHeaders():
+ """
+ Without this, YCM triggers errors on standards files etc...
+ It parses the output of
+ """
+ system_flags = []
+# https://github.com/Valloric/YouCompleteMe/issues/1478
+# echo | clang -stdlib=libc++ -v -E -x c++ -
+ cmd = "echo | clang -stdlib=libc++ -v -E -x c++ -- "
+ cmd += "|sed -n '/#include <...> search starts here/,/End of search list/{//!p}'"
+ log.info("Running command:\n%s" % cmd)
+ res = subprocess.check_output(cmd, shell=True)
+ log.debug("Result:\n%s" % res)
+ res = res.decode()
+ system_headers = res.splitlines()
+
+ for include in system_headers:
+ system_flags.append('-isystem')
+ log.info("Appends include: %s" % include)
+ system_flags.append(include.strip())
+
+ return system_flags
+
+
+if os.path.exists( compilation_database_folder ):
+ log.info("Loading database")
+ database = ycm_core.CompilationDatabase( compilation_database_folder )
+ log.info("database should be loaded: %r" % database)
+else:
+ database = None
+
+SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
+
+
+
+def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
+ log.info("Make flags absolute with directory [%s]" % working_directory)
+ if not working_directory:
+ return list( flags )
+ new_flags = []
+ make_next_absolute = False
+ path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
+ for flag in flags:
+ new_flag = flag
+
+ if make_next_absolute:
+ make_next_absolute = False
+ if not flag.startswith( '/' ):
+ new_flag = os.path.join( working_directory, flag )
+
+ for path_flag in path_flags:
+ if flag == path_flag:
+ make_next_absolute = True
+ break
+
+ if flag.startswith( path_flag ):
+ path = flag[ len( path_flag ): ]
+ new_flag = path_flag + os.path.join( working_directory, path )
+ break
+
+ if new_flag:
+ new_flags.append( new_flag )
+ return new_flags
+
+
+def IsHeaderFile( filename ):
+ extension = os.path.splitext( filename )[ 1 ]
+ return extension in [ '.h', '.hxx', '.hpp', '.hh' ]
+
+
+
+def MatchHeaderToSource( filename ):
+ """
+ NS3 headers are copied into a specific folder thus stock
+ YCM functions don't fit the bill
+ Return the .cc associated with the .h
+ """
+ log.debug("MatchHeaderToSource: %s" % filename)
+ filename = os.path.basename(filename)
+ filename = os.path.splitext( filename )[ 0 ]
+ filename += ".cc"
+ log.debug("Looking for implementation of %s" % filename)
+ # be careful it is the python 2.7 version and as such does not return bytes
+ try:
+ match = subprocess.check_output("find src -name %s" % (filename), shell=True)
+ match=match.strip()
+ except Exception as e:
+ log.error("Could not map header to implementation: %s:" % e)
+
+ match = os.path.abspath(match)
+ return match
+
+
+def GetCompilationInfoForFile( filename ):
+ # The compilation_commands.json file generated by waf does not have entries
+ # for header files. So we do our best by asking the db for flags for a
+ # corresponding source file, if any. If one exists, the flags for that file
+ # should be good enough.
+ log.debug("GetCompilationInfoForFile called with parameter=%s" % filename)
+ final_name = filename
+ if IsHeaderFile( filename ):
+ final_name = MatchHeaderToSource( filename)
+
+ log.info("compilation_info for =%s" % final_name)
+
+ return database.GetCompilationInfoForFile( final_name )
+
+
+# This is the entry point; this function is called by ycmd to produce flags for
+# a file.
+def FlagsForFile( filename, **kwargs ):
+ log.debug("== Getting flags for file %s" % filename)
+ if database:
+ # Bear in mind that compilation_info.compiler_flags_ does NOT return a
+ # python list, but a "list-like" StringVec object
+ compilation_info = GetCompilationInfoForFile( filename )
+ if not compilation_info:
+ log.warn("Could not find info for this one")
+ return None
+
+ log.debug(" flags before being made relative %s" % compilation_info.compiler_flags_)
+
+ # this should not be necessary, I leave it just in case
+ flags = MakeRelativePathsInFlagsAbsolute(
+ compilation_info.compiler_flags_,
+ compilation_info.compiler_working_dir_ )
+
+ flags += GetClangStandardHeaders();
+
+ log.debug("Open filename '%s': found flags=%s\n" % (filename, flags))
+ return {
+ 'flags': flags,
+ 'do_cache': True
+ }
+