Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ hubris.testout.*
!.vscode/launch.json
!.vscode/tasks.json
!.vscode/extensions.json
.nvim.lua
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.nvim.lua
.nvim.lua
.zed/settings.json

50 changes: 47 additions & 3 deletions README.mkdn
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,52 @@ $ cargo xtask clippy app/gimletlet/app.toml ping pong
## Integrating with `rust-analyzer`
The Hubris build system will not work with `rust-analyzer` out of the box.

However, `cargo xtask lsp` is here to help: it takes as its argument a Rust
file, and returns JSON-encoded configuration for how to set up `rust-analyzer`.
There are two strategies:

- `cargo xtask rust-analyzer` is a shim that pretends to be `rust-analyzer` but
intercepts setup messages to apply configuration specific to a
`(manifest,task)` tuple. This is easy to use but somewhat limited.
- `cargo xtask lsp` accepts a file path and emits config information that can be
used when setting up `rust-analyzer`. It can be tightly integrated (if you
write a bunch of editor-specific code) to automatically find a manifest and
task when a file is edited, then launch an appropriate `rust-analyzer`
instance.

Right now, you should probably use `cargo xtask rust-analyzer`; the instructions
below for `cargo xtask lsp` have rotted as Neovim's configuration has changed.

### Using `cargo xtask rust-analyzer`
Configure your editor to use a custom `rust-analyzer`:
```
cargo run -pxtask -- rust-analyzer PATH/TO/APP.TOML:TASK_NAME
```

#### Example Neovim integration
If you're using Neovim, you can enable project-specific `.nvim.lua` files in
your global configuration:
```lua
-- Enable project-specific `.nvim.lua` files
vim.o.exrc = true
```

Then add `.nvim.lua` to this repo which reads from a `HUBRIS_TASK` variable:
```lua
local project_root = vim.fn.fnamemodify(debug.getinfo(1, "S").source:sub(2), ":h")

vim.lsp.config("rust_analyzer", {
cmd = { "cargo", "run", "-pxtask", "--", "rust-analyzer", vim.env.HUBRIS_TASK },
cmd_cwd = project_root,
})
```

Finally, launch your editor with an appropriate `HUBRIS_TASK`:
```console
$ HUBRIS_TASK=app/cosmo/rev-a.toml:control_plane_agent nvim
```

### Using `cargo xtask lsp`
`cargo xtask lsp` takes as its argument a Rust file, and returns JSON-encoded
configuration for how to set up `rust-analyzer`.

To use this data, some editor configuration is required!

Expand Down Expand Up @@ -297,7 +341,7 @@ require'rust-tools'.setup{
end
```

### What's going on here?
#### What's going on here?
When a new LSP configuration is created (`on_new_config`), we run `cargo
xtask lsp` on the target file. The JSON configuration includes a hash of
the configuration; we use that hash to modify the name of the client from
Expand Down
30 changes: 30 additions & 0 deletions build/xtask/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod humility;
mod lsp;
mod passthrough;
mod print;
mod rust_analyzer;
mod sizes;
mod task_slot;

Expand Down Expand Up @@ -247,6 +248,15 @@ enum Xtask {
file: PathBuf,
},

/// Runs `rust-analyzer` for the target manifest + task
RustAnalyzer {
/// Path to which logs should be written
#[clap(short, long)]
log: Option<PathBuf>,
/// Colon-delimited `path/to/app.toml:task_name` value
target: Option<String>,
},

/// Prepare artifacts for upload in CI.
GhaPrepareArtifacts {
/// Path to the image configuration file, in TOML.
Expand Down Expand Up @@ -546,6 +556,26 @@ fn run(xtask: Xtask) -> Result<()> {
Xtask::Lsp { clients, file } => {
lsp::run(&file, &clients)?;
}
Xtask::RustAnalyzer { log, target } => {
let t = if let Some(target) = target {
let mut iter = target.split(':');
let manifest = iter
.next()
.ok_or_else(|| anyhow!("failed to get manifest"))?;
let task =
iter.next().ok_or_else(|| anyhow!("failed to get task"))?;
if iter.next().is_some() {
bail!("expected two colon-separated values in `{target}`");
}
Some(rust_analyzer::HubrisTargetTask {
manifest: manifest.into(),
task_name: task.to_owned(),
})
} else {
None
};
rust_analyzer::run(log, t)?;
}
Xtask::GhaPrepareArtifacts { cfg, attestation } => {
gha_prepare_artifacts::run(&cfg, attestation.as_deref())?;
}
Expand Down
Loading
Loading