diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e6a62ce..83c5feb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased](https://github.com/Kampfkarren/selene/compare/0.27.1...HEAD) ### Added - Added `Path2DControlPoint.new` to the Roblox standard library +- Added `.selene.toml` as possible config file with priority over `selene.toml`. ## [0.27.1](https://github.com/Kampfkarren/selene/releases/tag/0.27.1) - 2024-04-28 ### Fixed @@ -437,4 +438,4 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Added standard library chaining. This means you can combine two standard libraries by setting `std` in selene.toml to `std1+std2`. You can chain as many as you want. ## [0.1.0](https://github.com/Kampfkarren/selene/releases/tag/0.1.0) - 2019-11-06 -- Initial release \ No newline at end of file +- Initial release diff --git a/docs/src/cli/usage.md b/docs/src/cli/usage.md index 25eb5855..28b0ce83 100644 --- a/docs/src/cli/usage.md +++ b/docs/src/cli/usage.md @@ -16,7 +16,7 @@ FLAGS: OPTIONS: --color [default: auto] [possible values: Always, Auto, Never] - --config A toml file to configure the behavior of selene [default: selene.toml] + --config A toml file to configure the behavior of selene [default: .selene.toml] --display-style Sets the display method [possible values: Json, Json2, Rich, Quiet] --num-threads Number of threads to run on, default to the numbers of logical cores on your system [default: your system's cores] diff --git a/docs/src/lints/high_cyclomatic_complexity.md b/docs/src/lints/high_cyclomatic_complexity.md index 8d183553..53816b3f 100644 --- a/docs/src/lints/high_cyclomatic_complexity.md +++ b/docs/src/lints/high_cyclomatic_complexity.md @@ -29,7 +29,7 @@ end ## Remarks -This lint is off by default. In order to enable it, add this to your selene.toml: +This lint is off by default. In order to enable it, add this to your .selene.toml: ```toml [lints] diff --git a/docs/src/roblox.md b/docs/src/roblox.md index 77ed0709..d4040fff 100644 --- a/docs/src/roblox.md +++ b/docs/src/roblox.md @@ -6,13 +6,13 @@ If you try to run selene on a Roblox codebase, you'll get a bunch of errors sayi ## Installation -Thankfully, this process is very simple. All you need to do is edit your `selene.toml` (or create one) and add the following: +Thankfully, this process is very simple. All you need to do is edit your `.selene.toml` (or create one) and add the following: ```toml std = "roblox" ``` -The next time you run selene, or if you use the Visual Studio Code extension and start typing Lua code, a Roblox standard library will be automatically generated and used. This is an automatic process that occurs whenever you don't have a cached standard library file and your `selene.toml` has `std = "roblox"`. +The next time you run selene, or if you use the Visual Studio Code extension and start typing Lua code, a Roblox standard library will be automatically generated and used. This is an automatic process that occurs whenever you don't have a cached standard library file and your `.selene.toml` has `std = "roblox"`. ## Updating definitions @@ -32,7 +32,7 @@ There may be cases where you would rather not have selene automatically update t selene supports "pinning" the standard library to a specific version. -Add the following to your `selene.toml` configuration: +Add the following to your `.selene.toml` configuration: ```toml # `floating` by default, meaning it is stored in a cache folder on your system roblox-std-source = "pinned" diff --git a/docs/src/usage/configuration.md b/docs/src/usage/configuration.md index b6f57a9e..8ca7d677 100644 --- a/docs/src/usage/configuration.md +++ b/docs/src/usage/configuration.md @@ -1,10 +1,10 @@ # Configuration selene is meant to be easily configurable. You can specify configurations for the entire project as well as for individual lints. -Configuration files are placed in the directory you are running selene in and are named **selene.toml**. As the name suggests, the configurations use the [Tom's Obvious, Minimal Language (TOML)](https://github.com/toml-lang/toml) format. It is recommended you quickly brush up on the syntax, though it is very easy. +Configuration files are placed in the directory you are running selene in and are named **.selene.toml** (or **selene.toml**) . As the name suggests, the configurations use the [Tom's Obvious, Minimal Language (TOML)](https://github.com/toml-lang/toml) format. It is recommended you quickly brush up on the syntax, though it is very easy. ## Changing the severity of lints -You can change the severity of lints by entering the following into selene.toml: +You can change the severity of lints by entering the following into .selene.toml: ```toml [lints] @@ -22,7 +22,7 @@ Where "severity" is one of the following: Note that "deny" and "warn" are effectively the same, only warn will give orange text while error gives red text, and they both have different counters. ## Configuring specific lints -You can configure specific lints by entering the following into selene.toml: +You can configure specific lints by entering the following into .selene.toml: ```toml [config] @@ -47,7 +47,7 @@ By default, selene uses Lua 5.1, though if we wanted to use the Lua 5.2 standard std = "lua52" ``` -...at the top of selene.toml. You can learn more about the standard library format on the [standard library guide](./std.md). The standard library given can either be one of the builtin ones (currently only `lua51` and `lua52`) or the filename of a standard library file in this format. For example, if we had a file named `special.toml`, we would write: +...at the top of .selene.toml. You can learn more about the standard library format on the [standard library guide](./std.md). The standard library given can either be one of the builtin ones (currently only `lua51` and `lua52`) or the filename of a standard library file in this format. For example, if we had a file named `special.toml`, we would write: ```toml std = "special" @@ -68,4 +68,4 @@ It is possible to exclude files from being linted using the exclude option: ```toml exclude = ["external/*", "*.spec.lua"] -``` +``` \ No newline at end of file diff --git a/docs/src/usage/filtering.md b/docs/src/usage/filtering.md index 911c4b15..4e072b15 100644 --- a/docs/src/usage/filtering.md +++ b/docs/src/usage/filtering.md @@ -27,7 +27,7 @@ However, perhaps we as the programmer have some reason for leaving this unused ( local something = 1 ``` -This also works with settings other than `allow`--you can `warn` or `deny` lints in the same fashion. For example, you can have a project with the following `selene.toml` [configuration](./configuration.md): +This also works with settings other than `allow`--you can `warn` or `deny` lints in the same fashion. For example, you can have a project with the following `.selene.toml` [configuration](./configuration.md): ```toml [lints] diff --git a/selene-vscode/package.json b/selene-vscode/package.json index 2defeb01..24e11418 100644 --- a/selene-vscode/package.json +++ b/selene-vscode/package.json @@ -14,6 +14,7 @@ "activationEvents": [ "onLanguage:lua", "onLanguage:luau", + "workspaceContains:.selene.toml", "workspaceContains:selene.toml", "onCommand:selene.reinstall", "onCommand:selene.update-roblox-std", @@ -118,4 +119,4 @@ "semver": "^7.3.8", "unzipper": "^0.10.11" } -} +} \ No newline at end of file diff --git a/selene-vscode/src/configLint.ts b/selene-vscode/src/configLint.ts index ea3ccee8..86bebdde 100644 --- a/selene-vscode/src/configLint.ts +++ b/selene-vscode/src/configLint.ts @@ -15,6 +15,7 @@ export async function lintConfig( if ( document.languageId === "toml" && + !document.uri.path.endsWith(".selene.toml") && !document.uri.path.endsWith("selene.toml") ) { return @@ -81,4 +82,4 @@ export async function lintConfig( } diagnosticsCollection.set(document.uri, diagnostics) -} +} \ No newline at end of file diff --git a/selene-vscode/src/roblox.ts b/selene-vscode/src/roblox.ts index 90a1f8d7..5b8e5a5d 100644 --- a/selene-vscode/src/roblox.ts +++ b/selene-vscode/src/roblox.ts @@ -35,44 +35,52 @@ export function processDiagnostic( return } - const configFilename = vscode.Uri.joinPath( - workspace.uri, - "selene.toml", - ) + const configFilenames = [ + vscode.Uri.joinPath(workspace.uri, ".selene.toml"), + vscode.Uri.joinPath(workspace.uri, "selene.toml"), + ] let configContents: Uint8Array - - try { - configContents = await vscode.workspace.fs.readFile( - configFilename, - ) - } catch (error) { - if ( - error instanceof vscode.FileSystemError && - error.code === "FileNotFound" - ) { - configContents = new Uint8Array() - } else { - vscode.window.showErrorMessage( - `Couldn't read existing config, if there was one.\n\n${ - typeof error === "object" && error !== null + let configFilename: vscode.Uri | undefined + + for (const someConfigFilename of configFilenames) { + try { + configContents = await vscode.workspace.fs.readFile(someConfigFilename) + configFilename = someConfigFilename + break + } catch (error) { + if ( + error instanceof vscode.FileSystemError && + error.code === "FileNotFound" + ) { + continue + } else { + vscode.window.showErrorMessage( + `Couldn't read existing config, if there was one.\n\n${typeof error === "object" && error !== null ? error.toString() : error - }`, - ) - - return + }` + ) + return + } } } + if (!configFilename) { + configFilename = configFilenames[0] + configContents = new Uint8Array() + } + const contents = new TextDecoder().decode(configContents) vscode.workspace.fs.writeFile( configFilename, - new TextEncoder().encode(addRobloxLibrary(contents)), + new TextEncoder().encode(addRobloxLibrary(contents)) ) }) + + return true } @@ -103,4 +111,4 @@ function addRobloxLibrary(contents: string): string { return standardLibrarySet ? lines.join("\n") : `std = "roblox"\n${lines.join("\n")}` -} +} \ No newline at end of file diff --git a/selene/src/main.rs b/selene/src/main.rs index 610aeb8a..8fbe2eb1 100644 --- a/selene/src/main.rs +++ b/selene/src/main.rs @@ -1,3 +1,10 @@ +use codespan_reporting::{ + diagnostic::{ + Diagnostic as CodespanDiagnostic, Label as CodespanLabel, Severity as CodespanSeverity, + }, + term::DisplayStyle as CodespanDisplayStyle, +}; +use selene_lib::{lints::Severity, *}; use std::{ ffi::OsString, fmt, fs, @@ -8,14 +15,6 @@ use std::{ Arc, RwLock, }, }; - -use codespan_reporting::{ - diagnostic::{ - Diagnostic as CodespanDiagnostic, Label as CodespanLabel, Severity as CodespanSeverity, - }, - term::DisplayStyle as CodespanDisplayStyle, -}; -use selene_lib::{lints::Severity, *}; use structopt::{clap, StructOpt}; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; use threadpool::ThreadPool; @@ -391,6 +390,22 @@ fn read_file(checker: &Checker, filename: &Path) { ); } +fn read_config() -> Result<(String, PathBuf), String> { + const CONFIG_PATHS_TO_CHECK: [&str; 2] = [".selene.toml", "selene.toml"]; + + CONFIG_PATHS_TO_CHECK + .iter() + .find_map(|path_str| { + let path = Path::new(path_str); + + path.exists().then_some(match fs::read_to_string(path_str) { + Ok(contents) => Ok((contents, path.to_path_buf())), + Err(error) => Err(format!("Error reading config file: {error}")), + }) + }) + .unwrap_or(Err("No config file found".to_string())) +} + fn start(mut options: opts::Options) { *OPTIONS.write().unwrap() = Some(options.clone()); @@ -410,23 +425,16 @@ fn start(mut options: opts::Options) { std::process::exit(1); } - (config_contents, Path::new("-")) + (config_contents, Path::new("-").to_path_buf()) } else { - let config_path = Path::new("selene.toml"); - - let config_contents = match fs::read_to_string(config_path) { - Ok(contents) => contents, - Err(error) => { - error!("Error reading config file: {error}"); - std::process::exit(1); - } - }; - - (config_contents, config_path) + read_config().unwrap_or_else(|error| { + error!("{error}"); + std::process::exit(1); + }) }; if let Err(error) = validate_config::validate_config( - config_path, + &config_path, &config_contents, &std::env::current_dir().unwrap(), ) { @@ -517,15 +525,14 @@ fn start(mut options: opts::Options) { } } - None => match fs::read_to_string("selene.toml") { - Ok(config_contents) => match toml::from_str(&config_contents) { + None => match read_config() { + Ok((config_contents, _)) => match toml::from_str(&config_contents) { Ok(config) => (config, None), Err(error) => { error!("Config file not in correct format: {}", error); std::process::exit(1); } }, - Err(_) => (CheckerConfig::default(), None), }, };