summaryrefslogtreecommitdiff
path: root/degesch.c
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2015-07-09 22:32:14 +0200
committerPřemysl Janouch <p.janouch@gmail.com>2015-07-09 22:34:42 +0200
commitba1ac58d9d48a955786c05dddf17f57cffd9baf0 (patch)
tree92314cd4223a6ec5bdd584af5aa9a5d17f7d52d6 /degesch.c
parent5e7f9882dd5edfb8050d8fc487ba1378cbcb27dd (diff)
downloadxK-ba1ac58d9d48a955786c05dddf17f57cffd9baf0.tar.gz
xK-ba1ac58d9d48a955786c05dddf17f57cffd9baf0.tar.xz
xK-ba1ac58d9d48a955786c05dddf17f57cffd9baf0.zip
degesch: add backend support for aliases
Diffstat (limited to 'degesch.c')
-rw-r--r--degesch.c110
1 files changed, 93 insertions, 17 deletions
diff --git a/degesch.c b/degesch.c
index 26a1cbd..0119b13 100644
--- a/degesch.c
+++ b/degesch.c
@@ -1610,6 +1610,7 @@ register_config_modules (struct app_context *ctx)
struct config *config = &ctx->config;
// The servers are loaded later when we can create buffers for them
config_register_module (config, "servers", NULL, NULL);
+ config_register_module (config, "aliases", NULL, NULL);
config_register_module (config, "behaviour", load_config_behaviour, ctx);
config_register_module (config, "attributes", load_config_attributes, ctx);
}
@@ -7625,8 +7626,9 @@ init_partial_matching_user_command_map (struct str_map *partial)
}
}
-static void
-process_user_command (struct app_context *ctx, char *input)
+static bool
+process_user_command
+ (struct app_context *ctx, const char *command_name, char *input)
{
static bool initialized = false;
static struct str_map partial;
@@ -7636,9 +7638,8 @@ process_user_command (struct app_context *ctx, char *input)
initialized = true;
}
- char *command_name = cut_word (&input);
if (try_handle_buffer_goto (ctx, command_name))
- return;
+ return true;
struct handler_args args =
{
@@ -7647,10 +7648,11 @@ process_user_command (struct app_context *ctx, char *input)
.arguments = input,
};
- struct command_handler *handler = str_map_find (&partial, command_name);
- if (!handler)
- log_global_error (ctx, "#s: #s", "No such command", command_name);
- else if ((handler->flags & HANDLER_SERVER)
+ struct command_handler *handler;
+ if (!(handler = str_map_find (&map, command_name)))
+ return false;
+
+ if ((handler->flags & HANDLER_SERVER)
&& args.buffer->type == BUFFER_GLOBAL)
log_global_error (ctx, "/#s: #s",
command_name, "can't do this from a global buffer");
@@ -7671,6 +7673,64 @@ process_user_command (struct app_context *ctx, char *input)
else if (!handler->handler (&args))
log_global_error (ctx,
"#s: /#s #s", "Usage", handler->name, handler->usage);
+ return true;
+}
+
+static char *
+expand_alias_definition (const struct str *definition, const char *arguments)
+{
+ struct str_vector v;
+ str_vector_init (&v);
+ split_str_ignore_empty (arguments, ' ', &v);
+
+ struct str expanded;
+ str_init (&expanded);
+
+ // TODO: eventually also support argument ranges
+ bool escape = false;
+ for (const char *p = definition->str; *p; p++)
+ {
+ if (!escape)
+ {
+ if (*p == '$' && p[1])
+ escape = true;
+ else
+ str_append_c (&expanded, *p);
+ continue;
+ }
+
+ int as_number = *p - '0';
+ if (as_number > 0 && as_number <= 9
+ && (size_t) as_number <= v.len)
+ str_append (&expanded, v.vector[as_number - 1]);
+ else if (*p == '*')
+ str_append (&expanded, arguments);
+ else if (*p == '$')
+ str_append_c (&expanded, '$');
+ else
+ str_append_printf (&expanded, "$%c", *p);
+ escape = false;
+ }
+ str_vector_free (&v);
+ return str_steal (&expanded);
+}
+
+static char *
+expand_alias (struct app_context *ctx, const char *alias_name, char *input)
+{
+ struct str_map *aliases =
+ &config_item_get (ctx->config.root, "aliases", NULL)->value.object;
+
+ struct config_item_ *entry = str_map_find (aliases, alias_name);
+ if (!entry)
+ return NULL;
+
+ if (config_item_type_is_string (entry->type))
+ return expand_alias_definition (&entry->value.string, input);
+
+ log_global_error (ctx, "Error executing `/%s': "
+ "alias definition is not a string", alias_name);
+ return NULL;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -7708,20 +7768,36 @@ send_message_to_current_buffer (struct app_context *ctx, char *message)
}
static void
+process_input_utf8 (struct app_context *ctx, char *input, int alias_level)
+{
+ if (*input != '/' || *++input == '/')
+ {
+ send_message_to_current_buffer (ctx, input);
+ return;
+ }
+
+ char *name = cut_word (&input);
+ if (process_user_command (ctx, name, input))
+ return;
+
+ char *expanded = expand_alias (ctx, name, input);
+ if (!expanded)
+ log_global_error (ctx, "#s: /#s", "No such command or alias", name);
+ else if (alias_level != 0)
+ log_global_error (ctx, "#s: /#s", "Aliases can't nest", name);
+ else
+ process_input_utf8 (ctx, expanded, alias_level++);
+ free (expanded);
+}
+
+static void
process_input (struct app_context *ctx, char *user_input)
{
char *input;
- size_t len;
-
- if (!(input = iconv_xstrdup (ctx->term_to_utf8, user_input, -1, &len)))
+ if (!(input = iconv_xstrdup (ctx->term_to_utf8, user_input, -1, NULL)))
print_error ("character conversion failed for `%s'", "user input");
- else if (input[0] != '/')
- send_message_to_current_buffer (ctx, input);
- else if (input[1] == '/')
- send_message_to_current_buffer (ctx, input + 1);
else
- process_user_command (ctx, input + 1);
-
+ process_input_utf8 (ctx, input, 0);
free (input);
}