diff --git a/README.md b/README.md index 26924322..f537af95 100644 --- a/README.md +++ b/README.md @@ -314,11 +314,10 @@ or in any directory above it in the hierarchy (recursively); when the file is found, it is loaded (only once!) as a Python module. YCM calls a `FlagsForFile` method in that module which should provide it with the information necessary to compile the current file. (You can also provide a path to a global -`.ycm_extra_conf.py` file, which will be used as a fallback. See the Options -section for more details.) -To prevent the execution of malicious code from a file you didn't write -YCM will ask once per module if it is safe to be loaded. -(This can be disabled. See the Options section.) +`.ycm_extra_conf.py` file, which will be used as a fallback.) +To prevent the execution of malicious code from a file you didn't write YCM +will ask once per module if it is safe to be loaded. This can be disabled and +you can white-/blacklist files. See the Options section for more details. This system was designed this way so that the user can perform any arbitrary @@ -665,6 +664,38 @@ Default: `1` let g:ycm_confirm_extra_conf = 1 +### The `g:ycm_extra_conf_globlist` option + +This option is a list that may contain several globbing patterns. If a pattern +starts with a `!` all `.ycm_extra_conf.py` files matching that pattern will be +blacklisted, that is they won't be loaded and no confirmation dialog will be +shown. If a pattern does not start with a `!` all files matching that pattern +will be whitelisted. Note that this option is not used when confirmation is +disabled using `g:ycm_confirm_extra_conf` and that items earlier in the list +will take precedence over the later ones. + +Rules: + +* `*` matches everything +* `?` matches any single character +* `[seq]` matches any character in seq +* `[!seq]` matches any char not in seq + +Example: + + let g:ycm_extra_conf_globlist = ['~/dev/*','!~/*'] + +* The first rule will match everything contained in the `~/dev` directory so + `.ycm_extra_conf.py` files from there will be loaded. +* The second rule will match everything in the home directory so a + `.ycm_extra_conf.py` file from there won't be loaded. +* As the first rule takes precedence everything in the home directory excluding + the `~/dev` directory will be blacklisted. + +Default: `[]` + + let g:ycm_extra_conf_globlist = [] + ### The `g:ycm_semantic_triggers` option This option controls the character-based triggers for the various semantic diff --git a/plugin/youcompleteme.vim b/plugin/youcompleteme.vim index 1624aabd..292304ef 100644 --- a/plugin/youcompleteme.vim +++ b/plugin/youcompleteme.vim @@ -106,6 +106,9 @@ let g:ycm_global_ycm_extra_conf = let g:ycm_confirm_extra_conf = \ get( g:, 'ycm_confirm_extra_conf', 1 ) +let g:ycm_extra_conf_globlist = + \ get( g:, 'ycm_extra_conf_globlist', [] ) + let g:ycm_semantic_triggers = \ get( g:, 'ycm_semantic_triggers', { \ 'c' : ['->', '.'], diff --git a/python/completers/cpp/flags.py b/python/completers/cpp/flags.py index 7bec7ee3..be92e4ca 100644 --- a/python/completers/cpp/flags.py +++ b/python/completers/cpp/flags.py @@ -24,6 +24,7 @@ import random import string import sys import vimsupport +from fnmatch import fnmatch YCM_EXTRA_CONF_FILENAME = '.ycm_extra_conf.py' NO_EXTRA_CONF_FILENAME_MESSAGE = ('No {0} file detected, so no compile flags ' @@ -108,15 +109,24 @@ class FlagsModules( object ): @staticmethod def ShouldLoad( module_file ): - """Checks if a module is safe to be loaded. - By default this will ask the user for confirmation.""" - if module_file == GLOBAL_YCM_EXTRA_CONF_FILE: + """Checks if a module is safe to be loaded. By default this will try to + decide using a white-/blacklist and ask the user for confirmation as a + fallback.""" + + if ( module_file == GLOBAL_YCM_EXTRA_CONF_FILE or + not vimsupport.GetBoolValue( 'g:ycm_confirm_extra_conf' ) ): return True - if ( vimsupport.GetBoolValue( 'g:ycm_confirm_extra_conf' ) and - not vimsupport.Confirm( - CONFIRM_CONF_FILE_MESSAGE.format( module_file ) ) ): + + globlist = vimsupport.GetVariableValue( 'g:ycm_extra_conf_globlist' ) + for glob in globlist: + is_blacklisted = glob[0] == '!' + if MatchesGlobPattern( module_file, glob.lstrip('!') ): + return not is_blacklisted + + if vimsupport.Confirm( CONFIRM_CONF_FILE_MESSAGE.format( module_file ) ): + return True + else: return False - return True def Load( self, module_file, force = False ): """Load and return the module contained in a file. @@ -211,3 +221,12 @@ def _SpecialClangIncludes(): def _DirectoryOfThisScript(): return os.path.dirname( os.path.abspath( __file__ ) ) + + +def MatchesGlobPattern( filename, glob ): + """Returns true if a filename matches a given pattern. A '~' in glob will be + expanded to the home directory and checking will be performed using absolute + paths. See the documentation of fnmatch for the supported patterns.""" + + abspath = os.path.abspath( filename ) + return fnmatch( abspath, os.path.abspath( os.path.expanduser( glob ) ) )