Add commands next-buffer / previous-buffer (#20)

* Bind `next-buffer` to `C-x C-right` and `previous-buffer` to `C-x left` just like GNU Emacs
* next-buffer & previous-buffer skip buffers with BF_SYSTEM flag.
* next-buffer & previous-buffer command is ignored from minibuffer and popups.
* fix compilation errors on linux
This commit is contained in:
クエン酸 2024-05-19 22:19:26 +08:00 • committed by Charlie Gordon
commit bed552a905
4 changed files with 69 additions and 2 deletions

View file

@ -62,8 +62,6 @@
an EditBuffer could also have an embedded QECursor with no EditState
* use hash tables for command and variable names
* sort key binding tables?
* `next-buffer` command on C-x C-right
* `previous-buffer` command on C-x C-left
* `save-some-buffers` command on C-x s
* standardize key prefixes: C-, M-, S- and possibly others
* use C-M- prefix instead of M-C- in source and documentation but support

61
qe.c
View file

@ -7422,6 +7422,67 @@ void do_switch_to_buffer(EditState *s, const char *bufname)
switch_to_buffer(s, b);
}
/* Find next non-system buffer from the specified buffer. If the specified
buffer is the last one, returns the first one. If only one non-system buffer
exists currently, return itself. */
static EditBuffer *next_non_system_buffer(EditState *s, EditBuffer *b) {
EditBuffer *nb = b == NULL ? NULL : b->next;
if (nb == NULL) {
nb = s->qe_state->first_buffer;
}
/* qemacs guarantees at least one non-system buffer (i.e. `*scratch*`) exists */
while (nb->flags & BF_SYSTEM) {
nb = nb->next;
if (nb == NULL) {
nb = s->qe_state->first_buffer;
}
}
return nb;
}
void do_next_buffer(EditState *s)
{
EditBuffer *b;
/* ignore command from the minibuffer and popups */
if (s->flags & (WF_POPUP | WF_MINIBUF))
return;
b = next_non_system_buffer(s, s->b);
switch_to_buffer(s, b);
}
void do_previous_buffer(EditState *s)
{
// TODO(chqrlie): simplify this by counting non system buffers
// also handle universal argument
EditBuffer *orig, *curr, *curr_next;
/* ignore command from the minibuffer and popups */
if (s->flags & (WF_POPUP | WF_MINIBUF))
return;
/* what we want to compare & find are non-system buffers, so need to ignore
all non-system buffers; or it may fall into an infinite loop. */
/* original buffer is immutable */
orig = s->b;
if (orig->flags & BF_SYSTEM) {
orig = next_non_system_buffer(s, orig);
}
/* find from first buffer*/
curr = s->qe_state->first_buffer;
if (curr->flags & BF_SYSTEM) {
curr = next_non_system_buffer(s, curr);
}
curr_next = next_non_system_buffer(s, curr);
while (curr_next != orig) {
curr = curr_next;
curr_next = next_non_system_buffer(s, curr_next);
}
switch_to_buffer(s, curr);
}
void do_toggle_read_only(EditState *s)
{
s->b->flags ^= BF_READONLY;

2
qe.h
View file

@ -1403,6 +1403,8 @@ void display_mode_line(EditState *s);
int edit_set_mode(EditState *s, ModeDef *m);
void qe_set_next_mode(EditState *s, int n, int status);
void do_set_next_mode(EditState *s, int n);
void do_next_buffer(EditState *s);
void do_previous_buffer(EditState *s);
/* loading files */
void do_exit_qemacs(EditState *s, int argval);

View file

@ -224,6 +224,12 @@ static const CmdDef basic_commands[] = {
do_kill_buffer, ESsi,
"s{Kill buffer: }[buffer]|buffer|"
"v", 0)
CMD0( "next-buffer", "C-x C-right",
"Switch to the next buffer",
do_next_buffer)
CMD0( "previous-buffer", "C-x C-left",
"Switch to the previous buffer",
do_previous_buffer)
CMD0( "toggle-read-only", "C-x C-q, C-c %",
"Toggle the read-only flag of the current buffer",
do_toggle_read_only)