mirror of
https://github.com/tauri-apps/web-view.git
synced 2026-02-04 10:21:17 +01:00
188 lines
5.7 KiB
Rust
188 lines
5.7 KiB
Rust
extern crate grep;
|
|
extern crate walkdir;
|
|
extern crate web_view;
|
|
#[macro_use]
|
|
extern crate serde_derive;
|
|
extern crate serde_json;
|
|
extern crate tinyfiledialogs as tfd;
|
|
|
|
use grep::regex::RegexMatcher;
|
|
use grep::searcher::sinks::UTF8;
|
|
use grep::searcher::{BinaryDetection, SearcherBuilder};
|
|
use std::error::Error;
|
|
use std::ffi::OsString;
|
|
use tfd::MessageBoxIcon;
|
|
use walkdir::WalkDir;
|
|
use web_view::*;
|
|
|
|
fn main() {
|
|
web_view::builder()
|
|
.title("Simple Grep Example")
|
|
.content(Content::Html(HTML))
|
|
.size(825, 625)
|
|
.resizable(true)
|
|
.debug(true)
|
|
.user_data(())
|
|
.invoke_handler(|webview, arg| {
|
|
use Cmd::*;
|
|
|
|
match serde_json::from_str(arg).unwrap() {
|
|
Search { pattern, path } => {
|
|
let result = match search(&pattern, OsString::from(path)) {
|
|
Ok(s) => s,
|
|
Err(err) => {
|
|
let err_str = format!("{}", err);
|
|
tfd::message_box_ok("Error", &err_str, MessageBoxIcon::Error);
|
|
OsString::from("")
|
|
}
|
|
};
|
|
if result.is_empty() {
|
|
tfd::message_box_ok(
|
|
"Information",
|
|
"No results were found!",
|
|
MessageBoxIcon::Info,
|
|
);
|
|
} else {
|
|
let eval_str = format!("LoadTextArea({:?});", result);
|
|
webview.eval(&eval_str)?;
|
|
}
|
|
}
|
|
|
|
Browse {} => match tfd::open_file_dialog("Please choose a file...", "", None) {
|
|
Some(path_selected) => {
|
|
let eval_str = format!("SetPath({:?});", path_selected);
|
|
webview.eval(&eval_str)?;
|
|
}
|
|
None => {
|
|
tfd::message_box_ok(
|
|
"Warning",
|
|
"You didn't choose a file.",
|
|
MessageBoxIcon::Warning,
|
|
);
|
|
}
|
|
},
|
|
|
|
Error { msg } => tfd::message_box_ok("Error", &msg, MessageBoxIcon::Error),
|
|
}
|
|
|
|
Ok(())
|
|
})
|
|
.run()
|
|
.unwrap();
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
#[serde(tag = "cmd", rename_all = "camelCase")]
|
|
pub enum Cmd {
|
|
Search { pattern: String, path: String },
|
|
Browse {},
|
|
Error { msg: String },
|
|
}
|
|
|
|
fn search(pattern: &str, path: OsString) -> Result<OsString, Box<dyn Error>> {
|
|
let matcher = RegexMatcher::new_line_matcher(&pattern)?;
|
|
let mut matches: OsString = OsString::new();
|
|
let mut searcher = SearcherBuilder::new()
|
|
.binary_detection(BinaryDetection::quit(b'\x00'))
|
|
.line_number(true)
|
|
.build();
|
|
|
|
let mut matched_line = OsString::new();
|
|
|
|
for result in WalkDir::new(path) {
|
|
let entry = match result {
|
|
Ok(entry) => entry,
|
|
Err(err) => {
|
|
let err_str = format!("{}", err);
|
|
tfd::message_box_ok("Error", &err_str, MessageBoxIcon::Error);
|
|
continue;
|
|
}
|
|
};
|
|
if !entry.file_type().is_file() {
|
|
continue;
|
|
}
|
|
|
|
match searcher.search_path(
|
|
&matcher,
|
|
entry.path(),
|
|
UTF8(|lnum, line| {
|
|
matched_line = OsString::from(format!(
|
|
"{:?}\t {}:\t {}",
|
|
entry.path(),
|
|
lnum.to_string(),
|
|
line.to_string()
|
|
));
|
|
matches.push(&matched_line);
|
|
matches.push("\n");
|
|
Ok(true)
|
|
}),
|
|
) {
|
|
Ok(()) => (),
|
|
Err(err) => {
|
|
let err_str = format!("{}: {:?}", err, entry.path());
|
|
tfd::message_box_ok("Error", &err_str, MessageBoxIcon::Error);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(matches)
|
|
}
|
|
|
|
const HTML: &str = r#"
|
|
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<style>
|
|
.textarea {
|
|
width: 100%;
|
|
height: 30em;
|
|
font-size: 1em;
|
|
}
|
|
</style>
|
|
<script type="text/javascript">
|
|
'use strict';
|
|
var rpc = {
|
|
invoke : function(arg) { window.external.invoke(JSON.stringify(arg)); },
|
|
search : function() {
|
|
var pattern = document.getElementById("pattern");
|
|
var path = document.getElementById("path");
|
|
if (pattern.value.trim().length === 0) {
|
|
rpc.error("No pattern entered!");
|
|
return;
|
|
}
|
|
if (path.value.trim().length === 0) {
|
|
rpc.error("No path entered!");
|
|
return;
|
|
}
|
|
var textArea = document.getElementById("text_box");
|
|
textArea.value = "";
|
|
rpc.invoke({cmd : 'search', path : path.value, pattern : pattern.value});
|
|
},
|
|
browse : function() { rpc.invoke({cmd : 'browse'}); },
|
|
error : function(msg) { rpc.invoke({cmd : 'error', msg : msg}); },
|
|
};
|
|
|
|
function LoadTextArea(data) {
|
|
var textArea = document.getElementById("text_box");
|
|
textArea.value = data;
|
|
}
|
|
function SetPath(path_selected) {
|
|
var path = document.getElementById("path");
|
|
path.value = path_selected;
|
|
}
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<label for="pattern">Pattern to search for:</label>
|
|
<input style="font-size:16px" id="pattern" type="text" size="35" />
|
|
<label style="font-size:14px"> (prefix text with "(?i)" to ignore case)</label><br><br>
|
|
<label for="path">Path (directory or file):</label>
|
|
<input id="path" type="text" size="70" />
|
|
<button onclick="rpc.browse()">Browse</button>
|
|
<button onclick="rpc.search()">Search</button>
|
|
<textarea class="textarea" id="text_box"></textarea>
|
|
</body>
|
|
</html>
|
|
"#;
|