Skip to content

Commit

Permalink
Merge pull request #53 from luleyleo/31-add-content-preview-for-text-…
Browse files Browse the repository at this point in the history
…files

Add content preview for text files
  • Loading branch information
luleyleo authored Dec 9, 2024
2 parents 92e173d + fa3a58d commit 645998b
Show file tree
Hide file tree
Showing 12 changed files with 434 additions and 114 deletions.
36 changes: 36 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions build-aux/cargo-sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -2127,6 +2127,32 @@
"dest": "cargo/vendor/smallvec-1.13.2",
"dest-filename": ".cargo-checksum.json"
},
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/sourceview5/sourceview5-0.9.1.crate",
"sha256": "f0e07d99b15f12767aa1c84870c45667f42bf24fd6a989dc70088e32854ef56e",
"dest": "cargo/vendor/sourceview5-0.9.1"
},
{
"type": "inline",
"contents": "{\"package\": \"f0e07d99b15f12767aa1c84870c45667f42bf24fd6a989dc70088e32854ef56e\", \"files\": {}}",
"dest": "cargo/vendor/sourceview5-0.9.1",
"dest-filename": ".cargo-checksum.json"
},
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/sourceview5-sys/sourceview5-sys-0.9.0.crate",
"sha256": "4a3759467713554a8063faa380237ee2c753e89026bbe1b8e9611d991cb106ff",
"dest": "cargo/vendor/sourceview5-sys-0.9.0"
},
{
"type": "inline",
"contents": "{\"package\": \"4a3759467713554a8063faa380237ee2c753e89026bbe1b8e9611d991cb106ff\", \"files\": {}}",
"dest": "cargo/vendor/sourceview5-sys-0.9.0",
"dest-filename": ".cargo-checksum.json"
},
{
"type": "archive",
"archive-type": "tar-gzip",
Expand Down
1 change: 1 addition & 0 deletions gnome/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ gtk = { version = "0.9.2", package = "gtk4", features = ["blueprint", "v4_16"] }
flume = "0.11.0"
gettext-rs = { version = "0.7.1", features = ["gettext-system"] }
gtk-blueprint = "0.2.0"
sourceview5 = { version = "0.9.1", features = ["gtk_v4_12", "v5_12"] }

[dependencies.cosmic-config]
git = "https://github.com/pop-os/libcosmic.git"
Expand Down
4 changes: 4 additions & 0 deletions gnome/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ const APP_ID: &str = env!("APP_ID");
fn main() {
i18n::setup_gettext();

let _ = gtk::init();
let _ = adw::init();
sourceview5::init();

let application = adw::Application::builder()
.application_id(APP_ID)
.flags(ApplicationFlags::HANDLES_OPEN)
Expand Down
13 changes: 11 additions & 2 deletions gnome/src/search/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ glib::wrapper! {
pub struct SearchResult(ObjectSubclass<imp::SearchResult>);
}

impl Default for SearchResult {
fn default() -> Self {
glib::Object::new()
}
}

impl SearchResult {
pub fn new(
file: impl Into<PathBuf>,
Expand Down Expand Up @@ -48,7 +54,8 @@ impl SearchResult {
};

glib::Object::builder()
.property("file", file)
.property("relative_path", file)
.property("absolute_path", absolute_file.as_ref())
.property("uri", uri)
.property("line", line)
.property("content", content.as_ref())
Expand Down Expand Up @@ -96,7 +103,9 @@ mod imp {
#[properties(wrapper_type = super::SearchResult)]
pub struct SearchResult {
#[property(get, set)]
file: RefCell<PathBuf>,
relative_path: RefCell<PathBuf>,
#[property(get, set)]
absolute_path: RefCell<PathBuf>,
#[property(get, set)]
uri: RefCell<String>,
#[property(get, set)]
Expand Down
9 changes: 6 additions & 3 deletions gnome/src/styles.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
.cg-banner {
background-color: var(--accent-bg-color);
color: var(--accent-fg-color);
.view {
background-color: #00000000;
}

.view gutter {
background-color: #00000000;
}
2 changes: 2 additions & 0 deletions gnome/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ pub use error_window::ErrorWindow;

mod search_window;
pub use search_window::SearchWindow;

mod preview;
2 changes: 2 additions & 0 deletions gnome/src/ui/preview/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod plain_preview;
pub use plain_preview::PlainPreview;
39 changes: 39 additions & 0 deletions gnome/src/ui/preview/plain_preview.blp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Gtk 4.0;
using Adw 1;
using GtkSource 5;

template $ClapgrepPlainPreview: Widget {
layout-manager: Gtk.BinLayout {};

Adw.ToolbarView {
top-bar-style: flat;

[top]
Adw.HeaderBar {
title-widget: Adw.WindowTitle title {
title: _("Content Preview");
};
}

Stack views {
StackPage no_preview {
child: Adw.StatusPage {
title: _("No Preview Available");
description: _("Try clicking on on of the result lines.");
icon-name: "x-office-document-symbolic";
};
}

StackPage some_preview {
child: ScrolledWindow {
child: GtkSource.View text_view {
vexpand: true;
editable: false;
show-line-numbers: true;
highlight-current-line: true;
};
};
}
}
}
}
152 changes: 152 additions & 0 deletions gnome/src/ui/preview/plain_preview.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use gtk::glib::{self, Object};

use crate::search::SearchResult;

glib::wrapper! {
pub struct PlainPreview(ObjectSubclass<imp::PlainPreview>)
@extends gtk::Widget;
}

impl PlainPreview {
pub fn new(result: &SearchResult) -> Self {
Object::builder().property("result", result).build()
}
}

mod imp {
use crate::search::SearchResult;
use adw::subclass::prelude::*;
use gettextrs::gettext;
use glib::subclass::InitializingObject;
use gtk::{glib, prelude::*, CompositeTemplate};
use sourceview5::prelude::*;
use std::{cell::RefCell, fs, time::Duration};

#[derive(CompositeTemplate, glib::Properties, Default)]
#[template(file = "src/ui/preview/plain_preview.blp")]
#[properties(wrapper_type = super::PlainPreview)]
pub struct PlainPreview {
#[property(get, set)]
pub result: RefCell<SearchResult>,

#[template_child]
pub title: TemplateChild<adw::WindowTitle>,
#[template_child]
pub text_view: TemplateChild<sourceview5::View>,

#[template_child]
pub views: TemplateChild<gtk::Stack>,
#[template_child]
pub no_preview: TemplateChild<gtk::StackPage>,
#[template_child]
pub some_preview: TemplateChild<gtk::StackPage>,
}

#[glib::object_subclass]
impl ObjectSubclass for PlainPreview {
const NAME: &'static str = "ClapgrepPlainPreview";
type Type = super::PlainPreview;
type ParentType = gtk::Widget;

fn class_init(klass: &mut Self::Class) {
klass.bind_template();
klass.bind_template_callbacks();
}

fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}

#[gtk::template_callbacks]
impl PlainPreview {
fn buffer(&self) -> sourceview5::Buffer {
self.text_view
.buffer()
.downcast::<sourceview5::Buffer>()
.unwrap()
}

fn update_preview(&self) {
let result = self.result.borrow();
let file = result.absolute_path();

if !file.exists() {
return;
}

if let Ok(full_text) = fs::read_to_string(&file) {
let buffer = self.buffer();
buffer.set_text(&full_text);

// Setup syntax highlighting
let lm = sourceview5::LanguageManager::default();
let language = lm.guess_language(Some(&file), None);
buffer.set_language(language.as_ref());
self.text_view.set_monospace(language.is_some());

// Place cursor on result line.
let mut cursor_position = buffer.start_iter();
cursor_position.forward_lines((result.line() - 1) as i32);
buffer.place_cursor(&cursor_position);

// Set title to file name.
let file_name = file.file_name().unwrap().to_string_lossy();
self.title.set_title(file_name.as_ref());

// Scroll to result line after 100ms.
//
// The delay is needed because scroll_to_iter only works
// once the line hights have been calculated in an idle handler.
let text_view = self.text_view.clone();
glib::timeout_add_local_once(Duration::from_millis(100), move || {
text_view.scroll_to_iter(&mut cursor_position, 0.0, true, 0.0, 0.3);
});

self.views.set_visible_child(&self.some_preview.child());
} else {
self.title.set_title(&gettext("Content Preview"));
self.views.set_visible_child(&self.no_preview.child());
}
}

fn setup_style(&self) {
let text_view_buffer = self.buffer();

let asm = adw::StyleManager::default();
let sm = sourceview5::StyleSchemeManager::default();

let light_style = sm.scheme("Adwaita").unwrap();
let dark_style = sm.scheme("Adwaita-dark").unwrap();

let setter = move |asm: &adw::StyleManager| {
let current_style = if asm.is_dark() {
&dark_style
} else {
&light_style
};

text_view_buffer.set_style_scheme(Some(current_style));
};

setter(&asm);
asm.connect_dark_notify(setter);
}
}

#[glib::derived_properties]
impl ObjectImpl for PlainPreview {
fn constructed(&self) {
self.parent_constructed();
let obj = self.obj();

self.setup_style();

obj.connect_result_notify(|obj| {
obj.imp().update_preview();
});
}
}

impl WidgetImpl for PlainPreview {}
}
23 changes: 22 additions & 1 deletion gnome/src/ui/search_window/imp.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
use crate::{config::Config, i18n::gettext_f, search::SearchModel, ui::ErrorWindow};
use crate::{
config::Config,
i18n::gettext_f,
search::{SearchModel, SearchResult},
ui::{preview::PlainPreview, ErrorWindow},
};
use adw::subclass::prelude::*;
use clapgrep_core::{SearchEngine, SearchFlags, SearchMessage, SearchParameters};
use gettextrs::gettext;
Expand Down Expand Up @@ -75,6 +80,12 @@ pub struct SearchWindow {
pub results_page: TemplateChild<gtk::StackPage>,
#[template_child]
pub split_view: TemplateChild<adw::NavigationSplitView>,
#[template_child]
pub inner_split_view: TemplateChild<adw::NavigationSplitView>,
#[template_child]
pub preview_navigation_page: TemplateChild<adw::NavigationPage>,
#[template_child]
pub preview: TemplateChild<PlainPreview>,

pub engine: SearchEngine,
pub config: Config,
Expand Down Expand Up @@ -153,6 +164,16 @@ impl SearchWindow {
let error_window = ErrorWindow::new(&self.obj());
error_window.present();
}

#[template_callback]
fn on_result_activated(&self, position: u32) {
if let Some(result) = self.results.item(position) {
let result = result.downcast::<SearchResult>().unwrap();
self.preview.set_result(&result);
self.preview_navigation_page.set_visible(true);
self.inner_split_view.set_show_content(true);
}
}
}

impl SearchWindow {
Expand Down
Loading

0 comments on commit 645998b

Please sign in to comment.