File indexing completed on 2024-05-05 11:55:59

0001 /*
0002     SPDX-License-Identifier: GPL-2.0-or-later
0003     SPDX-FileCopyrightText: 2009 Alexander Rieder <alexanderrieder@gmail.com>
0004 */
0005 
0006 #include "sagecompletionobject.h"
0007 
0008 #include "sagesession.h"
0009 #include "sagekeywords.h"
0010 #include "textresult.h"
0011 
0012 #include <QDebug>
0013 #include <QStack>
0014 
0015 using namespace Cantor;
0016 
0017 SageCompletionObject::SageCompletionObject(const QString& command, int index, SageSession* session) : Cantor::CompletionObject(session)
0018 {
0019     setLine(command, index);
0020     m_expression=nullptr;
0021 }
0022 
0023 SageCompletionObject::~SageCompletionObject()
0024 {
0025     if(m_expression)
0026         m_expression->setFinishingBehavior(Expression::DeleteOnFinish);
0027 }
0028 
0029 void SageCompletionObject::fetchCompletions()
0030 {
0031     if (session()->status() != Cantor::Session::Done)
0032     {
0033         QStringList allCompletions;
0034 
0035         allCompletions << SageKeywords::instance()->keywords();
0036         allCompletions << SageKeywords::instance()->functions();
0037         allCompletions << SageKeywords::instance()->variables();
0038 
0039         setCompletions(allCompletions);
0040         emit fetchingDone();
0041     }
0042     else
0043     {
0044         if (m_expression)
0045             return;
0046 
0047         //cache the value of the "_" variable into __hist_tmp__, so we can restore the previous result
0048         //after complete() was evaluated
0049         const QString& cmd = QLatin1String("__hist_tmp__=_; sage.interfaces.tab_completion.completions(\"")+command()+QLatin1String("\",globals());_=__hist_tmp__");
0050         m_expression=session()->evaluateExpression(cmd, Cantor::Expression::FinishingBehavior::DoNotDelete, true);
0051         connect(m_expression, &Cantor::Expression::gotResult, this, &SageCompletionObject::extractCompletions);
0052     }
0053 }
0054 
0055 void SageCompletionObject::extractCompletions()
0056 {
0057   SageSession* s=qobject_cast<SageSession*>(session());
0058   if(s&&s->sageVersion()<SageSession::VersionInfo(5, 7))
0059     extractCompletionsLegacy();
0060   else
0061     extractCompletionsNew();
0062 }
0063 
0064 void SageCompletionObject::extractCompletionsNew()
0065 {
0066     Cantor::Result* res=m_expression->result();
0067     m_expression->deleteLater();
0068     m_expression=nullptr;
0069 
0070     if(!res || !(res->type()==Cantor::TextResult::Type))
0071     {
0072         qDebug()<<"something went wrong fetching tab completion";
0073         fetchingDone();
0074         return;
0075     }
0076 
0077     //the result looks like "['comp1', 'comp2']" parse it
0078 
0079     QString txt=res->data().toString().trimmed();
0080     txt=txt.mid(1); //remove [
0081     txt.chop(1); //remove ]
0082 
0083     qDebug()<<"completion string: "<<txt;
0084 
0085     QStringList tmp=txt.split(QLatin1Char(','));
0086     QStringList completions;
0087 
0088     foreach(QString c, tmp) // krazy:exclude=foreach
0089     {
0090         c=c.trimmed();
0091         c.chop(1);
0092         completions<<c.mid(1);
0093     }
0094 
0095     completions << SageKeywords::instance()->keywords();
0096     setCompletions(completions);
0097 
0098     emit fetchingDone();
0099 }
0100 
0101 void SageCompletionObject::extractCompletionsLegacy()
0102 {
0103     Cantor::Result* res=m_expression->result();
0104     m_expression->deleteLater();
0105     m_expression=nullptr;
0106 
0107     if(!res || !(res->type()==Cantor::TextResult::Type))
0108     {
0109         qDebug()<<"something went wrong fetching tab completion";
0110         fetchingDone();
0111         return;
0112     }
0113 
0114     //the result looks like "['comp1', 'comp2']" parse it
0115     QString txt=res->data().toString().trimmed();
0116     txt=txt.mid(1); //remove [
0117     txt.chop(1); //remove ]
0118 
0119     QStringList tmp=txt.split(QLatin1Char(','));
0120     QStringList completions;
0121 
0122     foreach(QString c, tmp) // krazy:exclude=foreach
0123     {
0124         c=c.trimmed();
0125         c.chop(1);
0126         completions<<c.mid(1);
0127     }
0128 
0129     completions << SageKeywords::instance()->keywords();
0130     setCompletions(completions);
0131 
0132     emit fetchingDone();
0133 }
0134 
0135 
0136 void SageCompletionObject::fetchIdentifierType()
0137 {
0138     if (SageKeywords::instance()->keywords().contains(identifier()))
0139     {
0140         emit fetchingTypeDone(KeywordType);
0141         return;
0142     }
0143 
0144     if (session()->status() != Cantor::Session::Done)
0145     {
0146         if (SageKeywords::instance()->functions().contains(identifier()))
0147             emit fetchingTypeDone(FunctionType);
0148         else if (SageKeywords::instance()->variables().contains(identifier()))
0149             emit fetchingTypeDone(VariableType);
0150         else
0151             emit fetchingTypeDone(UnknownType);
0152     }
0153     else
0154     {
0155         if (m_expression)
0156             return;
0157 
0158         QString expr = QString::fromLatin1("__cantor_internal__ = _; type(%1); _ = __cantor_internal__").arg(identifier());
0159         m_expression = session()->evaluateExpression(expr, Cantor::Expression::FinishingBehavior::DoNotDelete, true);
0160         connect(m_expression, &Cantor::Expression::statusChanged, this, &SageCompletionObject::extractIdentifierType);
0161     }
0162 }
0163 
0164 void SageCompletionObject::extractIdentifierType(Cantor::Expression::Status status)
0165 {
0166     switch(status)
0167     {
0168         case Cantor::Expression::Error:
0169             qDebug() << "Error with SageCompletionObject" << m_expression->errorMessage();
0170             emit fetchingTypeDone(UnknownType);
0171             break;
0172 
0173         case Cantor::Expression::Interrupted:
0174             qDebug() << "SageCompletionObject was interrupted";
0175             emit fetchingTypeDone(UnknownType);
0176             break;
0177 
0178         case Cantor::Expression::Done:
0179         {
0180             Cantor::Result* result = m_expression->result();
0181             if (result)
0182             {
0183                 QString res = result->data().toString();
0184                 if (res.contains(QLatin1String("function")) || res.contains(QLatin1String("method")))
0185                     emit fetchingTypeDone(FunctionType);
0186                 else
0187                     emit fetchingTypeDone(VariableType);
0188             }
0189             else
0190                 emit fetchingTypeDone(UnknownType);
0191             break;
0192         }
0193 
0194         default:
0195             return;
0196     }
0197 
0198     m_expression->deleteLater();
0199     m_expression = nullptr;
0200 }
0201 
0202 bool SageCompletionObject::mayIdentifierContain(QChar c) const
0203 {
0204     return c.isLetter() || c.isDigit() || c == QLatin1Char('_') || c == QLatin1Char('.');
0205 }
0206 
0207 bool SageCompletionObject::mayIdentifierBeginWith(QChar c) const
0208 {
0209     return c.isLetter() || c.isDigit() || c == QLatin1Char('_');
0210 }