handle file from cli args
All checks were successful
Build / Build - linux (push) Successful in 3m34s
Build / Build - windows (push) Successful in 1m36s

This commit is contained in:
2026-01-05 13:51:01 +01:00
parent 8affad428e
commit 576e5819b2
6 changed files with 447 additions and 10 deletions

129
Cargo.lock generated
View File

@@ -172,6 +172,56 @@ dependencies = [
"libc",
]
[[package]]
name = "anstream"
version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
[[package]]
name = "anstyle-parse"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys 0.61.2",
]
[[package]]
name = "arboard"
version = "3.6.1"
@@ -674,6 +724,46 @@ dependencies = [
"windows-link",
]
[[package]]
name = "clap"
version = "4.5.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.111",
]
[[package]]
name = "clap_lex"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
[[package]]
name = "clipboard-win"
version = "5.4.1"
@@ -693,6 +783,12 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "colorchoice"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "com"
version = "0.6.0"
@@ -1515,6 +1611,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.5.2"
@@ -1691,6 +1793,12 @@ dependencies = [
"hashbrown 0.16.1",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "itoa"
version = "1.0.15"
@@ -2300,6 +2408,12 @@ version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "once_cell_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "orbclient"
version = "0.3.49"
@@ -2706,9 +2820,10 @@ dependencies = [
[[package]]
name = "rlogg"
version = "0.3.1"
version = "0.4.0"
dependencies = [
"chrono",
"clap",
"eframe",
"rayon",
"regex",
@@ -3007,6 +3122,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "1.0.109"
@@ -3279,6 +3400,12 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.18.1"

View File

@@ -1,6 +1,6 @@
[package]
name = "rlogg"
version = "0.3.1"
version = "0.4.0"
edition = "2024"
authors = ["Stanislav Pastushenko <staspast1@gmail.com>"]
description = "A fast log file viewer with search, filtering, and highlighting capabilities"
@@ -18,6 +18,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
rayon = "1.10"
chrono = "0.4"
clap = { version = "4.5", features = ["derive"] }
[profile.release]
debug = false

248
README.md
View File

@@ -1,3 +1,247 @@
# rlogg
# RLogg - Fast Log File Viewer
A fast log file viewer with search, filtering, and highlighting capabilities
A fast, native log file viewer with search, filtering, and highlighting capabilities built with Rust and egui.
## Features
- **Fast Performance**: Handle large log files (GB+) with efficient line indexing
- **Advanced Search**: Regex support, case-sensitive/insensitive search, date range filtering
- **Syntax Highlighting**: Custom highlight rules with regex patterns
- **Multiple Tabs**: Open and view multiple log files simultaneously
- **Export Results**: Export filtered/searched results to new files
- **Cross-Platform**: Native builds for Linux, Windows, and macOS
- **Command-Line Interface**: Open files directly from terminal or OS file associations
## Installation
### From Source
1. **Clone the repository:**
```bash
git clone https://github.com/yourusername/rlogg.git
cd rlogg
```
2. **Build in release mode:**
```bash
cargo build --release
```
3. **The binary will be available at:**
```
target/release/rlogg
```
### Linux
#### Quick Install (User-Local)
```bash
cargo build --release
cd packaging/linux
./install.sh
```
This will:
- Install `rlogg` to `~/.local/bin/`
- Set up file associations for `.log` files
- Configure desktop integration
Make sure `~/.local/bin` is in your PATH:
```bash
export PATH="$HOME/.local/bin:$PATH"
```
#### System-Wide Install
```bash
sudo cp target/release/rlogg /usr/local/bin/
sudo cp packaging/linux/rlogg.desktop /usr/share/applications/
sudo cp packaging/linux/text-x-log.xml /usr/share/mime/packages/
sudo update-desktop-database /usr/share/applications
sudo update-mime-database /usr/share/mime
```
### Windows
1. **Build the project:**
```powershell
cargo build --release
```
2. **Run the installation script:**
```powershell
cd packaging\windows
powershell -ExecutionPolicy Bypass -File install.ps1
```
This will:
- Install RLogg to `%LOCALAPPDATA%\Programs\RLogg`
- Create file associations for `.log` files
- Add "Open with RLogg" to the context menu
## Usage
### Graphical Interface
**Launch without arguments:**
```bash
rlogg
```
Then use the "Open File" button to select log files.
### Command-Line Interface
**Open a single file:**
```bash
rlogg /path/to/file.log
```
**Open multiple files (each in a separate tab):**
```bash
rlogg file1.log file2.log file3.log
```
**Open all log files in a directory:**
```bash
rlogg /var/log/*.log
```
**Get help:**
```bash
rlogg --help
```
**Check version:**
```bash
rlogg --version
```
### File Associations
After installation, you can:
- **Double-click** `.log` files to open them in RLogg
- **Right-click** → "Open With" → RLogg
- **Drag and drop** multiple log files onto the RLogg icon
See [docs/FILE_ASSOCIATIONS.md](docs/FILE_ASSOCIATIONS.md) for detailed setup and troubleshooting.
## Features Guide
### Search
1. Enter search query in the search panel
2. Choose case-sensitive or regex mode
3. Optionally enable date range filtering
4. Results are highlighted and filtered in real-time
### Highlighting
1. Click "Highlight Rules" to open the editor
2. Add custom regex patterns with colors
3. Rules are applied to all open files
4. Perfect for highlighting errors, warnings, etc.
### Tabs
- Open multiple files simultaneously
- Each file maintains its own search/filter state
- Close tabs with the × button
- Switch between tabs with mouse or keyboard
### Export
- Export filtered/searched results to a new file
- Preserves line formatting
- Useful for extracting specific log entries
## Building
### Prerequisites
- Rust 1.70 or later
- Cargo
### Build Commands
**Development build:**
```bash
cargo build
```
**Release build (optimized):**
```bash
cargo build --release
```
**Run directly:**
```bash
cargo run -- /path/to/file.log
```
**Run tests:**
```bash
cargo test
```
See [BUILD.md](BUILD.md) for detailed build instructions.
## Packaging
See [packaging/README.md](packaging/README.md) for instructions on creating distribution packages:
- Linux: `.deb`, `.rpm`, AppImage, tarballs
- Windows: Installers, ZIP archives
## Configuration
RLogg stores configuration in `rlogg_config.json` next to the executable:
- Search history
- Highlight rules
- UI preferences
- Date format settings
## Troubleshooting
### Linux
**File associations not working:**
```bash
update-desktop-database ~/.local/share/applications
update-mime-database ~/.local/share/mime
```
**Binary not found:**
Ensure `~/.local/bin` is in your PATH.
### Windows
**File associations not working:**
1. Restart File Explorer
2. Check registry entries (see [docs/FILE_ASSOCIATIONS.md](docs/FILE_ASSOCIATIONS.md))
**Permission errors:**
Run PowerShell as Administrator or install to user directory.
For more troubleshooting, see [docs/FILE_ASSOCIATIONS.md](docs/FILE_ASSOCIATIONS.md).
## Contributing
Contributions are welcome! Please:
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Run tests and formatting
5. Submit a pull request
## License
MIT OR Apache-2.0
## Acknowledgments
Built with:
- [eframe](https://github.com/emilk/egui/tree/master/crates/eframe) - GUI framework
- [egui](https://github.com/emilk/egui) - Immediate mode GUI library
- [rfd](https://github.com/PolyMeilex/rfd) - Native file dialogs
- [clap](https://github.com/clap-rs/clap) - Command-line argument parsing

View File

@@ -1,10 +1,11 @@
use std::sync::Arc;
use std::path::PathBuf;
use eframe::egui;
use crate::config::AppConfig;
use crate::file_tab::FileTab;
use crate::highlight::HighlightManager;
use crate::search::{add_to_history, start_search, SearchParams, SearchState};
use crate::tab_manager::{close_tab, open_file_dialog, IndexingState};
use crate::tab_manager::{close_tab, open_file, open_file_dialog, IndexingState};
use crate::ui::{render_highlight_editor, render_search_panel, render_tabs_panel, render_top_menu, SearchPanelState};
use crate::ui::log_panel::{render_filter_panel, render_main_log_panel};
@@ -16,6 +17,7 @@ pub struct LogViewerApp {
search_state: SearchState,
highlight_manager: HighlightManager,
first_frame: bool,
file_open_errors: Vec<String>,
}
struct KeyAction {
@@ -34,9 +36,30 @@ impl KeyAction {
}
impl LogViewerApp {
pub fn new(config: AppConfig) -> Self {
pub fn new(config: AppConfig, initial_files: Vec<PathBuf>) -> Self {
let indexing_state = IndexingState::new();
let mut tabs = Vec::new();
let mut file_open_errors = Vec::new();
// Open initial files from command line
for file_path in initial_files {
if file_path.exists() {
if file_path.is_file() {
if let Some(tab) = open_file(file_path.clone(), &indexing_state) {
tabs.push(tab);
} else {
file_open_errors.push(format!("Failed to open: {}", file_path.display()));
}
} else {
file_open_errors.push(format!("Not a file: {}", file_path.display()));
}
} else {
file_open_errors.push(format!("File not found: {}", file_path.display()));
}
}
Self {
tabs: Vec::new(),
tabs,
active_tab_index: 0,
search_panel_state: SearchPanelState {
query: config.last_search_query,
@@ -48,10 +71,11 @@ impl LogViewerApp {
date_from: config.date_from,
date_to: config.date_to,
},
indexing_state: IndexingState::new(),
indexing_state,
search_state: SearchState::new(),
highlight_manager: HighlightManager::new(config.highlight_rules),
first_frame: true,
file_open_errors,
}
}
@@ -246,6 +270,32 @@ impl LogViewerApp {
self.first_frame = false;
ctx.send_viewport_cmd(egui::ViewportCommand::Maximized(true));
}
// Display file opening errors if any
if !self.file_open_errors.is_empty() {
egui::Window::new("File Opening Errors")
.collapsible(false)
.resizable(false)
.anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
.show(ctx, |ui| {
ui.label("The following files could not be opened:");
ui.add_space(10.0);
egui::ScrollArea::vertical()
.max_height(300.0)
.show(ui, |ui| {
for error in &self.file_open_errors {
ui.label(error);
}
});
ui.add_space(10.0);
if ui.button("OK").clicked() {
self.file_open_errors.clear();
}
});
}
}
}

View File

@@ -13,11 +13,25 @@ mod ui;
mod log_viewer_app;
use eframe::egui;
use clap::Parser;
use std::path::PathBuf;
use crate::log_viewer_app::LogViewerApp;
use config::AppConfig;
#[derive(Parser)]
#[command(name = "rlogg")]
#[command(version, about = "A fast log file viewer with search, filtering, and highlighting")]
struct Cli {
/// Log files to open on startup
#[arg(value_name = "FILES")]
files: Vec<PathBuf>,
}
fn main() -> eframe::Result {
// Parse command-line arguments
let cli = Cli::parse();
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([1200.0, 800.0])
@@ -28,13 +42,14 @@ fn main() -> eframe::Result {
};
let config = AppConfig::load();
let initial_files = cli.files;
eframe::run_native(
"RLogg",
options,
Box::new(move |cc| {
theme::apply_theme(&cc.egui_ctx);
Ok(Box::new(LogViewerApp::new(config)))
Ok(Box::new(LogViewerApp::new(config, initial_files)))
}),
)
}

View File

@@ -42,7 +42,7 @@ pub fn open_file_dialog(indexing_state: &IndexingState) -> Option<FileTab> {
open_file(path, indexing_state)
}
fn open_file(path: PathBuf, indexing_state: &IndexingState) -> Option<FileTab> {
pub fn open_file(path: PathBuf, indexing_state: &IndexingState) -> Option<FileTab> {
indexing_state.start_indexing();
// Background indexing for progress indication