FileDB.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "FileDB.h"
  7. #include <AK/LexicalPath.h>
  8. #include <AK/NonnullRefPtr.h>
  9. #include <LibCore/File.h>
  10. namespace LanguageServers {
  11. RefPtr<const GUI::TextDocument> FileDB::get_document(String const& filename) const
  12. {
  13. auto absolute_path = to_absolute_path(filename);
  14. auto document_optional = m_open_files.get(absolute_path);
  15. if (!document_optional.has_value())
  16. return nullptr;
  17. return *document_optional.value();
  18. }
  19. RefPtr<GUI::TextDocument> FileDB::get_document(String const& filename)
  20. {
  21. auto document = reinterpret_cast<FileDB const*>(this)->get_document(filename);
  22. if (document.is_null())
  23. return nullptr;
  24. return adopt_ref(*const_cast<GUI::TextDocument*>(document.leak_ref()));
  25. }
  26. Optional<String> FileDB::get_or_read_from_filesystem(StringView filename) const
  27. {
  28. auto absolute_path = to_absolute_path(filename);
  29. auto document = get_document(absolute_path);
  30. if (document)
  31. return document->text();
  32. document = create_from_filesystem(absolute_path);
  33. if (document)
  34. return document->text();
  35. return {};
  36. }
  37. bool FileDB::is_open(String const& filename) const
  38. {
  39. return m_open_files.contains(to_absolute_path(filename));
  40. }
  41. bool FileDB::add(String const& filename, int fd)
  42. {
  43. auto document = create_from_fd(fd);
  44. if (!document)
  45. return false;
  46. m_open_files.set(to_absolute_path(filename), document.release_nonnull());
  47. return true;
  48. }
  49. String FileDB::to_absolute_path(String const& filename) const
  50. {
  51. if (LexicalPath { filename }.is_absolute()) {
  52. return filename;
  53. }
  54. if (m_project_root.is_null())
  55. return filename;
  56. return LexicalPath { String::formatted("{}/{}", m_project_root, filename) }.string();
  57. }
  58. RefPtr<GUI::TextDocument> FileDB::create_from_filesystem(String const& filename) const
  59. {
  60. auto file = Core::File::open(to_absolute_path(filename), Core::OpenMode::ReadOnly);
  61. if (file.is_error()) {
  62. dbgln("failed to create document for {} from filesystem", filename);
  63. return nullptr;
  64. }
  65. return create_from_file(*file.value());
  66. }
  67. RefPtr<GUI::TextDocument> FileDB::create_from_fd(int fd) const
  68. {
  69. auto file = Core::File::construct();
  70. if (!file->open(fd, Core::OpenMode::ReadOnly, Core::File::ShouldCloseFileDescriptor::Yes)) {
  71. errno = file->error();
  72. perror("open");
  73. dbgln("Failed to open project file");
  74. return nullptr;
  75. }
  76. return create_from_file(*file);
  77. }
  78. class DefaultDocumentClient final : public GUI::TextDocument::Client {
  79. public:
  80. virtual ~DefaultDocumentClient() override = default;
  81. virtual void document_did_append_line() override {};
  82. virtual void document_did_insert_line(size_t) override {};
  83. virtual void document_did_remove_line(size_t) override {};
  84. virtual void document_did_remove_all_lines() override {};
  85. virtual void document_did_change(GUI::AllowCallback) override {};
  86. virtual void document_did_set_text(GUI::AllowCallback) override {};
  87. virtual void document_did_set_cursor(const GUI::TextPosition&) override {};
  88. virtual void document_did_update_undo_stack() override { }
  89. virtual bool is_automatic_indentation_enabled() const override { return false; }
  90. virtual int soft_tab_width() const override { return 4; }
  91. };
  92. static DefaultDocumentClient s_default_document_client;
  93. RefPtr<GUI::TextDocument> FileDB::create_from_file(Core::File& file) const
  94. {
  95. auto content = file.read_all();
  96. StringView content_view(content);
  97. auto document = GUI::TextDocument::create(&s_default_document_client);
  98. document->set_text(content_view);
  99. return document;
  100. }
  101. void FileDB::on_file_edit_insert_text(String const& filename, String const& inserted_text, size_t start_line, size_t start_column)
  102. {
  103. VERIFY(is_open(filename));
  104. auto document = get_document(filename);
  105. VERIFY(document);
  106. GUI::TextPosition start_position { start_line, start_column };
  107. document->insert_at(start_position, inserted_text, &s_default_document_client);
  108. dbgln_if(FILE_CONTENT_DEBUG, "{}", document->text());
  109. }
  110. void FileDB::on_file_edit_remove_text(String const& filename, size_t start_line, size_t start_column, size_t end_line, size_t end_column)
  111. {
  112. // TODO: If file is not open - need to get its contents
  113. // Otherwise- somehow verify that respawned language server is synced with all file contents
  114. VERIFY(is_open(filename));
  115. auto document = get_document(filename);
  116. VERIFY(document);
  117. GUI::TextPosition start_position { start_line, start_column };
  118. GUI::TextRange range {
  119. GUI::TextPosition { start_line, start_column },
  120. GUI::TextPosition { end_line, end_column }
  121. };
  122. document->remove(range);
  123. dbgln_if(FILE_CONTENT_DEBUG, "{}", document->text());
  124. }
  125. RefPtr<GUI::TextDocument> FileDB::create_with_content(String const& content)
  126. {
  127. StringView content_view(content);
  128. auto document = GUI::TextDocument::create(&s_default_document_client);
  129. document->set_text(content_view);
  130. return document;
  131. }
  132. bool FileDB::add(String const& filename, String const& content)
  133. {
  134. auto document = create_with_content(content);
  135. if (!document) {
  136. VERIFY_NOT_REACHED();
  137. return false;
  138. }
  139. m_open_files.set(to_absolute_path(filename), document.release_nonnull());
  140. return true;
  141. }
  142. }