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.text_document; 22 23 import dls.protocol.definitions; 24 import dls.protocol.interfaces.text_document; 25 import std.json : JSONValue; 26 import std.typecons : Nullable; 27 28 void didOpen(DidOpenTextDocumentParams params) 29 { 30 import dls.protocol.interfaces : PublishDiagnosticsParams; 31 import dls.protocol.jsonrpc : send; 32 import dls.protocol.logger : logger; 33 import dls.protocol.messages.methods : TextDocument; 34 import dls.tools.analysis_tool : AnalysisTool; 35 import dls.tools.symbol_tool : SymbolTool; 36 import dls.util.document : Document; 37 import dls.util.uri : Uri, sameFile; 38 import std.algorithm : canFind; 39 import std.uni : toLower; 40 41 auto uri = new Uri(params.textDocument.uri); 42 logger.info("Document opened: %s", uri.path); 43 44 if (!SymbolTool.instance.workspacesFilesUris.canFind!sameFile(uri)) 45 { 46 send(TextDocument.publishDiagnostics, new PublishDiagnosticsParams(uri, 47 AnalysisTool.instance.diagnostics(uri))); 48 } 49 50 if (!Document.open(params.textDocument)) 51 { 52 logger.warning("Document %s is already open", uri.path); 53 } 54 } 55 56 void didChange(DidChangeTextDocumentParams params) 57 { 58 import dls.protocol.logger : logger; 59 import dls.util.document : Document; 60 import dls.util.uri : Uri; 61 62 auto uri = new Uri(params.textDocument.uri); 63 logger.info("Document changed: %s", uri.path); 64 65 if (!Document.change(params.textDocument, params.contentChanges)) 66 { 67 logger.warning("Document %s is not open", uri.path); 68 } 69 } 70 71 void willSave(WillSaveTextDocumentParams params) 72 { 73 if (scanOnWillSave(true)) 74 { 75 scanDocument(params.textDocument); 76 } 77 } 78 79 TextEdit[] willSaveWaitUntil(WillSaveTextDocumentParams params) 80 { 81 return []; 82 } 83 84 void didSave(DidSaveTextDocumentParams params) 85 { 86 if (!scanOnWillSave(false)) 87 { 88 scanDocument(params.textDocument); 89 } 90 } 91 92 void didClose(DidCloseTextDocumentParams params) 93 { 94 import dls.protocol.interfaces : PublishDiagnosticsParams; 95 import dls.protocol.jsonrpc : send; 96 import dls.protocol.logger : logger; 97 import dls.protocol.messages.methods : TextDocument; 98 import dls.tools.analysis_tool : AnalysisTool; 99 import dls.util.document : Document; 100 import dls.util.uri : Uri, sameFile; 101 import std.algorithm : canFind; 102 103 auto uri = new Uri(params.textDocument.uri); 104 logger.info("Document closed: %s", uri.path); 105 106 if (!Document.close(params.textDocument)) 107 { 108 logger.warning("Document %s is not open", uri.path); 109 } 110 111 Uri[] discaredFiles; 112 113 if (!AnalysisTool.instance.getScannableFilesUris(discaredFiles).canFind!sameFile(uri)) 114 { 115 send(TextDocument.publishDiagnostics, new PublishDiagnosticsParams(uri, [])); 116 } 117 } 118 119 CompletionItem[] completion(CompletionParams params) 120 { 121 import dls.tools.symbol_tool : SymbolTool; 122 import dls.util.uri : Uri; 123 124 return SymbolTool.instance.completion(new Uri(params.textDocument.uri), params.position); 125 } 126 127 @("completionItem", "resolve") 128 CompletionItem completionItem_resolve(CompletionItem item) 129 { 130 import dls.tools.symbol_tool : SymbolTool; 131 132 return SymbolTool.instance.completionResolve(item); 133 } 134 135 Hover hover(TextDocumentPositionParams params) 136 { 137 import dls.tools.symbol_tool : SymbolTool; 138 import dls.util.uri : Uri; 139 140 return SymbolTool.instance.hover(new Uri(params.textDocument.uri), params.position); 141 } 142 143 SignatureHelp signatureHelp(TextDocumentPositionParams params) 144 { 145 return null; 146 } 147 148 Location[] declaration(TextDocumentPositionParams params) 149 { 150 return definition(params); 151 } 152 153 Location[] definition(TextDocumentPositionParams params) 154 { 155 import dls.tools.symbol_tool : SymbolTool; 156 import dls.util.uri : Uri; 157 158 return SymbolTool.instance.definition(new Uri(params.textDocument.uri), params.position); 159 } 160 161 Location[] typeDefinition(TextDocumentPositionParams params) 162 { 163 import dls.tools.symbol_tool : SymbolTool; 164 import dls.util.uri : Uri; 165 166 return SymbolTool.instance.typeDefinition(new Uri(params.textDocument.uri), params.position); 167 } 168 169 Location implementation(TextDocumentPositionParams params) 170 { 171 return null; 172 } 173 174 Location[] references(ReferenceParams params) 175 { 176 import dls.tools.symbol_tool : SymbolTool; 177 import dls.util.uri : Uri; 178 179 return SymbolTool.instance.references(new Uri(params.textDocument.uri), 180 params.position, params.context.includeDeclaration); 181 } 182 183 DocumentHighlight[] documentHighlight(TextDocumentPositionParams params) 184 { 185 import dls.tools.symbol_tool : SymbolTool; 186 import dls.util.uri : Uri; 187 188 return SymbolTool.instance.highlight(new Uri(params.textDocument.uri), params.position); 189 } 190 191 JSONValue documentSymbol(DocumentSymbolParams params) 192 { 193 import dls.protocol.state : initState; 194 import dls.tools.symbol_tool : SymbolTool; 195 import dls.util.json : convertToJSON; 196 import dls.util.uri : Uri; 197 198 auto uri = new Uri(params.textDocument.uri); 199 200 if (!initState.capabilities.textDocument.isNull && !initState.capabilities.textDocument.documentSymbol.isNull 201 && !initState.capabilities.textDocument.documentSymbol.hierarchicalDocumentSymbolSupport.isNull 202 && initState.capabilities.textDocument.documentSymbol.hierarchicalDocumentSymbolSupport) 203 { 204 return convertToJSON(SymbolTool.instance.symbol!DocumentSymbol(uri, null)); 205 } 206 else 207 { 208 return convertToJSON(SymbolTool.instance.symbol!SymbolInformation(uri, null)); 209 } 210 } 211 212 JSONValue codeAction(CodeActionParams params) 213 { 214 import dls.protocol.state : initState; 215 import dls.tools.analysis_tool : AnalysisTool; 216 import dls.util.json : convertToJSON; 217 import dls.util.uri : Uri; 218 219 if (initState.capabilities.textDocument.isNull || initState.capabilities.textDocument.codeAction.isNull 220 || initState.capabilities.textDocument.codeAction.codeActionLiteralSupport.isNull) 221 { 222 return convertToJSON(AnalysisTool.instance.codeAction(new Uri(params.textDocument.uri), 223 params.range, params.context.diagnostics, true)); 224 } 225 else 226 { 227 return convertToJSON(AnalysisTool.instance.codeAction(new Uri(params.textDocument.uri), 228 params.range, params.context.diagnostics, 229 params.context.only.isNull ? [] : params.context.only.get())); 230 } 231 } 232 233 CodeLens[] codeLens(CodeLensParams params) 234 { 235 return []; 236 } 237 238 @("codeLens", "resolve") 239 CodeLens codeLens_resolve(CodeLens codeLens) 240 { 241 return codeLens; 242 } 243 244 DocumentLink[] documentLink(DocumentLinkParams params) 245 { 246 return []; 247 } 248 249 @("documentLink", "resolve") 250 DocumentLink documentLink_resolve(DocumentLink link) 251 { 252 return link; 253 } 254 255 ColorInformation[] documentColor(DocumentColorParams params) 256 { 257 return []; 258 } 259 260 ColorPresentation[] colorPresentation(ColorPresentationParams params) 261 { 262 return []; 263 } 264 265 TextEdit[] formatting(DocumentFormattingParams params) 266 { 267 import dls.tools.format_tool : FormatTool; 268 import dls.util.uri : Uri; 269 270 return FormatTool.instance.formatting(new Uri(params.textDocument.uri), params.options); 271 } 272 273 TextEdit[] rangeFormatting(DocumentRangeFormattingParams params) 274 { 275 import dls.tools.format_tool : FormatTool; 276 import dls.util.uri : Uri; 277 278 return FormatTool.instance.rangeFormatting(new Uri(params.textDocument.uri), 279 params.range, params.options); 280 } 281 282 TextEdit[] onTypeFormatting(DocumentOnTypeFormattingParams params) 283 { 284 import dls.tools.format_tool : FormatTool; 285 import dls.util.uri : Uri; 286 287 return FormatTool.instance.onTypeFormatting(new Uri(params.textDocument.uri), 288 params.position, params.options); 289 } 290 291 WorkspaceEdit rename(RenameParams params) 292 { 293 import dls.tools.symbol_tool : SymbolTool; 294 import dls.util.uri : Uri; 295 296 return SymbolTool.instance.rename(new Uri(params.textDocument.uri), 297 params.position, params.newName); 298 } 299 300 Range prepareRename(TextDocumentPositionParams params) 301 { 302 import dls.tools.symbol_tool : SymbolTool; 303 import dls.util.uri : Uri; 304 305 return SymbolTool.instance.prepareRename(new Uri(params.textDocument.uri), params.position); 306 } 307 308 FoldingRange[] foldingRange(FoldingRangeParams params) 309 { 310 return []; 311 } 312 313 private bool scanOnWillSave(bool will) 314 { 315 import std.functional : memoize; 316 317 static bool result; 318 319 static bool impl() 320 { 321 return result; 322 } 323 324 result = will; 325 return memoize!impl(); 326 } 327 328 private void scanDocument(const TextDocumentIdentifier textDocument) 329 { 330 import dls.protocol.interfaces : PublishDiagnosticsParams; 331 import dls.protocol.jsonrpc : send; 332 import dls.protocol.logger : logger; 333 import dls.protocol.messages.methods : TextDocument; 334 import dls.tools.analysis_tool : AnalysisTool; 335 import dls.util.uri : Uri; 336 337 auto uri = new Uri(textDocument.uri); 338 logger.info("Document saved: %s", uri.path); 339 send(TextDocument.publishDiagnostics, new PublishDiagnosticsParams(uri, 340 AnalysisTool.instance.diagnostics(uri))); 341 }