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