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