diff --git a/src/libs/utils/completinglineedit.cpp b/src/libs/utils/completinglineedit.cpp index 4711ee8e721..1e4152ad087 100644 --- a/src/libs/utils/completinglineedit.cpp +++ b/src/libs/utils/completinglineedit.cpp @@ -58,8 +58,10 @@ void CompletingLineEdit::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Down && !e->modifiers()) { if (QCompleter *comp = completer()) { - if (!comp->popup()->isVisible()) + if (!comp->popup()->isVisible()) { comp->complete(); + return; + } } } QLineEdit::keyPressEvent(e); diff --git a/src/libs/utils/delegates.cpp b/src/libs/utils/delegates.cpp index 6b6ab7279ef..a677c8c9923 100644 --- a/src/libs/utils/delegates.cpp +++ b/src/libs/utils/delegates.cpp @@ -24,9 +24,11 @@ ****************************************************************************/ #include "delegates.h" +#include "completinglineedit.h" #include #include +#include using namespace Utils; @@ -174,3 +176,60 @@ void PathChooserDelegate::setHistoryCompleter(const QString &key) { m_historyKey = key; } + +CompleterDelegate::CompleterDelegate(const QStringList &candidates, QObject *parent) + : CompleterDelegate(new QCompleter(candidates, parent)) +{ } + +CompleterDelegate::CompleterDelegate(QAbstractItemModel *model, QObject *parent) + : CompleterDelegate(new QCompleter(model, parent)) +{ } + +CompleterDelegate::CompleterDelegate(QCompleter *completer, QObject *parent) + : QStyledItemDelegate(parent) + , m_completer(completer) +{ } + +CompleterDelegate::~CompleterDelegate() +{ + if (m_completer) + delete m_completer; +} + +QWidget *CompleterDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + Q_UNUSED(option); + Q_UNUSED(index); + + auto edit = new CompletingLineEdit(parent); + + edit->setCompleter(m_completer); + + return edit; +} + +void CompleterDelegate::setEditorData(QWidget *editor, + const QModelIndex &index) const +{ + if (auto *edit = qobject_cast(editor)) + edit->setText(index.model()->data(index, Qt::EditRole).toString()); +} + +void CompleterDelegate::setModelData(QWidget *editor, + QAbstractItemModel *model, + const QModelIndex &index) const +{ + if (auto edit = qobject_cast(editor)) + model->setData(index, edit->text(), Qt::EditRole); +} + +void CompleterDelegate::updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + Q_UNUSED(index); + + editor->setGeometry(option.rect); +} diff --git a/src/libs/utils/delegates.h b/src/libs/utils/delegates.h index cb9809a36f4..eb9819fc7ab 100644 --- a/src/libs/utils/delegates.h +++ b/src/libs/utils/delegates.h @@ -81,4 +81,30 @@ private: QString m_historyKey; }; +class QTCREATOR_UTILS_EXPORT CompleterDelegate : public QStyledItemDelegate +{ +public: + CompleterDelegate(const QStringList &candidates, QObject *parent = nullptr); + CompleterDelegate(QAbstractItemModel *model, QObject *parent = nullptr); + CompleterDelegate(QCompleter *completer, QObject *parent = nullptr); + ~CompleterDelegate() override; + + CompleterDelegate(const CompleterDelegate &other) = delete; + CompleterDelegate(CompleterDelegate &&other) = delete; + + CompleterDelegate &operator=(const CompleterDelegate &other) = delete; + CompleterDelegate &operator=(CompleterDelegate &&other) = delete; + + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + void setEditorData(QWidget *editor, const QModelIndex &index) const override; + void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const override; + void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const + QModelIndex &index) const override; + +private: + QCompleter *m_completer = nullptr; +}; + } // Utils diff --git a/src/plugins/languageclient/baseclient.cpp b/src/plugins/languageclient/baseclient.cpp index 3bac57b2b2d..3c5569266cb 100644 --- a/src/plugins/languageclient/baseclient.cpp +++ b/src/plugins/languageclient/baseclient.cpp @@ -114,8 +114,7 @@ BaseClient::State BaseClient::state() const void BaseClient::openDocument(Core::IDocument *document) { using namespace TextEditor; - const QString languageId = TextDocumentItem::mimeTypeToLanguageId(document->mimeType()); - if (!isSupportedLanguage(languageId)) + if (!isSupportedMimeType(document->mimeType())) return; const FileName &filePath = document->filePath(); const QString method(DidOpenTextDocumentNotification::methodName); @@ -137,7 +136,7 @@ void BaseClient::openDocument(Core::IDocument *document) } auto textDocument = qobject_cast(document); TextDocumentItem item; - item.setLanguageId(languageId); + item.setLanguageId(TextDocumentItem::mimeTypeToLanguageId(document->mimeType())); item.setUri(DocumentUri::fromFileName(filePath)); item.setText(QString::fromUtf8(document->contents())); item.setVersion(textDocument ? textDocument->document()->revision() : 0); @@ -483,14 +482,14 @@ void BaseClient::projectClosed(ProjectExplorer::Project *project) sendContent(change); } -void BaseClient::setSupportedLanguages(const QStringList &supportedLanguages) +void BaseClient::setSupportedMimeType(const QStringList &supportedMimeTypes) { - m_supportedLanguageIds = supportedLanguages; + m_supportedMimeTypes = supportedMimeTypes; } -bool BaseClient::isSupportedLanguage(const QString &language) const +bool BaseClient::isSupportedMimeType(const QString &mimeType) const { - return m_supportedLanguageIds.isEmpty() || m_supportedLanguageIds.contains(language); + return m_supportedMimeTypes.isEmpty() || m_supportedMimeTypes.contains(mimeType); } void BaseClient::reset() diff --git a/src/plugins/languageclient/baseclient.h b/src/plugins/languageclient/baseclient.h index 211b4b7a157..e0626bd7c78 100644 --- a/src/plugins/languageclient/baseclient.h +++ b/src/plugins/languageclient/baseclient.h @@ -104,8 +104,8 @@ public: const LanguageServerProtocol::IContent &content); void cancelRequest(const LanguageServerProtocol::MessageId &id); - void setSupportedLanguages(const QStringList &supportedLanguages); - bool isSupportedLanguage(const QString &language) const; + void setSupportedMimeType(const QStringList &supportedMimeTypes); + bool isSupportedMimeType(const QString &mimeType) const; void setName(const QString &name) { m_displayName = name; } QString name() const { return m_displayName; } @@ -149,7 +149,7 @@ private: QHash m_contentHandler; QBuffer m_buffer; QString m_displayName; - QStringList m_supportedLanguageIds; + QStringList m_supportedMimeTypes; QList m_openedDocument; Core::Id m_id; LanguageServerProtocol::ServerCapabilities m_serverCapabilities; diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index e1470edf05a..f2ee17ffc2a 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -30,10 +30,12 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -44,7 +46,7 @@ constexpr char nameKey[] = "name"; constexpr char enabledKey[] = "enabled"; -constexpr char languageKey[] = "language"; +constexpr char mimeTypeKey[] = "mimeType"; constexpr char executableKey[] = "executable"; constexpr char argumentsKey[] = "arguments"; constexpr char settingsGroupKey[] = "LanguageClient"; @@ -75,7 +77,7 @@ public: enum Columns { DisplayNameColumn = 0, EnabledColumn, - LanguageColumn, + MimeTypeColumn, ExecutableColumn, ArgumentsColumn, ColumnCount @@ -152,7 +154,14 @@ LanguageClientSettingsPageWidget::LanguageClientSettingsPageWidget(LanguageClien m_view->header()->setStretchLastSection(true); m_view->setRootIsDecorated(false); m_view->setItemsExpandable(false); - m_view->setItemDelegateForColumn(LanguageClientSettingsModel::LanguageColumn, new LanguageChooseDelegate()); + 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_view->setItemDelegateForColumn(LanguageClientSettingsModel::MimeTypeColumn, + new Utils::CompleterDelegate(mimeTypeCompleter)); auto executableDelegate = new Utils::PathChooserDelegate(); executableDelegate->setExpectedKind(Utils::PathChooser::File); executableDelegate->setHistoryCompleter("LanguageClient.ServerPathHistory"); @@ -232,7 +241,7 @@ QVariant LanguageClientSettingsModel::data(const QModelIndex &index, int role) c if (role == Qt::DisplayRole || role == Qt::EditRole) { switch (index.column()) { case DisplayNameColumn: return setting.m_name; - case LanguageColumn: return setting.m_language; + case MimeTypeColumn: return setting.m_mimeType; case ExecutableColumn: return setting.m_executable; case ArgumentsColumn: return setting.m_arguments.join(' '); } @@ -250,7 +259,7 @@ QVariant LanguageClientSettingsModel::headerData(int section, Qt::Orientation or switch (section) { case DisplayNameColumn: return tr("Name"); case EnabledColumn: return tr("Enabled"); - case LanguageColumn: return tr("Language"); + case MimeTypeColumn: return tr("Mime Type"); case ExecutableColumn: return tr("Executable"); case ArgumentsColumn: return tr("Arguments"); } @@ -288,7 +297,7 @@ bool LanguageClientSettingsModel::setData(const QModelIndex &index, const QVaria if (role == Qt::DisplayRole || role == Qt::EditRole) { switch (index.column()) { case DisplayNameColumn: setting.m_name = value.toString(); break; - case LanguageColumn: setting.m_language = value.toString(); break; + case MimeTypeColumn: setting.m_mimeType = value.toString(); break; case ExecutableColumn: setting.m_executable = value.toString(); break; case ArgumentsColumn: setting.m_arguments = value.toString().split(' '); break; default: @@ -346,8 +355,8 @@ void LanguageClientSettingsModel::applyChanges() }); if (setting.isValid() && setting.m_enabled) { toStart.removeAll(setting); - if (!interface->isSupportedLanguage(setting.m_language)) - interface->setSupportedLanguages({setting.m_language}); + if (!interface->isSupportedMimeType(setting.m_mimeType)) + interface->setSupportedMimeType({setting.m_mimeType}); } else { toShutdown << interface; } @@ -358,8 +367,8 @@ void LanguageClientSettingsModel::applyChanges() if (setting.isValid() && setting.m_enabled) { auto client = new StdIOClient(setting.m_executable, setting.m_arguments); client->setName(setting.m_name); - if (setting.m_language != noLanguageFilter) - client->setSupportedLanguages({setting.m_language}); + if (setting.m_mimeType != noLanguageFilter) + client->setSupportedMimeType({setting.m_mimeType}); LanguageClientManager::startClient(client); } } @@ -374,7 +383,7 @@ bool LanguageClientSettings::operator==(const LanguageClientSettings &other) con { return m_name == other.m_name && m_enabled == other.m_enabled - && m_language == other.m_language + && m_mimeType == other.m_mimeType && m_executable == other.m_executable && m_arguments == other.m_arguments; } @@ -384,7 +393,7 @@ QVariantMap LanguageClientSettings::toMap() const QVariantMap map; map.insert(nameKey, m_name); map.insert(enabledKey, m_enabled); - map.insert(languageKey, m_language); + map.insert(mimeTypeKey, m_mimeType); map.insert(executableKey, m_executable); map.insert(argumentsKey, m_arguments); return map; @@ -394,7 +403,7 @@ LanguageClientSettings LanguageClientSettings::fromMap(const QVariantMap &map) { return { map[nameKey].toString(), map[enabledKey].toBool(), - map[languageKey].toString(), + map[mimeTypeKey].toString(), map[executableKey].toString(), map[argumentsKey].toStringList() }; } diff --git a/src/plugins/languageclient/languageclientsettings.h b/src/plugins/languageclient/languageclientsettings.h index d06481e7632..cefcd0f2c7c 100644 --- a/src/plugins/languageclient/languageclientsettings.h +++ b/src/plugins/languageclient/languageclientsettings.h @@ -39,17 +39,17 @@ class LanguageClientSettings { public: LanguageClientSettings() = default; - LanguageClientSettings(const QString &name, bool enabled, const QString &language, + LanguageClientSettings(const QString &name, bool enabled, const QString &mimeTypeName, const QString &executable, const QStringList &arguments) : m_name(name) , m_enabled(enabled) - , m_language(language) + , m_mimeType(mimeTypeName) , m_executable(executable) , m_arguments(arguments) {} QString m_name = QString("New Language Server"); bool m_enabled = true; - QString m_language = QLatin1String(noLanguageFilter); + QString m_mimeType = QLatin1String(noLanguageFilter); QString m_executable; QStringList m_arguments;