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