Ely Office: six offline-first desktop apps in Rust and GPUI
ElyDoc, ElyTable, ElyShow (LibreOfficeKit), ElyPDF (MuPDF), ElyTree (Git), ElyMark (Milkdown and CodeMirror in CEF). ElyMail and ElyAgent follow.
This commit is contained in:
817 files changed
+143101
No files matched your search
@@ -0,0 +1,63 @@
|
||||
//! Links: followed, drawn, retargeted, deleted (PDF-07).
|
||||
|
||||
use ely_pdf_engine::{Link, Target};
|
||||
use gpui::Context;
|
||||
|
||||
use crate::view::{Failed, PdfView};
|
||||
|
||||
/// Addresses that may leave the document.
|
||||
pub fn outward(uri: &str) -> bool {
|
||||
["https://", "http://", "mailto:"].iter().any(|scheme| uri.starts_with(scheme))
|
||||
}
|
||||
|
||||
/// A target as typed: a page number or an address.
|
||||
pub fn parse(typed: &str, pages: usize) -> Option<Target> {
|
||||
let typed = typed.trim();
|
||||
match typed.parse::<usize>() {
|
||||
Ok(n) => (1..=pages).contains(&n).then(|| Target::Page(n - 1, 0.0)),
|
||||
Err(_) => outward(typed).then(|| Target::Web(typed.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
/// A link's target as a person types it.
|
||||
pub fn typed(link: &Link) -> String {
|
||||
match link.page {
|
||||
Some(page) => (page + 1).to_string(),
|
||||
None => link.uri.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfView {
|
||||
/// Goes where `link` points; only web and mail leave.
|
||||
pub fn follow(&mut self, link: &Link, cx: &mut Context<Self>) {
|
||||
match link.page {
|
||||
Some(page) => {
|
||||
log::info!("pdf: follows a link to page {}", page + 1);
|
||||
self.show(page, link.y, cx)
|
||||
}
|
||||
None if outward(&link.uri) => {
|
||||
log::info!("pdf: opens a link outside");
|
||||
cx.open_url(&link.uri)
|
||||
}
|
||||
None => {
|
||||
let text = crate::viewer::Viewer::text(cx, "pdf.link.refused", &[]);
|
||||
cx.emit(Failed(text.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn a_target_is_a_page_in_range_or_a_web_or_mail_address() {
|
||||
assert_eq!(parse(" 3 ", 5), Some(Target::Page(2, 0.0)));
|
||||
assert_eq!(parse("9", 5), None);
|
||||
assert_eq!(parse("0", 5), None);
|
||||
assert_eq!(parse("https://a.b", 5), Some(Target::Web("https://a.b".into())));
|
||||
assert_eq!(parse("javascript:x", 5), None);
|
||||
assert_eq!(parse("file:///etc", 5), None);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user