LanguageClient: also check for inherited mime types

... when trying to auto setup language servers as well when matching the
configured mime types against a document mime type.
In particular this fixes showing the auto setup editor info bar for the
newly introduced clang format mime type as well as starting the yaml
server for those files, since this clang format mime type inherits the
yaml mime type.

Change-Id: Id3ec64b0a1a128b070eadbcad600b3aaf4e667c3
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Reviewed-by: Artem Sokolovskii <artem.sokolovskii@qt.io>
This commit is contained in:
David Schulz
2024-01-05 09:01:25 +01:00
parent 6adb82eabc
commit 2e96194681
3 changed files with 79 additions and 36 deletions

View File

@@ -537,6 +537,41 @@ void LanguageClientManager::editorOpened(Core::IEditor *editor)
} }
} }
static QList<BaseSettings *> sortedSettingsForDocument(Core::IDocument *document)
{
const QList<BaseSettings *> prefilteredSettings
= Utils::filtered(LanguageClientManager::currentSettings(), [](BaseSettings *setting) {
return setting->isValid() && setting->m_enabled;
});
const Utils::MimeType mimeType = Utils::mimeTypeForName(document->mimeType());
if (mimeType.isValid()) {
QList<BaseSettings *> result;
// prefer exact mime type matches
result << Utils::filtered(prefilteredSettings, [mimeType](BaseSettings *setting) {
return setting->m_languageFilter.mimeTypes.contains(mimeType.name());
});
// add filePath matches next
result << Utils::filtered(prefilteredSettings, [document](BaseSettings *setting) {
return setting->m_languageFilter.isSupported(document->filePath(), {});
});
// add parent mime type matches last
Utils::visitMimeParents(mimeType, [&](const Utils::MimeType &mt) -> bool {
result << Utils::filtered(prefilteredSettings, [mt](BaseSettings *setting) {
return setting->m_languageFilter.mimeTypes.contains(mt.name());
});
return true; // continue
});
return result;
}
return Utils::filtered(prefilteredSettings, [document](BaseSettings *setting) {
return setting->m_languageFilter.isSupported(document);
});
}
void LanguageClientManager::documentOpened(Core::IDocument *document) void LanguageClientManager::documentOpened(Core::IDocument *document)
{ {
auto textDocument = qobject_cast<TextEditor::TextDocument *>(document); auto textDocument = qobject_cast<TextEditor::TextDocument *>(document);
@@ -544,40 +579,39 @@ void LanguageClientManager::documentOpened(Core::IDocument *document)
return; return;
// check whether we have to start servers for this document // check whether we have to start servers for this document
const QList<BaseSettings *> settings = currentSettings(); const QList<BaseSettings *> settings = sortedSettingsForDocument(document);
QList<Client *> allClients;
for (BaseSettings *setting : settings) { for (BaseSettings *setting : settings) {
if (setting->isValid() && setting->m_enabled QList<Client *> clients = clientsForSetting(setting);
&& setting->m_languageFilter.isSupported(document)) { if (setting->m_startBehavior == BaseSettings::RequiresProject) {
QList<Client *> clients = clientsForSetting(setting); const Utils::FilePath &filePath = document->filePath();
if (setting->m_startBehavior == BaseSettings::RequiresProject) { for (ProjectExplorer::Project *project : ProjectExplorer::ProjectManager::projects()) {
const Utils::FilePath &filePath = document->filePath(); // check whether file is part of this project
for (ProjectExplorer::Project *project : if (!project->isKnownFile(filePath))
ProjectExplorer::ProjectManager::projects()) { continue;
// check whether file is part of this project
if (!project->isKnownFile(filePath))
continue;
// check whether we already have a client running for this project // check whether we already have a client running for this project
Client *clientForProject = Utils::findOrDefault(clients, Client *clientForProject
[project](Client *client) { = Utils::findOrDefault(clients, Utils::equal(&Client::project, project));
return client->project() if (!clientForProject)
== project; clientForProject = startClient(setting, project);
});
if (!clientForProject)
clientForProject = startClient(setting, project);
QTC_ASSERT(clientForProject, continue); QTC_ASSERT(clientForProject, continue);
openDocumentWithClient(textDocument, clientForProject); openDocumentWithClient(textDocument, clientForProject);
// Since we already opened the document in this client we remove the client // Since we already opened the document in this client we remove the client
// from the list of clients that receive the openDocument call // from the list of clients that receive the openDocument call
clients.removeAll(clientForProject); clients.removeAll(clientForProject);
}
} else if (setting->m_startBehavior == BaseSettings::RequiresFile && clients.isEmpty()) {
clients << startClient(setting);
} }
for (auto client : std::as_const(clients)) } else if (setting->m_startBehavior == BaseSettings::RequiresFile && clients.isEmpty()) {
client->openDocument(textDocument); clients << startClient(setting);
} }
allClients << clients;
}
for (auto client : std::as_const(allClients)) {
if (m_clientForDocument[textDocument])
client->openDocument(textDocument);
else
openDocumentWithClient(textDocument, client);
} }
} }

View File

@@ -996,10 +996,16 @@ QString StdIOSettingsWidget::arguments() const
return m_arguments->text(); return m_arguments->text();
} }
bool LanguageFilter::isSupported(const Utils::FilePath &filePath, const QString &mimeType) const bool LanguageFilter::isSupported(const Utils::FilePath &filePath, const QString &mimeTypeName) const
{ {
if (mimeTypes.contains(mimeType)) if (!mimeTypes.isEmpty()) {
return true; const MimeType mimeType = Utils::mimeTypeForName(mimeTypeName);
if (Utils::anyOf(mimeTypes, [mimeType](const QString &supported) {
return mimeType.inherits(supported);
})) {
return true;
}
}
if (filePattern.isEmpty() && filePath.isEmpty()) if (filePattern.isEmpty() && filePath.isEmpty())
return mimeTypes.isEmpty(); return mimeTypes.isEmpty();
const QRegularExpression::PatternOptions options const QRegularExpression::PatternOptions options

View File

@@ -470,11 +470,14 @@ private:
QTimer m_killTimer; QTimer m_killTimer;
}; };
constexpr QLatin1StringView YAML_MIME_TYPE{"application/x-yaml"};
constexpr QLatin1StringView JSON_MIME_TYPE{"application/json"};
void autoSetupLanguageServer(TextDocument *document) void autoSetupLanguageServer(TextDocument *document)
{ {
const QString mimeType = document->mimeType(); const auto mimeType = Utils::mimeTypeForName(document->mimeType());
if (mimeType == "application/x-yaml" || mimeType == "application/json") { const bool isYaml = mimeType.inherits(YAML_MIME_TYPE);
const bool isYaml = mimeType == "application/x-yaml"; if (isYaml || mimeType.inherits(JSON_MIME_TYPE)) {
// check whether the user suppressed the info bar // check whether the user suppressed the info bar
const Id infoBarId = isYaml ? installYamlLsInfoBarId : installJsonLsInfoBarId; const Id infoBarId = isYaml ? installYamlLsInfoBarId : installJsonLsInfoBarId;
@@ -531,7 +534,7 @@ void autoSetupLanguageServer(TextDocument *document)
settings->m_executable = executable; settings->m_executable = executable;
settings->m_arguments = "--stdio"; settings->m_arguments = "--stdio";
settings->m_name = Tr::tr("%1 Language Server").arg(language); settings->m_name = Tr::tr("%1 Language Server").arg(language);
settings->m_languageFilter.mimeTypes = {mimeType}; settings->m_languageFilter.mimeTypes = {isYaml ? YAML_MIME_TYPE : JSON_MIME_TYPE};
LanguageClientSettings::addSettings(settings); LanguageClientSettings::addSettings(settings);
LanguageClientManager::applySettings(); LanguageClientManager::applySettings();