cxxd icon indicating copy to clipboard operation
cxxd copied to clipboard

C/C++ language server implemented on top of Clang frontend.

Contents

  • About
    • Features
    • Supported platforms
    • Dependencies
  • API
    • Design
      • Services
      • Server
      • Async
      • Plugin
    • Example usage
      • cxxd integration tests
      • Frontend implementation for Vim
    • Public API
  • Screenshots
  • FAQ

About

cxxd is a C/C++ language server which offers rich support for features that aid the process of source code navigation, editing, automatic formatting, static analysis etc. One can utilize it, for example, to bring IDE-like features to an editor of your choice.

Features

Feature Status cxxd-vim frontend
Indexer :heavy_check_mark: :heavy_check_mark:
Find-all-references :heavy_check_mark: :heavy_check_mark:
Go-to-definition :heavy_check_mark: :heavy_check_mark:
Go-to-include :heavy_check_mark: :heavy_check_mark:
Type-deduction :heavy_check_mark: :heavy_check_mark:
Fetch-all-diagnostics :heavy_check_mark: :heavy_check_mark:
Fixits-and-diagnostics :heavy_check_mark: :heavy_check_mark:
Semantic-syntax-highlighting :heavy_check_mark: :heavy_check_mark:
Code-completion work-in-progress work-in-progress
Clang-tidy :heavy_check_mark: :heavy_check_mark:
Clang-format :heavy_check_mark: :heavy_check_mark:
JSON-compilation-database :heavy_check_mark: :heavy_check_mark:
Project-builder :heavy_check_mark: :heavy_check_mark:
External configuration via JSON :heavy_check_mark: :heavy_check_mark:

In essence, the main idea behind it is very much alike to what LSP offers and its implementations like clangd.

Supported platforms

Platform Status Comments
Linux :heavy_check_mark: Main development environment of this project.
Windows :x: Not officially tested but it might work.
macOS :x: Not officially tested but it might work.

Dependencies

Required: Python2, libclang (with Python bindings), g++

Optional: clang-format, clang-tidy

In Fedora-based distributions, one may install the dependencies by running:

  • sudo dnf install python2 clang-devel clang-libs clang-tools-extra && pip install --user clang

In Debian-based distributions, one may install the dependencies by running:

  • sudo apt-get install python2.7 libclang-dev clang-tidy clang-format && pip install --user clang

API

API tries to stay fairly trivial and straightforward without putting too much burden (impl. details) on the frontend side but there are couple of important bits and pieces that should be understood in order to efficiently use this API.

Design

Services

Aforementioned features are organized into services. Each service:

  • Is assigned its own unique ID
  • Runs in its own context (process)
  • Supports a set of common operations: startup, shutdown, request
  • Provides a user-defined hook, so called plugin, to be invoked on completion of any of the supported operations

Server

Communication with any of the service is established/routed via proxy server which sits in between the client (frontend) and corresponding service. Server implements a very simple API:

  • start-all-services
  • start-service
  • shutdown-all-services
  • shutdown-service
  • send-service-request

Public API, which is exposed to clients, is implemented on top of server API.

Async

API, due to the nature of features being implemented, is designed to work in an asynchronous fashion. That means that retrieving the result from corresponding operation cannot be done via regular (synchronous) return-value mechanism but instead one must register a hook (callback) object which will then be invoked once the result is ready (after operation has completed). These callbacks we call plugins.

Plugin

Plugin is a mechanism to subscribe for a result of an asynchronous operation. This is a customization go-to point for client code to decide what to do with the result (e.g. process it further and communicate it back to the frontend using the appropriate inter-process mechanism).

Diagram

Diagram

Example usage

cxxd integration tests

Integration test suite is actually a representative example of a frontend which has a main purpose in validating the data computed by the services (e.g. if go-to-definition returns a valid/expected source code location). Some other frontends will rather like to do something more with the data, e.g. visualize it or populate the UI elements with it.

So, integration tests have all of the important bits which depict the usage of an API:

  • We have to start the server before anything else.

  • A mechanism which provides customization point for application-specific purposes is factory function. Factory function will be invoked during the server startup phase. Its purpose is to provide a means to instantiate an application-specific server with main (customization) part being the registration of application-specific plugins.

  • Application-specific plugins in integration tests will only make a copy of received data to be able to validate its contents from the test execution context.

  • To communicate the received data to different execution contexts (processes), one shall use some form of inter-process communication mechanisms. This integration test suite implements the inter-process communication by utilizing the shared-memory to store the data and named-semaphores to synchronize between R/W accesses. Some other application will use other means to achieve the same (i.e. to communicate the data back to vim instance one could make use one of the RPC mechanisms that vim provides).

  • Example of triggering the service is running the source code indexer on the given directory, waiting until it is completed and querying if it has run successfuly.

  • Many other examples depicting the usage of an API

Frontend implementation for Vim

Public API

General cxxd server startup/shutdown API

API Return Value
server_start(get_server_instance, get_server_instance_args, project_root_directory, log_file) handle
server_stop(handle, *payload) status, payload
server_start_all_services(handle, *payload) status, payload
server_stop_all_services(handle, *payload) status, payload

Source code model API

API Return Value
source_code_model_start(handle, compiler_args) status, payload
source_code_model_stop(handle, subscribe_for_callback) status, payload
source_code_model_semantic_syntax_highlight_request(handle, filename, contents) status, [translation_unit_ast, ast_visitor_function]
source_code_model_diagnostics_request(handle, filename, contents) status, [diagnostics_iterator, diagnostics_visitor_function, fixit_visitor_function]
source_code_model_type_deduction_request(handle, filename, contents, line, col) status, type_spelling
source_code_model_go_to_definition_request(handle, filename, contents, line, col) status, [definition_filename, definition_line, definition_column]
source_code_model_go_to_include_request(handle, filename, contents, line) status, include_header_filename
source_code_model_indexer_run_on_single_file_request(handle, filename, contents) status, None
source_code_model_indexer_run_on_directory_request(handle) status, None
source_code_model_indexer_drop_single_file_request(handle, filename) status, None
source_code_model_indexer_drop_all_request(handle, remove_db_from_disk) status, None
source_code_model_indexer_drop_all_and_run_on_directory_request(handle) status, None
source_code_model_indexer_find_all_references_request(handle, filename, line, col) status, list_of_references(filename, line, column, context)
source_code_model_indexer_fetch_all_diagnostics_request(handle, sorting_strategy) status, list_of_diagnostics(filename, line, column, description, severity)

Project Builder API

API Return Value
project_builder_start(handle) status, payload
project_builder_stop(handle, subscribe_for_callback) status, payload
project_builder_request(handle, build_command) status, [build_cmd_output_filename, build_exit_code, duration]

Clang-format API

API Return Value
clang_format_start(handle) status, payload
clang_format_stop(handle, subscribe_for_callback) status, payload
clang_format_request(handle, filename) status, None

Clang-tidy API

API Return Value
clang_tidy_start(handle, json_compilation_database) status, payload
clang_tidy_stop(handle, subscribe_for_callback) status, payload
clang_tidy_request(handle, filename, apply_fixes) status, clang_tidy_output_filename

Screenshots

Screenshots from cxxd-vim

FAQ

How do I make use of this in <insert_environment_of_your_choice>?

Look for and install a frontend suitable for your environment. I.e. cxxd-vim if you want to try it out from Vim. This is only a backend server. Other supported frontends are listed in the table from above and hopefully more will come with the help of community.

How do I develop a new frontend on top of it?

Understand the API. Look how cxxd integration tests have been implemented on top if it. Look into other available frontend implementations, such as the one for Vim.

Why?

One may question the reasoning behind the existence of this project (given that we have other alternatives such as aforementioned clangd), but the whole idea and implementation started to grow couple of months before LSP has been officially announced and, this being my own pet project, I decided not to stop with the development but to try to drive it more forward.

Idea may not have been obvious or recognized by many people as it has been actively developed under my other project, Yavide, which is a heavily modded Vim so naturally not really attracted by many. In order to enable usage from different editors (or any other type of frontends), I have decied to finally put some effort into packaging the server functionality into this standalone repository.