1 /* 2 *Copyright (C) 2018 Laurent Tréguier 3 * 4 *This file is part of DLS. 5 * 6 *DLS is free software: you can redistribute it and/or modify 7 *it under the terms of the GNU General Public License as published by 8 *the Free Software Foundation, either version 3 of the License, or 9 *(at your option) any later version. 10 * 11 *DLS is distributed in the hope that it will be useful, 12 *but WITHOUT ANY WARRANTY; without even the implied warranty of 13 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 *GNU General Public License for more details. 15 * 16 *You should have received a copy of the GNU General Public License 17 *along with DLS. If not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 module dls.protocol.messages.general; 22 23 import dls.protocol.interfaces.general; 24 import std.json : JSONValue; 25 26 @("") 27 InitializeResult initialize(InitializeParams params) 28 { 29 import dls.server : Server; 30 import dls.protocol.state : initOptions, initState; 31 import dls.tools.symbol_tool : useCompatCompletionItemKinds, 32 useCompatSymbolKinds; 33 import dls.tools.analysis_tool : AnalysisTool; 34 import dls.tools.format_tool : FormatTool; 35 import dls.tools.symbol_tool : SymbolTool; 36 import dls.util.logger : logger; 37 import dls.util.uri : Uri; 38 import std.algorithm : map, sort, uniq; 39 import std.array : array; 40 import std.typecons : Nullable, nullable; 41 42 logger.info("Initializing server"); 43 initState = params; 44 Server.initialized = true; 45 AnalysisTool.initialize(); 46 FormatTool.initialize(); 47 SymbolTool.initialize(); 48 49 debug 50 { 51 } 52 else 53 { 54 import dls.updater : cleanup; 55 import std.concurrency : spawn; 56 57 spawn(&cleanup); 58 } 59 60 if (params.capabilities.textDocument.completion.isNull 61 || params.capabilities.textDocument.completion.completionItemKind.isNull 62 || params.capabilities.textDocument.completion.completionItemKind.valueSet.isNull) 63 { 64 useCompatCompletionItemKinds(); 65 } 66 else 67 { 68 useCompatCompletionItemKinds( 69 params.capabilities.textDocument.completion.completionItemKind.valueSet); 70 } 71 72 if (params.capabilities.workspace.symbol.isNull || params.capabilities.workspace.symbol.symbolKind.isNull 73 || params.capabilities.workspace.symbol.symbolKind.valueSet.isNull) 74 { 75 useCompatSymbolKinds(); 76 } 77 else 78 { 79 useCompatSymbolKinds(params.capabilities.workspace.symbol.symbolKind.valueSet); 80 } 81 82 if (params.capabilities.textDocument.documentSymbol.isNull 83 || params.capabilities.textDocument.documentSymbol.symbolKind.isNull 84 || params.capabilities.textDocument.documentSymbol.symbolKind.valueSet.isNull) 85 { 86 useCompatSymbolKinds(); 87 } 88 else 89 { 90 useCompatSymbolKinds(params.capabilities.textDocument.documentSymbol.symbolKind.valueSet); 91 } 92 93 Uri[] uris; 94 95 if (!params.rootUri.isNull) 96 { 97 uris ~= new Uri(params.rootUri); 98 } 99 else if (!params.rootPath.isNull) 100 { 101 uris ~= Uri.fromPath(params.rootPath); 102 } 103 104 if (!params.workspaceFolders.isNull) 105 { 106 uris ~= params.workspaceFolders.map!(wf => new Uri(wf.uri)).array; 107 } 108 109 foreach (uri; uris.sort!q{a.path < b.path} 110 .uniq!q{a.path == b.path}) 111 { 112 SymbolTool.instance.importPath(uri); 113 AnalysisTool.instance.addAnalysisConfigPath(uri); 114 } 115 116 auto result = new InitializeResult(); 117 118 with (result.capabilities) 119 { 120 textDocumentSync = new TextDocumentSyncOptions(true.nullable, 121 TextDocumentSyncKind.incremental.nullable); 122 textDocumentSync.save = new SaveOptions(false.nullable); 123 hoverProvider = initOptions.capabilities.hover; 124 completionProvider = initOptions.capabilities.completion ? new CompletionOptions(true.nullable, 125 ["."].nullable).nullable : Nullable!CompletionOptions(); 126 definitionProvider = initOptions.capabilities.definition; 127 typeDefinitionProvider = initOptions.capabilities.definition; 128 referencesProvider = initOptions.capabilities.references; 129 documentHighlightProvider = initOptions.capabilities.documentHighlight; 130 documentSymbolProvider = initOptions.capabilities.documentSymbol; 131 workspaceSymbolProvider = initOptions.capabilities.workspaceSymbol; 132 documentFormattingProvider = initOptions.capabilities.documentFormatting; 133 renameProvider = initOptions.capabilities.rename 134 ? new RenameOptions(true.nullable) : Nullable!RenameOptions(); 135 workspace = new ServerCapabilities.Workspace(new ServerCapabilities.Workspace.WorkspaceFolders(true.nullable, 136 JSONValue(true).nullable).nullable); 137 } 138 139 return result; 140 } 141 142 @("") 143 void initialized(JSONValue nothing) 144 { 145 import dls.protocol.interfaces : DidChangeWatchedFilesRegistrationOptions, 146 FileSystemWatcher, Registration, RegistrationParams; 147 import dls.protocol.jsonrpc : send; 148 import dls.protocol.messages.methods : Client; 149 import dls.protocol.state : initOptions, initState; 150 import dls.server : Server; 151 import dls.util.logger : logger; 152 import std.typecons : nullable; 153 154 debug 155 { 156 } 157 else 158 { 159 import dls.updater : update; 160 import std.concurrency : spawn; 161 162 spawn(&update, initOptions.autoUpdate); 163 } 164 165 const didChangeWatchedFiles = initState.capabilities.workspace.didChangeWatchedFiles; 166 167 if (!didChangeWatchedFiles.isNull && didChangeWatchedFiles.dynamicRegistration) 168 { 169 logger.info("Registering watchers"); 170 auto watchers = [ 171 new FileSystemWatcher("**/dub.selections.json"), 172 new FileSystemWatcher("**/dub.{json,sdl}"), new FileSystemWatcher("**/*.ini") 173 ]; 174 auto registrationOptions = new DidChangeWatchedFilesRegistrationOptions(watchers); 175 auto registration = new Registration!DidChangeWatchedFilesRegistrationOptions( 176 "dls-registration-watch-dub-files", 177 "workspace/didChangeWatchedFiles", registrationOptions.nullable); 178 send(Client.registerCapability, 179 new RegistrationParams!DidChangeWatchedFilesRegistrationOptions([registration])); 180 } 181 } 182 183 @("") 184 JSONValue shutdown(JSONValue nothing) 185 { 186 import dls.server : Server; 187 import dls.tools.analysis_tool : AnalysisTool; 188 import dls.tools.format_tool : FormatTool; 189 import dls.tools.symbol_tool : SymbolTool; 190 import dls.util.logger : logger; 191 192 logger.info("Shutting down server"); 193 Server.shutdown = true; 194 AnalysisTool.shutdown(); 195 FormatTool.shutdown(); 196 SymbolTool.shutdown(); 197 return JSONValue(null); 198 } 199 200 @("") 201 void exit(JSONValue nothing) 202 { 203 import dls.server : Server; 204 import dls.util.logger : logger; 205 206 logger.info("Exiting server"); 207 Server.exit = true; 208 } 209 210 @("$") 211 void cancelRequest(JSONValue id) 212 { 213 }