Browse Source

language client: cleanup of workspace/applyEdit

master
eidheim 1 month ago
parent
commit
dd11a9c1d8
  1. 108
      src/source_language_protocol.cpp
  2. 2
      src/source_language_protocol.hpp

108
src/source_language_protocol.cpp

@ -64,13 +64,14 @@ LanguageProtocol::TextDocumentEdit::TextDocumentEdit(const JSON &text_document_e
LanguageProtocol::TextDocumentEdit::TextDocumentEdit(std::string file, std::vector<TextEdit> text_edits) : file(std::move(file)), text_edits(std::move(text_edits)) {}
LanguageProtocol::WorkspaceEdit::WorkspaceEdit(const JSON &workspace_edit, boost::filesystem::path file_path) {
LanguageProtocol::WorkspaceEdit::WorkspaceEdit(const JSON &workspace_edit, boost::filesystem::path path) {
boost::filesystem::path project_path;
auto build = Project::Build::create(file_path);
auto build = Project::Build::create(path);
boost::system::error_code ec;
if(!build->project_path.empty())
project_path = build->project_path;
else
project_path = file_path.parent_path();
project_path = boost::filesystem::is_directory(path, ec) ? path : path.parent_path();
try {
if(auto changes = workspace_edit.children_optional("changes")) {
for(auto &change : *changes) {
@ -587,67 +588,70 @@ void LanguageProtocol::Client::handle_server_request(const boost::variant<size_t
if(method == "workspace/applyEdit") {
std::promise<void> result_processed;
bool applied = true;
dispatcher->post([&result_processed, &applied, params = std::make_shared<JSON>(std::move(params))] {
dispatcher->post([this, &result_processed, &applied, params = std::make_shared<JSON>(std::move(params))] {
ScopeGuard guard({[&result_processed] {
result_processed.set_value();
}});
if(auto current_view = dynamic_cast<Source::LanguageProtocolView *>(Notebook::get().get_current_view())) {
LanguageProtocol::WorkspaceEdit workspace_edit;
try {
workspace_edit = LanguageProtocol::WorkspaceEdit(params->object("edit"), current_view->file_path);
}
catch(...) {
applied = false;
return;
}
LanguageProtocol::WorkspaceEdit workspace_edit;
try {
workspace_edit = LanguageProtocol::WorkspaceEdit(params->object("edit"), root_path);
}
catch(...) {
applied = false;
return;
}
for(auto &document_change : workspace_edit.document_changes) {
if(auto edit = boost::get<TextDocumentEdit>(&document_change)) {
Source::View *view = nullptr;
for(auto &e : Source::View::views) {
if(e->file_path == edit->file) {
view = e;
break;
}
auto current_view = Notebook::get().get_current_view();
for(auto &document_change : workspace_edit.document_changes) {
if(auto edit = boost::get<TextDocumentEdit>(&document_change)) {
Source::View *view = nullptr;
for(auto &e : Source::View::views) {
if(e->file_path == edit->file) {
view = e;
break;
}
if(!view) {
if(!Notebook::get().open(edit->file)) {
applied = false;
return;
}
view = Notebook::get().get_current_view();
}
if(!view) {
if(!Notebook::get().open(edit->file)) {
applied = false;
return;
}
view = Notebook::get().get_current_view();
}
auto buffer = view->get_buffer();
buffer->begin_user_action();
auto buffer = view->get_buffer();
buffer->begin_user_action();
auto end_iter = buffer->end();
// If entire buffer is replaced
if(edit->text_edits.size() == 1 &&
edit->text_edits[0].range.start.line == 0 && edit->text_edits[0].range.start.character == 0 &&
(edit->text_edits[0].range.end.line > end_iter.get_line() ||
(edit->text_edits[0].range.end.line == end_iter.get_line() && edit->text_edits[0].range.end.character >= current_view->get_line_pos(end_iter)))) {
view->replace_text(edit->text_edits[0].new_text);
}
else {
for(auto text_edit_it = edit->text_edits.rbegin(); text_edit_it != edit->text_edits.rend(); ++text_edit_it) {
auto start_iter = view->get_iter_at_line_pos(text_edit_it->range.start.line, text_edit_it->range.start.character);
auto end_iter = view->get_iter_at_line_pos(text_edit_it->range.end.line, text_edit_it->range.end.character);
if(view != current_view)
view->get_buffer()->place_cursor(start_iter);
buffer->erase(start_iter, end_iter);
start_iter = view->get_iter_at_line_pos(text_edit_it->range.start.line, text_edit_it->range.start.character);
buffer->insert(start_iter, text_edit_it->new_text);
}
auto get_line_pos = [this](Source::View *view, const Gtk::TextIter &iter) -> int {
if(capabilities.use_line_index)
return iter.get_line_index();
return utf16_code_unit_count(view->get_line(iter), 0, iter.get_line_index());
};
auto end_iter = buffer->end();
// If entire buffer is replaced
if(edit->text_edits.size() == 1 &&
edit->text_edits[0].range.start.line == 0 && edit->text_edits[0].range.start.character == 0 &&
(edit->text_edits[0].range.end.line > end_iter.get_line() ||
(edit->text_edits[0].range.end.line == end_iter.get_line() && edit->text_edits[0].range.end.character >= get_line_pos(view, end_iter)))) {
view->replace_text(edit->text_edits[0].new_text);
}
else {
for(auto text_edit_it = edit->text_edits.rbegin(); text_edit_it != edit->text_edits.rend(); ++text_edit_it) {
auto start_iter = view->get_iter_at_line_pos(text_edit_it->range.start.line, text_edit_it->range.start.character);
auto end_iter = view->get_iter_at_line_pos(text_edit_it->range.end.line, text_edit_it->range.end.character);
if(view != current_view)
view->get_buffer()->place_cursor(start_iter);
buffer->erase(start_iter, end_iter);
start_iter = view->get_iter_at_line_pos(text_edit_it->range.start.line, text_edit_it->range.start.character);
buffer->insert(start_iter, text_edit_it->new_text);
}
buffer->end_user_action();
}
}
if(current_view)
Notebook::get().open(current_view);
buffer->end_user_action();
}
}
if(current_view)
Notebook::get().open(current_view);
});
result_processed.get_future().get();
write_response(id, std::string("{\"applied\":") + (applied ? "true" : "false") + '}');

2
src/source_language_protocol.hpp

@ -111,7 +111,7 @@ namespace LanguageProtocol {
class WorkspaceEdit {
public:
WorkspaceEdit() = default;
WorkspaceEdit(const JSON &workspace_edit, boost::filesystem::path file_path);
WorkspaceEdit(const JSON &workspace_edit, boost::filesystem::path path);
std::vector<boost::variant<TextDocumentEdit, RenameFile>> document_changes;
};

Loading…
Cancel
Save