From f2da2503761ae0415894604c29357cc602491f51 Mon Sep 17 00:00:00 2001 From: yggverse Date: Tue, 4 Feb 2025 15:15:12 +0200 Subject: [PATCH] add `text/plain` content type support --- README.md | 2 +- .../window/tab/item/client/driver/gemini.rs | 8 ++- .../browser/window/tab/item/page/content.rs | 25 ++++------ .../window/tab/item/page/content/text.rs | 49 ++++++++++++++----- .../tab/item/page/content/text/plain.rs | 22 +++++++++ .../item/page/content/text/plain/reader.rs | 33 ------------- 6 files changed, 75 insertions(+), 64 deletions(-) create mode 100644 src/app/browser/window/tab/item/page/content/text/plain.rs delete mode 100644 src/app/browser/window/tab/item/page/content/text/plain/reader.rs diff --git a/README.md b/README.md index 19de23e5..71d04532 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ GTK 4 / Libadwaita client written in Rust #### Text * [x] `text/gemini` - * [ ] `text/plain` + * [x] `text/plain` #### Images * [x] `image/gif` diff --git a/src/app/browser/window/tab/item/client/driver/gemini.rs b/src/app/browser/window/tab/item/client/driver/gemini.rs index bb982b44..8137a097 100644 --- a/src/app/browser/window/tab/item/client/driver/gemini.rs +++ b/src/app/browser/window/tab/item/client/driver/gemini.rs @@ -236,7 +236,7 @@ fn handle( redirects.replace(0); // reset }, _ => match success.mime() { - "text/gemini" => memory_input_stream::from_stream_async( + "text/gemini" | "text/plain" => memory_input_stream::from_stream_async( connection.stream(), Priority::DEFAULT, cancellable.clone(), @@ -257,7 +257,11 @@ fn handle( let widget = if matches!(*feature, Feature::Source) { page.content.to_text_source(data) } else { - page.content.to_text_gemini(&uri, data) + match success.mime() { + "text/gemini" => page.content.to_text_gemini(&uri, data), + "text/plain" => page.content.to_text_plain(data), + _ => panic!() // unexpected + } }; page.search.set(Some(widget.text_view)); page.set_title(&match widget.meta.title { diff --git a/src/app/browser/window/tab/item/page/content.rs b/src/app/browser/window/tab/item/page/content.rs index 013953f3..a11374c3 100644 --- a/src/app/browser/window/tab/item/page/content.rs +++ b/src/app/browser/window/tab/item/page/content.rs @@ -113,21 +113,7 @@ impl Content { status } - /// Set new `content::Text` component for `Self` with new `text::Gemini` preset - /// - /// Useful as reader for [Gemtext](https://geminiprotocol.net/docs/gemtext.gmi) - /// - /// * action removes previous children component from `Self` - /// - /// **Arguments** - /// - /// * `base` - [Uri](https://docs.gtk.org/glib/struct.Uri.html) to resolve relative links in Gemtext - /// * `data` - Gemtext source to be parsed - /// - /// **Return** - /// - /// `Text` component with it public API - /// * could be useful to extract document title parsed from Gemtext + /// `text/gemini` pub fn to_text_gemini(&self, base: &Uri, data: &str) -> Text { self.clean(); let text = Text::gemini((&self.window_action, &self.item_action), base, data); @@ -135,6 +121,15 @@ impl Content { text } + /// `text/plain` + pub fn to_text_plain(&self, data: &str) -> Text { + self.clean(); + let text = Text::plain(data); + self.g_box.append(&text.scrolled_window); + text + } + + /// * system `source:` pub fn to_text_source(&self, data: &str) -> Text { self.clean(); let text = Text::source(data); diff --git a/src/app/browser/window/tab/item/page/content/text.rs b/src/app/browser/window/tab/item/page/content/text.rs index 5f81d06a..f0b45854 100644 --- a/src/app/browser/window/tab/item/page/content/text.rs +++ b/src/app/browser/window/tab/item/page/content/text.rs @@ -1,10 +1,12 @@ mod gemini; +mod plain; mod source; use super::{ItemAction, WindowAction}; use adw::ClampScrollable; use gemini::Gemini; use gtk::{glib::Uri, prelude::Cast, ScrolledWindow, TextView}; +use plain::Plain; use source::Source; use std::rc::Rc; @@ -34,19 +36,7 @@ impl Text { .maximum_size(800) .build(); - // Grab focus into the `TextView` on click empty `ClampScrollable` area - { - use gtk::{prelude::WidgetExt, GestureClick}; - let controller = GestureClick::new(); - - controller.connect_pressed({ - let text_view = gemini.text_view.clone(); - move |_, _, _, _| { - text_view.grab_focus(); - } - }); - clamp_scrollable.add_controller(controller); - } + grab_focus_patch(&clamp_scrollable, &gemini.text_view); Self { text_view: gemini.text_view, @@ -57,6 +47,22 @@ impl Text { } } + pub fn plain(data: &str) -> Self { + let text_view = TextView::plain(data); + let clamp_scrollable = ClampScrollable::builder() + .child(&text_view) + .css_classes(["view"]) + .build(); + + grab_focus_patch(&clamp_scrollable, &text_view); + + Self { + scrolled_window: ScrolledWindow::builder().child(&clamp_scrollable).build(), + text_view, + meta: Meta { title: None }, + } + } + pub fn source(data: &str) -> Self { let source = Source::new(data); Self { @@ -66,3 +72,20 @@ impl Text { } } } + +// Tools + +// Grab focus into the `TextView` on click empty `ClampScrollable` area +fn grab_focus_patch(clamp_scrollable: &ClampScrollable, text_view: &TextView) { + use gtk::{prelude::WidgetExt, GestureClick}; + let controller = GestureClick::new(); + + controller.connect_pressed({ + let text_view = text_view.clone(); + move |_, _, _, _| { + text_view.grab_focus(); + } + }); + + clamp_scrollable.add_controller(controller); +} diff --git a/src/app/browser/window/tab/item/page/content/text/plain.rs b/src/app/browser/window/tab/item/page/content/text/plain.rs new file mode 100644 index 00000000..0779b65f --- /dev/null +++ b/src/app/browser/window/tab/item/page/content/text/plain.rs @@ -0,0 +1,22 @@ +use gtk::{TextBuffer, TextView}; + +pub trait Plain { + fn plain(data: &str) -> Self; +} + +impl Plain for TextView { + fn plain(data: &str) -> Self { + const MARGIN: i32 = 8; + TextView::builder() + .bottom_margin(MARGIN) + .cursor_visible(false) + .buffer(&TextBuffer::builder().text(data).build()) + .editable(false) + .left_margin(MARGIN) + .monospace(true) + .right_margin(MARGIN) + .top_margin(MARGIN) + .vexpand(true) + .build() + } +} diff --git a/src/app/browser/window/tab/item/page/content/text/plain/reader.rs b/src/app/browser/window/tab/item/page/content/text/plain/reader.rs deleted file mode 100644 index 3153f39f..00000000 --- a/src/app/browser/window/tab/item/page/content/text/plain/reader.rs +++ /dev/null @@ -1,33 +0,0 @@ -use gtk::{Align, Label}; - -pub struct Reader { - widget: Label, -} - -impl Default for Reader { - fn default() -> Self { - Self::new() - } -} - -impl Reader { - // Construct - pub fn new() -> Self { - Self { - widget: Label::builder() - .halign(Align::Start) - .valign(Align::Start) - .margin_start(8) - .margin_end(8) - .wrap(true) - .selectable(true) - .use_markup(true) - .build(), - } - } - - // Getters - pub fn widget(&self) -> &Label { - &self.widget - } -}