nandi/frqpublic Fork 0
5f32523
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.

Show the overview strip on the Flutter side too

The strip itself was already shared — `frq.screens.chat/overview-pane` draws
it, and the toggle beside People turned `cells/overview?` on here as well. It
came up empty and the row buttons went nowhere, because the three things
under it were `frq.state`'s and nothing answered them on this half:
`recent-everywhere` was a private def in the jolt namespace, and
`leaving-for-overview!`, `overview-back!` and `after!` were installed only
there. `frq.actions` makes a missing key a no-op, so none of that was an
error — it was a heading, a separator, and "Nothing has been said in any
other room yet." over rooms that had plenty.

`recent-everywhere` and its round-robin move to `frq.rooms`, beside
`channel-list` and `last-preview`, which they belong with: it is a read over
`cells/channels` and `cells/current` and nothing else, so it was shared code
sitting on the wrong side of the boundary. `frq.state` re-defs it the way it
re-defs the other three, and the jolt half is unchanged.

`after!` is the one that is not a query. The strip's rows jump across rooms,
and the jump lets go of the scroll target one frame later and clears the mark
five seconds after that — without it the view stays pinned where the jump put
it and the reader cannot scroll away.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandi committed 2026-09-12T07:11:50-07:00 Browse files
5f32523 parent: 795fda4
modified common/frq/rooms.cljc +62 -2
@@ -3,8 +3,9 @@
33
44 Pure, and so shared: `channel-list` is a filter and a sort over
55 `frq.cells/channels` and the search box, `dm?` is a question about a name,
6- `last-preview` reads the last message of a buffer. `frq.state` re-defs all
7- three, so the thousand lines below them did not move."
6+ `last-preview` reads the last message of a buffer, `recent-everywhere` is
7+ the overview strip's list of what is happening in every other room. `frq.state`
8+ re-defs them all, so the thousand lines below them did not move."
89 (:require [clojure.string :as str]
910 [frq.cells :as cells]))
1011
@@ -66,3 +67,62 @@
6667 (seq (or (:from m) ""))
6768 (= (str/lower-case (:from m))
6869 (str/lower-case (or me "")))))
70+
71+
72+;; How many lines the overview holds in all.
73+(def overview-limit 100)
74+
75+(defn- round-robin
76+ "The colls' firsts, then their seconds, and so on until they are spent.
77+
78+ This is how the overview stays about every room while still being a fixed
79+ number of lines. Taking the newest hundred outright would be the strip
80+ answering about whichever room is busiest — which is the one you can already
81+ see. A turn each means a room that said one thing all day is in the first
82+ handful, beside the room that has said a hundred."
83+ [colls]
84+ (lazy-seq
85+ (let [colls (remove empty? colls)]
86+ (when (seq colls)
87+ (concat (map first colls)
88+ (round-robin (map rest colls)))))))
89+
90+(defn recent-everywhere
91+ "The newest lines from every buffer at once, newest first, and at most
92+ `overview-limit` of them — a turn to each room until they run out.
93+
94+ Each carries the room it was said in, since that is the one thing a line
95+ taken out of its own conversation no longer says for itself.
96+
97+ Bounded per room before anything else, so the cost is the number of rooms
98+ rather than the length of their backlogs: a channel with a week of history
99+ in it must not make this the most expensive thing on the screen.
100+
101+ Joins, parts and the rest of the system's own chatter are left out. They are
102+ the noise this strip would drown in: a room nobody has spoken in for a day
103+ still reports everyone who came and went in it.
104+
105+ So is the room being read. It is on the screen already, in full, directly
106+ above — repeating its last three lines under itself spends the strip's room
107+ saying what the conversation just said, and what the strip is for is the
108+ rooms you are not looking at."
109+ []
110+ (->> (dissoc @cells/channels @cells/current)
111+ (map (fn [[name buffer]]
112+ ;; Newest first, which is the order a turn each has to be taken
113+ ;; in: the first round is every room's latest line.
114+ (->> (:messages buffer)
115+ (remove :system?)
116+ (take-last overview-limit)
117+ reverse
118+ (map #(assoc % :channel name)))))
119+ (remove empty?)
120+ round-robin
121+ (take overview-limit)
122+ ;; Newest at the top, which is the other way round from a conversation
123+ ;; and right for the same reason a conversation is the way it is: what
124+ ;; you came to the strip for is what has just happened, and a list you
125+ ;; have to scroll to the bottom of to find it is a list that answers
126+ ;; last. The turn-taking above is about which lines are in it, not
127+ ;; about where they sit.
128+ (sort-by #(or (:at %) 0) >)))
@@ -3,8 +3,9 @@
3 3
4 Pure, and so shared: `channel-list` is a filter and a sort over4 Pure, and so shared: `channel-list` is a filter and a sort over
5 `frq.cells/channels` and the search box, `dm?` is a question about a name,5 `frq.cells/channels` and the search box, `dm?` is a question about a name,
6- `last-preview` reads the last message of a buffer. `frq.state` re-defs all6+ `last-preview` reads the last message of a buffer, `recent-everywhere` is
7- three, so the thousand lines below them did not move."7+ the overview strip's list of what is happening in every other room. `frq.state`
8+ re-defs them all, so the thousand lines below them did not move."
8 (:require [clojure.string :as str]9 (:require [clojure.string :as str]
9 [frq.cells :as cells]))10 [frq.cells :as cells]))
10 11
@@ -66,3 +67,62 @@
66 (seq (or (:from m) ""))67 (seq (or (:from m) ""))
67 (= (str/lower-case (:from m))68 (= (str/lower-case (:from m))
68 (str/lower-case (or me "")))))69 (str/lower-case (or me "")))))
70+
71+
72+;; How many lines the overview holds in all.
73+(def overview-limit 100)
74+
75+(defn- round-robin
76+ "The colls' firsts, then their seconds, and so on until they are spent.
77+
78+ This is how the overview stays about every room while still being a fixed
79+ number of lines. Taking the newest hundred outright would be the strip
80+ answering about whichever room is busiest — which is the one you can already
81+ see. A turn each means a room that said one thing all day is in the first
82+ handful, beside the room that has said a hundred."
83+ [colls]
84+ (lazy-seq
85+ (let [colls (remove empty? colls)]
86+ (when (seq colls)
87+ (concat (map first colls)
88+ (round-robin (map rest colls)))))))
89+
90+(defn recent-everywhere
91+ "The newest lines from every buffer at once, newest first, and at most
92+ `overview-limit` of them — a turn to each room until they run out.
93+
94+ Each carries the room it was said in, since that is the one thing a line
95+ taken out of its own conversation no longer says for itself.
96+
97+ Bounded per room before anything else, so the cost is the number of rooms
98+ rather than the length of their backlogs: a channel with a week of history
99+ in it must not make this the most expensive thing on the screen.
100+
101+ Joins, parts and the rest of the system's own chatter are left out. They are
102+ the noise this strip would drown in: a room nobody has spoken in for a day
103+ still reports everyone who came and went in it.
104+
105+ So is the room being read. It is on the screen already, in full, directly
106+ above — repeating its last three lines under itself spends the strip's room
107+ saying what the conversation just said, and what the strip is for is the
108+ rooms you are not looking at."
109+ []
110+ (->> (dissoc @cells/channels @cells/current)
111+ (map (fn [[name buffer]]
112+ ;; Newest first, which is the order a turn each has to be taken
113+ ;; in: the first round is every room's latest line.
114+ (->> (:messages buffer)
115+ (remove :system?)
116+ (take-last overview-limit)
117+ reverse
118+ (map #(assoc % :channel name)))))
119+ (remove empty?)
120+ round-robin
121+ (take overview-limit)
122+ ;; Newest at the top, which is the other way round from a conversation
123+ ;; and right for the same reason a conversation is the way it is: what
124+ ;; you came to the strip for is what has just happened, and a list you
125+ ;; have to scroll to the bottom of to find it is a list that answers
126+ ;; last. The turn-taking above is about which lines are in it, not
127+ ;; about where they sit.
128+ (sort-by #(or (:at %) 0) >)))
modified flutter/src/frq/main.cljd +19 -0
@@ -695,6 +695,25 @@
695695 :member-list (fn [room] (members/member-list @cells/channels room))
696696 :toggle-users! (fn [] (swap! cells/show-users? not))
697697 :toggle-overview! (fn [] (swap! cells/overview? not))
698+ ;; What the strip is a list of: every other room's recent lines, a turn
699+ ;; each. `frq.rooms` reads it off the cells, so both halves ask the same
700+ ;; question of the same buffers — the desktop's is the same def.
701+ :recent-everywhere rooms/recent-everywhere
702+ ;; Where the reader was when a line in the strip took them out of it,
703+ ;; and the way back to it. The room, not the place in it: one scroll
704+ ;; position is remembered per conversation either way.
705+ :leaving-for-overview! (fn [] (reset! cells/overview-return @cells/current))
706+ :overview-back! (fn []
707+ (when-let [room @cells/overview-return]
708+ (reset! cells/overview-return nil)
709+ (actions/open-channel! room)))
710+ ;; Timers, for the two the strip's jump needs: aim the scroll, then let
711+ ;; go of it, and clear the mark a while after that. `Future.delayed` in
712+ ;; milliseconds, which is the unit `frq.screens.chat` asks in.
713+ :after! (fn [ms f]
714+ (.then (async/Future.delayed (Duration .milliseconds ms))
715+ (fn [_] (f) nil))
716+ nil)
698717 :toggle-chat-list! (fn [] (swap! cells/hide-chat-list? not))
699718 :toggle-hide-join-part! (fn [] (swap! cells/hide-join-part? not))
700719 :quit! (fn [] nil)
@@ -695,6 +695,25 @@
695 :member-list (fn [room] (members/member-list @cells/channels room))695 :member-list (fn [room] (members/member-list @cells/channels room))
696 :toggle-users! (fn [] (swap! cells/show-users? not))696 :toggle-users! (fn [] (swap! cells/show-users? not))
697 :toggle-overview! (fn [] (swap! cells/overview? not))697 :toggle-overview! (fn [] (swap! cells/overview? not))
698+ ;; What the strip is a list of: every other room's recent lines, a turn
699+ ;; each. `frq.rooms` reads it off the cells, so both halves ask the same
700+ ;; question of the same buffers — the desktop's is the same def.
701+ :recent-everywhere rooms/recent-everywhere
702+ ;; Where the reader was when a line in the strip took them out of it,
703+ ;; and the way back to it. The room, not the place in it: one scroll
704+ ;; position is remembered per conversation either way.
705+ :leaving-for-overview! (fn [] (reset! cells/overview-return @cells/current))
706+ :overview-back! (fn []
707+ (when-let [room @cells/overview-return]
708+ (reset! cells/overview-return nil)
709+ (actions/open-channel! room)))
710+ ;; Timers, for the two the strip's jump needs: aim the scroll, then let
711+ ;; go of it, and clear the mark a while after that. `Future.delayed` in
712+ ;; milliseconds, which is the unit `frq.screens.chat` asks in.
713+ :after! (fn [ms f]
714+ (.then (async/Future.delayed (Duration .milliseconds ms))
715+ (fn [_] (f) nil))
716+ nil)
698 :toggle-chat-list! (fn [] (swap! cells/hide-chat-list? not))717 :toggle-chat-list! (fn [] (swap! cells/hide-chat-list? not))
699 :toggle-hide-join-part! (fn [] (swap! cells/hide-join-part? not))718 :toggle-hide-join-part! (fn [] (swap! cells/hide-join-part? not))
700 :quit! (fn [] nil)719 :quit! (fn [] nil)
modified src/frq/state.clj +2 -60
@@ -1725,67 +1725,9 @@
17251725 (def highlight cells/highlight)
17261726
17271727
1728+(def overview-limit rooms/overview-limit)
17281729
1729-;; How many lines the overview holds in all.
1730-(def overview-limit 100)
1731-
1732-;; How many it shows without being scrolled — the terminal's whole answer,
1733-;; since a strip there is a handful of rows taken off a conversation that is
1734-;; measured in how many of those fit.
1735-(defn- round-robin
1736- "The colls' firsts, then their seconds, and so on until they are spent.
1737-
1738- This is how the overview stays about every room while still being a fixed
1739- number of lines. Taking the newest hundred outright would be the strip
1740- answering about whichever room is busiest — which is the one you can already
1741- see. A turn each means a room that said one thing all day is in the first
1742- handful, beside the room that has said a hundred."
1743- [colls]
1744- (lazy-seq
1745- (let [colls (remove empty? colls)]
1746- (when (seq colls)
1747- (concat (map first colls)
1748- (round-robin (map rest colls)))))))
1749-
1750-(defn recent-everywhere
1751- "The newest lines from every buffer at once, newest first, and at most
1752- `overview-limit` of them — a turn to each room until they run out.
1753-
1754- Each carries the room it was said in, since that is the one thing a line
1755- taken out of its own conversation no longer says for itself.
1756-
1757- Bounded per room before anything else, so the cost is the number of rooms
1758- rather than the length of their backlogs: a channel with a week of history
1759- in it must not make this the most expensive thing on the screen.
1760-
1761- Joins, parts and the rest of the system's own chatter are left out. They are
1762- the noise this strip would drown in: a room nobody has spoken in for a day
1763- still reports everyone who came and went in it.
1764-
1765- So is the room being read. It is on the screen already, in full, directly
1766- above — repeating its last three lines under itself spends the strip's room
1767- saying what the conversation just said, and what the strip is for is the
1768- rooms you are not looking at."
1769- []
1770- (->> (dissoc @channels @current)
1771- (map (fn [[name buffer]]
1772- ;; Newest first, which is the order a turn each has to be taken
1773- ;; in: the first round is every room's latest line.
1774- (->> (:messages buffer)
1775- (remove :system?)
1776- (take-last overview-limit)
1777- reverse
1778- (map #(assoc % :channel name)))))
1779- (remove empty?)
1780- round-robin
1781- (take overview-limit)
1782- ;; Newest at the top, which is the other way round from a conversation
1783- ;; and right for the same reason a conversation is the way it is: what
1784- ;; you came to the strip for is what has just happened, and a list you
1785- ;; have to scroll to the bottom of to find it is a list that answers
1786- ;; last. The turn-taking above is about which lines are in it, not
1787- ;; about where they sit.
1788- (sort-by #(or (:at %) 0) >)))
1730+(def recent-everywhere rooms/recent-everywhere)
17891731
17901732 (def last-preview rooms/last-preview)
17911733
@@ -1725,67 +1725,9 @@
1725 (def highlight cells/highlight)1725 (def highlight cells/highlight)
1726 1726
1727 1727
1728+(def overview-limit rooms/overview-limit)
1728 1729
1729-;; How many lines the overview holds in all.1730+(def recent-everywhere rooms/recent-everywhere)
1730-(def overview-limit 100)
1731-
1732-;; How many it shows without being scrolled — the terminal's whole answer,
1733-;; since a strip there is a handful of rows taken off a conversation that is
1734-;; measured in how many of those fit.
1735-(defn- round-robin
1736- "The colls' firsts, then their seconds, and so on until they are spent.
1737-
1738- This is how the overview stays about every room while still being a fixed
1739- number of lines. Taking the newest hundred outright would be the strip
1740- answering about whichever room is busiest — which is the one you can already
1741- see. A turn each means a room that said one thing all day is in the first
1742- handful, beside the room that has said a hundred."
1743- [colls]
1744- (lazy-seq
1745- (let [colls (remove empty? colls)]
1746- (when (seq colls)
1747- (concat (map first colls)
1748- (round-robin (map rest colls)))))))
1749-
1750-(defn recent-everywhere
1751- "The newest lines from every buffer at once, newest first, and at most
1752- `overview-limit` of them — a turn to each room until they run out.
1753-
1754- Each carries the room it was said in, since that is the one thing a line
1755- taken out of its own conversation no longer says for itself.
1756-
1757- Bounded per room before anything else, so the cost is the number of rooms
1758- rather than the length of their backlogs: a channel with a week of history
1759- in it must not make this the most expensive thing on the screen.
1760-
1761- Joins, parts and the rest of the system's own chatter are left out. They are
1762- the noise this strip would drown in: a room nobody has spoken in for a day
1763- still reports everyone who came and went in it.
1764-
1765- So is the room being read. It is on the screen already, in full, directly
1766- above — repeating its last three lines under itself spends the strip's room
1767- saying what the conversation just said, and what the strip is for is the
1768- rooms you are not looking at."
1769- []
1770- (->> (dissoc @channels @current)
1771- (map (fn [[name buffer]]
1772- ;; Newest first, which is the order a turn each has to be taken
1773- ;; in: the first round is every room's latest line.
1774- (->> (:messages buffer)
1775- (remove :system?)
1776- (take-last overview-limit)
1777- reverse
1778- (map #(assoc % :channel name)))))
1779- (remove empty?)
1780- round-robin
1781- (take overview-limit)
1782- ;; Newest at the top, which is the other way round from a conversation
1783- ;; and right for the same reason a conversation is the way it is: what
1784- ;; you came to the strip for is what has just happened, and a list you
1785- ;; have to scroll to the bottom of to find it is a list that answers
1786- ;; last. The turn-taking above is about which lines are in it, not
1787- ;; about where they sit.
1788- (sort-by #(or (:at %) 0) >)))
1789 1731
1790 (def last-preview rooms/last-preview)1732 (def last-preview rooms/last-preview)
1791 1733