diff --git a/aql2/src/prompt/Prompt.cpp b/aql2/src/prompt/Prompt.cpp index 1ced201fe28acdcf53a8da745957ce1d53d8d2c7..02cc99bedc024b64607482a74e4a9e9a1b97a7d4 100644 --- a/aql2/src/prompt/Prompt.cpp +++ b/aql2/src/prompt/Prompt.cpp @@ -68,7 +68,7 @@ Prompt::Prompt ( cli::Environment environment ) : m_history_file ( std::string ( } // register readline completion function, pass environment - rl_attempted_completion_function = readline_completion; + rl_attempted_completion_function = ReadlinePromptCompletion::readline_completion; } Prompt::~Prompt ( ) { diff --git a/aql2/src/prompt/ReadlinePromptCompletion.cpp b/aql2/src/prompt/ReadlinePromptCompletion.cpp index 6155a7f98ebd90780fbb079cb5fd76687e80b38b..615116ed06165df4b9dddfe863f0185b0e7fae7f 100644 --- a/aql2/src/prompt/ReadlinePromptCompletion.cpp +++ b/aql2/src/prompt/ReadlinePromptCompletion.cpp @@ -5,18 +5,11 @@ * Author: Tomas Pecka */ -#include <alib/set> -#include <alib/vector> -#include <alib/string> -#include <readline/readline.h> -#include <registry/Registry.h> - #include "ReadlinePromptCompletion.h" -#include "Prompt.h" /* ========================================================================= */ -std::set < std::string > addPrefix ( const std::set < std::string > & collection, const std::string & prefix ) { +std::set < std::string > ReadlinePromptCompletion::addPrefix ( const std::set < std::string > & collection, const std::string & prefix ) { std::set < std::string > res; for ( const std::string & s : collection ) res.insert ( prefix + s ); @@ -24,14 +17,14 @@ std::set < std::string > addPrefix ( const std::set < std::string > & collection return res; } -bool startswith ( const std::string & subject, const std::string & prefix ) { +bool ReadlinePromptCompletion::startswith ( const std::string & subject, const std::string & prefix ) { if ( prefix.size ( ) > subject.size ( ) ) return false; return subject.substr ( 0, prefix.size ( ) ) == prefix; } -std::set < std::string > filter_completions ( const std::set < std::string > & choices, const char *text ) { +std::set < std::string > ReadlinePromptCompletion::filter_completions ( const std::set < std::string > & choices, const char *text ) { std::pair < std::set < std::string > :: const_iterator, std::set < std::string > :: const_iterator > range; const std::string prefix = text; @@ -43,124 +36,7 @@ std::set < std::string > filter_completions ( const std::set < std::string > & c /* ========================================================================= */ -std::set < std::string > fetchAlgorithms ( const char *text ) { - std::set < std::string > res; - const ext::set < ext::pair < std::string, ext::vector < std::string > > >& algos = abstraction::Registry::listAlgorithms ( ); - - for ( const std::pair < std::string, std::vector < std::string > > & algo : algos ) { - res.insert ( algo.first ); - } - - return filter_completions ( res, text ); -} - -std::set < std::string > fetchCommands ( const char *text ) { - return filter_completions ( { "execute", "introspect", "quit", "help" }, text ); -} - -std::set < std::string > fetchCommandsIntrospect ( const char *text ) { - return filter_completions ( { "algorithms", "overloads", "casts", "datatypes" }, text ); -} - -std::set < std::string > fetchBindings ( const char *text ) { - return filter_completions ( addPrefix ( Prompt::getPrompt ( ).getEnvironment ( ).getBindingNames ( ), "#" ), text ); -} - -std::set < std::string > fetchVariables ( const char *text ) { - return filter_completions ( addPrefix ( Prompt::getPrompt ( ).getEnvironment ( ).getVariableNames ( ), "$" ), text ); -} - -std::set < std::string > fetchFilepath ( const char *text ) { - std::set < std::string > res; - char *str; - int state = 0; - - while ( ( str = rl_filename_completion_function ( text, state++ ) ) != nullptr ) { - res.insert ( str ); - } - - return res; -} - -/* ========================================================================= */ - -/** - * @param text Prefix - * @param state Invocation number of this completion - * @param generator Function that generates the completion-strings - */ -template < typename... CompletionGeneratorFunc > -char * completion_generator ( const char *text, int state, const CompletionGeneratorFunc & ... generators ) { - static std::string prefix; - static std::set < std::string > choices; - static std::set < std::string > :: const_iterator iter; - - /* on first call initialize choices */ - if ( state == 0 ) { - prefix = text; - - choices = std::set < std::string > ( ); - - /* merge choices from all generators */ - const std::vector < std::function < std::set < std::string > ( const char* ) > > gens = { generators... }; - for ( const auto & gen : gens ) { - std::set < std::string > tmpres, tmpg = gen ( text ); - - std::set_union ( std::begin ( choices ), std::end ( choices ), - std::begin ( tmpg ), std::end ( tmpg ), - std::inserter ( tmpres, std::begin ( tmpres ) ) ); - choices = tmpres; - } - - iter = choices.begin ( ); - } - - /* iterate through choices */ - while ( iter != choices.end ( ) ) { - return strdup ( iter ++ -> c_str ( ) ); - } - - return nullptr; -} - -/* ========================================================================= */ - -/** - * http://www.delorie.com/gnu/docs/readline/rlman_45.html - * @param state Function invocation number - * @return malloc-allocated string or NULL if no more strings can be generated. - * */ -char * complete_algorithm ( const char *text, int state ) { - return completion_generator ( text, state, fetchAlgorithms ); -} - -char * complete_command ( const char *text, int state ) { - return completion_generator ( text, state, fetchCommands ); -} - -char * complete_command_introspect ( const char *text, int state ) { - return completion_generator ( text, state, fetchCommandsIntrospect ); -} - -char * complete_variable ( const char *text, int state ) { - return completion_generator ( text, state, fetchVariables ); -} - -char * complete_binding ( const char *text, int state ) { - return completion_generator ( text, state, fetchBindings ); -} - -char * complete_filepath ( const char *text, int state ) { - return completion_generator ( text, state, fetchFilepath ); -} - -char * complete_filepath_or_variable ( const char *text, int state ) { - return completion_generator ( text, state, fetchFilepath, fetchVariables ); -} - -/* ========================================================================= */ - -CompletionContext context ( const char *text, const int start, const int end ) { +ReadlinePromptCompletion::CompletionContext ReadlinePromptCompletion::context ( const char *text, const int start, const int end ) { std::string line ( rl_line_buffer ); if ( start == 0 ) @@ -198,7 +74,7 @@ CompletionContext context ( const char *text, const int start, const int end ) { /* ========================================================================= */ -char ** readline_completion ( const char *text, int start, int end ) { +char ** ReadlinePromptCompletion::readline_completion ( const char *text, int start, int end ) { // for variables and bindings rl_special_prefixes = "$#@"; rl_attempted_completion_over = 1; diff --git a/aql2/src/prompt/ReadlinePromptCompletion.h b/aql2/src/prompt/ReadlinePromptCompletion.h index e2bf6f375867620d948154deef39d01e9503f88d..2034e5c7464a3f3c849a4e77790bcf8fd1964a66 100644 --- a/aql2/src/prompt/ReadlinePromptCompletion.h +++ b/aql2/src/prompt/ReadlinePromptCompletion.h @@ -8,26 +8,152 @@ #ifndef _READLINE_PROMPT_COMPLETION_H #define _READLINE_PROMPT_COMPLETION_H +#include <readline/readline.h> + #include <alib/vector> #include <alib/set> #include <alib/map> +#include <alib/string> + +#include <registry/Registry.h> -#include <readline/readline.h> #include <environment/Environment.h> +#include <prompt/Prompt.h> -enum class CompletionContext { - COMMAND, - COMMAND_INTROSPECT, +class ReadlinePromptCompletion { + static std::set < std::string > fetchAlgorithms ( const char *text ) { + std::set < std::string > res; + const ext::set < ext::pair < std::string, ext::vector < std::string > > >& algos = abstraction::Registry::listAlgorithms ( ); - ALGORITHM, + for ( const std::pair < std::string, std::vector < std::string > > & algo : algos ) { + res.insert ( algo.first ); + } - FILEPATH, - FILEPATH_OR_VARIABLE, + return filter_completions ( res, text ); + } - VARIABLE, - BINDING, -}; + static std::set < std::string > fetchCommands ( const char *text ) { + return filter_completions ( { "execute", "introspect", "quit", "help" }, text ); + } + + static std::set < std::string > fetchCommandsIntrospect ( const char *text ) { + return filter_completions ( { "algorithms", "overloads", "casts", "datatypes" }, text ); + } + + static std::set < std::string > fetchBindings ( const char *text ) { + return filter_completions ( addPrefix ( Prompt::getPrompt ( ).getEnvironment ( ).getBindingNames ( ), "#" ), text ); + } + + static std::set < std::string > fetchVariables ( const char *text ) { + return filter_completions ( addPrefix ( Prompt::getPrompt ( ).getEnvironment ( ).getVariableNames ( ), "$" ), text ); + } + + static std::set < std::string > fetchFilepath ( const char *text ) { + std::set < std::string > res; + char *str; + int state = 0; + + while ( ( str = rl_filename_completion_function ( text, state++ ) ) != nullptr ) { + res.insert ( str ); + } + + return res; + } + +public: + enum class CompletionContext { + COMMAND, + COMMAND_INTROSPECT, + + ALGORITHM, + + FILEPATH, + FILEPATH_OR_VARIABLE, + + VARIABLE, + BINDING, + }; + + static char** readline_completion ( const char *text, int start, int end ); + static CompletionContext context ( const char *text, const int start, const int end ); + +private: + static std::set < std::string > addPrefix ( const std::set < std::string > & collection, const std::string & prefix ); + static bool startswith ( const std::string & subject, const std::string & prefix ); + static std::set < std::string > filter_completions ( const std::set < std::string > & choices, const char *text ); -char** readline_completion ( const char *text, int start, int end ); + /** + * @param text Prefix + * @param state Invocation number of this completion + * @param generator Function that generates the completion-strings + */ + template < typename... CompletionGeneratorFunc > + static char * completion_generator ( const char *text, int state, const CompletionGeneratorFunc & ... generators ) { + static std::string prefix; + static std::set < std::string > choices; + static std::set < std::string > :: const_iterator iter; + + /* on first call initialize choices */ + if ( state == 0 ) { + prefix = text; + + choices = std::set < std::string > ( ); + + /* merge choices from all generators */ + const std::vector < std::function < std::set < std::string > ( const char* ) > > gens = { generators... }; + for ( const auto & gen : gens ) { + std::set < std::string > tmpres, tmpg = gen ( text ); + + std::set_union ( std::begin ( choices ), std::end ( choices ), + std::begin ( tmpg ), std::end ( tmpg ), + std::inserter ( tmpres, std::begin ( tmpres ) ) ); + choices = tmpres; + } + + iter = choices.begin ( ); + } + + /* iterate through choices */ + while ( iter != choices.end ( ) ) { + return strdup ( iter ++ -> c_str ( ) ); + } + + return nullptr; + } + + /** + * http://www.delorie.com/gnu/docs/readline/rlman_45.html + * @param state Function invocation number + * @return malloc-allocated string or NULL if no more strings can be generated. + */ + static char * complete_algorithm ( const char *text, int state ) { + return completion_generator ( text, state, fetchAlgorithms ); + } + + static char * complete_command ( const char *text, int state ) { + return completion_generator ( text, state, fetchCommands ); + } + + static char * complete_command_introspect ( const char *text, int state ) { + return completion_generator ( text, state, fetchCommandsIntrospect ); + } + + static char * complete_variable ( const char *text, int state ) { + return completion_generator ( text, state, fetchVariables ); + } + + static char * complete_binding ( const char *text, int state ) { + return completion_generator ( text, state, fetchBindings ); + } + + static char * complete_filepath ( const char *text, int state ) { + return completion_generator ( text, state, fetchFilepath ); + } + + static char * complete_filepath_or_variable ( const char *text, int state ) { + return completion_generator ( text, state, fetchFilepath, fetchVariables ); + } + +}; #endif /* _READLINE_PROMPT_COMPLETION_H */