Skip to content

Commit

Permalink
Add support for .air.toml too (#159)
Browse files Browse the repository at this point in the history
* Add support for `.air.toml`

* CHANGELOG bullet
  • Loading branch information
DavisVaughan authored Jan 17, 2025
1 parent 575918f commit 44f0385
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 13 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

# Development version

- Air now supports `.air.toml` files in addition to `air.toml` files. If both
are in the same directory, `air.toml` is preferred, but we don't recommend
doing that (#152).


# 0.1.2

Expand Down
16 changes: 11 additions & 5 deletions crates/lsp/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,22 @@ pub(crate) async fn handle_initialized(lsp_state: &LspState) -> anyhow::Result<(
.capabilities
.dynamic_registration_for_did_change_watched_files
{
// Watch for changes in `air.toml` files so we can react dynamically
// Watch for changes in configuration files so we can react dynamically
let watch_air_toml_registration = lsp_types::Registration {
id: String::from("air-toml-watcher"),
method: "workspace/didChangeWatchedFiles".into(),
register_options: Some(
serde_json::to_value(DidChangeWatchedFilesRegistrationOptions {
watchers: vec![FileSystemWatcher {
glob_pattern: lsp_types::GlobPattern::String("**/air.toml".into()),
kind: None,
}],
watchers: vec![
FileSystemWatcher {
glob_pattern: lsp_types::GlobPattern::String("**/air.toml".into()),
kind: None,
},
FileSystemWatcher {
glob_pattern: lsp_types::GlobPattern::String("**/.air.toml".into()),
kind: None,
},
],
})
.unwrap(),
),
Expand Down
3 changes: 2 additions & 1 deletion crates/lsp/src/workspaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use workspace::discovery::discover_settings;
use workspace::discovery::DiscoveredSettings;
use workspace::resolve::PathResolver;
use workspace::settings::Settings;
use workspace::toml::is_air_toml;

/// Convenience type for the inner resolver of path -> [`Settings`]
type SettingsResolver = PathResolver<Settings>;
Expand Down Expand Up @@ -164,7 +165,7 @@ impl WorkspaceSettingsResolver {
}
};

if !path.ends_with("air.toml") {
if !is_air_toml(&path) {
// We could get called with a changed file that isn't an `air.toml` if we are
// watching more than `air.toml` files
tracing::trace!("Ignoring non-`air.toml` changed URL: {url}");
Expand Down
84 changes: 77 additions & 7 deletions crates/workspace/src/toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::fmt::Formatter;
use std::io;
use std::path::{Path, PathBuf};

/// Parse an `air.toml` file.
/// Parse an air configuration file.
pub fn parse_air_toml<P: AsRef<Path>>(path: P) -> Result<TomlOptions, ParseTomlError> {
let contents = std::fs::read_to_string(path.as_ref())
.map_err(|err| ParseTomlError::Read(path.as_ref().to_path_buf(), err))?;
Expand Down Expand Up @@ -50,19 +50,25 @@ impl Display for ParseTomlError {
}
}

/// Return the path to the `air.toml` file in a given directory.
/// Return the path to the `air.toml` or `.air.toml` file in a given directory.
pub fn find_air_toml_in_directory<P: AsRef<Path>>(path: P) -> Option<PathBuf> {
// Check for `air.toml`.
// Check for `air.toml` first, as we prioritize the "visible" one.
let toml = path.as_ref().join("air.toml");
if toml.is_file() {
return Some(toml);
}

// Now check for `.air.toml` as well
let toml = path.as_ref().join(".air.toml");
if toml.is_file() {
Some(toml)
} else {
None
return Some(toml);
}

// Didn't find a configuration file
None
}

/// Find the path to the closest `air.toml` if one exists, walking up the filesystem
/// Find the path to the closest `air.toml` or `.air.toml` if one exists, walking up the filesystem
pub fn find_air_toml<P: AsRef<Path>>(path: P) -> Option<PathBuf> {
for directory in path.as_ref().ancestors() {
if let Some(toml) = find_air_toml_in_directory(directory) {
Expand All @@ -72,6 +78,14 @@ pub fn find_air_toml<P: AsRef<Path>>(path: P) -> Option<PathBuf> {
None
}

/// Check if a path is named like an `air.toml` or `.air.toml` file
///
/// Does not check if the path is an existing file on disk
pub fn is_air_toml<P: AsRef<Path>>(path: P) -> bool {
let path = path.as_ref();
path.ends_with("air.toml") || path.ends_with(".air.toml")
}

#[cfg(test)]
mod tests {
use anyhow::{Context, Result};
Expand Down Expand Up @@ -128,4 +142,60 @@ line-ending = "auto"

Ok(())
}

#[test]
fn find_and_parse_dot_air_toml() -> Result<()> {
let tempdir = TempDir::new()?;
let toml = tempdir.path().join(".air.toml");
fs::write(
toml,
r#"
[format]
ignore-magic-line-break = true
"#,
)?;

let toml = find_air_toml(tempdir.path()).context("Failed to find air.toml")?;
let options = parse_air_toml(toml)?;

let ignore_magic_line_break = options
.format
.as_ref()
.context("Expected to find [format] table")?
.ignore_magic_line_break
.context("Expected to find `ignore-magic-line-break` field")?;

assert!(ignore_magic_line_break);

Ok(())
}

#[test]
fn test_air_toml_priority() -> Result<()> {
let tempdir = TempDir::new()?;

let toml = tempdir.path().join("air.toml");
fs::write(
toml.clone(),
r#"
[format]
indent-width = 3
"#,
)?;

let dot_toml = tempdir.path().join(".air.toml");
fs::write(
dot_toml,
r#"
[format]
indent-width = 4
"#,
)?;

// Finds `air.toml` over `.air.toml`
let found_toml = find_air_toml(tempdir.path()).context("Failed to find air.toml")?;
assert_eq!(found_toml, toml);

Ok(())
}
}
5 changes: 5 additions & 0 deletions docs/configuration.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ If you run `air format` with a working directory of `~/files/dplyr` or open your
Air also supports walking up the directory tree from the project root.
For example, if you ran `air format` from within `~/files/dplyr/R`, then Air would look "up" one directory and would find and use `~/files/dplyr/air.toml`.

## Dotfiles

Air supports both `air.toml` and `.air.toml`.
If both are present in the same directory, then `air.toml` is preferred (but we don't recommend this).

## Format options

All formatting options are specified under the `[format]` table.
Expand Down

0 comments on commit 44f0385

Please sign in to comment.