Salome HOME
8915f07656c90eef32e14f840f735a86a2d49e6c
[modules/gui.git] / src / PyConsole / PyConsole_EnhInterp.cxx
1 // Copyright (C) 2007-2014  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 Run Python dir() command and saves the result internally in _lastPy
42   \param dirArgument Python expression to pass to the dir command. The parsing of what the
43   user actually started typing is dedicated to the caller
44   \param startMatch string representing the begining of the patter to be completed. For example when
45   the user types "a_string_variable.rsp <TAB>", this is "rsp".
46   \return command exit status - 0 = success
47 */
48 int PyConsole_EnhInterp::runDirCommand(const QString & dirArgument, const QString & startMatch)
49 {
50   int ret;
51   std::vector<QString> v;
52
53   clearCompletion();
54   if ( (ret = runDirAndExtract(dirArgument, startMatch, _last_matches)) )
55       return ret;
56
57   // If dirArgument is empty, we append the __builtins__
58   if (dirArgument.isEmpty())
59     {
60       if ( (ret = runDirAndExtract(QString("__builtins__"), startMatch, _last_matches, false)) )
61             return ret;
62
63       // ... and we match on Python's keywords as well:
64       for (std::vector<QString>::const_iterator it = PYTHON_KEYWORDS.begin(); it != PYTHON_KEYWORDS.end(); it++)
65           if ((*it).startsWith(startMatch))
66             _last_matches.push_back(*it);
67     }
68
69   // Try to get doc string of the first match
70   if (_last_matches.size() > 0)
71     {
72       QString cmd("");
73       if (dirArgument.trimmed() != "")
74         cmd = dirArgument + ".";
75       cmd += _last_matches[0] + ".__doc__";
76       PyObject * str = PyRun_String(cmd.toStdString().c_str(), Py_eval_input, _context, _context);
77       if (!str || str == Py_None || !PyString_Check(str))
78         {
79           if (!str)
80             PyErr_Clear();
81           _doc_str = "";
82         }
83       else
84         _doc_str = QString(PyString_AsString(str));
85       Py_XDECREF(str);
86     }
87
88   // The command has been successfully executed
89   return 0;
90 }
91
92 /**
93  * See runDirCommand().
94  * @param dirArgument see runDirCommand()
95  * @param startMatch  see runDirCommand()
96  * @param[out] result the list of matches
97  * @param discardSwig if true a regular expression is used to discard all static method generated
98  * by SWIG. typically: MEDCouplingUMesh_Blabla
99  * @return -1 if the call to dir() or the parsing of the result failed, 0 otherwise.
100  */
101 int PyConsole_EnhInterp::runDirAndExtract(const QString& dirArgument,
102        const QString & startMatch, std::vector<QString> & result,
103        bool discardSwig) const
104 {
105   QRegExp re("^[A-Z].+_[A-Z]+[a-z]+.+$");  // discard SWIG static method, e.g. MEDCouplingUMesh_Blabla
106   QString command("dir(" + dirArgument + ")");
107   PyObject * plst = PyRun_String(command.toStdString().c_str(), Py_eval_input, _context, _context);
108   if(!plst || plst == Py_None) {
109     if(!plst)
110       PyErr_Clear();
111
112     Py_XDECREF(plst);
113     return -1;
114   }
115
116   // Extract the returned list and convert it to a vector<>
117   if (!PySequence_Check(plst))
118     {
119       // Should never happen ...
120       //std::cerr << "not a list!" << std::endl;
121       Py_XDECREF(plst);
122       return -1;
123     }
124
125   // Convert plst to a vector of QString
126   int n = PySequence_Length(plst);
127   for (int i = 0; i < n; i++)
128     {
129       PyObject * it;
130       it = PySequence_GetItem(plst, i);
131       QString s(PyString_AsString(it));
132       // if the method is not from swig, not static (guessed from the reg exp) and matches
133       // what is already there
134       if (s.startsWith(startMatch))
135         if(!discardSwig || (!re.exactMatch(s) && !s.contains("swig")))
136           result.push_back(s);
137       Py_DECREF(it);
138     }
139   Py_DECREF(plst);
140
141   return 0;
142 }
143
144 /**
145  * Clear internal members containing the last completion results.
146  */
147 void PyConsole_EnhInterp::clearCompletion()
148 {
149   _last_matches.resize(0);
150   _doc_str = QString("");
151 }
152
153
154