Repository: carbon-language/carbon-lang
File: toolchain/language_server/context.cpp (C++)

Code before:
                                           .tree_and_subtrees_getter = getter,
                                           .sem_ir = &sem_ir}};
  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> fs =
      new llvm::vfs::InMemoryFileSystem;
  // TODO: Include the prelude.
  Check::CheckParseTrees(units, /*prelude_import=*/false, fs,
                         context.vlog_stream(), /*fuzzing=*/false);

  // Note we need to publish diagnostics even when empty.
  // TODO: Consider caching previously published diagnostics and only publishing
  // when they change.
  context.outgoing().notify("textDocument/publishDiagnostics",
                            consumer.params());
}

auto Context::File::PositionToIndex(const clang::clangd::Position& position)
    -> size_t {
  return PositionToIndex(source_->text().data(), position);
}

auto Context::File::PositionToIndex(const std::string& contents,
                                    const clang::clangd::Position& position)
    -> size_t {
  size_t result = 0;

  for (int row = 0; row < position.line; row++) {
    const size_t newline_index = contents.find('\n', result);

    CARBON_CHECK(newline_index != std::string::npos,
                 "Line number greater than number of lines in the file");

    result = newline_index + 1;
  }

  result += position.character;

  CARBON_CHECK(result <= contents.size(),
               "Position greater than source code size");

  return result;
}

auto Context::File::ApplyChanges(
    Context& context, std::optional<int64_t> version,
    const std::vector<clang::clangd::TextDocumentContentChangeEvent>&
        content_changes) -> void {
  std::string contents = source_->text().data();

  for (const auto& change : content_changes) {
    // if range is not present, then we copy entire text
    if (!change.range) {

Review comment (suggestion):
I think we can use `llvm::seq` where to make clear this is just doing N finds:
```suggestion
  for ([[maybe_unused]] auto _ : llvm::seq(position.line)) {
```

Code after:
                                           .tree_and_subtrees_getter = getter,
                                           .sem_ir = &sem_ir}};
  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> fs =
      new llvm::vfs::InMemoryFileSystem;
  // TODO: Include the prelude.
  Check::CheckParseTrees(units, /*prelude_import=*/false, fs,
                         context.vlog_stream(), /*fuzzing=*/false);

  // Note we need to publish diagnostics even when empty.
  // TODO: Consider caching previously published diagnostics and only publishing
  // when they change.
  context.outgoing().notify("textDocument/publishDiagnostics",
                            consumer.params());
}

auto Context::LookupFile(llvm::StringRef filename) -> File* {
  if (!filename.ends_with(".carbon")) {
    CARBON_DIAGNOSTIC(LanguageServerFileUnsupported, Warning,
                      "non-Carbon file requested");
    file_emitter_.Emit(filename, LanguageServerFileUnsupported);
    return nullptr;
  }

  if (auto lookup_result = files().Lookup(filename)) {
    return &lookup_result.value();
  } else {
    CARBON_DIAGNOSTIC(LanguageServerFileUnknown, Warning,
                      "unknown file requested");
    file_emitter_.Emit(filename, LanguageServerFileUnknown);
    return nullptr;
  }
}

}  // namespace Carbon::LanguageServer