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 }