MLIR  20.0.0git
Protocol.cpp
Go to the documentation of this file.
1 //===--- Protocol.cpp - Language Server Protocol Implementation -----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains the serialization code for the LSP structs.
10 //
11 //===----------------------------------------------------------------------===//
12 
15 #include "llvm/ADT/Hashing.h"
16 #include "llvm/ADT/SmallString.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/ADT/StringSet.h"
19 #include "llvm/Support/ErrorHandling.h"
20 #include "llvm/Support/Format.h"
21 #include "llvm/Support/FormatVariadic.h"
22 #include "llvm/Support/JSON.h"
23 #include "llvm/Support/MemoryBuffer.h"
24 #include "llvm/Support/Path.h"
25 #include "llvm/Support/raw_ostream.h"
26 
27 using namespace mlir;
28 using namespace mlir::lsp;
29 
30 // Helper that doesn't treat `null` and absent fields as failures.
31 template <typename T>
32 static bool mapOptOrNull(const llvm::json::Value &params,
33  llvm::StringLiteral prop, T &out,
34  llvm::json::Path path) {
35  const llvm::json::Object *o = params.getAsObject();
36  assert(o);
37 
38  // Field is missing or null.
39  auto *v = o->get(prop);
40  if (!v || v->getAsNull())
41  return true;
42  return fromJSON(*v, out, path.field(prop));
43 }
44 
45 //===----------------------------------------------------------------------===//
46 // LSPError
47 //===----------------------------------------------------------------------===//
48 
49 char LSPError::ID;
50 
51 //===----------------------------------------------------------------------===//
52 // URIForFile
53 //===----------------------------------------------------------------------===//
54 
55 static bool isWindowsPath(StringRef path) {
56  return path.size() > 1 && llvm::isAlpha(path[0]) && path[1] == ':';
57 }
58 
59 static bool isNetworkPath(StringRef path) {
60  return path.size() > 2 && path[0] == path[1] &&
61  llvm::sys::path::is_separator(path[0]);
62 }
63 
64 static bool shouldEscapeInURI(unsigned char c) {
65  // Unreserved characters.
66  if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
67  (c >= '0' && c <= '9'))
68  return false;
69 
70  switch (c) {
71  case '-':
72  case '_':
73  case '.':
74  case '~':
75  // '/' is only reserved when parsing.
76  case '/':
77  // ':' is only reserved for relative URI paths, which we doesn't produce.
78  case ':':
79  return false;
80  }
81  return true;
82 }
83 
84 /// Encodes a string according to percent-encoding.
85 /// - Unreserved characters are not escaped.
86 /// - Reserved characters always escaped with exceptions like '/'.
87 /// - All other characters are escaped.
88 static void percentEncode(StringRef content, std::string &out) {
89  for (unsigned char c : content) {
90  if (shouldEscapeInURI(c)) {
91  out.push_back('%');
92  out.push_back(llvm::hexdigit(c / 16));
93  out.push_back(llvm::hexdigit(c % 16));
94  } else {
95  out.push_back(c);
96  }
97  }
98 }
99 
100 /// Decodes a string according to percent-encoding.
101 static std::string percentDecode(StringRef content) {
102  std::string result;
103  for (auto i = content.begin(), e = content.end(); i != e; ++i) {
104  if (*i != '%') {
105  result += *i;
106  continue;
107  }
108  if (*i == '%' && i + 2 < content.end() && llvm::isHexDigit(*(i + 1)) &&
109  llvm::isHexDigit(*(i + 2))) {
110  result.push_back(llvm::hexFromNibbles(*(i + 1), *(i + 2)));
111  i += 2;
112  } else {
113  result.push_back(*i);
114  }
115  }
116  return result;
117 }
118 
119 /// Return the set containing the supported URI schemes.
121  static StringSet<> schemes({"file", "test"});
122  return schemes;
123 }
124 
125 /// Returns true if the given scheme is structurally valid, i.e. it does not
126 /// contain any invalid scheme characters. This does not check that the scheme
127 /// is actually supported.
128 static bool isStructurallyValidScheme(StringRef scheme) {
129  if (scheme.empty())
130  return false;
131  if (!llvm::isAlpha(scheme[0]))
132  return false;
133  return llvm::all_of(llvm::drop_begin(scheme), [](char c) {
134  return llvm::isAlnum(c) || c == '+' || c == '.' || c == '-';
135  });
136 }
137 
138 static llvm::Expected<std::string> uriFromAbsolutePath(StringRef absolutePath,
139  StringRef scheme) {
140  std::string body;
141  StringRef authority;
142  StringRef root = llvm::sys::path::root_name(absolutePath);
143  if (isNetworkPath(root)) {
144  // Windows UNC paths e.g. \\server\share => file://server/share
145  authority = root.drop_front(2);
146  absolutePath.consume_front(root);
147  } else if (isWindowsPath(root)) {
148  // Windows paths e.g. X:\path => file:///X:/path
149  body = "/";
150  }
151  body += llvm::sys::path::convert_to_slash(absolutePath);
152 
153  std::string uri = scheme.str() + ":";
154  if (authority.empty() && body.empty())
155  return uri;
156 
157  // If authority if empty, we only print body if it starts with "/"; otherwise,
158  // the URI is invalid.
159  if (!authority.empty() || StringRef(body).starts_with("/")) {
160  uri.append("//");
161  percentEncode(authority, uri);
162  }
163  percentEncode(body, uri);
164  return uri;
165 }
166 
167 static llvm::Expected<std::string> getAbsolutePath(StringRef authority,
168  StringRef body) {
169  if (!body.starts_with("/"))
170  return llvm::createStringError(
171  llvm::inconvertibleErrorCode(),
172  "File scheme: expect body to be an absolute path starting "
173  "with '/': " +
174  body);
175  SmallString<128> path;
176  if (!authority.empty()) {
177  // Windows UNC paths e.g. file://server/share => \\server\share
178  ("//" + authority).toVector(path);
179  } else if (isWindowsPath(body.substr(1))) {
180  // Windows paths e.g. file:///X:/path => X:\path
181  body.consume_front("/");
182  }
183  path.append(body);
184  llvm::sys::path::native(path);
185  return std::string(path);
186 }
187 
189  StringRef uri = origUri;
190 
191  // Decode the scheme of the URI.
192  size_t pos = uri.find(':');
193  if (pos == StringRef::npos)
194  return llvm::createStringError(llvm::inconvertibleErrorCode(),
195  "Scheme must be provided in URI: " +
196  origUri);
197  StringRef schemeStr = uri.substr(0, pos);
198  std::string uriScheme = percentDecode(schemeStr);
199  if (!isStructurallyValidScheme(uriScheme))
200  return llvm::createStringError(llvm::inconvertibleErrorCode(),
201  "Invalid scheme: " + schemeStr +
202  " (decoded: " + uriScheme + ")");
203  uri = uri.substr(pos + 1);
204 
205  // Decode the authority of the URI.
206  std::string uriAuthority;
207  if (uri.consume_front("//")) {
208  pos = uri.find('/');
209  uriAuthority = percentDecode(uri.substr(0, pos));
210  uri = uri.substr(pos);
211  }
212 
213  // Decode the body of the URI.
214  std::string uriBody = percentDecode(uri);
215 
216  // Compute the absolute path for this uri.
217  if (!getSupportedSchemes().contains(uriScheme)) {
218  return llvm::createStringError(llvm::inconvertibleErrorCode(),
219  "unsupported URI scheme `" + uriScheme +
220  "' for workspace files");
221  }
222  return getAbsolutePath(uriAuthority, uriBody);
223 }
224 
227  if (!filePath)
228  return filePath.takeError();
229  return URIForFile(std::move(*filePath), uri.str());
230 }
231 
233  StringRef scheme) {
235  uriFromAbsolutePath(absoluteFilepath, scheme);
236  if (!uri)
237  return uri.takeError();
238  return fromURI(*uri);
239 }
240 
241 StringRef URIForFile::scheme() const { return uri().split(':').first; }
242 
243 void URIForFile::registerSupportedScheme(StringRef scheme) {
244  getSupportedSchemes().insert(scheme);
245 }
246 
247 bool mlir::lsp::fromJSON(const llvm::json::Value &value, URIForFile &result,
248  llvm::json::Path path) {
249  if (std::optional<StringRef> str = value.getAsString()) {
251  if (!expectedURI) {
252  path.report("unresolvable URI");
253  consumeError(expectedURI.takeError());
254  return false;
255  }
256  result = std::move(*expectedURI);
257  return true;
258  }
259  return false;
260 }
261 
262 llvm::json::Value mlir::lsp::toJSON(const URIForFile &value) {
263  return value.uri();
264 }
265 
266 raw_ostream &mlir::lsp::operator<<(raw_ostream &os, const URIForFile &value) {
267  return os << value.uri();
268 }
269 
270 //===----------------------------------------------------------------------===//
271 // ClientCapabilities
272 //===----------------------------------------------------------------------===//
273 
274 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
275  ClientCapabilities &result, llvm::json::Path path) {
276  const llvm::json::Object *o = value.getAsObject();
277  if (!o) {
278  path.report("expected object");
279  return false;
280  }
281  if (const llvm::json::Object *textDocument = o->getObject("textDocument")) {
282  if (const llvm::json::Object *documentSymbol =
283  textDocument->getObject("documentSymbol")) {
284  if (std::optional<bool> hierarchicalSupport =
285  documentSymbol->getBoolean("hierarchicalDocumentSymbolSupport"))
286  result.hierarchicalDocumentSymbol = *hierarchicalSupport;
287  }
288  if (auto *codeAction = textDocument->getObject("codeAction")) {
289  if (codeAction->getObject("codeActionLiteralSupport"))
290  result.codeActionStructure = true;
291  }
292  }
293  return true;
294 }
295 
296 //===----------------------------------------------------------------------===//
297 // ClientInfo
298 //===----------------------------------------------------------------------===//
299 
300 bool mlir::lsp::fromJSON(const llvm::json::Value &value, ClientInfo &result,
301  llvm::json::Path path) {
302  llvm::json::ObjectMapper o(value, path);
303  if (!o || !o.map("name", result.name))
304  return false;
305 
306  // Don't fail if we can't parse version.
307  o.map("version", result.version);
308  return true;
309 }
310 
311 //===----------------------------------------------------------------------===//
312 // InitializeParams
313 //===----------------------------------------------------------------------===//
314 
315 bool mlir::lsp::fromJSON(const llvm::json::Value &value, TraceLevel &result,
316  llvm::json::Path path) {
317  if (std::optional<StringRef> str = value.getAsString()) {
318  if (*str == "off") {
319  result = TraceLevel::Off;
320  return true;
321  }
322  if (*str == "messages") {
323  result = TraceLevel::Messages;
324  return true;
325  }
326  if (*str == "verbose") {
327  result = TraceLevel::Verbose;
328  return true;
329  }
330  }
331  return false;
332 }
333 
334 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
335  InitializeParams &result, llvm::json::Path path) {
336  llvm::json::ObjectMapper o(value, path);
337  if (!o)
338  return false;
339  // We deliberately don't fail if we can't parse individual fields.
340  o.map("capabilities", result.capabilities);
341  o.map("trace", result.trace);
342  mapOptOrNull(value, "clientInfo", result.clientInfo, path);
343 
344  return true;
345 }
346 
347 //===----------------------------------------------------------------------===//
348 // TextDocumentItem
349 //===----------------------------------------------------------------------===//
350 
351 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
352  TextDocumentItem &result, llvm::json::Path path) {
353  llvm::json::ObjectMapper o(value, path);
354  return o && o.map("uri", result.uri) &&
355  o.map("languageId", result.languageId) && o.map("text", result.text) &&
356  o.map("version", result.version);
357 }
358 
359 //===----------------------------------------------------------------------===//
360 // TextDocumentIdentifier
361 //===----------------------------------------------------------------------===//
362 
363 llvm::json::Value mlir::lsp::toJSON(const TextDocumentIdentifier &value) {
364  return llvm::json::Object{{"uri", value.uri}};
365 }
366 
367 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
368  TextDocumentIdentifier &result,
369  llvm::json::Path path) {
370  llvm::json::ObjectMapper o(value, path);
371  return o && o.map("uri", result.uri);
372 }
373 
374 //===----------------------------------------------------------------------===//
375 // VersionedTextDocumentIdentifier
376 //===----------------------------------------------------------------------===//
377 
378 llvm::json::Value
380  return llvm::json::Object{
381  {"uri", value.uri},
382  {"version", value.version},
383  };
384 }
385 
386 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
388  llvm::json::Path path) {
389  llvm::json::ObjectMapper o(value, path);
390  return o && o.map("uri", result.uri) && o.map("version", result.version);
391 }
392 
393 //===----------------------------------------------------------------------===//
394 // Position
395 //===----------------------------------------------------------------------===//
396 
397 bool mlir::lsp::fromJSON(const llvm::json::Value &value, Position &result,
398  llvm::json::Path path) {
399  llvm::json::ObjectMapper o(value, path);
400  return o && o.map("line", result.line) &&
401  o.map("character", result.character);
402 }
403 
404 llvm::json::Value mlir::lsp::toJSON(const Position &value) {
405  return llvm::json::Object{
406  {"line", value.line},
407  {"character", value.character},
408  };
409 }
410 
411 raw_ostream &mlir::lsp::operator<<(raw_ostream &os, const Position &value) {
412  return os << value.line << ':' << value.character;
413 }
414 
415 //===----------------------------------------------------------------------===//
416 // Range
417 //===----------------------------------------------------------------------===//
418 
419 bool mlir::lsp::fromJSON(const llvm::json::Value &value, Range &result,
420  llvm::json::Path path) {
421  llvm::json::ObjectMapper o(value, path);
422  return o && o.map("start", result.start) && o.map("end", result.end);
423 }
424 
425 llvm::json::Value mlir::lsp::toJSON(const Range &value) {
426  return llvm::json::Object{
427  {"start", value.start},
428  {"end", value.end},
429  };
430 }
431 
432 raw_ostream &mlir::lsp::operator<<(raw_ostream &os, const Range &value) {
433  return os << value.start << '-' << value.end;
434 }
435 
436 //===----------------------------------------------------------------------===//
437 // Location
438 //===----------------------------------------------------------------------===//
439 
440 bool mlir::lsp::fromJSON(const llvm::json::Value &value, Location &result,
441  llvm::json::Path path) {
442  llvm::json::ObjectMapper o(value, path);
443  return o && o.map("uri", result.uri) && o.map("range", result.range);
444 }
445 
446 llvm::json::Value mlir::lsp::toJSON(const Location &value) {
447  return llvm::json::Object{
448  {"uri", value.uri},
449  {"range", value.range},
450  };
451 }
452 
453 raw_ostream &mlir::lsp::operator<<(raw_ostream &os, const Location &value) {
454  return os << value.range << '@' << value.uri;
455 }
456 
457 //===----------------------------------------------------------------------===//
458 // TextDocumentPositionParams
459 //===----------------------------------------------------------------------===//
460 
461 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
463  llvm::json::Path path) {
464  llvm::json::ObjectMapper o(value, path);
465  return o && o.map("textDocument", result.textDocument) &&
466  o.map("position", result.position);
467 }
468 
469 //===----------------------------------------------------------------------===//
470 // ReferenceParams
471 //===----------------------------------------------------------------------===//
472 
473 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
474  ReferenceContext &result, llvm::json::Path path) {
475  llvm::json::ObjectMapper o(value, path);
476  return o && o.mapOptional("includeDeclaration", result.includeDeclaration);
477 }
478 
479 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
480  ReferenceParams &result, llvm::json::Path path) {
481  TextDocumentPositionParams &base = result;
482  llvm::json::ObjectMapper o(value, path);
483  return fromJSON(value, base, path) && o &&
484  o.mapOptional("context", result.context);
485 }
486 
487 //===----------------------------------------------------------------------===//
488 // DidOpenTextDocumentParams
489 //===----------------------------------------------------------------------===//
490 
491 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
493  llvm::json::Path path) {
494  llvm::json::ObjectMapper o(value, path);
495  return o && o.map("textDocument", result.textDocument);
496 }
497 
498 //===----------------------------------------------------------------------===//
499 // DidCloseTextDocumentParams
500 //===----------------------------------------------------------------------===//
501 
502 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
504  llvm::json::Path path) {
505  llvm::json::ObjectMapper o(value, path);
506  return o && o.map("textDocument", result.textDocument);
507 }
508 
509 //===----------------------------------------------------------------------===//
510 // DidChangeTextDocumentParams
511 //===----------------------------------------------------------------------===//
512 
513 LogicalResult
514 TextDocumentContentChangeEvent::applyTo(std::string &contents) const {
515  // If there is no range, the full document changed.
516  if (!range) {
517  contents = text;
518  return success();
519  }
520 
521  // Try to map the replacement range to the content.
522  llvm::SourceMgr tmpScrMgr;
523  tmpScrMgr.AddNewSourceBuffer(llvm::MemoryBuffer::getMemBuffer(contents),
524  SMLoc());
525  SMRange rangeLoc = range->getAsSMRange(tmpScrMgr);
526  if (!rangeLoc.isValid())
527  return failure();
528 
529  contents.replace(rangeLoc.Start.getPointer() - contents.data(),
530  rangeLoc.End.getPointer() - rangeLoc.Start.getPointer(),
531  text);
532  return success();
533 }
534 
536  ArrayRef<TextDocumentContentChangeEvent> changes, std::string &contents) {
537  for (const auto &change : changes)
538  if (failed(change.applyTo(contents)))
539  return failure();
540  return success();
541 }
542 
543 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
545  llvm::json::Path path) {
546  llvm::json::ObjectMapper o(value, path);
547  return o && o.map("range", result.range) &&
548  o.map("rangeLength", result.rangeLength) && o.map("text", result.text);
549 }
550 
551 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
553  llvm::json::Path path) {
554  llvm::json::ObjectMapper o(value, path);
555  return o && o.map("textDocument", result.textDocument) &&
556  o.map("contentChanges", result.contentChanges);
557 }
558 
559 //===----------------------------------------------------------------------===//
560 // MarkupContent
561 //===----------------------------------------------------------------------===//
562 
563 static llvm::StringRef toTextKind(MarkupKind kind) {
564  switch (kind) {
566  return "plaintext";
568  return "markdown";
569  }
570  llvm_unreachable("Invalid MarkupKind");
571 }
572 
573 raw_ostream &mlir::lsp::operator<<(raw_ostream &os, MarkupKind kind) {
574  return os << toTextKind(kind);
575 }
576 
577 llvm::json::Value mlir::lsp::toJSON(const MarkupContent &mc) {
578  if (mc.value.empty())
579  return nullptr;
580 
581  return llvm::json::Object{
582  {"kind", toTextKind(mc.kind)},
583  {"value", mc.value},
584  };
585 }
586 
587 //===----------------------------------------------------------------------===//
588 // Hover
589 //===----------------------------------------------------------------------===//
590 
591 llvm::json::Value mlir::lsp::toJSON(const Hover &hover) {
592  llvm::json::Object result{{"contents", toJSON(hover.contents)}};
593  if (hover.range)
594  result["range"] = toJSON(*hover.range);
595  return std::move(result);
596 }
597 
598 //===----------------------------------------------------------------------===//
599 // DocumentSymbol
600 //===----------------------------------------------------------------------===//
601 
602 llvm::json::Value mlir::lsp::toJSON(const DocumentSymbol &symbol) {
603  llvm::json::Object result{{"name", symbol.name},
604  {"kind", static_cast<int>(symbol.kind)},
605  {"range", symbol.range},
606  {"selectionRange", symbol.selectionRange}};
607 
608  if (!symbol.detail.empty())
609  result["detail"] = symbol.detail;
610  if (!symbol.children.empty())
611  result["children"] = symbol.children;
612  return std::move(result);
613 }
614 
615 //===----------------------------------------------------------------------===//
616 // DocumentSymbolParams
617 //===----------------------------------------------------------------------===//
618 
619 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
620  DocumentSymbolParams &result, llvm::json::Path path) {
621  llvm::json::ObjectMapper o(value, path);
622  return o && o.map("textDocument", result.textDocument);
623 }
624 
625 //===----------------------------------------------------------------------===//
626 // DiagnosticRelatedInformation
627 //===----------------------------------------------------------------------===//
628 
629 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
631  llvm::json::Path path) {
632  llvm::json::ObjectMapper o(value, path);
633  return o && o.map("location", result.location) &&
634  o.map("message", result.message);
635 }
636 
637 llvm::json::Value mlir::lsp::toJSON(const DiagnosticRelatedInformation &info) {
638  return llvm::json::Object{
639  {"location", info.location},
640  {"message", info.message},
641  };
642 }
643 
644 //===----------------------------------------------------------------------===//
645 // Diagnostic
646 //===----------------------------------------------------------------------===//
647 
648 llvm::json::Value mlir::lsp::toJSON(DiagnosticTag tag) {
649  return static_cast<int>(tag);
650 }
651 
652 bool mlir::lsp::fromJSON(const llvm::json::Value &value, DiagnosticTag &result,
653  llvm::json::Path path) {
654  if (std::optional<int64_t> i = value.getAsInteger()) {
655  result = (DiagnosticTag)*i;
656  return true;
657  }
658 
659  return false;
660 }
661 
662 llvm::json::Value mlir::lsp::toJSON(const Diagnostic &diag) {
663  llvm::json::Object result{
664  {"range", diag.range},
665  {"severity", (int)diag.severity},
666  {"message", diag.message},
667  };
668  if (diag.category)
669  result["category"] = *diag.category;
670  if (!diag.source.empty())
671  result["source"] = diag.source;
672  if (diag.relatedInformation)
673  result["relatedInformation"] = *diag.relatedInformation;
674  if (!diag.tags.empty())
675  result["tags"] = diag.tags;
676  return std::move(result);
677 }
678 
679 bool mlir::lsp::fromJSON(const llvm::json::Value &value, Diagnostic &result,
680  llvm::json::Path path) {
681  llvm::json::ObjectMapper o(value, path);
682  if (!o)
683  return false;
684  int severity = 0;
685  if (!mapOptOrNull(value, "severity", severity, path))
686  return false;
687  result.severity = (DiagnosticSeverity)severity;
688 
689  return o.map("range", result.range) && o.map("message", result.message) &&
690  mapOptOrNull(value, "category", result.category, path) &&
691  mapOptOrNull(value, "source", result.source, path) &&
692  mapOptOrNull(value, "relatedInformation", result.relatedInformation,
693  path) &&
694  mapOptOrNull(value, "tags", result.tags, path);
695 }
696 
697 //===----------------------------------------------------------------------===//
698 // PublishDiagnosticsParams
699 //===----------------------------------------------------------------------===//
700 
701 llvm::json::Value mlir::lsp::toJSON(const PublishDiagnosticsParams &params) {
702  return llvm::json::Object{
703  {"uri", params.uri},
704  {"diagnostics", params.diagnostics},
705  {"version", params.version},
706  };
707 }
708 
709 //===----------------------------------------------------------------------===//
710 // TextEdit
711 //===----------------------------------------------------------------------===//
712 
713 bool mlir::lsp::fromJSON(const llvm::json::Value &value, TextEdit &result,
714  llvm::json::Path path) {
715  llvm::json::ObjectMapper o(value, path);
716  return o && o.map("range", result.range) && o.map("newText", result.newText);
717 }
718 
719 llvm::json::Value mlir::lsp::toJSON(const TextEdit &value) {
720  return llvm::json::Object{
721  {"range", value.range},
722  {"newText", value.newText},
723  };
724 }
725 
726 raw_ostream &mlir::lsp::operator<<(raw_ostream &os, const TextEdit &value) {
727  os << value.range << " => \"";
728  llvm::printEscapedString(value.newText, os);
729  return os << '"';
730 }
731 
732 //===----------------------------------------------------------------------===//
733 // CompletionItemKind
734 //===----------------------------------------------------------------------===//
735 
736 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
737  CompletionItemKind &result, llvm::json::Path path) {
738  if (std::optional<int64_t> intValue = value.getAsInteger()) {
739  if (*intValue < static_cast<int>(CompletionItemKind::Text) ||
740  *intValue > static_cast<int>(CompletionItemKind::TypeParameter))
741  return false;
742  result = static_cast<CompletionItemKind>(*intValue);
743  return true;
744  }
745  return false;
746 }
747 
749  CompletionItemKind kind,
750  CompletionItemKindBitset &supportedCompletionItemKinds) {
751  size_t kindVal = static_cast<size_t>(kind);
752  if (kindVal >= kCompletionItemKindMin &&
753  kindVal <= supportedCompletionItemKinds.size() &&
754  supportedCompletionItemKinds[kindVal])
755  return kind;
756 
757  // Provide some fall backs for common kinds that are close enough.
758  switch (kind) {
765  default:
767  }
768 }
769 
770 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
771  CompletionItemKindBitset &result,
772  llvm::json::Path path) {
773  if (const llvm::json::Array *arrayValue = value.getAsArray()) {
774  for (size_t i = 0, e = arrayValue->size(); i < e; ++i) {
775  CompletionItemKind kindOut;
776  if (fromJSON((*arrayValue)[i], kindOut, path.index(i)))
777  result.set(size_t(kindOut));
778  }
779  return true;
780  }
781  return false;
782 }
783 
784 //===----------------------------------------------------------------------===//
785 // CompletionItem
786 //===----------------------------------------------------------------------===//
787 
788 llvm::json::Value mlir::lsp::toJSON(const CompletionItem &value) {
789  assert(!value.label.empty() && "completion item label is required");
790  llvm::json::Object result{{"label", value.label}};
791  if (value.kind != CompletionItemKind::Missing)
792  result["kind"] = static_cast<int>(value.kind);
793  if (!value.detail.empty())
794  result["detail"] = value.detail;
795  if (value.documentation)
796  result["documentation"] = value.documentation;
797  if (!value.sortText.empty())
798  result["sortText"] = value.sortText;
799  if (!value.filterText.empty())
800  result["filterText"] = value.filterText;
801  if (!value.insertText.empty())
802  result["insertText"] = value.insertText;
804  result["insertTextFormat"] = static_cast<int>(value.insertTextFormat);
805  if (value.textEdit)
806  result["textEdit"] = *value.textEdit;
807  if (!value.additionalTextEdits.empty()) {
808  result["additionalTextEdits"] =
809  llvm::json::Array(value.additionalTextEdits);
810  }
811  if (value.deprecated)
812  result["deprecated"] = value.deprecated;
813  return std::move(result);
814 }
815 
816 raw_ostream &mlir::lsp::operator<<(raw_ostream &os,
817  const CompletionItem &value) {
818  return os << value.label << " - " << toJSON(value);
819 }
820 
822  const CompletionItem &rhs) {
823  return (lhs.sortText.empty() ? lhs.label : lhs.sortText) <
824  (rhs.sortText.empty() ? rhs.label : rhs.sortText);
825 }
826 
827 //===----------------------------------------------------------------------===//
828 // CompletionList
829 //===----------------------------------------------------------------------===//
830 
831 llvm::json::Value mlir::lsp::toJSON(const CompletionList &value) {
832  return llvm::json::Object{
833  {"isIncomplete", value.isIncomplete},
834  {"items", llvm::json::Array(value.items)},
835  };
836 }
837 
838 //===----------------------------------------------------------------------===//
839 // CompletionContext
840 //===----------------------------------------------------------------------===//
841 
842 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
843  CompletionContext &result, llvm::json::Path path) {
844  llvm::json::ObjectMapper o(value, path);
845  int triggerKind;
846  if (!o || !o.map("triggerKind", triggerKind) ||
847  !mapOptOrNull(value, "triggerCharacter", result.triggerCharacter, path))
848  return false;
849  result.triggerKind = static_cast<CompletionTriggerKind>(triggerKind);
850  return true;
851 }
852 
853 //===----------------------------------------------------------------------===//
854 // CompletionParams
855 //===----------------------------------------------------------------------===//
856 
857 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
858  CompletionParams &result, llvm::json::Path path) {
859  if (!fromJSON(value, static_cast<TextDocumentPositionParams &>(result), path))
860  return false;
861  if (const llvm::json::Value *context = value.getAsObject()->get("context"))
862  return fromJSON(*context, result.context, path.field("context"));
863  return true;
864 }
865 
866 //===----------------------------------------------------------------------===//
867 // ParameterInformation
868 //===----------------------------------------------------------------------===//
869 
870 llvm::json::Value mlir::lsp::toJSON(const ParameterInformation &value) {
871  assert((value.labelOffsets || !value.labelString.empty()) &&
872  "parameter information label is required");
873  llvm::json::Object result;
874  if (value.labelOffsets)
875  result["label"] = llvm::json::Array(
876  {value.labelOffsets->first, value.labelOffsets->second});
877  else
878  result["label"] = value.labelString;
879  if (!value.documentation.empty())
880  result["documentation"] = value.documentation;
881  return std::move(result);
882 }
883 
884 //===----------------------------------------------------------------------===//
885 // SignatureInformation
886 //===----------------------------------------------------------------------===//
887 
888 llvm::json::Value mlir::lsp::toJSON(const SignatureInformation &value) {
889  assert(!value.label.empty() && "signature information label is required");
890  llvm::json::Object result{
891  {"label", value.label},
892  {"parameters", llvm::json::Array(value.parameters)},
893  };
894  if (!value.documentation.empty())
895  result["documentation"] = value.documentation;
896  return std::move(result);
897 }
898 
899 raw_ostream &mlir::lsp::operator<<(raw_ostream &os,
900  const SignatureInformation &value) {
901  return os << value.label << " - " << toJSON(value);
902 }
903 
904 //===----------------------------------------------------------------------===//
905 // SignatureHelp
906 //===----------------------------------------------------------------------===//
907 
908 llvm::json::Value mlir::lsp::toJSON(const SignatureHelp &value) {
909  assert(value.activeSignature >= 0 &&
910  "Unexpected negative value for number of active signatures.");
911  assert(value.activeParameter >= 0 &&
912  "Unexpected negative value for active parameter index");
913  return llvm::json::Object{
914  {"activeSignature", value.activeSignature},
915  {"activeParameter", value.activeParameter},
916  {"signatures", llvm::json::Array(value.signatures)},
917  };
918 }
919 
920 //===----------------------------------------------------------------------===//
921 // DocumentLinkParams
922 //===----------------------------------------------------------------------===//
923 
924 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
925  DocumentLinkParams &result, llvm::json::Path path) {
926  llvm::json::ObjectMapper o(value, path);
927  return o && o.map("textDocument", result.textDocument);
928 }
929 
930 //===----------------------------------------------------------------------===//
931 // DocumentLink
932 //===----------------------------------------------------------------------===//
933 
934 llvm::json::Value mlir::lsp::toJSON(const DocumentLink &value) {
935  return llvm::json::Object{
936  {"range", value.range},
937  {"target", value.target},
938  };
939 }
940 
941 //===----------------------------------------------------------------------===//
942 // InlayHintsParams
943 //===----------------------------------------------------------------------===//
944 
945 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
946  InlayHintsParams &result, llvm::json::Path path) {
947  llvm::json::ObjectMapper o(value, path);
948  return o && o.map("textDocument", result.textDocument) &&
949  o.map("range", result.range);
950 }
951 
952 //===----------------------------------------------------------------------===//
953 // InlayHint
954 //===----------------------------------------------------------------------===//
955 
956 llvm::json::Value mlir::lsp::toJSON(const InlayHint &value) {
957  return llvm::json::Object{{"position", value.position},
958  {"kind", (int)value.kind},
959  {"label", value.label},
960  {"paddingLeft", value.paddingLeft},
961  {"paddingRight", value.paddingRight}};
962 }
963 bool mlir::lsp::operator==(const InlayHint &lhs, const InlayHint &rhs) {
964  return std::tie(lhs.position, lhs.kind, lhs.label) ==
965  std::tie(rhs.position, rhs.kind, rhs.label);
966 }
967 bool mlir::lsp::operator<(const InlayHint &lhs, const InlayHint &rhs) {
968  return std::tie(lhs.position, lhs.kind, lhs.label) <
969  std::tie(rhs.position, rhs.kind, rhs.label);
970 }
971 
972 llvm::raw_ostream &mlir::lsp::operator<<(llvm::raw_ostream &os,
973  InlayHintKind value) {
974  switch (value) {
976  return os << "parameter";
977  case InlayHintKind::Type:
978  return os << "type";
979  }
980  llvm_unreachable("Unknown InlayHintKind");
981 }
982 
983 //===----------------------------------------------------------------------===//
984 // CodeActionContext
985 //===----------------------------------------------------------------------===//
986 
987 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
988  CodeActionContext &result, llvm::json::Path path) {
989  llvm::json::ObjectMapper o(value, path);
990  if (!o || !o.map("diagnostics", result.diagnostics))
991  return false;
992  o.map("only", result.only);
993  return true;
994 }
995 
996 //===----------------------------------------------------------------------===//
997 // CodeActionParams
998 //===----------------------------------------------------------------------===//
999 
1000 bool mlir::lsp::fromJSON(const llvm::json::Value &value,
1001  CodeActionParams &result, llvm::json::Path path) {
1002  llvm::json::ObjectMapper o(value, path);
1003  return o && o.map("textDocument", result.textDocument) &&
1004  o.map("range", result.range) && o.map("context", result.context);
1005 }
1006 
1007 //===----------------------------------------------------------------------===//
1008 // WorkspaceEdit
1009 //===----------------------------------------------------------------------===//
1010 
1011 bool mlir::lsp::fromJSON(const llvm::json::Value &value, WorkspaceEdit &result,
1012  llvm::json::Path path) {
1013  llvm::json::ObjectMapper o(value, path);
1014  return o && o.map("changes", result.changes);
1015 }
1016 
1017 llvm::json::Value mlir::lsp::toJSON(const WorkspaceEdit &value) {
1018  llvm::json::Object fileChanges;
1019  for (auto &change : value.changes)
1020  fileChanges[change.first] = llvm::json::Array(change.second);
1021  return llvm::json::Object{{"changes", std::move(fileChanges)}};
1022 }
1023 
1024 //===----------------------------------------------------------------------===//
1025 // CodeAction
1026 //===----------------------------------------------------------------------===//
1027 
1028 const llvm::StringLiteral CodeAction::kQuickFix = "quickfix";
1029 const llvm::StringLiteral CodeAction::kRefactor = "refactor";
1030 const llvm::StringLiteral CodeAction::kInfo = "info";
1031 
1032 llvm::json::Value mlir::lsp::toJSON(const CodeAction &value) {
1033  llvm::json::Object codeAction{{"title", value.title}};
1034  if (value.kind)
1035  codeAction["kind"] = *value.kind;
1036  if (value.diagnostics)
1037  codeAction["diagnostics"] = llvm::json::Array(*value.diagnostics);
1038  if (value.isPreferred)
1039  codeAction["isPreferred"] = true;
1040  if (value.edit)
1041  codeAction["edit"] = *value.edit;
1042  return std::move(codeAction);
1043 }
static std::string diag(const llvm::Value &value)
static char ID
Definition: Protocol.h:79
URI in "file" scheme for a file.
Definition: Protocol.h:97
StringRef uri() const
Returns the original uri of the file.
Definition: Protocol.h:113
static void registerSupportedScheme(StringRef scheme)
Register a supported URI scheme.
Definition: Protocol.cpp:243
static llvm::Expected< URIForFile > fromFile(StringRef absoluteFilepath, StringRef scheme="file")
Try to build a URIForFile from the given absolute file path and optional scheme.
Definition: Protocol.cpp:232
static llvm::Expected< URIForFile > fromURI(StringRef uri)
Try to build a URIForFile from the given URI string.
Definition: Protocol.cpp:225
StringRef scheme() const
Return the scheme of the uri.
Definition: Protocol.cpp:241
static llvm::Expected< std::string > uriFromAbsolutePath(StringRef absolutePath, StringRef scheme)
Definition: Protocol.cpp:138
static bool isNetworkPath(StringRef path)
Definition: Protocol.cpp:59
static llvm::Expected< std::string > getAbsolutePath(StringRef authority, StringRef body)
Definition: Protocol.cpp:167
static llvm::StringRef toTextKind(MarkupKind kind)
Definition: Protocol.cpp:563
static std::string percentDecode(StringRef content)
Decodes a string according to percent-encoding.
Definition: Protocol.cpp:101
static void percentEncode(StringRef content, std::string &out)
Encodes a string according to percent-encoding.
Definition: Protocol.cpp:88
static bool isStructurallyValidScheme(StringRef scheme)
Returns true if the given scheme is structurally valid, i.e.
Definition: Protocol.cpp:128
static StringSet & getSupportedSchemes()
Return the set containing the supported URI schemes.
Definition: Protocol.cpp:120
static bool isWindowsPath(StringRef path)
Definition: Protocol.cpp:55
static bool mapOptOrNull(const llvm::json::Value &params, llvm::StringLiteral prop, T &out, llvm::json::Path path)
Definition: Protocol.cpp:32
static llvm::Expected< std::string > parseFilePathFromURI(StringRef origUri)
Definition: Protocol.cpp:188
static bool shouldEscapeInURI(unsigned char c)
Definition: Protocol.cpp:64
llvm::json::Value toJSON(const URIForFile &value)
Add support for JSON serialization.
Definition: Protocol.cpp:262
raw_ostream & operator<<(raw_ostream &os, const URIForFile &value)
Definition: Protocol.cpp:266
DiagnosticSeverity
Definition: Protocol.h:667
bool operator<(const CompletionItem &lhs, const CompletionItem &rhs)
Definition: Protocol.cpp:821
constexpr auto kCompletionItemKindMin
Definition: Protocol.h:799
MarkupKind
Describes the content type that a client supports in various result literals like Hover.
Definition: Protocol.h:519
bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
bool fromJSON(const llvm::json::Value &value, URIForFile &result, llvm::json::Path path)
Definition: Protocol.cpp:247
CompletionItemKind adjustKindToCapability(CompletionItemKind kind, CompletionItemKindBitset &supportedCompletionItemKinds)
Definition: Protocol.cpp:748
std::bitset< kCompletionItemKindMax+1 > CompletionItemKindBitset
Definition: Protocol.h:803
CompletionTriggerKind
Definition: Protocol.h:913
InlayHintKind
Inlay hint kinds.
Definition: Protocol.h:1082
@ Parameter
An inlay hint that is for a parameter.
@ Type
An inlay hint that for a type annotation.
CompletionItemKind
The kind of a completion entry.
Definition: Protocol.h:768
bool operator==(const TextEdit &lhs, const TextEdit &rhs)
Definition: Protocol.h:754
Include the generated interface declarations.
bool codeActionStructure
Client supports CodeAction return value for textDocument/codeAction.
Definition: Protocol.h:160
bool hierarchicalDocumentSymbol
Client supports hierarchical document symbols.
Definition: Protocol.h:156
std::string name
The name of the client as defined by the client.
Definition: Protocol.h:173
std::optional< std::string > version
The client's version as defined by the client.
Definition: Protocol.h:176
std::vector< std::string > only
Requested kind of actions to return.
Definition: Protocol.h:1157
std::vector< Diagnostic > diagnostics
An array of diagnostics known on the client side overlapping the range provided to the textDocument/c...
Definition: Protocol.h:1151
TextDocumentIdentifier textDocument
The document in which the command was invoked.
Definition: Protocol.h:1170
Range range
The range for which the command was invoked.
Definition: Protocol.h:1173
CodeActionContext context
Context carrying additional information.
Definition: Protocol.h:1176
A code action represents a change that can be performed in code, e.g.
Definition: Protocol.h:1209
bool isPreferred
Marks this as a preferred action.
Definition: Protocol.h:1228
std::optional< WorkspaceEdit > edit
The workspace edit this code action performs.
Definition: Protocol.h:1231
std::optional< std::string > kind
The kind of the code action.
Definition: Protocol.h:1215
static const llvm::StringLiteral kRefactor
Definition: Protocol.h:1217
static const llvm::StringLiteral kInfo
Definition: Protocol.h:1218
std::optional< std::vector< Diagnostic > > diagnostics
The diagnostics that this code action resolves.
Definition: Protocol.h:1221
static const llvm::StringLiteral kQuickFix
Definition: Protocol.h:1216
std::string title
A short, human-readable, title for this code action.
Definition: Protocol.h:1211
std::string triggerCharacter
The trigger character (a single character) that has trigger code complete.
Definition: Protocol.h:932
CompletionTriggerKind triggerKind
How the completion was triggered.
Definition: Protocol.h:928
std::string detail
A human-readable string with additional information about this item, like type or symbol information.
Definition: Protocol.h:850
std::string filterText
A string that should be used when filtering a set of completion items.
Definition: Protocol.h:861
std::optional< TextEdit > textEdit
An edit which is applied to a document when selecting this completion.
Definition: Protocol.h:876
std::optional< MarkupContent > documentation
A human-readable string that represents a doc-comment.
Definition: Protocol.h:853
std::string insertText
A string that should be inserted to a document when selecting this completion.
Definition: Protocol.h:865
std::string label
The label of this completion item.
Definition: Protocol.h:842
bool deprecated
Indicates if this item is deprecated.
Definition: Protocol.h:884
CompletionItemKind kind
The kind of this completion item.
Definition: Protocol.h:846
std::vector< TextEdit > additionalTextEdits
An optional array of additional text edits that are applied when selecting this completion.
Definition: Protocol.h:881
InsertTextFormat insertTextFormat
The format of the insert text.
Definition: Protocol.h:869
std::string sortText
A string that should be used when comparing this item with other items.
Definition: Protocol.h:857
Represents a collection of completion items to be presented in the editor.
Definition: Protocol.h:897
std::vector< CompletionItem > items
The completion items.
Definition: Protocol.h:903
bool isIncomplete
The list is not complete.
Definition: Protocol.h:900
CompletionContext context
Definition: Protocol.h:944
Represents a related message and source code location for a diagnostic.
Definition: Protocol.h:647
std::string message
The message of this related diagnostic information.
Definition: Protocol.h:655
Location location
The location of this related diagnostic information.
Definition: Protocol.h:653
std::vector< DiagnosticTag > tags
Additional metadata about the diagnostic.
Definition: Protocol.h:707
std::string source
A human-readable string describing the source of this diagnostic, e.g.
Definition: Protocol.h:697
DiagnosticSeverity severity
The diagnostic's severity.
Definition: Protocol.h:693
Range range
The source range where the message applies.
Definition: Protocol.h:689
std::optional< std::vector< DiagnosticRelatedInformation > > relatedInformation
An array of related diagnostic information, e.g.
Definition: Protocol.h:704
std::string message
The diagnostic's message.
Definition: Protocol.h:700
std::optional< std::string > category
The diagnostic's category.
Definition: Protocol.h:713
VersionedTextDocumentIdentifier textDocument
The document that changed.
Definition: Protocol.h:503
std::vector< TextDocumentContentChangeEvent > contentChanges
The actual content changes.
Definition: Protocol.h:506
TextDocumentIdentifier textDocument
The document that was closed.
Definition: Protocol.h:469
TextDocumentItem textDocument
The document that was opened.
Definition: Protocol.h:456
Parameters for the document link request.
Definition: Protocol.h:1015
TextDocumentIdentifier textDocument
The document to provide document links for.
Definition: Protocol.h:1017
TextDocumentIdentifier textDocument
Definition: Protocol.h:633
Represents programming constructs like variables, classes, interfaces etc.
Definition: Protocol.h:593
std::string detail
More detail for this symbol, e.g the signature of a function.
Definition: Protocol.h:605
Range range
The range enclosing this symbol not including leading/trailing whitespace but everything else like co...
Definition: Protocol.h:614
Range selectionRange
The range that should be selected and revealed when this symbol is being picked, e....
Definition: Protocol.h:618
std::vector< DocumentSymbol > children
Children of this symbol, e.g. properties of a class.
Definition: Protocol.h:621
SymbolKind kind
The kind of this symbol.
Definition: Protocol.h:608
std::string name
The name of this symbol.
Definition: Protocol.h:602
std::optional< Range > range
An optional range is a range inside a text document that is used to visualize a hover,...
Definition: Protocol.h:546
MarkupContent contents
The hover's content.
Definition: Protocol.h:542
std::optional< ClientInfo > clientInfo
Information about the client.
Definition: Protocol.h:202
ClientCapabilities capabilities
The capabilities provided by the client (editor or tool).
Definition: Protocol.h:199
std::optional< TraceLevel > trace
The initial trace setting. If omitted trace is disabled ('off').
Definition: Protocol.h:205
Inlay hint information.
Definition: Protocol.h:1103
bool paddingLeft
Render padding before the hint.
Definition: Protocol.h:1124
InlayHintKind kind
The kind of this hint.
Definition: Protocol.h:1117
Position position
The position of this hint.
Definition: Protocol.h:1107
bool paddingRight
Render padding after the hint.
Definition: Protocol.h:1131
std::string label
The label of this hint.
Definition: Protocol.h:1113
A parameter literal used in inlay hint requests.
Definition: Protocol.h:1065
Range range
The visible document range for which inlay hints should be computed.
Definition: Protocol.h:1070
TextDocumentIdentifier textDocument
The text document.
Definition: Protocol.h:1067
URIForFile uri
The text document's URI.
Definition: Protocol.h:391
A single parameter of a particular signature.
Definition: Protocol.h:956
std::optional< std::pair< unsigned, unsigned > > labelOffsets
Inclusive start and exclusive end offsets withing the containing signature label.
Definition: Protocol.h:962
std::string labelString
The label of this parameter. Ignored when labelOffsets is set.
Definition: Protocol.h:958
std::string documentation
The documentation of this parameter. Optional.
Definition: Protocol.h:965
int line
Line position in a document (zero-based).
Definition: Protocol.h:290
int character
Character offset on a line in a document (zero-based).
Definition: Protocol.h:293
std::vector< Diagnostic > diagnostics
The list of reported diagnostics.
Definition: Protocol.h:732
URIForFile uri
The URI for which diagnostic information is reported.
Definition: Protocol.h:730
int64_t version
The version number of the document the diagnostics are published for.
Definition: Protocol.h:734
Position end
The range's end position.
Definition: Protocol.h:342
Position start
The range's start position.
Definition: Protocol.h:339
bool includeDeclaration
Include the declaration of the current symbol.
Definition: Protocol.h:435
ReferenceContext context
Definition: Protocol.h:443
Represents the signature of a callable.
Definition: Protocol.h:996
int activeSignature
The active signature.
Definition: Protocol.h:1001
int activeParameter
The active parameter of the active signature.
Definition: Protocol.h:1004
std::vector< SignatureInformation > signatures
The resulting signatures.
Definition: Protocol.h:998
Represents the signature of something callable.
Definition: Protocol.h:976
std::string label
The label of this signature. Mandatory.
Definition: Protocol.h:978
std::string documentation
The documentation of this signature. Optional.
Definition: Protocol.h:981
std::vector< ParameterInformation > parameters
The parameters of this signature.
Definition: Protocol.h:984
std::string text
The new text of the range/document.
Definition: Protocol.h:494
LogicalResult applyTo(std::string &contents) const
Try to apply this change to the given contents string.
Definition: Protocol.cpp:514
std::optional< Range > range
The range of the document that changed.
Definition: Protocol.h:488
std::optional< int > rangeLength
The length of the range that got replaced.
Definition: Protocol.h:491
URIForFile uri
The text document's URI.
Definition: Protocol.h:250
std::string languageId
The text document's language identifier.
Definition: Protocol.h:231
int64_t version
The version number of this document.
Definition: Protocol.h:237
std::string text
The content of the opened text document.
Definition: Protocol.h:234
URIForFile uri
The text document's URI.
Definition: Protocol.h:228
TextDocumentIdentifier textDocument
The text document.
Definition: Protocol.h:419
Position position
The position inside the text document.
Definition: Protocol.h:422
std::string newText
The string to be inserted.
Definition: Protocol.h:751
Range range
The range of the text document to be manipulated.
Definition: Protocol.h:747
int64_t version
The version number of this document.
Definition: Protocol.h:266
URIForFile uri
The text document's URI.
Definition: Protocol.h:264
std::map< std::string, std::vector< TextEdit > > changes
Holds changes to existing resources.
Definition: Protocol.h:1189