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