From bbc91d22a3e3b86cf53fea296537d8c49d22457b Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sun, 14 Nov 2021 16:23:50 +0700 Subject: [PATCH] feat: initialize project --- .editorconfig | 11 ++ .github/FUNDING.yml | 1 + .github/workflows/ci.yml | 23 ++++ .gitignore | 1 + Cargo.lock | 106 +++++++++++++++ Cargo.toml | 16 +++ LICENSE | 21 +++ README.md | 35 +++++ src/main.rs | 269 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 483 insertions(+) create mode 100644 .editorconfig create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 src/main.rs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4045901 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +end_of_line = lf +indent_size = 2 +indent_style = space +tab_width = 4 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +max_line_length = 80 \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..3b4eb20 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +ko_fi: aldy505 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..09d392d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,23 @@ +name: CI + +on: + push: + branches: ["*"] + pull_request: + branches: ["*"] + +jobs: + Build: + name: API + runs-on: ubuntu-latest + container: rust:1.56-buster + timeout-minutes: 15 + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Check + run: cargo check + + - name: Build + run: cargo build diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..63e265e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,106 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "add-editorconfig" +version = "0.1.0" +dependencies = [ + "dirs", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3dd8a2f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "add-editorconfig" +version = "0.1.0" +description = "Generate .editorconfig file in current directory" +edition = "2018" +authors = ["Reinaldy Rafli "] +categories = ["command-line-utilities"] +license = "MIT" +homepage = "https://github.com/aldy505/add-editorconfig" +repository = "https://github.com/aldy505/add-editorconfig" + + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dirs = "4.0" \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7fe0727 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Reinaldy Rafli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e225c78 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# add-editorconfig + +Small and simple CLI app to generate .editorconfig based on a given settings. + +## Usage + +```sh +# Will create an .editorconfig in the current directory +$ add-editorconfig + +# Will create an .editorconfig with the default config from .editorconfig that +# exists on the home directory. +$ add-editorconfig default + +# Show help +$ add-editorconfig help + +# Show current version +$ add-editorconfig version +``` + +## Installation + +Yes, you'll need to build from source. + +1. Clone this repository. +2. Make sure to have Rust in your system. At this point of time, I have v1.54.0. +3. Run `cargo build`. +4. Run `sudo cp -v target/debug/add-editorconfig /usr/local/bin`. +If you're not running in Linux, try to check how to move file on your own. +5. Check it via `add-editorconfig version`. + +## License + +[MIT](./LICENSE) diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ee71fd2 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,269 @@ +use std::{env, fs::{self, File}, io::{self, Error, Write}, path::{Path, PathBuf}}; +extern crate dirs; + +#[derive(Debug,Clone)] +pub struct Settings { + end_of_line: String, + indent_size: i32, + indent_style: String, + tab_width: i32, + charset: String, + root: bool, + trim_trailing_whitespace: bool, + insert_final_newline: bool, + max_line_length: i32, +} + +fn main() { + let args: Vec = env::args().collect(); + let current_path: PathBuf = Path::new(".editorconfig").to_path_buf(); + + // Check if the user supplied any args + if args.len() > 1 { + if args[1] == "default" { + let default_path: PathBuf = dirs::home_dir().unwrap().join(".editorconfig"); + // Check if there is default editorconfig + // already exists on `~/.editorconfig` + if !Path::new(default_path.as_os_str()).exists() { + println!("Looks like there is no default .editorconfig on your home directory. Creating one.."); + let p: Settings = prompt(); + // If not, create one + match create_config(default_path, p.clone()) { + Ok(_) => println!("Successfully created .editorconfig on your home directory."), + Err(e) => println!("Error: {}", e) + } + + match create_config(current_path, p.clone()) { + Ok(_) => println!("Successfully created .editorconfig on current directory."), + Err(e) => println!("Error: {}", e) + } + + return; + } + + // If there is, print a message + println!("Using default .editorconfig...\n"); + match fs::read_to_string(default_path) { + Ok(s) => { + match create_config(current_path, parse_settings(s)) { + Ok(_) => println!("Successfully created .editorconfig"), + Err(e) => println!("Error: {}", e) + } + }, + Err(e) => println!("Error: {}", e), + } + return; + } else if args[1] == "version" || args[1] == "--version" || args[1] == "-v" { + println!("add-editorconfig 0.1.0"); + return; + } else if args[1] == "help" || args[1] == "--help" || args[1] == "-h" { + println!("add-editorconfig"); + println!("Small and simple CLI app to generate .editorconfig based on a given settings.\n"); + println!("Usage:"); + println!(" add-editorconfig - Create an .editorconfig in the current directory"); + println!(" add-editorconfig default - Create an .editorconfig with the default config"); + println!(" from .editorconfig that exists on the home directory."); + println!(" add-editorconfig help - Print this help command"); + println!(" add-editorconfig version - Show current version\n"); + println!("If you had encountered with any bugs, please open an issue at:"); + println!("https://github.com/aldy505/add-editorconfig"); + return; + } + + } + + let p: Settings = prompt(); + match create_config(current_path, p) { + Ok(_) => println!("Successfully created .editorconfig"), + Err(e) => println!("Error: {}", e) + } +} + +pub fn default_settings() -> Settings { + return Settings { + end_of_line: String::from("lf"), + indent_size: 4, + indent_style: String::from("space"), + tab_width: 4, + charset: String::from("utf-8"), + root: true, + trim_trailing_whitespace: true, + insert_final_newline: true, + max_line_length: 80 + }; +} + +pub fn prompt() -> Settings { + let mut settings: Settings = Settings { + ..default_settings() + }; + let mut temp = String::new(); + println!("Fill the config with the provided options."); + println!("Entering nothing will set the parameter to its' default value.\n"); + + // indent_style + print!("Indentation style (space / tabs): "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut temp).unwrap(); + if temp.trim() == "tabs" { + settings.indent_style = String::from("tabs"); + } else { + settings.indent_style = String::from("space"); + } + temp = String::from(""); + + // indent_size + print!("Indent size (number): "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut temp).unwrap(); + if temp.trim().parse::().is_ok() { + settings.indent_size = temp.trim().parse::().unwrap(); + } else { + settings.indent_size = 4; + } + temp = String::from(""); + + + // tab_width + print!("Tab width (number): "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut temp).unwrap(); + if temp.trim().parse::().is_ok() { + settings.tab_width = temp.trim().parse::().unwrap(); + } else { + settings.tab_width = 4; + } + temp = String::from(""); + + // tab_width + print!("End of line (lf / crlf / cr): "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut temp).unwrap(); + if temp.trim() == "lf" { + settings.end_of_line = String::from("lf"); + } else if temp.trim() == "crlf" { + settings.end_of_line = String::from("crlf"); + } else if temp.trim() == "cr" { + settings.end_of_line = String::from("cr"); + } else { + settings.end_of_line = String::from("lf"); + } + temp = String::from(""); + + // charset + print!("Charset (latin1 / utf-8 / utf-16be / utf-16le / utf-8-bom): "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut temp).unwrap(); + if temp.trim() == "latin1" { + settings.charset = String::from("latin1"); + } else if temp.trim() == "utf-8" { + settings.charset = String::from("utf-8"); + } else if temp.trim() == "utf-16be" { + settings.charset = String::from("utf-16be"); + } else if temp.trim() == "utf-16le" { + settings.charset = String::from("utf-16le"); + } else if temp.trim() == "utf-8-bom" { + settings.charset = String::from("utf-8-bom"); + } else { + settings.charset = String::from("utf-8"); + } + temp = String::from(""); + + // trim_trailing_whitespace + print!("Trim trailing whitespace (true / false): "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut temp).unwrap(); + if temp.trim() == "true" { + settings.trim_trailing_whitespace = true; + } else { + settings.trim_trailing_whitespace = false; + } + temp = String::from(""); + + // insert_final_newline + print!("Insert final newline (true / false): "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut temp).unwrap(); + if temp.trim() == "true" { + settings.insert_final_newline = true; + } else { + settings.insert_final_newline = false; + } + temp = String::from(""); + + // max_line_length + print!("Max line length (number): "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut temp).unwrap(); + if temp.trim().parse::().is_ok() { + settings.max_line_length = temp.trim().parse::().unwrap(); + } else { + settings.max_line_length = 80; + } + print!("\n"); + + return settings; +} + +pub fn create_config(path: PathBuf, settings: Settings) -> Result<(), Error> { + let mut file = File::create(path)?; + let config: Vec = vec![ + format!("root = {}", settings.root), + format!(""), + format!("[*]"), + format!("end_of_line = {}", settings.end_of_line), + format!("indent_size = {}", settings.indent_size), + format!("indent_style = {}", settings.indent_style), + format!("tab_width = {}", settings.tab_width), + format!("charset = {}", settings.charset), + format!("trim_trailing_whitespace = {}", settings.trim_trailing_whitespace), + format!("insert_final_newline = {}", settings.insert_final_newline), + format!("max_line_length = {}", settings.max_line_length), + ]; + let w = file.write_all(config.join("\n").as_bytes()); + return w; +} + +pub fn parse_settings(str: String) -> Settings { + let s: Vec<&str> = str.split_terminator("\n").collect(); + let mut settings: Settings = Settings { + ..default_settings() + }; + for x in s.iter() { + let kv = x.split("=").collect::>(); + match kv[0].trim() { + "end_of_line" => { + settings.end_of_line = kv[1].trim().to_string(); + }, + "indent_size" => { + settings.indent_size = kv[1].trim().parse::().unwrap(); + }, + "indent_style" => { + settings.indent_style = kv[1].trim().to_string(); + }, + "tab_width" => { + settings.tab_width = kv[1].trim().parse::().unwrap(); + }, + "charset" => { + settings.charset = kv[1].trim().to_string(); + }, + "root" => { + settings.root = kv[1].trim().to_string().parse::().unwrap(); + }, + "trim_trailing_whitespace" => { + settings.trim_trailing_whitespace = kv[1].trim().parse::().unwrap(); + }, + "insert_final_newline" => { + settings.insert_final_newline = kv[1].trim().parse::().unwrap(); + }, + "max_line_length" => { + settings.max_line_length = kv[1].trim().parse::().unwrap(); + }, + _ => { + continue; + } + } + }; + + return settings; +}