File indexing completed on 2024-04-28 08:25:23

0001 /*****************************************************************************
0002  * Copyright (c) 2007 Piyush verma <piyush.verma@gmail.com>                  *
0003  * Copyright (c) 2008,2010 Niko Sams <niko.sams@gmail.com>                   *
0004  * Copyright (c) 2010 Milian Wolff <mail@milianw.de>                         *
0005  *                                                                           *
0006  * This program is free software; you can redistribute it and/or modify      *
0007  * it under the terms of the GNU General Public License as published by      *
0008  * the Free Software Foundation; either version 2 of the License, or         *
0009  * (at your option) any later version.                                       *
0010  *                                                                           *
0011  * This program is distributed in the hope that it will be useful,           *
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
0014  * GNU General Public License for more details.                              *
0015  *                                                                           *
0016  * You should have received a copy of the GNU General Public License         *
0017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.     *
0018  *****************************************************************************/
0019 
0020 #include "parsejob.h"
0021 
0022 #include <QFile>
0023 #include <QMimeDatabase>
0024 #include <QReadWriteLock>
0025 #include <QReadLocker>
0026 #include <QThread>
0027 
0028 #include <language/duchain/duchainlock.h>
0029 #include <language/duchain/duchain.h>
0030 #include <language/duchain/topducontext.h>
0031 #include <language/duchain/parsingenvironment.h>
0032 #include <language/duchain/declaration.h>
0033 #include <language/backgroundparser/urlparselock.h>
0034 
0035 #include "debug.h"
0036 #include "parser/editorintegrator.h"
0037 #include "parser/parsesession.h"
0038 #include "csslanguagesupport.h"
0039 #include "duchain/builders/declarationbuilder.h"
0040 #include "parser/htmlparser.h"
0041 
0042 
0043 namespace Css
0044 {
0045 
0046 ParseJob::ParseJob(const KDevelop::IndexedString& url, KDevelop::ILanguageSupport* languageSupport)
0047         : KDevelop::ParseJob(url, languageSupport)
0048 {
0049     qCDebug(KDEV_CSS);
0050 }
0051 
0052 ParseJob::~ParseJob()
0053 {
0054     qCDebug(KDEV_CSS);
0055 }
0056 
0057 void ParseJob::run(ThreadWeaver::JobPointer /*self*/, ThreadWeaver::Thread */*thread*/)
0058 {
0059     KDevelop::UrlParseLock urlLock(document());
0060 
0061     if ( !(minimumFeatures() & KDevelop::TopDUContext::ForceUpdate) ) {
0062         KDevelop::DUChainReadLocker lock(KDevelop::DUChain::lock());
0063         bool needsUpdate = true;
0064         foreach(const KDevelop::ParsingEnvironmentFilePointer &file, KDevelop::DUChain::self()->allEnvironmentFiles(document())) {
0065             if (file->needsUpdate()) {
0066                 needsUpdate = true;
0067                 break;
0068             } else {
0069                 needsUpdate = false;
0070             }
0071         }
0072         if (!needsUpdate) {
0073             qCDebug(KDEV_CSS) << "Already up to date" << document().str();
0074             return;
0075         }
0076     }
0077 
0078     qCDebug(KDEV_CSS) << "parsing" << document().str();
0079 
0080     KDevelop::ProblemPointer p = readContents();
0081     if (p) {
0082         //TODO: associate problem with topducontext
0083         return abortJob();;
0084     }
0085 
0086     QList<HtmlParser::Part> parts;
0087 
0088     QMimeDatabase db;
0089     if (db.mimeTypeForUrl(document().toUrl()).name() == "text/css") {
0090         HtmlParser::Part part;
0091         part.kind = HtmlParser::Part::Standalone;
0092         part.contents = contents().contents;
0093         part.range.start() = {0, 0};
0094         //part.range.end = TODO (needed?)
0095         parts << part;
0096     } else {
0097         HtmlParser p;
0098         p.setContents(contents().contents);
0099         parts = p.parse();
0100         if (parts.isEmpty()) {
0101             parts << HtmlParser::Part(); //empty part
0102         }
0103     }
0104     Q_ASSERT(!parts.isEmpty());
0105 
0106     HtmlAst *fileAst = new HtmlAst;
0107     fileAst->kind = HtmlAst::KIND;
0108     foreach (const HtmlParser::Part &part, parts) {
0109         ParseSession *session = new ParseSession;
0110         session->setCurrentDocument(document());
0111         session->setOffset(KDevelop::CursorInRevision::castFromSimpleCursor(part.range.start()));
0112         session->setContents(part.contents);
0113         if (part.kind != HtmlParser::Part::InlineStyle) {
0114             StyleElementAst *el = new StyleElementAst;
0115             el->kind = StyleElementAst::KIND;
0116             StartAst* ast = nullptr;
0117             session->parse(&ast);
0118             el->start = ast;
0119             el->session = session;
0120             fileAst->elements << el;
0121         } else {
0122             InlineStyleAst *el = new InlineStyleAst;
0123             el->kind = InlineStyleAst::KIND;
0124             DeclarationListAst* ast = nullptr;
0125             session->parse(&ast);
0126             el->declarationList = ast;
0127             el->session = session;
0128             fileAst->elements << el;
0129         }
0130 
0131         if (abortRequested())
0132         {
0133             return abortJob();
0134         }
0135     }
0136 
0137     KDevelop::ReferencedTopDUContext top;
0138     {
0139         KDevelop::DUChainReadLocker lock(KDevelop::DUChain::lock());
0140         top = KDevelop::DUChain::self()->chainForDocument(document());
0141     }
0142     if (top) {
0143         qCDebug(KDEV_CSS) << "re-compiling" << document().str();
0144         KDevelop::DUChainWriteLocker lock(KDevelop::DUChain::lock());
0145         top->clearImportedParentContexts();
0146         top->parsingEnvironmentFile()->clearModificationRevisions();
0147         top->clearProblems();
0148     } else {
0149         qCDebug(KDEV_CSS) << "compiling" << document().str();
0150     }
0151 
0152     QReadLocker parseLock(languageSupport()->parseLock());
0153 
0154     EditorIntegrator editor;
0155     DeclarationBuilder builder;
0156     builder.setEditor(&editor);
0157     top = builder.build(document(), fileAst, top);
0158     qCDebug(KDEV_CSS) << top;
0159     Q_ASSERT(top);
0160 
0161     foreach (AstNode *el, fileAst->elements) {
0162 
0163         ParseSession *session = nullptr;
0164         if (el->kind == StyleElementAst::KIND) {
0165             session = static_cast<StyleElementAst*>(el)->session;
0166             static_cast<StyleElementAst*>(el)->session = nullptr; //deleted below
0167         } else if (el->kind == InlineStyleAst::KIND) {
0168             session = static_cast<InlineStyleAst*>(el)->session;
0169             static_cast<InlineStyleAst*>(el)->session = nullptr; //deleted below
0170         }
0171         Q_ASSERT(session);
0172         foreach(const KDevelop::ProblemPointer &p, session->problems()) {
0173             KDevelop::DUChainWriteLocker lock(KDevelop::DUChain::lock());
0174             top->addProblem(p);
0175         }
0176         delete session;
0177 
0178         if (abortRequested()) {
0179             return abortJob();
0180         }
0181         delete el;
0182     }
0183     delete fileAst;
0184     setDuChain(top);
0185 
0186     KDevelop::DUChainWriteLocker lock(KDevelop::DUChain::lock());
0187 
0188     top->setFeatures(minimumFeatures());
0189     KDevelop::ParsingEnvironmentFilePointer file = top->parsingEnvironmentFile();
0190 
0191     QFileInfo fileInfo(document().str());
0192     QDateTime lastModified = fileInfo.lastModified();
0193     file->setModificationRevision(contents().modification);
0194     KDevelop::DUChain::self()->updateContextEnvironment( top->topContext(), file.data() );
0195     KDevelop::DUChain::self()->emitUpdateReady(document(), top);
0196 }
0197 
0198 }
0199 
0200 // kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on; auto-insert-doxygen on