Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a limit to outline tree size #194

Merged
2 changes: 1 addition & 1 deletion cmake/external_gtest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ include(FetchContent)

FetchContent_Declare(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.10.0
GIT_TAG release-1.11.0
LOG_DOWNLOAD ON
GIT_PROGRESS 1
)
Expand Down
3 changes: 2 additions & 1 deletion language_server/src/lsp/feature_language_features.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,8 @@ void feature_language_features::document_symbol(const json& id, const json& para
{
auto document_uri = params["textDocument"]["uri"].get<std::string>();

auto symbol_list = ws_mngr_.document_symbol(uri_to_path(document_uri).c_str());
const auto limit = 5000LL;
auto symbol_list = ws_mngr_.document_symbol(uri_to_path(document_uri).c_str(), limit);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to make the limit configurable by adding it to the user configuration and then using the configuration changed notification (which is already implemented). Might be even easier, since no edits to workspace_manager would be required.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the user configurable option - given how poorly vscode behaves when too many nodes are reported, I think we would just end up giving users an option that could only cause problems.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the workspace_manager changes, that could be done, but lsp_context and workspace share the interface, so if there is to be a parameter on the document_symbol function, it must be present on the workspace version as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I would prefer that workspace would not implement the interface and put the limit into lib_config. But then lib_config wouldn't represent only user-configurable options.

I guess I am fine with both versions, then.


response_->respond(id, "", document_symbol_list_json(symbol_list));
}
Expand Down
2 changes: 1 addition & 1 deletion parser_library/include/workspace_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class PARSER_LIBRARY_EXPORT workspace_manager
const char* document_uri, position pos, char trigger_char, completion_trigger_kind trigger_kind);

virtual const std::vector<token_info>& semantic_tokens(const char* document_uri);
virtual document_symbol_list document_symbol(const char* document_uri);
virtual document_symbol_list document_symbol(const char* document_uri, long long limit);

virtual void configuration_changed(const lib_config& new_config);

Expand Down
52 changes: 7 additions & 45 deletions parser_library/src/lsp/document_symbol_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include "document_symbol_item.h"

#include "utils/similar.h"

namespace hlasm_plugin::parser_library::lsp {

document_symbol_item_s::document_symbol_item_s(std::string name, document_symbol_kind kind, range symbol_range)
Expand All @@ -31,55 +33,15 @@ document_symbol_item_s::document_symbol_item_s(
, children(children)
{}

bool is_permutation_with_permutations(const document_symbol_list_s& lhs, const document_symbol_list_s& rhs)
{
if (lhs.size() != rhs.size())
{
return false;
}
for (auto& item : lhs)
{
auto i = std::find(rhs.begin(), rhs.end(), item);
if (i == rhs.end())
{
return false;
}
if (!is_permutation_with_permutations(item.children, i->children))
{
return false;
}
}
return true;
}

document_symbol_list_s::iterator document_symbol_no_children_find(
document_symbol_list_s::iterator begin, document_symbol_list_s::iterator end, const document_symbol_item_s& item)
{
while (begin != end)
{
if (item.name == begin->name && item.kind == begin->kind && item.symbol_range == begin->symbol_range
&& item.symbol_selection_range == begin->symbol_selection_range)
{
return begin;
}
begin++;
}
return end;
}

bool operator==(const document_symbol_item_s& lhs, const document_symbol_item_s& rhs)
bool is_similar(const document_symbol_list_s& l, const document_symbol_list_s& r)
{
return lhs.name == rhs.name && lhs.kind == rhs.kind && lhs.symbol_range == rhs.symbol_range
&& lhs.symbol_selection_range == rhs.symbol_selection_range
&& is_permutation_with_permutations(lhs.children, rhs.children);
return l.size() == r.size() && std::is_permutation(l.begin(), l.end(), r.begin(), utils::is_similar);
}

void operator+=(document_symbol_list_s& lhs, const document_symbol_list_s& rhs)
bool is_similar(const document_symbol_item_s& l, const document_symbol_item_s& r)
{
for (const auto& item : rhs)
{
lhs.push_back(item);
}
return l.name == r.name && l.kind == r.kind && l.symbol_range == r.symbol_range
&& l.symbol_selection_range == r.symbol_selection_range && is_similar(l.children, r.children);
}

} // namespace hlasm_plugin::parser_library::lsp
8 changes: 2 additions & 6 deletions parser_library/src/lsp/document_symbol_item.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,8 @@ struct document_symbol_item_s

std::vector<range> scope;
};

bool operator==(const document_symbol_item_s& lhs, const document_symbol_item_s& rhs);
bool is_permutation_with_permutations(const document_symbol_list_s& lhs, const document_symbol_list_s& rhs);
document_symbol_list_s::iterator document_symbol_no_children_find(
document_symbol_list_s::iterator begin, document_symbol_list_s::iterator end, const document_symbol_item_s& item);
void operator+=(document_symbol_list_s& lhs, const document_symbol_list_s& rhs);
bool is_similar(const document_symbol_list_s& l, const document_symbol_list_s& r);
bool is_similar(const document_symbol_item_s& l, const document_symbol_item_s& r);

} // namespace hlasm_plugin::parser_library::lsp

Expand Down
2 changes: 1 addition & 1 deletion parser_library/src/lsp/feature_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct feature_provider
position pos,
char trigger_char,
completion_trigger_kind trigger_kind) const = 0;
virtual document_symbol_list_s document_symbol(const std::string& document_uri) const = 0;
virtual document_symbol_list_s document_symbol(const std::string& document_uri, long long limit) const = 0;

protected:
~feature_provider() = default;
Expand Down
27 changes: 24 additions & 3 deletions parser_library/src/lsp/file_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,20 @@ occurence_scope_t file_info::find_occurence_with_scope(position pos) const
{
const symbol_occurence* found = nullptr;

auto l = std::lower_bound(occurences.begin(), occurences.end(), pos, [](const auto& occ, const auto& p) {
return occ.occurence_range.end.line < p.line;
});
auto it_limit = occurences_start_limit.begin() + std::distance(occurences.begin(), l);
// find in occurences
for (const auto& occ : occurences)
for (auto it = l; it != occurences.end() && *it_limit <= pos.line; ++it, ++it_limit)
{
const auto& occ = *it;
if (is_in_range(pos, occ.occurence_range))
{
found = &occ;
break;
}
}

// if not found, return
if (!found)
Expand Down Expand Up @@ -93,8 +100,7 @@ std::vector<position> file_info::find_references(

void file_info::update_occurences(const occurence_storage& occurences_upd)
{
for (const auto& occ : occurences_upd)
occurences.emplace_back(occ);
occurences.insert(occurences.end(), occurences_upd.begin(), occurences_upd.end());
}

void file_info::update_slices(const std::vector<file_slice_t>& slices_upd)
Expand Down Expand Up @@ -145,4 +151,19 @@ std::vector<file_slice_t> file_slice_t::transform_slices(

const std::vector<symbol_occurence>& file_info::get_occurences() const { return occurences; }

void file_info::process_occurrences()
{
std::sort(occurences.begin(), occurences.end(), [](const auto& l, const auto& r) {
return std::tie(l.occurence_range.end.line, l.occurence_range.start.line)
< std::tie(r.occurence_range.end.line, r.occurence_range.start.line);
});

occurences_start_limit.resize(occurences.size());

std::transform(occurences.rbegin(),
occurences.rend(),
occurences_start_limit.rbegin(),
[min = (size_t)-1](const auto& occ) mutable { return min = std::min(min, occ.occurence_range.start.line); });
}

} // namespace hlasm_plugin::parser_library::lsp
2 changes: 2 additions & 0 deletions parser_library/src/lsp/file_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,12 @@ class file_info
void update_occurences(const occurence_storage& occurences_upd);
void update_slices(const std::vector<file_slice_t>& slices);
const std::vector<symbol_occurence>& get_occurences() const;
void process_occurrences();

private:
std::map<line_range, file_slice_t> slices;
std::vector<symbol_occurence> occurences;
std::vector<size_t> occurences_start_limit;
};

} // namespace hlasm_plugin::parser_library::lsp
Expand Down
Loading