Implement vim-like marks
Commands are 'mark' and 'goto'. Both can be used either directly, like 'mark a' and 'goto a', or interactively (just 'mark'). For interactive mode, i3-input must be installed and in your PATH.
This commit is contained in:
28
src/client.c
28
src/client.c
@ -24,6 +24,7 @@
|
||||
#include "queue.h"
|
||||
#include "layout.h"
|
||||
#include "client.h"
|
||||
#include "table.h"
|
||||
|
||||
/*
|
||||
* Removes the given client from the container, either because it will be inserted into another
|
||||
@ -316,3 +317,30 @@ void client_map(xcb_connection_t *conn, Client *client) {
|
||||
|
||||
xcb_map_window(conn, client->frame);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the given mark for this client. Used for jumping to the client
|
||||
* afterwards (like m<mark> and '<mark> in vim).
|
||||
*
|
||||
*/
|
||||
void client_mark(xcb_connection_t *conn, Client *client, const char *mark) {
|
||||
if (client->mark != NULL)
|
||||
free(client->mark);
|
||||
client->mark = sstrdup(mark);
|
||||
|
||||
/* Make sure no other client has this mark set */
|
||||
Client *current;
|
||||
for (int c = 0; c < 10; c++)
|
||||
SLIST_FOREACH(current, &(workspaces[c].focus_stack), focus_clients) {
|
||||
if (current == client ||
|
||||
current->mark == NULL ||
|
||||
strcmp(current->mark, mark) != 0)
|
||||
continue;
|
||||
|
||||
free(current->mark);
|
||||
current->mark = NULL;
|
||||
/* We can break here since there can only be one other
|
||||
* client with this mark. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,22 @@ bool focus_window_in_container(xcb_connection_t *conn, Container *container, dir
|
||||
|
||||
typedef enum { THING_WINDOW, THING_CONTAINER, THING_SCREEN } thing_t;
|
||||
|
||||
static void jump_to_mark(xcb_connection_t *conn, const char *mark) {
|
||||
Client *current;
|
||||
LOG("Jumping to \"%s\"\n", mark);
|
||||
|
||||
for (int c = 0; c < 10; c++)
|
||||
SLIST_FOREACH(current, &(workspaces[c].focus_stack), focus_clients) {
|
||||
if (current->mark == NULL || strcmp(current->mark, mark) != 0)
|
||||
continue;
|
||||
|
||||
set_focus(conn, current, true);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG("No window with this mark found\n");
|
||||
}
|
||||
|
||||
static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t thing) {
|
||||
LOG("focusing direction %d\n", direction);
|
||||
|
||||
@ -817,6 +833,38 @@ void parse_command(xcb_connection_t *conn, const char *command) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (STARTS_WITH(command, "mark")) {
|
||||
if (last_focused == NULL) {
|
||||
LOG("There is no window to mark\n");
|
||||
return;
|
||||
}
|
||||
const char *rest = command + strlen("mark");
|
||||
while (*rest == ' ')
|
||||
rest++;
|
||||
if (*rest == '\0') {
|
||||
LOG("interactive mark starting\n");
|
||||
start_application("i3-input -p 'mark ' -l 1 -P 'Mark: '");
|
||||
} else {
|
||||
LOG("mark with \"%s\"\n", rest);
|
||||
client_mark(conn, last_focused, rest);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (STARTS_WITH(command, "goto")) {
|
||||
const char *rest = command + strlen("goto");
|
||||
while (*rest == ' ')
|
||||
rest++;
|
||||
if (*rest == '\0') {
|
||||
LOG("interactive go to mark starting\n");
|
||||
start_application("i3-input -p 'goto ' -l 1 -P 'Goto: '");
|
||||
} else {
|
||||
LOG("go to \"%s\"\n", rest);
|
||||
jump_to_mark(conn, rest);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Is it an <exit>? */
|
||||
if (STARTS_WITH(command, "exit")) {
|
||||
LOG("User issued exit-command, exiting without error.\n");
|
||||
|
Reference in New Issue
Block a user