~damien/gtk-webby

54709b2cd32aab80824231ea0deea61e9d4c9dfb — Damien Radtke 3 months ago 6b1d761
Begin adding html-translator feature
5 files changed, 339 insertions(+), 11 deletions(-)

M Cargo.lock
M Cargo.toml
A src/html.rs
M src/main.rs
M src/window.rs
M Cargo.lock => Cargo.lock +266 -3
@@ 338,6 338,16 @@ dependencies = [
]

[[package]]
name = "futf"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
dependencies = [
 "mac",
 "new_debug_unreachable",
]

[[package]]
name = "futures-channel"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 481,6 491,17 @@ dependencies = [
]

[[package]]
name = "getrandom"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
dependencies = [
 "cfg-if",
 "libc",
 "wasi",
]

[[package]]
name = "gimli"
version = "0.27.3"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 758,6 779,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"

[[package]]
name = "html5ever"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7"
dependencies = [
 "log",
 "mac",
 "markup5ever",
 "proc-macro2",
 "quote",
 "syn 1.0.109",
]

[[package]]
name = "http"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 978,9 1013,9 @@ dependencies = [

[[package]]
name = "libc"
version = "0.2.147"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"

[[package]]
name = "linux-raw-sys"


@@ 995,12 1030,54 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0"

[[package]]
name = "lock_api"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
dependencies = [
 "autocfg",
 "scopeguard",
]

[[package]]
name = "log"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"

[[package]]
name = "mac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"

[[package]]
name = "markup5ever"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016"
dependencies = [
 "log",
 "phf",
 "phf_codegen",
 "string_cache",
 "string_cache_codegen",
 "tendril",
]

[[package]]
name = "markup5ever_rcdom"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9521dd6750f8e80ee6c53d65e2e4656d7de37064f3a7a5d2d11d05df93839c2"
dependencies = [
 "html5ever",
 "markup5ever",
 "tendril",
 "xml5ever",
]

[[package]]
name = "matches"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1090,6 1167,12 @@ dependencies = [
]

[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"

[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1194,12 1277,73 @@ dependencies = [
]

[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
 "lock_api",
 "parking_lot_core",
]

[[package]]
name = "parking_lot_core"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
dependencies = [
 "cfg-if",
 "libc",
 "redox_syscall 0.4.1",
 "smallvec",
 "windows-targets",
]

[[package]]
name = "percent-encoding"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"

[[package]]
name = "phf"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
dependencies = [
 "phf_shared",
]

[[package]]
name = "phf_codegen"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd"
dependencies = [
 "phf_generator",
 "phf_shared",
]

[[package]]
name = "phf_generator"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
dependencies = [
 "phf_shared",
 "rand",
]

[[package]]
name = "phf_shared"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
dependencies = [
 "siphasher",
]

[[package]]
name = "pin-project"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1238,6 1382,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"

[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"

[[package]]
name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"

[[package]]
name = "proc-macro-crate"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1315,6 1471,36 @@ dependencies = [
]

[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
 "libc",
 "rand_chacha",
 "rand_core",
]

[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
 "ppv-lite86",
 "rand_core",
]

[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
 "getrandom",
]

[[package]]
name = "redox_syscall"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1324,6 1510,15 @@ dependencies = [
]

[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
 "bitflags 1.3.2",
]

[[package]]
name = "regex"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1470,6 1665,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"

[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"

[[package]]
name = "security-framework"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1559,6 1760,12 @@ dependencies = [
]

[[package]]
name = "siphasher"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"

[[package]]
name = "slab"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1620,6 1827,32 @@ dependencies = [
]

[[package]]
name = "string_cache"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
dependencies = [
 "new_debug_unreachable",
 "once_cell",
 "parking_lot",
 "phf_shared",
 "precomputed-hash",
 "serde",
]

[[package]]
name = "string_cache_codegen"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988"
dependencies = [
 "phf_generator",
 "phf_shared",
 "proc-macro2",
 "quote",
]

[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1669,12 1902,23 @@ dependencies = [
 "autocfg",
 "cfg-if",
 "fastrand",
 "redox_syscall",
 "redox_syscall 0.3.5",
 "rustix 0.37.23",
 "windows-sys",
]

[[package]]
name = "tendril"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
dependencies = [
 "futf",
 "mac",
 "utf-8",
]

[[package]]
name = "termcolor"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1931,6 2175,12 @@ dependencies = [
]

[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"

[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 2074,7 2324,9 @@ version = "0.1.0"
dependencies = [
 "env_logger",
 "gtk4",
 "html5ever",
 "libadwaita",
 "markup5ever_rcdom",
 "mime",
 "mlua",
 "quick-xml",


@@ 2221,3 2473,14 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
 "winapi",
]

[[package]]
name = "xml5ever"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4034e1d05af98b51ad7214527730626f019682d797ba38b51689212118d8e650"
dependencies = [
 "log",
 "mac",
 "markup5ever",
]

M Cargo.toml => Cargo.toml +4 -1
@@ 18,7 18,10 @@ tiny_http = "0.11"
webdriver = "0.48"
env_logger = "0.10" # for seeing messages from webdriver
url = "2.3"
html5ever = { version = "0.26.0", optional = true }
markup5ever_rcdom = { version = "0.2.0", optional = true }

[features]
default = ["lua"]
default = ["lua", "html-translator"]
lua = ["dep:mlua"]
html-translator = ["dep:html5ever", "dep:markup5ever_rcdom"]

A src/html.rs => src/html.rs +51 -0
@@ 0,0 1,51 @@
extern crate markup5ever_rcdom as rcdom;

use crate::error::Error;
use std::default::Default;
use std::io::Read;
use html5ever::tendril::TendrilSink;

// See https://github.com/servo/html5ever/blob/master/rcdom/examples/print-rcdom.rs
// See https://docs.rs/html5ever/0.26.0/html5ever/
pub fn translate<R: Read>(mut body: R) -> Result<String, Error> {
    let dom = html5ever::parse_document(rcdom::RcDom::default(), Default::default())
        .from_utf8()
        .read_from(&mut body)?;

    if !dom.errors.is_empty() {
        println!("DOM parsing errors:");
        for error in &dom.errors {
            println!("{}", error);
        }
    }

    let mut gtk_markup = String::from(r#"<?xml version="1.0" encoding="UTF-8"?>
<interface>
    <object class="GtkBox" id="body">
        <property name="orientation">vertical</property>
        <property name="halign">start</property>
    </object>
"#);

    walk(dom.document);

    gtk_markup.push_str("
</interface>");

    Ok(gtk_markup)
}

fn walk(node: rcdom::Handle) {
    for child in &(*node.children.borrow()) {
        walk(child.clone());
    }
    use rcdom::NodeData::*;
    match &node.data {
        Document => println!("=> document"),
        Doctype {name, ..} => println!("=> doctype: {:?}", &name),
        Element {name, attrs: _, ..} => println!("element: {:?}", &name),
        Text {contents} => println!("text: {:?}", &contents),
        ProcessingInstruction {..} => println!("processing instruction"),
        Comment {contents: _} => println!("comment"),
    }
}

M src/main.rs => src/main.rs +1 -0
@@ 16,6 16,7 @@ mod editor;
mod error;
mod headers;
mod history;
#[cfg(feature = "html-translator")] mod html;
mod script;
mod types;
mod ui;

M src/window.rs => src/window.rs +17 -7
@@ 1,6 1,7 @@
use std::io::Read;
use std::sync::{Arc, Mutex};

use crate::error::Error;
use glib::{clone, Continue, MainContext, PRIORITY_DEFAULT};
use gtk::prelude::*;
use gtk::{gdk, gio, glib};


@@ 234,20 235,21 @@ impl Window {

                let mime_type: mime::Mime = match response.headers().get(reqwest::header::CONTENT_TYPE) {
                    Some(content_type) => content_type.to_str()?.parse()?,
                    None => return Err(crate::error::Error::NoContentTypeError),
                    None => return Err(Error::NoContentTypeError),
                };

                if let Some(charset) = mime_type.get_param("charset") {
                    if charset.as_str() != "utf-8" {
                        return Err(crate::error::Error::UnsupportedCharsetError(charset.as_str().into()));
                        return Err(Error::UnsupportedCharsetError(charset.as_str().into()));
                    }
                }

                match mime_type.type_() {
                    mime::TEXT if mime_type.subtype() == "gtk" => window.clone().render_gtk(Self::read_all(response)?),
                    mime::TEXT => window.clone().render_text(Self::read_all(response)?),
                    mime::APPLICATION if mime_type.subtype() == "gtk" => window.clone().render_gtk(Self::read_all(response)?),
                    _ => println!("{}", crate::error::Error::UnsupportedContentTypeError(mime_type.essence_str().to_string())),
                match (mime_type.type_(), mime_type.subtype().as_str()) {
                    (mime::TEXT, "gtk") | (mime::APPLICATION, "gtk") => window.clone().render_gtk(Self::read_all(response)?),
                    #[cfg(feature = "html-translator")]
                    (mime::TEXT, "html") => window.clone().render_html(response),
                    (mime::TEXT, _) => window.clone().render_text(Self::read_all(response)?),
                    _ => println!("{}", Error::UnsupportedContentTypeError(mime_type.essence_str().to_string())),
                }
                Ok(())
            };


@@ 396,6 398,14 @@ impl Window {
        );
    }

    #[cfg(feature = "html-translator")]
    fn render_html<R: Read>(self: Arc<Self>, body: R) {
        match crate::html::translate(body) {
            Ok(s) => self.render_gtk(s),
            Err(err) => println!("Failed to render HTML: {}", &err),
        }
    }

    fn href(self: Arc<Self>, target: &String) {
        let location = crate::util::absolutize_url(&self.state.lock().unwrap().location, target);
        self.address_entry.set_text(&location);