swaymsg pretty-print for get_bindings

This adds the capability to swaymsg to pretty-print the bindings returned
by the get_bindings IPC command.

Each line of the pretty output contains a text representation of the
modifiers and key symbols along with the bound sway command.

The sort order of the bindings attempts to group bindings first by common
command prefix and then by key modifiers and symbols. This hybrid sort is
meant to be useful to a human reader.

Signed-off-by: Peter Grayson <pete@jpgrayson.net>
This commit is contained in:
Peter Grayson 2019-03-08 12:43:04 -05:00
parent 331bcac3ea
commit af7dd68559

View file

@ -254,6 +254,180 @@ static void pretty_print_output(json_object *o) {
printf("\n");
}
static int binding_cmp(const void *a, const void *b) {
int cmp = 0;
json_object *binding_a = *(json_object **)a;
json_object *binding_b = *(json_object **)b;
json_object *cmd_a;
json_object *cmd_b;
json_object_object_get_ex(binding_a, "command", &cmd_a);
json_object_object_get_ex(binding_b, "command", &cmd_b);
const char *cmd_a_str = json_object_get_string(cmd_a);
const char *cmd_b_str = json_object_get_string(cmd_b);
list_t *cmd_list_a = split_string(cmd_a_str, " ");
list_t *cmd_list_b = split_string(cmd_b_str, " ");
int min_cmd_list_len = (cmd_list_a->length < cmd_list_b->length) ?
cmd_list_a->length : cmd_list_b->length;
for (int i = 0; !cmp && i < min_cmd_list_len - 1; ++i) {
cmp = strcmp(cmd_list_a->items[i], cmd_list_b->items[i]);
}
list_free(cmd_list_a);
list_free(cmd_list_b);
if (cmp) {
return cmp;
}
json_object *modifiers_a;
json_object *modifiers_b;
json_object_object_get_ex(binding_a, "event_state_mask", &modifiers_a);
json_object_object_get_ex(binding_b, "event_state_mask", &modifiers_b);
size_t mod_len_a = json_object_array_length(modifiers_a);
size_t mod_len_b = json_object_array_length(modifiers_b);
for (size_t i = 0; i < mod_len_a && i < mod_len_b; ++i) {
json_object *mod_a = json_object_array_get_idx(modifiers_a, i);
json_object *mod_b = json_object_array_get_idx(modifiers_b, i);
const char *mod_a_str = json_object_get_string(mod_a);
const char *mod_b_str = json_object_get_string(mod_b);
cmp = strcmp(mod_a_str, mod_b_str);
if (cmp) {
return cmp;
}
}
if (mod_len_a < mod_len_b) {
return -1;
} else if (mod_len_a > mod_len_b) {
return 1;
}
json_object *symbols_a;
json_object *symbols_b;
json_object_object_get_ex(binding_a, "symbols", &symbols_a);
json_object_object_get_ex(binding_b, "symbols", &symbols_b);
size_t sym_len_a = json_object_array_length(symbols_a);
size_t sym_len_b = json_object_array_length(symbols_b);
for (size_t i = 0; i < sym_len_a && i < sym_len_b; ++i) {
json_object *sym_a = json_object_array_get_idx(symbols_a, i);
json_object *sym_b = json_object_array_get_idx(symbols_b, i);
const char *sym_a_str = json_object_get_string(sym_a);
const char *sym_b_str = json_object_get_string(sym_b);
cmp = strcmp(sym_a_str, sym_b_str);
if (cmp) {
return cmp;
}
}
if (sym_len_a < sym_len_b) {
return -1;
} else if (sym_len_a > sym_len_b) {
return 1;
}
json_object *codes_a;
json_object *codes_b;
json_object_object_get_ex(binding_a, "input_codes", &codes_a);
json_object_object_get_ex(binding_b, "input_codes", &codes_b);
size_t codes_len_a = json_object_array_length(codes_a);
size_t codes_len_b = json_object_array_length(codes_b);
for (size_t i = 0; i < codes_len_a && i < codes_len_b; ++i) {
uint32_t code_a = (uint32_t)json_object_get_int64(
json_object_array_get_idx(codes_a, i));
uint32_t code_b = (uint32_t)json_object_get_int64(
json_object_array_get_idx(codes_b, i));
if (code_a < code_b) {
return -1;
} else if (code_a > code_b) {
return 1;
}
}
return 0;
}
static void pretty_print_binding(json_object *binding) {
char keys_str[64];
size_t keys_len = 0;
size_t array_len;
json_object *modifiers;
json_object_object_get_ex(binding, "event_state_mask", &modifiers);
array_len = json_object_array_length(modifiers);
for (size_t i = 0; i < array_len; ++i) {
json_object *modifier = json_object_array_get_idx(modifiers, i);
const char *mod_str = json_object_get_string(modifier);
int len = snprintf(keys_str + keys_len, sizeof(keys_str) - keys_len,
"%s%s", keys_len ? "+" : "", mod_str);
if (len < 0) {
fprintf(stderr, "error printing modifier symbol\n");
return;
}
keys_len += len;
}
json_object *symbols;
json_object_object_get_ex(binding, "symbols", &symbols);
array_len = json_object_array_length(symbols);
for (size_t i = 0; i < array_len; ++i) {
json_object *symbol = json_object_array_get_idx(symbols, i);
const char *sym_str = json_object_get_string(symbol);
int len = snprintf(keys_str + keys_len, sizeof(keys_str) - keys_len,
"%s%s", keys_len ? "+" : "", sym_str);
if (len < 0) {
fprintf(stderr, "error printing key symbol\n");
return;
}
keys_len += len;
}
json_object *input_codes;
json_object_object_get_ex(binding, "input_codes", &input_codes);
array_len = json_object_array_length(input_codes);
for (size_t i = 0; i < array_len; ++i) {
json_object *input_code = json_object_array_get_idx(input_codes, i);
uint32_t code = (uint32_t)json_object_get_int64(input_code);
int len = snprintf(keys_str + keys_len, sizeof(keys_str) - keys_len,
"%s%d", keys_len ? "+" : "", code);
if (len < 0) {
fprintf(stderr, "error printing input code\n");
return;
}
keys_len += len;
}
json_object *command;
json_object_object_get_ex(binding, "command", &command);
const char *cmd_str = json_object_get_string(command);
printf("%-30s %s\n", keys_str, cmd_str);
}
static void pretty_print_bindings(json_object *binding_modes) {
json_object_object_foreach(binding_modes, mode_name, bindings) {
printf("%s:\n", mode_name);
json_object_array_sort(bindings, binding_cmp);
size_t len = json_object_array_length(bindings);
for (size_t i = 0; i < len; ++i) {
printf(" ");
pretty_print_binding(json_object_array_get_idx(bindings, i));
}
}
}
static void pretty_print_version(json_object *v) {
json_object *ver;
json_object_object_get_ex(v, "human_readable", &ver);
@ -270,7 +444,8 @@ static void pretty_print(int type, json_object *resp) {
if (type != IPC_COMMAND && type != IPC_GET_WORKSPACES &&
type != IPC_GET_INPUTS && type != IPC_GET_OUTPUTS &&
type != IPC_GET_VERSION && type != IPC_GET_SEATS &&
type != IPC_GET_CONFIG && type != IPC_SEND_TICK) {
type != IPC_GET_CONFIG && type != IPC_SEND_TICK &&
type != IPC_GET_BINDINGS) {
printf("%s\n", json_object_to_json_string_ext(resp,
JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED));
return;
@ -290,6 +465,11 @@ static void pretty_print(int type, json_object *resp) {
return;
}
if (type == IPC_GET_BINDINGS) {
pretty_print_bindings(resp);
return;
}
json_object *obj;
size_t len = json_object_array_length(resp);
for (size_t i = 0; i < len; ++i) {