An example of running a containerised ycmd to:
- obviate the need to build
ycm_core.so. - capture completion suggestions for libraries that may not be present on the
user's system when using
YouCompleteMe.
YouCompleteMe is a popular Vim
plugin that provides the user with semantic completion. It has a client-server
architecture, with the server component ycmd
providing code-completion and comprehension.
However, there is a pain point in that ycmd
requires the user compile ycm_core.so with a modern enough CMake
and LibClang for it to function properly.
Furthermore, more and more projects are using Docker containers to provide a
uniform build environment containing all dependencies needed to build them.
These dependencies (usually libraries and headers) may not be present on the
user's system, and thus YouCompleteMe
will not be able to pick them up for completion.
Normally, YouCompleteMe fires up
ycmd by invoking python on its nested
ycmd folder (which
essentially invokes the contained __main__.py).
We will configure YouCompleteMe to instead fire up our own Docker container
by fooling it into thinking our script ycmd-python is the Python
server interpreter (when it really just launches our own dockerized ycmd
instead).
The Dockerfile provided is only intended as an example (though
it can be used for basic completion).
The parent image ubuntu should instead be
replaced with the build image, and subsequently apt-get
with the corresponding package manager for that image.
We copy the ycmd-python script somewhere into our $PATH,
tweaking the image name as necessary.
We then override g:ycm_server_python_interpreter to launch our own container,
using an image which has both our dependencies (headers, libraries, etc) and
ycmd:
Plug 'Valloric/YouCompleteMe' let g:ycm_server_python_interpreter = 'ycmd-python'
It is imperative that the name of ycmd-python ends with
python (should it need to be changed), else YouCompleteMe
will refuse to launch it.
NB: I have little success with this; while in theory this should work emacs-ycmd
fails to contact the launched Docker container.
Emacs integration with ycmd is provided through emacs-ycmd.
Spacemacs provides this package through its ycmd layer.
To use our container here, we override ycmd-server-command to use our binary:
(setq ycmd-server-command '("ycmd-python")')
There does not appear to be any restriction on the name of ycmd-python,
though filename expansion is not supported for characters like ~, so it may
be necessary to use file-truename to expand it.
A typical YouCompleteMe instance will display the following diagnostics with
:YcmDebugInfo:
Printing YouCompleteMe debug information...
...
-- Server running at: http://127.0.0.1:8888
-- Server process ID: 12345
...
Normally we would use the process ID to locate the running instance and monitor
it.
However, as we are using docker to run this, we cannot use this method.
To make this easier for the user, the containers launched using ycmd-python
will have the format ycmd-<pid>, so that this will match what we see in the
diagnostic information.
In this instance, we would look for the container ycmd-12345 using
docker ps -a.
A regular installation of YouCompleteMe will start a server that logs to
several files, which can be inspected using :YcmDebugInfo:
Printing YouCompleteMe debug information...
...
-- Server running at: http://127.0.0.1:8888
...
-- Server logfiles:
-- /tmp/ycmd_8888_stdout_abcdefgh.log
-- /tmp/ycmd_8888_stderr_ijklmnop.log
...
However, on a long running server this will result in log files that may never be cleaned up.
To resolve this, we do not copy across the arguments provided to the stdout
and stderr options so that ycmd will log to /dev/stdout and /dev/stderr
respectively, and clean this up when we are done with them.
To retrieve them, we can use docker logs on the particular instance that we
want (using the process ID as described above).
Note that YouCompleteMe will still create these files regardless of whether
they end up being used,
though they will remain empty.
YouCompleteMe uses
jedi for Python
semantic completion. By default, it uses the same python interpreter used to
run ycmd (which in the example image is /usr/bin/python3).
In order to capture completions for third-party libraries found in a
virtual environment, one can tweak their .vimrc to point to the currently
active python:
let g:ycm_python_binary_path = 'python'
ycmd-python will automatically pick this up if the activated virtual
environment lies in $HOME.
You will not be able to jump to a file that is located only inside the container, as your editor will not be able to find it in the host filesystem.
Each version of YouCompleteMe is
designed for a particular ycmd revision.
As such, every time we update our YouCompleteMe instance this image should
also be updated accordingly.
This is done by tweaking the YCMD_REVISION variable in the Makefile
to match the corresponding version used in YouCompleteMe.
Furthermore, we should transfer any differences in the original examples/example_client.py
and the samples found in examples/samples
across into our repository.