added yaml,json + configurable keys
This commit is contained in:
191
src/main.rs
191
src/main.rs
@@ -1,53 +1,93 @@
|
||||
mod app;
|
||||
mod cli;
|
||||
mod config;
|
||||
mod env;
|
||||
mod format;
|
||||
mod runner;
|
||||
mod ui;
|
||||
|
||||
use app::{App, Mode};
|
||||
use app::App;
|
||||
use config::load_config;
|
||||
use env::{merge_env, parse_env_example, write_env};
|
||||
use format::{detect_format, get_handler};
|
||||
use runner::AppRunner;
|
||||
use std::error::Error;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crossterm::{
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
|
||||
event::{DisableMouseCapture, EnableMouseCapture},
|
||||
execute,
|
||||
terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
|
||||
};
|
||||
use ratatui::{
|
||||
Terminal,
|
||||
backend::{Backend, CrosstermBackend},
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use ratatui::{backend::CrosstermBackend, Terminal};
|
||||
|
||||
fn determine_output_path(input: &Path) -> PathBuf {
|
||||
let file_name = input.file_name().unwrap_or_default().to_string_lossy();
|
||||
if file_name == ".env.example" {
|
||||
return input.with_file_name(".env");
|
||||
}
|
||||
if file_name == "docker-compose.yml" {
|
||||
return input.with_file_name("docker-compose.override.yml");
|
||||
}
|
||||
if file_name == "docker-compose.yaml" {
|
||||
return input.with_file_name("docker-compose.override.yaml");
|
||||
}
|
||||
if file_name.ends_with(".example.json") {
|
||||
return input.with_file_name(file_name.replace(".example.json", ".json"));
|
||||
}
|
||||
if file_name.ends_with(".template.json") {
|
||||
return input.with_file_name(file_name.replace(".template.json", ".json"));
|
||||
}
|
||||
input.with_extension(format!(
|
||||
"{}.out",
|
||||
input.extension().unwrap_or_default().to_string_lossy()
|
||||
))
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let example_path = ".env.example";
|
||||
let env_path = ".env";
|
||||
let args = cli::parse();
|
||||
|
||||
// Load vars
|
||||
let mut vars = parse_env_example(example_path).unwrap_or_else(|_| vec![]);
|
||||
if vars.is_empty() {
|
||||
println!("No variables found in .env.example or file does not exist.");
|
||||
println!("Please run this tool in a directory with a valid .env.example file.");
|
||||
let input_path = args.input;
|
||||
if !input_path.exists() {
|
||||
println!("Input file does not exist: {}", input_path.display());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Merge existing .env if present
|
||||
let _ = merge_env(env_path, &mut vars);
|
||||
let format_type = detect_format(&input_path, args.format);
|
||||
let handler = get_handler(format_type);
|
||||
|
||||
let output_path = args
|
||||
.output
|
||||
.unwrap_or_else(|| determine_output_path(&input_path));
|
||||
|
||||
let mut vars = handler.parse(&input_path).unwrap_or_else(|err| {
|
||||
println!("Error parsing input file: {}", err);
|
||||
vec![]
|
||||
});
|
||||
|
||||
if vars.is_empty() {
|
||||
println!(
|
||||
"No variables found in {} or file could not be parsed.",
|
||||
input_path.display()
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Err(e) = handler.merge(&output_path, &mut vars) {
|
||||
println!("Warning: Could not merge existing output file: {}", e);
|
||||
}
|
||||
|
||||
let config = load_config();
|
||||
let mut app = App::new(vars);
|
||||
|
||||
// Setup terminal
|
||||
enable_raw_mode()?;
|
||||
let mut stdout = io::stdout();
|
||||
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
|
||||
let backend = CrosstermBackend::new(stdout);
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
|
||||
// Run app
|
||||
let res = run_app(&mut terminal, &mut app, &config, env_path);
|
||||
let mut runner = AppRunner::new(&mut terminal, &mut app, &config, &output_path, handler.as_ref());
|
||||
let res = runner.run();
|
||||
|
||||
// Restore terminal
|
||||
disable_raw_mode()?;
|
||||
execute!(
|
||||
terminal.backend_mut(),
|
||||
@@ -62,110 +102,3 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_app<B: Backend>(
|
||||
terminal: &mut Terminal<B>,
|
||||
app: &mut App,
|
||||
config: &config::Config,
|
||||
env_path: &str,
|
||||
) -> io::Result<()>
|
||||
where
|
||||
io::Error: From<B::Error>,
|
||||
{
|
||||
// For handling commands like :w, :q
|
||||
let mut command_buffer = String::new();
|
||||
|
||||
loop {
|
||||
terminal.draw(|f| ui::draw(f, app, config))?;
|
||||
|
||||
if let Event::Key(key) = event::read()? {
|
||||
match app.mode {
|
||||
Mode::Normal => {
|
||||
if !command_buffer.is_empty() {
|
||||
if key.code == KeyCode::Enter {
|
||||
match command_buffer.as_str() {
|
||||
":w" => {
|
||||
if write_env(env_path, &app.vars).is_ok() {
|
||||
app.status_message = Some("Saved to .env".to_string());
|
||||
} else {
|
||||
app.status_message =
|
||||
Some("Error saving to .env".to_string());
|
||||
}
|
||||
}
|
||||
":q" => return Ok(()),
|
||||
":wq" => {
|
||||
write_env(env_path, &app.vars)?;
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
app.status_message = Some("Unknown command".to_string());
|
||||
}
|
||||
}
|
||||
command_buffer.clear();
|
||||
} else if key.code == KeyCode::Esc {
|
||||
command_buffer.clear();
|
||||
app.status_message = None;
|
||||
} else if key.code == KeyCode::Backspace {
|
||||
command_buffer.pop();
|
||||
if command_buffer.is_empty() {
|
||||
app.status_message = None;
|
||||
} else {
|
||||
app.status_message = Some(command_buffer.clone());
|
||||
}
|
||||
} else if let KeyCode::Char(c) = key.code {
|
||||
command_buffer.push(c);
|
||||
app.status_message = Some(command_buffer.clone());
|
||||
}
|
||||
} else {
|
||||
match key.code {
|
||||
KeyCode::Char('q') => return Ok(()),
|
||||
KeyCode::Char('j') | KeyCode::Down => app.next(),
|
||||
KeyCode::Char('k') | KeyCode::Up => app.previous(),
|
||||
KeyCode::Char('i') => {
|
||||
app.enter_insert();
|
||||
app.status_message = None;
|
||||
}
|
||||
KeyCode::Char(':') => {
|
||||
command_buffer.push(':');
|
||||
app.status_message = Some(command_buffer.clone());
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
// Default action for Enter in Normal mode is save
|
||||
if write_env(env_path, &app.vars).is_ok() {
|
||||
app.status_message = Some("Saved to .env".to_string());
|
||||
} else {
|
||||
app.status_message = Some("Error saving to .env".to_string());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Mode::Insert => match key.code {
|
||||
KeyCode::Esc => {
|
||||
app.enter_normal();
|
||||
}
|
||||
KeyCode::Char(c) => {
|
||||
if let Some(var) = app.vars.get_mut(app.selected) {
|
||||
var.value.push(c);
|
||||
}
|
||||
}
|
||||
KeyCode::Backspace => {
|
||||
if let Some(var) = app.vars.get_mut(app.selected) {
|
||||
var.value.pop();
|
||||
}
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
app.enter_normal();
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if !app.running {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user