================
@@ -7,103 +7,157 @@
 
//===----------------------------------------------------------------------===//
 
 #include "DAP.h"
-#include "JSONUtils.h"
+#include "LLDBUtils.h"
 #include "Protocol/ProtocolRequests.h"
 #include "Protocol/ProtocolTypes.h"
 #include "RequestHandler.h"
 #include "lldb/API/SBStringList.h"
+#include "llvm/Support/ConvertUTF.h"
 
 using namespace llvm;
 using namespace lldb_dap;
+using namespace lldb;
 using namespace lldb_dap::protocol;
 
 namespace lldb_dap {
+/// Gets the position in the UTF8 string where the specified line started.
+static size_t GetLineStartPos(llvm::StringRef text, uint32_t line) {
+  if (line == 0) // Invalid line.
+    return llvm::StringRef::npos;
+
+  if (line == 1)
+    return 0;
+
+  uint32_t cur_line = 1;
+  size_t pos = 0;
+
+  while (cur_line < line) {
+    const size_t new_line_pos = text.find('\n', pos);
+
+    if (new_line_pos == llvm::StringRef::npos) {
+      return new_line_pos;
+    }
+
+    pos = new_line_pos + 1;
+    // text may end with a new line
+    if (pos >= text.size())
+      return llvm::StringRef::npos;
+
+    cur_line++;
+  }
+
+  assert(pos < text.size());
+  return pos;
+}
+
+static std::optional<size_t> GetCursorPos(llvm::StringRef text, uint32_t line,
+                                          uint32_t utf16_codeunits) {
+  if (text.empty())
+    return std::nullopt;
+
+  const size_t line_start_pos = GetLineStartPos(text, line);
+  if (line_start_pos == llvm::StringRef::npos)
+    return std::nullopt;
+
+  const llvm::StringRef completion_line =
+      text.substr(line_start_pos, text.find('\n', line_start_pos));
+  if (completion_line.empty())
+    return std::nullopt;
+
+  const std::optional<size_t> cursor_pos_opt =
+      UTF16CodeunitToBytes(completion_line, utf16_codeunits);
+  if (!cursor_pos_opt)
+    return std::nullopt;
+
+  const size_t cursor_pos = line_start_pos + *cursor_pos_opt;
+  return cursor_pos;
+}
 
 /// Returns a list of possible completions for a given caret position and text.
 ///
 /// Clients should only call this request if the corresponding capability
 /// `supportsCompletionsRequest` is true.
 Expected<CompletionsResponseBody>
 CompletionsRequestHandler::Run(const CompletionsArguments &args) const {
+  std::string text = args.text;
----------------
da-viper wrote:

the column is measured in code unit. 
If we convert the string to UTF-16, it does not tell us how many bytes we need 
to move the cursor by. so we end up converting from the offset back to UTF-8 
and checking if its valid UTF-8. 
something like
```cpp 
  // completion request input 
  int codeunit = 2;
  std::string text = "fƒ";

  llvm::SmallVector<UTF16, 10> dest; 
  llvm::convertUTF8ToUTF16String(text, dest); // convert to UTF-16
  
  llvm::ArrayRef<UTF16> input(dest.begin(), dest.begin() + codeunit); // get 
characters until the codeunit.
  std::string out_str;
  llvm::convertUTF16ToUTF8String(input, out_str); // convert back to UTF-8 
  llvm::isLegalUTF8String(...) // check it is valid and add it to the cursor 
offset.
  const auto matches = out_str.size() == 3; // f -> 1 byte and ƒ -> 2 byte

  // view it normally
  auto view = std::wstring(dest.begin(), dest.end());
```

https://github.com/llvm/llvm-project/pull/176211
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to