Skip to content

Commit d540fc4

Browse files
committed
refactor: remove ConfigPath struct
- remove handling file paths containing a file, as we will always receive a directory - inline from_dir - test cases to handle existing and missing config files
1 parent fcda774 commit d540fc4

File tree

3 files changed

+52
-115
lines changed

3 files changed

+52
-115
lines changed

crates/typos-lsp/src/config.rs

Lines changed: 30 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -3,70 +3,27 @@ use std::path::{Path, PathBuf};
33
use anyhow::{anyhow, Context};
44
use toml_edit::DocumentMut;
55

6-
/// Represents a path to a typos_cli config file and, if it contains a configuration file, the file
7-
/// contents.
8-
///
9-
/// When reading a config from a directory, many configuration files are supported, and only one is
10-
/// chosen in a given order. Shows the name of the config file that is used ("typos.toml",
11-
/// "_typos.toml", ".typos.toml", "pyproject.toml"). This information is useful when we want to
12-
/// modify the config file later on.
13-
#[derive(Debug, Clone)]
14-
pub struct ConfigPath {
15-
pub path: PathBuf,
16-
pub config: Option<typos_cli::config::Config>,
17-
}
18-
19-
impl PartialEq for ConfigPath {
20-
fn eq(&self, other: &Self) -> bool {
21-
self.path == other.path && format!("{:?}", self.config) == format!("{:?}", other.config)
22-
}
23-
}
24-
25-
impl ConfigPath {
26-
pub fn from_file_path_or_default(path: &Path) -> ConfigPath {
27-
let config = typos_cli::config::Config::from_file(path).ok().flatten();
28-
29-
ConfigPath {
30-
path: path.to_path_buf(),
31-
config,
6+
pub fn find_config_file_or_default(directory: &Path) -> PathBuf {
7+
assert!(
8+
directory.is_dir(),
9+
"Expected a directory that might contain a configuration file, got {:?}",
10+
directory.is_dir()
11+
);
12+
13+
// adapted from typos_cli::config::Config::from_dir
14+
for file in typos_cli::config::SUPPORTED_FILE_NAMES {
15+
let config_path = directory.join(file);
16+
if typos_cli::config::Config::from_file(&config_path)
17+
.ok()
18+
.flatten()
19+
.is_some()
20+
{
21+
return config_path;
3222
}
3323
}
3424

35-
pub fn from_dir_or_default(path: &Path) -> ConfigPath {
36-
let directory = if path.is_dir() {
37-
path
38-
} else {
39-
path.parent().unwrap()
40-
};
41-
ConfigPath::from_dir(directory).unwrap_or_else(|_| ConfigPath {
42-
path: path.join("typos.toml").to_path_buf(),
43-
config: None,
44-
})
45-
}
46-
47-
// copied from typos_cli::config::Config::from_dir
48-
fn from_dir(dir: &Path) -> anyhow::Result<ConfigPath> {
49-
assert!(
50-
dir.is_dir(),
51-
"Expected a directory that might contain a configuration file, got {:?}",
52-
dir.is_dir()
53-
);
54-
55-
for file in typos_cli::config::SUPPORTED_FILE_NAMES {
56-
let path = dir.join(file);
57-
if let Ok(Some(config)) = typos_cli::config::Config::from_file(path.as_path()) {
58-
return Ok(ConfigPath {
59-
path,
60-
config: Some(config),
61-
});
62-
}
63-
}
64-
65-
Err(anyhow::anyhow!(
66-
"No typos_cli config file found starting from {:?}",
67-
dir
68-
))
69-
}
25+
// no config file found in the directory, so provide a default typos.toml path
26+
directory.join("typos.toml")
7027
}
7128

7229
pub fn add_ignore(config_file_path: &Path, typo: &str) -> anyhow::Result<()> {
@@ -104,54 +61,37 @@ pub fn add_ignore(config_file_path: &Path, typo: &str) -> anyhow::Result<()> {
10461
mod tests {
10562
use super::*;
10663
use std::fs::File;
107-
use std::io::Write;
10864
use tempfile::tempdir;
10965

11066
#[test]
111-
fn test_from_dir_or_default_with_exact_path() -> anyhow::Result<()> {
112-
// when given a path to a configuration file, should resolve it to the same file
113-
114-
// create a temporary directory on disk
67+
fn test_find_config_file_found() -> anyhow::Result<()> {
68+
// when a configuration file is found in the directory, should return that file path
11569
let dir = tempdir()?;
70+
let dir_path = dir.path();
71+
let config_path = dir_path.join(".typos.toml");
72+
File::create(&config_path)?;
11673

117-
let file_path = dir.path().join("typos.toml");
118-
let mut file = File::create(&file_path)?;
119-
writeln!(file, "#")?;
120-
121-
assert_eq!(
122-
ConfigPath::from_dir_or_default(&file_path),
123-
ConfigPath {
124-
path: file_path.to_path_buf(),
125-
config: Some(typos_cli::config::Config::default()),
126-
}
127-
);
74+
assert_eq!(find_config_file_or_default(dir_path), config_path);
12875

12976
Ok(())
13077
}
13178

13279
#[test]
133-
fn test_from_dir_or_default_with_directory() -> anyhow::Result<()> {
134-
// when given a path to a directory, should resolve it to the first configuration file
135-
// found in the directory. This should support all of the supported file names, although
136-
// this test only tests one of them.
137-
138-
// NOTE when `dir` is dropped, the temporary directory is deleted from disk
80+
fn test_find_config_file_missing() -> anyhow::Result<()> {
81+
// when no configuration file is found in the directory, should return the default typos.toml path
13982
let dir = tempdir()?;
14083
let dir_path = dir.path();
14184

14285
assert_eq!(
143-
ConfigPath::from_dir_or_default(dir.path()),
144-
ConfigPath {
145-
path: dir_path.join("typos.toml").to_path_buf(),
146-
config: None,
147-
}
86+
find_config_file_or_default(dir_path),
87+
dir_path.join("typos.toml").to_path_buf()
14888
);
14989

15090
Ok(())
15191
}
15292

15393
#[test]
154-
fn test_add_ignore_to_new_file() -> anyhow::Result<()> {
94+
fn test_add_ignore_to_new_config_file() -> anyhow::Result<()> {
15595
let dir = tempdir()?;
15696
let file_path = dir.path().join("test.toml");
15797

@@ -173,7 +113,7 @@ mod tests {
173113
}
174114

175115
#[test]
176-
fn test_add_ignore_to_existing_file() -> anyhow::Result<()> {
116+
fn test_add_ignore_to_existing_config_file() -> anyhow::Result<()> {
177117
// should preserve comments and formatting
178118

179119
let existing_file = [

crates/typos-lsp/src/lsp.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,7 @@ impl LanguageServer for Backend<'static, 'static> {
231231
[serde_json::to_value(IgnoreInProjectCommandArguments {
232232
typo: typo.to_string(),
233233
config_file_path: value
234-
.project_root
235-
.path
234+
.config_file
236235
.to_string_lossy()
237236
.to_string(),
238237
})
@@ -241,14 +240,14 @@ impl LanguageServer for Backend<'static, 'static> {
241240
),
242241
}));
243242

244-
if let Some(explicit_config) = &value.explicit_config {
243+
if let Some(explicit_config) = &value.custom_config {
245244
suggestions.push(CodeActionOrCommand::Command(Command {
246245
title: format!("Ignore `{}` in the configuration file", typo),
247246
command: IGNORE_IN_PROJECT.to_string(),
248247
arguments: Some(
249248
[serde_json::to_value(IgnoreInProjectCommandArguments {
250249
typo: typo.to_string(),
251-
config_file_path: explicit_config.path.to_string_lossy().to_string(),
250+
config_file_path: explicit_config.to_string_lossy().to_string(),
252251
})
253252
.unwrap()]
254253
.into(),

crates/typos-lsp/src/typos.rs

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
use std::path::Path;
1+
use std::path::{Path, PathBuf};
22

33
use bstr::ByteSlice;
4-
use crate::config::ConfigPath;
54
use ignore::overrides::{Override, OverrideBuilder};
65
use typos_cli::policy;
76

7+
use crate::config;
8+
89
pub struct Instance<'s> {
910
/// File path rules to ignore
1011
pub ignores: Override,
1112
pub engine: policy::ConfigEngine<'s>,
1213

13-
/// The path where the LSP server was started
14-
pub project_root: ConfigPath,
14+
/// The path to the configuration file for the files in this instance
15+
pub config_file: PathBuf,
1516

1617
/// The explicit configuration file that was given to the LSP server at startup
17-
pub explicit_config: Option<ConfigPath>,
18+
pub custom_config: Option<PathBuf>,
1819
}
1920

2021
impl Instance<'_> {
@@ -31,38 +32,35 @@ impl Instance<'_> {
3132
// a default config?
3233

3334
let mut c = typos_cli::config::Config::default();
34-
let explicit_config = config.map(ConfigPath::from_file_path_or_default);
35-
36-
if let Some(ConfigPath {
37-
config: Some(ref config),
38-
..
39-
}) = explicit_config
40-
{
41-
c.update(config);
42-
engine.set_overrides(c);
35+
if let Some(config_path) = config {
36+
let custom = typos_cli::config::Config::from_file(config_path)?;
37+
if let Some(custom) = custom {
38+
c.update(&custom);
39+
engine.set_overrides(c);
40+
}
4341
}
4442

4543
// initialise an engine and overrides using the config file from path or its parent
4644
engine.init_dir(path)?;
4745
let walk_policy = engine.walk(path);
4846

49-
let mut ignores = OverrideBuilder::new(path);
47+
let mut ob = OverrideBuilder::new(path);
5048
// always ignore the config files like typos cli does
5149
for f in typos_cli::config::SUPPORTED_FILE_NAMES {
52-
ignores.add(&format!("!{f}"))?;
50+
ob.add(&format!("!{f}"))?;
5351
}
5452

5553
// add any explicit excludes
5654
for pattern in walk_policy.extend_exclude.iter() {
57-
ignores.add(&format!("!{pattern}"))?;
55+
ob.add(&format!("!{pattern}"))?;
5856
}
59-
let ignore = ignores.build()?;
57+
let ignores = ob.build()?;
6058

6159
Ok(Instance {
62-
explicit_config,
63-
project_root: ConfigPath::from_dir_or_default(path),
64-
ignores: ignore,
60+
ignores,
6561
engine,
62+
config_file: config::find_config_file_or_default(path),
63+
custom_config: config.map(|p| p.to_path_buf()),
6664
})
6765
}
6866
}

0 commit comments

Comments
 (0)