From 2d1df86a461f9056aa138ff8ae160ba47e2112b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Eric=20Janouch?=
Date: Sun, 9 Aug 2026 13:30:22 +0200
Subject: [PATCH] xC + frontends: merge M-! into M-a + reversed M-A
Both WeeChat and irssi merge these two by prioritising highlights
when you press M-a.
---
NEWS | 3 ++
xA/xA.go | 50 ++++++++++++++++++------------
xC.adoc | 6 ++--
xC.c | 78 +++++++++++++++++++++--------------------------
xF.c | 31 +++++++++++++------
xM/main.swift | 34 +++++++++++++--------
xP/public/xP.js | 28 +++++++++--------
xT/xT.cpp | 42 +++++++++++++++----------
xW/xW-resources.h | 4 +--
xW/xW.cpp | 31 +++++++++++--------
xW/xW.rc | 2 +-
11 files changed, 180 insertions(+), 129 deletions(-)
diff --git a/NEWS b/NEWS
index 7a577de..3257af0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
Unreleased
+ * xC + all frontends: M-a now prioritizes highlights, newly added M-A looks
+ for buffers in reverse order, and the old M-! binding has been removed
+
* xF: reached near feature parity with xC and xP
* xP: fixed channel title layout for narrow browser windows
diff --git a/xA/xA.go b/xA/xA.go
index c211a08..596dd78 100644
--- a/xA/xA.go
+++ b/xA/xA.go
@@ -1420,7 +1420,7 @@ func (l *customLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// rotatedBuffers returns buffer indexes starting with the current buffer.
+// rotatedBuffers returns buffer indexes starting after the current buffer.
func rotatedBuffers() []int {
r, start := make([]int, len(buffers)), 0
for i := range buffers {
@@ -1458,6 +1458,29 @@ func actionBufferLast() {
}
}
+func actionBufferActivity(backwards bool) {
+ r := rotatedBuffers()
+ if len(r) == 0 {
+ return
+ }
+ r = r[:len(r)-1]
+ if backwards {
+ slices.Reverse(r)
+ }
+ for _, i := range r {
+ if buffers[i].highlighted {
+ bufferActivate(buffers[i].bufferName)
+ return
+ }
+ }
+ for _, i := range r {
+ if buffers[i].newMessages != 0 {
+ bufferActivate(buffers[i].bufferName)
+ return
+ }
+ }
+}
+
var shortcuts = map[desktop.CustomShortcut]func(){
{
KeyName: fyne.KeyPageUp,
@@ -1487,28 +1510,17 @@ var shortcuts = map[desktop.CustomShortcut]func(){
KeyName: fyne.KeyTab,
Modifier: fyne.KeyModifierAlt,
}: actionBufferLast,
- {
- // XXX: This makes an assumption on the keyboard layout (we want '!').
- KeyName: fyne.Key1,
- Modifier: fyne.KeyModifierAlt | fyne.KeyModifierShift,
- }: func() {
- for _, i := range rotatedBuffers() {
- if buffers[i].highlighted {
- bufferActivate(buffers[i].bufferName)
- break
- }
- }
- },
{
KeyName: fyne.KeyA,
Modifier: fyne.KeyModifierAlt,
}: func() {
- for _, i := range rotatedBuffers() {
- if buffers[i].newMessages != 0 {
- bufferActivate(buffers[i].bufferName)
- break
- }
- }
+ actionBufferActivity(false)
+ },
+ {
+ KeyName: fyne.KeyA,
+ Modifier: fyne.KeyModifierAlt | fyne.KeyModifierShift,
+ }: func() {
+ actionBufferActivity(true)
},
{
KeyName: fyne.KeyH,
diff --git a/xC.adoc b/xC.adoc
index 23ff37e..68a8d33 100644
--- a/xC.adoc
+++ b/xC.adoc
@@ -56,10 +56,10 @@ This is a list of all local specialties and their respective function names:
*M-0*, *M-1*, ..., *M-9*: *goto-buffer*::
Go to the N-th buffer (normally sets a repeat counter).
Since there is no buffer number zero, *M-0* goes to the tenth one.
-*M-!*: *goto-highlight*::
- Go to the first following buffer with an unseen highlight.
*M-a*: *goto-activity*::
- Go to the first following buffer with unseen activity.
+*M-A*: *goto-backtivity*::
+ Go to the first following/preceding buffer with an unseen highlight,
+ or, if there are none, with unseen activity.
*PageUp*: *display-backlog*::
Show the in-memory backlog for this buffer using *general.pager*,
which is almost certainly the *less*(1) program.
diff --git a/xC.c b/xC.c
index 6e84d91..d3a9012 100644
--- a/xC.c
+++ b/xC.c
@@ -5105,23 +5105,20 @@ buffer_at_index (struct app_context *ctx, int n)
}
static struct buffer *
-buffer_next (struct app_context *ctx, int count)
+buffer_after (struct app_context *ctx, struct buffer *iter, bool backwards)
{
- struct buffer *new_buffer = ctx->current_buffer;
- while (count-- > 0)
- if (!(new_buffer = new_buffer->next))
- new_buffer = ctx->buffers;
- return new_buffer;
+ return backwards
+ ? (iter->prev ? iter->prev : ctx->buffers_tail)
+ : (iter->next ? iter->next : ctx->buffers);
}
static struct buffer *
-buffer_previous (struct app_context *ctx, int count)
+buffer_step (struct app_context *ctx, int count, bool backwards)
{
- struct buffer *new_buffer = ctx->current_buffer;
+ struct buffer *iter = ctx->current_buffer;
while (count-- > 0)
- if (!(new_buffer = new_buffer->prev))
- new_buffer = ctx->buffers_tail;
- return new_buffer;
+ iter = buffer_after (ctx, iter, backwards);
+ return iter;
}
static bool
@@ -5177,7 +5174,7 @@ buffer_remove_safe (struct app_context *ctx, struct buffer *buffer)
if (buffer == ctx->current_buffer)
buffer_activate (ctx, ctx->last_buffer
? ctx->last_buffer
- : buffer_next (ctx, 1));
+ : buffer_step (ctx, 1, false));
buffer_remove (ctx, buffer);
}
@@ -14283,7 +14280,7 @@ static bool
on_previous_buffer (int key, void *user_data)
{
(void) key;
- buffer_activate (user_data, buffer_previous (user_data, 1));
+ buffer_activate (user_data, buffer_step (user_data, 1, true));
return true;
}
@@ -14291,7 +14288,7 @@ static bool
on_next_buffer (int key, void *user_data)
{
(void) key;
- buffer_activate (user_data, buffer_next (user_data, 1));
+ buffer_activate (user_data, buffer_step (user_data, 1, false));
return true;
}
@@ -14308,41 +14305,36 @@ on_switch_buffer (int key, void *user_data)
}
static bool
-on_goto_highlight (int key, void *user_data)
+goto_activity (struct app_context *ctx, bool backwards)
{
- (void) key;
-
- struct app_context *ctx = user_data;
- struct buffer *iter = ctx->current_buffer;;
- do
- {
- if (!(iter = iter->next))
- iter = ctx->buffers;
- if (iter == ctx->current_buffer)
- return false;
- }
- while (!iter->highlighted);
- buffer_activate (ctx, iter);
- return true;
+ struct buffer *iter = ctx->current_buffer, *stop = iter;
+ while ((iter = buffer_after (ctx, iter, backwards)) != stop)
+ if (iter->highlighted)
+ {
+ buffer_activate (ctx, iter);
+ return true;
+ }
+ while ((iter = buffer_after (ctx, iter, backwards)) != stop)
+ if (iter->new_messages_count != iter->new_unimportant_count)
+ {
+ buffer_activate (ctx, iter);
+ return true;
+ }
+ return false;
}
static bool
on_goto_activity (int key, void *user_data)
{
(void) key;
+ return goto_activity (user_data, false);
+}
- struct app_context *ctx = user_data;
- struct buffer *iter = ctx->current_buffer;
- do
- {
- if (!(iter = iter->next))
- iter = ctx->buffers;
- if (iter == ctx->current_buffer)
- return false;
- }
- while (iter->new_messages_count == iter->new_unimportant_count);
- buffer_activate (ctx, iter);
- return true;
+static bool
+on_goto_backtivity (int key, void *user_data)
+{
+ (void) key;
+ return goto_activity (user_data, true);
}
static bool
@@ -14610,8 +14602,8 @@ app_input_init (struct input *self)
XX ("next-buffer", "Next buffer", on_next_buffer)
XX ("goto-buffer", "Go to buffer", on_goto_buffer)
XX ("switch-buffer", "Switch buffer", on_switch_buffer)
- XX ("goto-highlight", "Go to highlight", on_goto_highlight)
XX ("goto-activity", "Go to activity", on_goto_activity)
+ XX ("goto-backtivity", "Go to activity", on_goto_backtivity)
XX ("move-buffer-left", "Move buffer left", on_move_buffer_left)
XX ("move-buffer-right", "Move buffer right", on_move_buffer_right)
XX ("display-backlog", "Show backlog", on_display_backlog)
@@ -14638,8 +14630,8 @@ app_input_init (struct input *self)
input_bind (self, "M-Tab", "switch-buffer");
input_bind (self, "M-/", "switch-buffer");
- input_bind (self, "M-!", "goto-highlight");
input_bind (self, "M-a", "goto-activity");
+ input_bind (self, "M-A", "goto-backtivity");
input_bind (self, "M-m", "insert-attribute");
input_bind (self, "M-h", "display-full-log");
input_bind (self, "M-H", "toggle-unimportant");
diff --git a/xF.c b/xF.c
index 1e1b085..69450e4 100644
--- a/xF.c
+++ b/xF.c
@@ -258,8 +258,8 @@ enum action
ACTION_BUFFER_PREVIOUS,
ACTION_BUFFER_NEXT,
ACTION_BUFFER_LAST,
- ACTION_BUFFER_HIGHLIGHT,
ACTION_BUFFER_ACTIVITY,
+ ACTION_BUFFER_BACKTIVITY,
ACTION_BUFFER_1,
ACTION_BUFFER_2,
ACTION_BUFFER_3,
@@ -3376,16 +3376,29 @@ app_switch_buffer (int direction)
app_send_buffer_activate (next);
}
+static struct buffer *
+buffer_after (struct buffer *b, bool backwards)
+{
+ return backwards
+ ? (b->prev ? b->prev : g.buffers_tail)
+ : (b->next ? b->next : g.buffers);
+}
+
static bool
-app_switch_buffer_matching (bool highlighted)
+app_goto_activity (bool backwards)
{
if (!g.buffers || !g.buffer_current)
return false;
struct buffer *b = g.buffer_current, *stop = b;
- while ((b = b->next ? b->next : g.buffers) != stop)
- if ((highlighted && b->highlighted)
- || (!highlighted && b->new_messages))
+ while ((b = buffer_after (b, backwards)) != stop)
+ if (b->highlighted)
+ {
+ app_send_buffer_activate (b);
+ return true;
+ }
+ while ((b = buffer_after (b, backwards)) != stop)
+ if (b->new_messages)
{
app_send_buffer_activate (b);
return true;
@@ -3832,10 +3845,10 @@ app_process_action (enum action action)
return false;
app_send_buffer_activate (g.buffer_last);
return true;
- case ACTION_BUFFER_HIGHLIGHT:
- return app_switch_buffer_matching (true);
case ACTION_BUFFER_ACTIVITY:
- return app_switch_buffer_matching (false);
+ return app_goto_activity (false);
+ case ACTION_BUFFER_BACKTIVITY:
+ return app_goto_activity (true);
case ACTION_BUFFER_1:
case ACTION_BUFFER_2:
case ACTION_BUFFER_3:
@@ -4025,8 +4038,8 @@ g_default_bindings[] =
{ "F6", ACTION_BUFFER_NEXT }, // WeeChat
{ "M-Tab", ACTION_BUFFER_LAST }, // xC
{ "M-/", ACTION_BUFFER_LAST }, // WeeChat
- { "M-!", ACTION_BUFFER_HIGHLIGHT }, // xC
{ "M-a", ACTION_BUFFER_ACTIVITY }, // xC
+ { "M-A", ACTION_BUFFER_BACKTIVITY }, // xC
{ "M-H", ACTION_TOGGLE_UNIMPORTANT }, // xC
{ "M-h", ACTION_LOG }, // xC
{ "M-e", ACTION_EDIT_INPUT }, // xC
diff --git a/xM/main.swift b/xM/main.swift
index be8ca0e..71183ad 100644
--- a/xM/main.swift
+++ b/xM/main.swift
@@ -1210,7 +1210,7 @@ class WindowDelegate: NSObject, NSWindowDelegate {
refreshBufferList()
}
- // Buffer indexes rotated to start after the current buffer.
+ // Buffers rotated to start after the current buffer.
func rotatedBuffers() -> Array