12 Customization
Fangrui Song edited this page 2019-10-09 09:16:14 -07:00

There are four possible ways to customize the behavior of the ccls server.

  1. The ccls server command line.
  2. The .ccls file, if it exists.
  3. The compile_commands.json file, if it exists.
  4. Initialization options

Command Line

By default, the ccls server will run as a daemon waiting for clients to send requests. The ccls server will accept these command-line options:

-h / --help

Show help. The server is not started.

--index=<root>

Stand-alone mode: index the entire project at <root> then exit.

--init=<json>

A JSON string <json> containing initialization options.

--log-file=<file> / --log-file-append=<bool>

Write logging to <file> / whether to append logging to <file>

-v=<N>

Set the logging verbosity level to <N>. Currently only 1 is supported: it will show the compiler arguments used to index files.

Initialization Options

Initialization options are defined in config.hh.

Each language client may have its own way to specify initialization options. Also, initialization options can be specified on the ccls command line using the --init option.

cache.directory

Default: ".ccls-cache"

This option was named cacheDirectory in the 0.20181225.8 release and before.

If your project is /a/b, cache directories will be created at /a/b/.ccls-cache/@a@b/ (files under the project root) /a/b/.ccls-cache/@@a@b/ (files outside the project root, e.g. /usr/include/stdio.h).

If the path name is longer than the system limit, set cache.hierarchicalPath to true. The cache files will be stored in a hierarchical manner: /a/b/.ccls-cache/a/b/. Be careful if you specify an absolute path as files indexed by different projects may conflict.

This can also be an absolute path. Because the project path is encoded with @, cache directories of different projects will not conflict.

When ccls is started, it will try loading cache files if they are not stale (compile command line matches and timestamps of main source and its #include (direct and transitive) dependencies do not change).

If the argument is an empty string, the cache will be stored only in memory. Use this if you don't want to write cache files.

Example: {"cache": {"directory": "/tmp/ccls-cache"}}

cache.format

Default: "binary"

This option was named cacheFormat in the 0.20181225.8 release and before.

Specify the format of the cached index files. Binary is a compact binary serialization format.

If you would like to inspect the contents of the cache you can change this to "json" then use a JSON formatter such as jq . < /tmp/ccls/@tmp@c/a.cc.json to display it.

Example: {"cacheFormat": "json"}

clang.extraArgs / clang.excludeArgs

Default: empty

Additional arguments or excluded arguments for compile_commands.json entries.

If your compiler is not Clang and it supports arguments which Clang doesn't understand, then you can use clang.excludeArgs to remove those arguments when indexing.

Conversely, you can add more arguments using clang.extraArgs (this could also be done through the .ccls file).

Example: {"clang": {"excludeArgs": ["-frounding-math"]}}

clang.pathMappings

Default: empty

A list of src>dest path conversions used to remap the paths of files in the project. This can be used to move a project to a new location without re-indexing.

If cache files were built with project root /tmp/remote/proj, and you want to reuse them with a different project root /tmp/host/proj then copy the cache:

rsync -a /tmp/ccls/@tmp@remote@proj/ /tmp/ccls/@tmp@host@proj/ # files under project root
rsync -a /tmp/ccls/@@tmp@remote@proj/ /tmp/ccls/@@tmp@host@proj/ # files outside of project root

Then use the initialization option

{"clang": {"pathMappings": ["/remote/>/host/"]}

When ccls indexes /tmp/host/proj/a.cc, the cache file /tmp/ccls/@tmp@remote@proj/a.cc.blob will be reused. When a.cc is saved (re-indexed), the newly generated a.cc.blob will not contain /tmp/remote paths any more.

cache.retainInMemory

Default: 1

Change to 0 if you want to save memory, but having multiple ccls processes operating in the same directory may corrupt ccls's in-memory representation of the index.

After this number of loads, keep a copy of file index in memory (which increases memory usage). During incremental updates, the removed file index will be taken from the in-memory copy, instead of the on-disk file.

Every index action is counted: the initial load, a save action. 0: never retain; 1: retain after initial load; 2: retain after 2 loads (initial load+first save)

clang.resourceDir

Default: empty

The clang resource directory (something like .../lib/clang/9.0.0) is hard-coded into ccls at compile time. You should be able to find <resourceDir>/include/stddef.h. Set this option to a non-empty string to override the hard-coded value.

Use the path provided as the Clang resource directory rather the default. See Clang Resource Directory for more information.

client.snippetSupport

completion.placeholder

client.snippetSupport (default: true) and completion.placeholder (default: true) decide the completion style.

  • client.snippetSupport: false => foo
  • client.snippetSupport: true
    • completion.placeholder: false => foo($1)$0 bar<$1>()$0
    • completion.placeholder: true => foo(${1:int a}, ${2:int b})$0 bar<${1:typename T}>()$0

If the client announces that it does not support snippets, client.snippetSupport will be forced to false.

Example: {"client": {"snippetSupport": true}, "completion": {"placeholder": false}}

compilationDatabaseDirectory

Default: ""

If not empty, look for compile_commands.json in it, otherwise the file is retrieved in the project root.

Useful when using out-of-tree builds with the compilation database being generated in the build directory.

Example: {"compilationDatabaseDirectory": "out/release"}

diagnostics.onOpen / diagnostics.onChange / diagnostics.onSave

Default: onOpen: 0 / onChange: 1000 / onSave: 0

Time (in milliseconds) to wait before computing diagnostics for textDocument/{didOpen,didChange,didSave}.

  • diagnostics.onOpen: How long to wait before diagnostics are emitted when a document is opened.
  • diagnostics.onChange: after receiving a textDocument/didChange, wait up to this long before reporting diagnostics. Changes during this period of time only lead to one computation.
  • diagnostics.onSave: How long to wait before diagnostics are emitted after a document is saved.

Diagnostics require parsing the file. If diagnostics.onChange: 1000 makes you feel slow, consider {"diagnostics": {"onChange": 1}}.

index.threads

Default: 0

How many threads to start when indexing a project. 0 means use std::thread::hardware_concurrency() (the number of cores the system has). If you want to reduce peak CPU and memory usage, set it to a small integer.

Example: {"index": {"threads": 2}}

index.comments

Default: 2

ccls can index the contents of comments associated with functions/types/variables (macros are not handled). This value controls how comments are indexed:

  • 0: don't index comments
  • 1: index Doxygen comment markers
  • 2: use -fparse-all-comments and recognize plain // /* */ in addition to Doxygen comment markers

This feature requires UI support as multi-line textDocument/hover results pose a problem for some editors:

Example: {"index": {"comments": 1}}

index.multiVersion

Default: 0

Index a file only once (0), or in each translation unit that includes it (1).

The default is sensible for common usage: it reduces memory footprint. If both a.cc and b.cc include a.h, there is only one indexed version of a.h.

But for dependent name lookup, or references in headers that may change depending on other macros, etc, you may want to index a file multiple times to get every possible cross reference. In that case set the option to 1 but be aware that it may increase index file sizes significantly.

Also consider using index.multiVersionBlacklist to exclude system headers.

index.multiVersionBlacklist

Default: empty

A list of regular expressions matching files that should not be indexed via multi-version if that value is 1.

Commonly this is used to avoid indexing system headers multiple times as this is seldom useful.

Example: {"index": {"multiVersion": 1, "multiVersionBlacklist": ["^/usr/include"]}}

index.initialBlacklist

Default: []

A list of regular expressions matching files that should not be indexed when the ccls server starts up, but will still be indexed if a client opens them. If there are areas of the project that you have no interest in indexing you can use this to avoid it unless you visit those files.

This can also be set to match all files, which is helpful in avoiding massive parsing operations when performing quick edits on large projects.

Be aware that you will not have access to full cross-referencing information in this situation.

If index.initialWhitelist is also specified, the whitelist takes precedence.

Example: {"index": {"initialBlacklist": ["."]}} (matches all files)

index.onChange

Default: false

If false, a file is re-indexed when saved, updating the global index incrementally.

If set to true, a document is re-indexed for every (unsaved) change. Performance may suffer, but it is convenient for playground projects. Generally this is best used in conjunction with empty cache.directory to avoid writing cache files to disk.

Example: {"cache": {"directory": ""}, "index": {"onChange": true}}

index.trackDependency

Default: 2

Determine whether a file should be re-indexed when any of its dependencies changes timestamp.

If a.h has been changed, when you open a.cc which includes a.h then if trackDependency is:

  • 0: no re-indexing unless a.cc itself changes timestamp.
  • 2: the index of a.cc is considered stale and it should be re-indexed.
  • 1: before the initial load, the behavior of 2 is used, otherwise the behavior of 0 is used.

Example: {"index": {"trackDependency": 1}}

completion.detailedLabel

Default: true

When this option is enabled, label and detailed are re-purposed:

  • label: detailed function signature, e.g. foo(int a, int b) -> bool
  • detailed: the name of the parent context, e.g. in S s; s.<complete>, the parent context is S.

Example: {"completion": {"detailedLabel": false}}

completion.filterAndSort

Default: true

ccls filters and sorts completions to try to be nicer to clients that can't handle big numbers of completion candidates. This behaviour can be disabled by specifying false for the option.

This option is useful for LSP clients that implement their own filtering and sorting logic.

Example: {"completion": {"filterAndSort": false}}