mirror of
https://github.com/mikedilger/gossip.git
synced 2024-09-19 11:43:43 +00:00
Merge pull request #156 from fiatjaf/tag-stuff
Highlight npub/etc references in the textarea
This commit is contained in:
commit
c3b60b227a
23
Cargo.lock
generated
23
Cargo.lock
generated
@ -1712,6 +1712,7 @@ dependencies = [
|
|||||||
"image",
|
"image",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"linkify",
|
"linkify",
|
||||||
|
"memoize",
|
||||||
"nostr-types",
|
"nostr-types",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
@ -2191,6 +2192,28 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoize"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c25d125e4063f313300d87c8f658e5b3d69257095df9a4221c12ba50b0421bff"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"memoize-inner",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoize-inner"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8b7d5160e6ffcc59d4c571c38238ec5b7065bc91a5a24f511988dabcddda723"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mime"
|
name = "mime"
|
||||||
version = "0.3.16"
|
version = "0.3.16"
|
||||||
|
@ -25,6 +25,7 @@ http = "0.2"
|
|||||||
image = { version = "0.24", features = [ "png", "jpeg" ] }
|
image = { version = "0.24", features = [ "png", "jpeg" ] }
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
linkify = "0.9"
|
linkify = "0.9"
|
||||||
|
memoize = "0.3"
|
||||||
nostr-types = { git = "https://github.com/mikedilger/nostr-types" }
|
nostr-types = { git = "https://github.com/mikedilger/nostr-types" }
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
|
75
src/tags.rs
75
src/tags.rs
@ -1,4 +1,9 @@
|
|||||||
use crate::db::DbRelay;
|
use crate::db::DbRelay;
|
||||||
|
use eframe::epaint::{
|
||||||
|
text::{LayoutJob, TextFormat},
|
||||||
|
Color32, FontFamily, FontId,
|
||||||
|
};
|
||||||
|
use memoize::memoize;
|
||||||
use nostr_types::{Id, PublicKey, PublicKeyHex, Tag};
|
use nostr_types::{Id, PublicKey, PublicKeyHex, Tag};
|
||||||
|
|
||||||
pub fn keys_from_text(text: &str) -> Vec<(String, PublicKey)> {
|
pub fn keys_from_text(text: &str) -> Vec<(String, PublicKey)> {
|
||||||
@ -87,6 +92,76 @@ pub async fn add_event_to_tags(existing_tags: &mut Vec<Tag>, added: Id, marker:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum HighlightType {
|
||||||
|
Nothing,
|
||||||
|
PublicKey,
|
||||||
|
Event,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[memoize]
|
||||||
|
pub fn textarea_highlighter(text: String) -> LayoutJob {
|
||||||
|
let mut job = LayoutJob::default();
|
||||||
|
|
||||||
|
let ids = notes_from_text(&text);
|
||||||
|
let pks = keys_from_text(&text);
|
||||||
|
|
||||||
|
// we will gather indices such that we can split the text in chunks
|
||||||
|
let mut indices: Vec<(usize, HighlightType)> = vec![];
|
||||||
|
for pk in pks {
|
||||||
|
for m in text.match_indices(&pk.0) {
|
||||||
|
indices.push((m.0, HighlightType::Nothing));
|
||||||
|
indices.push((m.0 + pk.0.len(), HighlightType::PublicKey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for id in ids {
|
||||||
|
for m in text.match_indices(&id.0) {
|
||||||
|
indices.push((m.0, HighlightType::Nothing));
|
||||||
|
indices.push((m.0 + id.0.len(), HighlightType::Event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indices.sort_by_key(|x| x.0);
|
||||||
|
indices.dedup_by_key(|x| x.0);
|
||||||
|
|
||||||
|
// add a breakpoint at the end if it doesn't exist
|
||||||
|
if indices.is_empty() || indices[indices.len() - 1].0 != text.len() {
|
||||||
|
indices.push((text.len(), HighlightType::Nothing));
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we will add each chunk back to the textarea with custom formatting
|
||||||
|
let mut curr = 0;
|
||||||
|
for (index, highlight) in indices {
|
||||||
|
let chunk = &text[curr..index];
|
||||||
|
|
||||||
|
job.append(
|
||||||
|
chunk,
|
||||||
|
0.0,
|
||||||
|
match highlight {
|
||||||
|
HighlightType::Nothing => TextFormat {
|
||||||
|
font_id: FontId::new(14.0, FontFamily::Proportional),
|
||||||
|
color: Color32::BLACK,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
HighlightType::PublicKey => TextFormat {
|
||||||
|
font_id: FontId::new(16.0, FontFamily::Monospace),
|
||||||
|
background: Color32::LIGHT_GRAY,
|
||||||
|
color: Color32::DARK_GREEN,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
HighlightType::Event => TextFormat {
|
||||||
|
font_id: FontId::new(16.0, FontFamily::Monospace),
|
||||||
|
background: Color32::LIGHT_GRAY,
|
||||||
|
color: Color32::DARK_RED,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
curr = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
job
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -2,7 +2,7 @@ use super::{GossipUi, Page};
|
|||||||
use crate::comms::ToOverlordMessage;
|
use crate::comms::ToOverlordMessage;
|
||||||
use crate::feed::FeedKind;
|
use crate::feed::FeedKind;
|
||||||
use crate::globals::{Globals, GLOBALS};
|
use crate::globals::{Globals, GLOBALS};
|
||||||
use crate::tags::keys_from_text;
|
use crate::tags::{keys_from_text, textarea_highlighter};
|
||||||
use crate::ui::widgets::CopyButton;
|
use crate::ui::widgets::CopyButton;
|
||||||
use crate::AVATAR_SIZE_F32;
|
use crate::AVATAR_SIZE_F32;
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
@ -185,11 +185,18 @@ fn real_posting_area(app: &mut GossipUi, ctx: &Context, frame: &mut eframe::Fram
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Text area
|
// Text area
|
||||||
|
let mut layouter = |ui: &Ui, text: &str, wrap_width: f32| {
|
||||||
|
let mut layout_job = textarea_highlighter(text.to_owned());
|
||||||
|
layout_job.wrap.max_width = wrap_width;
|
||||||
|
ui.fonts().layout_job(layout_job)
|
||||||
|
};
|
||||||
|
|
||||||
ui.add(
|
ui.add(
|
||||||
TextEdit::multiline(&mut app.draft)
|
TextEdit::multiline(&mut app.draft)
|
||||||
.hint_text("Type your message here")
|
.hint_text("Type your message here")
|
||||||
.desired_width(f32::INFINITY)
|
.desired_width(f32::INFINITY)
|
||||||
.lock_focus(true),
|
.lock_focus(true)
|
||||||
|
.layouter(&mut layouter),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user