aboutsummaryrefslogtreecommitdiffhomepage
path: root/builtin_commandline.cpp
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-08-15 18:14:36 -0700
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-08-15 18:14:36 -0700
commit06400b83b188156f31ed92216ec27122d29f88cd (patch)
tree2f9cec409aba50449638c8d4361b4dafe530f3ec /builtin_commandline.cpp
parentfe68d30be97853865b24ad5f5998d3e50769f860 (diff)
Support for command wrapping ("aliases")
Add the --wraps option to 'complete' and 'function'. This allows a command to (recursively) inherit the completions of a wrapped command. Fixes #393. When evaluating a completion, we inspect the entire "wrap chain" for a command, i.e. we follow the sequence of wrapping until we either hit a loop (which we silently ignore) or the end of the chain. We then evaluate completions as if the wrapping command were substituted with the wrapped command. Currently this only works for commands, i.e. 'complete --command gco --wraps git\ checkout' won't work (that would seem to encroaching on abbreviations anyways). It might be useful to show an error message for that case. The commandline builtin reflects the commandline with the wrapped command substituted in, so e.g. git completions (which inspect the command line) will just work. This sort of command line munging is also performed by 'complete -C' so it's not totally without precedent. 'alias will also now mark its generated function as wrapping the 'target.
Diffstat (limited to 'builtin_commandline.cpp')
-rw-r--r--builtin_commandline.cpp57
1 files changed, 53 insertions, 4 deletions
diff --git a/builtin_commandline.cpp b/builtin_commandline.cpp
index 88084c3b..0af6f656 100644
--- a/builtin_commandline.cpp
+++ b/builtin_commandline.cpp
@@ -79,6 +79,51 @@ static size_t get_cursor_pos()
return current_cursor_pos;
}
+static pthread_mutex_t transient_commandline_lock = PTHREAD_MUTEX_INITIALIZER;
+static wcstring_list_t *get_transient_stack()
+{
+ ASSERT_IS_MAIN_THREAD();
+ ASSERT_IS_LOCKED(transient_commandline_lock);
+ // A pointer is a little more efficient than an object as a static because we can elide the thread-safe initialization
+ static wcstring_list_t *result = NULL;
+ if (! result)
+ {
+ result = new wcstring_list_t();
+ }
+ return result;
+}
+
+static bool get_top_transient(wcstring *out_result)
+{
+ ASSERT_IS_MAIN_THREAD();
+ bool result = false;
+ scoped_lock locker(transient_commandline_lock);
+ const wcstring_list_t *stack = get_transient_stack();
+ if (! stack->empty())
+ {
+ out_result->assign(stack->back());
+ result = true;
+ }
+ return result;
+}
+
+builtin_commandline_scoped_transient_t::builtin_commandline_scoped_transient_t(const wcstring &cmd)
+{
+ ASSERT_IS_MAIN_THREAD();
+ scoped_lock locker(transient_commandline_lock);
+ wcstring_list_t *stack = get_transient_stack();
+ stack->push_back(cmd);
+ this->token = stack->size();
+}
+
+builtin_commandline_scoped_transient_t::~builtin_commandline_scoped_transient_t()
+{
+ ASSERT_IS_MAIN_THREAD();
+ scoped_lock locker(transient_commandline_lock);
+ wcstring_list_t *stack = get_transient_stack();
+ assert(this->token == stack->size());
+ stack->pop_back();
+}
/**
Replace/append/insert the selection with/at/after the specified string.
@@ -216,11 +261,15 @@ static int builtin_commandline(parser_t &parser, wchar_t **argv)
int search_mode = 0;
int paging_mode = 0;
const wchar_t *begin = NULL, *end = NULL;
-
- current_buffer = (wchar_t *)builtin_complete_get_temporary_buffer();
- if (current_buffer)
+
+ scoped_push<const wchar_t *> saved_current_buffer(&current_buffer);
+ scoped_push<size_t> saved_current_cursor_pos(&current_cursor_pos);
+
+ wcstring transient_commandline;
+ if (get_top_transient(&transient_commandline))
{
- current_cursor_pos = wcslen(current_buffer);
+ current_buffer = transient_commandline.c_str();
+ current_cursor_pos = transient_commandline.size();
}
else
{