1 #pragma once 2 3 #include "lsp_diagnostic.h" 4 #include "utils.h" 5 6 #include <clang-c/Index.h> 7 #include <optional.h> 8 9 #include <mutex> 10 #include <string> 11 12 struct WorkingFile { 13 int version = 0; 14 AbsolutePath filename; 15 16 std::string buffer_content; 17 // Note: This assumes 0-based lines (1-based lines are normally assumed). 18 std::vector<std::string> index_lines; 19 // Note: This assumes 0-based lines (1-based lines are normally assumed). 20 std::vector<std::string> buffer_lines; 21 // Mappings between index line number and buffer line number. 22 // Empty indicates either buffer or index has been changed and re-computation 23 // is required. 24 // For index_to_buffer[i] == j, if j >= 0, we are confident that index line 25 // i maps to buffer line j; if j == -1, FindMatchingLine will use the nearest 26 // confident lines to resolve its line number. 27 std::vector<int> index_to_buffer; 28 std::vector<int> buffer_to_index; 29 // A set of diagnostics that have been reported for this file. 30 // NOTE: _ is appended because it must be accessed under the WorkingFiles 31 // lock! 32 std::vector<lsDiagnostic> diagnostics_; 33 34 WorkingFile(const AbsolutePath& filename, const std::string& buffer_content); 35 36 // This should be called when the indexed content has changed. 37 void SetIndexContent(const std::string& index_content); 38 // This should be called whenever |buffer_content| has changed. 39 void OnBufferContentUpdated(); 40 41 // Finds the buffer line number which maps to index line number |line|. 42 // Also resolves |column| if not NULL. 43 // When resolving a range, use is_end = false for begin() and is_end = 44 // true for end() to get a better alignment of |column|. 45 optional<int> GetBufferPosFromIndexPos(int line, int* column, bool is_end); 46 // Finds the index line number which maps to buffer line number |line|. 47 // Also resolves |column| if not NULL. 48 optional<int> GetIndexPosFromBufferPos(int line, int* column, bool is_end); 49 50 // TODO: Move FindClosestCallNameInBuffer and FindStableCompletionSource into 51 // lex_utils.h/cc 52 53 // Finds the closest 'callable' name prior to position. This is used for 54 // signature help to filter code completion results. 55 // 56 // |completion_position| will be point to a good code completion location to 57 // for fetching signatures. 58 std::string FindClosestCallNameInBuffer( 59 lsPosition position, 60 int* active_parameter, 61 lsPosition* completion_position = nullptr) const; 62 63 // Returns a relatively stable completion position (it jumps back until there 64 // is a non-alphanumeric character). 65 // 66 // The out param |is_global_completion| is set to true if this looks like a 67 // global completion. 68 // The out param |existing_completion| is set to any existing completion 69 // content the user has entered. 70 // The out param |replace_end_position| is set to the end of the existing 71 // identifier, including characters after the original position. 72 lsPosition FindStableCompletionSource(lsPosition position, 73 bool* is_global_completion, 74 std::string* existing_completion, 75 lsPosition* replace_end_position) const; 76 77 private: 78 // Compute index_to_buffer and buffer_to_index. 79 void ComputeLineMapping(); 80 }; 81 82 struct WorkingFiles { 83 struct Snapshot { 84 struct File { 85 std::string filename; 86 std::string content; 87 }; 88 89 std::vector<CXUnsavedFile> AsUnsavedFiles() const; 90 std::vector<File> files; 91 }; 92 93 // 94 // :: IMPORTANT :: All methods in this class are guarded by a single lock. 95 // 96 97 // Find the file with the given filename. 98 WorkingFile* GetFileByFilename(const AbsolutePath& filename); 99 WorkingFile* GetFileByFilenameNoLock(const AbsolutePath& filename); 100 101 // Run |action| under the lock. 102 void DoAction(const std::function<void()>& action); 103 // Run |action| on the file identified by |filename|. This executes under the 104 // lock. 105 void DoActionOnFile(const AbsolutePath& filename, 106 const std::function<void(WorkingFile* file)>& action); 107 108 WorkingFile* OnOpen(const lsTextDocumentItem& open); 109 void OnChange(const lsTextDocumentDidChangeParams& change); 110 void OnClose(const lsTextDocumentIdentifier& close); 111 112 // If |filter_paths| is non-empty, only files which contain any of the given 113 // strings. For example, {"foo", "bar"} means that every result has either the 114 // string "foo" or "bar" contained within it. 115 Snapshot AsSnapshot(const std::vector<std::string>& filter_paths); 116 117 // Use unique_ptrs so we can handout WorkingFile ptrs and not have them 118 // invalidated if we resize files. 119 std::vector<std::unique_ptr<WorkingFile>> files; 120 std::mutex files_mutex; // Protects |files|. 121 }; 122