File indexing completed on 2023-05-30 09:03:12

0001 /*
0002     SPDX-License-Identifier: GPL-2.0-or-later
0003     SPDX-FileCopyrightText: 2013 Filipe Saraiva <filipe@kde.org>
0004 */
0005 
0006 #include "pythoncompletionobject.h"
0007 
0008 #include <QDebug>
0009 
0010 #include "result.h"
0011 
0012 #include "pythonsession.h"
0013 #include "pythonkeywords.h"
0014 
0015 using namespace Cantor;
0016 
0017 PythonCompletionObject::PythonCompletionObject(const QString& command, int index, PythonSession* session) : Cantor::CompletionObject(session),
0018 m_expression(nullptr)
0019 {
0020     setLine(command, index);
0021 }
0022 
0023 PythonCompletionObject::~PythonCompletionObject()
0024 {
0025     if (m_expression)
0026         m_expression->setFinishingBehavior(Expression::DeleteOnFinish);
0027 }
0028 
0029 void PythonCompletionObject::fetchCompletions()
0030 {
0031     if (session()->status() != Session::Done)
0032     {
0033         QStringList allCompletions;
0034 
0035         allCompletions << PythonKeywords::instance()->variables();
0036         allCompletions << PythonKeywords::instance()->functions();
0037         allCompletions << PythonKeywords::instance()->keywords();
0038 
0039         setCompletions(allCompletions);
0040 
0041         emit fetchingDone();
0042     }
0043     else
0044     {
0045         if (m_expression)
0046             return;
0047 
0048         qDebug() << "run fetchCompletions";
0049         const QString& expr = QString::fromLatin1(
0050             "from __main__ import __dict__;"
0051             "import rlcompleter;"
0052             "print('|'.join(rlcompleter.Completer(__dict__).global_matches('%1')+rlcompleter.Completer(__dict__).attr_matches('%1')))"
0053         ).arg(command());
0054         m_expression = session()->evaluateExpression(expr, Cantor::Expression::FinishingBehavior::DoNotDelete, true);
0055         connect(m_expression, &Cantor::Expression::statusChanged, this, &PythonCompletionObject::extractCompletions);
0056     }
0057 }
0058 
0059 
0060 
0061 void PythonCompletionObject::fetchIdentifierType()
0062 {
0063     if (session()->status() != Cantor::Session::Done)
0064     {
0065         if (std::binary_search(PythonKeywords::instance()->functions().begin(),
0066                 PythonKeywords::instance()->functions().end(), identifier()))
0067         emit fetchingTypeDone(FunctionType);
0068         else if (std::binary_search(PythonKeywords::instance()->keywords().begin(),
0069                 PythonKeywords::instance()->keywords().end(), identifier()))
0070         emit fetchingTypeDone(KeywordType);
0071         else
0072         emit fetchingTypeDone(VariableType);
0073     }
0074     else
0075     {
0076         if (m_expression)
0077             return;
0078 
0079         const QString& expr = QString::fromLatin1("callable(%1)").arg(identifier());
0080         m_expression = session()->evaluateExpression(expr, Cantor::Expression::FinishingBehavior::DoNotDelete, true);
0081         connect(m_expression, &Cantor::Expression::statusChanged, this, &PythonCompletionObject::extractIdentifierType);
0082     }
0083 }
0084 
0085 void PythonCompletionObject::extractCompletions(Cantor::Expression::Status status)
0086 {
0087     switch(status)
0088     {
0089         case Cantor::Expression::Error:
0090             qDebug() << "Error with PythonCompletionObject" << (m_expression->result() ? m_expression->result()->toHtml() : QLatin1String("extractCompletions"));
0091             break;
0092 
0093         case Cantor::Expression::Interrupted:
0094             qDebug() << "PythonCompletionObject was interrupted";
0095             break;
0096 
0097         case Cantor::Expression::Done:
0098             if (m_expression->result())
0099                 setCompletions(m_expression->result()->data().toString().remove(QLatin1Char('(')).split(QLatin1Char('|')));
0100             break;
0101         default:
0102             return;
0103     }
0104     m_expression->deleteLater();
0105     m_expression = nullptr;
0106     emit fetchingDone();
0107 }
0108 
0109 void PythonCompletionObject::extractIdentifierType(Cantor::Expression::Status status)
0110 {
0111     switch(status)
0112     {
0113         case Cantor::Expression::Error:
0114 
0115             if (m_expression->errorMessage().contains(QLatin1String("SyntaxError: invalid syntax")))
0116                 emit fetchingTypeDone(KeywordType);
0117             else
0118             {
0119                 qDebug() << "Error with PythonCompletionObject" << (m_expression->result() ? m_expression->result()->toHtml() : QLatin1String("extractIdentifierType"));
0120                 emit fetchingTypeDone(UnknownType);
0121             }
0122             break;
0123 
0124         case Cantor::Expression::Interrupted:
0125             qDebug() << "PythonCompletionObject was interrupted";
0126             emit fetchingTypeDone(UnknownType);
0127             break;
0128 
0129         case Cantor::Expression::Done:
0130             if (m_expression->result())
0131             {
0132                 if (m_expression->result()->data().toString() == QLatin1String("True"))
0133                     emit fetchingTypeDone(FunctionType);
0134                 else
0135                     emit fetchingTypeDone(VariableType);
0136             }
0137             else
0138                 emit fetchingTypeDone(UnknownType);
0139             break;
0140         default:
0141             return;
0142     }
0143     m_expression->deleteLater();
0144     m_expression = nullptr;
0145 }
0146 
0147 bool PythonCompletionObject::mayIdentifierContain(QChar c) const
0148 {
0149     return c.isLetter() || c.isDigit() || c == QLatin1Char('_') || c == QLatin1Char('%') || c == QLatin1Char('$') || c == QLatin1Char('.');
0150 }
0151 
0152 bool PythonCompletionObject::mayIdentifierBeginWith(QChar c) const
0153 {
0154     return c.isLetter() || c == QLatin1Char('_') || c == QLatin1Char('%') || c == QLatin1Char('$');
0155 }