Nim: Add support for goto field under cursor

Change-Id: Ic0cce41d2c3d8dc9bcc9ccd07c3943fd0b2659f9
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Filippo Cucchetto
2019-11-05 12:33:42 +01:00
parent b94688035e
commit a504472790
13 changed files with 237 additions and 51 deletions

View File

@@ -5,6 +5,7 @@ add_qtc_plugin(Nim
editor/nimeditorfactory.cpp editor/nimeditorfactory.h
editor/nimhighlighter.cpp editor/nimhighlighter.h
editor/nimindenter.cpp editor/nimindenter.h
editor/nimtexteditorwidget.cpp editor/nimtexteditorwidget.h
nim.qrc
nimconstants.h
nimplugin.cpp nimplugin.h

View File

@@ -119,12 +119,12 @@ private:
std::unique_ptr<QTemporaryFile> dirtyFile = writeDirtyFile(interface);
QTC_ASSERT(dirtyFile, return);
std::shared_ptr<Suggest::SugRequest> request = sendRequest(interface,
std::shared_ptr<Suggest::NimSuggestClientRequest> request = sendRequest(interface,
suggest,
dirtyFile->fileName(),
pos);
QTC_ASSERT(request, return);
connect(request.get(), &Suggest::SugRequest::finished, this,
connect(request.get(), &Suggest::NimSuggestClientRequest::finished, this,
&NimCompletionAssistProcessor::onRequestFinished);
m_pos = pos;
@@ -162,10 +162,10 @@ private:
return Nim::Suggest::NimSuggestCache::instance().get(filename);
}
static std::shared_ptr<Suggest::SugRequest> sendRequest(const AssistInterface *interface,
Suggest::NimSuggest *suggest,
QString dirtyFile,
int pos)
static std::shared_ptr<Suggest::NimSuggestClientRequest> sendRequest(const AssistInterface *interface,
Suggest::NimSuggest *suggest,
QString dirtyFile,
int pos)
{
int line = 0, column = 0;
Utils::Text::convertPosition(interface->textDocument(), pos, &line, &column);
@@ -256,7 +256,7 @@ private:
bool m_running = false;
int m_pos = -1;
std::weak_ptr<Suggest::NimSuggest> m_suggest;
std::shared_ptr<Suggest::SugRequest> m_request;
std::shared_ptr<Suggest::NimSuggestClientRequest> m_request;
std::unique_ptr<QTemporaryFile> m_dirtyFile;
const TextEditor::AssistInterface *m_interface = nullptr;
};

View File

@@ -30,6 +30,7 @@
#include "../nimconstants.h"
#include "../nimplugin.h"
#include "nimtexteditorwidget.h"
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/texteditorconstants.h>
@@ -50,12 +51,10 @@ NimEditorFactory::NimEditorFactory()
setEditorActionHandlers(TextEditorActionHandler::Format
| TextEditorActionHandler::UnCommentSelection
| TextEditorActionHandler::UnCollapseAll);
| TextEditorActionHandler::UnCollapseAll
| TextEditorActionHandler::FollowSymbolUnderCursor);
setEditorWidgetCreator([]{
auto result = new TextEditorWidget();
result->setLanguageSettingsId(Nim::Constants::C_NIMLANGUAGE_ID);
return result;
return new NimTextEditorWidget();
});
setDocumentCreator([]() {
return new TextDocument(Constants::C_NIMEDITOR_ID);

View File

@@ -0,0 +1,109 @@
/****************************************************************************
**
** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com>
** Contact: http://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 "nimtexteditorwidget.h"
#include "nimconstants.h"
#include "suggest/nimsuggestcache.h"
#include "suggest/nimsuggest.h"
#include <texteditor/textdocument.h>
#include <texteditor/codeassist/assistinterface.h>
#include <utils/qtcassert.h>
#include <utils/textutils.h>
#include <QTextStream>
#include <QTemporaryFile>
#include <QTextDocument>
using namespace Nim;
using namespace Suggest;
namespace {
std::unique_ptr<QTemporaryFile> writeDirtyFile(const TextEditor::TextDocument *doc)
{
auto result = std::make_unique<QTemporaryFile>("qtcnim.XXXXXX.nim");
QTC_ASSERT(result->open(), return nullptr);
QTextStream stream(result.get());
stream << doc->plainText();
result->close();
return result;
}
}
NimTextEditorWidget::NimTextEditorWidget(QWidget *parent)
: TextEditorWidget(parent)
{
setLanguageSettingsId(Nim::Constants::C_NIMLANGUAGE_ID);
}
void NimTextEditorWidget::findLinkAt(const QTextCursor &c, Utils::ProcessLinkCallback &&processLinkCallback, bool /*resolveTarget*/, bool /*inNextSplit*/)
{
const Utils::FilePath &path = textDocument()->filePath();
NimSuggest *suggest = NimSuggestCache::instance().get(path);
if (!suggest)
return processLinkCallback(Utils::Link());
std::unique_ptr<QTemporaryFile> dirtyFile = writeDirtyFile(textDocument());
int line = 0, column = 0;
Utils::Text::convertPosition(document(), c.position(), &line, &column);
std::shared_ptr<NimSuggestClientRequest> request = suggest->def(path.toString(),
line,
column - 1,
dirtyFile->fileName());
if (!request)
return processLinkCallback(Utils::Link());
if (m_request) {
QObject::disconnect(m_request.get());
m_request = nullptr;
}
if (m_callback)
m_callback(Utils::Link());
m_dirtyFile = std::move(dirtyFile);
m_callback = std::move(processLinkCallback);
m_request = std::move(request);
QObject::connect(m_request.get(), &NimSuggestClientRequest::finished, this, &NimTextEditorWidget::onFindLinkFinished);
}
void NimTextEditorWidget::onFindLinkFinished()
{
QTC_ASSERT(m_request.get() == this->sender(), return);
if (m_request->lines().empty()) {
m_callback(Utils::Link());
return;
}
const Line &line = m_request->lines().front();
m_callback(Utils::Link{line.abs_path, line.row, line.column});
}

View File

@@ -0,0 +1,49 @@
/****************************************************************************
**
** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com>
** Contact: http://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/texteditor.h>
namespace Nim {
namespace Suggest { class NimSuggestClientRequest; }
class NimTextEditorWidget : public TextEditor::TextEditorWidget
{
public:
NimTextEditorWidget(QWidget* parent = nullptr);
protected:
void findLinkAt(const QTextCursor &, Utils::ProcessLinkCallback &&processLinkCallback, bool resolveTarget, bool inNextSplit);
private:
void onFindLinkFinished();
std::shared_ptr<Nim::Suggest::NimSuggestClientRequest> m_request;
Utils::ProcessLinkCallback m_callback;
std::unique_ptr<QTemporaryFile> m_dirtyFile;
};
}

View File

@@ -14,6 +14,7 @@ HEADERS += \
editor/nimcompletionassistprovider.h \
editor/nimhighlighter.h \
editor/nimindenter.h \
editor/nimtexteditorwidget.h \
project/nimblebuildconfiguration.h \
project/nimblebuildstep.h \
project/nimblebuildstepwidget.h \
@@ -53,6 +54,7 @@ SOURCES += \
editor/nimcompletionassistprovider.cpp \
editor/nimhighlighter.cpp \
editor/nimindenter.cpp \
editor/nimtexteditorwidget.cpp \
project/nimblebuildconfiguration.cpp \
project/nimblebuildstep.cpp \
project/nimbletaskstep.cpp \

View File

@@ -28,6 +28,7 @@ QtcPlugin {
"nimeditorfactory.h", "nimeditorfactory.cpp",
"nimhighlighter.h", "nimhighlighter.cpp",
"nimindenter.h", "nimindenter.cpp",
"nimtexteditorwidget.h", "nimtexteditorwidget.cpp",
"nimcompletionassistprovider.h", "nimcompletionassistprovider.cpp"
]
}

View File

@@ -53,22 +53,38 @@ bool NimSuggestClient::disconnectFromServer()
return true;
}
std::shared_ptr<SugRequest> NimSuggestClient::sug(const QString &nimFile,
int line, int column,
const QString &dirtyFile)
std::shared_ptr<NimSuggestClientRequest> NimSuggestClient::sug(const QString &nimFile,
int line, int column,
const QString &dirtyFile)
{
return sendRequest(QLatin1String("sug"), nimFile, line, column, dirtyFile);
}
std::shared_ptr<NimSuggestClientRequest> NimSuggestClient::def(const QString &nimFile,
int line, int column,
const QString &dirtyFile)
{
return sendRequest(QLatin1String("def"), nimFile, line, column, dirtyFile);
}
std::shared_ptr<NimSuggestClientRequest> NimSuggestClient::sendRequest(const QString& type,
const QString &nimFile,
int line, int column,
const QString &dirtyFile)
{
if (!m_socket.isOpen())
return nullptr;
auto result = std::make_shared<SugRequest>(m_lastMessageId++);
auto result = std::make_shared<NimSuggestClientRequest>(m_lastMessageId++);
m_requests.emplace(result->id(), result);
QByteArray body = QString(R"((call %1 sug ("%2" %3 %4 "%5"))\n)")
.arg(result->id())
.arg(nimFile)
.arg(line).arg(column)
.arg(dirtyFile)
.toUtf8();
QByteArray body = QString(R"((call %1 %2 ("%3" %4 %5 "%6"))\n)")
.arg(result->id())
.arg(type)
.arg(nimFile)
.arg(line).arg(column)
.arg(dirtyFile)
.toUtf8();
QByteArray length = QString::number(body.size(), 16).rightJustified(6, '0').toUtf8();
QByteArray message = length + body;
@@ -135,7 +151,7 @@ void NimSuggestClient::parsePayload(const char *payload, std::size_t size)
if (it == m_requests.end())
return;
auto req = std::dynamic_pointer_cast<SugRequest>((*it).second.lock());
auto req = std::dynamic_pointer_cast<NimSuggestClientRequest>((*it).second.lock());
if (!req)
return;

View File

@@ -49,15 +49,24 @@ public:
bool disconnectFromServer();
std::shared_ptr<SugRequest> sug(const QString &nimFile,
int line, int column,
const QString &dirtyFile);
std::shared_ptr<NimSuggestClientRequest> sug(const QString &nimFile,
int line, int column,
const QString &dirtyFile);
std::shared_ptr<NimSuggestClientRequest> def(const QString &nimFile,
int line, int column,
const QString &dirtyFile);
signals:
void connected();
void disconnected();
private:
std::shared_ptr<NimSuggestClientRequest> sendRequest(const QString &type,
const QString &nimFile,
int line, int column,
const QString &dirtyFile);
void clear();
void onDisconnectedFromServer();
void onReadyRead();
@@ -65,7 +74,7 @@ private:
QTcpSocket m_socket;
quint16 m_port;
std::unordered_map<quint64, std::weak_ptr<BaseNimSuggestClientRequest>> m_requests;
std::unordered_map<quint64, std::weak_ptr<NimSuggestClientRequest>> m_requests;
std::vector<QString> m_lines;
std::vector<char> m_readBuffer;
quint64 m_lastMessageId = 0;

View File

@@ -47,14 +47,10 @@ bool Line::fromString(Line::SymbolKind &type, const std::string &str)
return result;
}
BaseNimSuggestClientRequest::BaseNimSuggestClientRequest(quint64 id)
NimSuggestClientRequest::NimSuggestClientRequest(quint64 id)
: m_id(id)
{}
quint64 BaseNimSuggestClientRequest::id() const
{
return m_id;
}
} // namespace Suggest
} // namespace Nim

View File

@@ -93,26 +93,17 @@ public:
QString doc;
};
class BaseNimSuggestClientRequest : public QObject
class NimSuggestClientRequest : public QObject
{
Q_OBJECT
public:
BaseNimSuggestClientRequest(quint64 id);
NimSuggestClientRequest(quint64 id);
quint64 id() const;
signals:
void finished();
private:
const quint64 m_id;
};
class SugRequest : public BaseNimSuggestClientRequest
{
public:
using BaseNimSuggestClientRequest::BaseNimSuggestClientRequest;
quint64 id() const
{
return m_id;
}
std::vector<Line> &lines()
{
@@ -124,14 +115,19 @@ public:
return m_lines;
}
signals:
void finished();
private:
friend class NimSuggestClient;
void setFinished(std::vector<Line> lines)
{
m_lines = std::move(lines);
emit finished();
}
const quint64 m_id;
std::vector<Line> m_lines;
};

View File

@@ -76,12 +76,17 @@ bool NimSuggest::isReady() const
return m_ready;
}
std::shared_ptr<SugRequest> NimSuggest::sug(const QString &filename, int line, int column,
const QString &dirtyFilename)
std::shared_ptr<NimSuggestClientRequest> NimSuggest::sug(const QString &filename, int line, int column,
const QString &dirtyFilename)
{
return m_ready ? m_client.sug(filename, line, column, dirtyFilename) : nullptr;
}
std::shared_ptr<NimSuggestClientRequest> NimSuggest::def(const QString &filename, int line, int column, const QString &dirtyFilename)
{
return m_ready ? m_client.def(filename, line, column, dirtyFilename) : nullptr;
}
void NimSuggest::restart()
{
disconnectClient();

View File

@@ -46,8 +46,11 @@ public:
bool isReady() const;
std::shared_ptr<SugRequest> sug(const QString &filename, int line, int column,
const QString &dirtyFilename);
std::shared_ptr<NimSuggestClientRequest> sug(const QString &filename, int line, int column,
const QString &dirtyFilename);
std::shared_ptr<NimSuggestClientRequest> def(const QString &filename, int line, int column,
const QString &dirtyFilename);
signals:
void readyChanged(bool ready);