From 5f79e3c38ffe1657e35b384a6c3924328addac06 Mon Sep 17 00:00:00 2001
From: Tomas Pecka <peckato1@fit.cvut.cz>
Date: Sat, 20 Apr 2019 16:32:02 +0200
Subject: [PATCH] aql: ReadlineCompletion: Add introspect algorithms/datatypes
 and SET completion.

---
 aql2/src/prompt/ReadlinePromptCompletion.cpp | 38 ++++++++--
 aql2/src/prompt/ReadlinePromptCompletion.h   | 73 ++++++++++++++++++--
 2 files changed, 101 insertions(+), 10 deletions(-)

diff --git a/aql2/src/prompt/ReadlinePromptCompletion.cpp b/aql2/src/prompt/ReadlinePromptCompletion.cpp
index 40d88fc1a6..fea1012721 100644
--- a/aql2/src/prompt/ReadlinePromptCompletion.cpp
+++ b/aql2/src/prompt/ReadlinePromptCompletion.cpp
@@ -31,6 +31,23 @@ bool ReadlinePromptCompletion::startswith ( const std::string & subject, const s
 	return subject.substr ( 0, prefix.size ( ) ) == prefix;
 }
 
+std::set < std::string > ReadlinePromptCompletion::getGroups ( const std::string & qualified_name ) {
+	std::set < std::string > res;
+
+	unsigned template_level = 0;
+	for ( size_t i = 0; i < qualified_name.size ( ); i++ ) {
+		if ( qualified_name [ i ] == '<' )
+			template_level ++;
+		else if ( qualified_name [ i ] == '>' )
+			template_level --;
+
+		else if ( template_level == 0 && i > 0 && qualified_name [ i - 1 ] == ':' && qualified_name [ i ] == ':' )
+			res.insert ( qualified_name.substr ( 0, i + 1 ) );
+	}
+
+	return res;
+}
+
 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;
@@ -49,9 +66,12 @@ ReadlinePromptCompletion::CompletionContext ReadlinePromptCompletion::context (
 	if ( start == 0 )
 		return CompletionContext::COMMAND;
 
-	if ( startswith ( line, "introspect" ) && start == 11 ) {
+	if ( startswith ( line, "introspect" ) && start == 11 )
 		return CompletionContext::COMMAND_INTROSPECT;
-	}
+
+	else if ( startswith ( line, "set" ) && start == 4 )
+		return CompletionContext::SET;
+
 	else if ( startswith ( line, "introspect overloads" ) && start == 21 )
 		return CompletionContext::ALGORITHM;
 
@@ -61,10 +81,14 @@ ReadlinePromptCompletion::CompletionContext ReadlinePromptCompletion::context (
 	else if ( startswith ( line, "introspect bindings" ) && start == 20 )
 		return CompletionContext::BINDING;
 
+	else if ( startswith ( line, "introspect algorithms" ) && start == 22 )
+		return CompletionContext::ALGORITHM_GROUP;
+
+	else if ( startswith ( line, "introspect datatypes" ) && start == 21 )
+		return CompletionContext::DATATYPE_GROUP;
+
 	/* TODO
-	else if ( startswith ( line, "introspect algorithms" ) && start == 21 )
 	else if ( startswith ( line, "introspect casts" ) && start == 17 )
-	else if ( startswith ( line, "introspect datatypes" ) && start == 20 )
 	*/
 
 	if ( end - start > 0 && text [ 0 ] == '$' )
@@ -100,6 +124,10 @@ char ** ReadlinePromptCompletion::readline_completion ( const char *text, int st
 	switch ( context ( text, start, end ) ) {
 		case CompletionContext::ALGORITHM:
 			return rl_completion_matches ( text, complete_algorithm );
+		case CompletionContext::ALGORITHM_GROUP:
+			return rl_completion_matches ( text, complete_algorithm_group );
+		case CompletionContext::DATATYPE_GROUP:
+			return rl_completion_matches ( text, complete_datatype_group );
 		case CompletionContext::COMMAND:
 			return rl_completion_matches ( text, complete_command );
 		case CompletionContext::COMMAND_INTROSPECT:
@@ -112,6 +140,8 @@ char ** ReadlinePromptCompletion::readline_completion ( const char *text, int st
 			return rl_completion_matches ( text, complete_filepath );
 		case CompletionContext::FILEPATH_OR_VARIABLE:
 			return rl_completion_matches ( text, complete_filepath_or_variable );
+		case CompletionContext::SET:
+			return rl_completion_matches ( text, complete_set );
 		default:
 			return nullptr;
 	}
diff --git a/aql2/src/prompt/ReadlinePromptCompletion.h b/aql2/src/prompt/ReadlinePromptCompletion.h
index b325f5c9bc..31e92768f2 100644
--- a/aql2/src/prompt/ReadlinePromptCompletion.h
+++ b/aql2/src/prompt/ReadlinePromptCompletion.h
@@ -16,24 +16,63 @@
 #include <alib/string>
 
 #include <registry/Registry.h>
+#include <registry/XmlRegistry.h>
 
 #include <environment/Environment.h>
 #include <prompt/Prompt.h>
 
 class ReadlinePromptCompletion {
-	static std::set < std::string > fetchAlgorithms ( const char *text ) {
+	static std::set < std::string > fetchAlgorithmsFullyQualifiedName ( const char *text ) {
+		std::set < std::string > fullyQualifiedNames;
+
+		for ( const std::pair < std::string, std::vector < std::string > > & algo : abstraction::Registry::listAlgorithms ( ) ) {
+			fullyQualifiedNames.insert ( algo.first );
+		}
+
+		return filter_completions ( fullyQualifiedNames, text );
+	}
+
+	static std::set < std::string > fetchAlgorithmsLastSegmentName ( const char *text ) {
+		std::map < std::string, unsigned > collisions;
+
+		for ( const std::pair < std::string, std::vector < std::string > > & algo : abstraction::Registry::listAlgorithms ( ) ) {
+			size_t pos = algo.first.find_last_of ( ':' );
+			if ( pos != std::string::npos )
+				collisions [ algo.first.substr ( pos + 1 ) ] += 1;
+		}
+
+		std::set < std::string > res;
+		for ( const std::pair < const std::string, unsigned > & kv : collisions )
+			if ( kv.second == 1 )
+				res.insert ( kv.first );
+
+		return filter_completions ( res, text );
+	}
+
+	static std::set < std::string > fetchAlgorithmGroups ( const char *text ) {
+		std::set < std::string > res;
+
+		for ( const std::pair < std::string, std::vector < std::string > > & algo : abstraction::Registry::listAlgorithms ( ) ) {
+			std::set < std::string > groups = getGroups ( algo.first );
+			res.insert ( groups.begin ( ), groups.end ( ) );
+		}
+
+		return filter_completions ( res, text );
+	}
+
+	static std::set < std::string > fetchDatatypeGroups ( 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 );
+		for ( const std::string & dtt : abstraction::XmlRegistry::listDataTypes ( ) ) {
+			std::set < std::string > groups = getGroups ( dtt );
+			res.insert ( groups.begin ( ), groups.end ( ) );
 		}
 
 		return filter_completions ( res, text );
 	}
 
 	static std::set < std::string > fetchCommands ( const char *text ) {
-		return filter_completions ( { "execute", "introspect", "quit", "help" }, text );
+		return filter_completions ( { "execute", "introspect", "quit", "help", "set" }, text );
 	}
 
 	static std::set < std::string > fetchCommandsIntrospect ( const char *text ) {
@@ -48,6 +87,10 @@ class ReadlinePromptCompletion {
 		return filter_completions ( addPrefix ( Prompt::getPrompt ( ).getEnvironment ( ).getVariableNames ( ), "$" ), text );
 	}
 
+	static std::set < std::string > fetchSet ( const char *text ) {
+		return filter_completions ( { "verbose", "measure", "optimizeXml", "seed" }, text );
+	}
+
 	static std::set < std::string > fetchFilepath ( const char *text ) {
 		std::set < std::string > res;
 		char *str;
@@ -66,12 +109,17 @@ public:
 		COMMAND_INTROSPECT,
 
 		ALGORITHM,
+		ALGORITHM_GROUP,
+
+		DATATYPE_GROUP,
 
 		FILEPATH,
 		FILEPATH_OR_VARIABLE,
 
 		VARIABLE,
 		BINDING,
+
+		SET,
 	};
 
 	static char** readline_completion ( const char *text, int start, int end );
@@ -80,6 +128,7 @@ public:
 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 > getGroups ( const std::string & qualified_name );
 	static std::set < std::string > filter_completions ( const std::set < std::string > & choices, const char *text );
 
 	/**
@@ -127,7 +176,15 @@ private:
 	 * @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 );
+		return completion_generator ( text, state, fetchAlgorithmsFullyQualifiedName, fetchAlgorithmsLastSegmentName );
+	}
+
+	static char * complete_algorithm_group ( const char *text, int state ) {
+		return completion_generator ( text, state, fetchAlgorithmGroups );
+	}
+
+	static char * complete_datatype_group ( const char *text, int state ) {
+		return completion_generator ( text, state, fetchDatatypeGroups );
 	}
 
 	static char * complete_command ( const char *text, int state ) {
@@ -154,6 +211,10 @@ private:
 		return completion_generator ( text, state, fetchFilepath, fetchVariables );
 	}
 
+	static char * complete_set ( const char *text, int state ) {
+		return completion_generator ( text, state, fetchSet );
+	}
+
 };
 
 #endif /* _READLINE_PROMPT_COMPLETION_H */
-- 
GitLab