Skip to content

Rust Completion with Standalone Files

Alex edited this page Nov 30, 2023 · 2 revisions

YCM can be configured to provide completion for standalone Rust modules. While the Rust compiler (rustc) is capable of compiling standalone files by treating the input file as the root module, rust-analyzer presents a limitation. It does not offer code completion for files unless they are part of a project managed by Cargo or include a rust-project.json file. This can lead to an issue where rust-analyzer fails with a 'rust-analyzer failed to discover workspace' error, particularly in the absence of a Cargo project.

To address this, YCM can be configured to pass the contents of the rust-project.json file directly to the language server, which enables code completion for standalone Rust files. This functionality is especially useful for those working on smaller projects or scripts that do not warrant a full Cargo setup.

The configuration can be implemented through a the ycm_extra_conf.py Python script. This script includes functions to determine the Rust system root and check if the current directory is a Cargo package. If it is not part of a Cargo package, the script configures the language server to treat the current file as a standalone package. This assumes that rustc and cargo are installed and accessible in the PATH.

See the Non-Cargo Based Projects documentation for more information.

# Configuration script for rust-analyzer to work with standalone files
import subprocess

def GetRustSysroot():
    result = subprocess.check_output( [ 'rustc', '--print', 'sysroot' ], encoding='utf-8' )
    return result.strip()

def IsCargoPackage() -> bool:
    result = subprocess.run( [ 'cargo', 'pkgid' ] )
    return result.returncode == 0

def Settings( **kwargs ):

    if kwargs[ 'language' ] == 'rust':

        if IsCargoPackage():
            return {} # use Cargo.toml autodiscovery

        # Treat current file as a standalone package
        try:
            sysroot = GetRustSysroot()
        except subprocess.CalledProcessError:
            return {}

        file = kwargs['filename']

        return {
            'ls': {
                'linkedProjects': [
                    {
                        "sysroot": sysroot,
                        "crates": [
                            {
                                "root_module": file,
                                "edition": "2021",
                                "deps": []
                            },
                        ],
                    },
                ]
            },
        }