Salome HOME
According to cotech80 PyConsoleBase->PyConsole and PyConsole->SalomePyConsole
[modules/gui.git] / src / PyConsole / PyConsole_EnhInterp.cxx
1 // Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Adrien Bruneton (CEA/DEN)
20 // Created on: 4 avr. 2013
21
22
23 #include "PyConsole.h"
24
25 #include "PyConsole_EnhInterp.h"
26
27 #include <pythonrun.h>
28 #include <string>
29 #include <QRegExp>
30
31 static const char * tmp_k[] = {"and",  "as", "assert", "break",  "class",
32     "continue", "def",  "del",
33     "elif", "else", "except", "exec", "finally",  "for",  "from", "global", "if",
34     "import", "in", "is", "lambda", "not",  "or", "pass", "print",  "raise",
35     "return", "try",  "while",  "with", "yield"};
36
37 const std::vector<QString> PyConsole_EnhInterp::PYTHON_KEYWORDS = \
38       std::vector<QString>(tmp_k, tmp_k+sizeof(tmp_k)/sizeof(tmp_k[0]));
39
40 /*!
41   \brief Constructor
42 */
43 PyConsole_EnhInterp::PyConsole_EnhInterp()
44   : PyConsole_Interp()
45 {
46 }
47
48 /*!
49   \brief Destructor
50 */
51 PyConsole_EnhInterp::~PyConsole_EnhInterp()
52 {
53 }
54
55 QStringList PyConsole_EnhInterp::getLastMatches() const
56 {
57   return _last_matches;
58 }
59
60 QString PyConsole_EnhInterp::getDocStr() const
61 {
62   return _doc_str;
63 }
64
65 /*!
66   \brief Run Python dir() command and saves the result internally in _lastPy
67   \param dirArgument Python expression to pass to the dir command. The parsing of what the
68   user actually started typing is dedicated to the caller
69   \param startMatch string representing the begining of the patter to be completed. For example when
70   the user types "a_string_variable.rsp <TAB>", this is "rsp".
71   \return command exit status - 0 = success
72 */
73 int PyConsole_EnhInterp::runDirCommand(const QString& dirArgument, const QString& startMatch)
74 {
75   int ret;
76   std::vector<QString> v;
77
78   clearCompletion();
79   if ( (ret = runDirAndExtract(dirArgument, startMatch, _last_matches)) )
80       return ret;
81
82   // If dirArgument is empty, we append the __builtins__
83   if (dirArgument.isEmpty())
84     {
85       if ( (ret = runDirAndExtract(QString("__builtins__"), startMatch, _last_matches, false)) )
86             return ret;
87
88       // ... and we match on Python's keywords as well:
89       for (std::vector<QString>::const_iterator it = PYTHON_KEYWORDS.begin(); it != PYTHON_KEYWORDS.end(); it++)
90           if ((*it).startsWith(startMatch))
91             _last_matches.push_back(*it);
92     }
93
94   // Try to get doc string of the first match
95   if (_last_matches.size() > 0)
96     {
97       QString cmd("");
98       if (dirArgument.trimmed() != "")
99         cmd = dirArgument + ".";
100       cmd += _last_matches[0] + ".__doc__";
101       PyObject * str = PyRun_String(cmd.toStdString().c_str(), Py_eval_input, _global_context, _local_context);
102       if (!str || str == Py_None || !PyString_Check(str))
103         {
104           if (!str)
105             PyErr_Clear();
106           _doc_str = "";
107         }
108       else
109         _doc_str = QString(PyString_AsString(str));
110       Py_XDECREF(str);
111     }
112
113   // The command has been successfully executed
114   return 0;
115 }
116
117 /**
118  * See runDirCommand().
119  * @param dirArgument see runDirCommand()
120  * @param startMatch  see runDirCommand()
121  * @param[out] result the list of matches
122  * @param discardSwig if true a regular expression is used to discard all static method generated
123  * by SWIG. typically: MEDCouplingUMesh_Blabla
124  * @return -1 if the call to dir() or the parsing of the result failed, 0 otherwise.
125  */
126 int PyConsole_EnhInterp::runDirAndExtract(const QString& dirArgument,
127                                           const QString& startMatch,
128                                           QStringList& result,
129                                           bool discardSwig) const
130 {
131   QRegExp re("^[A-Z].+_[A-Z]+[a-z]+.+$");  // discard SWIG static method, e.g. MEDCouplingUMesh_Blabla
132   QString command("dir(" + dirArgument + ")");
133   PyObject * plst = PyRun_String(command.toStdString().c_str(), Py_eval_input, _global_context, _local_context);
134   if(!plst || plst == Py_None) {
135     if(!plst)
136       PyErr_Clear();
137
138     Py_XDECREF(plst);
139     return -1;
140   }
141
142   // Extract the returned list and convert it to a vector<>
143   if (!PySequence_Check(plst))
144     {
145       // Should never happen ...
146       //std::cerr << "not a list!" << std::endl;
147       Py_XDECREF(plst);
148       return -1;
149     }
150
151   // Convert plst to a vector of QString
152   int n = PySequence_Length(plst);
153   for (int i = 0; i < n; i++)
154     {
155       PyObject * it;
156       it = PySequence_GetItem(plst, i);
157       QString s(PyString_AsString(it));
158       // if the method is not from swig, not static (guessed from the reg exp) and matches
159       // what is already there
160       if (s.startsWith(startMatch))
161         if(!discardSwig || (!re.exactMatch(s) && !s.contains("swig")))
162           result.push_back(s);
163       Py_DECREF(it);
164     }
165   Py_DECREF(plst);
166
167   return 0;
168 }
169
170 /**
171  * Clear internal members containing the last completion results.
172  */
173 void PyConsole_EnhInterp::clearCompletion()
174 {
175   _last_matches.clear();
176   _doc_str = "";
177 }