degesch: add backend support for aliases
This commit is contained in:
parent
5e7f9882dd
commit
ba1ac58d9d
110
degesch.c
110
degesch.c
@ -1610,6 +1610,7 @@ register_config_modules (struct app_context *ctx)
|
|||||||
struct config *config = &ctx->config;
|
struct config *config = &ctx->config;
|
||||||
// The servers are loaded later when we can create buffers for them
|
// The servers are loaded later when we can create buffers for them
|
||||||
config_register_module (config, "servers", NULL, NULL);
|
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, "behaviour", load_config_behaviour, ctx);
|
||||||
config_register_module (config, "attributes", load_config_attributes, 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
|
static bool
|
||||||
process_user_command (struct app_context *ctx, char *input)
|
process_user_command
|
||||||
|
(struct app_context *ctx, const char *command_name, char *input)
|
||||||
{
|
{
|
||||||
static bool initialized = false;
|
static bool initialized = false;
|
||||||
static struct str_map partial;
|
static struct str_map partial;
|
||||||
@ -7636,9 +7638,8 @@ process_user_command (struct app_context *ctx, char *input)
|
|||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *command_name = cut_word (&input);
|
|
||||||
if (try_handle_buffer_goto (ctx, command_name))
|
if (try_handle_buffer_goto (ctx, command_name))
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
struct handler_args args =
|
struct handler_args args =
|
||||||
{
|
{
|
||||||
@ -7647,10 +7648,11 @@ process_user_command (struct app_context *ctx, char *input)
|
|||||||
.arguments = input,
|
.arguments = input,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct command_handler *handler = str_map_find (&partial, command_name);
|
struct command_handler *handler;
|
||||||
if (!handler)
|
if (!(handler = str_map_find (&map, command_name)))
|
||||||
log_global_error (ctx, "#s: #s", "No such command", command_name);
|
return false;
|
||||||
else if ((handler->flags & HANDLER_SERVER)
|
|
||||||
|
if ((handler->flags & HANDLER_SERVER)
|
||||||
&& args.buffer->type == BUFFER_GLOBAL)
|
&& args.buffer->type == BUFFER_GLOBAL)
|
||||||
log_global_error (ctx, "/#s: #s",
|
log_global_error (ctx, "/#s: #s",
|
||||||
command_name, "can't do this from a global buffer");
|
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))
|
else if (!handler->handler (&args))
|
||||||
log_global_error (ctx,
|
log_global_error (ctx,
|
||||||
"#s: /#s #s", "Usage", handler->name, handler->usage);
|
"#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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
@ -7707,21 +7767,37 @@ 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
|
static void
|
||||||
process_input (struct app_context *ctx, char *user_input)
|
process_input (struct app_context *ctx, char *user_input)
|
||||||
{
|
{
|
||||||
char *input;
|
char *input;
|
||||||
size_t len;
|
if (!(input = iconv_xstrdup (ctx->term_to_utf8, user_input, -1, NULL)))
|
||||||
|
|
||||||
if (!(input = iconv_xstrdup (ctx->term_to_utf8, user_input, -1, &len)))
|
|
||||||
print_error ("character conversion failed for `%s'", "user input");
|
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
|
else
|
||||||
process_user_command (ctx, input + 1);
|
process_input_utf8 (ctx, input, 0);
|
||||||
|
|
||||||
free (input);
|
free (input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user