File indexing completed on 2023-05-30 11:20:06
0001 /* 0002 SPDX-FileCopyrightText: 2007 Piyush verma <piyush.verma@gmail.com> 0003 SPDX-FileCopyrightText: 2009 Niko Sams <niko.sams@gmail.com> 0004 SPDX-FileCopyrightText: 2010 Milian Wolff <mail@milianw.de> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "phplanguagesupport.h" 0010 0011 #include <QMutexLocker> 0012 #include <QReadWriteLock> 0013 0014 #include <kpluginfactory.h> 0015 #include <kpluginloader.h> 0016 #include <KTextEditor/Document> 0017 0018 #include <interfaces/icore.h> 0019 #include <interfaces/ilanguagecontroller.h> 0020 #include <interfaces/iplugincontroller.h> 0021 #include <interfaces/idocument.h> 0022 #include <interfaces/iproject.h> 0023 #include <language/backgroundparser/backgroundparser.h> 0024 #include <language/duchain/duchain.h> 0025 #include <language/duchain/duchainlock.h> 0026 #include <interfaces/idocumentcontroller.h> 0027 #include <interfaces/contextmenuextension.h> 0028 #include <language/interfaces/editorcontext.h> 0029 0030 #include "phpparsejob.h" 0031 #include "phphighlighting.h" 0032 #include "kdevphpversion.h" 0033 #include "phpdebug.h" 0034 #include "codegen/refactoring.h" 0035 0036 #include <language/codecompletion/codecompletion.h> 0037 #include <language/codecompletion/codecompletionmodel.h> 0038 0039 #include "completion/model.h" 0040 #include "completion/worker.h" 0041 0042 #include "navigation/navigationwidget.h" 0043 #include <language/duchain/parsingenvironment.h> 0044 0045 #include "duchain/helper.h" 0046 #include <QTimer> 0047 0048 using namespace KTextEditor; 0049 using namespace KDevelop; 0050 0051 K_PLUGIN_FACTORY_WITH_JSON(KDevPhpSupportFactory, "kdevphpsupport.json", registerPlugin<Php::LanguageSupport>(); ) 0052 0053 namespace Php 0054 { 0055 0056 LanguageSupport::LanguageSupport(QObject* parent, const QVariantList& /*args*/) 0057 : KDevelop::IPlugin(QStringLiteral("kdevphpsupport"), parent), 0058 KDevelop::ILanguageSupport() 0059 { 0060 Q_ASSERT(internalFunctionFile().toUrl().isValid()); 0061 0062 m_highlighting = new Php::Highlighting(this); 0063 m_refactoring = new Php::Refactoring(this); 0064 0065 auto* ccModel = new CodeCompletionModel(this); 0066 new KDevelop::CodeCompletion(this, ccModel, name()); 0067 } 0068 0069 LanguageSupport::~LanguageSupport() 0070 { 0071 parseLock()->lockForWrite(); 0072 //By locking the parse-mutexes, we make sure that parse- and preprocess-jobs 0073 //get a chance to finish in a good state 0074 parseLock()->unlock(); 0075 } 0076 0077 KDevelop::ParseJob *LanguageSupport::createParseJob(const IndexedString &url) 0078 { 0079 auto *job = new ParseJob(url, this); 0080 0081 // bypass the 5 MB maximum file size limit for the internal file 0082 if (url == internalFunctionFile()) { 0083 job->setMaximumFileSize(std::numeric_limits<qint64>::max()); 0084 job->setMinimumFeatures(TopDUContext::AllDeclarationsAndContexts); 0085 } 0086 0087 return job; 0088 } 0089 0090 QString LanguageSupport::name() const 0091 { 0092 return QStringLiteral("Php"); 0093 } 0094 0095 KDevelop::ICodeHighlighting* LanguageSupport::codeHighlighting() const 0096 { 0097 return m_highlighting; 0098 } 0099 0100 ContextMenuExtension LanguageSupport::contextMenuExtension(Context* context, QWidget* parent) 0101 { 0102 ContextMenuExtension cm; 0103 EditorContext *ed = dynamic_cast<KDevelop::EditorContext *>(context); 0104 0105 if (ed && ICore::self()->languageController()->languagesForUrl(ed->url()).contains(this)) { 0106 // It's safe to add our own ContextMenuExtension. 0107 m_refactoring->fillContextMenu(cm, context, parent); 0108 } 0109 return cm; 0110 } 0111 0112 QPair<QString, Range> LanguageSupport::wordUnderCursor(const QUrl& url, const Cursor& position) 0113 { 0114 KDevelop::IDocument* doc = core()->documentController()->documentForUrl(url); 0115 if(!doc || !doc->textDocument()) 0116 return {}; 0117 0118 int lineNumber = position.line(); 0119 int lineLength = doc->textDocument()->lineLength(lineNumber); 0120 0121 QString line = doc->textDocument()->text(Range(lineNumber, 0, lineNumber, lineLength)); 0122 0123 int startCol = position.column(); 0124 for ( ; startCol >= 0; --startCol ) { 0125 if ( !line[startCol].isLetter() && line[startCol] != '_' ) { 0126 // don't include the wrong char 0127 if ( startCol != position.column() ) { 0128 ++startCol; 0129 } 0130 break; 0131 } 0132 } 0133 int endCol = position.column(); 0134 for ( ; endCol <= lineLength; ++endCol ) { 0135 if ( !line[endCol].isLetter() && line[endCol] != '_' ) { 0136 break; 0137 } 0138 } 0139 QString word = line.mid(startCol, endCol - startCol); 0140 Range range(lineNumber, startCol, lineNumber, endCol); 0141 return qMakePair(word, range); 0142 } 0143 0144 bool isMagicConstant(QPair<QString, Range> word) { 0145 if ( word.second.isValid() && !word.second.isEmpty() ) { 0146 if ( word.first == QLatin1String("__FILE__") || word.first == QLatin1String("__LINE__") || 0147 word.first == QLatin1String("__METHOD__") || word.first == QLatin1String("__CLASS__") || 0148 word.first == QLatin1String("__FUNCTION__") || word.first == QLatin1String("__NAMESPACE__") || 0149 word.first == QLatin1String("__DIR__") || word.first == QLatin1String("__TRAIT__") 0150 ) 0151 { 0152 ///TODO: maybe we should use the tokenizer to really make sure this is such a token 0153 /// and we are not inside a string, comment or similar 0154 /// otoh, it doesn't hurt imo 0155 return true; 0156 } 0157 } 0158 return false; 0159 } 0160 0161 QPair<QWidget*, Range> LanguageSupport::specialLanguageObjectNavigationWidget(const QUrl& url, const Cursor& position) 0162 { 0163 QPair<QString, Range> word = wordUnderCursor(url, position); 0164 if ( isMagicConstant(word) ) { 0165 DUChainReadLocker lock; 0166 if (TopDUContext* top = standardContext(url)) { 0167 return {new NavigationWidget(TopDUContextPointer(top), position, word.first), word.second}; 0168 } else { 0169 return {nullptr, Range::invalid()}; 0170 } 0171 } 0172 return ILanguageSupport::specialLanguageObjectNavigationWidget(url, position); 0173 } 0174 0175 Range LanguageSupport::specialLanguageObjectRange(const QUrl& url, const Cursor& position) 0176 { 0177 QPair<QString, Range> word = wordUnderCursor(url, position); 0178 if ( isMagicConstant(word) ) { 0179 return word.second; 0180 } 0181 return ILanguageSupport::specialLanguageObjectRange(url, position); 0182 } 0183 0184 } 0185 0186 #include "phplanguagesupport.moc"