diff -Nru herbstluftwm-0.1+git2011.11.28/BUGS herbstluftwm-0.1+git2011.12.09/BUGS --- herbstluftwm-0.1+git2011.11.28/BUGS 2011-11-28 17:59:28.000000000 +0000 +++ herbstluftwm-0.1+git2011.12.09/BUGS 2011-12-09 17:41:02.000000000 +0000 @@ -21,8 +21,8 @@ Planned features: - dump/load floating values - jumpto urgent - - completion für keybind (recursive!) - - completion für keyunbind + - completion for keybind (recursive!) + - completion for keyunbind - (optional) move cursor after focus change - optional focus selection after frame_split - focus_follows_mouse based on frames/monitors diff -Nru herbstluftwm-0.1+git2011.11.28/debian/changelog herbstluftwm-0.1+git2011.12.09/debian/changelog --- herbstluftwm-0.1+git2011.11.28/debian/changelog 2011-11-28 18:00:35.000000000 +0000 +++ herbstluftwm-0.1+git2011.12.09/debian/changelog 2011-12-09 17:42:49.000000000 +0000 @@ -1,4 +1,10 @@ -herbstluftwm (0.1+git2011.11.28-1) unstable; urgency=low +herbstluftwm (0.1+git2011.12.09-1) oneiric; urgency=low + + * New upstream version + + -- Christoph Egger Fri, 09 Dec 2011 18:42:43 +0100 + +herbstluftwm (0.1+git2011.11.28-1~oneiric1) oneiric; urgency=low * New upstream version * add docbook-xsl to Build-Depends (Closes: #650084) diff -Nru herbstluftwm-0.1+git2011.11.28/scripts/herbstcommander.sh herbstluftwm-0.1+git2011.12.09/scripts/herbstcommander.sh --- herbstluftwm-0.1+git2011.11.28/scripts/herbstcommander.sh 2011-11-28 17:59:28.000000000 +0000 +++ herbstluftwm-0.1+git2011.12.09/scripts/herbstcommander.sh 2011-12-09 17:41:02.000000000 +0000 @@ -27,8 +27,11 @@ while :; do if [[ "$forceexec" != 1 ]]; then completion=$($herbstclient_cmd complete "${#cmd[@]}" "${cmd[@]}") + if [[ "$?" = 7 ]] ; then + forceexec=1 + fi fi - if [[ -z "$completion" || "$forceexec" == 1 ]]; then + if [[ "$forceexec" == 1 ]]; then echo "Executing ${cmd[@]}" reply=$($herbstclient_cmd "${cmd[@]}") status=$? diff -Nru herbstluftwm-0.1+git2011.11.28/src/command.c herbstluftwm-0.1+git2011.12.09/src/command.c --- herbstluftwm-0.1+git2011.11.28/src/command.c 2011-11-28 17:59:28.000000000 +0000 +++ herbstluftwm-0.1+git2011.12.09/src/command.c 2011-12-09 17:41:02.000000000 +0000 @@ -13,6 +13,98 @@ #include #include +static char* completion_directions[] = { "left", "right", "down", "up",NULL}; +static char* completion_focus_args[] = { "-i", "-e", NULL }; +static char* completion_unrule_args[] = { "-F", "--all", NULL }; +static char* completion_flag_args[] = { "on", "off", "toggle", NULL }; +static char* completion_status[] = { "status", NULL }; + +static bool no_completion(int argc, char** argv, int pos) { + return false; +} + +static bool first_parameter_is_tag(int argc, char** argv, int pos); +static bool first_parameter_is_flag(int argc, char** argv, int pos); + +/* find out, if a parameter still expects a parameter at a certain index. + * only if this returns true, than a completion will be searched. + * + * if no match is found, then it defaults to "command still expects a + * parameter". + */ +struct { + char* command; /* the first argument */ + int min_index; /* rule will only be considered */ + /* if current pos >= min_index */ + bool (*function)(int argc, char** argv, int pos); +} g_parameter_expected[] = { + { "quit", 0, no_completion }, + { "reload", 0, no_completion }, + { "version", 0, no_completion }, + { "list_monitors", 0, no_completion }, + { "list_commands", 0, no_completion }, + { "add_monitor", 7, no_completion }, + { "dump", 2, no_completion }, + { "floating", 3, no_completion }, + { "floating", 2, first_parameter_is_tag }, + { "merge_tag", 3, no_completion }, + { "focus", 3, no_completion }, + { "focus", 2, first_parameter_is_flag }, + { "shift", 3, no_completion }, + { "shift", 2, first_parameter_is_flag }, + { "fullscreen", 2, no_completion }, + { "pseudotile", 2, no_completion }, + { "layout", 2, no_completion }, + { "load", 3, no_completion }, + { "load", 2, first_parameter_is_tag }, + { "move", 2, no_completion }, + { "rename", 3, no_completion }, + { "resize", 3, no_completion }, + { "unrule", 2, no_completion }, + { "use", 2, no_completion }, + { "add", 2, no_completion }, + { "get", 2, no_completion }, + { "set", 3, no_completion }, + { 0 }, +}; + +/* list of completions, if a line matches, then it will be used, the order + * doesnot matter */ +struct { + char* command; + int index; /* which parameter to complete */ + /* command name is index = 0 */ + /* === various methods, how to complete === */ + /* completion by function */ + void (*function)(int argc, char** argv, int pos, GString** output); + /* completion by a list of strings */ + char** list; +} g_completions[] = { + /* name , index, completion method */ + { "add_monitor", 2, .function = complete_against_tags }, + { "dump", 1, .function = complete_against_tags }, + { "floating", 1, .function = complete_against_tags }, + { "floating", 1, .list = completion_flag_args }, + { "floating", 1, .list = completion_status }, + { "floating", 2, .list = completion_flag_args }, + { "floating", 2, .list = completion_status }, + { "focus", 1, .list = completion_directions }, + { "focus", 1, .list = completion_focus_args }, + { "focus", 2, .list = completion_directions }, + { "fullscreen", 1, .list = completion_flag_args }, + { "layout", 1, .function = complete_against_tags }, + { "load", 1, .function = complete_against_tags }, + { "move", 1, .function = complete_against_tags }, + { "pseudotile", 1, .list = completion_flag_args }, + { "rename", 1, .function = complete_against_tags }, + { "resize", 1, .list = completion_directions }, + { "shift", 1, .list = completion_directions }, + { "shift", 1, .list = completion_focus_args }, + { "shift", 2, .list = completion_directions }, + { "unrule", 1, .list = completion_unrule_args }, + { "use", 1, .function = complete_against_tags }, + { 0 }, +}; int call_command(int argc, char** argv, GString** output) { if (argc <= 0) { @@ -59,6 +151,52 @@ return 0; } +void complete_against_list(char* needle, char** list, GString** output) { + size_t len = strlen(needle); + while (*list) { + char* name = *list; + if (!strncmp(needle, name, len)) { + *output = g_string_append(*output, name); + *output = g_string_append(*output, "\n"); + } + list++; + } +} + +void complete_against_tags(int argc, char** argv, int pos, GString** output) { + char* needle; + if (pos >= argc) { + needle = ""; + } else { + needle = argv[pos]; + } + size_t len = strlen(needle); + for (int i = 0; i < g_tags->len; i++) { + char* name = g_array_index(g_tags, HSTag*, i)->name->str; + if (!strncmp(needle, name, len)) { + *output = g_string_append(*output, name); + *output = g_string_append(*output, "\n"); + } + } +} + +bool parameter_expected(int argc, char** argv, int pos) { + if (pos <= 0 || argc < 1) { + /* no parameter if there is no command */ + return false; + } + for (int i = 0; i < LENGTH(g_parameter_expected) + && g_parameter_expected[i].command; i++) { + if (pos < g_parameter_expected[i].min_index) { + continue; + } + if (!strcmp(g_parameter_expected[i].command, argv[0])) { + return g_parameter_expected[i].function(argc, argv, pos); + } + } + return true; +} + int complete_command(int argc, char** argv, GString** output) { // usage: complete POSITION command to complete ... if (argc < 2) { @@ -79,6 +217,10 @@ } i++; } + return 0; + } + if (!parameter_expected(argc - 2, argv + 2, position)) { + return HERBST_NO_PARAMETER_EXPECTED; } if (argc >= 3) { char* str = (argc >= 4) ? argv[3] : ""; @@ -101,9 +243,7 @@ } } } - else if ((position == 1 && !strcmp(argv[2], "use")) || - (position == 1 && !strcmp(argv[2], "move")) || - (position >= 1 && position <= 2 + else if ((position >= 1 && position <= 2 && !strcmp(argv[2], "merge_tag"))) { // we can complete first argument of use // or first and second argument of merge_tag @@ -128,14 +268,25 @@ } } } - else if (position == 1 && (!strcmp(argv[2], "focus") || - !strcmp(argv[2], "resize") || !strcmp(argv[2], "shift"))) { - char* words[] = { "left", "right", "up", "down" }; - for (int i = 0; i < LENGTH(words); i++) { - char* name = words[i]; - if (!strncmp(str, name, len)) { - *output = g_string_append(*output, name); - *output = g_string_append(*output, "\n"); + else { + for (int i = 0; i < LENGTH(g_completions); i++) { + if (!g_completions[i].command + || position != g_completions[i].index + || strcmp(argv[2], g_completions[i].command)) { + continue; + } + char* needle = ((position + 2) < argc) ? argv[position + 2] : ""; + if (!needle) { + needle = ""; + } + // try to complete + if (g_completions[i].function) { + g_completions[i].function(argc - 2, argv + 2, + position, output); + } + if (g_completions[i].list) { + complete_against_list(needle, g_completions[i].list, + output); } } } @@ -143,7 +294,21 @@ return 0; } +bool first_parameter_is_tag(int argc, char** argv, int pos) { + // only complete if first parameter is a valid tag + if (argc >= 2 && find_tag(argv[1]) && pos == 2) { + return true; + } else { + return false; + } +} - - +bool first_parameter_is_flag(int argc, char** argv, int pos) { + // only complete if first parameter is a flag like -i or -e + if (argc >= 2 && argv[1][0] == '-' && pos == 2) { + return true; + } else { + return false; + } +} diff -Nru herbstluftwm-0.1+git2011.11.28/src/command.h herbstluftwm-0.1+git2011.12.09/src/command.h --- herbstluftwm-0.1+git2011.11.28/src/command.h 2011-11-28 17:59:28.000000000 +0000 +++ herbstluftwm-0.1+git2011.12.09/src/command.h 2011-12-09 17:41:02.000000000 +0000 @@ -42,6 +42,8 @@ int complete_command(int argc, char** argv, GString** output); void complete_settings(char* str, GString** output); +void complete_against_list(char* needle, char** list, GString** output); +void complete_against_tags(int argc, char** argv, int pos, GString** output); #endif diff -Nru herbstluftwm-0.1+git2011.11.28/src/ipc-protocol.h herbstluftwm-0.1+git2011.12.09/src/ipc-protocol.h --- herbstluftwm-0.1+git2011.11.28/src/ipc-protocol.h 2011-08-28 12:04:29.000000000 +0000 +++ herbstluftwm-0.1+git2011.12.09/src/ipc-protocol.h 2011-12-09 17:41:02.000000000 +0000 @@ -30,6 +30,7 @@ HERBST_SETTING_NOT_FOUND, HERBST_TAG_IN_USE, HERBST_FORBIDDEN, + HERBST_NO_PARAMETER_EXPECTED, }; #endif