Skip to content
benjackson-btcs edited this page Apr 4, 2024 · 29 revisions

I'm only getting [ID] suggestions... Where is printf ?

See the next question

The completions are just words from my buffer, how do I get the right functions listed?

TL;DR: Hit <Ctrl-Space>. See https://github.com/ycm-core/YouCompleteMe#the-gycm_semantic_triggers-option

You are getting "identifier" completions (i.e. just words scanned from files), but you want "semantic" completion based on your code.

YCM only queries the semantic engine after a trigger. Usually, this is a language-specific trigger like abc. in many languages. The trigger here is .. This works well for most things, and the [ID] (identifier - basically words) suggestions fill the gap.

For some languages, like C, there are very many semantic options at the "top" level scope, such as printf etc. For these, you can type <Ctrl-Space> in insert mode to force YCM to request semantic completion from the semantic engine.

To customise the triggers, see https://github.com/ycm-core/YouCompleteMe#the-gycm_semantic_triggers-option.

How do I configure YCM to always use semantic completion?

Here's an example that tells YCM to trigger semantic completion after typing 3 "word" characters or an _ character.

This works well for C and similar languages:

let g:ycm_semantic_triggers =  {
  \   'c,cpp,objc': [ 're!\w{3}', '_' ],
  \ }

To request semantic completion for any word-character in a language, for example, JSON:

let g:ycm_semantic_triggers =  {
  \   'json': [ 're!\w' ],
  \ }

However, this is strongly discouraged.

See :help ycm_semantic_triggers.

I get a weird window at the top of my file when I use the semantic engine

TL;DR: set completeopt+=popup (see :help completeopt), or let g:ycm_add_preview_to_completeopt="popup". This will give you the same information in a popup near the completion menu and will overall improve performance as the information will be obtained on demand.

What you're seeing is Vim's preview window. Vim uses it to show you extra information about something if such information is available. YCM provides Vim with such extra information. For instance, when you select a function in the completion list, the preview window will hold that function's prototype and the prototypes of any overloads of the function. It will stay there after you select the completion so that you can use the information about the parameters and their types to write the function call.

If you would like this window to auto-close after you select a completion string, set the g:ycm_autoclose_preview_window_after_completion option to 1 in your vimrc file. Similarly, the g:ycm_autoclose_preview_window_after_insertion option can be set to close the preview window after leaving insert mode.

If you don't want this window to ever show up, add set completeopt-=preview to your vimrc. Also make sure that the g:ycm_add_preview_to_completeopt option is set to 0.

YCM shows errors on standard includes in cross-compiled C/C++ projects (clangd completer)

This is because clangd doesn't know about your cross-compiler's includes. To solve this specify something like the following:

let g:ycm_clangd_args=['--query-driver=arm-none-eabi-g++']

If the cross-compiler isn't in your $PATH, you'll need to use the full path to the compiler. If it's inconvenient to place this option in your .vimrc, you can also use :h exrc.

I'm using clangd, how can I specify a per-project compilation database path?

Using an extra conf file and passing the compilationDatabasePath option to clangd.

For example, if your compilation database (compile_commands.json) is in a dir like build under your project root, you could put something like this in a .ycm_extra_conf.py file in your project root:

DIR_OF_THIS_SCRIPT = p.abspath( p.dirname( __file__ ) )

def Settings( **kwargs ):
  if language == 'cfamily':
    cmake_commands = os.path.join( DIR_OF_THIS_SCRIPT, 'build', 'compile_commands.json')
    if os.path.exists( cmake_commands ):
      return {
        'ls': {
          'compilationDatabasePath': os.path.dirname( cmake_commands )
        }
      }
  return None

I'm using ccls, how can I specify a per-project compilation database path?

See "I'm using clangd, how can I specify a per-project compilation database path?" and replace compilationDatabasePath with compilationDatabaseDirectory in the python snippet.

I'm using clangd and it is inserting headers that I don't want

clangd/YCM will insert #include directives for you if it can. This is very cool.

However, clangd uses the "Include what you use" style of header insertion by default. This style of explicit inclusion of everything (even when something is provided by a transitive include) is not always to everyone's liking.

If you don't like this behaviour, you can control it by setting the --header-insertion option in g:ycm_clangd_args. For example, to disable it entirely set something like this:

let g:ycm_clangd_args = [ '--header-insertion=never' ]

Adapt this to add it if you already set g:ycmd_clangd_args.

After updating, Python completion no longer works

Sorry about that, it happens when switching Python versions, we think. Solution here: https://github.com/ycm-core/YouCompleteMe/issues/3765#issuecomment-695970983

I get a linker warning regarding libpython on macOS when compiling YCM

If the warning is ld: warning: path '/usr/lib/libpython2.7.dylib' following -L not a directory, then feel free to ignore it; it's caused by a limitation of CMake and is not an issue. Everything should still work fine.

It appears that YCM is not working

First, check this troubleshooting guide.

In Vim, run :messages and carefully read the output. YCM will echo messages to the message log if it encounters problems. It's likely you misconfigured something and YCM is complaining about it.

Also, you may want to run the :YcmDebugInfo command; it will make YCM spew out various debugging information, including the YCM and ycmd logfile paths and the compile flags for the current file if the file is a C-family language file and you have compiled in Clang support. Logfiles can be opened in the editor using the :YcmToggleLogs command.

YCM auto-inserts completion strings I don't want!

This could be some mappings that interfere with YCM's internal ones. Make sure you don't have something mapped to <C-p>, <C-x> or <C-u> (in insert mode).

YCM never selects something for you; it just shows you a menu and the user has to explicitly select something. If something is being selected automatically, this means there's a bug or a misconfiguration somewhere.

I get a E227: mapping already exists for <blah> error when I start Vim

This means that YCM tried to set up a key mapping but failed because you already had something mapped to that key combination. The <blah> part of the message will tell you what was the key combination that failed.

Look in the Options section and see if any of the default mappings conflict with your own. Then change that option value to something else so that the conflict goes away.

I get 'GLIBC_2.XX' not found (required by libclang.so) when starting Vim

Your system is too old for the precompiled binaries from llvm.org. Compile Clang on your machine and then link against the libclang.so you just produced. See the full installation guide for help.

I get LONG_BIT definition appears wrong for platform when compiling

Look at the output of your CMake call. There should be a line in it like the following (with .dylib in place of .so on macOS):

-- Found PythonLibs: /usr/lib/libpython2.7.so (Required is at least version "2.5")

That would be the correct output. An example of incorrect output would be the following:

-- Found PythonLibs: /usr/lib/libpython2.7.so (found suitable version "2.5.1", minimum required is "2.5")

Notice how there's an extra bit of output there, the found suitable version "<version>" part, where <version> is not the same as the version of the dynamic library. In the example shown, the library is version 2.7 but the second string is version 2.5.1.

This means that CMake found one version of Python headers and a different version for the library. This is wrong. It can happen when you have multiple versions of Python installed on your machine.

You should probably add the following flags to your cmake call (again, dylib instead of so on macOS):

-DPYTHON_INCLUDE_DIR=/usr/include/python2.7 -DPYTHON_LIBRARY=/usr/lib/libpython2.7.so

This will force the paths to the Python include directory and the Python library to use. You may need to set these flags to something else, but you need to make sure you use the same version of Python that your Vim binary is built against, which is highly likely to be the system's default Python.

I see undefined symbol: clang_getCompletionFixIt in the server logs.

This means that the server is trying to load a version of libclang that is too old. You need at least libclang 9.0.0. We recommend running the install.py script without --system-libclang or downloading the latest prebuilt binaries from llvm.org when going through the full installation guide.

I get Fatal Python error: PyThreadState_Get: no current thread on startup

This is caused by linking a static version of libpython into ycmd's ycm_core.so. This leads to multiple copies of the Python interpreter loaded when python loads ycmd_core.so and this messes up Python's global state. The details aren't important.

The solution is that the version of Python linked and run against must be built with either --enable-shared or --enable-framework (on OS X). This is achieved as follows (NOTE: for macOS, replace --enable-shared with --enable-framework):

  • When building Python from source: ./configure --enable-shared {options}
  • When building Python from pyenv: PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install {version}

install.py says python must be compiled with --enable-framework. Wat?

See the previous answer for how to ensure your python is built to support dynamic modules.

YCM does not read identifiers from my tags files

First, put let g:ycm_collect_identifiers_from_tags_files = 1 in your vimrc.

Make sure you are using Exuberant Ctags to produce your tags files since the only supported tag format is the Exuberant Ctags format. The format from "plain" ctags is NOT supported. The output of ctags --version should list "Exuberant Ctags". See Universal Ctags for a maintained version.

Ctags needs to be called with the --fields=+l (that's a lowercase L, not a one) option because YCM needs the language:<lang> field in the tags output.

NOTE: Exuberant Ctags by default sets language tag for *.h files as C++. If you have a C (not C++) project, consider giving parameter --langmap=c:.c.h to ctags to see tags from *.h files.

NOTE: macOS comes with "plain" ctags installed by default. brew install ctags will get you the Exuberant Ctags version.

Also, make sure that your Vim tags option is set correctly. See :h 'tags' for details. If you want to see which tag files YCM will read for a given buffer, run :echo tagfiles() with the relevant buffer active. Note that that function will only list tag files that already exist.

CTRL-U in insert mode does not work while the completion menu is visible

YCM uses completefunc completion mode to show suggestions and Vim disables <C-U> in that mode as a "feature." Sadly there's nothing I can do about this.

My CTRL-R mapping does not work while the completion menu is visible

Vim prevents remapping of the <C-R> key in all <C-X> completion modes (except the <C-X><C-N>/<C-X><C-P> mode which operates in the same mode as <C-N>/<C-P>) and YCM uses the <C-X><C-U> (completefunc) mode for completions. This means that adding <C-R> to any of the g:ycm_key_list_* options have no effect. You need to use another key.

YCM conflicts with UltiSnips TAB key usage

YCM comes with support for UltiSnips (snippet suggestions in the popup menu), but you'll have to change the UltiSnips mappings. See :h UltiSnips-triggers in Vim for details. You'll probably want to change some/all of the following options:

g:UltiSnipsExpandTrigger
g:UltiSnipsJumpForwardTrigger
g:UltiSnipsJumpBackwardTrigger

For example, this works well:

" UltiSnips triggering :
"  - ctrl-j to expand
"  - ctrl-j to go to next tabstop
"  - ctrl-k to go to previous tabstop
let g:UltiSnipsExpandTrigger = '<C-j>'
let g:UltiSnipsJumpForwardTrigger = '<C-j>'
let g:UltiSnipsJumpBackwardTrigger = '<C-k>'

Snippets added with :UltiSnipsAddFiletypes do not appear in the popup menu

For efficiency, YCM only fetches UltiSnips snippets in specific scenarios like visiting a buffer or setting its filetype. You can force YCM to retrieve them by manually triggering the FileType autocommand:

:doautocmd FileType

I get an internal compiler error when installing

This can be a problem on virtual servers with limited memory. A possible solution is to add more swap memory. A more practical solution would be to force the build script to run only one compile job at a time. You can do this by setting the YCM_CORES environment variable to 1. Example:

YCM_CORES=1 ./install.py --clang-completer

I get weird errors when I press Ctrl-C in Vim

Never use Ctrl-C in Vim.

Using Ctrl-C to exit insert mode in Vim is a bad idea. The main issue here is that Ctrl-C in Vim doesn't just leave insert mode, it leaves it without triggering InsertLeave autocommands (as per Vim docs). This is a bad idea and is likely to break many other things and not just YCM.

Bottom line, if you use Ctrl-C to exit insert mode in Vim, you're gonna have a bad time.

If pressing <esc> is too annoying (agreed, it is), we suggest mapping it to something more convenient. On a QWERTY keyboard, a good pick for the <esc> map is inoremap jk <Esc>. This is right on the home row, it's an incredibly rare digraph in English and if you ever need to type those two chars in sequence in insert mode, you just type j, then wait 500ms, then type k.

Completion doesn't work with the C++ standard library headers

This is caused by an issue with libclang that only affects some operating systems. Compiling with clang the binary will use the correct default header search paths but compiling with libclang.so (which YCM uses) does not.

macOS is normally affected, but there's a workaround in YCM for that specific OS. If you're not running that OS but still have the same problem, continue reading.

The workaround is to call echo | clang -v -E -x c++ - and look at the paths under the #include <...> search starts here: heading. You should take those paths, prepend -isystem to each individual path and append them all to the list of flags you return from your Settings function in your .ycm_extra_conf.py file.

See issue #303 for details.

When I start Vim I get a runtime error saying R6034 An application has made an attempt to load the C runtime library incorrectly.

CMake and other things seem to screw up the PATH with their own msvcrXX.dll versions. Add the following to the very top of your vimrc to remove these entries from the path.

python << EOF
import os
import re
path = os.environ['PATH'].split(';')

def contains_msvcr_lib(folder):
    try:
        for item in os.listdir(folder):
            if re.match(r'msvcr\d+\.dll', item):
                return True
    except:
        pass
    return False

path = [folder for folder in path if not contains_msvcr_lib(folder)]
os.environ['PATH'] = ';'.join(path)
EOF

On Windows I get E887: Sorry, this command is disabled, the Python's site module could not be loaded

If you are running Vim on Windows with Python 2.7.11, this is likely caused by a bug. Follow this workaround or use a different version (Python 2.7.12 does not suffer from the bug).

I can't complete Python packages in a virtual environment.

This means that the Python used to run Jedi is not the Python of the virtual environment you're in. To resolve this you should create a .ycm_extra_conf.py file at the root of your project that sets the interpreter_path option to the Python of your virtual environment, e.g.

def Settings(**kwargs):
  return {
    'interpreter_path': '/path/to/virtual/env/bin/python'
  }

See the Python Semantic Completion section for more details.

I want to defer the loading of YouCompleteMe until after Vim finishes booting

In recent versions of Vim, you can install YCM in a folder under ~/.vim/pack/*/opt and then load it once the user is idle via an autocommand:

augroup load_ycm
  autocmd!
  autocmd CursorHold, CursorHoldI * :packadd YouCompleteMe
                                \ | autocmd! load_ycm
augroup END

YCM does not shut down when I quit Vim

YCM relies on the VimLeave event to shut down the ycmd server. Some plugins prevent this event from triggering by exiting Vim through an autocommand without using the nested keyword (see :h autocmd-nested). You should identify which plugin is responsible for the issue and report it to the plugin author. Note that when this happens, ycmd will automatically shut itself down after 30 minutes.

YCM does not work with my Anaconda Python setup

Anaconda is often incompatible with the pre-built libclang used by YCM and therefore is not supported. The recommended way to solve this is to run /path/to/real/python3 install.py (for example /usr/bin/python3 install.py).

If you want completion in Anaconda projects, point to the interpreter_path option in your .ycm_extra_conf.py file to the path of your Anaconda Python e.g.

def Settings(**kwargs):
  return {
    'interpreter_path': '/path/to/anaconda/python'
  }

See the Python Semantic Completion section for more details.

TAB is already mapped to trigger completion in the command-line window

Vim automatically maps the key set by the wildchar option, which is TAB by default, to complete commands in the command-line window. If you would prefer using this key to cycle through YCM's suggestions without changing the value of wildchar, add the following to your vimrc:

autocmd CmdwinEnter * inoremap <expr><buffer> <TAB>
      \ pumvisible() ? "\<C-n>" : "\<TAB>"

Go completion: read-only files and directories in third_party/ycmd/third_party/go/pkg

When YCM is installed with --go-completion flag, it invokes go get golang.org/x/tools/gopls@v0.4.2. By default, go get unsets the write bit from every tree element in $GOPATH/pkg. See the details in issue 3721 and ycmd PR 1456.

To avoid it, if you use go version >=1.14, set the GOFLAGS="$GOFLAGS -modcacherw". Here's a snippet for vim-plug:

Plug 'ycm-core/YouCompleteMe', { 'do': 'git submodule update --init --recursive && GOFLAGS=-modcacherw ./install.py --go-completer' }

YCM crashes when using musl

YCM bundles clangd for glibc systems, which gives the following error on musl-based systems:

libclang.so.11: mallinfo: symbol not found

To make YCM work on musl systems, do the following:

  1. Install clangd globally on your system.
  2. rm /path/to/YCM/third_party/ycmd/third_party/clang/lib/libclang*
  3. Add let g:ycm_clangd_binary_path='clangd' to your .vimrc file.
  4. Recompile YCM without --clang-completer.

I get "Unknown compiler - C++17 filesystem library missing" on macOS

This is due to the old version of your macOS. If the system can't be updated for some reason, then homebrew can be used to install the necessary up-to-date build tools:

brew install cmake python llvm

llvm is keg-only, which means it was not symlinked into the homebrew installation directory, because macOS already provides this software and installing another version in parallel can cause all kinds of trouble.

To force llvm symlinks:

brew link -f llvm

Note that homebrew's llvm ships with its own libc++ but use the system's libc++ by default.

To use the bundled libc++ we need to specify the corresponding flags to the linker:

export LDFLAGS="-L$(brew --prefix)/opt/llvm/lib -Wl,-rpath,$(brew --prefix)/opt/llvm/lib"

Then install using the homebrew llvm clang and clang++:

CC=$(brew --prefix)/bin/clang CXX=$(brew --prefix)/bin/clang++ ./install.py --clangd-completer --verbose

I'm using rust with YCM and this causes breaks in incremental builds of my project!

TL;DR - set g:ycm_rust_toolchain_root to point at your rust toolchain, and ensure that it includes a compatible version of rust-analyzer.

The reason for this is... reasons. We're not going to go into them because they are tedious and annoying.

See https://github.com/ycm-core/YouCompleteMe/issues/4012 for some more info.

How do I set java options?

AKA "How do I set the java home directory (i.e. java version) used for gradle?"

The eclipse.jdt.ls project provides the list of options in the form of this page: https://github.com/eclipse-jdtls/eclipse.jdt.ls/wiki/Running-the-JAVA-LS-server-from-the-command-line#initialize-request

Essentially you reverse-engineer that graph of objects into a string like java.import.gradle.java.home and set the values as follows:

def Settings(**kwargs):
    if kwargs['language'] == 'java':
        return {
            'ls': { 'settings': {
                'java.import.gradle.java.home': '/etc/alternatives/java_sdk_11',
            } }
        }

Repeat for any of the other Preferences. The rule is basically that the ls dictionary is merged with the 'initializationOptions', and anything under 'settings' is read either as a dotted name, or as a fully qualified object. settings must be a dict (despite what the documentation says).

So the above is equivalent to:

def Settings(**kwargs):
    if kwargs['language'] == 'java':
        return {
            'ls': { 'settings': {
                'java': { 'import': { 'gradle' { 'java': { 'home': '/etc/alternatives/java_sdk_11' } } } }
            } }
        }

The later is preferred, as that's actually what JDT.LS documents, but the former is a lot easier to write and maintain.

Clone this wiki locally