From 4913db7d5237f49f0b4b94e52c84687c6f0a4adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Adel=C3=A9?= Date: Sat, 3 Mar 2018 21:11:35 +0100 Subject: [PATCH] Add a help feature to bspc command, Fix #776 --- Makefile | 4 +- src/bspc.c | 3 +- src/help.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++ src/help.h | 38 ++++++++++++ src/helpers.c | 10 ++++ src/helpers.h | 1 + src/messages.c | 53 ++++++++++------- src/messages.h | 1 - 8 files changed, 242 insertions(+), 27 deletions(-) create mode 100644 src/help.c create mode 100644 src/help.h diff --git a/Makefile b/Makefile index 9f49aafb..c2fa39d4 100644 --- a/Makefile +++ b/Makefile @@ -18,9 +18,9 @@ MD_DOCS = README.md doc/CHANGELOG.md doc/CONTRIBUTING.md doc/INSTALL.md doc/M XSESSIONS ?= $(PREFIX)/share/xsessions WM_SRC = bspwm.c helpers.c geometry.c jsmn.c settings.c monitor.c desktop.c tree.c stack.c history.c \ - events.c pointer.c window.c messages.c parse.c query.c restore.c rule.c ewmh.c subscribe.c + events.c pointer.c window.c messages.c parse.c query.c restore.c rule.c ewmh.c subscribe.c help.c WM_OBJ := $(WM_SRC:.c=.o) -CLI_SRC = bspc.c helpers.c +CLI_SRC = bspc.c helpers.c help.c CLI_OBJ := $(CLI_SRC:.c=.o) all: bspwm bspc diff --git a/src/bspc.c b/src/bspc.c index ca91d076..9c54b65e 100644 --- a/src/bspc.c +++ b/src/bspc.c @@ -30,6 +30,7 @@ #include #include #include +#include "help.h" #include "helpers.h" #include "common.h" @@ -40,7 +41,7 @@ int main(int argc, char *argv[]) char msg[BUFSIZ], rsp[BUFSIZ]; if (argc < 2) { - err("No arguments given.\n"); + show_bspc_help(); } sock_address.sun_family = AF_UNIX; diff --git a/src/help.c b/src/help.c new file mode 100644 index 00000000..a140b0b1 --- /dev/null +++ b/src/help.c @@ -0,0 +1,159 @@ +/* Copyright (c) 2012, Bastien Dejean + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "helpers.h" +#include "help.h" + +void show_bspc_help(void) { + warn("bspc usage:\n"); + warn(" node\n"); + warn(" desktop\n"); + warn(" monitor\n"); + warn(" query\n"); + warn(" wm\n"); + warn(" rule\n"); + warn(" subscribe\n"); + warn(" config\n"); + warn(" quit\n"); + exit(EXIT_SUCCESS); +} + +void show_node_help(FILE *rsp) { + fail(rsp,"node usage:\n"); + fail(rsp," -f,--focus [NODE_SEL] Focus the selected or given node\n"); + fail(rsp," -a,--activate [NODE_SEL] Activate the selected or given node\n"); + fail(rsp," -d,--to-desktop DESKTOP_SEL Send the selected node to the given desktop\n"); + fail(rsp," -m,--to-monitor MONITOR_SEL Send the selected node to the given monitor\n"); + fail(rsp," -n,--to-node NODE_SEL Transplant the selected node to the given node\n"); + fail(rsp," -s,--swap NODE_SEL Swap the selected node with the given node\n"); + fail(rsp," -p,--presel-dir [~]DIR|cancel Preselect the splitting area of the selected node (or cancel the preselection)\n"); + fail(rsp," -o,--presel-ratio RATIO Set the splitting ratio of the preselection area\n"); + fail(rsp," -v,--move dx dy Move the selected window by dx pixels horizontally and dy pixels vertically\n"); + fail(rsp," -z,--resize top|left|bottom|right|top_left|top_right|bottom_right|bottom_left dx dy\n"); + fail(rsp," Resize the selected window by moving the given handle by dx pixels horizontally and dy pixels vertically.\n"); + fail(rsp,"\n"); + fail(rsp," -r,--ratio RATIO|(+|-)PIXELS Set the splitting ratio of the selected node (0 < RATIO < 1).\n"); + fail(rsp," -R,--rotate 90|270|180 Rotate the tree rooted at the selected node\n"); + fail(rsp," -Z,--flip horizontal|vertical Flip the the tree rooted at selected node\n"); + fail(rsp," -E,--equalize Reset the split ratios of the tree rooted at the selected node to their default value\n"); + fail(rsp," -B,--balance Adjust the split ratios of the tree rooted at the selected node so that all windows occupy the same area\n"); + fail(rsp," -C,--circulate forward|backward Circulate the windows of the tree rooted at the selected node\n"); + fail(rsp," -t,--state [~](tiled|pseudo_tiled|floating|fullscreen) Set the state of the selected windo\n"); + fail(rsp," -g,--flag hidden|sticky|private|locked[=on|off] Set or toggle the given flag for the selected nod\n"); + fail(rsp," -l,--layer below|normal|above Set the stacking layer of the selected window\n"); + fail(rsp," -i,--insert-receptacle Insert a receptacle node at the selected node\n"); + fail(rsp," -c,--close Close the windows rooted at the selected node\n"); + fail(rsp," -k,--kill Kill the windows rooted at the selected nodes\n"); + fail(rsp," -h,--help Help\n"); +} + +void show_desktop_help(FILE *rsp) { + fail(rsp,"desktop usage:\n"); + fail(rsp," -f, --focus [DESKTOP_SEL] Focus the selected or given desktop\n"); + fail(rsp," -a, --activate [DESKTOP_SEL] Activate the selected or given desktop\n"); + fail(rsp," -m, --to-monitor MONITOR_SEL Send the selected desktop to the given monitor\n"); + fail(rsp," -s, --swap DESKTOP_SEL Swap the selected desktop with the given desktop\n"); + fail(rsp," -b, --bubble CYCLE_DIR Bubble the selected desktop in the given direction\n"); + fail(rsp," -l, --layout CYCLE_DIR|monocle|tiled Set or cycle the layout of the selected desktop\n"); + fail(rsp," -n, --rename Rename the selected desktop\n"); + fail(rsp," -r, --remove Remove the selected desktop\n"); + fail(rsp," -h,--help Help\n"); +} + +void show_monitor_help(FILE *rsp) { + fail(rsp,"monitor usage:\n"); + fail(rsp," -f, --focus [MONITOR_SEL] Focus the selected or given monitor\n"); + fail(rsp," -s, --swap MONITOR_SEL Swap the selected monitor with the given monitor\n"); + fail(rsp," -d, --reset-desktop Rename, add or remove desktops depending on whether the number of given names is equal\n"); + fail(rsp," -a, --add-desktops Create desktops with the given names in the selected monito\n"); + fail(rsp," -o, --reorder-desktops Reorder the desktops of the selected monitor to match the given order\n"); + fail(rsp," -g, --rectangle WxH+X+Y Set the rectangle of the selected monitor\n"); + fail(rsp," -n, --rename Rename the selected monitor\n"); + fail(rsp," -r, --remove Remove the selected monitor\n"); + fail(rsp," -h,--help Help\n"); +} + +void show_query_help(FILE *rsp) { + fail(rsp,"query usage:\n"); + fail(rsp," -N, --nodes [NODE_SEL] List the IDs of the matching nodes\n"); + fail(rsp," -D, --desktops [DESKTOP_SEL] List the IDs of the matching desktops\n"); + fail(rsp," -M, --monitors [MONITOR_SEL] List the IDs of the matching monitors\n"); + fail(rsp," -T, --tree Print a JSON representation of the matching item\n"); + fail(rsp,"\n"); + fail(rsp," Options:\n"); + fail(rsp," -m,--monitor [MONITOR_SEL]\n"); + fail(rsp," -d,--desktop [DESKTOP_SEL]\n"); + fail(rsp," -n, --node [NODE_SEL]\n"); + fail(rsp,"\n"); + fail(rsp," -h,--help Help\n"); +} + +void show_wm_help(FILE *rsp) { + fail(rsp,"wm usage: \n"); + fail(rsp," -d, --dump-state Dump the current world state on standard output\n"); + fail(rsp," -l, --load-state Load a world state from the given file\n"); + fail(rsp," -a, --add-monitor WxH+X+Y Add a monitor for the given name and rectangle\n"); + fail(rsp," -o, --adopt-orphans Manage all the unmanaged windows remaining from a previous session\n"); + fail(rsp," -h, --record-history on|off Enable or disable the recording of node focus history\n"); + fail(rsp," -O, --reorder-monitors Reorder the list of monitors to match the given order\n"); + fail(rsp," -g, --get-status Print the current status information\n"); + fail(rsp," -e,--help Help\n"); +} + + +void show_rule_help(FILE *rsp) { + fail(rsp,"rule usage:\n"); + fail(rsp," -a,--add (|*)[:(|*)] [-o|--one-shot]\n"); + fail(rsp," [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|node=NODE_SEL] [state=STATE] [layer=LAYER] [split_dir=DIR] \n"); + fail(rsp," [split_ratio=RATIO] [(hidden|sticky|private|locked|center|follow|manage|focus|border)=(on|off)]\n"); + fail(rsp," Create a new rule\n"); + fail(rsp,"\n"); + fail(rsp," -r,--remove ^|head|tail|(|*)[:(|*)]... Remove the given rules\n"); + fail(rsp," -l,--list List the rules\n"); + fail(rsp," -h,--help Help\n"); +} + +void show_subscribe_help(FILE *rsp) { + fail(rsp,"subscribe usage:\n"); + fail(rsp," (all|report|monitor|desktop|node|…​)*\n"); + fail(rsp,"\n"); + fail(rsp," Options:\n"); + fail(rsp," -f, --fifo\n"); + fail(rsp," -c, --count COUNT\n"); + fail(rsp," -h,--help Help\n"); +} + +void show_config_help(FILE *rsp) { + fail(rsp,"config usage:\n"); + fail(rsp," [-m MONITOR_SEL] []\n"); + fail(rsp," [-d DESKTOP_SEL] []\n"); + fail(rsp," [-n NODE_SEL] []\n"); + fail(rsp,"\n"); + fail(rsp," Options:\n"); + fail(rsp," -f, --fifo Print a path to a FIFO from which events can be read and return\n"); + fail(rsp," -c, --count COUNT Stop the corresponding bspc process after having received COUNT events\n"); + fail(rsp," -h,--help Help\n"); +} diff --git a/src/help.h b/src/help.h new file mode 100644 index 00000000..8b0de0a6 --- /dev/null +++ b/src/help.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2012, Bastien Dejean + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BSPWM_HELP_H +#define BSPWM_HELP_H + +void show_bspc_help(void); +void show_node_help(FILE *rsp); +void show_desktop_help(FILE *rsp); +void show_monitor_help(FILE *rsp); +void show_query_help(FILE *rsp); +void show_wm_help(FILE *rsp); +void show_rule_help(FILE *rsp); +void show_subscribe_help(FILE *rsp); +void show_config_help(FILE *rsp); + +#endif diff --git a/src/helpers.c b/src/helpers.c index 1fc555f5..95193b01 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -31,6 +31,7 @@ #include #include #include +#include "common.h" #include "bspwm.h" void warn(char *fmt, ...) @@ -51,6 +52,15 @@ void err(char *fmt, ...) exit(EXIT_FAILURE); } +void fail(FILE *rsp, char *fmt, ...) +{ + fprintf(rsp, FAILURE_MESSAGE); + va_list ap; + va_start(ap, fmt); + vfprintf(rsp, fmt, ap); + va_end(ap); +} + char *read_string(const char *file_path, size_t *tlen) { if (file_path == NULL) { diff --git a/src/helpers.h b/src/helpers.h index 82bad85e..ae9b28a6 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -77,6 +77,7 @@ void warn(char *fmt, ...); void err(char *fmt, ...); +void fail(FILE *rsp, char *fmt, ...); char *read_string(const char *file_path, size_t *tlen); char *copy_string(char *str, size_t len); char *mktempfifo(const char *template); diff --git a/src/messages.c b/src/messages.c index 70d3be45..bc619f26 100644 --- a/src/messages.c +++ b/src/messages.c @@ -38,9 +38,9 @@ #include "settings.h" #include "tree.h" #include "window.h" -#include "common.h" #include "parse.h" #include "messages.h" +#include "help.h" void handle_message(char *msg, int msg_len, FILE *rsp) { @@ -73,7 +73,7 @@ void handle_message(char *msg, int msg_len, FILE *rsp) if (num < 1) { free(args); - fail(rsp, "No arguments given.\n"); + show_bspc_help(); return; } @@ -114,7 +114,7 @@ void process_message(char **args, int num, FILE *rsp) void cmd_node(char **args, int num, FILE *rsp) { if (num < 1) { - fail(rsp, "node: Missing arguments.\n"); + show_node_help(rsp); return; } @@ -131,8 +131,8 @@ void cmd_node(char **args, int num, FILE *rsp) } } - if (num < 1) { - fail(rsp, "node: Missing commands.\n"); +if (num < 1) { + show_node_help(rsp); return; } @@ -582,6 +582,8 @@ void cmd_node(char **args, int num, FILE *rsp) kill_node(trg.monitor, trg.desktop, trg.node); changed = true; break; + } else if (streq("-h", *args) || streq("--help", *args)) { + show_node_help(rsp); } else { fail(rsp, "node: Unknown command: '%s'.\n", *args); break; @@ -598,7 +600,7 @@ void cmd_node(char **args, int num, FILE *rsp) void cmd_desktop(char **args, int num, FILE *rsp) { if (num < 1) { - fail(rsp, "desktop: Missing arguments.\n"); + show_desktop_help(rsp); return; } @@ -616,7 +618,7 @@ void cmd_desktop(char **args, int num, FILE *rsp) } if (num < 1) { - fail(rsp, "desktop: Missing commands.\n"); + show_desktop_help(rsp); return; } @@ -774,6 +776,8 @@ void cmd_desktop(char **args, int num, FILE *rsp) fail(rsp, ""); break; } + } else if (streq("-h", *args) || streq("--help", *args)) { + show_desktop_help(rsp); } else { fail(rsp, "desktop: Unknown command: '%s'.\n", *args); break; @@ -789,7 +793,7 @@ void cmd_desktop(char **args, int num, FILE *rsp) void cmd_monitor(char **args, int num, FILE *rsp) { if (num < 1) { - fail(rsp, "monitor: Missing arguments.\n"); + show_monitor_help(rsp); return; } @@ -807,7 +811,7 @@ void cmd_monitor(char **args, int num, FILE *rsp) } if (num < 1) { - fail(rsp, "monitor: Missing commands.\n"); + show_monitor_help(rsp); return; } @@ -927,6 +931,8 @@ void cmd_monitor(char **args, int num, FILE *rsp) return; } rename_monitor(trg.monitor, *args); + } else if (streq("-h", *args) || streq("--help", *args)) { + show_monitor_help(rsp); } else { fail(rsp, "monitor: Unknown command: '%s'.\n", *args); return; @@ -947,7 +953,7 @@ void cmd_query(char **args, int num, FILE *rsp) uint8_t d = 0; if (num < 1) { - fail(rsp, "query: Missing arguments.\n"); + show_query_help(rsp); return; } @@ -1060,6 +1066,8 @@ void cmd_query(char **args, int num, FILE *rsp) } } else if (streq("--names", *args)) { print_ids = false; + } else if (streq("-h", *args) || streq("--help", *args)) { + show_query_help(rsp); } else { fail(rsp, "query: Unknown option: '%s'.\n", *args); goto end; @@ -1119,7 +1127,7 @@ void cmd_query(char **args, int num, FILE *rsp) void cmd_rule(char **args, int num, FILE *rsp) { if (num < 1) { - fail(rsp, "rule: Missing commands.\n"); + show_rule_help(rsp); return; } @@ -1173,6 +1181,8 @@ void cmd_rule(char **args, int num, FILE *rsp) } } else if (streq("-l", *args) || streq("--list", *args)) { list_rules(rsp); + } else if (streq("-h", *args) || streq("--help", *args)) { + show_rule_help(rsp); } else { fail(rsp, "rule: Unknown command: '%s'.\n", *args); return; @@ -1184,7 +1194,7 @@ void cmd_rule(char **args, int num, FILE *rsp) void cmd_wm(char **args, int num, FILE *rsp) { if (num < 1) { - fail(rsp, "wm: Missing commands.\n"); + show_wm_help(rsp); return; } @@ -1255,6 +1265,8 @@ void cmd_wm(char **args, int num, FILE *rsp) fail(rsp, "wm %s: Invalid argument: '%s'.\n", *(args - 1), *args); break; } + } else if (streq("-e", *args) || streq("--help", *args)) { + show_wm_help(rsp); } else { fail(rsp, "wm: Unknown command: '%s'.\n", *args); break; @@ -1290,6 +1302,8 @@ void cmd_subscribe(char **args, int num, FILE *rsp) } } else if (parse_subscriber_mask(*args, &mask)) { field |= mask; + } else if (streq("-h", *args) || streq("--help", *args)) { + show_subscribe_help(rsp); } else { fail(rsp, "subscribe: Invalid argument: '%s'.\n", *args); goto failed; @@ -1340,7 +1354,7 @@ void cmd_quit(char **args, int num, FILE *rsp) void cmd_config(char **args, int num, FILE *rsp) { if (num < 1) { - fail(rsp, "config: Missing arguments.\n"); + show_config_help(rsp); return; } @@ -1381,6 +1395,8 @@ void cmd_config(char **args, int num, FILE *rsp) handle_failure(ret, "config -n", *args, rsp); return; } + } else if (streq("-h", *args) || streq("--help", *args)) { + show_config_help(rsp); } else { fail(rsp, "config: Unknown option: '%s'.\n", *args); return; @@ -1772,13 +1788,4 @@ void handle_failure(int code, char *src, char *val, FILE *rsp) fail(rsp, ""); break; } -} - -void fail(FILE *rsp, char *fmt, ...) -{ - fprintf(rsp, FAILURE_MESSAGE); - va_list ap; - va_start(ap, fmt); - vfprintf(rsp, fmt, ap); - va_end(ap); -} +} \ No newline at end of file diff --git a/src/messages.h b/src/messages.h index 8f45434b..026fabd0 100644 --- a/src/messages.h +++ b/src/messages.h @@ -42,6 +42,5 @@ void cmd_config(char **args, int num, FILE *rsp); void set_setting(coordinates_t loc, char *name, char *value, FILE *rsp); void get_setting(coordinates_t loc, char *name, FILE* rsp); void handle_failure(int code, char *src, char *val, FILE *rsp); -void fail(FILE *rsp, char *fmt, ...); #endif