FileDB.cpp 5.5 KB

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