diff --git a/damus-c/block.h b/damus-c/block.h index a4453af2..7fa4a75d 100644 --- a/damus-c/block.h +++ b/damus-c/block.h @@ -46,6 +46,7 @@ typedef struct note_block { } block_t; typedef struct note_blocks { + int words; int num_blocks; struct note_block *blocks; } blocks_t; diff --git a/damus-c/damus.c b/damus-c/damus.c index 8073e4ff..b13b4916 100644 --- a/damus-c/damus.c +++ b/damus-c/damus.c @@ -216,6 +216,7 @@ int damus_parse_content(struct note_blocks *blocks, const char *content) { struct note_block block; u8 *start, *pre_mention; + blocks->words = 0; blocks->num_blocks = 0; make_cursor((u8*)content, (u8*)content + strlen(content), &cur); @@ -224,6 +225,11 @@ int damus_parse_content(struct note_blocks *blocks, const char *content) { cp = peek_char(&cur, -1); c = peek_char(&cur, 0); + // new word + if (is_whitespace(cp) && !is_whitespace(c)) { + blocks->words++; + } + pre_mention = cur.p; if (cp == -1 || is_whitespace(cp) || c == '#') { if (c == '#' && (parse_mention_index(&cur, &block) || parse_hashtag(&cur, &block))) { diff --git a/damus/Models/HomeModel.swift b/damus/Models/HomeModel.swift index 94f72f2f..ef6f42cb 100644 --- a/damus/Models/HomeModel.swift +++ b/damus/Models/HomeModel.swift @@ -1170,7 +1170,7 @@ func process_local_notification(damus_state: DamusState, event ev: NostrEvent) { } if type == .text && damus_state.settings.mention_notification { - let blocks = ev.blocks(damus_state.keypair.privkey) + let blocks = ev.blocks(damus_state.keypair.privkey).blocks for case .mention(let mention) in blocks where mention.ref.ref_id == damus_state.keypair.pubkey { let content = NSAttributedString(render_note_content(ev: ev, profiles: damus_state.profiles, privkey: damus_state.keypair.privkey).content.attributed).string diff --git a/damus/Models/Mentions.swift b/damus/Models/Mentions.swift index d790dd5b..ba1904fa 100644 --- a/damus/Models/Mentions.swift +++ b/damus/Models/Mentions.swift @@ -150,7 +150,12 @@ func render_blocks(blocks: [Block]) -> String { } } -func parse_mentions(content: String, tags: [[String]]) -> [Block] { +struct Blocks { + let words: Int + let blocks: [Block] +} + +func parse_mentions(content: String, tags: [[String]]) -> Blocks { var out: [Block] = [] var bs = note_blocks() @@ -174,9 +179,10 @@ func parse_mentions(content: String, tags: [[String]]) -> [Block] { i += 1 } + let words = Int(bs.words) blocks_free(&bs) - return out + return Blocks(words: words, blocks: out) } func strblock_to_string(_ s: str_block_t) -> String? { diff --git a/damus/Nostr/NostrEvent.swift b/damus/Nostr/NostrEvent.swift index 2879ddef..1658c20e 100644 --- a/damus/Nostr/NostrEvent.swift +++ b/damus/Nostr/NostrEvent.swift @@ -83,8 +83,8 @@ class NostrEvent: Codable, Identifiable, CustomStringConvertible, Equatable, Has return calculate_event_id(ev: self) == self.id } - private var _blocks: [Block]? = nil - func blocks(_ privkey: String?) -> [Block] { + private var _blocks: Blocks? = nil + func blocks(_ privkey: String?) -> Blocks { if let bs = _blocks { return bs } @@ -93,7 +93,7 @@ class NostrEvent: Codable, Identifiable, CustomStringConvertible, Equatable, Has return blocks } - func get_blocks(content: String) -> [Block] { + func get_blocks(content: String) -> Blocks { return parse_mentions(content: content, tags: self.tags) } @@ -118,7 +118,7 @@ class NostrEvent: Codable, Identifiable, CustomStringConvertible, Equatable, Has if let rs = _event_refs { return rs } - let refs = interpret_event_refs(blocks: self.blocks(privkey), tags: self.tags) + let refs = interpret_event_refs(blocks: self.blocks(privkey).blocks, tags: self.tags) self._event_refs = refs return refs } @@ -232,7 +232,7 @@ class NostrEvent: Codable, Identifiable, CustomStringConvertible, Equatable, Has func note_language(_ privkey: String?) -> String? { // Rely on Apple's NLLanguageRecognizer to tell us which language it thinks the note is in // and filter on only the text portions of the content as URLs and hashtags confuse the language recognizer. - let originalBlocks = blocks(privkey) + let originalBlocks = blocks(privkey).blocks let originalOnlyText = originalBlocks.compactMap { $0.is_text }.joined(separator: " ") // Only accept language recognition hypothesis if there's at least a 50% probability that it's accurate. @@ -942,7 +942,7 @@ func last_etag(tags: [[String]]) -> String? { } func first_eref_mention(ev: NostrEvent, privkey: String?) -> Mention? { - let blocks = ev.blocks(privkey).filter { block in + let blocks = ev.blocks(privkey).blocks.filter { block in guard case .mention(let mention) = block else { return false } diff --git a/damus/Views/NoteContentView.swift b/damus/Views/NoteContentView.swift index f1716c99..7dbc79e4 100644 --- a/damus/Views/NoteContentView.swift +++ b/damus/Views/NoteContentView.swift @@ -188,7 +188,7 @@ struct NoteContentView: View { .onReceive(handle_notify(.profile_updated)) { notif in let profile = notif.object as! ProfileUpdate let blocks = event.blocks(damus_state.keypair.privkey) - for block in blocks { + for block in blocks.blocks { switch block { case .mention(let m): if m.type == .pubkey && m.ref.ref_id == profile.pubkey { @@ -261,6 +261,7 @@ struct NoteArtifacts: Equatable { } let content: CompatibleText + let words: Int let urls: [UrlType] let invoices: [Invoice] @@ -278,7 +279,7 @@ struct NoteArtifacts: Equatable { static func just_content(_ content: String) -> NoteArtifacts { let txt = CompatibleText(attributed: AttributedString(stringLiteral: content)) - return NoteArtifacts(content: txt, urls: [], invoices: []) + return NoteArtifacts(content: txt, words: 0, urls: [], invoices: []) } } @@ -313,9 +314,10 @@ func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) - return render_blocks(blocks: blocks, profiles: profiles) } -func render_blocks(blocks: [Block], profiles: Profiles) -> NoteArtifacts { +func render_blocks(blocks bs: Blocks, profiles: Profiles) -> NoteArtifacts { var invoices: [Invoice] = [] var urls: [UrlType] = [] + let blocks = bs.blocks let one_note_ref = blocks .filter({ $0.is_note_mention }) @@ -369,7 +371,7 @@ func render_blocks(blocks: [Block], profiles: Profiles) -> NoteArtifacts { } } - return NoteArtifacts(content: txt, urls: urls, invoices: invoices) + return NoteArtifacts(content: txt, words: bs.words, urls: urls, invoices: invoices) } enum MediaUrl {