| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | /****************************************************************************
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Copyright (C) 2018 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.
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ****************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | #include "client.h"
 | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 08:46:23 +01:00
										 |  |  | #include "languageclientinterface.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | #include "languageclientmanager.h"
 | 
					
						
							| 
									
										
										
										
											2019-01-31 08:46:23 +01:00
										 |  |  | #include "languageclientutils.h"
 | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  | #include "semantichighlightsupport.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <coreplugin/icore.h>
 | 
					
						
							|  |  |  | #include <coreplugin/idocument.h>
 | 
					
						
							|  |  |  | #include <coreplugin/messagemanager.h>
 | 
					
						
							|  |  |  | #include <languageserverprotocol/diagnostics.h>
 | 
					
						
							|  |  |  | #include <languageserverprotocol/languagefeatures.h>
 | 
					
						
							|  |  |  | #include <languageserverprotocol/messages.h>
 | 
					
						
							|  |  |  | #include <languageserverprotocol/workspace.h>
 | 
					
						
							| 
									
										
										
										
											2019-05-16 11:09:55 +02:00
										 |  |  | #include <projectexplorer/project.h>
 | 
					
						
							|  |  |  | #include <projectexplorer/session.h>
 | 
					
						
							|  |  |  | #include <texteditor/codeassist/documentcontentcompletion.h>
 | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  | #include <texteditor/syntaxhighlighter.h>
 | 
					
						
							| 
									
										
										
										
											2020-01-08 12:03:54 +01:00
										 |  |  | #include <texteditor/tabsettings.h>
 | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | #include <texteditor/textdocument.h>
 | 
					
						
							|  |  |  | #include <texteditor/texteditor.h>
 | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  | #include <texteditor/texteditorsettings.h>
 | 
					
						
							| 
									
										
										
										
											2019-02-01 14:08:02 +01:00
										 |  |  | #include <texteditor/textmark.h>
 | 
					
						
							| 
									
										
										
										
											2019-07-16 12:29:20 +02:00
										 |  |  | #include <texteditor/ioutlinewidget.h>
 | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | #include <utils/mimetypes/mimedatabase.h>
 | 
					
						
							| 
									
										
										
										
											2018-09-10 15:15:37 +02:00
										 |  |  | #include <utils/qtcprocess.h>
 | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | #include <utils/synchronousprocess.h>
 | 
					
						
							| 
									
										
										
										
											2019-02-01 14:08:02 +01:00
										 |  |  | #include <utils/utilsicons.h>
 | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <QDebug>
 | 
					
						
							|  |  |  | #include <QLoggingCategory>
 | 
					
						
							|  |  |  | #include <QMessageBox>
 | 
					
						
							|  |  |  | #include <QPointer>
 | 
					
						
							| 
									
										
										
										
											2018-09-12 10:24:02 +02:00
										 |  |  | #include <QPushButton>
 | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | #include <QTextBlock>
 | 
					
						
							|  |  |  | #include <QTextCursor>
 | 
					
						
							|  |  |  | #include <QTextDocument>
 | 
					
						
							| 
									
										
										
										
											2018-09-19 09:36:32 +02:00
										 |  |  | #include <QTimer>
 | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | using namespace LanguageServerProtocol; | 
					
						
							|  |  |  | using namespace Utils; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace LanguageClient { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 09:33:30 +03:00
										 |  |  | static Q_LOGGING_CATEGORY(LOGLSPCLIENT, "qtc.languageclient.client", QtWarningMsg); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-01 14:08:02 +01:00
										 |  |  | class TextMark : public TextEditor::TextMark | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2019-10-15 13:48:34 +02:00
										 |  |  |     TextMark(const Utils::FilePath &fileName, const Diagnostic &diag, const Core::Id &clientId) | 
					
						
							|  |  |  |         : TextEditor::TextMark(fileName, diag.range().start().line() + 1, clientId) | 
					
						
							| 
									
										
										
										
											2019-01-29 13:20:58 +01:00
										 |  |  |         , m_diagnostic(diag) | 
					
						
							| 
									
										
										
										
											2019-02-01 14:08:02 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         using namespace Utils; | 
					
						
							|  |  |  |         setLineAnnotation(diag.message()); | 
					
						
							|  |  |  |         setToolTip(diag.message()); | 
					
						
							|  |  |  |         const bool isError | 
					
						
							|  |  |  |             = diag.severity().value_or(DiagnosticSeverity::Hint) == DiagnosticSeverity::Error; | 
					
						
							|  |  |  |         setColor(isError ? Theme::CodeModel_Error_TextMarkColor | 
					
						
							|  |  |  |                          : Theme::CodeModel_Warning_TextMarkColor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         setIcon(isError ? Icons::CODEMODEL_ERROR.icon() | 
					
						
							|  |  |  |                         : Icons::CODEMODEL_WARNING.icon()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-01-29 13:20:58 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const Diagnostic &diagnostic() const { return m_diagnostic; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     const Diagnostic m_diagnostic; | 
					
						
							| 
									
										
										
										
											2019-02-01 14:08:02 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | Client::Client(BaseClientInterface *clientInterface) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     : m_id(Core::Id::fromString(QUuid::createUuid().toString())) | 
					
						
							| 
									
										
										
										
											2019-01-31 08:46:23 +01:00
										 |  |  |     , m_clientInterface(clientInterface) | 
					
						
							| 
									
										
										
										
											2019-04-04 14:36:28 +02:00
										 |  |  |     , m_documentSymbolCache(this) | 
					
						
							| 
									
										
										
										
											2019-05-15 11:19:31 +02:00
										 |  |  |     , m_hoverHandler(this) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:36 +02:00
										 |  |  |     m_clientProviders.completionAssistProvider = new LanguageClientCompletionAssistProvider(this); | 
					
						
							|  |  |  |     m_clientProviders.functionHintProvider = new FunctionHintAssistProvider(this); | 
					
						
							|  |  |  |     m_clientProviders.quickFixAssistProvider = new LanguageClientQuickFixProvider(this); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     m_contentHandler.insert(JsonRpcMessageHandler::jsonRpcMimeType(), | 
					
						
							|  |  |  |                             &JsonRpcMessageHandler::parseContent); | 
					
						
							| 
									
										
										
										
											2019-01-31 08:46:23 +01:00
										 |  |  |     QTC_ASSERT(clientInterface, return); | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  |     connect(clientInterface, &BaseClientInterface::messageReceived, this, &Client::handleMessage); | 
					
						
							|  |  |  |     connect(clientInterface, &BaseClientInterface::error, this, &Client::setError); | 
					
						
							|  |  |  |     connect(clientInterface, &BaseClientInterface::finished, this, &Client::finished); | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  |     connect(TextEditor::TextEditorSettings::instance(), | 
					
						
							|  |  |  |             &TextEditor::TextEditorSettings::fontSettingsChanged, | 
					
						
							|  |  |  |             this, | 
					
						
							|  |  |  |             &Client::rehighlight); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-11 14:31:20 +02:00
										 |  |  | static void updateEditorToolBar(QList<TextEditor::TextDocument *> documents) | 
					
						
							| 
									
										
										
										
											2019-03-26 13:48:06 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-09-11 14:31:20 +02:00
										 |  |  |     for (TextEditor::TextDocument *document : documents) { | 
					
						
							|  |  |  |         for (Core::IEditor *editor : Core::DocumentModel::editorsForDocument(document)) | 
					
						
							|  |  |  |             updateEditorToolBar(editor); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-03-26 13:48:06 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | Client::~Client() | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  |     using namespace TextEditor; | 
					
						
							| 
									
										
										
										
											2018-10-16 07:00:48 +02:00
										 |  |  |     // FIXME: instead of replacing the completion provider in the text document store the
 | 
					
						
							|  |  |  |     // completion provider as a prioritised list in the text document
 | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:36 +02:00
										 |  |  |     for (TextDocument *document : m_resetAssistProvider.keys()) | 
					
						
							|  |  |  |         resetAssistProviders(document); | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  |     for (Core::IEditor * editor : Core::DocumentModel::editorsForOpenedDocuments()) { | 
					
						
							|  |  |  |         if (auto textEditor = qobject_cast<BaseTextEditor *>(editor)) { | 
					
						
							|  |  |  |             TextEditorWidget *widget = textEditor->editorWidget(); | 
					
						
							|  |  |  |             widget->setRefactorMarkers(RefactorMarker::filterOutType(widget->refactorMarkers(), id())); | 
					
						
							| 
									
										
										
										
											2019-05-15 11:19:31 +02:00
										 |  |  |             widget->removeHoverHandler(&m_hoverHandler); | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-01 14:08:02 +01:00
										 |  |  |     for (const DocumentUri &uri : m_diagnostics.keys()) | 
					
						
							|  |  |  |         removeDiagnostics(uri); | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  |     for (const DocumentUri &uri : m_highlights.keys()) { | 
					
						
							| 
									
										
										
										
											2019-10-01 09:11:02 +02:00
										 |  |  |         if (TextDocument *doc = TextDocument::textDocumentForFilePath(uri.toFilePath())) { | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  |             if (TextEditor::SyntaxHighlighter *highlighter = doc->syntaxHighlighter()) | 
					
						
							|  |  |  |                 highlighter->clearAllExtraFormats(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-02 10:49:23 +02:00
										 |  |  |     updateEditorToolBar(m_openedDocument.keys()); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-15 14:53:36 +01:00
										 |  |  | static ClientCapabilities generateClientCapabilities() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ClientCapabilities capabilities; | 
					
						
							|  |  |  |     WorkspaceClientCapabilities workspaceCapabilities; | 
					
						
							|  |  |  |     workspaceCapabilities.setWorkspaceFolders(true); | 
					
						
							|  |  |  |     workspaceCapabilities.setApplyEdit(true); | 
					
						
							|  |  |  |     DynamicRegistrationCapabilities allowDynamicRegistration; | 
					
						
							|  |  |  |     allowDynamicRegistration.setDynamicRegistration(true); | 
					
						
							|  |  |  |     workspaceCapabilities.setDidChangeConfiguration(allowDynamicRegistration); | 
					
						
							|  |  |  |     workspaceCapabilities.setExecuteCommand(allowDynamicRegistration); | 
					
						
							|  |  |  |     capabilities.setWorkspace(workspaceCapabilities); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TextDocumentClientCapabilities documentCapabilities; | 
					
						
							|  |  |  |     TextDocumentClientCapabilities::SynchronizationCapabilities syncCapabilities; | 
					
						
							|  |  |  |     syncCapabilities.setDynamicRegistration(true); | 
					
						
							|  |  |  |     syncCapabilities.setWillSave(true); | 
					
						
							|  |  |  |     syncCapabilities.setWillSaveWaitUntil(false); | 
					
						
							|  |  |  |     syncCapabilities.setDidSave(true); | 
					
						
							|  |  |  |     documentCapabilities.setSynchronization(syncCapabilities); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SymbolCapabilities symbolCapabilities; | 
					
						
							|  |  |  |     SymbolCapabilities::SymbolKindCapabilities symbolKindCapabilities; | 
					
						
							|  |  |  |     symbolKindCapabilities.setValueSet( | 
					
						
							|  |  |  |         {SymbolKind::File,       SymbolKind::Module,       SymbolKind::Namespace, | 
					
						
							|  |  |  |          SymbolKind::Package,    SymbolKind::Class,        SymbolKind::Method, | 
					
						
							|  |  |  |          SymbolKind::Property,   SymbolKind::Field,        SymbolKind::Constructor, | 
					
						
							|  |  |  |          SymbolKind::Enum,       SymbolKind::Interface,    SymbolKind::Function, | 
					
						
							|  |  |  |          SymbolKind::Variable,   SymbolKind::Constant,     SymbolKind::String, | 
					
						
							|  |  |  |          SymbolKind::Number,     SymbolKind::Boolean,      SymbolKind::Array, | 
					
						
							|  |  |  |          SymbolKind::Object,     SymbolKind::Key,          SymbolKind::Null, | 
					
						
							|  |  |  |          SymbolKind::EnumMember, SymbolKind::Struct,       SymbolKind::Event, | 
					
						
							|  |  |  |          SymbolKind::Operator,   SymbolKind::TypeParameter}); | 
					
						
							|  |  |  |     symbolCapabilities.setSymbolKind(symbolKindCapabilities); | 
					
						
							|  |  |  |     documentCapabilities.setDocumentSymbol(symbolCapabilities); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  |     TextDocumentClientCapabilities::SemanticHighlightingCapabilities semanticHighlight; | 
					
						
							|  |  |  |     semanticHighlight.setSemanticHighlighting(true); | 
					
						
							|  |  |  |     documentCapabilities.setSemanticHighlightingCapabilities(semanticHighlight); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-15 14:53:36 +01:00
										 |  |  |     TextDocumentClientCapabilities::CompletionCapabilities completionCapabilities; | 
					
						
							|  |  |  |     completionCapabilities.setDynamicRegistration(true); | 
					
						
							|  |  |  |     TextDocumentClientCapabilities::CompletionCapabilities::CompletionItemKindCapabilities | 
					
						
							|  |  |  |         completionItemKindCapabilities; | 
					
						
							|  |  |  |     completionItemKindCapabilities.setValueSet( | 
					
						
							|  |  |  |         {CompletionItemKind::Text,         CompletionItemKind::Method, | 
					
						
							|  |  |  |          CompletionItemKind::Function,     CompletionItemKind::Constructor, | 
					
						
							|  |  |  |          CompletionItemKind::Field,        CompletionItemKind::Variable, | 
					
						
							|  |  |  |          CompletionItemKind::Class,        CompletionItemKind::Interface, | 
					
						
							|  |  |  |          CompletionItemKind::Module,       CompletionItemKind::Property, | 
					
						
							|  |  |  |          CompletionItemKind::Unit,         CompletionItemKind::Value, | 
					
						
							|  |  |  |          CompletionItemKind::Enum,         CompletionItemKind::Keyword, | 
					
						
							|  |  |  |          CompletionItemKind::Snippet,      CompletionItemKind::Color, | 
					
						
							|  |  |  |          CompletionItemKind::File,         CompletionItemKind::Reference, | 
					
						
							|  |  |  |          CompletionItemKind::Folder,       CompletionItemKind::EnumMember, | 
					
						
							|  |  |  |          CompletionItemKind::Constant,     CompletionItemKind::Struct, | 
					
						
							|  |  |  |          CompletionItemKind::Event,        CompletionItemKind::Operator, | 
					
						
							|  |  |  |          CompletionItemKind::TypeParameter}); | 
					
						
							|  |  |  |     completionCapabilities.setCompletionItemKind(completionItemKindCapabilities); | 
					
						
							| 
									
										
										
										
											2019-05-06 08:19:22 +02:00
										 |  |  |     TextDocumentClientCapabilities::CompletionCapabilities::CompletionItemCapbilities | 
					
						
							|  |  |  |         completionItemCapbilities; | 
					
						
							|  |  |  |     completionItemCapbilities.setSnippetSupport(false); | 
					
						
							| 
									
										
										
										
											2019-05-06 08:25:30 +02:00
										 |  |  |     completionItemCapbilities.setCommitCharacterSupport(true); | 
					
						
							| 
									
										
										
										
											2019-05-06 08:19:22 +02:00
										 |  |  |     completionCapabilities.setCompletionItem(completionItemCapbilities); | 
					
						
							| 
									
										
										
										
											2019-03-15 14:53:36 +01:00
										 |  |  |     documentCapabilities.setCompletion(completionCapabilities); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TextDocumentClientCapabilities::CodeActionCapabilities codeActionCapabilities; | 
					
						
							|  |  |  |     TextDocumentClientCapabilities::CodeActionCapabilities::CodeActionLiteralSupport literalSupport; | 
					
						
							|  |  |  |     literalSupport.setCodeActionKind( | 
					
						
							|  |  |  |         TextDocumentClientCapabilities::CodeActionCapabilities::CodeActionLiteralSupport:: | 
					
						
							|  |  |  |             CodeActionKind(QList<QString>{"*"})); | 
					
						
							|  |  |  |     codeActionCapabilities.setCodeActionLiteralSupport(literalSupport); | 
					
						
							|  |  |  |     documentCapabilities.setCodeAction(codeActionCapabilities); | 
					
						
							| 
									
										
										
										
											2019-05-15 11:19:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     TextDocumentClientCapabilities::HoverCapabilities hover; | 
					
						
							| 
									
										
										
										
											2019-11-04 17:14:25 +01:00
										 |  |  | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
 | 
					
						
							|  |  |  |     hover.setContentFormat({MarkupKind::markdown, MarkupKind::plaintext}); | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2019-05-15 11:19:31 +02:00
										 |  |  |     hover.setContentFormat({MarkupKind::plaintext}); | 
					
						
							| 
									
										
										
										
											2019-11-04 17:14:25 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-05-15 11:19:31 +02:00
										 |  |  |     hover.setDynamicRegistration(true); | 
					
						
							|  |  |  |     documentCapabilities.setHover(hover); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-26 09:29:55 +01:00
										 |  |  |     documentCapabilities.setReferences(allowDynamicRegistration); | 
					
						
							|  |  |  |     documentCapabilities.setDocumentHighlight(allowDynamicRegistration); | 
					
						
							|  |  |  |     documentCapabilities.setDefinition(allowDynamicRegistration); | 
					
						
							|  |  |  |     documentCapabilities.setTypeDefinition(allowDynamicRegistration); | 
					
						
							|  |  |  |     documentCapabilities.setImplementation(allowDynamicRegistration); | 
					
						
							| 
									
										
										
										
											2019-03-15 14:53:36 +01:00
										 |  |  |     capabilities.setTextDocument(documentCapabilities); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return capabilities; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::initialize() | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     using namespace ProjectExplorer; | 
					
						
							| 
									
										
										
										
											2019-01-31 08:46:23 +01:00
										 |  |  |     QTC_ASSERT(m_clientInterface, return); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     QTC_ASSERT(m_state == Uninitialized, return); | 
					
						
							|  |  |  |     qCDebug(LOGLSPCLIENT) << "initializing language server " << m_displayName; | 
					
						
							| 
									
										
										
										
											2020-02-20 10:11:35 +01:00
										 |  |  |     InitializeRequest initRequest; | 
					
						
							|  |  |  |     auto params = initRequest.params().value_or(InitializeParams()); | 
					
						
							| 
									
										
										
										
											2019-05-15 14:55:55 +02:00
										 |  |  |     params.setCapabilities(generateClientCapabilities()); | 
					
						
							| 
									
										
										
										
											2019-03-15 11:25:48 +01:00
										 |  |  |     if (m_project) { | 
					
						
							| 
									
										
										
										
											2019-09-11 14:34:20 +02:00
										 |  |  |         params.setRootUri(DocumentUri::fromFilePath(m_project->projectDirectory())); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |         params.setWorkSpaceFolders(Utils::transform(SessionManager::projects(), [](Project *pro){ | 
					
						
							|  |  |  |             return WorkSpaceFolder(pro->projectDirectory().toString(), pro->displayName()); | 
					
						
							|  |  |  |         })); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-02-20 10:11:35 +01:00
										 |  |  |     initRequest.setParams(params); | 
					
						
							|  |  |  |     initRequest.setResponseCallback([this](const InitializeRequest::Response &initResponse){ | 
					
						
							| 
									
										
										
										
											2019-09-18 14:26:08 +02:00
										 |  |  |         initializeCallback(initResponse); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  |     // directly send data otherwise the state check would fail;
 | 
					
						
							| 
									
										
										
										
											2020-02-20 10:11:35 +01:00
										 |  |  |     initRequest.registerResponseHandler(&m_responseHandlers); | 
					
						
							| 
									
										
										
										
											2020-02-20 10:13:14 +01:00
										 |  |  |     LanguageClientManager::logBaseMessage(LspLogMessage::ClientMessage, | 
					
						
							|  |  |  |                                           name(), | 
					
						
							|  |  |  |                                           initRequest.toBaseMessage()); | 
					
						
							| 
									
										
										
										
											2020-02-20 10:11:35 +01:00
										 |  |  |     m_clientInterface->sendMessage(initRequest.toBaseMessage()); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     m_state = InitializeRequested; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::shutdown() | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     QTC_ASSERT(m_state == Initialized, emit finished(); return); | 
					
						
							|  |  |  |     qCDebug(LOGLSPCLIENT) << "shutdown language server " << m_displayName; | 
					
						
							|  |  |  |     ShutdownRequest shutdown; | 
					
						
							| 
									
										
										
										
											2018-11-20 07:45:22 +01:00
										 |  |  |     shutdown.setResponseCallback([this](const ShutdownRequest::Response &shutdownResponse){ | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |         shutDownCallback(shutdownResponse); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     sendContent(shutdown); | 
					
						
							|  |  |  |     m_state = ShutdownRequested; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | Client::State Client::state() const | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     return m_state; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  | void Client::openDocument(TextEditor::TextDocument *document) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     using namespace TextEditor; | 
					
						
							| 
									
										
										
										
											2018-10-10 14:26:57 +02:00
										 |  |  |     if (!isSupportedDocument(document)) | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_openedDocument[document] = document->plainText(); | 
					
						
							|  |  |  |     if (m_state != Initialized) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-28 13:49:26 +02:00
										 |  |  |     const FilePath &filePath = document->filePath(); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     const QString method(DidOpenTextDocumentNotification::methodName); | 
					
						
							|  |  |  |     if (Utils::optional<bool> registered = m_dynamicCapabilities.isRegistered(method)) { | 
					
						
							|  |  |  |         if (!registered.value()) | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |             return; | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |         const TextDocumentRegistrationOptions option( | 
					
						
							| 
									
										
										
										
											2019-09-11 11:15:39 +02:00
										 |  |  |             m_dynamicCapabilities.option(method).toObject()); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |         if (option.isValid(nullptr) | 
					
						
							| 
									
										
										
										
											2019-09-11 11:15:39 +02:00
										 |  |  |             && !option.filterApplies(filePath, Utils::mimeTypeForName(document->mimeType()))) { | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |             return; | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } else if (Utils::optional<ServerCapabilities::TextDocumentSync> _sync | 
					
						
							|  |  |  |                = m_serverCapabilities.textDocumentSync()) { | 
					
						
							|  |  |  |         if (auto options = Utils::get_if<TextDocumentSyncOptions>(&_sync.value())) { | 
					
						
							|  |  |  |             if (!options->openClose().value_or(true)) | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |                 return; | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |     connect(document, &TextDocument::contentsChangedWithPosition, this, | 
					
						
							| 
									
										
										
										
											2019-09-11 11:15:39 +02:00
										 |  |  |             [this, document](int position, int charsRemoved, int charsAdded) { | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |         documentContentsChanged(document, position, charsRemoved, charsAdded); | 
					
						
							| 
									
										
										
										
											2019-09-11 11:15:39 +02:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     TextDocumentItem item; | 
					
						
							| 
									
										
										
										
											2018-09-05 13:38:08 +02:00
										 |  |  |     item.setLanguageId(TextDocumentItem::mimeTypeToLanguageId(document->mimeType())); | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |     item.setUri(DocumentUri::fromFilePath(filePath)); | 
					
						
							|  |  |  |     item.setText(document->plainText()); | 
					
						
							| 
									
										
										
										
											2019-09-11 11:15:39 +02:00
										 |  |  |     item.setVersion(document->document()->revision()); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     sendContent(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item))); | 
					
						
							| 
									
										
										
										
											2019-03-26 13:48:06 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |     if (LanguageClientManager::clientForDocument(document) == this) | 
					
						
							|  |  |  |         activateDocument(document); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::sendContent(const IContent &content) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-01-31 08:46:23 +01:00
										 |  |  |     QTC_ASSERT(m_clientInterface, return); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     QTC_ASSERT(m_state == Initialized, return); | 
					
						
							|  |  |  |     content.registerResponseHandler(&m_responseHandlers); | 
					
						
							|  |  |  |     QString error; | 
					
						
							|  |  |  |     if (!QTC_GUARD(content.isValid(&error))) | 
					
						
							|  |  |  |         Core::MessageManager::write(error); | 
					
						
							| 
									
										
										
										
											2020-02-20 10:13:14 +01:00
										 |  |  |     LanguageClientManager::logBaseMessage(LspLogMessage::ClientMessage, | 
					
						
							|  |  |  |                                           name(), | 
					
						
							|  |  |  |                                           content.toBaseMessage()); | 
					
						
							| 
									
										
										
										
											2019-01-31 08:46:23 +01:00
										 |  |  |     m_clientInterface->sendMessage(content.toBaseMessage()); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::sendContent(const DocumentUri &uri, const IContent &content) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-09-11 14:31:20 +02:00
										 |  |  |     if (!Utils::anyOf(m_openedDocument.keys(), [uri](TextEditor::TextDocument *documnent) { | 
					
						
							| 
									
										
										
										
											2019-09-11 14:34:20 +02:00
										 |  |  |             return uri.toFilePath() == documnent->filePath(); | 
					
						
							| 
									
										
										
										
											2019-09-11 14:31:20 +02:00
										 |  |  |         })) { | 
					
						
							|  |  |  |         sendContent(content); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::cancelRequest(const MessageId &id) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     m_responseHandlers.remove(id); | 
					
						
							|  |  |  |     sendContent(CancelRequest(CancelParameter(id))); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-11 11:15:39 +02:00
										 |  |  | void Client::closeDocument(TextEditor::TextDocument *document) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-01-08 12:03:54 +01:00
										 |  |  |     deactivateDocument(document); | 
					
						
							| 
									
										
										
										
											2019-09-11 14:34:20 +02:00
										 |  |  |     const DocumentUri &uri = DocumentUri::fromFilePath(document->filePath()); | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  |     m_highlights[uri].clear(); | 
					
						
							| 
									
										
										
										
											2020-02-17 13:40:11 +01:00
										 |  |  |     if (m_openedDocument.remove(document) != 0 && m_state == Initialized) { | 
					
						
							| 
									
										
										
										
											2020-01-08 12:03:54 +01:00
										 |  |  |         DidCloseTextDocumentParams params(TextDocumentIdentifier{uri}); | 
					
						
							|  |  |  |         sendContent(DidCloseTextDocumentNotification(params)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Client::activateDocument(TextEditor::TextDocument *document) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto uri = DocumentUri::fromFilePath(document->filePath()); | 
					
						
							|  |  |  |     showDiagnostics(uri); | 
					
						
							|  |  |  |     SemanticHighligtingSupport::applyHighlight(document, m_highlights.value(uri), capabilities()); | 
					
						
							|  |  |  |     // only replace the assist provider if the completion provider is the default one or null
 | 
					
						
							|  |  |  |     if (!document->completionAssistProvider() | 
					
						
							|  |  |  |         || qobject_cast<TextEditor::DocumentContentCompletionProvider *>( | 
					
						
							|  |  |  |             document->completionAssistProvider())) { | 
					
						
							|  |  |  |         m_resetAssistProvider[document] = {document->completionAssistProvider(), | 
					
						
							|  |  |  |                                            document->functionHintAssistProvider(), | 
					
						
							|  |  |  |                                            document->quickFixAssistProvider()}; | 
					
						
							|  |  |  |         document->setCompletionAssistProvider(m_clientProviders.completionAssistProvider); | 
					
						
							|  |  |  |         document->setFunctionHintAssistProvider(m_clientProviders.functionHintProvider); | 
					
						
							|  |  |  |         document->setQuickFixAssistProvider(m_clientProviders.quickFixAssistProvider); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-01-08 12:03:54 +01:00
										 |  |  |     document->setFormatter(new LanguageClientFormatter(document, this)); | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |     for (Core::IEditor *editor : Core::DocumentModel::editorsForDocument(document)) { | 
					
						
							|  |  |  |         updateEditorToolBar(editor); | 
					
						
							|  |  |  |         if (auto textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor)) | 
					
						
							| 
									
										
										
										
											2019-11-06 10:14:13 +01:00
										 |  |  |             textEditor->editorWidget()->addHoverHandler(&m_hoverHandler); | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Client::deactivateDocument(TextEditor::TextDocument *document) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     hideDiagnostics(document); | 
					
						
							| 
									
										
										
										
											2019-09-11 11:15:39 +02:00
										 |  |  |     resetAssistProviders(document); | 
					
						
							| 
									
										
										
										
											2020-01-08 12:03:54 +01:00
										 |  |  |     document->setFormatter(nullptr); | 
					
						
							| 
									
										
										
										
											2020-02-17 12:57:59 +01:00
										 |  |  |     if (m_serverCapabilities.semanticHighlighting().has_value()) { | 
					
						
							|  |  |  |         if (TextEditor::SyntaxHighlighter *highlighter = document->syntaxHighlighter()) | 
					
						
							|  |  |  |             highlighter->clearAllExtraFormats(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-11-06 10:14:13 +01:00
										 |  |  |     for (Core::IEditor *editor : Core::DocumentModel::editorsForDocument(document)) { | 
					
						
							|  |  |  |         if (auto textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor)) | 
					
						
							|  |  |  |             textEditor->editorWidget()->removeHoverHandler(&m_hoverHandler); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-08 12:03:54 +01:00
										 |  |  | bool Client::documentOpen(const TextEditor::TextDocument *document) const | 
					
						
							| 
									
										
										
										
											2019-03-26 13:48:06 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-01-08 12:03:54 +01:00
										 |  |  |     return m_openedDocument.contains(const_cast<TextEditor::TextDocument *>(document)); | 
					
						
							| 
									
										
										
										
											2019-03-26 13:48:06 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-11 11:15:39 +02:00
										 |  |  | void Client::documentContentsSaved(TextEditor::TextDocument *document) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-09-11 14:31:20 +02:00
										 |  |  |     if (!m_openedDocument.contains(document)) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |         return; | 
					
						
							|  |  |  |     bool sendMessage = true; | 
					
						
							|  |  |  |     bool includeText = false; | 
					
						
							|  |  |  |     const QString method(DidSaveTextDocumentNotification::methodName); | 
					
						
							|  |  |  |     if (Utils::optional<bool> registered = m_dynamicCapabilities.isRegistered(method)) { | 
					
						
							|  |  |  |         sendMessage = registered.value(); | 
					
						
							|  |  |  |         if (sendMessage) { | 
					
						
							|  |  |  |             const TextDocumentSaveRegistrationOptions option( | 
					
						
							|  |  |  |                         m_dynamicCapabilities.option(method).toObject()); | 
					
						
							|  |  |  |             if (option.isValid(nullptr)) { | 
					
						
							|  |  |  |                 sendMessage = option.filterApplies(document->filePath(), | 
					
						
							|  |  |  |                                                    Utils::mimeTypeForName(document->mimeType())); | 
					
						
							|  |  |  |                 includeText = option.includeText().value_or(includeText); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else if (Utils::optional<ServerCapabilities::TextDocumentSync> _sync | 
					
						
							|  |  |  |                = m_serverCapabilities.textDocumentSync()) { | 
					
						
							|  |  |  |         if (auto options = Utils::get_if<TextDocumentSyncOptions>(&_sync.value())) { | 
					
						
							|  |  |  |             if (Utils::optional<SaveOptions> saveOptions = options->save()) | 
					
						
							|  |  |  |                 includeText = saveOptions.value().includeText().value_or(includeText); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!sendMessage) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     DidSaveTextDocumentParams params( | 
					
						
							| 
									
										
										
										
											2019-09-11 14:34:20 +02:00
										 |  |  |                 TextDocumentIdentifier(DocumentUri::fromFilePath(document->filePath()))); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     if (includeText) | 
					
						
							| 
									
										
										
										
											2019-09-11 11:15:39 +02:00
										 |  |  |         params.setText(document->plainText()); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     sendContent(DidSaveTextDocumentNotification(params)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::documentWillSave(Core::IDocument *document) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-05-28 13:49:26 +02:00
										 |  |  |     const FilePath &filePath = document->filePath(); | 
					
						
							| 
									
										
										
										
											2019-09-11 14:31:20 +02:00
										 |  |  |     auto textDocument = qobject_cast<TextEditor::TextDocument *>(document); | 
					
						
							|  |  |  |     if (!m_openedDocument.contains(textDocument)) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |         return; | 
					
						
							|  |  |  |     bool sendMessage = true; | 
					
						
							|  |  |  |     const QString method(WillSaveTextDocumentNotification::methodName); | 
					
						
							|  |  |  |     if (Utils::optional<bool> registered = m_dynamicCapabilities.isRegistered(method)) { | 
					
						
							|  |  |  |         sendMessage = registered.value(); | 
					
						
							|  |  |  |         if (sendMessage) { | 
					
						
							|  |  |  |             const TextDocumentRegistrationOptions option(m_dynamicCapabilities.option(method)); | 
					
						
							|  |  |  |             if (option.isValid(nullptr)) { | 
					
						
							|  |  |  |                 sendMessage = option.filterApplies(filePath, | 
					
						
							|  |  |  |                                                    Utils::mimeTypeForName(document->mimeType())); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else if (Utils::optional<ServerCapabilities::TextDocumentSync> _sync | 
					
						
							|  |  |  |                = m_serverCapabilities.textDocumentSync()) { | 
					
						
							|  |  |  |         if (auto options = Utils::get_if<TextDocumentSyncOptions>(&_sync.value())) | 
					
						
							|  |  |  |             sendMessage = options->willSave().value_or(sendMessage); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!sendMessage) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     const WillSaveTextDocumentParams params( | 
					
						
							| 
									
										
										
										
											2019-09-11 14:34:20 +02:00
										 |  |  |         TextDocumentIdentifier(DocumentUri::fromFilePath(filePath))); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     sendContent(WillSaveTextDocumentNotification(params)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-02 10:49:23 +02:00
										 |  |  | void Client::documentContentsChanged(TextEditor::TextDocument *document, | 
					
						
							|  |  |  |                                      int position, | 
					
						
							|  |  |  |                                      int charsRemoved, | 
					
						
							|  |  |  |                                      int charsAdded) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-25 13:27:46 +01:00
										 |  |  |     if (!m_openedDocument.contains(document) || !reachable()) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |         return; | 
					
						
							|  |  |  |     const QString method(DidChangeTextDocumentNotification::methodName); | 
					
						
							|  |  |  |     TextDocumentSyncKind syncKind = m_serverCapabilities.textDocumentSyncKindHelper(); | 
					
						
							|  |  |  |     if (Utils::optional<bool> registered = m_dynamicCapabilities.isRegistered(method)) { | 
					
						
							|  |  |  |         syncKind = registered.value() ? TextDocumentSyncKind::None : TextDocumentSyncKind::Full; | 
					
						
							|  |  |  |         if (syncKind != TextDocumentSyncKind::None) { | 
					
						
							|  |  |  |             const TextDocumentChangeRegistrationOptions option( | 
					
						
							|  |  |  |                                     m_dynamicCapabilities.option(method).toObject()); | 
					
						
							|  |  |  |             syncKind = option.isValid(nullptr) ? option.syncKind() : syncKind; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     auto textDocument = qobject_cast<TextEditor::TextDocument *>(document); | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-11 14:34:20 +02:00
										 |  |  |     const auto uri = DocumentUri::fromFilePath(document->filePath()); | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  |     m_highlights[uri].clear(); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     if (syncKind != TextDocumentSyncKind::None) { | 
					
						
							|  |  |  |         VersionedTextDocumentIdentifier docId(uri); | 
					
						
							|  |  |  |         docId.setVersion(textDocument ? textDocument->document()->revision() : 0); | 
					
						
							| 
									
										
										
										
											2019-04-02 10:49:23 +02:00
										 |  |  |         DidChangeTextDocumentParams params; | 
					
						
							|  |  |  |         params.setTextDocument(docId); | 
					
						
							|  |  |  |         if (syncKind == TextDocumentSyncKind::Incremental) { | 
					
						
							|  |  |  |             DidChangeTextDocumentParams::TextDocumentContentChangeEvent change; | 
					
						
							| 
									
										
										
										
											2019-09-11 14:31:20 +02:00
										 |  |  |             QTextDocument oldDoc(m_openedDocument[document]); | 
					
						
							| 
									
										
										
										
											2019-04-02 10:49:23 +02:00
										 |  |  |             QTextCursor cursor(&oldDoc); | 
					
						
							|  |  |  |             cursor.setPosition(position + charsRemoved); | 
					
						
							|  |  |  |             cursor.setPosition(position, QTextCursor::KeepAnchor); | 
					
						
							|  |  |  |             change.setRange(Range(cursor)); | 
					
						
							| 
									
										
										
										
											2019-07-18 10:52:27 +02:00
										 |  |  |             change.setRangeLength(cursor.selectionEnd() - cursor.selectionStart()); | 
					
						
							| 
									
										
										
										
											2019-04-02 10:49:23 +02:00
										 |  |  |             change.setText(document->textAt(position, charsAdded)); | 
					
						
							|  |  |  |             params.setContentChanges({change}); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             params.setContentChanges({document->plainText()}); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-09-11 14:31:20 +02:00
										 |  |  |         m_openedDocument[document] = document->plainText(); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |         sendContent(DidChangeTextDocumentNotification(params)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (textDocument) { | 
					
						
							|  |  |  |         using namespace TextEditor; | 
					
						
							| 
									
										
										
										
											2019-03-12 13:46:31 +01:00
										 |  |  |         for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(textDocument)) | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  |             if (TextEditorWidget *widget = editor->editorWidget()) | 
					
						
							|  |  |  |                 widget->setRefactorMarkers(RefactorMarker::filterOutType(widget->refactorMarkers(), id())); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::registerCapabilities(const QList<Registration> ®istrations) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     m_dynamicCapabilities.registerCapability(registrations); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::unregisterCapabilities(const QList<Unregistration> &unregistrations) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     m_dynamicCapabilities.unregisterCapability(unregistrations); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-28 08:16:19 +01:00
										 |  |  | template <typename Request> | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | static bool sendTextDocumentPositionParamsRequest(Client *client, | 
					
						
							| 
									
										
										
										
											2018-11-28 08:16:19 +01:00
										 |  |  |                                                   const Request &request, | 
					
						
							|  |  |  |                                                   const DynamicCapabilities &dynamicCapabilities, | 
					
						
							|  |  |  |                                                   const optional<bool> &serverCapability) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-28 08:16:19 +01:00
										 |  |  |     if (!request.isValid(nullptr)) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     const DocumentUri uri = request.params().value().textDocument().uri(); | 
					
						
							|  |  |  |     const bool supportedFile = client->isSupportedUri(uri); | 
					
						
							|  |  |  |     bool sendMessage = dynamicCapabilities.isRegistered(Request::methodName).value_or(false); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     if (sendMessage) { | 
					
						
							| 
									
										
										
										
											2018-11-28 08:16:19 +01:00
										 |  |  |         const TextDocumentRegistrationOptions option(dynamicCapabilities.option(Request::methodName)); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |         if (option.isValid(nullptr)) | 
					
						
							| 
									
										
										
										
											2019-05-28 13:49:26 +02:00
										 |  |  |             sendMessage = option.filterApplies(FilePath::fromString(QUrl(uri).adjusted(QUrl::PreferLocalFile).toString())); | 
					
						
							| 
									
										
										
										
											2018-11-28 08:16:19 +01:00
										 |  |  |         else | 
					
						
							|  |  |  |             sendMessage = supportedFile; | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2018-11-28 08:16:19 +01:00
										 |  |  |         sendMessage = serverCapability.value_or(sendMessage) && supportedFile; | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (sendMessage) | 
					
						
							| 
									
										
										
										
											2018-11-28 08:16:19 +01:00
										 |  |  |         client->sendContent(request); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     return sendMessage; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | bool Client::findLinkAt(GotoDefinitionRequest &request) | 
					
						
							| 
									
										
										
										
											2018-11-28 08:16:19 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     return LanguageClient::sendTextDocumentPositionParamsRequest( | 
					
						
							|  |  |  |                 this, request, m_dynamicCapabilities, m_serverCapabilities.definitionProvider()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | bool Client::findUsages(FindReferencesRequest &request) | 
					
						
							| 
									
										
										
										
											2018-11-28 08:16:19 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     return LanguageClient::sendTextDocumentPositionParamsRequest( | 
					
						
							|  |  |  |                 this, request, m_dynamicCapabilities, m_serverCapabilities.referencesProvider()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | TextEditor::HighlightingResult createHighlightingResult(const SymbolInformation &info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!info.isValid(nullptr)) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  |     const Position &start = info.location().range().start(); | 
					
						
							| 
									
										
										
										
											2019-09-11 13:49:18 +02:00
										 |  |  |     return TextEditor::HighlightingResult(start.line() + 1, | 
					
						
							|  |  |  |                                           start.character() + 1, | 
					
						
							|  |  |  |                                           info.name().length(), | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  |                                           info.kind()); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::cursorPositionChanged(TextEditor::TextEditorWidget *widget) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-09-11 14:34:20 +02:00
										 |  |  |     const auto uri = DocumentUri::fromFilePath(widget->textDocument()->filePath()); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     if (m_dynamicCapabilities.isRegistered(DocumentHighlightsRequest::methodName).value_or(false)) { | 
					
						
							|  |  |  |         TextDocumentRegistrationOptions option( | 
					
						
							|  |  |  |                     m_dynamicCapabilities.option(DocumentHighlightsRequest::methodName)); | 
					
						
							|  |  |  |         if (!option.filterApplies(widget->textDocument()->filePath())) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |     } else if (!m_serverCapabilities.documentHighlightProvider().value_or(false)) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto runningRequest = m_highlightRequests.find(uri); | 
					
						
							|  |  |  |     if (runningRequest != m_highlightRequests.end()) | 
					
						
							|  |  |  |         cancelRequest(runningRequest.value()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     DocumentHighlightsRequest request(TextDocumentPositionParams(uri, widget->textCursor())); | 
					
						
							|  |  |  |     request.setResponseCallback( | 
					
						
							|  |  |  |                 [widget = QPointer<TextEditor::TextEditorWidget>(widget), this, uri] | 
					
						
							| 
									
										
										
										
											2018-11-20 07:45:22 +01:00
										 |  |  |                 (DocumentHighlightsRequest::Response response) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         m_highlightRequests.remove(uri); | 
					
						
							|  |  |  |         if (!widget) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         QList<QTextEdit::ExtraSelection> selections; | 
					
						
							|  |  |  |         const DocumentHighlightsResult result = response.result().value_or(DocumentHighlightsResult()); | 
					
						
							|  |  |  |         if (!holds_alternative<QList<DocumentHighlight>>(result)) { | 
					
						
							|  |  |  |             widget->setExtraSelections(TextEditor::TextEditorWidget::CodeSemanticsSelection, selections); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const QTextCharFormat &format = | 
					
						
							|  |  |  |                 widget->textDocument()->fontSettings().toTextCharFormat(TextEditor::C_OCCURRENCES); | 
					
						
							|  |  |  |         QTextDocument *document = widget->document(); | 
					
						
							|  |  |  |         for (const auto &highlight : get<QList<DocumentHighlight>>(result)) { | 
					
						
							|  |  |  |             QTextEdit::ExtraSelection selection{widget->textCursor(), format}; | 
					
						
							|  |  |  |             const int &start = highlight.range().start().toPositionInDocument(document); | 
					
						
							|  |  |  |             const int &end = highlight.range().end().toPositionInDocument(document); | 
					
						
							|  |  |  |             if (start < 0 || end < 0) | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             selection.cursor.setPosition(start); | 
					
						
							|  |  |  |             selection.cursor.setPosition(end, QTextCursor::KeepAnchor); | 
					
						
							|  |  |  |             selections << selection; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         widget->setExtraSelections(TextEditor::TextEditorWidget::CodeSemanticsSelection, selections); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     m_highlightRequests[uri] = request.id(); | 
					
						
							|  |  |  |     sendContent(request); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::requestCodeActions(const DocumentUri &uri, const QList<Diagnostic> &diagnostics) | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-09-11 14:34:20 +02:00
										 |  |  |     const Utils::FilePath fileName = uri.toFilePath(); | 
					
						
							| 
									
										
										
										
											2019-10-01 09:11:02 +02:00
										 |  |  |     TextEditor::TextDocument *doc = TextEditor::TextDocument::textDocumentForFilePath(fileName); | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  |     if (!doc) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CodeActionParams codeActionParams; | 
					
						
							|  |  |  |     CodeActionParams::CodeActionContext context; | 
					
						
							|  |  |  |     context.setDiagnostics(diagnostics); | 
					
						
							|  |  |  |     codeActionParams.setContext(context); | 
					
						
							|  |  |  |     codeActionParams.setTextDocument(uri); | 
					
						
							|  |  |  |     Position start(0, 0); | 
					
						
							|  |  |  |     const QTextBlock &lastBlock = doc->document()->lastBlock(); | 
					
						
							|  |  |  |     Position end(lastBlock.blockNumber(), lastBlock.length() - 1); | 
					
						
							|  |  |  |     codeActionParams.setRange(Range(start, end)); | 
					
						
							|  |  |  |     CodeActionRequest request(codeActionParams); | 
					
						
							|  |  |  |     request.setResponseCallback( | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  |         [uri, self = QPointer<Client>(this)](const CodeActionRequest::Response &response) { | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  |         if (self) | 
					
						
							|  |  |  |             self->handleCodeActionResponse(response, uri); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-01-29 13:20:58 +01:00
										 |  |  |     requestCodeActions(request); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Client::requestCodeActions(const CodeActionRequest &request) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!request.isValid(nullptr)) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-28 13:49:26 +02:00
										 |  |  |     const Utils::FilePath fileName | 
					
						
							| 
									
										
										
										
											2019-09-11 14:34:20 +02:00
										 |  |  |         = request.params().value_or(CodeActionParams()).textDocument().uri().toFilePath(); | 
					
						
							| 
									
										
										
										
											2019-01-29 13:20:58 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const QString method(CodeActionRequest::methodName); | 
					
						
							|  |  |  |     if (Utils::optional<bool> registered = m_dynamicCapabilities.isRegistered(method)) { | 
					
						
							|  |  |  |         if (!registered.value()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         const TextDocumentRegistrationOptions option( | 
					
						
							|  |  |  |             m_dynamicCapabilities.option(method).toObject()); | 
					
						
							|  |  |  |         if (option.isValid(nullptr) && !option.filterApplies(fileName)) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         Utils::variant<bool, CodeActionOptions> provider | 
					
						
							|  |  |  |             = m_serverCapabilities.codeActionProvider().value_or(false); | 
					
						
							|  |  |  |         if (!(Utils::holds_alternative<CodeActionOptions>(provider) || Utils::get<bool>(provider))) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  |     sendContent(request); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::handleCodeActionResponse(const CodeActionRequest::Response &response, | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  |                                           const DocumentUri &uri) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (const Utils::optional<CodeActionRequest::Response::Error> &error = response.error()) | 
					
						
							|  |  |  |         log(*error); | 
					
						
							|  |  |  |     if (const Utils::optional<CodeActionResult> &_result = response.result()) { | 
					
						
							|  |  |  |         const CodeActionResult &result = _result.value(); | 
					
						
							|  |  |  |         if (auto list = Utils::get_if<QList<Utils::variant<Command, CodeAction>>>(&result)) { | 
					
						
							|  |  |  |             for (const Utils::variant<Command, CodeAction> &item : *list) { | 
					
						
							|  |  |  |                 if (auto action = Utils::get_if<CodeAction>(&item)) | 
					
						
							|  |  |  |                     updateCodeActionRefactoringMarker(this, *action, uri); | 
					
						
							| 
									
										
										
										
											2019-02-03 22:51:04 +02:00
										 |  |  |                 else if (auto command = Utils::get_if<Command>(&item)) { | 
					
						
							| 
									
										
										
										
											2019-07-23 10:58:00 +02:00
										 |  |  |                     Q_UNUSED(command) // todo
 | 
					
						
							| 
									
										
										
										
											2019-02-03 22:51:04 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::executeCommand(const Command &command) | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     using CommandOptions = LanguageServerProtocol::ServerCapabilities::ExecuteCommandOptions; | 
					
						
							|  |  |  |     const QString method(ExecuteCommandRequest::methodName); | 
					
						
							|  |  |  |     if (Utils::optional<bool> registered = m_dynamicCapabilities.isRegistered(method)) { | 
					
						
							|  |  |  |         if (!registered.value()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         const CommandOptions option(m_dynamicCapabilities.option(method).toObject()); | 
					
						
							|  |  |  |         if (option.isValid(nullptr) && !option.commands().isEmpty() && !option.commands().contains(command.command())) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |     } else if (Utils::optional<CommandOptions> option = m_serverCapabilities.executeCommandProvider()) { | 
					
						
							|  |  |  |         if (option->isValid(nullptr) && !option->commands().isEmpty() && !option->commands().contains(command.command())) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const ExecuteCommandRequest request((ExecuteCommandParams(command))); | 
					
						
							|  |  |  |     sendContent(request); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-08 12:03:54 +01:00
										 |  |  | static const FormattingOptions formattingOptions(const TextEditor::TabSettings &settings) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     FormattingOptions options; | 
					
						
							|  |  |  |     options.setTabSize(settings.m_tabSize); | 
					
						
							|  |  |  |     options.setInsertSpace(settings.m_tabPolicy == TextEditor::TabSettings::SpacesOnlyTabPolicy); | 
					
						
							|  |  |  |     return options; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename FormattingResponse> | 
					
						
							|  |  |  | static void handleFormattingResponse(const DocumentUri &uri, | 
					
						
							|  |  |  |                                      const QPointer<Client> client, | 
					
						
							|  |  |  |                                      const FormattingResponse &response) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (client) { | 
					
						
							|  |  |  |         if (const Utils::optional<typename FormattingResponse::Error> &error = response.error()) | 
					
						
							|  |  |  |             client->log(*error); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (Utils::optional<LanguageClientArray<TextEdit>> result = response.result()) { | 
					
						
							|  |  |  |         if (!result->isNull()) { | 
					
						
							|  |  |  |             applyTextEdits(uri, result->toList()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Client::formatFile(const TextEditor::TextDocument *document) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!isSupportedDocument(document)) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const FilePath &filePath = document->filePath(); | 
					
						
							|  |  |  |     const QString method(DocumentFormattingRequest::methodName); | 
					
						
							|  |  |  |     if (Utils::optional<bool> registered = m_dynamicCapabilities.isRegistered(method)) { | 
					
						
							|  |  |  |         if (!registered.value()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         const TextDocumentRegistrationOptions option( | 
					
						
							|  |  |  |             m_dynamicCapabilities.option(method).toObject()); | 
					
						
							|  |  |  |         if (option.isValid(nullptr) | 
					
						
							|  |  |  |             && !option.filterApplies(filePath, Utils::mimeTypeForName(document->mimeType()))) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else if (!m_serverCapabilities.documentFormattingProvider().value_or(false)) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     DocumentFormattingParams params; | 
					
						
							|  |  |  |     const DocumentUri uri = DocumentUri::fromFilePath(filePath); | 
					
						
							|  |  |  |     params.setTextDocument(uri); | 
					
						
							|  |  |  |     params.setOptions(formattingOptions(document->tabSettings())); | 
					
						
							|  |  |  |     DocumentFormattingRequest request(params); | 
					
						
							|  |  |  |     request.setResponseCallback( | 
					
						
							|  |  |  |         [uri, self = QPointer<Client>(this)](const DocumentFormattingRequest::Response &response) { | 
					
						
							|  |  |  |             handleFormattingResponse(uri, self, response); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     sendContent(request); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Client::formatRange(const TextEditor::TextDocument *document, const QTextCursor &cursor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!isSupportedDocument(document)) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const FilePath &filePath = document->filePath(); | 
					
						
							|  |  |  |     const QString method(DocumentRangeFormattingRequest::methodName); | 
					
						
							|  |  |  |     if (Utils::optional<bool> registered = m_dynamicCapabilities.isRegistered(method)) { | 
					
						
							|  |  |  |         if (!registered.value()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         const TextDocumentRegistrationOptions option( | 
					
						
							|  |  |  |             m_dynamicCapabilities.option(method).toObject()); | 
					
						
							|  |  |  |         if (option.isValid(nullptr) | 
					
						
							|  |  |  |             && !option.filterApplies(filePath, Utils::mimeTypeForName(document->mimeType()))) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else if (!m_serverCapabilities.documentRangeFormattingProvider().value_or(false)) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     DocumentRangeFormattingParams params; | 
					
						
							|  |  |  |     const DocumentUri uri = DocumentUri::fromFilePath(filePath); | 
					
						
							|  |  |  |     params.setTextDocument(uri); | 
					
						
							|  |  |  |     params.setOptions(formattingOptions(document->tabSettings())); | 
					
						
							|  |  |  |     if (!cursor.hasSelection()) { | 
					
						
							|  |  |  |         QTextCursor c = cursor; | 
					
						
							|  |  |  |         c.select(QTextCursor::LineUnderCursor); | 
					
						
							|  |  |  |         params.setRange(Range(c)); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         params.setRange(Range(cursor)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     DocumentRangeFormattingRequest request(params); | 
					
						
							|  |  |  |     request.setResponseCallback([uri, self = QPointer<Client>(this)]( | 
					
						
							|  |  |  |                                     const DocumentRangeFormattingRequest::Response &response) { | 
					
						
							|  |  |  |         handleFormattingResponse(uri, self, response); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     sendContent(request); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-15 11:25:48 +01:00
										 |  |  | const ProjectExplorer::Project *Client::project() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_project; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Client::setCurrentProject(ProjectExplorer::Project *project) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_project = project; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::projectOpened(ProjectExplorer::Project *project) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!sendWorkspceFolderChanges()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     WorkspaceFoldersChangeEvent event; | 
					
						
							|  |  |  |     event.setAdded({WorkSpaceFolder(project->projectDirectory().toString(), project->displayName())}); | 
					
						
							|  |  |  |     DidChangeWorkspaceFoldersParams params; | 
					
						
							|  |  |  |     params.setEvent(event); | 
					
						
							|  |  |  |     DidChangeWorkspaceFoldersNotification change(params); | 
					
						
							|  |  |  |     sendContent(change); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::projectClosed(ProjectExplorer::Project *project) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-15 11:25:48 +01:00
										 |  |  |     if (project == m_project) { | 
					
						
							|  |  |  |         if (m_state == Initialized) { | 
					
						
							|  |  |  |             shutdown(); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             m_state = Shutdown; // otherwise the manager would try to restart this server
 | 
					
						
							|  |  |  |             emit finished(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     if (!sendWorkspceFolderChanges()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     WorkspaceFoldersChangeEvent event; | 
					
						
							| 
									
										
										
										
											2019-03-15 11:25:48 +01:00
										 |  |  |     event.setRemoved( | 
					
						
							|  |  |  |         {WorkSpaceFolder(project->projectDirectory().toString(), project->displayName())}); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     DidChangeWorkspaceFoldersParams params; | 
					
						
							|  |  |  |     params.setEvent(event); | 
					
						
							|  |  |  |     DidChangeWorkspaceFoldersNotification change(params); | 
					
						
							|  |  |  |     sendContent(change); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::setSupportedLanguage(const LanguageFilter &filter) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-10 14:26:57 +02:00
										 |  |  |     m_languagFilter = filter; | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-11 11:15:39 +02:00
										 |  |  | bool Client::isSupportedDocument(const TextEditor::TextDocument *document) const | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-10 14:26:57 +02:00
										 |  |  |     QTC_ASSERT(document, return false); | 
					
						
							| 
									
										
										
										
											2019-03-12 11:01:25 +01:00
										 |  |  |     return m_languagFilter.isSupported(document); | 
					
						
							| 
									
										
										
										
											2018-11-28 08:16:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-28 13:49:26 +02:00
										 |  |  | bool Client::isSupportedFile(const Utils::FilePath &filePath, const QString &mimeType) const | 
					
						
							| 
									
										
										
										
											2018-11-28 08:16:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-11 15:13:36 +01:00
										 |  |  |     return m_languagFilter.isSupported(filePath, mimeType); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | bool Client::isSupportedUri(const DocumentUri &uri) const | 
					
						
							| 
									
										
										
										
											2018-11-28 08:16:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-09-11 14:34:20 +02:00
										 |  |  |     return m_languagFilter.isSupported(uri.toFilePath(), | 
					
						
							|  |  |  |                                        Utils::mimeTypeForFile(uri.toFilePath().fileName()).name()); | 
					
						
							| 
									
										
										
										
											2018-11-28 08:16:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | bool Client::needsRestart(const BaseSettings *settings) const | 
					
						
							| 
									
										
										
										
											2018-09-18 10:43:17 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-19 07:05:46 +02:00
										 |  |  |     QTC_ASSERT(settings, return false); | 
					
						
							|  |  |  |     return m_languagFilter.mimeTypes != settings->m_languageFilter.mimeTypes | 
					
						
							|  |  |  |             || m_languagFilter.filePattern != settings->m_languageFilter.filePattern; | 
					
						
							| 
									
										
										
										
											2018-09-18 10:43:17 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-29 13:20:58 +01:00
										 |  |  | QList<Diagnostic> Client::diagnosticsAt(const DocumentUri &uri, const Range &range) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QList<Diagnostic> diagnostics; | 
					
						
							| 
									
										
										
										
											2019-10-15 13:48:34 +02:00
										 |  |  |     for (const Diagnostic &diagnostic : m_diagnostics[uri]) { | 
					
						
							| 
									
										
										
										
											2019-01-29 13:20:58 +01:00
										 |  |  |         if (diagnostic.range().overlaps(range)) | 
					
						
							|  |  |  |             diagnostics << diagnostic; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return diagnostics; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | bool Client::start() | 
					
						
							| 
									
										
										
										
											2019-01-31 08:46:23 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     return m_clientInterface->start(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | bool Client::reset() | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-09-14 10:00:29 +02:00
										 |  |  |     if (!m_restartsLeft) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     --m_restartsLeft; | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     m_state = Uninitialized; | 
					
						
							|  |  |  |     m_responseHandlers.clear(); | 
					
						
							| 
									
										
										
										
											2019-01-31 08:46:23 +01:00
										 |  |  |     m_clientInterface->resetBuffer(); | 
					
						
							| 
									
										
										
										
											2019-04-02 10:49:23 +02:00
										 |  |  |     updateEditorToolBar(m_openedDocument.keys()); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     m_serverCapabilities = ServerCapabilities(); | 
					
						
							|  |  |  |     m_dynamicCapabilities.reset(); | 
					
						
							| 
									
										
										
										
											2019-02-01 14:08:02 +01:00
										 |  |  |     for (const DocumentUri &uri : m_diagnostics.keys()) | 
					
						
							|  |  |  |         removeDiagnostics(uri); | 
					
						
							| 
									
										
										
										
											2020-02-25 13:30:20 +01:00
										 |  |  |     for (TextEditor::TextDocument *document : m_openedDocument.keys()) | 
					
						
							|  |  |  |         document->disconnect(this); | 
					
						
							| 
									
										
										
										
											2019-12-10 09:41:11 +01:00
										 |  |  |     for (TextEditor::TextDocument *document : m_resetAssistProvider.keys()) | 
					
						
							|  |  |  |         resetAssistProviders(document); | 
					
						
							| 
									
										
										
										
											2018-09-14 10:00:29 +02:00
										 |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::setError(const QString &message) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     log(message); | 
					
						
							|  |  |  |     m_state = Error; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::handleMessage(const BaseMessage &message) | 
					
						
							| 
									
										
										
										
											2019-01-31 08:46:23 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-20 10:13:14 +01:00
										 |  |  |     LanguageClientManager::logBaseMessage(LspLogMessage::ServerMessage, name(), message); | 
					
						
							| 
									
										
										
										
											2019-01-31 08:46:23 +01:00
										 |  |  |     if (auto handler = m_contentHandler[message.mimeType]) { | 
					
						
							|  |  |  |         QString parseError; | 
					
						
							|  |  |  |         handler(message.content, message.codec, parseError, | 
					
						
							|  |  |  |                 [this](MessageId id, const QByteArray &content, QTextCodec *codec){ | 
					
						
							|  |  |  |                     this->handleResponse(id, content, codec); | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 [this](const QString &method, MessageId id, const IContent *content){ | 
					
						
							|  |  |  |                     this->handleMethod(method, id, content); | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |         if (!parseError.isEmpty()) | 
					
						
							|  |  |  |             log(parseError); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         log(tr("Cannot handle content of type: %1").arg(QLatin1String(message.mimeType))); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::log(const QString &message, Core::MessageManager::PrintToOutputPaneFlag flag) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     Core::MessageManager::write(QString("LanguageClient %1: %2").arg(name(), message), flag); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-24 13:40:12 +02:00
										 |  |  | void Client::showDiagnostics(Core::IDocument *doc) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-09-11 14:34:20 +02:00
										 |  |  |     showDiagnostics(DocumentUri::fromFilePath(doc->filePath())); | 
					
						
							| 
									
										
										
										
											2019-07-24 13:40:12 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-11 11:15:39 +02:00
										 |  |  | void Client::hideDiagnostics(TextEditor::TextDocument *doc) | 
					
						
							| 
									
										
										
										
											2019-07-24 13:40:12 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |     if (!doc) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2019-10-15 13:48:34 +02:00
										 |  |  |     qDeleteAll(Utils::filtered(doc->marks(), Utils::equal(&TextEditor::TextMark::category, id()))); | 
					
						
							| 
									
										
										
										
											2019-07-24 13:40:12 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | const ServerCapabilities &Client::capabilities() const | 
					
						
							| 
									
										
										
										
											2018-11-23 09:45:51 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     return m_serverCapabilities; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | const DynamicCapabilities &Client::dynamicCapabilities() const | 
					
						
							| 
									
										
										
										
											2018-11-23 09:45:51 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     return m_dynamicCapabilities; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-11 07:33:07 +01:00
										 |  |  | const BaseClientInterface *Client::clientInterface() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_clientInterface.data(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-04 14:36:28 +02:00
										 |  |  | DocumentSymbolCache *Client::documentSymbolCache() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return &m_documentSymbolCache; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-15 11:19:31 +02:00
										 |  |  | HoverHandler *Client::hoverHandler() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return &m_hoverHandler; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::log(const ShowMessageParams &message, | 
					
						
							| 
									
										
										
										
											2018-09-12 08:14:25 +02:00
										 |  |  |                      Core::MessageManager::PrintToOutputPaneFlag flag) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     log(message.toString(), flag); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::showMessageBox(const ShowMessageRequestParams &message, const MessageId &id) | 
					
						
							| 
									
										
										
										
											2018-09-12 10:24:02 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     auto box = new QMessageBox(); | 
					
						
							|  |  |  |     box->setText(message.toString()); | 
					
						
							|  |  |  |     box->setAttribute(Qt::WA_DeleteOnClose); | 
					
						
							|  |  |  |     switch (message.type()) { | 
					
						
							|  |  |  |     case Error: box->setIcon(QMessageBox::Critical); break; | 
					
						
							|  |  |  |     case Warning: box->setIcon(QMessageBox::Warning); break; | 
					
						
							|  |  |  |     case Info: box->setIcon(QMessageBox::Information); break; | 
					
						
							|  |  |  |     case Log: box->setIcon(QMessageBox::NoIcon); break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     QHash<QAbstractButton *, MessageActionItem> itemForButton; | 
					
						
							|  |  |  |     if (const Utils::optional<QList<MessageActionItem>> actions = message.actions()) { | 
					
						
							|  |  |  |         for (const MessageActionItem &action : actions.value()) | 
					
						
							|  |  |  |             itemForButton.insert(box->addButton(action.title(), QMessageBox::InvalidRole), action); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     box->setModal(true); | 
					
						
							|  |  |  |     connect(box, &QMessageBox::finished, this, [=]{ | 
					
						
							| 
									
										
										
										
											2019-03-15 10:05:40 +01:00
										 |  |  |         ShowMessageRequest::Response response(id); | 
					
						
							| 
									
										
										
										
											2018-09-12 10:24:02 +02:00
										 |  |  |         const MessageActionItem &item = itemForButton.value(box->clickedButton()); | 
					
						
							|  |  |  |         response.setResult(item.isValid(nullptr) ? LanguageClientValue<MessageActionItem>(item) | 
					
						
							|  |  |  |                                                  : LanguageClientValue<MessageActionItem>()); | 
					
						
							|  |  |  |         sendContent(response); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     box->show(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-01 14:08:02 +01:00
										 |  |  | void Client::showDiagnostics(const DocumentUri &uri) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-15 13:48:34 +02:00
										 |  |  |     const FilePath &filePath = uri.toFilePath(); | 
					
						
							|  |  |  |     if (TextEditor::TextDocument *doc = TextEditor::TextDocument::textDocumentForFilePath( | 
					
						
							|  |  |  |             uri.toFilePath())) { | 
					
						
							|  |  |  |         for (const Diagnostic &diagnostic : m_diagnostics.value(uri)) | 
					
						
							|  |  |  |             doc->addMark(new TextMark(filePath, diagnostic, id())); | 
					
						
							| 
									
										
										
										
											2019-02-01 14:08:02 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Client::removeDiagnostics(const DocumentUri &uri) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-15 13:48:34 +02:00
										 |  |  |     hideDiagnostics(TextEditor::TextDocument::textDocumentForFilePath(uri.toFilePath())); | 
					
						
							|  |  |  |     m_diagnostics.remove(uri); | 
					
						
							| 
									
										
										
										
											2019-02-01 14:08:02 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:36 +02:00
										 |  |  | void Client::resetAssistProviders(TextEditor::TextDocument *document) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const AssistProviders providers = m_resetAssistProvider.take(document); | 
					
						
							| 
									
										
										
										
											2019-09-20 07:40:51 +02:00
										 |  |  |     if (document->completionAssistProvider() == m_clientProviders.completionAssistProvider) | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:36 +02:00
										 |  |  |         document->setCompletionAssistProvider(providers.completionAssistProvider); | 
					
						
							| 
									
										
										
										
											2019-09-20 07:40:51 +02:00
										 |  |  |     if (document->functionHintAssistProvider() == m_clientProviders.functionHintProvider) | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:36 +02:00
										 |  |  |         document->setFunctionHintAssistProvider(providers.functionHintProvider); | 
					
						
							| 
									
										
										
										
											2019-09-20 07:40:51 +02:00
										 |  |  |     if (document->quickFixAssistProvider() == m_clientProviders.quickFixAssistProvider) | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:36 +02:00
										 |  |  |         document->setQuickFixAssistProvider(providers.quickFixAssistProvider); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::handleResponse(const MessageId &id, const QByteArray &content, QTextCodec *codec) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (auto handler = m_responseHandlers[id]) | 
					
						
							|  |  |  |         handler(content, codec); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::handleMethod(const QString &method, MessageId id, const IContent *content) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-10 10:31:32 +01:00
										 |  |  |     ErrorHierarchy error; | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |     auto logError = [&](const JsonObject &content) { | 
					
						
							|  |  |  |         log(QJsonDocument(content).toJson(QJsonDocument::Indented) + '\n' | 
					
						
							|  |  |  |                 + tr("Invalid parameter in \"%1\": %2").arg(method, error.toString()), | 
					
						
							|  |  |  |             Core::MessageManager::Flash); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     if (method == PublishDiagnosticsNotification::methodName) { | 
					
						
							|  |  |  |         auto params = dynamic_cast<const PublishDiagnosticsNotification *>(content)->params().value_or(PublishDiagnosticsParams()); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         if (params.isValid(&error)) | 
					
						
							| 
									
										
										
										
											2019-02-01 14:08:02 +01:00
										 |  |  |             handleDiagnostics(params); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         else | 
					
						
							|  |  |  |             logError(params); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     } else if (method == LogMessageNotification::methodName) { | 
					
						
							|  |  |  |         auto params = dynamic_cast<const LogMessageNotification *>(content)->params().value_or(LogMessageParams()); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         if (params.isValid(&error)) | 
					
						
							| 
									
										
										
										
											2018-09-12 10:24:02 +02:00
										 |  |  |             log(params, Core::MessageManager::Flash); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         else | 
					
						
							|  |  |  |             logError(params); | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  |     } else if (method == SemanticHighlightNotification::methodName) { | 
					
						
							|  |  |  |         auto params = dynamic_cast<const SemanticHighlightNotification *>(content)->params().value_or(SemanticHighlightingParams()); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         if (params.isValid(&error)) | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  |             handleSemanticHighlight(params); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         else | 
					
						
							|  |  |  |             logError(params); | 
					
						
							| 
									
										
										
										
											2018-09-12 10:24:02 +02:00
										 |  |  |     } else if (method == ShowMessageNotification::methodName) { | 
					
						
							|  |  |  |         auto params = dynamic_cast<const ShowMessageNotification *>(content)->params().value_or(ShowMessageParams()); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         if (params.isValid(&error)) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |             log(params); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         else | 
					
						
							|  |  |  |             logError(params); | 
					
						
							| 
									
										
										
										
											2018-09-12 10:24:02 +02:00
										 |  |  |     } else if (method == ShowMessageRequest::methodName) { | 
					
						
							| 
									
										
										
										
											2018-11-14 01:21:20 +01:00
										 |  |  |         auto request = dynamic_cast<const ShowMessageRequest *>(content); | 
					
						
							| 
									
										
										
										
											2018-09-12 10:24:02 +02:00
										 |  |  |         auto params = request->params().value_or(ShowMessageRequestParams()); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         if (params.isValid(&error)) { | 
					
						
							| 
									
										
										
										
											2018-09-12 10:24:02 +02:00
										 |  |  |             showMessageBox(params, request->id()); | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2019-03-15 10:05:40 +01:00
										 |  |  |             ShowMessageRequest::Response response(request->id()); | 
					
						
							| 
									
										
										
										
											2019-01-07 13:24:01 +01:00
										 |  |  |             ResponseError<std::nullptr_t> error; | 
					
						
							| 
									
										
										
										
											2018-09-12 10:24:02 +02:00
										 |  |  |             const QString errorMessage = | 
					
						
							|  |  |  |                     QString("Could not parse ShowMessageRequest parameter of '%1': \"%2\"") | 
					
						
							|  |  |  |                     .arg(request->id().toString(), | 
					
						
							|  |  |  |                          QString::fromUtf8(QJsonDocument(params).toJson())); | 
					
						
							|  |  |  |             error.setMessage(errorMessage); | 
					
						
							|  |  |  |             response.setError(error); | 
					
						
							|  |  |  |             sendContent(response); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     } else if (method == RegisterCapabilityRequest::methodName) { | 
					
						
							|  |  |  |         auto params = dynamic_cast<const RegisterCapabilityRequest *>(content)->params().value_or(RegistrationParams()); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         if (params.isValid(&error)) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |             m_dynamicCapabilities.registerCapability(params.registrations()); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         else | 
					
						
							|  |  |  |             logError(params); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     } else if (method == UnregisterCapabilityRequest::methodName) { | 
					
						
							|  |  |  |         auto params = dynamic_cast<const UnregisterCapabilityRequest *>(content)->params().value_or(UnregistrationParams()); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         if (params.isValid(&error)) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |             m_dynamicCapabilities.unregisterCapability(params.unregistrations()); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         else | 
					
						
							|  |  |  |             logError(params); | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  |     } else if (method == ApplyWorkspaceEditRequest::methodName) { | 
					
						
							|  |  |  |         auto params = dynamic_cast<const ApplyWorkspaceEditRequest *>(content)->params().value_or(ApplyWorkspaceEditParams()); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         if (params.isValid(&error)) | 
					
						
							| 
									
										
										
										
											2019-01-25 09:48:44 +01:00
										 |  |  |             applyWorkspaceEdit(params.edit()); | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         else | 
					
						
							|  |  |  |             logError(params); | 
					
						
							| 
									
										
										
										
											2019-03-15 10:09:17 +01:00
										 |  |  |     } else if (method == WorkSpaceFolderRequest::methodName) { | 
					
						
							|  |  |  |         WorkSpaceFolderRequest::Response response(dynamic_cast<const WorkSpaceFolderRequest *>(content)->id()); | 
					
						
							|  |  |  |         const QList<ProjectExplorer::Project *> projects | 
					
						
							|  |  |  |             = ProjectExplorer::SessionManager::projects(); | 
					
						
							|  |  |  |         WorkSpaceFolderResult result; | 
					
						
							|  |  |  |         if (projects.isEmpty()) { | 
					
						
							|  |  |  |             result = nullptr; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             result = Utils::transform(projects, [](ProjectExplorer::Project *project) { | 
					
						
							|  |  |  |                 return WorkSpaceFolder(project->projectDirectory().toString(), | 
					
						
							|  |  |  |                                        project->displayName()); | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         response.setResult(result); | 
					
						
							|  |  |  |         sendContent(response); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     } else if (id.isValid(&error)) { | 
					
						
							| 
									
										
										
										
											2019-03-15 10:05:40 +01:00
										 |  |  |         Response<JsonObject, JsonObject> response(id); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |         ResponseError<JsonObject> error; | 
					
						
							|  |  |  |         error.setCode(ResponseError<JsonObject>::MethodNotFound); | 
					
						
							|  |  |  |         response.setError(error); | 
					
						
							|  |  |  |         sendContent(response); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     delete content; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-01 14:08:02 +01:00
										 |  |  | void Client::handleDiagnostics(const PublishDiagnosticsParams ¶ms) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const DocumentUri &uri = params.uri(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     removeDiagnostics(uri); | 
					
						
							|  |  |  |     const QList<Diagnostic> &diagnostics = params.diagnostics(); | 
					
						
							| 
									
										
										
										
											2019-10-15 13:48:34 +02:00
										 |  |  |     m_diagnostics[uri] = diagnostics; | 
					
						
							|  |  |  |     if (LanguageClientManager::clientForUri(uri) == this) { | 
					
						
							|  |  |  |         showDiagnostics(uri); | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |         requestCodeActions(uri, diagnostics); | 
					
						
							| 
									
										
										
										
											2019-10-15 13:48:34 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-01 14:08:02 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  | void Client::handleSemanticHighlight(const SemanticHighlightingParams ¶ms) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const DocumentUri &uri = params.textDocument().uri(); | 
					
						
							|  |  |  |     m_highlights[uri].clear(); | 
					
						
							|  |  |  |     const LanguageClientValue<int> &version = params.textDocument().version(); | 
					
						
							| 
									
										
										
										
											2019-10-01 09:11:02 +02:00
										 |  |  |     TextEditor::TextDocument *doc = TextEditor::TextDocument::textDocumentForFilePath( | 
					
						
							| 
									
										
										
										
											2019-09-11 14:34:20 +02:00
										 |  |  |         uri.toFilePath()); | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |     if (!doc || LanguageClientManager::clientForDocument(doc) != this | 
					
						
							|  |  |  |         || (!version.isNull() && doc->document()->revision() != version.value())) { | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const TextEditor::HighlightingResults results = SemanticHighligtingSupport::generateResults( | 
					
						
							|  |  |  |         params.lines()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_highlights[uri] = results; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SemanticHighligtingSupport::applyHighlight(doc, results, capabilities()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Client::rehighlight() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     using namespace TextEditor; | 
					
						
							|  |  |  |     for (auto it = m_highlights.begin(), end = m_highlights.end(); it != end; ++it) { | 
					
						
							| 
									
										
										
										
											2019-10-01 09:11:02 +02:00
										 |  |  |         if (TextDocument *doc = TextDocument::textDocumentForFilePath(it.key().toFilePath())) { | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  |             if (LanguageClientManager::clientForDocument(doc) == this) | 
					
						
							|  |  |  |                 SemanticHighligtingSupport::applyHighlight(doc, it.value(), capabilities()); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-06-12 12:55:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-18 14:26:08 +02:00
										 |  |  | void Client::initializeCallback(const InitializeRequest::Response &initResponse) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     QTC_ASSERT(m_state == InitializeRequested, return); | 
					
						
							|  |  |  |     if (optional<ResponseError<InitializeError>> error = initResponse.error()) { | 
					
						
							|  |  |  |         if (error.value().data().has_value() | 
					
						
							|  |  |  |                 && error.value().data().value().retry().value_or(false)) { | 
					
						
							| 
									
										
										
										
											2018-10-24 06:56:14 +02:00
										 |  |  |             const QString title(tr("Language Server \"%1\" Initialize Error").arg(m_displayName)); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |             auto result = QMessageBox::warning(Core::ICore::dialogParent(), | 
					
						
							|  |  |  |                                                title, | 
					
						
							|  |  |  |                                                error.value().message(), | 
					
						
							|  |  |  |                                                QMessageBox::Retry | QMessageBox::Cancel, | 
					
						
							|  |  |  |                                                QMessageBox::Retry); | 
					
						
							|  |  |  |             if (result == QMessageBox::Retry) { | 
					
						
							|  |  |  |                 m_state = Uninitialized; | 
					
						
							|  |  |  |                 initialize(); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         setError(tr("Initialize error: ") + error.value().message()); | 
					
						
							|  |  |  |         emit finished(); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const optional<InitializeResult> &_result = initResponse.result(); | 
					
						
							|  |  |  |     if (!_result.has_value()) {// continue on ill formed result
 | 
					
						
							|  |  |  |         log(tr("No initialize result.")); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         const InitializeResult &result = _result.value(); | 
					
						
							| 
									
										
										
										
											2020-02-10 10:31:32 +01:00
										 |  |  |         ErrorHierarchy error; | 
					
						
							| 
									
										
										
										
											2020-02-10 14:28:08 +01:00
										 |  |  |         if (!result.isValid(&error)) { // continue on ill formed result
 | 
					
						
							|  |  |  |             log(QJsonDocument(result).toJson(QJsonDocument::Indented) + '\n' | 
					
						
							|  |  |  |                 + tr("Initialize result is not valid: ") + error.toString()); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         m_serverCapabilities = result.capabilities().value_or(ServerCapabilities()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-10 09:37:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (auto completionProvider = qobject_cast<LanguageClientCompletionAssistProvider *>( | 
					
						
							|  |  |  |             m_clientProviders.completionAssistProvider)) { | 
					
						
							|  |  |  |         completionProvider->setTriggerCharacters( | 
					
						
							|  |  |  |             m_serverCapabilities.completionProvider() | 
					
						
							|  |  |  |                 .value_or(ServerCapabilities::CompletionOptions()) | 
					
						
							|  |  |  |                 .triggerCharacters() | 
					
						
							|  |  |  |                 .value_or(QList<QString>())); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (auto functionHintAssistProvider = qobject_cast<FunctionHintAssistProvider *>( | 
					
						
							|  |  |  |             m_clientProviders.completionAssistProvider)) { | 
					
						
							|  |  |  |         functionHintAssistProvider->setTriggerCharacters( | 
					
						
							|  |  |  |             m_serverCapabilities.signatureHelpProvider() | 
					
						
							|  |  |  |                 .value_or(ServerCapabilities::SignatureHelpOptions()) | 
					
						
							|  |  |  |                 .triggerCharacters() | 
					
						
							|  |  |  |                 .value_or(QList<QString>())); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     qCDebug(LOGLSPCLIENT) << "language server " << m_displayName << " initialized"; | 
					
						
							|  |  |  |     m_state = Initialized; | 
					
						
							|  |  |  |     sendContent(InitializeNotification()); | 
					
						
							| 
									
										
										
										
											2019-07-16 12:29:20 +02:00
										 |  |  |     if (m_dynamicCapabilities.isRegistered(DocumentSymbolsRequest::methodName) | 
					
						
							|  |  |  |             .value_or(capabilities().documentSymbolProvider().value_or(false))) { | 
					
						
							|  |  |  |         TextEditor::IOutlineWidgetFactory::updateOutline(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-10 08:03:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (TextEditor::TextDocument *document : m_openedDocument.keys()) | 
					
						
							|  |  |  |         openDocument(document); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-05 10:05:25 +02:00
										 |  |  |     emit initialized(m_serverCapabilities); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | void Client::shutDownCallback(const ShutdownRequest::Response &shutdownResponse) | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     QTC_ASSERT(m_state == ShutdownRequested, return); | 
					
						
							| 
									
										
										
										
											2019-01-31 08:46:23 +01:00
										 |  |  |     QTC_ASSERT(m_clientInterface, return); | 
					
						
							| 
									
										
										
										
											2019-01-07 13:24:01 +01:00
										 |  |  |     optional<ShutdownRequest::Response::Error> errorValue = shutdownResponse.error(); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     if (errorValue.has_value()) { | 
					
						
							| 
									
										
										
										
											2019-01-07 13:24:01 +01:00
										 |  |  |         ShutdownRequest::Response::Error error = errorValue.value(); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |         qDebug() << error; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // directly send data otherwise the state check would fail;
 | 
					
						
							| 
									
										
										
										
											2019-01-31 08:46:23 +01:00
										 |  |  |     m_clientInterface->sendMessage(ExitNotification().toBaseMessage()); | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  |     qCDebug(LOGLSPCLIENT) << "language server " << m_displayName << " shutdown"; | 
					
						
							|  |  |  |     m_state = Shutdown; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 12:15:43 +01:00
										 |  |  | bool Client::sendWorkspceFolderChanges() const | 
					
						
							| 
									
										
										
										
											2018-07-13 12:33:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (m_dynamicCapabilities.isRegistered( | 
					
						
							|  |  |  |                 DidChangeWorkspaceFoldersNotification::methodName).value_or(false)) { | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (auto workspace = m_serverCapabilities.workspace()) { | 
					
						
							|  |  |  |         if (auto folder = workspace.value().workspaceFolders()) { | 
					
						
							|  |  |  |             if (folder.value().supported().value_or(false)) { | 
					
						
							|  |  |  |                 // holds either the Id for deregistration or whether it is registered
 | 
					
						
							|  |  |  |                 auto notification = folder.value().changeNotifications().value_or(false); | 
					
						
							|  |  |  |                 return holds_alternative<QString>(notification) | 
					
						
							|  |  |  |                         || (holds_alternative<bool>(notification) && get<bool>(notification)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace LanguageClient
 |