ms-linkifying @references.

This commit is contained in:
Robert C. Martin 2023-02-16 11:27:55 -06:00
parent ffb1d9ddc9
commit 207a226f3a
2 changed files with 83 additions and 24 deletions

View File

@ -230,27 +230,44 @@
(describe "Segment article content" (describe "Segment article content"
(it "returns empty list if content is empty" (it "returns empty list if content is empty"
(should= '() (segment-article ""))) (should= '() (segment-article "")))
(it "returns a single :text element if no url in content" (it "returns a single :text element if no url in content"
(should= '([:text "no url"]) (segment-article "no url"))) (should= '([:text "no url"]) (segment-article "no url")))
(it "returns a single :url element if whole content is a url" (it "returns a single :url element if whole content is a url"
(should= '([:url "http://nostr.com"]) (segment-article "http://nostr.com"))) (should= '([:url "http://nostr.com"]) (segment-article "http://nostr.com")))
(it "returns a list of :text and :url elements when content contains multiple text and url segments"
(should= '([:text "Check this "] [:url "http://nostr.com"] [:text " It's cool"]) (it "returns a :namereference segment"
(segment-article "Check this http://nostr.com It's cool"))) (should= [[:namereference "@name"] [:text " text"]]
(segment-article "@name text")))
(it "returns a list of :text and :url and :namereference segments"
(should= [[:text "Hey "] [:namereference "@bob"] [:text " Check this "] [:url "http://nostr.com"] [:text " It's cool"]]
(segment-article "Hey @bob Check this http://nostr.com It's cool")))
) )
(describe "Format article" (describe "Format article"
(it "should escape HTML entities" (it "should escape HTML entities"
(should= "&lt;b&gt;text&lt;&#x2F;b&gt;" (reformat-article "<b>text</b>"))) (should= "&lt;b&gt;text&lt;&#x2F;b&gt;" (reformat-article "<b>text</b>")))
(it "should linkify url" (it "should linkify url"
(should= "<a href=\"https://nostr.com\">nostr.com</a>" (reformat-article "https://nostr.com"))) (should= "<a href=\"https://nostr.com\">nostr.com</a>" (reformat-article "https://nostr.com")))
(it "should ms-link a namereference"
(should= "<a href=\"ms-namereference://@name\">@name</a>"
(reformat-article "@name")))
(it "should escape HTML entities and linkify url" (it "should escape HTML entities and linkify url"
(should= "&lt;b&gt;Clojure&lt;&#x2F;b&gt;: <a href=\"https://clojure.org/\">clojure.org/</a>" (should= "&lt;b&gt;Clojure&lt;&#x2F;b&gt;: <a href=\"https://clojure.org/\">clojure.org/</a>"
(reformat-article "<b>Clojure</b>: https://clojure.org/"))) (reformat-article "<b>Clojure</b>: https://clojure.org/")))
(it "should format replies and escape HTML entities properly" (it "should format replies and escape HTML entities properly"
(should= "&gt;this is<br>&gt;a reply" (reformat-article ">this is >a reply"))) (should= "&gt;this is<br>&gt;a reply" (reformat-article ">this is >a reply")))
(it "should replace multiple spaces with &nbsp" (it "should replace multiple spaces with &nbsp"
(should= "one two&nbsp three&nbsp&nbsp ." (reformat-article "one two three ."))) (should= "one two&nbsp three&nbsp&nbsp ." (reformat-article "one two three .")))
) )
(declare db) (declare db)
@ -305,3 +322,17 @@
(set-mem :pubkey my-pubkey) (set-mem :pubkey my-pubkey)
(should= "2-deg<-trusted-pet" (format-user-id trusted-by-trusted-user)))) (should= "2-deg<-trusted-pet" (format-user-id trusted-by-trusted-user))))
) )
(describe "combine patterns"
(it "combines a single pattern and name"
(let [pattern (combine-patterns [:name1 #"pattern1"])]
(should= java.util.regex.Pattern (type pattern))
(should= "(?<name1>pattern1)" (str pattern))))
(it "combines multiple patterns and names"
(let [pattern (combine-patterns [:name1 #"pattern1"]
[:name2 #"pattern2"])]
(should= java.util.regex.Pattern (type pattern))
(should= "(?<name1>pattern1)|(?<name2>pattern2)" (str pattern))))
)

View File

@ -6,8 +6,7 @@
[more-speech.nostr.contact-list :as contact-list] [more-speech.nostr.contact-list :as contact-list]
[more-speech.ui.formatter-util :refer :all] [more-speech.ui.formatter-util :refer :all]
[more-speech.config :as config :refer [get-db]] [more-speech.config :as config :refer [get-db]]
[more-speech.db.gateway :as gateway]) [more-speech.db.gateway :as gateway]))
)
(defn format-user-id (defn format-user-id
([user-id] ([user-id]
@ -153,30 +152,56 @@
uri (if (= 2 (count split-url)) (second split-url) url)] uri (if (= 2 (count split-url)) (second split-url) url)]
(str "<a href=\"" url "\">" uri "</a>"))) (str "<a href=\"" url "\">" uri "</a>")))
(defn ms-linkify [type subject]
(str "<a href=\"" (str type "://" subject) "\">" subject "</a>"))
(defn combine-patterns
"patterns are a list of [:name pattern]"
[& patterns]
(let [grouped-patterns (map #(str "(?<" (name (first %)) ">" (second %) ")") patterns)
combined-patterns (interpose "|" grouped-patterns)]
(re-pattern (apply str combined-patterns))))
(defn segment-article (defn segment-article
([content] ([content]
(let [segment (re-find config/url-pattern content)] (segment-article content []))
(cond
(not (nil? segment)) ([content segments]
(let [url-start-index (string/index-of content segment) (let [patterns [[:url config/url-pattern]
url-end-index (+ url-start-index (.length segment)) [:namereference config/user-name-pattern]]
text-sub (subs content 0 url-start-index) pattern (apply combine-patterns patterns)
url-sub (subs content url-start-index url-end-index) group-names (map first patterns)]
rest (subs content url-end-index)] (loop [content content
(concat segments segments]
(if (empty? text-sub) (let [matcher (re-matcher pattern content)
[[:url url-sub]] segment (first (re-find matcher))]
[[:text text-sub] [:url url-sub]]) (cond
(segment-article rest))) (empty? content)
(not (empty? content)) (list [:text content]) segments
:else '()))))
(some? segment)
(let [grouped-by-name (map #(vector (keyword %) (.group matcher (name %))) group-names)
the-group (filter #(some? (second %)) grouped-by-name)
segment-type (ffirst the-group)
url-start-index (string/index-of content segment)
url-end-index (+ url-start-index (.length segment))
text-sub (subs content 0 url-start-index)
url-sub (subs content url-start-index url-end-index)
rest (subs content url-end-index)]
(recur rest
(concat segments
(if (empty? text-sub)
[[segment-type url-sub]]
[[:text text-sub] [segment-type url-sub]]))))
:else
(concat segments (list [:text content]))))))))
(defn reformat-article [article] (defn reformat-article [article]
(let [segments (segment-article article)] (let [segments (segment-article article)]
(reduce (reduce
(fn [formatted-content [seg-type seg]] (fn [formatted-content [seg-type seg]]
(cond (condp = seg-type
(= seg-type :text) :text
(str formatted-content (str formatted-content
((comp ((comp
non-breaking-spaces non-breaking-spaces
@ -185,8 +210,11 @@
format-replies format-replies
) seg) ) seg)
) )
(= seg-type :url) :url
(str formatted-content (linkify seg)))) (str formatted-content (linkify seg))
:namereference
(str formatted-content (ms-linkify "ms-namereference" seg))))
"" ""
segments))) segments)))