aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock136
-rw-r--r--htmlua-parser/Cargo.toml3
-rw-r--r--htmlua-parser/src/config.rs98
-rw-r--r--htmlua-parser/src/helpers.rs3
-rw-r--r--htmlua-parser/src/lib.rs1
-rw-r--r--htmlua-parser/src/render.rs11
-rw-r--r--htmlua-parser/src/serve.rs32
7 files changed, 257 insertions, 27 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2ae966a..d31c5bd 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -226,6 +226,27 @@ dependencies = [
]
[[package]]
+name = "dirs"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -558,6 +579,7 @@ name = "htmlua-parser"
version = "0.1.0"
dependencies = [
"anyhow",
+ "dirs",
"html5ever 0.35.0",
"httptest",
"kuchikiki",
@@ -569,6 +591,7 @@ dependencies = [
"serde_json",
"syntect",
"tendril",
+ "toml",
]
[[package]]
@@ -920,6 +943,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
+name = "libredox"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638"
+dependencies = [
+ "bitflags 2.9.1",
+ "libc",
+]
+
+[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1210,6 +1243,12 @@ dependencies = [
]
[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
name = "ordered-float"
version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1397,9 +1436,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "plist"
-version = "1.7.3"
+version = "1.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "546b279bf0638ee811d9e47de2ca5b66575a543035d79fdf83959dd2f5c3b4c3"
+checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1"
dependencies = [
"base64",
"indexmap 2.10.0",
@@ -1474,9 +1513,9 @@ checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
[[package]]
name = "quick-xml"
-version = "0.37.5"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb"
+checksum = "8927b0664f5c5a98265138b7e3f90aa19a6b21353182469ace36d4ac527b7b1b"
dependencies = [
"memchr",
]
@@ -1587,6 +1626,17 @@ dependencies = [
]
[[package]]
+name = "redox_users"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
+dependencies = [
+ "getrandom 0.2.16",
+ "libredox",
+ "thiserror 2.0.12",
+]
+
+[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1866,6 +1916,15 @@ dependencies = [
]
[[package]]
+name = "serde_spanned"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
+dependencies = [
+ "serde",
+]
+
+[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2023,7 +2082,7 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
- "thiserror",
+ "thiserror 1.0.69",
"walkdir",
"yaml-rust",
]
@@ -2085,7 +2144,16 @@ version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
- "thiserror-impl",
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+dependencies = [
+ "thiserror-impl 2.0.12",
]
[[package]]
@@ -2100,6 +2168,17 @@ dependencies = [
]
[[package]]
+name = "thiserror-impl"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
+[[package]]
name = "time"
version = "0.3.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2203,6 +2282,45 @@ dependencies = [
]
[[package]]
+name = "toml"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac"
+dependencies = [
+ "indexmap 2.10.0",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_parser",
+ "toml_writer",
+ "winnow",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30"
+dependencies = [
+ "winnow",
+]
+
+[[package]]
+name = "toml_writer"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
+
+[[package]]
name = "tower"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2676,6 +2794,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]]
+name = "winnow"
+version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
+
+[[package]]
name = "winsafe"
version = "0.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/htmlua-parser/Cargo.toml b/htmlua-parser/Cargo.toml
index 4ee6be3..8200513 100644
--- a/htmlua-parser/Cargo.toml
+++ b/htmlua-parser/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2024"
[dependencies]
anyhow = "1.0.98"
+dirs = "6.0.0"
html5ever = "0.35.0"
httptest = "0.16.3"
kuchikiki = "0.8.2"
@@ -16,7 +17,7 @@ serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
syntect = "5.2.0"
tendril = "0.4.3"
-
+toml = "0.9.2"
[lints.clippy]
pedantic = { level = "warn", priority = -1 }
diff --git a/htmlua-parser/src/config.rs b/htmlua-parser/src/config.rs
new file mode 100644
index 0000000..70ea7a8
--- /dev/null
+++ b/htmlua-parser/src/config.rs
@@ -0,0 +1,98 @@
+use anyhow::{Context, Result};
+use serde::{Deserialize, Serialize};
+use std::{fs, path::PathBuf};
+
+#[derive(Debug, Deserialize, Serialize, Clone)]
+pub struct Config {
+ pub paths: PathConfig,
+ pub server: ServerConfig,
+ pub syntax_highlighting: SyntaxConfig,
+}
+
+#[derive(Debug, Deserialize, Serialize, Clone)]
+pub struct PathConfig {
+ pub pages: PathBuf,
+ pub components: PathBuf,
+ pub themes: PathBuf,
+}
+
+#[derive(Debug, Deserialize, Serialize, Clone)]
+pub struct ServerConfig {
+ pub host: String,
+ pub port: u16,
+}
+
+#[derive(Debug, Deserialize, Serialize, Clone)]
+pub struct SyntaxConfig {
+ pub default_theme: String,
+ pub load_custom_themes: bool,
+}
+
+impl Default for Config {
+ fn default() -> Self {
+ Self {
+ paths: PathConfig {
+ pages: PathBuf::from("/var/www/htmlua/pages"),
+ components: PathBuf::from("/var/www/htmlua/components"),
+ themes: PathBuf::from("/var/www/htmlua/themes"),
+ },
+ server: ServerConfig {
+ host: "127.0.0.1".to_string(),
+ port: 8080,
+ },
+ syntax_highlighting: SyntaxConfig {
+ default_theme: "base16-ocean.dark".to_string(),
+ load_custom_themes: true,
+ },
+ }
+ }
+}
+
+impl Config {
+ pub fn load() -> Result<Self> {
+ let config_path = Self::get_config_path();
+ if config_path.exists() {
+ let config_content = fs::read_to_string(&config_path)
+ .with_context(|| format!("Failed to read config file: {}", config_path.display()))?;
+ let config: Config = toml::from_str(&config_content)
+ .with_context(|| format!("Failed to parse config file: {}", config_path.display()))?;
+ Ok(config)
+ } else {
+ let default_config = Config::default();
+ if let Some(parent) = config_path.parent() {
+ fs::create_dir_all(parent)
+ .with_context(|| format!("Failed to create config directory: {}", parent.display()))?;
+ }
+ let config_content =
+ toml::to_string_pretty(&default_config).context("Failed to serialize default config")?;
+ fs::write(&config_path, config_content)
+ .with_context(|| format!("Failed to write default config to: {}", config_path.display()))?;
+ Ok(default_config)
+ }
+ }
+
+ fn get_config_path() -> PathBuf {
+ if cfg!(windows) {
+ dirs::config_dir()
+ .unwrap_or_else(|| PathBuf::from("C:\\ProgramData"))
+ .join("htmlua")
+ .join("config.toml")
+ } else {
+ PathBuf::from("/etc/htmlua.toml")
+ }
+ }
+
+ pub fn save(&self) -> Result<()> {
+ let config_path = Self::get_config_path();
+ if let Some(parent) = config_path.parent() {
+ fs::create_dir_all(parent)
+ .with_context(|| format!("Failed to create config directory: {}", parent.display()))?;
+ }
+ let config_content = toml::to_string_pretty(self).context("Failed to serialize config")?;
+ fs::write(&config_path, config_content)
+ .with_context(|| format!("Failed to write config to: {}", config_path.display()))?;
+ Ok(())
+ }
+
+ pub fn config_file_path() -> PathBuf { Self::get_config_path() }
+}
diff --git a/htmlua-parser/src/helpers.rs b/htmlua-parser/src/helpers.rs
index 512ebb7..bd99f81 100644
--- a/htmlua-parser/src/helpers.rs
+++ b/htmlua-parser/src/helpers.rs
@@ -9,9 +9,6 @@ use kuchikiki::NodeRef;
use markup5ever::{LocalName, Namespace, QualName};
use tendril::TendrilSink;
-
-
-
pub fn read_doc_from_file(path: PathBuf) -> Result<NodeRef> {
let mut file = File::open(path)?;
let mut reader = BufReader::new(&mut file);
diff --git a/htmlua-parser/src/lib.rs b/htmlua-parser/src/lib.rs
index 062fcb4..2dc831c 100644
--- a/htmlua-parser/src/lib.rs
+++ b/htmlua-parser/src/lib.rs
@@ -1,4 +1,5 @@
pub mod helpers;
pub mod htmlua_stdlib;
+pub mod config;
pub mod render;
pub mod serve;
diff --git a/htmlua-parser/src/render.rs b/htmlua-parser/src/render.rs
index a92e7c5..011412f 100644
--- a/htmlua-parser/src/render.rs
+++ b/htmlua-parser/src/render.rs
@@ -17,7 +17,7 @@ use syntect::{
util::LinesWithEndings,
};
-use crate::{helpers::read_doc_from_file, htmlua_stdlib::create_htmlua_stdlib};
+use crate::{helpers::read_doc_from_file, htmlua_stdlib::create_htmlua_stdlib, serve::get_config};
fn build_lua_with_stdout(stdout: &Rc<RefCell<String>>) -> Result<Lua> {
@@ -134,16 +134,15 @@ pub fn expand_template(document: NodeRef, component_path: &PathBuf, include_from
}
pub fn process_syntax_highlighting(document: NodeRef) -> Result<NodeRef> {
+ let config = get_config();
let ps = SyntaxSet::load_defaults_newlines();
let mut ts = ThemeSet::load_defaults();
let syntax_elements: Vec<_> = match document.select("syntaxhighlight") {
Ok(e) => e.collect(),
Err(()) => return Err(anyhow!("Unable to find syntaxhighlight elements")),
};
- if !syntax_elements.is_empty() {
- // TODO: read from config
- let themes = PathBuf::from("/var/www/htmlua/themes");
- let _ = ts.add_from_folder(themes);
+ if !syntax_elements.is_empty() && config.syntax_highlighting.load_custom_themes {
+ let _ = ts.add_from_folder(&config.paths.themes);
}
for node in syntax_elements {
let attrs = match node.as_node().as_element() {
@@ -151,7 +150,7 @@ pub fn process_syntax_highlighting(document: NodeRef) -> Result<NodeRef> {
None => continue,
};
let language = attrs.get("lang").unwrap_or("text");
- let theme_name = attrs.get("theme").unwrap_or("base16-ocean.dark");
+ let theme_name = attrs.get("theme").unwrap_or(&config.syntax_highlighting.default_theme);
if let Some(text_node) = node.as_node().first_child() {
if let Some(code_text) = text_node.as_text() {
let syntax = ps
diff --git a/htmlua-parser/src/serve.rs b/htmlua-parser/src/serve.rs
index cfb3811..9821210 100644
--- a/htmlua-parser/src/serve.rs
+++ b/htmlua-parser/src/serve.rs
@@ -1,19 +1,29 @@
-use crate::helpers::read_doc_from_file;
-
-use super::render::{execute_lua, expand_template, process_markdown, process_syntax_highlighting};
+use crate::{
+ config::Config,
+ helpers::read_doc_from_file,
+ render::{execute_lua, expand_template, process_markdown, process_syntax_highlighting},
+};
use anyhow::Result;
-use std::path::{Path, PathBuf};
+use std::{path::Path, sync::OnceLock};
+
+static CONFIG: OnceLock<Config> = OnceLock::new();
+
+pub fn get_config() -> &'static Config {
+ CONFIG.get_or_init(|| {
+ Config::load().unwrap_or_else(|e| {
+ eprintln!("Warning: Failed to load config: {}", e);
+ eprintln!("Using default configuration");
+ Config::default()
+ })
+ })
+}
pub fn serve_content(request_uri: &str) -> Result<String> {
- // TODO: read from config
- let pages = PathBuf::from("/var/www/htmlua/pages");
- let components = PathBuf::from("/var/www/htmlua/components");
+ let config = get_config();
let safe_path = Path::new(request_uri).strip_prefix("/")?;
- let page_path = pages.join(safe_path);
-
+ let page_path = config.paths.pages.join(safe_path);
let doc = read_doc_from_file(page_path)?;
-
- let full_doc = expand_template(doc, &components, None)?;
+ let full_doc = expand_template(doc, &config.paths.components, None)?;
let markdown_doc = process_markdown(full_doc)?;
let highlighted_doc = process_syntax_highlighting(markdown_doc)?;
let executed_doc = execute_lua(highlighted_doc)?;