The below snippet detect the venv name of the Python virtual environment created by .direnv and update the config of Pyright language server.
E.g. If a /Users/user/git/rust/project/.direnv/python-3.10.6/bin/python executable is found, it update the config /Users/user/git/rust/project/pyrightconfig.json with value
you can use the anyhow::Context extension trait to replace the bail!() statements under nested if let on Result and Option types:
use anyhow::Context;
//...
let project_root = python.ancestors().nth(4).context("failed to detect project root")?;
let venv = python.ancestors().nth(2).context("failed to detect venv name")?;
let venv = venv.file_name().with_context(|| format!("invalid venv name: {:?}", venv.file_name()))?;
let venv = venv.to_str().with_context(|| format!("invalid venv name: {:?}", venv))?;
//...
you can also chain those venv conversions, but you lose the ability to format error messages using the intermidate values.
let venv = python
.ancestors()
.nth(2)
.context("failed to detect venv name")?
.file_name()
.context("invalid venv name")?
.to_str()
.context("invalid venv name")?;
alternatively, you can use ok_or() (lazily: ok_or_else()) to turn Option<T> into anyhow::Result<T> without using anyhow::Context, but it's more verbose.
let project_root = python.ancestors().nth(4).ok_or(anyhow!("failed to detect project root"))?;
or if you somehow prefer bail!(), let else is a thing now:
let Some(project_root) = python.ancestors().nth(4) else {
bail!("failed to detect project root");
};
let Some(venv) = python.ancestors().nth(2) else {
bail!("failed to detect venv name");
};
//...
Oh, I add that clone because the borrow checker tells me the variable is moved when I try to use it again to write back to the file later. Didn't notice that I can use reference here. Thank you!