From 37e5069b58a332a4c2e360aa1324bc436abcf269 Mon Sep 17 00:00:00 2001
From: Giovanni Bussi <giovanni.bussi@gmail.com>
Date: Fri, 16 Mar 2018 20:11:37 +0100
Subject: [PATCH] Implemented completion of options

---
 src/cltools/Completion.cpp  | 37 ++++++++++++++++++++++++++++++-------
 src/cltools/completion.sh   |  6 +++++-
 src/core/CLToolRegister.cpp | 12 +++++++++++-
 src/core/CLToolRegister.h   |  4 +++-
 src/tools/Keywords.h        |  2 ++
 5 files changed, 51 insertions(+), 10 deletions(-)

diff --git a/src/cltools/Completion.cpp b/src/cltools/Completion.cpp
index 6b05fe82c..997f62d66 100644
--- a/src/cltools/Completion.cpp
+++ b/src/cltools/Completion.cpp
@@ -94,17 +94,40 @@ int Completion::main(FILE* in, FILE*out,Communicator& pc) {
   for(unsigned j=0; j<tmp.size(); ++j) if(tmp[j].length()>0) fprintf(out," %s",tmp[j].c_str());
   fprintf(out,"\"\n");
 
+  for(unsigned j=0; j<availableCxx.size(); j++) {
+    std::string s=availableCxx[j];
+// handle - sign (convert to underscore)
+    for(;;) {
+      size_t n=s.find("-");
+      if(n==std::string::npos) break;
+      s[n]='_';
+    }
+    fprintf(out,"local cmd_keys_%s=\"",s.c_str());
+    std::vector<std::string> keys=cltoolRegister().getKeys(availableCxx[j]);
+    for(unsigned k=0; k<keys.size(); k++) {
+// handle --help/-h
+      std::string s=keys[k];
+      for(;;) {
+        size_t n=s.find("/");
+        if(n==std::string::npos) break;
+        s[n]=' ';
+      }
+      fprintf(out," %s",s.c_str());
+    }
+    fprintf(out,"\"\n");
+  }
+
   fprintf(out,"%s\n",completion);
   std::string name=config::getPlumedProgramName();
 
   fprintf(out,
-"############################################\n"
-"## ADD THESE COMMANDS TO YOUR .bashrc FILE:\n"
-"############################################\n"
-"# _%s() { eval \"$(%s --no-mpi completion 2>/dev/null)\";}\n"
-"# complete -F _%s -o default %s\n"
-"############################################\n",
-name.c_str(),name.c_str(),name.c_str(),name.c_str());
+          "############################################\n"
+          "## ADD THESE COMMANDS TO YOUR .bashrc FILE:\n"
+          "############################################\n"
+          "# _%s() { eval \"$(%s --no-mpi completion 2>/dev/null)\";}\n"
+          "# complete -F _%s -o default %s\n"
+          "############################################\n",
+          name.c_str(),name.c_str(),name.c_str(),name.c_str());
 
   return 0;
 }
diff --git a/src/cltools/completion.sh b/src/cltools/completion.sh
index 5cc7cb295..2169f30b5 100644
--- a/src/cltools/completion.sh
+++ b/src/cltools/completion.sh
@@ -18,7 +18,11 @@
       cmd_found=""
       for cmd_test in $cmds ; do
         if [[ "$cmd_test" == "${COMP_WORDS[i]}" ]] ; then
-          COMPREPLY=( $(compgen -o bashdefault -- $cur ) )
+          eval "local comp=\"\$cmd_keys_${cmd_test//-/_}\""
+          case "$cur" in 
+            (-*) COMPREPLY=( $(compgen -W "$comp" -- $cur ) ) ;;
+            (*)  COMPREPLY=( $(compgen -o bashdefault -- ${cur}) ) ;;
+          esac
           return 0
         fi
       done
diff --git a/src/core/CLToolRegister.cpp b/src/core/CLToolRegister.cpp
index fc82332df..5a9cae99e 100644
--- a/src/core/CLToolRegister.cpp
+++ b/src/core/CLToolRegister.cpp
@@ -61,7 +61,7 @@ void CLToolRegister::add(string key,creator_pointer f,keywords_pointer kf) {
   };
 }
 
-bool CLToolRegister::check(string key) {
+bool CLToolRegister::check(string key)const {
   if(m.count(key)>0) return true;
   return false;
 }
@@ -101,6 +101,16 @@ bool CLToolRegister::printManual( const std::string& cltool ) {
   }
 }
 
+std::vector<std::string> CLToolRegister::getKeys(const std::string& cltool)const {
+  if ( check(cltool) ) {
+    return mk.find(cltool)->second.getKeys();
+  } else {
+    std::vector<std::string> empty;
+    return empty;
+  }
+}
+
+
 vector<string> CLToolRegister::list()const {
   vector<string> s;
   for(const_mIterator it=m.begin(); it!=m.end(); ++it)
diff --git a/src/core/CLToolRegister.h b/src/core/CLToolRegister.h
index 3ff40964d..6dc789c03 100644
--- a/src/core/CLToolRegister.h
+++ b/src/core/CLToolRegister.h
@@ -59,7 +59,7 @@ public:
 /// \param kp  A pointer to a function which returns the allowed keywords
   void add(std::string key,creator_pointer cp,keywords_pointer kp);
 /// Verify if a directive is present in the register
-  bool check(std::string cltool);
+  bool check(std::string cltool)const;
 /// Create an CLTool of the type indicated in the options
 /// \param ao object containing information for initialization, such as the full input line, a pointer to PlumedMain, etc
   CLTool* create(const CLToolOptions&ao);
@@ -69,6 +69,8 @@ public:
   std::vector<std::string> list()const;
 /// Print out the instructions for using the tool in html ready for input into the manual
   bool printManual(const std::string& cltool);
+/// Return all the keys of this cltool
+  std::vector<std::string> getKeys(const std::string& cltool)const;
 };
 
 /// Function returning a reference to the CLToolRegister.
diff --git a/src/tools/Keywords.h b/src/tools/Keywords.h
index a8e69121d..059c93630 100644
--- a/src/tools/Keywords.h
+++ b/src/tools/Keywords.h
@@ -154,6 +154,8 @@ public:
   void addOutputComponent( const std::string& name, const std::string& key, const std::string& descr );
 /// Has a component with this name been added?
   bool outputComponentExists( const std::string& name, const bool& custom ) const ;
+/// Reference to keys
+  std::vector<std::string> getKeys() const { return keys; }
 };
 
 }
-- 
GitLab