diff options
author | Eike Ziller <eike.ziller@qt.io> | 2019-10-24 12:03:52 +0200 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2019-10-24 12:31:14 +0000 |
commit | d59eb32ce6271f8f7069b4d526ba767ae59c8aed (patch) | |
tree | 5a36f4ba921cac301751d05d91d7b0eefaa66340 /plugins | |
parent | 126fe0fa0b58e3d70ca1109336f784d5659c846f (diff) |
Remove support for ghc-mod
ghc-mod is no longer active and doesn't even compile against newer
GHC versions.
Use haskell-ide-engine and Qt Creator's language protocol client
instead.
Change-Id: I5776ec8375c732b8066d09e629148ae222e981c5
Reviewed-by: hjk <hjk@qt.io>
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/haskell/CMakeLists.txt | 7 | ||||
-rw-r--r-- | plugins/haskell/filecache.cpp | 139 | ||||
-rw-r--r-- | plugins/haskell/filecache.h | 61 | ||||
-rw-r--r-- | plugins/haskell/followsymbol.cpp | 141 | ||||
-rw-r--r-- | plugins/haskell/followsymbol.h | 94 | ||||
-rw-r--r-- | plugins/haskell/ghcmod.cpp | 408 | ||||
-rw-r--r-- | plugins/haskell/ghcmod.h | 150 | ||||
-rw-r--r-- | plugins/haskell/haskell.pro | 14 | ||||
-rw-r--r-- | plugins/haskell/haskell.qbs | 7 | ||||
-rw-r--r-- | plugins/haskell/haskellcompletionassist.cpp | 44 | ||||
-rw-r--r-- | plugins/haskell/haskellcompletionassist.h | 45 | ||||
-rw-r--r-- | plugins/haskell/haskelldocument.cpp | 51 | ||||
-rw-r--r-- | plugins/haskell/haskelldocument.h | 51 | ||||
-rw-r--r-- | plugins/haskell/haskelleditorfactory.cpp | 9 | ||||
-rw-r--r-- | plugins/haskell/haskelleditorwidget.cpp | 113 | ||||
-rw-r--r-- | plugins/haskell/haskelleditorwidget.h | 60 | ||||
-rw-r--r-- | plugins/haskell/haskellhoverhandler.cpp | 166 | ||||
-rw-r--r-- | plugins/haskell/haskellhoverhandler.h | 57 | ||||
-rw-r--r-- | plugins/haskell/haskellmanager.cpp | 23 | ||||
-rw-r--r-- | plugins/haskell/haskellmanager.h | 5 | ||||
-rw-r--r-- | plugins/haskell/haskellplugin.cpp | 3 |
21 files changed, 1 insertions, 1647 deletions
diff --git a/plugins/haskell/CMakeLists.txt b/plugins/haskell/CMakeLists.txt index d2e08af..1b5ec8f 100644 --- a/plugins/haskell/CMakeLists.txt +++ b/plugins/haskell/CMakeLists.txt @@ -6,19 +6,12 @@ add_qtc_plugin(Haskell QtCreator::Core QtCreator::TextEditor QtCreator::ProjectExplorer DEPENDS Qt5::Widgets SOURCES - filecache.cpp filecache.h - followsymbol.cpp followsymbol.h - ghcmod.cpp ghcmod.h haskell.qrc haskell_global.h haskellbuildconfiguration.cpp haskellbuildconfiguration.h - haskellcompletionassist.cpp haskellcompletionassist.h haskellconstants.h - haskelldocument.cpp haskelldocument.h haskelleditorfactory.cpp haskelleditorfactory.h - haskelleditorwidget.cpp haskelleditorwidget.h haskellhighlighter.cpp haskellhighlighter.h - haskellhoverhandler.cpp haskellhoverhandler.h haskellmanager.cpp haskellmanager.h haskellplugin.cpp haskellplugin.h haskellproject.cpp haskellproject.h diff --git a/plugins/haskell/filecache.cpp b/plugins/haskell/filecache.cpp deleted file mode 100644 index 5d931c9..0000000 --- a/plugins/haskell/filecache.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "filecache.h" - -#include <coreplugin/idocument.h> -#include <texteditor/textdocument.h> -#include <utils/algorithm.h> - -#include <QFile> -#include <QLoggingCategory> -#include <QTemporaryFile> -#include <QTextDocument> - -Q_LOGGING_CATEGORY(cacheLog, "qtc.haskell.filecache", QtWarningMsg) - -using namespace Core; -using namespace TextEditor; -using namespace Utils; - -namespace Haskell { -namespace Internal { - -FileCache::FileCache(const QString &id, - const std::function<QList<Core::IDocument *>()> &documentsToUpdate) - : m_tempDir(id), - m_documentsToUpdate(documentsToUpdate) -{ - qCDebug(cacheLog) << "creating cache path at" << m_tempDir.path(); -} - - -void FileCache::update() -{ - const QList<IDocument *> documents = m_documentsToUpdate(); - for (IDocument *document : documents) { - const Utils::FilePath filePath = document->filePath(); - if (m_fileMap.contains(filePath)) { - // update the existing cached file - // check revision if possible - if (auto textDocument = qobject_cast<TextDocument *>(document)) { - if (m_fileRevision.value(filePath) != textDocument->document()->revision()) - writeFile(document); - } else { - writeFile(document); - } - } else { - // save file if it is modified - if (document->isModified()) - writeFile(document); - } - } - cleanUp(documents); -} - -QHash<FilePath, FilePath> FileCache::fileMap() const -{ - return m_fileMap; -} - -void FileCache::writeFile(IDocument *document) -{ - FilePath cacheFilePath = m_fileMap.value(document->filePath()); - if (cacheFilePath.isEmpty()) { - cacheFilePath = createCacheFile(document->filePath()); - m_fileMap.insert(document->filePath(), cacheFilePath); - } - qCDebug(cacheLog) << "writing" << cacheFilePath; - if (auto baseTextDocument = qobject_cast<BaseTextDocument *>(document)) { - QString errorMessage; - if (baseTextDocument->write(cacheFilePath.toString(), - QString::fromUtf8(baseTextDocument->contents()), - &errorMessage)) { - if (auto textDocument = qobject_cast<TextDocument *>(document)) { - m_fileRevision.insert(document->filePath(), textDocument->document()->revision()); - } else { - m_fileRevision.insert(document->filePath(), -1); - } - } else { - qCDebug(cacheLog) << "!!! writing file failed:" << errorMessage; - } - - } else { - QFile file(cacheFilePath.toString()); - if (file.open(QIODevice::WriteOnly)) { - file.write(document->contents()); - } else { - qCDebug(cacheLog) << "!!! opening file for writing failed"; - } - } -} - -void FileCache::cleanUp(const QList<IDocument *> &documents) -{ - const QSet<FilePath> files = Utils::transform<QSet>(documents, &IDocument::filePath); - auto it = QMutableHashIterator<FilePath, FilePath>(m_fileMap); - while (it.hasNext()) { - it.next(); - if (!files.contains(it.key())) { - qCDebug(cacheLog) << "deleting" << it.value(); - QFile::remove(it.value().toString()); - m_fileRevision.remove(it.key()); - it.remove(); - } - } -} - -FilePath FileCache::createCacheFile(const FilePath &filePath) -{ - QTemporaryFile tempFile(m_tempDir.path() + "/XXXXXX-" + filePath.fileName()); - tempFile.setAutoRemove(false); - tempFile.open(); - return FilePath::fromString(tempFile.fileName()); -} - -} // namespace Internal -} // namespace Haskell diff --git a/plugins/haskell/filecache.h b/plugins/haskell/filecache.h deleted file mode 100644 index 3c53d40..0000000 --- a/plugins/haskell/filecache.h +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include <utils/fileutils.h> -#include <utils/temporarydirectory.h> - -#include <QHash> - -#include <functional> - -namespace Core { class IDocument; } - -namespace Haskell { -namespace Internal { - -class FileCache -{ -public: - FileCache(const QString &id, - const std::function<QList<Core::IDocument *>()> &documentsToUpdate); - - void update(); - QHash<Utils::FilePath, Utils::FilePath> fileMap() const; - -private: - void writeFile(Core::IDocument *document); - void cleanUp(const QList<Core::IDocument *> &documents); - Utils::FilePath createCacheFile(const Utils::FilePath &filePath); - - Utils::TemporaryDirectory m_tempDir; - QHash<Utils::FilePath, Utils::FilePath> m_fileMap; - QHash<Utils::FilePath, int> m_fileRevision; - std::function<QList<Core::IDocument *>()> m_documentsToUpdate; -}; - -} // namespace Internal -} // namespace Haskell diff --git a/plugins/haskell/followsymbol.cpp b/plugins/haskell/followsymbol.cpp deleted file mode 100644 index ab32614..0000000 --- a/plugins/haskell/followsymbol.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "followsymbol.h" - -#include "haskelleditorwidget.h" -#include "haskellmanager.h" -#include "haskelltokenizer.h" - -#include <coreplugin/editormanager/editormanager.h> -#include <texteditor/codeassist/assistinterface.h> -#include <texteditor/codeassist/assistproposalitem.h> -#include <texteditor/codeassist/genericproposal.h> -#include <texteditor/codeassist/genericproposalmodel.h> - -#include <utils/qtcassert.h> - -using namespace TextEditor; -using namespace Utils; - -namespace Haskell { -namespace Internal { - -IAssistProvider::RunType FollowSymbolAssistProvider::runType() const -{ - return AsynchronousWithThread; -} - -IAssistProcessor *FollowSymbolAssistProvider::createProcessor() const -{ - return new FollowSymbolAssistProcessor(m_inNextSplit); -} - -void FollowSymbolAssistProvider::setOpenInNextSplit(bool inNextSplit) -{ - m_inNextSplit = inNextSplit; -} - -FollowSymbolAssistProcessor::FollowSymbolAssistProcessor(bool inNextSplit) - : m_inNextSplit(inNextSplit) -{ -} - -IAssistProposal *FollowSymbolAssistProcessor::immediateProposal(const AssistInterface *interface) -{ - int line, column; - const optional<Token> symbol - = HaskellEditorWidget::symbolAt(interface->textDocument(), interface->position(), - &line, &column); - QTC_ASSERT(symbol, return nullptr); // should have been checked before - const auto filePath = FilePath::fromString(interface->fileName()); - m_ghcmod = HaskellManager::ghcModForFile(filePath); - m_symbolFuture = m_ghcmod->findSymbol(filePath, symbol->text.toString()); - - auto item = new AssistProposalItem(); - item->setText(HaskellManager::trLookingUp(symbol->text.toString())); - item->setData(QString()); - item->setOrder(-1000); - - const QList<TextEditor::AssistProposalItemInterface *> list = {item}; - auto proposal = new GenericProposal(interface->position(), list); - proposal->setFragile(true); - return proposal; -} - -IAssistProposal *FollowSymbolAssistProcessor::perform(const AssistInterface *interface) -{ - const int position = interface->position(); - delete interface; - const SymbolInfoOrError info = m_symbolFuture.result(); - auto item = new FollowSymbolAssistProposalItem(m_ghcmod->basePath(), info, m_inNextSplit); - return new InstantProposal(position, {item}); -} - -FollowSymbolAssistProposalItem::FollowSymbolAssistProposalItem(const FilePath &basePath, - const SymbolInfoOrError &info, - bool inNextSplit) - : m_basePath(basePath), - m_inNextSplit(inNextSplit) -{ - const SymbolInfo *info_p = Utils::get_if<SymbolInfo>(&info); - if (info_p && !info_p->file.isEmpty()) { - m_info = info; - setText(m_basePath.toString() + '/' + info_p->file.toString()); - } -} - -void FollowSymbolAssistProposalItem::apply(TextDocumentManipulatorInterface &, int) const -{ - const SymbolInfo *info_p = Utils::get_if<SymbolInfo>(&m_info); - if (info_p) - Core::EditorManager::openEditorAt(m_basePath.toString() + '/' + info_p->file.toString(), - info_p->line, info_p->col - 1, Core::Id(), - m_inNextSplit ? Core::EditorManager::OpenInOtherSplit - : Core::EditorManager::NoFlags); -} - -void InstantActivationProposalWidget::showProposal(const QString &prefix) -{ - if (model() && model()->size() == 1) { - emit proposalItemActivated(model()->proposalItem(0)); - deleteLater(); - return; - } - GenericProposalWidget::showProposal(prefix); -} - -InstantProposal::InstantProposal(int cursorPos, const QList<AssistProposalItemInterface *> &items) - : GenericProposal(cursorPos, items) -{ -} - -IAssistProposalWidget *InstantProposal::createWidget() const -{ - return new InstantActivationProposalWidget(); -} - -} // namespace Internal -} // namespace Haskell diff --git a/plugins/haskell/followsymbol.h b/plugins/haskell/followsymbol.h deleted file mode 100644 index a4f9051..0000000 --- a/plugins/haskell/followsymbol.h +++ /dev/null @@ -1,94 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include "ghcmod.h" - -#include <texteditor/codeassist/assistproposalitem.h> -#include <texteditor/codeassist/genericproposal.h> -#include <texteditor/codeassist/genericproposalwidget.h> -#include <texteditor/codeassist/iassistprocessor.h> -#include <texteditor/codeassist/iassistprovider.h> - -namespace Haskell { -namespace Internal { - -class FollowSymbolAssistProposalItem : public TextEditor::AssistProposalItem -{ -public: - FollowSymbolAssistProposalItem(const Utils::FilePath &basePath, - const SymbolInfoOrError &info, - bool inNextSplit); - - void apply(TextEditor::TextDocumentManipulatorInterface &, int) const override; - -private: - Utils::FilePath m_basePath; - SymbolInfoOrError m_info; - bool m_inNextSplit; -}; - -class InstantActivationProposalWidget : public TextEditor::GenericProposalWidget -{ -protected: - void showProposal(const QString &prefix) override; -}; - -class InstantProposal : public TextEditor::GenericProposal -{ -public: - InstantProposal(int cursorPos, const QList<TextEditor::AssistProposalItemInterface *> &items); - - TextEditor::IAssistProposalWidget *createWidget() const override; -}; - -class FollowSymbolAssistProvider : public TextEditor::IAssistProvider -{ -public: - RunType runType() const override; - TextEditor::IAssistProcessor *createProcessor() const override; - void setOpenInNextSplit(bool inNextSplit); - -private: - bool m_inNextSplit = false; -}; - -class FollowSymbolAssistProcessor : public TextEditor::IAssistProcessor -{ -public: - FollowSymbolAssistProcessor(bool inNextSplit); - - TextEditor::IAssistProposal *immediateProposal(const TextEditor::AssistInterface *interface) override; - TextEditor::IAssistProposal *perform(const TextEditor::AssistInterface *interface) override; - -private: - std::shared_ptr<AsyncGhcMod> m_ghcmod; - QFuture<SymbolInfoOrError> m_symbolFuture; - bool m_inNextSplit; -}; - -} // namespace Internal -} // namespace Haskell diff --git a/plugins/haskell/ghcmod.cpp b/plugins/haskell/ghcmod.cpp deleted file mode 100644 index 1ca7713..0000000 --- a/plugins/haskell/ghcmod.cpp +++ /dev/null @@ -1,408 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "ghcmod.h" - -#include <coreplugin/editormanager/documentmodel.h> -#include <coreplugin/idocument.h> -#include <utils/algorithm.h> -#include <utils/environment.h> -#include <utils/qtcassert.h> - -#include <QFileInfo> -#include <QFutureWatcher> -#include <QLoggingCategory> -#include <QMetaObject> -#include <QMutexLocker> -#include <QProcess> -#include <QRegularExpression> -#include <QTime> -#include <QTimer> - -#include <functional> - -Q_LOGGING_CATEGORY(ghcModLog, "qtc.haskell.ghcmod", QtWarningMsg) -Q_LOGGING_CATEGORY(asyncGhcModLog, "qtc.haskell.ghcmod.async", QtWarningMsg) - -// TODO do not hardcode -const int kTimeoutMS = 10 * 1000; - -using namespace Utils; - -namespace Haskell { -namespace Internal { - -FilePath GhcMod::m_stackExecutable = Utils::FilePath::fromString("stack"); -QMutex GhcMod::m_mutex; - -GhcMod::GhcMod(const Utils::FilePath &path) - : m_path(path) -{ -} - -GhcMod::~GhcMod() -{ - shutdown(); -} - -FilePath GhcMod::basePath() const -{ - return m_path; -} - -void GhcMod::setFileMap(const QHash<FilePath, FilePath> &fileMap) -{ - if (fileMap != m_fileMap) { - log("setting new file map"); - m_fileMap = fileMap; - shutdown(); - } -} - -static QString toUnicode(QByteArray data) -{ - // clean zero bytes which let QString think that the string ends there - data.replace('\x0', QByteArray()); - return QString::fromUtf8(data); -} - -SymbolInfoOrError GhcMod::findSymbol(const FilePath &filePath, const QString &symbol) -{ - return parseFindSymbol(runFindSymbol(filePath, symbol)); -} - -QStringOrError GhcMod::typeInfo(const FilePath &filePath, int line, int col) -{ - return parseTypeInfo(runTypeInfo(filePath, line, col)); -} - -static QStringList fileMapArgs(const QHash<FilePath, FilePath> &map) -{ - QStringList result; - const auto end = map.cend(); - for (auto it = map.cbegin(); it != end; ++it) - result << "--map-file" << it.key().toString() + "=" + it.value().toString(); - return result; -} - -Utils::optional<Error> GhcMod::ensureStarted() -{ - m_mutex.lock(); - const FilePath plainStackExecutable = m_stackExecutable; - m_mutex.unlock(); - Environment env = Environment::systemEnvironment(); - const FilePath stackExecutable = env.searchInPath(plainStackExecutable.toString()); - if (m_process) { - if (m_process->state() == QProcess::NotRunning) { - log("is no longer running"); - m_process.reset(); - } else if (FilePath::fromString(m_process->program()) != stackExecutable) { - log("stack settings changed"); - shutdown(); - } - } - if (m_process) - return Utils::nullopt; - log("starting"); - // for ghc-mod finding stack back: - env.prependOrSetPath(stackExecutable.toFileInfo().absolutePath()); - m_process.reset(new QProcess); - m_process->setWorkingDirectory(m_path.toString()); - m_process->setEnvironment(env.toStringList()); - m_process->start(stackExecutable.toString(), - QStringList{"exec", "ghc-mod", "--"} + fileMapArgs(m_fileMap) - << "legacy-interactive"); - if (!m_process->waitForStarted(kTimeoutMS)) { - log("failed to start"); - m_process.reset(); - return Error({Error::Type::FailedToStartStack, plainStackExecutable.toUserOutput()}); - } - log("started"); - m_process->setReadChannel(QProcess::StandardOutput); - return Utils::nullopt; -} - -void GhcMod::shutdown() -{ - if (!m_process) - return; - log("shutting down"); - m_process->write("\n"); - m_process->closeWriteChannel(); - m_process->waitForFinished(300); - m_process.reset(); -} - -void GhcMod::log(const QString &message) -{ - qCDebug(ghcModLog) << "ghcmod for" << m_path.toString() << ":" << qPrintable(message); -} - -QByteArrayOrError GhcMod::runQuery(const QString &query) -{ - const Utils::optional<Error> error = ensureStarted(); - if (error) - return error.value(); - log("query \"" + query + "\""); - m_process->write(query.toUtf8() + "\n"); - bool ok = false; - QByteArray response; - QTime readTime; - readTime.start(); - while (!ok && readTime.elapsed() < kTimeoutMS) { - m_process->waitForReadyRead(kTimeoutMS - readTime.elapsed() + 10); - response += m_process->read(2048); - ok = response.endsWith("OK\n") || response.endsWith("OK\r\n"); - } - if (ghcModLog().isDebugEnabled()) - qCDebug(ghcModLog) << "response" << QTextCodec::codecForLocale()->toUnicode(response); - if (!ok) { - log("failed"); - shutdown(); - return Error({Error::Type::Other, QString()}); - } - log("success"); - // convert to unix line endings - response.replace("\r\n", "\n"); - response.chop(3); // cut off "OK\n" - return response; -} - -QByteArrayOrError GhcMod::runFindSymbol(const FilePath &filePath, const QString &symbol) -{ - return runQuery(QString("info %1 %2").arg(filePath.toString()) // TODO toNative? quoting? - .arg(symbol)); -} - -QByteArrayOrError GhcMod::runTypeInfo(const FilePath &filePath, int line, int col) -{ - return runQuery(QString("type %1 %2 %3").arg(filePath.toString()) // TODO toNative? quoting? - .arg(line) - .arg(col + 1)); -} - -SymbolInfoOrError GhcMod::parseFindSymbol(const QByteArrayOrError &response) -{ - QRegularExpression infoRegEx("^\\s*(.*?)\\s+--\\sDefined ((at (.+?)(:(\\d+):(\\d+))?)|(in ‘(.+)’.*))$"); - const QByteArray *bytes = Utils::get_if<QByteArray>(&response); - if (!bytes) - return Utils::get<Error>(response); - SymbolInfo info; - bool hasFileOrModule = false; - const QString str = toUnicode(QByteArray(*bytes).replace('\x0', '\n')); - for (const QString &line : str.split('\n')) { - if (hasFileOrModule) { - info.additionalInfo += line; - } else { - QRegularExpressionMatch result = infoRegEx.match(line); - if (result.hasMatch()) { - hasFileOrModule = true; - info.definition += result.captured(1); - if (result.lastCapturedIndex() == 7) { // Defined at <file:line:col> - info.file = FilePath::fromString(result.captured(4)); - bool ok; - int num = result.captured(6).toInt(&ok); - if (ok) - info.line = num; - num = result.captured(7).toInt(&ok); - if (ok) - info.col = num; - } else if (result.lastCapturedIndex() == 9) { // Defined in <module> - info.module = result.captured(9); - } - } else { - info.definition += line; - } - } - } - if (hasFileOrModule) - return info; - return Error({Error::Type::Other, QString()}); -} - -QStringOrError GhcMod::parseTypeInfo(const QByteArrayOrError &response) -{ - QRegularExpression typeRegEx("^\\d+\\s+\\d+\\s+\\d+\\s+\\d+\\s+\"(.*)\"$", - QRegularExpression::MultilineOption); - const QByteArray *bytes = Utils::get_if<QByteArray>(&response); - if (!bytes) - return Utils::get<Error>(response); - QRegularExpressionMatch result = typeRegEx.match(toUnicode(*bytes)); - if (result.hasMatch()) - return result.captured(1); - return Error({Error::Type::Other, QString()}); -} - -void GhcMod::setStackExecutable(const FilePath &filePath) -{ - QMutexLocker lock(&m_mutex); - m_stackExecutable = filePath; -} - -static QList<Core::IDocument *> getOpenDocuments(const FilePath &path) -{ - return Utils::filtered(Core::DocumentModel::openedDocuments(), [path] (Core::IDocument *doc) { - return path.isEmpty() || doc->filePath().isChildOf(path); - }); -} - -AsyncGhcMod::AsyncGhcMod(const FilePath &path) - : m_ghcmod(path), - m_fileCache("haskell", std::bind(getOpenDocuments, path)) -{ - qCDebug(asyncGhcModLog) << "starting thread for" << m_ghcmod.basePath().toString(); - m_thread.start(); - m_threadTarget.moveToThread(&m_thread); -} - -AsyncGhcMod::~AsyncGhcMod() -{ - qCDebug(asyncGhcModLog) << "stopping thread for" << m_ghcmod.basePath().toString(); - m_mutex.lock(); - for (Operation &op : m_queue) - op.fi.cancel(); - m_queue.clear(); - m_mutex.unlock(); - m_thread.quit(); - m_thread.wait(); -} - -FilePath AsyncGhcMod::basePath() const -{ - return m_ghcmod.basePath(); -} - -template <typename Result> -QFuture<Result> createFuture(AsyncGhcMod::Operation op, - const std::function<Result(const QByteArrayOrError &)> &postOp) -{ - auto fi = new QFutureInterface<Result>; - fi->reportStarted(); - - // propagate inner events to outside future - auto opWatcher = new QFutureWatcher<QByteArrayOrError>(); - QObject::connect(opWatcher, &QFutureWatcherBase::canceled, [fi] { fi->cancel(); }); - QObject::connect(opWatcher, &QFutureWatcherBase::finished, opWatcher, &QObject::deleteLater); - QObject::connect(opWatcher, &QFutureWatcherBase::finished, [fi] { - fi->reportFinished(); - delete fi; - }); - QObject::connect(opWatcher, &QFutureWatcherBase::resultReadyAt, - [fi, opWatcher, postOp](int index) { - fi->reportResult(postOp(opWatcher->future().resultAt(index))); - }); - opWatcher->setFuture(op.fi.future()); - - // propagate cancel from outer future to inner future - auto fiWatcher = new QFutureWatcher<Result>(); - QObject::connect(fiWatcher, &QFutureWatcherBase::canceled, [op] { op.fi.cancel(); }); - QObject::connect(fiWatcher, &QFutureWatcherBase::finished, fiWatcher, &QObject::deleteLater); - fiWatcher->setFuture(fi->future()); - - return fi->future(); -} - -/*! - Asynchronously looks up the \a symbol in the context of \a filePath. - - Returns a QFuture handle for the asynchronous operation. You may not block the main event loop - while waiting for it to finish - doing so will result in a deadlock. -*/ -QFuture<SymbolInfoOrError> AsyncGhcMod::findSymbol(const FilePath &filePath, - const QString &symbol) -{ - QMutexLocker lock(&m_mutex); - Operation op([this, filePath, symbol] { return m_ghcmod.runFindSymbol(filePath, symbol); }); - m_queue.append(op); - QTimer::singleShot(0, &m_threadTarget, [this] { reduceQueue(); }); - return createFuture<SymbolInfoOrError>(op, &GhcMod::parseFindSymbol); -} - -/*! - Asynchronously looks up the type at \a line and \a col in \a filePath. - - Returns a QFuture handle for the asynchronous operation. You may not block the main event loop - while waiting for it to finish - doing so will result in a deadlock. -*/ -QFuture<QStringOrError> AsyncGhcMod::typeInfo(const FilePath &filePath, int line, int col) -{ - QMutexLocker lock(&m_mutex); - Operation op([this, filePath, line, col] { return m_ghcmod.runTypeInfo(filePath, line, col); }); - m_queue.append(op); - QTimer::singleShot(0, &m_threadTarget, [this] { reduceQueue(); }); - return createFuture<QStringOrError>(op, &GhcMod::parseTypeInfo); -} - -/*! - Synchronously runs an update of the cache of modified files. - This must be run on the main thread. - - \internal -*/ -void AsyncGhcMod::updateCache() -{ - m_fileCache.update(); -} - -/*! - Takes operations from the queue and executes them, until the queue is empty. - This must be run within the internal thread whenever an operation is added to the queue. - Canceled operations are not executed, but removed from the queue. - Before each operation, the cache of modified files is updated on the main thread. - - \internal -*/ -void AsyncGhcMod::reduceQueue() -{ - QTC_ASSERT(QThread::currentThread() != thread(), return); - const auto takeFirst = [this]() { - Operation op; - m_mutex.lock(); - if (!m_queue.isEmpty()) - op = m_queue.takeFirst(); - m_mutex.unlock(); - return op; - }; - - Operation op; - while ((op = takeFirst()).op) { - if (!op.fi.isCanceled()) { - QMetaObject::invokeMethod(this, "updateCache", Qt::BlockingQueuedConnection); - m_ghcmod.setFileMap(m_fileCache.fileMap()); - QByteArrayOrError result = op.op(); - op.fi.reportResult(result); - } - op.fi.reportFinished(); - } -} - -AsyncGhcMod::Operation::Operation(const std::function<QByteArrayOrError()> &op) - : op(op) -{ - fi.reportStarted(); -} - -} // Internal -} // Haskell diff --git a/plugins/haskell/ghcmod.h b/plugins/haskell/ghcmod.h deleted file mode 100644 index fb3dd3f..0000000 --- a/plugins/haskell/ghcmod.h +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include "filecache.h" - -#include <utils/fileutils.h> -#include <utils/optional.h> -#include <utils/synchronousprocess.h> -#include <utils/variant.h> - -#include <QFuture> -#include <QMutex> -#include <QThread> - -#include <memory> - -QT_BEGIN_NAMESPACE -class QProcess; -QT_END_NAMESPACE - -namespace Haskell { -namespace Internal { - -class Error { -public: - enum class Type { - FailedToStartStack, - Other // TODO get rid of it - }; - Type type; - QString details; -}; - -class SymbolInfo { -public: - QStringList definition; - QStringList additionalInfo; - Utils::FilePath file; - int line = -1; - int col = -1; - QString module; -}; - -using QByteArrayOrError = Utils::variant<QByteArray, Error>; -using QStringOrError = Utils::variant<QString, Error>; -using SymbolInfoOrError = Utils::variant<SymbolInfo, Error>; - -template <typename T> class ghcmod_deleter; -template <> class ghcmod_deleter<QProcess> -{ -public: - void operator()(QProcess *p) { Utils::SynchronousProcess::stopProcess(*p); delete p; } -}; -using unique_ghcmod_process = std::unique_ptr<QProcess, ghcmod_deleter<QProcess>>; - -class GhcMod -{ -public: - GhcMod(const Utils::FilePath &path); - ~GhcMod(); - - Utils::FilePath basePath() const; - void setFileMap(const QHash<Utils::FilePath, Utils::FilePath> &fileMap); - - SymbolInfoOrError findSymbol(const Utils::FilePath &filePath, const QString &symbol); - QStringOrError typeInfo(const Utils::FilePath &filePath, int line, int col); - - QByteArrayOrError runQuery(const QString &query); - - QByteArrayOrError runFindSymbol(const Utils::FilePath &filePath, const QString &symbol); - QByteArrayOrError runTypeInfo(const Utils::FilePath &filePath, int line, int col); - - static SymbolInfoOrError parseFindSymbol(const QByteArrayOrError &response); - static QStringOrError parseTypeInfo(const QByteArrayOrError &response); - - static void setStackExecutable(const Utils::FilePath &filePath); - -private: - Utils::optional<Error> ensureStarted(); - void shutdown(); - void log(const QString &message); - - static Utils::FilePath m_stackExecutable; - static QMutex m_mutex; - - Utils::FilePath m_path; - unique_ghcmod_process m_process; // kills process on reset - QHash<Utils::FilePath, Utils::FilePath> m_fileMap; -}; - -class AsyncGhcMod : public QObject -{ - Q_OBJECT - -public: - struct Operation { - Operation() = default; - Operation(const std::function<QByteArrayOrError()> &op); - mutable QFutureInterface<QByteArrayOrError> fi; - std::function<QByteArrayOrError()> op; - }; - - AsyncGhcMod(const Utils::FilePath &path); - ~AsyncGhcMod(); - - Utils::FilePath basePath() const; - - QFuture<SymbolInfoOrError> findSymbol(const Utils::FilePath &filePath, const QString &symbol); - QFuture<QStringOrError> typeInfo(const Utils::FilePath &filePath, int line, int col); - -private slots: - void updateCache(); // called through QMetaObject::invokeMethod - -private: - void reduceQueue(); - - QThread m_thread; - QObject m_threadTarget; // used to run methods in m_thread - GhcMod m_ghcmod; // only use in m_thread - FileCache m_fileCache; // only update through reduceQueue - QVector<Operation> m_queue; - QMutex m_mutex; -}; - -} // Internal -} // Haskell diff --git a/plugins/haskell/haskell.pro b/plugins/haskell/haskell.pro index 92d0307..df46a27 100644 --- a/plugins/haskell/haskell.pro +++ b/plugins/haskell/haskell.pro @@ -3,19 +3,12 @@ DEFINES += HASKELL_LIBRARY # Haskell files SOURCES += \ - haskellcompletionassist.cpp \ haskelleditorfactory.cpp \ - haskellhoverhandler.cpp \ haskellplugin.cpp \ haskellhighlighter.cpp \ haskelltokenizer.cpp \ - ghcmod.cpp \ haskellmanager.cpp \ - haskelldocument.cpp \ optionspage.cpp \ - filecache.cpp \ - haskelleditorwidget.cpp \ - followsymbol.cpp \ haskellproject.cpp \ haskellbuildconfiguration.cpp \ stackbuildstep.cpp \ @@ -23,20 +16,13 @@ SOURCES += \ HEADERS += \ haskell_global.h \ - haskellcompletionassist.h \ haskellconstants.h \ haskelleditorfactory.h \ - haskellhoverhandler.h \ haskellplugin.h \ haskellhighlighter.h \ haskelltokenizer.h \ - ghcmod.h \ haskellmanager.h \ - haskelldocument.h \ optionspage.h \ - filecache.h \ - haskelleditorwidget.h \ - followsymbol.h \ haskellproject.h \ haskellbuildconfiguration.h \ stackbuildstep.h \ diff --git a/plugins/haskell/haskell.qbs b/plugins/haskell/haskell.qbs index d2296a9..30eb832 100644 --- a/plugins/haskell/haskell.qbs +++ b/plugins/haskell/haskell.qbs @@ -11,19 +11,12 @@ QtcPlugin { Depends { name: "ProjectExplorer" } files: [ - "filecache.cpp", "filecache.h", - "followsymbol.cpp", "followsymbol.h", - "ghcmod.cpp", "ghcmod.h", "haskell.qrc", "haskellbuildconfiguration.cpp", "haskellbuildconfiguration.h", - "haskellcompletionassist.cpp", "haskellcompletionassist.h", "haskellconstants.h", - "haskelldocument.cpp", "haskelldocument.h", "haskelleditorfactory.cpp", "haskelleditorfactory.h", - "haskelleditorwidget.cpp", "haskelleditorwidget.h", "haskell_global.h", "haskellhighlighter.cpp", "haskellhighlighter.h", - "haskellhoverhandler.cpp", "haskellhoverhandler.h", "haskellmanager.cpp", "haskellmanager.h", "haskellplugin.cpp", "haskellplugin.h", "haskellproject.cpp", "haskellproject.h", diff --git a/plugins/haskell/haskellcompletionassist.cpp b/plugins/haskell/haskellcompletionassist.cpp deleted file mode 100644 index aa053f5..0000000 --- a/plugins/haskell/haskellcompletionassist.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "haskellcompletionassist.h" - -#include "haskellconstants.h" - -#include <coreplugin/id.h> -#include <texteditor/codeassist/keywordscompletionassist.h> - -namespace Haskell { -namespace Internal { - -TextEditor::IAssistProcessor *HaskellCompletionAssistProvider::createProcessor() const -{ - auto processor = new TextEditor::KeywordsCompletionAssistProcessor(TextEditor::Keywords()); - processor->setSnippetGroup(Constants::C_HASKELLSNIPPETSGROUP_ID); - return processor; -} - -} // namespace Internal -} // namespace Haskell diff --git a/plugins/haskell/haskellcompletionassist.h b/plugins/haskell/haskellcompletionassist.h deleted file mode 100644 index 9b3f0ca..0000000 --- a/plugins/haskell/haskellcompletionassist.h +++ /dev/null @@ -1,45 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#ifndef HASKELLCOMPLETIONASSIST_H -#define HASKELLCOMPLETIONASSIST_H - -#include <texteditor/codeassist/completionassistprovider.h> - -namespace Haskell { -namespace Internal { - -class HaskellCompletionAssistProvider : public TextEditor::CompletionAssistProvider -{ - Q_OBJECT - -public: - TextEditor::IAssistProcessor *createProcessor() const override; -}; - -} // namespace Internal -} // namespace Haskell - -#endif // HASKELLCOMPLETIONASSIST_H diff --git a/plugins/haskell/haskelldocument.cpp b/plugins/haskell/haskelldocument.cpp deleted file mode 100644 index b2cc8e0..0000000 --- a/plugins/haskell/haskelldocument.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "haskelldocument.h" - -#include "haskellconstants.h" -#include "haskellmanager.h" - -using namespace TextEditor; -using namespace Utils; - -namespace Haskell { -namespace Internal { - -HaskellDocument::HaskellDocument() - : TextDocument(Constants::C_HASKELLEDITOR_ID) -{ - connect(this, &IDocument::filePathChanged, this, [this](const FilePath &, const FilePath &fn) { - m_ghcmod = HaskellManager::ghcModForFile(fn); - }); -} - -std::shared_ptr<AsyncGhcMod> HaskellDocument::ghcMod() const -{ - return m_ghcmod; -} - -} // namespace Internal -} // namespace Haskell diff --git a/plugins/haskell/haskelldocument.h b/plugins/haskell/haskelldocument.h deleted file mode 100644 index 72af5e9..0000000 --- a/plugins/haskell/haskelldocument.h +++ /dev/null @@ -1,51 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include <texteditor/textdocument.h> - -#include <memory> - -namespace Haskell { -namespace Internal { - -class AsyncGhcMod; - -class HaskellDocument : public TextEditor::TextDocument -{ - Q_OBJECT - -public: - HaskellDocument(); - - std::shared_ptr<AsyncGhcMod> ghcMod() const; - -private: - std::shared_ptr<AsyncGhcMod> m_ghcmod; -}; - -} // namespace Internal -} // namespace Haskell diff --git a/plugins/haskell/haskelleditorfactory.cpp b/plugins/haskell/haskelleditorfactory.cpp index 8e5d837..6570d22 100644 --- a/plugins/haskell/haskelleditorfactory.cpp +++ b/plugins/haskell/haskelleditorfactory.cpp @@ -25,12 +25,8 @@ #include "haskelleditorfactory.h" -#include "haskellcompletionassist.h" #include "haskellconstants.h" -#include "haskelldocument.h" -#include "haskelleditorwidget.h" #include "haskellhighlighter.h" -#include "haskellhoverhandler.h" #include <texteditor/textdocument.h> #include <texteditor/texteditoractionhandler.h> @@ -47,13 +43,10 @@ HaskellEditorFactory::HaskellEditorFactory() addMimeType("text/x-haskell"); setEditorActionHandlers(TextEditor::TextEditorActionHandler::UnCommentSelection | TextEditor::TextEditorActionHandler::FollowSymbolUnderCursor); - addHoverHandler(new HaskellHoverHandler); - setDocumentCreator([] { return new HaskellDocument(); }); - setEditorWidgetCreator([] { return new HaskellEditorWidget; }); + setDocumentCreator([] { return new TextEditor::TextDocument(Constants::C_HASKELLEDITOR_ID); }); setCommentDefinition(Utils::CommentDefinition("--", "{-", "-}")); setParenthesesMatchingEnabled(true); setMarksVisible(true); - setCompletionAssistProvider(new HaskellCompletionAssistProvider); setSyntaxHighlighterCreator([] { return new HaskellHighlighter(); }); } diff --git a/plugins/haskell/haskelleditorwidget.cpp b/plugins/haskell/haskelleditorwidget.cpp deleted file mode 100644 index d4154ae..0000000 --- a/plugins/haskell/haskelleditorwidget.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "haskelleditorwidget.h" - -#include "haskellconstants.h" -#include "haskelltokenizer.h" - -#include <coreplugin/icore.h> -#include <coreplugin/infobar.h> -#include <texteditor/textdocument.h> -#include <utils/textutils.h> - -#include <QTextBlock> -#include <QTimer> - -using namespace TextEditor; - -namespace Haskell { -namespace Internal { - -HaskellEditorWidget::HaskellEditorWidget(QWidget *parent) - : TextEditorWidget(parent) -{ -} - -Utils::optional<Token> HaskellEditorWidget::symbolAt(QTextDocument *doc, int position, - int *line, int *column) -{ - Utils::Text::convertPosition(doc, position, line, column); - if (*line < 0 || *column < 0) - return Utils::nullopt; - const QTextBlock block = doc->findBlockByNumber(*line - 1); - if (block.text().isEmpty()) - return Utils::nullopt; - const int startState = block.previous().isValid() ? block.previous().userState() : -1; - const Tokens tokens = HaskellTokenizer::tokenize(block.text(), startState); - const Token token = tokens.tokenAtColumn(*column); - if (token.isValid() - && (token.type == TokenType::Variable - || token.type == TokenType::Operator - || token.type == TokenType::Constructor - || token.type == TokenType::OperatorConstructor)) { - return token; - } - return Utils::nullopt; -} - -void HaskellEditorWidget::showFailedToStartStackError(const QString &stackExecutable, - TextEditorWidget *widget) -{ - static const char id[] = "Haskell.FailedToStartStack"; - Core::IDocument *document = widget->textDocument(); - if (!document->infoBar()->containsInfo(id)) { - Core::InfoBarEntry info( - id, - tr("Failed to start Haskell Stack \"%1\". Make sure you have stack installed and configured in the options.") - .arg(stackExecutable)); - info.setCustomButtonInfo(Core::ICore::msgShowOptionsDialog(), [document] { - QTimer::singleShot(0, Core::ICore::instance(), [document] { - document->infoBar()->removeInfo(id); - Core::ICore::showOptionsDialog(Constants::OPTIONS_GENERAL); - }); - }); - document->infoBar()->addInfo(info); - } -} - -void HaskellEditorWidget::findLinkAt(const QTextCursor &cursor, - Utils::ProcessLinkCallback &&processLinkCallback, - bool resolveTarget, - bool inNextSplit) -{ - Utils::Link link; - int line, column; - const Utils::optional<Token> symbol = symbolAt(document(), cursor.position(), &line, &column); - if (symbol) { - const QTextBlock block = document()->findBlockByNumber(line - 1); - Utils::Link link; - link.linkTextStart = block.position() + symbol->startCol; - link.linkTextEnd = link.linkTextStart + symbol->length; - if (resolveTarget) { - m_followSymbolAssistProvider.setOpenInNextSplit(inNextSplit); - invokeAssist(FollowSymbol, &m_followSymbolAssistProvider); - } - } - processLinkCallback(link); -} - -} // namespace Internal -} // namespace Haskell diff --git a/plugins/haskell/haskelleditorwidget.h b/plugins/haskell/haskelleditorwidget.h deleted file mode 100644 index 24af561..0000000 --- a/plugins/haskell/haskelleditorwidget.h +++ /dev/null @@ -1,60 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include "followsymbol.h" - -#include <texteditor/texteditor.h> -#include <utils/optional.h> - -namespace Haskell { -namespace Internal { - -class Token; - -class HaskellEditorWidget : public TextEditor::TextEditorWidget -{ -public: - HaskellEditorWidget(QWidget *parent = 0); - - static Utils::optional<Token> symbolAt(QTextDocument *doc, int position, - int *line, int *column); - - static void showFailedToStartStackError(const QString &stackExecutable, - TextEditor::TextEditorWidget *widget); - -protected: - void findLinkAt(const QTextCursor &cursor, - Utils::ProcessLinkCallback &&processLinkCallback, - bool resolveTarget = true, - bool inNextSplit = false) override; - -private: - FollowSymbolAssistProvider m_followSymbolAssistProvider; -}; - -} // namespace Internal -} // namespace Haskell diff --git a/plugins/haskell/haskellhoverhandler.cpp b/plugins/haskell/haskellhoverhandler.cpp deleted file mode 100644 index 1719297..0000000 --- a/plugins/haskell/haskellhoverhandler.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "haskellhoverhandler.h" - -#include "haskelldocument.h" -#include "haskelleditorwidget.h" -#include "haskellmanager.h" -#include "haskelltokenizer.h" - -#include <texteditor/textdocument.h> -#include <texteditor/texteditor.h> -#include <utils/qtcassert.h> -#include <utils/runextensions.h> -#include <utils/synchronousprocess.h> -#include <utils/tooltip/tooltip.h> - -using namespace Utils; - -static QString toCode(const QString &s) -{ - if (s.isEmpty()) - return s; - return "<pre>" + s.toHtmlEscaped() + "</pre>"; -} - -namespace Haskell { -namespace Internal { - -QString symbolToHtml(const SymbolInfo &info) -{ - if (info.definition.isEmpty()) - return QString(); - QString result = "<pre>" + info.definition.join("\n") + "</pre>"; - if (!info.file.isEmpty()) { - result += "<div align=\"right\"><i>-- " + info.file.toString(); - if (info.line >= 0) { - result += ":" + QString::number(info.line); - if (info.col >= 0) - result += ":" + QString::number(info.col); - } - result += "</i></div>"; - } else if (!info.module.isEmpty()) { - result += "<div align=\"right\"><i>-- Module \"" + info.module + "\"</i></div>"; - } - if (!info.additionalInfo.isEmpty()) - result += "<pre>" + info.additionalInfo.join("\n") + "</pre>"; - return result; -} - -void HaskellHoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget, - int pos, - ReportPriority report) -{ - cancel(); - m_name.clear(); - m_filePath.clear(); - const Utils::optional<Token> token = HaskellEditorWidget::symbolAt(editorWidget->document(), - pos, &m_line, &m_col); - if (token) { - m_filePath = editorWidget->textDocument()->filePath(); - m_name = token->text.toString(); - setPriority(Priority_Tooltip); - } else { - setPriority(-1); - } - report(priority()); -} - -static void showError(const QPointer<TextEditor::TextEditorWidget> &widget, - const Error &typeError, const Error &infoError) -{ - if (typeError.type == Error::Type::FailedToStartStack - || infoError.type == Error::Type::FailedToStartStack) { - const QString stackExecutable = typeError.type == Error::Type::FailedToStartStack - ? typeError.details - : infoError.details; - HaskellEditorWidget::showFailedToStartStackError(stackExecutable, widget); - } -} - -static void tryShowToolTip(const QPointer<TextEditor::TextEditorWidget> &widget, const QPoint &point, - QFuture<QStringOrError> typeFuture, - QFuture<SymbolInfoOrError> symbolFuture) -{ - if (Utils::ToolTip::isVisible() && widget - && symbolFuture.isResultReadyAt(0) && typeFuture.isResultReadyAt(0)) { - const QStringOrError typeOrError = typeFuture.result(); - const SymbolInfoOrError infoOrError = symbolFuture.result(); - if (const Error *typeError = Utils::get_if<Error>(&typeOrError)) - if (const Error *infoError = Utils::get_if<Error>(&infoOrError)) - showError(widget, *typeError, *infoError); - const QString *type = Utils::get_if<QString>(&typeOrError); - const SymbolInfo *info = Utils::get_if<SymbolInfo>(&infoOrError); - const QString typeString = !type || type->isEmpty() - ? QString() - : toCode(":: " + *type); - const QString infoString = info ? symbolToHtml(*info) : QString(); - const QString tip = typeString + infoString; - Utils::ToolTip::show(point, tip, widget); - } -} - -void HaskellHoverHandler::operateTooltip(TextEditor::TextEditorWidget *editorWidget, - const QPoint &point) -{ - cancel(); - if (m_name.isEmpty()) { - Utils::ToolTip::hide(); - return; - } - Utils::ToolTip::show(point, HaskellManager::trLookingUp(m_name), editorWidget); - - QPointer<TextEditor::TextEditorWidget> widget = editorWidget; - std::shared_ptr<AsyncGhcMod> ghcmod; - auto doc = qobject_cast<HaskellDocument *>(editorWidget->textDocument()); - QTC_ASSERT(doc, return); - ghcmod = doc->ghcMod(); - m_typeFuture = ghcmod->typeInfo(m_filePath, m_line, m_col); - m_symbolFuture = ghcmod->findSymbol(m_filePath, m_name); - Utils::onResultReady(m_typeFuture, - [typeFuture = m_typeFuture, symbolFuture = m_symbolFuture, - ghcmod, widget, point] // hold shared ghcmod pointer - (const QStringOrError &) { - tryShowToolTip(widget, point, typeFuture, symbolFuture); - }); - Utils::onResultReady(m_symbolFuture, - [typeFuture = m_typeFuture, symbolFuture = m_symbolFuture, - ghcmod, widget, point] // hold shared ghcmod pointer - (const SymbolInfoOrError &) { - tryShowToolTip(widget, point, typeFuture, symbolFuture); - }); -} - -void HaskellHoverHandler::cancel() -{ - if (m_symbolFuture.isRunning()) - m_symbolFuture.cancel(); - if (m_typeFuture.isRunning()) - m_typeFuture.cancel(); -} - -} // namespace Internal -} // namespace Haskell diff --git a/plugins/haskell/haskellhoverhandler.h b/plugins/haskell/haskellhoverhandler.h deleted file mode 100644 index a85da8e..0000000 --- a/plugins/haskell/haskellhoverhandler.h +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include "ghcmod.h" - -#include <texteditor/basehoverhandler.h> -#include <utils/fileutils.h> -#include <utils/optional.h> - -namespace Haskell { -namespace Internal { - -class HaskellHoverHandler : public TextEditor::BaseHoverHandler -{ -private: - void identifyMatch(TextEditor::TextEditorWidget *editorWidget, - int pos, - ReportPriority report) override; - void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) override; - - void cancel(); - - Utils::FilePath m_filePath; - int m_line = -1; - int m_col = -1; - QString m_name; - - QFuture<SymbolInfoOrError> m_symbolFuture; - QFuture<QStringOrError> m_typeFuture; -}; - -} // namespace Internal -} // namespace Haskell diff --git a/plugins/haskell/haskellmanager.cpp b/plugins/haskell/haskellmanager.cpp index a2eadc6..9e18b51 100644 --- a/plugins/haskell/haskellmanager.cpp +++ b/plugins/haskell/haskellmanager.cpp @@ -25,8 +25,6 @@ #include "haskellmanager.h" -#include "ghcmod.h" - #include <utils/hostosinfo.h> #include <QCoreApplication> @@ -46,7 +44,6 @@ namespace Internal { class HaskellManagerPrivate { public: - std::unordered_map<FilePath, std::weak_ptr<AsyncGhcMod>> ghcModCache; FilePath stackExecutable; }; @@ -74,21 +71,6 @@ FilePath HaskellManager::findProjectDirectory(const FilePath &filePath) return {}; } -std::shared_ptr<AsyncGhcMod> HaskellManager::ghcModForFile(const FilePath &filePath) -{ - const FilePath projectPath = findProjectDirectory(filePath); - const auto cacheEntry = m_d->ghcModCache.find(projectPath); - if (cacheEntry != m_d->ghcModCache.cend()) { - if (cacheEntry->second.expired()) - m_d->ghcModCache.erase(cacheEntry); - else - return cacheEntry->second.lock(); - } - auto ghcmod = std::make_shared<AsyncGhcMod>(projectPath); - m_d->ghcModCache.insert(std::make_pair(projectPath, ghcmod)); - return ghcmod; -} - FilePath defaultStackExecutable() { // stack from brew or the installer script from https://docs.haskellstack.org @@ -127,10 +109,5 @@ void HaskellManager::writeSettings(QSettings *settings) settings->setValue(kStackExecutableKey, m_d->stackExecutable.toString()); } -QString HaskellManager::trLookingUp(const QString &name) -{ - return QCoreApplication::translate("HaskellManager", "Looking up \"%1\"...").arg(name); -} - } // namespace Internal } // namespace Haskell diff --git a/plugins/haskell/haskellmanager.h b/plugins/haskell/haskellmanager.h index b4a2e35..63013c9 100644 --- a/plugins/haskell/haskellmanager.h +++ b/plugins/haskell/haskellmanager.h @@ -36,8 +36,6 @@ QT_END_NAMESPACE namespace Haskell { namespace Internal { -class AsyncGhcMod; - class HaskellManager : public QObject { Q_OBJECT @@ -46,14 +44,11 @@ public: static HaskellManager *instance(); static Utils::FilePath findProjectDirectory(const Utils::FilePath &filePath); - static std::shared_ptr<AsyncGhcMod> ghcModForFile(const Utils::FilePath &filePath); static Utils::FilePath stackExecutable(); static void setStackExecutable(const Utils::FilePath &filePath); static void readSettings(QSettings *settings); static void writeSettings(QSettings *settings); - static QString trLookingUp(const QString &name); - signals: void stackExecutableChanged(const Utils::FilePath &filePath); }; diff --git a/plugins/haskell/haskellplugin.cpp b/plugins/haskell/haskellplugin.cpp index d92c4f8..0aa187f 100644 --- a/plugins/haskell/haskellplugin.cpp +++ b/plugins/haskell/haskellplugin.cpp @@ -25,7 +25,6 @@ #include "haskellplugin.h" -#include "ghcmod.h" #include "haskellbuildconfiguration.h" #include "haskellconstants.h" #include "haskelleditorfactory.h" @@ -72,8 +71,6 @@ bool HaskellPlugin::initialize(const QStringList &arguments, QString *errorStrin connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested, this, [] { HaskellManager::writeSettings(Core::ICore::settings()); }); - connect(HaskellManager::instance(), &HaskellManager::stackExecutableChanged, - &GhcMod::setStackExecutable); HaskellManager::readSettings(Core::ICore::settings()); return true; |