diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp index 42ead5e2d4..f13b6d44ce 100644 --- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp +++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp @@ -75,7 +75,7 @@ Vector CppComprehensionEngine::get_suggestions auto containing_token = document.parser().token_at(position); if (containing_token.has_value() && containing_token->type() == Token::Type::IncludePath) { - auto results = try_autocomplete_include(document, containing_token.value()); + auto results = try_autocomplete_include(document, containing_token.value(), position); if (results.has_value()) return results.value(); } @@ -637,7 +637,7 @@ Vector CppComprehensionEngine::scope_of_node(const ASTNode& node) co return parent_scope; } -Optional> CppComprehensionEngine::try_autocomplete_include(const DocumentData&, Token include_path_token) +Optional> CppComprehensionEngine::try_autocomplete_include(const DocumentData&, Token include_path_token, Cpp::Position const& cursor_position) const { VERIFY(include_path_token.type() == Token::Type::IncludePath); auto partial_include = include_path_token.text().trim_whitespace(); @@ -648,14 +648,27 @@ Optional> CppComprehensionEngine::try_a } include_type { Project }; String include_root; + bool already_has_suffix = false; if (partial_include.starts_with("<")) { include_root = "/usr/include/"; include_type = System; + if (partial_include.ends_with(">")) { + already_has_suffix = true; + partial_include = partial_include.substring_view(0, partial_include.length() - 1).trim_whitespace(); + } } else if (partial_include.starts_with("\"")) { include_root = filedb().project_root(); + if (partial_include.length() > 1 && partial_include.ends_with("\"")) { + already_has_suffix = true; + partial_include = partial_include.substring_view(0, partial_include.length() - 1).trim_whitespace(); + } } else return {}; + // The cursor is past the end of the <> or "", and so should not trigger autocomplete. + if (already_has_suffix && include_path_token.end() <= cursor_position) + return {}; + auto last_slash = partial_include.find_last('/'); auto include_dir = String::empty(); auto partial_basename = partial_include.substring_view((last_slash.has_value() ? last_slash.value() : 0) + 1); @@ -674,7 +687,11 @@ Optional> CppComprehensionEngine::try_a if (!(path.ends_with(".h") || Core::File::is_directory(LexicalPath::join(full_dir, path).string()))) continue; if (path.starts_with(partial_basename)) { - auto completion = include_type == System ? String::formatted("<{}>", path) : String::formatted("\"{}\"", path); + // FIXME: Place the cursor after the trailing > or ", even if it was + // already typed. + auto prefix = include_type == System ? "<" : "\""; + auto suffix = include_type == System ? ">" : "\""; + auto completion = String::formatted("{}{}{}", prefix, path, already_has_suffix ? "" : suffix); options.append({ completion, partial_basename.length() + 1, GUI::AutocompleteProvider::Language::Cpp, path }); } } diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.h b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.h index d0d83720b4..ecf84ecaf8 100644 --- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.h +++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.h @@ -129,7 +129,7 @@ private: OwnPtr create_document_data(String&& text, const String& filename); Optional> try_autocomplete_property(const DocumentData&, const ASTNode&, Optional containing_token) const; Optional> try_autocomplete_name(const DocumentData&, const ASTNode&, Optional containing_token) const; - Optional> try_autocomplete_include(const DocumentData&, Token include_path_token); + Optional> try_autocomplete_include(const DocumentData&, Token include_path_token, Cpp::Position const& cursor_position) const; static bool is_symbol_available(const Symbol&, const Vector& current_scope, const Vector& reference_scope); Optional get_function_params_hint(DocumentData const&, FunctionCall&, size_t argument_index);