Salome HOME
Merge branch 'master' of newgeom:newgeom
[modules/shaper.git] / src / PyConsole / PyConsole_EnhInterp.cpp
1
2
3
4 #include "PyConsole.h"
5
6 #include "PyConsole_EnhInterp.h"
7
8 #include <pythonrun.h>
9 #include <string>
10 #include <QRegExp>
11
12 static const char * tmp_k[] = {"and",  "as", "assert", "break",  "class",
13     "continue", "def",  "del",
14     "elif", "else", "except", "exec", "finally",  "for",  "from", "global", "if",
15     "import", "in", "is", "lambda", "not",  "or", "pass", "print",  "raise",
16     "return", "try",  "while",  "with", "yield"};
17
18 const std::vector<QString> PyConsole_EnhInterp::PYTHON_KEYWORDS = \
19       std::vector<QString>(tmp_k, tmp_k+sizeof(tmp_k)/sizeof(tmp_k[0]));
20
21 /*!
22   \brief Run Python dir() command and saves the result internally in _lastPy
23   \param dirArgument Python expression to pass to the dir command. The parsing of what the
24   user actually started typing is dedicated to the caller
25   \param startMatch string representing the begining of the patter to be completed. For example when
26   the user types "a_string_variable.rsp <TAB>", this is "rsp".
27   \return command exit status - 0 = success
28 */
29 int PyConsole_EnhInterp::runDirCommand(const QString & dirArgument, const QString & startMatch)
30 {
31   int ret;
32   std::vector<QString> v;
33
34   clearCompletion();
35   if ( (ret = runDirAndExtract(dirArgument, startMatch, _last_matches)) )
36       return ret;
37
38   // If dirArgument is empty, we append the __builtins__
39   if (dirArgument.isEmpty())
40     {
41       if ( (ret = runDirAndExtract(QString("__builtins__"), startMatch, _last_matches, false)) )
42             return ret;
43
44       // ... and we match on Python's keywords as well:
45       for (std::vector<QString>::const_iterator it = PYTHON_KEYWORDS.begin(); it != PYTHON_KEYWORDS.end(); it++)
46           if ((*it).startsWith(startMatch))
47             _last_matches.push_back(*it);
48     }
49
50   // Try to get doc string of the first match
51   if (_last_matches.size() > 0)
52     {
53       QString cmd("");
54       if (dirArgument.trimmed() != "")
55         cmd = dirArgument + ".";
56       cmd += _last_matches[0] + ".__doc__";
57       PyObject * str = PyRun_String(cmd.toStdString().c_str(), Py_eval_input, _g, _g);
58       if (!str || str == Py_None || !PyString_Check(str))
59         {
60           if (!str)
61             PyErr_Clear();
62           _doc_str = "";
63         }
64       else
65         _doc_str = QString(PyString_AsString(str));
66       Py_XDECREF(str);
67     }
68
69   // The command has been successfully executed
70   return 0;
71 }
72
73 /**
74  * See runDirCommand().
75  * @param dirArgument see runDirCommand()
76  * @param startMatch  see runDirCommand()
77  * @param[out] result the list of matches
78  * @param discardSwig if true a regular expression is used to discard all static method generated
79  * by SWIG. typically: MEDCouplingUMesh_Blabla
80  * @return -1 if the call to dir() or the parsing of the result failed, 0 otherwise.
81  */
82 int PyConsole_EnhInterp::runDirAndExtract(const QString& dirArgument,
83        const QString & startMatch, std::vector<QString> & result,
84        bool discardSwig) const
85 {
86   QRegExp re("^[A-Z].+_[A-Z]+[a-z]+.+$");  // discard SWIG static method, e.g. MEDCouplingUMesh_Blabla
87   QString command("dir(" + dirArgument + ")");
88   PyObject * plst = PyRun_String(command.toStdString().c_str(), Py_eval_input, _g, _g);
89   if(!plst || plst == Py_None) {
90     if(!plst)
91       PyErr_Clear();
92
93     Py_XDECREF(plst);
94     return -1;
95   }
96
97   // Extract the returned list and convert it to a vector<>
98   if (!PySequence_Check(plst))
99     {
100       // Should never happen ...
101       //std::cerr << "not a list!" << std::endl;
102       Py_XDECREF(plst);
103       return -1;
104     }
105
106   // Convert plst to a vector of QString
107   int n = PySequence_Length(plst);
108   for (int i = 0; i < n; i++)
109     {
110       PyObject * it;
111       it = PySequence_GetItem(plst, i);
112       QString s(PyString_AsString(it));
113       // if the method is not from swig, not static (guessed from the reg exp) and matches
114       // what is already there
115       if (s.startsWith(startMatch))
116         if(!discardSwig || (!re.exactMatch(s) && !s.contains("swig")))
117           result.push_back(s);
118       Py_DECREF(it);
119     }
120   Py_DECREF(plst);
121
122   return 0;
123 }
124
125 /**
126  * Clear internal members containing the last completion results.
127  */
128 void PyConsole_EnhInterp::clearCompletion()
129 {
130   _last_matches.resize(0);
131   _doc_str = QString("");
132 }
133
134
135