Skip to content

Commit af40e98

Browse files
authored
Merge pull request #73 from umpire274/v0.5.2
Release v0.5.2 – New config edit command and improved configuration system
2 parents c7af9ec + 4110036 commit af40e98

File tree

14 files changed

+376
-63
lines changed

14 files changed

+376
-63
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "dev_tools"]
2+
path = dev_tools
3+
url = git@github.com:umpire274/rust_dev_scripts.git

CHANGELOG.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,39 @@
11
# Changelog
22

3+
## [0.5.2] - 2025-11-04
4+
5+
### Added
6+
7+
- New **`ConsoleLog`** utility for rich, colorized console output with Unicode symbols:
8+
-`info()` – Informational messages
9+
-`ok()` – Successful operations
10+
- ⚠️ `warn()` – Warnings and recoverable issues
11+
-`ko()` – Errors and critical failures
12+
- Integrated `ConsoleLog` throughout configuration, cache, and file management commands for consistent CLI feedback.
13+
- New subcommand **`config edit`** for editing the configuration file directly from the terminal:
14+
- `rfortune config edit` → opens `rfortune.conf` using the system’s default text editor.
15+
- `rfortune config edit --editor <name|path>` → opens it with a specific editor (e.g. `vi`, `nano`, `code`).
16+
- Automatic editor detection logic:
17+
- Checks `$VISUAL` and `$EDITOR` environment variables.
18+
- Falls back to **`nano`** on macOS/Linux and **`notepad`** on Windows.
19+
- Integrated colored console messages (`ConsoleLog`) for clear feedback during editing.
20+
21+
### Changed
22+
23+
- Configuration filename renamed from **`config.yaml`****`rfortune.conf`** for better clarity and platform
24+
consistency.
25+
- Updated initialization logic to automatically migrate existing `config.yaml` to the new format (backup saved as
26+
`config.yaml.bak`).
27+
- Unified editor behavior across platforms for a consistent CLI experience.
28+
- Improved user feedback when creating or editing the configuration file.
29+
30+
### Fixed
31+
32+
- Improved user feedback during `config init`, `file init`, and `cache clear` operations to prevent duplicate or missing
33+
log messages.
34+
35+
---
36+
337
## [0.5.1] - 2025-10-27
438

539
### Added

Cargo.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "rfortune"
3-
version = "0.5.1"
3+
version = "0.5.2"
44
edition = "2024"
55
authors = ["Umpire274 <umpire274@gmail.com>"]
66
description = "A Rust-based clone of the classic UNIX 'fortune' command"
@@ -25,7 +25,7 @@ winresource = "0.1.23"
2525
Icon = "res/rfortune.ico"
2626

2727
[dependencies]
28-
clap = { version = "4.5.50", features = ["derive"] }
28+
clap = { version = "4.5.51", features = ["derive"] }
2929
rand = "0.9.2"
3030
dirs = "6.0.0"
3131
serde = { version = "1.0.228", features = ["derive"] }

README.md

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,25 @@ scripting, or just a bit of inspiration.
1313
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS%20Intel%20%7C%20macOS%20Apple%20Silicon-blue)](https://github.com/umpire274/rFortune/releases)
1414
[![GitHub release](https://img.shields.io/github/v/release/umpire274/rfortune)](https://github.com/umpire274/rfortune/releases/latest)
1515

16+
---
17+
18+
## ✨ New in v0.5.2
19+
20+
### 🆕 Configuration system improvements
21+
22+
- Configuration filename renamed from config.yaml → rfortune.conf for better clarity and portability.
23+
- Automatic migration from legacy config.yaml to the new format — the old file is safely backed up as config.yaml.bak.
24+
- Added the new subcommand config edit:
25+
- rfortune config edit → opens rfortune.conf using the system’s default text editor.
26+
- rfortune config edit --editor <name|path> → opens it with a specific editor (e.g. vi, nano, code).
27+
- Automatic detection of preferred editors via $VISUAL and $EDITOR environment variables.
28+
- Default fallback editors are nano (macOS/Linux) and notepad (Windows).
29+
30+
### 🎨 Improved CLI feedback
31+
32+
- Introduced the new ConsoleLog class for rich, colored terminal output:
33+
- ℹ Info, ✅ Success, ⚠️ Warning, ❌ Error
34+
- Unified message style and improved feedback during configuration, cache, and fortune file operations.
1635

1736
---
1837

@@ -128,30 +147,37 @@ Running `rfortune` without subcommands prints a random fortune from the default
128147

129148
## 🧩 Options & Subcommands
130149

131-
| Command / Option | Description |
132-
|-----------------------|-------------------------------------------------------|
133-
| `-f`, `--file <PATH>` | Use a custom fortune file instead of the default |
134-
| `config init` | Create the configuration file with default options |
135-
| `file init` | Create a sample default fortune file (`rfortune.dat`) |
136-
| `cache clear` | Remove all cached last-used fortunes |
137-
| `-V`, `--version` | Show version information |
138-
| `-h`, `--help` | Show help message |
150+
| Command / Option | Description |
151+
|------------------------------|---------------------------------------------------------------------------|
152+
| `-f`, `--file <PATH>` | Use a custom fortune file instead of the default |
153+
| `config init` | Create the configuration file with default options |
154+
| `config edit [--editor <E>]` | Open the configuration file in the system’s default or a specified editor |
155+
| `file init` | Create a sample default fortune file (`rfortune.dat`) |
156+
| `cache clear` | Remove all cached last-used fortunes |
157+
| `-V`, `--version` | Show version information |
158+
| `-h`, `--help` | Show help message |
139159

140160
---
141161

142-
## 🧪 Examples
162+
## 💡 Examples
143163

144-
```sh
145-
# Print a random fortune from the default file
164+
```bash
165+
# Print a random fortune from the default file (rfortune.dat)
146166
rfortune
147167

148168
# Print a random fortune from a specific file
149169
rfortune --file ~/fortunes/misc
150170

151-
# Initialize configuration file
171+
# Create the default configuration file in the user data directory
152172
rfortune config init
153173

154-
# Create a sample default fortune file
174+
# Open the configuration file in the system’s default text editor
175+
rfortune config edit
176+
177+
# Open the configuration file with a specific editor (e.g. vi, nano, code)
178+
rfortune config edit --editor vi
179+
180+
# Create a sample default fortune file (rfortune.dat)
155181
rfortune file init
156182

157183
# Clear all cached last-used fortunes

dev_tools

Submodule dev_tools added at 7f8e961

src/cli.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,18 @@ must be separated by a line containing only the '%' character.\n\n\
1212
You can specify a custom fortune file with `--file`, or manage configuration, \
1313
fortune files, and cache using subcommands:\n\n \
1414
• `config init` Create a configuration file with default options.\n \
15+
• `config edit` Edit the configuration file using the system or a chosen editor.\n \
1516
• `file init` Create a sample default fortune file (rfortune.dat).\n \
1617
• `cache clear` Remove all cached last-used fortunes.\n\n\
1718
This makes it easy to test, customize and extend your fortune collections \
1819
while preserving the spirit of the original UNIX command.",
19-
after_help = "EXAMPLES:\n rfortune\n Print a random fortune from the default file (rfortune.dat).\n\n rfortune --file ~/fortunes/misc\n Print a random fortune from the file ~/fortunes/misc.\n\n rfortune config init\n Create a default configuration file in the user data directory.\n\n rfortune file init\n Create a sample fortune file (rfortune.dat) in the user data directory.\n\n rfortune cache clear\n Remove all cached last-used fortunes."
20+
after_help = "EXAMPLES:\n rfortune\n Print a random fortune from the default file (rfortune.dat).\n\n \
21+
rfortune --file ~/fortunes/misc\n Print a random fortune from the file ~/fortunes/misc.\n\n \
22+
rfortune config init\n Create a default configuration file in the user data directory.\n\n \
23+
rfortune config edit\n Open the configuration file in your default system editor.\n\n \
24+
rfortune config edit --editor vi\n Open the configuration file with a specific editor.\n\n \
25+
rfortune file init\n Create a sample fortune file (rfortune.dat) in the user data directory.\n\n \
26+
rfortune cache clear\n Remove all cached last-used fortunes."
2027
)]
2128
pub struct Cli {
2229
/// Fortune file to use instead of the default (rfortune.dat)
@@ -50,6 +57,13 @@ pub enum Commands {
5057
pub enum ConfigAction {
5158
/// Initialize the configuration file
5259
Init,
60+
61+
/// Edit the configuration file with the system or custom editor
62+
Edit {
63+
/// Specify a custom editor name or path
64+
#[arg(short, long)]
65+
editor: Option<String>,
66+
},
5367
}
5468

5569
#[derive(Subcommand, Debug)]

src/commands.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
11
use crate::{config, utils};
2+
use rfortune::log::ConsoleLog;
23

34
pub fn run_config_init() {
5+
ConsoleLog::info("Initializing configuration file...");
46
if let Err(e) = config::init_config_file() {
5-
eprintln!("Error initializing config: {e}");
7+
ConsoleLog::ko(format!("Error initializing config: {e}"));
68
}
79
}
810

911
pub fn run_file_init() {
12+
ConsoleLog::info("Initializing default fortune file...");
1013
if let Err(e) = config::init_default_file() {
11-
eprintln!("Error initializing fortune file: {e}");
14+
ConsoleLog::ko(format!("Error initializing fortune file: {e}"));
1215
}
1316
}
1417

1518
pub fn run_cache_clear() {
19+
ConsoleLog::info("Clearing cache directory...");
1620
if let Err(e) = utils::clear_cache_dir() {
17-
eprintln!("Error clearing cache: {e}");
21+
ConsoleLog::ko(format!("Error clearing cache: {e}"));
22+
}
23+
}
24+
25+
pub(crate) fn run_config_edit(editor: Option<String>) {
26+
ConsoleLog::info("Clearing cache directory...");
27+
if let Err(e) = config::run_config_edit(editor) {
28+
ConsoleLog::ko(format!("Error opening config in editor: {e}"));
1829
}
1930
}

src/config.rs

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
use crate::log::ConsoleLog;
12
use dirs::data_dir;
23
use serde::{Deserialize, Serialize};
3-
use std::fs;
44
use std::path::PathBuf;
5+
use std::process::Command;
6+
use std::{env, fs};
57

68
#[derive(Debug, Serialize, Deserialize)]
79
pub struct Config {
@@ -24,7 +26,7 @@ pub(crate) fn app_dir() -> PathBuf {
2426

2527
pub fn get_config_path() -> PathBuf {
2628
let mut p = app_dir();
27-
p.push("config.yaml");
29+
p.push("rfortune.conf");
2830
p
2931
}
3032

@@ -40,9 +42,18 @@ pub fn init_config_file() -> std::io::Result<()> {
4042
let dir = app_dir();
4143
fs::create_dir_all(&dir)?;
4244

45+
if let Err(e) = migrate_old_config() {
46+
ConsoleLog::warn(format!("Migration warning: {e}"));
47+
}
48+
4349
let path = get_config_path();
4450
if path.exists() {
45-
return Ok(()); // non sovrascrivere
51+
ConsoleLog::info("Configuration file already exists, skipping.");
52+
return Ok(());
53+
}
54+
55+
if let Err(e) = init_default_file() {
56+
ConsoleLog::ko(format!("Error initializing fortune file: {e}"));
4657
}
4758

4859
let cfg = Config {
@@ -51,7 +62,10 @@ pub fn init_config_file() -> std::io::Result<()> {
5162
use_cache: Some(true),
5263
};
5364
let yaml = serde_yaml::to_string(&cfg).expect("Failed to serialize config");
54-
fs::write(path, yaml)
65+
fs::write(path, yaml)?;
66+
67+
ConsoleLog::ok("Configuration file successfully created.");
68+
Ok(())
5569
}
5670

5771
/// Crea un file fortune di esempio (rfortune.dat) se assente
@@ -81,3 +95,98 @@ pub fn load_config() -> Option<Config> {
8195
let content = fs::read_to_string(path).ok()?;
8296
serde_yaml::from_str(&content).ok()
8397
}
98+
99+
/// Tenta di migrare una vecchia configurazione `config.yaml` a `rfortune.conf`
100+
pub fn migrate_old_config() -> std::io::Result<()> {
101+
let dir = app_dir();
102+
let old_path = dir.join("config.yaml");
103+
let new_path = get_config_path();
104+
105+
// Se non c'è un vecchio file o esiste già il nuovo, non fare nulla
106+
if !old_path.exists() || new_path.exists() {
107+
return Ok(());
108+
}
109+
110+
ConsoleLog::info("Old configuration file detected — attempting migration…");
111+
112+
// Legge e prova a deserializzare il vecchio file
113+
match fs::read_to_string(&old_path) {
114+
Ok(content) => match serde_yaml::from_str::<Config>(&content) {
115+
Ok(cfg) => {
116+
// Serializza e salva nel nuovo formato
117+
let yaml =
118+
serde_yaml::to_string(&cfg).expect("Failed to serialize migrated config");
119+
fs::write(&new_path, yaml)?;
120+
121+
// Rinomina il vecchio file come backup
122+
let backup = dir.join("config.yaml.bak");
123+
fs::rename(&old_path, &backup)?;
124+
125+
ConsoleLog::ok(format!(
126+
"Configuration migrated successfully → {:?}",
127+
new_path
128+
));
129+
ConsoleLog::info(format!("Backup saved as {:?}", backup));
130+
}
131+
Err(e) => {
132+
ConsoleLog::ko(format!("Failed to parse old config.yaml: {e}"));
133+
}
134+
},
135+
Err(e) => {
136+
ConsoleLog::ko(format!("Failed to read old config.yaml: {e}"));
137+
}
138+
}
139+
140+
Ok(())
141+
}
142+
143+
/// Apre il file di configurazione in modifica.
144+
/// Se viene specificato `--editor`, usa quello; altrimenti tenta di rilevare l’editor di sistema.
145+
pub fn run_config_edit(editor_arg: Option<String>) -> std::io::Result<()> {
146+
let path: PathBuf = get_config_path();
147+
148+
// Se non esiste, crealo
149+
if !path.exists() {
150+
ConsoleLog::warn("Configuration file not found. Creating a new one...");
151+
if let Err(e) = init_config_file() {
152+
ConsoleLog::ko(format!("Failed to create configuration file: {e}"))
153+
}
154+
}
155+
156+
// 1️⃣ Priorità all'argomento CLI --editor
157+
let editor = if let Some(e) = editor_arg {
158+
e
159+
} else {
160+
// 2️⃣ Poi variabili d'ambiente VISUAL o EDITOR
161+
if let Ok(visual) = env::var("VISUAL") {
162+
visual
163+
} else if let Ok(editor) = env::var("EDITOR") {
164+
editor
165+
} else {
166+
// 3️⃣ Fallback per piattaforma
167+
if cfg!(target_os = "windows") {
168+
"notepad".to_string()
169+
} else {
170+
"nano".to_string()
171+
}
172+
}
173+
};
174+
175+
ConsoleLog::info(format!(
176+
"Opening configuration file with editor: {}",
177+
editor
178+
));
179+
180+
// 4️⃣ Avvia l’editor
181+
let status = Command::new(&editor)
182+
.arg(path.to_string_lossy().to_string())
183+
.status();
184+
185+
match status {
186+
Ok(s) if s.success() => ConsoleLog::ok("Configuration file closed successfully."),
187+
Ok(_) => ConsoleLog::warn("Editor exited with a non-zero status code."),
188+
Err(e) => ConsoleLog::ko(format!("Failed to launch editor '{}': {e}", editor)),
189+
}
190+
191+
Ok(())
192+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pub mod config;
22
pub mod loader;
3+
pub mod log;
34
pub mod utils;

0 commit comments

Comments
 (0)