nandi/frqpublic Fork 0
eb6778a
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Send a draft with a break in it as the lines it is

The terminal's compose box takes a paragraph now, and there is no newline on
the wire: a PRIVMSG is one line and ends where the protocol says it does. So
the box that let a reader write the paragraph is what takes it apart again —
one message a line, in order, blank lines dropped. The reply tag goes on the
first, since that is the one answering something, and the picture on the last,
since a link at the end of a paragraph is where a link goes. A command and a
rewrite are single-line things whatever the box holds, and read the lines
joined.

And the placeholder says so where it is new: Enter sends, as it always has,
and Shift+Enter is the break nobody would think to try unasked.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandi committed 2026-09-10T09:58:39-07:00 Browse files
eb6778a parent: 3d7c428
modified src/frq/app.clj +4 -1
@@ -1468,7 +1468,10 @@
14681468 ;; the minimum it always was.
14691469 :hexpand true
14701470 :rows (if @terminal? 3 1)
1471- :placeholder "Message"
1471+ ;; The break is worth saying out loud where it is new: Enter
1472+ ;; sends, as it always has, and the box under it takes a
1473+ ;; paragraph now — which nobody would think to try unasked.
1474+ :placeholder (if @terminal? "Message — Shift+Enter for a new line" "Message")
14721475 :on-change #(reset! s/draft %)
14731476 :on-paste-empty s/paste-image!
14741477 :on-activate s/send-draft!}]
@@ -1468,7 +1468,10 @@
1468 ;; the minimum it always was.1468 ;; the minimum it always was.
1469 :hexpand true1469 :hexpand true
1470 :rows (if @terminal? 3 1)1470 :rows (if @terminal? 3 1)
1471- :placeholder "Message"1471+ ;; The break is worth saying out loud where it is new: Enter
1472+ ;; sends, as it always has, and the box under it takes a
1473+ ;; paragraph now — which nobody would think to try unasked.
1474+ :placeholder (if @terminal? "Message — Shift+Enter for a new line" "Message")
1472 :on-change #(reset! s/draft %)1475 :on-change #(reset! s/draft %)
1473 :on-paste-empty s/paste-image!1476 :on-paste-empty s/paste-image!
1474 :on-activate s/send-draft!}]1477 :on-activate s/send-draft!}]
modified src/frq/state.clj +32 -10
@@ -1574,9 +1574,21 @@
15741574 A picture still on its way up holds the send rather than losing it: the line
15751575 is left in the box, said so, and the reader presses send again a moment
15761576 later. Sending the text without its picture would be the one outcome nobody
1577- asked for."
1577+ asked for.
1578+
1579+ A draft with a break in it is several messages. There is no newline on the
1580+ wire — a PRIVMSG is one line and a line ends where the protocol says it does
1581+ — so the box that lets a reader write a paragraph has to be the thing that
1582+ takes it apart again: one message a line, in order, blank lines dropped. Only
1583+ the last one carries the picture, and only the first one answers the message
1584+ being replied to; the rest are the same thought continuing."
15781585 []
1579- (let [text (str/trim @draft)
1586+ (let [lines (->> (str/split-lines @draft)
1587+ (map str/trim)
1588+ (remove str/blank?))
1589+ ;; What the branches below that are about one line read: a command and
1590+ ;; a rewrite are single-line things whatever the box holds.
1591+ text (str/join " " lines)
15801592 target @current
15811593 reply-to @replying-to
15821594 edit @editing
@@ -1616,16 +1628,26 @@
16161628 (reset! draft ""))
16171629 (and (str/blank? text) (not url)) nil
16181630 :else
1619- (let [text (if (str/starts-with? text "//") (subs text 1) text)
1620- line (str/trim (str text (when url (str " " url))))]
1631+ (let [lines (map #(if (str/starts-with? % "//") (subs % 1) %) lines)
1632+ ;; The picture rides the last line, so a message that is only a
1633+ ;; picture is the link on its own.
1634+ lines (if (seq lines) (vec lines) [""])
1635+ last-i (dec (count lines))
1636+ lines (map-indexed (fn [i line]
1637+ (str/trim (str line (when (and url (= i last-i))
1638+ (str " " url)))))
1639+ lines)]
16211640 ;; Saying something is a way of asking to see it.
16221641 (jump-to-present!)
1623- (when-let [c @conn] (irc/privmsg! c target line (:id reply-to)))
1624- ;; Only when the server will not send the line back itself. Its copy
1625- ;; carries the msgid, and a message with no id is one nobody can react
1626- ;; or reply to; echoing locally as well would put the line up twice.
1627- (when-not (some-> @conn (irc/cap-acked? "echo-message"))
1628- (push-message! target @form-nick line {:reply-to (:id reply-to)}))
1642+ (doseq [[i line] (map-indexed vector lines)]
1643+ (when-let [c @conn]
1644+ (irc/privmsg! c target line (when (zero? i) (:id reply-to))))
1645+ ;; Only when the server will not send the line back itself. Its copy
1646+ ;; carries the msgid, and a message with no id is one nobody can react
1647+ ;; or reply to; echoing locally as well would put the line up twice.
1648+ (when-not (some-> @conn (irc/cap-acked? "echo-message"))
1649+ (push-message! target @form-nick line
1650+ {:reply-to (when (zero? i) (:id reply-to))})))
16291651 (reset! replying-to nil)
16301652 (reset! draft "")
16311653 (when att
@@ -1574,9 +1574,21 @@
1574 A picture still on its way up holds the send rather than losing it: the line1574 A picture still on its way up holds the send rather than losing it: the line
1575 is left in the box, said so, and the reader presses send again a moment1575 is left in the box, said so, and the reader presses send again a moment
1576 later. Sending the text without its picture would be the one outcome nobody1576 later. Sending the text without its picture would be the one outcome nobody
1577- asked for."1577+ asked for.
1578+
1579+ A draft with a break in it is several messages. There is no newline on the
1580+ wire — a PRIVMSG is one line and a line ends where the protocol says it does
1581+ — so the box that lets a reader write a paragraph has to be the thing that
1582+ takes it apart again: one message a line, in order, blank lines dropped. Only
1583+ the last one carries the picture, and only the first one answers the message
1584+ being replied to; the rest are the same thought continuing."
1578 []1585 []
1579- (let [text (str/trim @draft)1586+ (let [lines (->> (str/split-lines @draft)
1587+ (map str/trim)
1588+ (remove str/blank?))
1589+ ;; What the branches below that are about one line read: a command and
1590+ ;; a rewrite are single-line things whatever the box holds.
1591+ text (str/join " " lines)
1580 target @current1592 target @current
1581 reply-to @replying-to1593 reply-to @replying-to
1582 edit @editing1594 edit @editing
@@ -1616,16 +1628,26 @@
1616 (reset! draft ""))1628 (reset! draft ""))
1617 (and (str/blank? text) (not url)) nil1629 (and (str/blank? text) (not url)) nil
1618 :else1630 :else
1619- (let [text (if (str/starts-with? text "//") (subs text 1) text)1631+ (let [lines (map #(if (str/starts-with? % "//") (subs % 1) %) lines)
1620- line (str/trim (str text (when url (str " " url))))]1632+ ;; The picture rides the last line, so a message that is only a
1633+ ;; picture is the link on its own.
1634+ lines (if (seq lines) (vec lines) [""])
1635+ last-i (dec (count lines))
1636+ lines (map-indexed (fn [i line]
1637+ (str/trim (str line (when (and url (= i last-i))
1638+ (str " " url)))))
1639+ lines)]
1621 ;; Saying something is a way of asking to see it.1640 ;; Saying something is a way of asking to see it.
1622 (jump-to-present!)1641 (jump-to-present!)
1623- (when-let [c @conn] (irc/privmsg! c target line (:id reply-to)))1642+ (doseq [[i line] (map-indexed vector lines)]
1624- ;; Only when the server will not send the line back itself. Its copy1643+ (when-let [c @conn]
1625- ;; carries the msgid, and a message with no id is one nobody can react1644+ (irc/privmsg! c target line (when (zero? i) (:id reply-to))))
1626- ;; or reply to; echoing locally as well would put the line up twice.1645+ ;; Only when the server will not send the line back itself. Its copy
1627- (when-not (some-> @conn (irc/cap-acked? "echo-message"))1646+ ;; carries the msgid, and a message with no id is one nobody can react
1628- (push-message! target @form-nick line {:reply-to (:id reply-to)}))1647+ ;; or reply to; echoing locally as well would put the line up twice.
1648+ (when-not (some-> @conn (irc/cap-acked? "echo-message"))
1649+ (push-message! target @form-nick line
1650+ {:reply-to (when (zero? i) (:id reply-to))})))
1629 (reset! replying-to nil)1651 (reset! replying-to nil)
1630 (reset! draft "")1652 (reset! draft "")
1631 (when att1653 (when att