clang-tools  10.0.0
DraftStore.cpp
Go to the documentation of this file.
1 //===--- DraftStore.cpp - File contents container ---------------*- C++ -*-===//
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 #include "DraftStore.h"
10 #include "SourceCode.h"
11 #include "llvm/Support/Errc.h"
12 
13 namespace clang {
14 namespace clangd {
15 
16 llvm::Optional<std::string> DraftStore::getDraft(PathRef File) const {
17  std::lock_guard<std::mutex> Lock(Mutex);
18 
19  auto It = Drafts.find(File);
20  if (It == Drafts.end())
21  return None;
22 
23  return It->second;
24 }
25 
26 std::vector<Path> DraftStore::getActiveFiles() const {
27  std::lock_guard<std::mutex> Lock(Mutex);
28  std::vector<Path> ResultVector;
29 
30  for (auto DraftIt = Drafts.begin(); DraftIt != Drafts.end(); DraftIt++)
31  ResultVector.push_back(DraftIt->getKey());
32 
33  return ResultVector;
34 }
35 
36 void DraftStore::addDraft(PathRef File, llvm::StringRef Contents) {
37  std::lock_guard<std::mutex> Lock(Mutex);
38 
39  Drafts[File] = Contents;
40 }
41 
42 llvm::Expected<std::string> DraftStore::updateDraft(
43  PathRef File, llvm::ArrayRef<TextDocumentContentChangeEvent> Changes) {
44  std::lock_guard<std::mutex> Lock(Mutex);
45 
46  auto EntryIt = Drafts.find(File);
47  if (EntryIt == Drafts.end()) {
48  return llvm::make_error<llvm::StringError>(
49  "Trying to do incremental update on non-added document: " + File,
50  llvm::errc::invalid_argument);
51  }
52 
53  std::string Contents = EntryIt->second;
54 
55  for (const TextDocumentContentChangeEvent &Change : Changes) {
56  if (!Change.range) {
57  Contents = Change.text;
58  continue;
59  }
60 
61  const Position &Start = Change.range->start;
62  llvm::Expected<size_t> StartIndex =
63  positionToOffset(Contents, Start, false);
64  if (!StartIndex)
65  return StartIndex.takeError();
66 
67  const Position &End = Change.range->end;
68  llvm::Expected<size_t> EndIndex = positionToOffset(Contents, End, false);
69  if (!EndIndex)
70  return EndIndex.takeError();
71 
72  if (*EndIndex < *StartIndex)
73  return llvm::make_error<llvm::StringError>(
74  llvm::formatv(
75  "Range's end position ({0}) is before start position ({1})", End,
76  Start),
77  llvm::errc::invalid_argument);
78 
79  // Since the range length between two LSP positions is dependent on the
80  // contents of the buffer we compute the range length between the start and
81  // end position ourselves and compare it to the range length of the LSP
82  // message to verify the buffers of the client and server are in sync.
83 
84  // EndIndex and StartIndex are in bytes, but Change.rangeLength is in UTF-16
85  // code units.
86  ssize_t ComputedRangeLength =
87  lspLength(Contents.substr(*StartIndex, *EndIndex - *StartIndex));
88 
89  if (Change.rangeLength && ComputedRangeLength != *Change.rangeLength)
90  return llvm::make_error<llvm::StringError>(
91  llvm::formatv("Change's rangeLength ({0}) doesn't match the "
92  "computed range length ({1}).",
93  *Change.rangeLength, ComputedRangeLength),
94  llvm::errc::invalid_argument);
95 
96  std::string NewContents;
97  NewContents.reserve(*StartIndex + Change.text.length() +
98  (Contents.length() - *EndIndex));
99 
100  NewContents = Contents.substr(0, *StartIndex);
101  NewContents += Change.text;
102  NewContents += Contents.substr(*EndIndex);
103 
104  Contents = std::move(NewContents);
105  }
106 
107  EntryIt->second = Contents;
108  return Contents;
109 }
110 
112  std::lock_guard<std::mutex> Lock(Mutex);
113 
114  Drafts.erase(File);
115 }
116 
117 } // namespace clangd
118 } // namespace clang
llvm::StringRef Contents
tooling::Replacements Changes
Definition: Format.cpp:108
size_t lspLength(llvm::StringRef Code)
Definition: SourceCode.cpp:131
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:23
void addDraft(PathRef File, StringRef Contents)
Replace contents of the draft for File with Contents.
Definition: DraftStore.cpp:36
Documents should not be synced at all.
llvm::Expected< std::string > updateDraft(PathRef File, llvm::ArrayRef< TextDocumentContentChangeEvent > Changes)
Update the contents of the draft for File based on Changes.
Definition: DraftStore.cpp:42
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
Definition: SourceCode.cpp:155
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::vector< Path > getActiveFiles() const
Definition: DraftStore.cpp:26
void removeDraft(PathRef File)
Remove the draft from the store.
Definition: DraftStore.cpp:111
llvm::Optional< std::string > getDraft(PathRef File) const
Definition: DraftStore.cpp:16