Warning, file /education/cantor/src/lib/completionobject.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-License-Identifier: GPL-2.0-or-later 0003 SPDX-FileCopyrightText: 2009 Alexander Rieder <alexanderrieder@gmail.com> 0004 */ 0005 0006 #include "completionobject.h" 0007 using namespace Cantor; 0008 0009 #include <QStringList> 0010 #include <QTimer> 0011 #include <QDebug> 0012 0013 #include "session.h" 0014 0015 class Cantor::CompletionObjectPrivate 0016 { 0017 public: 0018 QStringList completions; 0019 QString line; 0020 QString command; 0021 QString identifier; 0022 QString completion; 0023 int position; 0024 Session* session; 0025 bool parenCompletion; 0026 }; 0027 0028 CompletionObject::CompletionObject(Session* session) : 0029 d(new CompletionObjectPrivate) 0030 { 0031 setParent(session); 0032 d->position = -1; 0033 d->session=session; 0034 0035 connect(this, &CompletionObject::fetchingDone, this, &CompletionObject::findCompletion); 0036 connect(this, &CompletionObject::fetchingTypeDone, this, &CompletionObject::completeLineWithType); 0037 0038 setCompletionMode(KCompletion::CompletionShell); 0039 } 0040 0041 CompletionObject::~CompletionObject() 0042 { 0043 delete d; 0044 } 0045 0046 QString CompletionObject::command() const 0047 { 0048 return d->command; 0049 } 0050 0051 Session* CompletionObject::session() const 0052 { 0053 return d->session; 0054 } 0055 0056 QStringList CompletionObject::completions() const 0057 { 0058 return d->completions; 0059 } 0060 0061 QString CompletionObject::identifier() const 0062 { 0063 return d->identifier; 0064 } 0065 0066 QString CompletionObject::completion() const 0067 { 0068 return d->completion; 0069 } 0070 0071 void CompletionObject::setLine(const QString& line, int index) 0072 { 0073 d->parenCompletion = false; 0074 d->line = line; 0075 if (index < 0) 0076 index = line.length(); 0077 if (index > 1 && line[index-1] == QLatin1Char('(')) { 0078 --index; // move before the parenthesis 0079 d->parenCompletion = true; // but remember it was there 0080 } 0081 int cmd_index = locateIdentifier(line, index-1); 0082 if (cmd_index < 0) 0083 cmd_index = index; 0084 d->position=cmd_index; 0085 d->command=line.mid(cmd_index, index-cmd_index); 0086 0087 //start a delayed fetch 0088 QTimer::singleShot(0, this, &CompletionObject::fetchCompletions); 0089 } 0090 0091 void CompletionObject::updateLine(const QString& line, int index) 0092 { 0093 d->line = line; 0094 if (index < 0) 0095 index = line.length(); 0096 int cmd_index = locateIdentifier(line, index-1); 0097 if (cmd_index < 0) 0098 cmd_index = index; 0099 d->command=line.mid(cmd_index, index-cmd_index); 0100 0101 // start a delayed fetch 0102 // For some backends this is a lot of unnecessary work... 0103 QTimer::singleShot(0, this, &CompletionObject::fetchCompletions); 0104 } 0105 0106 void CompletionObject::completeLine(const QString& comp, CompletionObject::LineCompletionMode mode) 0107 { 0108 d->identifier = comp; 0109 if (comp.isEmpty()) { 0110 int index = d->position + d->command.length(); 0111 emit lineDone(d->line, index); 0112 } else if (mode == PreliminaryCompletion) { 0113 completeUnknownLine(); 0114 } else /* mode == FinalCompletion */ { 0115 QTimer::singleShot(0, this, &CompletionObject::fetchIdentifierType); 0116 } 0117 } 0118 0119 void CompletionObject::fetchIdentifierType() 0120 { 0121 emit fetchingTypeDone(UnknownType); 0122 } 0123 0124 0125 void CompletionObject::setCompletions(const QStringList& completions) 0126 { 0127 d->completions=completions; 0128 this->setItems(completions); 0129 } 0130 0131 void CompletionObject::setCommand(const QString& cmd) 0132 { 0133 d->command=cmd; 0134 } 0135 0136 int CompletionObject::locateIdentifier(const QString& cmd, int index) const 0137 { 0138 if (index < 0) 0139 return -1; 0140 0141 int i; 0142 for (i=index; i>=0 && mayIdentifierContain(cmd[i]); --i) 0143 {} 0144 0145 if (i==index || !mayIdentifierBeginWith(cmd[i+1])) 0146 return -1; 0147 return i+1; 0148 } 0149 0150 bool CompletionObject::mayIdentifierContain(QChar c) const 0151 { 0152 return c.isLetter() || c.isDigit() || c == QLatin1Char('_'); 0153 } 0154 0155 bool CompletionObject::mayIdentifierBeginWith(QChar c) const 0156 { 0157 return c.isLetter() || c == QLatin1Char('_'); 0158 } 0159 0160 void CompletionObject::findCompletion() 0161 { 0162 if (d->parenCompletion) { 0163 disconnect(this, SIGNAL(fetchingTypeDone(IdentifierType)), nullptr, nullptr); 0164 connect(this, &CompletionObject::fetchingTypeDone, this, &CompletionObject::handleParenCompletionWithType); 0165 d->identifier = d->command; 0166 fetchIdentifierType(); 0167 return; 0168 } 0169 d->completion = makeCompletion(command()); 0170 emit done(); 0171 } 0172 0173 void CompletionObject::handleParenCompletionWithType(IdentifierType type) 0174 { 0175 disconnect(this, SIGNAL(fetchingTypeDone(IdentifierType)), nullptr, nullptr); 0176 connect(this, &CompletionObject::fetchingTypeDone, this, &CompletionObject::completeLineWithType); 0177 0178 if (type == FunctionWithArguments || type == FunctionWithoutArguments) { 0179 d->completion = d->command; 0180 emit done(); 0181 } 0182 } 0183 0184 void CompletionObject::completeLineWithType(IdentifierType type) 0185 { 0186 switch(type) { 0187 case VariableType: 0188 completeVariableLine(); 0189 break; 0190 case FunctionWithArguments: 0191 case FunctionWithoutArguments: 0192 completeFunctionLine(type); 0193 break; 0194 case KeywordType: 0195 completeKeywordLine(); 0196 break; 0197 case UnknownType: 0198 completeUnknownLine(); 0199 break; 0200 } 0201 } 0202 0203 void CompletionObject::completeFunctionLine(IdentifierType type) 0204 { 0205 QString newline; 0206 int newindex; 0207 0208 QString func = d->identifier; 0209 int after_command = d->position + d->command.length(); 0210 QString part1 = d->line.left(d->position) + func; 0211 int index = d->position + func.length() + 1; 0212 if (after_command < d->line.length() && d->line.at(after_command) == QLatin1Char('(')) { 0213 QString part2 = d->line.mid(after_command+1); 0214 int i; 0215 // search for next non-space position 0216 for (i = after_command+1; 0217 i < d->line.length() && d->line.at(i).isSpace(); 0218 ++i) {} 0219 if (type == FunctionWithArguments) { 0220 if (i < d->line.length()) { 0221 newline = part1+QLatin1Char('(')+part2; 0222 newindex = index; 0223 } else { 0224 newline = part1+QLatin1String("()")+part2; 0225 newindex = index; 0226 } 0227 } else /*type == FunctionWithoutArguments*/ { 0228 if (i < d->line.length() && d->line.at(i) == QLatin1Char(')')) { 0229 newline = part1+QLatin1Char('(')+part2; 0230 newindex = index+i-after_command; 0231 } else { 0232 newline = part1+QLatin1String("()")+part2; 0233 newindex = index+1; 0234 } 0235 } 0236 } else { 0237 QString part2 = d->line.mid(after_command); 0238 if (type == FunctionWithArguments) { 0239 newline = part1+QLatin1String("()")+part2; 0240 newindex = index; 0241 } else /*type == FunctionWithoutArguments*/ { 0242 newline = part1+QLatin1String("()")+part2; 0243 newindex = index+1; 0244 } 0245 } 0246 emit lineDone(newline, newindex); 0247 } 0248 0249 void CompletionObject::completeKeywordLine() 0250 { 0251 QString keyword = d->identifier; 0252 int after_command = d->position + d->command.length(); 0253 int newindex = d->position + keyword.length() + 1; 0254 QString part1 = d->line.left(d->position) + keyword; 0255 QString part2 = d->line.mid(after_command); 0256 if (after_command < d->line.length() && d->line.at(after_command) == QLatin1Char(' ')) 0257 emit lineDone(part1+part2, newindex); 0258 else 0259 emit lineDone(part1+QLatin1Char(' ')+part2, newindex); 0260 } 0261 0262 void CompletionObject::completeVariableLine() 0263 { 0264 QString var = d->identifier; 0265 int after_command = d->position + d->command.length(); 0266 QString newline = d->line.left(d->position) + var + d->line.mid(after_command); 0267 int newindex = d->position + var.length(); 0268 emit lineDone(newline, newindex); 0269 } 0270 0271 void CompletionObject::completeUnknownLine() 0272 { 0273 // identifiers of unknown type are completed like variables 0274 completeVariableLine(); 0275 } 0276 0277