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.workspace; 22 23 import dls.protocol.interfaces : SymbolInformation; 24 import dls.protocol.interfaces.workspace; 25 import std.json : JSONValue; 26 import std.typecons : Nullable; 27 28 void workspaceFolders(string id, Nullable!(WorkspaceFolder[]) folders) 29 { 30 import dls.protocol.jsonrpc : send; 31 import dls.protocol.messages.methods : Workspace; 32 import dls.protocol.state : initState; 33 import dls.tools.analysis_tool : AnalysisTool; 34 import dls.tools.symbol_tool : SymbolTool; 35 import dls.util.uri : Uri; 36 import std.typecons : nullable; 37 38 if (!folders.isNull) 39 { 40 ConfigurationItem[] items; 41 42 foreach (workspaceFolder; folders) 43 { 44 auto uri = new Uri(workspaceFolder.uri); 45 items ~= new ConfigurationItem(uri.toString().nullable); 46 SymbolTool.instance.importPath(uri); 47 AnalysisTool.instance.addAnalysisConfig(uri); 48 } 49 50 immutable conf = !initState.capabilities.workspace.isNull 51 && !initState.capabilities.workspace.configuration.isNull 52 && initState.capabilities.workspace.configuration; 53 54 if (conf) 55 { 56 send(Workspace.configuration, new ConfigurationParams(items)); 57 } 58 } 59 } 60 61 void didChangeWorkspaceFolders(DidChangeWorkspaceFoldersParams params) 62 { 63 import dls.tools.analysis_tool : AnalysisTool; 64 import dls.tools.symbol_tool : SymbolTool; 65 import dls.tools.tool : Tool; 66 import dls.util.uri : Uri; 67 import std.typecons : nullable; 68 69 workspaceFolders(null, params.event.added.nullable); 70 71 foreach (folder; params.event.removed) 72 { 73 auto uri = new Uri(folder.uri); 74 SymbolTool.instance.clearPath(uri); 75 AnalysisTool.instance.removeAnalysisConfig(uri); 76 Tool.removeConfig(uri); 77 } 78 } 79 80 void configuration(string id, JSONValue[] configs) 81 { 82 import dls.protocol.logger : logger; 83 import dls.tools.tool : Tool; 84 85 auto uris = null ~ Tool.workspacesUris; 86 87 logger.info("Updating workspace configurations"); 88 89 for (size_t i; i < configs.length && i < uris.length; ++i) 90 { 91 auto config = configs[i]; 92 93 if ("d" in config && "dls" in config["d"]) 94 { 95 Tool.updateConfig(uris[i], config["d"]["dls"]); 96 } 97 } 98 } 99 100 void didChangeConfiguration(DidChangeConfigurationParams params) 101 { 102 import dls.protocol.jsonrpc : send; 103 import dls.protocol.logger : logger; 104 import dls.protocol.messages.methods : Workspace; 105 import dls.protocol.state : initState; 106 import dls.tools.configuration : Configuration; 107 import dls.tools.tool : Tool; 108 import std.typecons : Nullable, nullable; 109 110 logger.info("Configuration changed"); 111 112 immutable conf = !initState.capabilities.workspace.isNull 113 && !initState.capabilities.workspace.configuration.isNull 114 && initState.capabilities.workspace.configuration; 115 116 if (conf) 117 { 118 auto items = [new ConfigurationItem(Nullable!string(null))]; 119 120 foreach (uri; Tool.workspacesUris) 121 { 122 items ~= new ConfigurationItem(uri.toString().nullable); 123 } 124 125 send(Workspace.configuration, new ConfigurationParams(items)); 126 } 127 else if ("d" in params.settings && "dls" in params.settings["d"]) 128 { 129 logger.info("Updating configuration"); 130 Tool.updateConfig(null, params.settings["d"]["dls"]); 131 } 132 } 133 134 void didChangeWatchedFiles(DidChangeWatchedFilesParams params) 135 { 136 import dls.protocol.interfaces : FileChangeType, PublishDiagnosticsParams; 137 import dls.protocol.jsonrpc : send; 138 import dls.protocol.logger : logger; 139 import dls.protocol.messages.methods : TextDocument; 140 import dls.tools.analysis_tool : AnalysisTool; 141 import dls.tools.symbol_tool : SymbolTool; 142 import dls.util.document : Document; 143 import dls.util.uri : Uri, sameFile; 144 import std.algorithm : canFind, filter, startsWith; 145 import std.file : exists, isFile; 146 import std.path : baseName, dirName, extension, pathSplitter; 147 148 foreach (event; params.changes.filter!(event => event.type == FileChangeType.deleted)) 149 { 150 auto workspaceUri = SymbolTool.instance.getWorkspace(new Uri(event.uri)); 151 152 if (workspaceUri !is null && !exists(workspaceUri.path)) 153 { 154 SymbolTool.instance.clearPath(workspaceUri); 155 } 156 } 157 158 outer: foreach (event; params.changes) 159 { 160 auto uri = new Uri(event.uri); 161 auto dirPath = dirName(uri.path); 162 163 foreach (part; pathSplitter(dirPath)) 164 { 165 if (part.startsWith('.')) 166 { 167 continue outer; 168 } 169 } 170 171 auto dirUri = Uri.fromPath(dirPath); 172 173 logger.info("Resource %s: %s", event.type, uri.path); 174 175 if (exists(uri.path) && !isFile(uri.path)) 176 { 177 continue; 178 } 179 180 switch (baseName(uri.path)) 181 { 182 case "dub.json", "dub.sdl": 183 if (event.type != FileChangeType.deleted) 184 { 185 SymbolTool.instance.importDubProject(dirUri); 186 } 187 188 continue; 189 190 case "dub.selections.json": 191 if (event.type != FileChangeType.deleted) 192 { 193 SymbolTool.instance.importDubSelections(dirUri); 194 } 195 196 continue; 197 198 case ".gitmodules": 199 if (event.type != FileChangeType.deleted) 200 { 201 SymbolTool.instance.importGitSubmodules(dirUri); 202 } 203 204 continue; 205 206 default: 207 break; 208 } 209 210 switch (extension(uri.path)) 211 { 212 case ".d", ".di": 213 if (event.type != FileChangeType.deleted 214 && !Document.uris.canFind!sameFile(uri) 215 && SymbolTool.instance.workspacesFilesUris.canFind!sameFile(uri)) 216 { 217 send(TextDocument.publishDiagnostics, new PublishDiagnosticsParams(uri, 218 AnalysisTool.instance.diagnostics(uri))); 219 } 220 221 continue; 222 223 case ".ini": 224 AnalysisTool.instance.updateAnalysisConfig(dirUri); 225 continue; 226 227 default: 228 break; 229 } 230 } 231 } 232 233 SymbolInformation[] symbol(WorkspaceSymbolParams params) 234 { 235 import dls.tools.symbol_tool : SymbolTool; 236 237 return SymbolTool.instance.symbol(params.query); 238 } 239 240 JSONValue executeCommand(ExecuteCommandParams params) 241 { 242 import dls.tools.command_tool : CommandTool; 243 244 return CommandTool.instance.executeCommand(params.command, 245 params.arguments.isNull ? [] : params.arguments.get()); 246 } 247 248 void applyEdit(string id, ApplyWorkspaceEditResponse response) 249 { 250 }