forked from qt-creator/qt-creator
LSP: support file pattern filter and multiple mime types for lsp clients
Change-Id: I6d1b6c38d41dfd247c8883e765e5e432dbe53a9e Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -121,7 +121,7 @@ BaseClient::State BaseClient::state() const
|
||||
void BaseClient::openDocument(Core::IDocument *document)
|
||||
{
|
||||
using namespace TextEditor;
|
||||
if (!isSupportedMimeType(document->mimeType()))
|
||||
if (!isSupportedDocument(document))
|
||||
return;
|
||||
const FileName &filePath = document->filePath();
|
||||
const QString method(DidOpenTextDocumentNotification::methodName);
|
||||
@@ -497,14 +497,22 @@ void BaseClient::projectClosed(ProjectExplorer::Project *project)
|
||||
sendContent(change);
|
||||
}
|
||||
|
||||
void BaseClient::setSupportedMimeType(const QStringList &supportedMimeTypes)
|
||||
void BaseClient::setSupportedLanguage(const LanguageFilter &filter)
|
||||
{
|
||||
m_supportedMimeTypes = supportedMimeTypes;
|
||||
m_languagFilter = filter;
|
||||
}
|
||||
|
||||
bool BaseClient::isSupportedMimeType(const QString &mimeType) const
|
||||
bool BaseClient::isSupportedDocument(const Core::IDocument *document) const
|
||||
{
|
||||
return m_supportedMimeTypes.isEmpty() || m_supportedMimeTypes.contains(mimeType);
|
||||
QTC_ASSERT(document, return false);
|
||||
if (m_languagFilter.mimeTypes.isEmpty() || m_languagFilter.mimeTypes.contains(document->mimeType()))
|
||||
return true;
|
||||
auto regexps = Utils::transform(m_languagFilter.filePattern, [](const QString &pattern){
|
||||
return QRegExp(pattern, Utils::HostOsInfo::fileNameCaseSensitivity(), QRegExp::Wildcard);
|
||||
});
|
||||
return Utils::anyOf(regexps, [filePath = document->filePath()](const QRegExp ®){
|
||||
return reg.exactMatch(filePath.toString()) || reg.exactMatch(filePath.fileName());
|
||||
});
|
||||
}
|
||||
|
||||
bool BaseClient::needsRestart(const BaseSettings *) const
|
||||
|
@@ -105,8 +105,8 @@ public:
|
||||
const LanguageServerProtocol::IContent &content);
|
||||
void cancelRequest(const LanguageServerProtocol::MessageId &id);
|
||||
|
||||
void setSupportedMimeType(const QStringList &supportedMimeTypes);
|
||||
bool isSupportedMimeType(const QString &mimeType) const;
|
||||
void setSupportedLanguage(const LanguageFilter &filter);
|
||||
bool isSupportedDocument(const Core::IDocument *document) const;
|
||||
|
||||
void setName(const QString &name) { m_displayName = name; }
|
||||
QString name() const { return m_displayName; }
|
||||
@@ -154,7 +154,7 @@ private:
|
||||
QHash<QByteArray, ContentHandler> m_contentHandler;
|
||||
QBuffer m_buffer;
|
||||
QString m_displayName;
|
||||
QStringList m_supportedMimeTypes;
|
||||
LanguageFilter m_languagFilter;
|
||||
QList<Utils::FileName> m_openedDocument;
|
||||
Core::Id m_id;
|
||||
LanguageServerProtocol::ServerCapabilities m_serverCapabilities;
|
||||
|
@@ -41,17 +41,23 @@
|
||||
#include <QComboBox>
|
||||
#include <QCompleter>
|
||||
#include <QCoreApplication>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QListView>
|
||||
#include <QPushButton>
|
||||
#include <QSettings>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStringListModel>
|
||||
#include <QTreeView>
|
||||
|
||||
constexpr char nameKey[] = "name";
|
||||
constexpr char enabledKey[] = "enabled";
|
||||
constexpr char mimeTypeKey[] = "mimeType";
|
||||
constexpr char filePatternKey[] = "filePattern";
|
||||
constexpr char executableKey[] = "executable";
|
||||
constexpr char argumentsKey[] = "arguments";
|
||||
constexpr char settingsGroupKey[] = "LanguageClient";
|
||||
@@ -373,7 +379,7 @@ void BaseSettings::applyFromSettingsWidget(QWidget *widget)
|
||||
{
|
||||
if (auto settingsWidget = qobject_cast<BaseSettingsWidget *>(widget)) {
|
||||
m_name = settingsWidget->name();
|
||||
m_mimeType = settingsWidget->mimeType();
|
||||
m_languageFilter = settingsWidget->filter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +408,8 @@ QVariantMap BaseSettings::toMap() const
|
||||
QVariantMap map;
|
||||
map.insert(nameKey, m_name);
|
||||
map.insert(enabledKey, m_enabled);
|
||||
map.insert(mimeTypeKey, m_mimeType);
|
||||
map.insert(mimeTypeKey, m_languageFilter.mimeTypes);
|
||||
map.insert(filePatternKey, m_languageFilter.filePattern);
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -410,7 +417,8 @@ void BaseSettings::fromMap(const QVariantMap &map)
|
||||
{
|
||||
m_name = map[nameKey].toString();
|
||||
m_enabled = map[enabledKey].toBool();
|
||||
m_mimeType = map[mimeTypeKey].toString();
|
||||
m_languageFilter.mimeTypes = map[mimeTypeKey].toStringList();
|
||||
m_languageFilter.filePattern = map[filePatternKey].toStringList();
|
||||
}
|
||||
|
||||
void LanguageClientSettings::init()
|
||||
@@ -474,8 +482,7 @@ BaseClient *StdIOSettings::createClient() const
|
||||
{
|
||||
auto client = new StdIOClient(m_executable, m_arguments);
|
||||
client->setName(m_name);
|
||||
if (m_mimeType != noLanguageFilter)
|
||||
client->setSupportedMimeType({m_mimeType});
|
||||
client->setSupportedLanguage(m_languageFilter);
|
||||
return client;
|
||||
}
|
||||
|
||||
@@ -497,21 +504,25 @@ void StdIOSettings::fromMap(const QVariantMap &map)
|
||||
BaseSettingsWidget::BaseSettingsWidget(const BaseSettings *settings, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_name(new QLineEdit(settings->m_name, this))
|
||||
, m_mimeType(new QLineEdit(settings->m_mimeType, this))
|
||||
, m_mimeTypes(new QLabel(settings->m_languageFilter.mimeTypes.join(filterSeparator), this))
|
||||
, m_filePattern(new QLineEdit(settings->m_languageFilter.filePattern.join(filterSeparator), this))
|
||||
{
|
||||
auto *mainLayout = new QGridLayout(this);
|
||||
mainLayout->addWidget(new QLabel(tr("Name:")), 0, 0);
|
||||
mainLayout->addWidget(m_name, 0, 1);
|
||||
mainLayout->addWidget(new QLabel(tr("Language:")), 1, 0);
|
||||
mainLayout->addWidget(m_mimeType, 1 , 1);
|
||||
int row = 0;
|
||||
auto *mainLayout = new QGridLayout;
|
||||
mainLayout->addWidget(new QLabel(tr("Name:")), row, 0);
|
||||
mainLayout->addWidget(m_name, row, 1);
|
||||
mainLayout->addWidget(new QLabel(tr("Language:")), ++row, 0);
|
||||
auto mimeLayout = new QHBoxLayout;
|
||||
mimeLayout->addWidget(m_mimeTypes);
|
||||
mimeLayout->addStretch();
|
||||
auto addMimeTypeButton = new QPushButton(tr("Set MIME Types..."), this);
|
||||
mimeLayout->addWidget(addMimeTypeButton);
|
||||
mainLayout->addLayout(mimeLayout, row, 1);
|
||||
m_filePattern->setPlaceholderText(tr("File pattern"));
|
||||
mainLayout->addWidget(m_filePattern, ++row, 1);
|
||||
|
||||
auto mimeTypes = Utils::transform(Utils::allMimeTypes(), [](const Utils::MimeType &mimeType){
|
||||
return mimeType.name();
|
||||
});
|
||||
auto mimeTypeCompleter = new QCompleter(mimeTypes);
|
||||
mimeTypeCompleter->setCaseSensitivity(Qt::CaseInsensitive);
|
||||
mimeTypeCompleter->setFilterMode(Qt::MatchContains);
|
||||
m_mimeType->setCompleter(mimeTypeCompleter);
|
||||
connect(addMimeTypeButton, &QPushButton::pressed,
|
||||
this, &BaseSettingsWidget::showAddMimeTypeDialog);
|
||||
|
||||
setLayout(mainLayout);
|
||||
}
|
||||
@@ -521,9 +532,101 @@ QString BaseSettingsWidget::name() const
|
||||
return m_name->text();
|
||||
}
|
||||
|
||||
QString BaseSettingsWidget::mimeType() const
|
||||
LanguageFilter BaseSettingsWidget::filter() const
|
||||
{
|
||||
return m_mimeType->text();
|
||||
return {m_mimeTypes->text().split(filterSeparator),
|
||||
m_filePattern->text().split(filterSeparator)};
|
||||
}
|
||||
|
||||
class MimeTypeModel : public QStringListModel
|
||||
{
|
||||
public:
|
||||
using QStringListModel::QStringListModel;
|
||||
QVariant data(const QModelIndex &index, int role) const final
|
||||
{
|
||||
if (index.isValid() && role == Qt::CheckStateRole)
|
||||
return m_selectedMimeTypes.contains(index.data().toString()) ? Qt::Checked : Qt::Unchecked;
|
||||
return QStringListModel::data(index, role);
|
||||
}
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) final
|
||||
{
|
||||
if (index.isValid() && role == Qt::CheckStateRole) {
|
||||
QString mimeType = index.data().toString();
|
||||
if (value.toInt() == Qt::Checked) {
|
||||
if (!m_selectedMimeTypes.contains(mimeType))
|
||||
m_selectedMimeTypes.append(index.data().toString());
|
||||
} else {
|
||||
m_selectedMimeTypes.removeAll(index.data().toString());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return QStringListModel::setData(index, value, role);
|
||||
}
|
||||
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const final
|
||||
{
|
||||
if (!index.isValid())
|
||||
return Qt::NoItemFlags;
|
||||
return (QStringListModel::flags(index)
|
||||
& ~(Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled))
|
||||
| Qt::ItemIsUserCheckable;
|
||||
}
|
||||
QStringList m_selectedMimeTypes;
|
||||
};
|
||||
|
||||
class MimeTypeDialog : public QDialog
|
||||
{
|
||||
public:
|
||||
explicit MimeTypeDialog(const QStringList &selectedMimeTypes, QWidget *parent = nullptr)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setWindowTitle(tr("Select MIME Types"));
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
auto filter = new QLineEdit(this);
|
||||
mainLayout->addWidget(filter);
|
||||
auto listView = new QListView(this);
|
||||
mainLayout->addWidget(listView);
|
||||
auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||
mainLayout->addWidget(buttons);
|
||||
setLayout(mainLayout);
|
||||
|
||||
filter->setPlaceholderText(tr("Filter"));
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
auto proxy = new QSortFilterProxyModel(this);
|
||||
m_mimeTypeModel = new MimeTypeModel(Utils::transform(Utils::allMimeTypes(),
|
||||
&Utils::MimeType::name), this);
|
||||
m_mimeTypeModel->m_selectedMimeTypes = selectedMimeTypes;
|
||||
proxy->setSourceModel(m_mimeTypeModel);
|
||||
connect(filter, &QLineEdit::textChanged, proxy, &QSortFilterProxyModel::setFilterWildcard);
|
||||
listView->setModel(proxy);
|
||||
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setModal(true);
|
||||
}
|
||||
|
||||
MimeTypeDialog(const MimeTypeDialog &other) = delete;
|
||||
MimeTypeDialog(MimeTypeDialog &&other) = delete;
|
||||
|
||||
MimeTypeDialog operator=(const MimeTypeDialog &other) = delete;
|
||||
MimeTypeDialog operator=(MimeTypeDialog &&other) = delete;
|
||||
|
||||
|
||||
QStringList mimeTypes() const
|
||||
{
|
||||
return m_mimeTypeModel->m_selectedMimeTypes;
|
||||
}
|
||||
private:
|
||||
MimeTypeModel *m_mimeTypeModel = nullptr;
|
||||
};
|
||||
|
||||
void BaseSettingsWidget::showAddMimeTypeDialog()
|
||||
{
|
||||
MimeTypeDialog dialog(m_mimeTypes->text().split(filterSeparator, QString::SkipEmptyParts),
|
||||
Core::ICore::dialogParent());
|
||||
if (dialog.exec() == QDialog::Rejected)
|
||||
return;
|
||||
m_mimeTypes->setText(dialog.mimeTypes().join(filterSeparator));
|
||||
}
|
||||
|
||||
StdIOSettingsWidget::StdIOSettingsWidget(const StdIOSettings *settings, QWidget *parent)
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include <coreplugin/dialogs/ioptionspage.h>
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QLabel>
|
||||
#include <QPointer>
|
||||
#include <QWidget>
|
||||
|
||||
@@ -44,21 +45,27 @@ constexpr char noLanguageFilter[] = "No Filter";
|
||||
|
||||
class BaseClient;
|
||||
|
||||
struct LanguageFilter
|
||||
{
|
||||
QStringList mimeTypes;
|
||||
QStringList filePattern;
|
||||
};
|
||||
|
||||
class BaseSettings
|
||||
{
|
||||
public:
|
||||
BaseSettings() = default;
|
||||
BaseSettings(const QString &name, bool enabled, const QString &mimeTypeName)
|
||||
BaseSettings(const QString &name, bool enabled, const LanguageFilter &filter)
|
||||
: m_name(name)
|
||||
, m_enabled(enabled)
|
||||
, m_mimeType(mimeTypeName)
|
||||
, m_languageFilter(filter)
|
||||
{}
|
||||
|
||||
virtual ~BaseSettings() = default;
|
||||
|
||||
QString m_name = QString("New Language Server");
|
||||
bool m_enabled = true;
|
||||
QString m_mimeType = QLatin1String(noLanguageFilter);
|
||||
LanguageFilter m_languageFilter;
|
||||
QPointer<BaseClient> m_client; // not owned
|
||||
|
||||
virtual void applyFromSettingsWidget(QWidget *widget);
|
||||
@@ -81,9 +88,9 @@ class StdIOSettings : public BaseSettings
|
||||
{
|
||||
public:
|
||||
StdIOSettings() = default;
|
||||
StdIOSettings(const QString &name, bool enabled, const QString &mimeTypeName,
|
||||
StdIOSettings(const QString &name, bool enabled, const LanguageFilter &filter,
|
||||
const QString &executable, const QString &arguments)
|
||||
: BaseSettings(name, enabled, mimeTypeName)
|
||||
: BaseSettings(name, enabled, filter)
|
||||
, m_executable(executable)
|
||||
, m_arguments(arguments)
|
||||
{}
|
||||
@@ -125,11 +132,16 @@ public:
|
||||
~BaseSettingsWidget() = default;
|
||||
|
||||
QString name() const;
|
||||
QString mimeType() const;
|
||||
LanguageFilter filter() const;
|
||||
|
||||
private:
|
||||
void showAddMimeTypeDialog();
|
||||
|
||||
QLineEdit *m_name = nullptr;
|
||||
QLineEdit *m_mimeType = nullptr;
|
||||
QLabel *m_mimeTypes = nullptr;
|
||||
QLineEdit *m_filePattern = nullptr;
|
||||
|
||||
static constexpr char filterSeparator = ';';
|
||||
};
|
||||
|
||||
class StdIOSettingsWidget : public BaseSettingsWidget
|
||||
|
Reference in New Issue
Block a user