26 #include "wasphit/HITInterpreter.h" 27 #include "waspcore/utils.h" 35 : _moose_app(moose_app),
36 _connection(
std::make_shared<wasp::lsp::IOStreamConnection>(this)),
37 _formatting_tab_size(0)
40 server_capabilities[wasp::lsp::m_text_doc_sync] = wasp::DataObject();
41 server_capabilities[wasp::lsp::m_text_doc_sync][wasp::lsp::m_open_close] =
true;
42 server_capabilities[wasp::lsp::m_text_doc_sync][wasp::lsp::m_change] = wasp::lsp::m_change_full;
45 server_capabilities[wasp::lsp::m_completion_provider] = wasp::DataObject();
46 server_capabilities[wasp::lsp::m_completion_provider][wasp::lsp::m_resolve_provider] =
false;
47 server_capabilities[wasp::lsp::m_doc_symbol_provider] =
true;
48 server_capabilities[wasp::lsp::m_doc_format_provider] =
true;
49 server_capabilities[wasp::lsp::m_definition_provider] =
true;
50 server_capabilities[wasp::lsp::m_references_provider] =
true;
51 server_capabilities[wasp::lsp::m_hover_provider] =
true;
58 std::string parse_file_path = document_path;
59 pcrecpp::RE(
"(.*://)(.*)").Replace(
"\\2", &parse_file_path);
63 app_params.
set<std::shared_ptr<Parser>>(
"_parser") =
64 std::make_shared<Parser>(parse_file_path, document_text);
67 if (command_line->hasArgument(
"--language-server"))
68 command_line->removeArgument(
"--language-server");
69 command_line->addArgument(
"--check-input");
70 command_line->addArgument(
"--error-unused");
71 command_line->addArgument(
"--error");
72 command_line->addArgument(
"--color=off");
73 command_line->addArgument(
"--disable-perf-graph-live");
74 command_line->parse();
75 app_params.
set<std::shared_ptr<CommandLine>>(
"_command_line") = std::move(command_line);
95 catch (std::exception &
err)
98 int column_number = 1;
100 std::istringstream caught_msg(
err.what());
103 for (std::string error_line; std::getline(caught_msg, error_line);)
106 if (error_line.rfind(parse_file_path +
":", 0) == 0)
109 error_line.erase(0, parse_file_path.size() + 1);
111 int match_line_number;
112 int match_column_number;
113 std::string match_error_line;
116 if (pcrecpp::RE(
"^(\\d+)\\.(\\d+)\\-?\\d*:\\s*(.*)$")
117 .FullMatch(error_line, &match_line_number, &match_column_number, &match_error_line))
119 line_number = match_line_number;
120 column_number = match_column_number;
121 error_line = match_error_line;
125 else if (pcrecpp::RE(
"^(\\d+):\\s*(.*)$")
126 .FullMatch(error_line, &match_line_number, &match_error_line))
128 line_number = match_line_number;
130 error_line = match_error_line;
135 if (error_line.find_first_not_of(
" \t") == std::string::npos)
139 diagnosticsList.push_back(wasp::DataObject());
140 wasp::DataObject * diagnostic = diagnosticsList.back().to_object();
141 pass &= wasp::lsp::buildDiagnosticObject(*diagnostic,
169 document_text = replacement_text;
176 bool & is_incomplete,
182 return addSubblocksToList(completionItems,
"/", line, character, line, character,
"",
false);
185 auto is_request_in_open_block = [](wasp::HITNodeView request_context) {
186 return request_context.type() == wasp::OBJECT || request_context.type() == wasp::DOCUMENT_ROOT;
188 auto is_request_on_param_decl = [](wasp::HITNodeView request_context)
190 return request_context.type() == wasp::DECL && request_context.has_parent() &&
191 (request_context.parent().type() == wasp::KEYED_VALUE ||
192 request_context.parent().type() == wasp::ARRAY);
194 auto is_request_on_block_decl = [](wasp::HITNodeView request_context)
196 return request_context.type() == wasp::DECL && request_context.has_parent() &&
197 request_context.parent().type() == wasp::OBJECT;
201 wasp::HITNodeView view_root =
getRoot().getNodeView();
202 wasp::HITNodeView request_context;
205 if (line + 1 < (
int)view_root.last_line() ||
206 (line + 1 == (
int)view_root.last_line() && character <= (
int)view_root.last_column()))
207 request_context = wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
213 wasp::findNodeUnderLineColumn(view_root, view_root.last_line(), view_root.last_column());
216 wasp::HITNodeView object_context = request_context;
217 while (object_context.type() != wasp::OBJECT && object_context.has_parent())
218 object_context = object_context.parent();
219 if (request_context.type() == wasp::OBJECT_TERM && object_context.has_parent())
220 object_context = object_context.parent();
221 request_context = object_context;
225 if (is_request_in_open_block(request_context))
227 wasp::HITNodeView backup_context = request_context;
228 for (
int backup_char = character; backup_context == request_context && --backup_char > 0;)
229 backup_context = wasp::findNodeUnderLineColumn(request_context, line + 1, backup_char + 1);
230 if (backup_context.type() == wasp::ASSIGN || backup_context.type() == wasp::OVERRIDE_ASSIGN)
231 request_context = backup_context;
235 int replace_line_beg = line;
236 int replace_char_beg = character;
237 int replace_line_end = line;
238 int replace_char_end = character;
239 std::string filtering_prefix;
240 if (request_context.type() == wasp::DECL || request_context.type() == wasp::VALUE)
243 replace_line_beg = request_context.line() - 1;
244 replace_char_beg = request_context.column() - 1;
245 replace_line_end = request_context.last_line() - 1;
246 replace_char_end = request_context.last_column();
247 filtering_prefix = request_context.data();
250 if (is_request_on_block_decl(request_context) && filtering_prefix.empty())
258 const auto & parent_name = request_context.has_parent() ? request_context.parent().name() :
"";
261 wasp::HITNodeView object_context = request_context;
262 while (object_context.type() != wasp::OBJECT && object_context.has_parent())
263 object_context = object_context.parent();
264 if (is_request_on_block_decl(request_context))
265 object_context = object_context.parent();
266 const std::string & object_path = object_context.path();
267 wasp::HITNodeView type_node = object_context.first_child_by_name(
"type");
268 const std::string & object_type =
269 type_node.is_null() ?
"" : wasp::strip_quotes(hit::extractValue(type_node.data()));
272 std::set<std::string> existing_params, existing_subblocks;
279 std::set<std::string> obj_act_tasks;
287 if (is_request_in_open_block(request_context) || is_request_on_param_decl(request_context))
298 if (is_request_in_open_block(request_context) || is_request_on_param_decl(request_context) ||
299 is_request_on_block_decl(request_context))
307 is_request_on_block_decl(request_context));
310 if ((request_context.type() == wasp::VALUE || request_context.type() == wasp::ASSIGN ||
311 request_context.type() == wasp::OVERRIDE_ASSIGN) &&
325 is_incomplete = !pass;
332 std::set<std::string> & existing_params,
333 std::set<std::string> & existing_subblocks)
336 for (
auto itr = parent_node.begin(); itr != parent_node.end(); itr.next())
338 auto child_node = itr.get();
341 if (child_node.type() == wasp::KEYED_VALUE || child_node.type() == wasp::ARRAY)
342 existing_params.insert(child_node.name());
343 else if (child_node.type() == wasp::OBJECT)
344 existing_subblocks.insert(child_node.name());
350 const std::string & object_path,
351 const std::string & object_type,
352 std::set<std::string> & obj_act_tasks)
362 const std::string & object_path,
363 std::set<std::string> & obj_act_tasks)
370 std::string registered_syntax = syntax.
isAssociated(object_path, &is_parent);
376 auto action_range = syntax.
getActions(registered_syntax);
379 for (
auto action_iter = action_range.first; action_iter != action_range.second; action_iter++)
381 const std::string & action_name = action_iter->second._action;
389 if (action_params.
get<
bool>(
"isObjectAction"))
391 std::set<std::string> tasks_by_actions = action_factory.
getTasksByAction(action_name);
392 obj_act_tasks.insert(tasks_by_actions.begin(), tasks_by_actions.end());
396 action_params.
remove(
"isObjectAction");
400 valid_params += action_params;
407 std::string object_type,
408 const std::set<std::string> & obj_act_tasks)
414 if (object_type.empty() && valid_params.
have_parameter<std::string>(
"type") &&
415 !valid_params.
get<std::string>(
"type").empty())
417 object_type = valid_params.
get<std::string>(
"type");
432 const std::string & moose_base = object_params.
get<std::string>(
"_moose_base");
434 for (
const auto & obj_act_task : obj_act_tasks)
439 valid_params += object_params;
447 if (valid_params.
have_parameter<std::vector<std::string>>(
"_object_params_set_by_action"))
449 auto names = valid_params.
get<std::vector<std::string>>(
"_object_params_set_by_action");
450 for (
const auto &
name : names)
454 valid_params.
remove(
"_object_params_set_by_action");
461 const std::set<std::string> & existing_params,
462 int replace_line_beg,
463 int replace_char_beg,
464 int replace_line_end,
465 int replace_char_end,
466 const std::string & filtering_prefix)
471 for (
const auto & valid_params_iter : valid_params)
473 const std::string & param_name = valid_params_iter.first;
474 bool deprecated = valid_params.isParamDeprecated(param_name);
475 bool is_private = valid_params.isPrivate(param_name);
478 if (deprecated || is_private || existing_params.count(param_name))
482 if (param_name.rfind(filtering_prefix, 0) != 0)
486 std::string dirty_type = valid_params.type(param_name);
489 std::string doc_string = valid_params.getDocString(param_name);
493 bool is_array = basic_type.compare(0, 6,
"Array:") == 0;
496 pcrecpp::RE(
"(Array:)*(.*)").GlobalReplace(
"\\2", &basic_type);
499 pcrecpp::RE(
".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace(
"\\1", &clean_type);
505 std::string default_value;
508 if (valid_params.isParamValid(param_name))
515 else if (valid_params.hasDefaultCoupledValue(param_name))
517 std::ostringstream oss;
518 oss << valid_params.defaultCoupledValue(param_name);
519 default_value = oss.str();
523 if (basic_type ==
"Boolean" && default_value ==
"1")
524 default_value =
"true";
525 else if (basic_type ==
"Boolean" && default_value ==
"0")
526 default_value =
"false";
529 std::string array_quote = is_array && !default_value.empty() ?
"'" :
"";
533 std::string insert_text;
534 if (client_snippet_support && !default_value.empty())
536 text_format = wasp::lsp::m_text_format_snippet;
537 insert_text = param_name +
" = " + array_quote +
"${1:" + default_value +
"}" + array_quote;
541 text_format = wasp::lsp::m_text_format_plaintext;
542 insert_text = param_name +
" = " + array_quote + default_value + array_quote;
547 completionItems.push_back(wasp::DataObject());
548 wasp::DataObject * item = completionItems.back().to_object();
549 pass &= wasp::lsp::buildCompletionObject(*item,
570 const std::string & object_path,
571 int replace_line_beg,
572 int replace_char_beg,
573 int replace_line_end,
574 int replace_char_end,
575 const std::string & filtering_prefix,
576 bool request_on_block_decl)
581 std::set<std::string> syntax_paths_processed;
588 std::string syntax_path =
"/" + syntax_path_iter.first;
591 if (!syntax_paths_processed.insert(syntax_path).second)
595 for (std::size_t last_sep; (last_sep = syntax_path.find_last_of(
"/")) != std::string::npos;)
597 std::string subblock_name = syntax_path.substr(last_sep + 1);
598 syntax_path = syntax_path.substr(0, last_sep);
610 if (!registered_syntax.empty() || object_path ==
"/")
613 int text_format = client_snippet_support ? wasp::lsp::m_text_format_snippet
614 : wasp::lsp::m_text_format_plaintext;
619 if (subblock_name !=
"*" && subblock_name.rfind(filtering_prefix, 0) != 0)
622 std::string doc_string;
623 std::string insert_text;
627 const std::string full_block_path = object_path +
"/" + subblock_name;
631 if (subblock_name ==
"*")
633 doc_string =
"custom user named block";
634 insert_text = (request_on_block_decl ?
"" :
"[") +
635 (filtering_prefix.size() ? filtering_prefix :
"block_name") +
"]" +
636 req_params +
"\n " + (client_snippet_support ?
"$0" :
"") +
"\n[]";
637 complete_kind = wasp::lsp::m_comp_kind_variable;
641 doc_string =
"application named block";
642 insert_text = (request_on_block_decl ?
"" :
"[") + subblock_name +
"]" + req_params +
643 "\n " + (client_snippet_support ?
"$0" :
"") +
"\n[]";
644 complete_kind = wasp::lsp::m_comp_kind_struct;
648 completionItems.push_back(wasp::DataObject());
649 wasp::DataObject * item = completionItems.back().to_object();
650 pass &= wasp::lsp::buildCompletionObject(*item,
673 const std::set<std::string> & existing_params,
674 const std::set<std::string> & existing_subblocks,
675 const std::string & param_name,
676 const std::set<std::string> & obj_act_tasks,
677 const std::string & object_path,
678 int replace_line_beg,
679 int replace_char_beg,
680 int replace_line_end,
681 int replace_char_end)
687 std::string dirty_type = valid_params.
type(param_name);
692 pcrecpp::RE(
"(Array:)*(.*)").GlobalReplace(
"\\2", &basic_type);
695 pcrecpp::RE(
".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace(
"\\1", &clean_type);
701 std::map<std::string, std::string> options_and_descs;
704 if (param_name ==
"active" || param_name ==
"inactive")
705 for (
const auto & subblock_name : existing_subblocks)
706 options_and_descs[subblock_name] =
"subblock name";
709 else if (basic_type ==
"Boolean")
711 options_and_descs[
"true"];
712 options_and_descs[
"false"];
722 else if (valid_params.
have_parameter<std::vector<MooseEnum>>(param_name))
723 getEnumsAndDocs(valid_params.
get<std::vector<MooseEnum>>(param_name)[0], options_and_descs);
726 else if (param_name ==
"type")
731 const std::string & object_name = objects_iter.first;
732 const InputParameters & object_params = objects_iter.second->buildParameters();
736 req_params += req_params.size() ?
"\n" + std::string(client_snippet_support ?
"$0" :
"") :
"";
741 const std::string & moose_base = object_params.
get<std::string>(
"_moose_base");
744 for (
const auto & obj_act_task : obj_act_tasks)
750 options_and_descs[object_name + req_params] = type_description;
764 const std::string &
type = associated_types_iter.second;
765 const std::string & path = associated_types_iter.first;
775 wasp::HITNodeView view_root =
getRoot().getNodeView();
778 for (
const auto & input_path : input_path_iter->second)
781 wasp::SIRENInterpreter<> selector;
782 if (!selector.parseString(input_path))
784 wasp::SIRENResultSet<wasp::HITNodeView> results;
785 std::size_t count = selector.evaluate(view_root, results);
788 for (std::size_t i = 0; i < count; i++)
789 if (results.adapted(i).type() == wasp::OBJECT)
790 options_and_descs[results.adapted(i).name()] =
"from /" + input_path;
796 int text_format = client_snippet_support ? wasp::lsp::m_text_format_snippet
797 : wasp::lsp::m_text_format_plaintext;
802 for (
const auto & option_and_desc : options_and_descs)
804 const std::string & insert_text = option_and_desc.first;
805 const std::string & option_name = insert_text.substr(0, insert_text.find(
'\n'));
806 const std::string & description = option_and_desc.second;
809 completionItems.push_back(wasp::DataObject());
810 wasp::DataObject * item = completionItems.back().to_object();
811 pass &= wasp::lsp::buildCompletionObject(*item,
830 template <
typename MooseEnumType>
833 std::map<std::string, std::string> & options_and_descs)
836 const auto & enum_docs = moose_enum_param.getItemDocumentation();
839 for (
const auto & item : moose_enum_param.items())
840 options_and_descs[item.name()] = enum_docs.count(item) ? enum_docs.at(item) :
"";
855 wasp::HITNodeView view_root =
getRoot().getNodeView();
856 wasp::HITNodeView request_context =
857 wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
860 if (request_context.type() != wasp::VALUE)
864 std::string param_name = request_context.has_parent() ? request_context.parent().name() :
"";
865 std::string val_string = request_context.last_as_string();
868 if (param_name ==
"type" && factory.
isRegistered(val_string))
874 if (!file_line_info.
isValid() ||
879 auto location_uri = wasp::lsp::m_uri_prefix + file_line_info.
file();
882 definitionLocations.push_back(wasp::DataObject());
883 wasp::DataObject * location = definitionLocations.back().to_object();
884 return wasp::lsp::buildLocationObject(*location,
887 file_line_info.
line() - 1,
889 file_line_info.
line() - 1,
894 wasp::HITNodeView object_context = request_context;
895 while (object_context.type() != wasp::OBJECT && object_context.has_parent())
896 object_context = object_context.parent();
897 const std::string & object_path = object_context.path();
898 wasp::HITNodeView type_node = object_context.first_child_by_name(
"type");
899 const std::string & object_type =
900 type_node.is_null() ?
"" : wasp::strip_quotes(hit::extractValue(type_node.data()));
906 std::set<std::string> obj_act_tasks;
913 [](
const wasp::HITNodeView & l,
const wasp::HITNodeView & r)
915 const std::string & l_file = l.node_pool()->stream_name();
916 const std::string & r_file = r.node_pool()->stream_name();
917 return (l_file < r_file || (l_file == r_file && l.line() < r.line()) ||
918 (l_file == r_file && l.line() == r.line() && l.column() < r.column()));
922 for (
const auto & valid_params_iter : valid_params)
924 if (valid_params_iter.first == param_name)
927 std::string dirty_type = valid_params.type(param_name);
929 pcrecpp::RE(
".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace(
"\\1", &clean_type);
938 if (location_nodes.empty() && request_context.has_parent() &&
939 request_context.parent().child_count_by_name(
"decl"))
940 location_nodes.insert(request_context.parent().first_child_by_name(
"decl"));
948 const std::string & clean_type,
949 const std::string & val_string)
958 const std::string &
type = associated_types_iter.second;
959 const std::string & path = associated_types_iter.first;
972 wasp::HITNodeView view_root =
getRoot().getNodeView();
975 for (
const auto & input_path : input_path_iter->second)
978 wasp::SIRENInterpreter<> selector;
979 if (!selector.parseString(input_path))
981 wasp::SIRENResultSet<wasp::HITNodeView> results;
982 std::size_t count = selector.evaluate(view_root, results);
985 for (std::size_t i = 0; i < count; i++)
986 if (results.adapted(i).type() == wasp::OBJECT && results.adapted(i).name() == val_string &&
987 results.adapted(i).child_count_by_name(
"decl"))
988 location_nodes.insert(results.adapted(i).first_child_by_name(
"decl"));
999 for (
const auto & location_nodes_iter : location_nodes)
1002 auto location_uri = wasp::lsp::m_uri_prefix + location_nodes_iter.node_pool()->stream_name();
1005 defsOrRefsLocations.push_back(wasp::DataObject());
1006 wasp::DataObject * location = defsOrRefsLocations.back().to_object();
1007 pass &= wasp::lsp::buildLocationObject(*location,
1010 location_nodes_iter.line() - 1,
1011 location_nodes_iter.column() - 1,
1012 location_nodes_iter.last_line() - 1,
1013 location_nodes_iter.last_column());
1030 wasp::HITNodeView view_root =
getRoot().getNodeView();
1031 wasp::HITNodeView request_context =
1032 wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
1035 if ((request_context.type() != wasp::DECL && request_context.type() != wasp::VALUE) ||
1036 !request_context.has_parent() ||
1037 (request_context.parent().type() != wasp::KEYED_VALUE &&
1038 request_context.parent().type() != wasp::ARRAY))
1042 std::string paramkey = request_context.parent().name();
1043 std::string paramval = request_context.last_as_string();
1046 wasp::HITNodeView object_context = request_context;
1047 while (object_context.type() != wasp::OBJECT && object_context.has_parent())
1048 object_context = object_context.parent();
1049 const std::string object_path = object_context.path();
1050 wasp::HITNodeView type_node = object_context.first_child_by_name(
"type");
1051 const std::string object_type =
1052 type_node.is_null() ?
"" : wasp::strip_quotes(hit::extractValue(type_node.data()));
1056 std::set<std::string> obj_act_tasks;
1060 if (request_context.type() == wasp::VALUE && paramkey ==
"type" && factory.
isRegistered(paramval))
1065 const std::string moose_base = object_params.
get<std::string>(
"_moose_base");
1066 for (
const auto & obj_act_task : obj_act_tasks)
1078 else if (request_context.type() == wasp::VALUE)
1080 std::map<std::string, std::string> options_and_descs;
1087 else if (valid_params.
have_parameter<std::vector<MooseEnum>>(paramkey))
1088 getEnumsAndDocs(valid_params.
get<std::vector<MooseEnum>>(paramkey)[0], options_and_descs);
1089 if (options_and_descs.count(paramval))
1090 display_text = options_and_descs.find(paramval)->second;
1094 else if (request_context.type() == wasp::DECL && valid_params.
getParametersList().count(paramkey))
1105 bool include_declaration)
1114 wasp::HITNodeView view_root =
getRoot().getNodeView();
1115 wasp::HITNodeView request_context =
1116 wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
1119 if ((request_context.type() != wasp::DECL && request_context.type() != wasp::DOT_SLASH &&
1120 request_context.type() != wasp::LBRACKET && request_context.type() != wasp::RBRACKET) ||
1121 !request_context.has_parent() || request_context.parent().type() != wasp::OBJECT)
1125 const std::string & block_path = request_context.parent().path();
1126 const std::string & block_name = request_context.parent().name();
1132 const std::string & path = associated_types_iter.first;
1133 const std::string &
type = associated_types_iter.second;
1150 [](
const wasp::HITNodeView & l,
const wasp::HITNodeView & r)
1152 const std::string & l_file = l.node_pool()->stream_name();
1153 const std::string & r_file = r.node_pool()->stream_name();
1154 return (l_file < r_file || (l_file == r_file && l.line() < r.line()) ||
1155 (l_file == r_file && l.line() == r.line() && l.column() < r.column()));
1162 if (match_nodes.empty())
1166 if (include_declaration && request_context.parent().child_count_by_name(
"decl"))
1167 match_nodes.insert(request_context.parent().first_child_by_name(
"decl"));
1175 wasp::HITNodeView view_parent,
1176 const std::string & target_value,
1177 const std::set<std::string> & target_types)
1180 for (
const auto & view_child : view_parent)
1183 if (view_child.type() == wasp::VALUE && view_child.to_string() == target_value)
1186 wasp::HITNodeView object_context = view_child;
1187 while (object_context.type() != wasp::OBJECT && object_context.has_parent())
1188 object_context = object_context.parent();
1189 const std::string object_path = object_context.path();
1190 wasp::HITNodeView type_node = object_context.first_child_by_name(
"type");
1191 const std::string object_type =
1192 type_node.is_null() ?
"" : wasp::strip_quotes(hit::extractValue(type_node.data()));
1196 std::set<std::string> obj_act_tasks;
1200 std::string param_name = view_child.has_parent() ? view_child.parent().name() :
"";
1203 std::string dirty_type = valid_params.
type(param_name);
1205 pcrecpp::RE(
".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace(
"\\1", &clean_type);
1208 if (target_types.count(clean_type))
1209 match_nodes.insert(view_child);
1213 if (!view_child.is_leaf())
1224 std::string parse_file_path = document_path;
1225 pcrecpp::RE(
"(.*://)(.*)").Replace(
"\\2", &parse_file_path);
1229 wasp::DefaultHITInterpreter interpreter(input_errors);
1232 if (!interpreter.parseStream(input_stream, parse_file_path))
1236 if (interpreter.root().is_null())
1240 wasp::HITNodeView view_root = interpreter.root();
1241 int document_start_line = view_root.line() - 1;
1242 int document_start_char = view_root.column() - 1;
1243 int document_last_line = view_root.last_line() - 1;
1244 int document_last_char = view_root.last_column();
1248 std::size_t starting_line = view_root.line() - 1;
1249 std::string document_format =
formatDocument(view_root, starting_line, 0);
1252 formattingTextEdits.push_back(wasp::DataObject());
1253 wasp::DataObject * item = formattingTextEdits.back().to_object();
1254 bool pass = wasp::lsp::buildTextEditObject(*item,
1256 document_start_line,
1257 document_start_char,
1271 auto collapse_spaces = [](std::string string_copy)
1273 pcrecpp::RE(
"\\s+").Replace(
" ", &string_copy);
1278 std::string format_string;
1281 for (
const auto i :
make_range(parent.child_count()))
1284 wasp::HITNodeView child = parent.child_at(i);
1287 std::string blank = child.line() > prev_line + 1 ?
"\n" :
"";
1290 if (child.type() == wasp::FILE)
1291 format_string += blank + newline_indent +
MooseUtils::trim(collapse_spaces(child.data()));
1294 else if (child.type() == wasp::COMMENT)
1295 format_string += (child.line() == prev_line ?
" " : blank + newline_indent) +
1299 else if (child.type() == wasp::OBJECT)
1300 format_string += blank + newline_indent +
"[" + child.name() +
"]" +
1301 formatDocument(child, prev_line, level + 1) + newline_indent +
"[]";
1304 else if (child.type() == wasp::KEYED_VALUE || child.type() == wasp::ARRAY)
1306 const std::string prefix = newline_indent + child.name() +
" = ";
1308 const std::string render_val = hit::extractValue(child.data());
1309 std::size_t val_column = child.child_count() > 2 ? child.child_at(2).column() : 0;
1310 std::size_t prefix_len = prefix.size() - 1;
1312 format_string += blank + prefix + hit::formatValue(render_val, val_column, prefix_len);
1316 prev_line = child.last_line();
1320 return level != 0 ? format_string : format_string.substr(1);
1330 wasp::HITNodeView view_root =
getRoot().getNodeView();
1335 for (
const auto i :
make_range(view_root.child_count()))
1338 wasp::HITNodeView view_child = view_root.child_at(i);
1341 std::string
name = view_child.name();
1342 int line = view_child.line() - 1;
1343 int column = view_child.column() - 1;
1344 int last_line = view_child.last_line() - 1;
1345 int last_column = view_child.last_column();
1347 std::string detail =
1348 !view_child.first_child_by_name(
"type").is_null()
1349 ? wasp::strip_quotes(hit::extractValue(view_child.first_child_by_name(
"type").data()))
1353 documentSymbols.push_back(wasp::DataObject());
1354 wasp::DataObject * data_child = documentSymbols.back().to_object();
1355 pass &= wasp::lsp::buildDocumentSymbolObject(*data_child,
1379 wasp::DataObject & data_parent)
1382 if (wasp::is_nested_file(view_parent))
1388 for (
const auto i :
make_range(view_parent.child_count()))
1391 wasp::HITNodeView view_child = view_parent.child_at(i);
1394 std::string
name = view_child.name();
1395 int line = view_child.line() - 1;
1396 int column = view_child.column() - 1;
1397 int last_line = view_child.last_line() - 1;
1398 int last_column = view_child.last_column();
1400 std::string detail =
1401 !view_child.first_child_by_name(
"type").is_null()
1402 ? wasp::strip_quotes(hit::extractValue(view_child.first_child_by_name(
"type").data()))
1406 wasp::DataObject & data_child = wasp::lsp::addDocumentSymbolChild(data_parent);
1407 pass &= wasp::lsp::buildDocumentSymbolObject(data_child,
1431 const std::string & param_name,
1432 const std::string & clean_type,
1436 auto associated_types =
getCheckApp()->syntax().getAssociatedTypes();
1439 return wasp::lsp::m_comp_kind_event;
1440 else if (param_name ==
"active" || param_name ==
"inactive")
1441 return wasp::lsp::m_comp_kind_class;
1442 else if (clean_type ==
"bool")
1443 return wasp::lsp::m_comp_kind_interface;
1448 return is_param ? wasp::lsp::m_comp_kind_enum : wasp::lsp::m_comp_kind_enum_member;
1449 else if (param_name ==
"type")
1450 return wasp::lsp::m_comp_kind_type_param;
1451 else if (std::find_if(associated_types.begin(),
1452 associated_types.end(),
1453 [&](
const auto & entry)
1454 {
return entry.second == clean_type; }) != associated_types.end())
1455 return wasp::lsp::m_comp_kind_reference;
1457 return is_param ? wasp::lsp::m_comp_kind_keyword : wasp::lsp::m_comp_kind_value;
1464 auto is_boolean = [](wasp::HITNodeView symbol_node)
1468 return (iss >> std::boolalpha >>
convert && !iss.fail());
1470 auto is_number = [](wasp::HITNodeView symbol_node)
1473 std::istringstream iss(symbol_node.last_as_string());
1474 return (iss >>
convert && iss.eof());
1478 if (symbol_node.type() == wasp::OBJECT)
1479 return wasp::lsp::m_symbol_kind_struct;
1480 else if (symbol_node.type() == wasp::FILE)
1481 return wasp::lsp::m_symbol_kind_file;
1482 else if (symbol_node.type() == wasp::ARRAY)
1483 return wasp::lsp::m_symbol_kind_array;
1484 else if (symbol_node.type() == wasp::KEYED_VALUE && symbol_node.name() == std::string(
"type"))
1485 return wasp::lsp::m_symbol_kind_type_param;
1486 else if (symbol_node.type() == wasp::KEYED_VALUE && is_boolean(symbol_node))
1487 return wasp::lsp::m_symbol_kind_boolean;
1488 else if (symbol_node.type() == wasp::KEYED_VALUE && is_number(symbol_node))
1489 return wasp::lsp::m_symbol_kind_number;
1490 else if (symbol_node.type() == wasp::KEYED_VALUE)
1491 return wasp::lsp::m_symbol_kind_key;
1492 else if (symbol_node.type() == wasp::VALUE)
1493 return wasp::lsp::m_symbol_kind_string;
1495 return wasp::lsp::m_symbol_kind_property;
1500 const std::string & subblock_type,
1501 const std::set<std::string> & existing_params,
1502 const std::string & indent_spaces)
1506 std::set<std::string> obj_act_tasks;
1510 std::string required_param_text;
1511 std::size_t param_index = 1;
1512 for (
const auto & valid_params_iter : valid_params)
1515 const std::string & param_name = valid_params_iter.first;
1516 if (!valid_params.isParamDeprecated(param_name) && !valid_params.isPrivate(param_name) &&
1517 !valid_params.isParamValid(param_name) && valid_params.isParamRequired(param_name) &&
1518 !existing_params.count(param_name))
1520 std::string tab_stop = client_snippet_support ?
"$" + std::to_string(param_index++) :
"";
1521 required_param_text +=
"\n" + indent_spaces + param_name +
" = " + tab_stop;
1525 return required_param_text;
1532 !
getCheckApp()->builder().root()->getNodeView().is_null();
1542 std::shared_ptr<MooseApp>
1545 mooseAssert(
_check_apps.count(document_path),
"No check app for path");
1552 mooseAssert(
_path_to_text.count(document_path),
"No text for path");
int getDocumentSymbolKind(wasp::HITNodeView symbol_node)
Get document symbol kind value that client may use for outline icon.
const std::multimap< std::string, std::string > & getAssociatedTypes() const
Get a multimap of registered associations of syntax with type.
std::pair< std::multimap< std::string, ActionInfo >::const_iterator, std::multimap< std::string, ActionInfo >::const_iterator > getActions(const std::string &syntax) const
Returns a pair of multimap iterators to all the ActionInfo objects associated with a given piece of s...
std::map< std::string, std::set< std::string > > _type_to_input_paths
_type_to_input_paths - map of parameter types to lookup paths
T convert(const std::string &str, bool throw_on_failure=false)
convert takes a string representation of a number type and converts it to the number.
A MultiMooseEnum object to hold "execute_on" flags.
std::shared_ptr< MooseApp > getCheckApp() const
bool isRegistered(const std::string &obj_name) const
Returns a Boolean indicating whether an object type has been registered.
std::string toLower(const std::string &name)
Convert supplied string to lower case.
void getInputLookupDefinitionNodes(SortedLocationNodes &location_nodes, const std::string &clean_type, const std::string &val_string)
Get set of nodes from associated path lookups matching value string.
const std::multimap< std::string, ActionInfo > & getAssociatedActions() const
Return all Syntax to Action associations.
std::string getRequiredParamsText(const std::string &subblock_path, const std::string &subblock_type, const std::set< std::string > &existing_params, const std::string &indent_spaces)
Get required parameter completion text list for given subblock path.
std::map< std::string, std::set< std::string > > _input_path_to_types
_type_to_input_paths - map of lookup paths to parameter types
Generic factory class for build all sorts of objects.
const std::string & getDocumentText() const
InputParameters getValidParams(const std::string &name)
std::shared_ptr< CommandLine > commandLine() const
Get the command line.
MooseServer(MooseApp &moose_app)
bool addValuesToList(wasp::DataArray &completionItems, const InputParameters &valid_params, const std::set< std::string > &existing_params, const std::set< std::string > &existing_subblocks, const std::string ¶m_name, const std::set< std::string > &obj_act_tasks, const std::string &object_path, int replace_line_beg, int replace_char_beg, int replace_line_end, int replace_char_end)
Add parameter values to completion list for request line and column.
MooseAppPtr createShared(const std::string &app_type, const std::string &name, InputParameters parameters, MPI_Comm COMM_WORLD_IN)
Build an application object (must be registered)
bool gatherDocumentSymbols(wasp::DataArray &documentSymbols)
Gather document symbols - specific to this server implemention.
bool addParametersToList(wasp::DataArray &completionItems, const InputParameters &valid_params, const std::set< std::string > &existing_params, int replace_line_beg, int replace_char_beg, int replace_line_end, int replace_char_end, const std::string &filtering_prefix)
Add parameters that were previously gathered to list for completion.
std::set< std::string > getTasksByAction(const std::string &action) const
static InputParameters validParams()
Parameters that are processed directly by the Parser and are valid anywhere in the input...
InputParameters getValidParams(const std::string &name) const
Get valid parameters for the object.
Base class for MOOSE-based applications.
bool getHoverDisplayText(std::string &display_text, int line, int character)
Get hover display text - logic specific to this server implemention.
const InputParameters & parameters()
Get the parameters of the object.
virtual const std::string & name() const
Get the name of the class.
bool updateDocumentTextChanges(const std::string &replacement_text, int start_line, int start_character, int end_line, int end_character, int range_length)
Update document text changes - specific to this server implemention.
FileLineInfo getLineInfo(const std::string &name) const
Gets file and line information where an object was initially registered.
std::set< wasp::HITNodeView, std::function< bool(const wasp::HITNodeView &, const wasp::HITNodeView &)> > SortedLocationNodes
SortedLocationNodes - type alias for set of nodes sorted by location.
void getObjectParameters(InputParameters &valid_params, std::string object_type, const std::set< std::string > &obj_act_tasks)
Get all object parameters using requested object path to collection.
void getNodesByValueAndTypes(SortedLocationNodes &match_nodes, wasp::HITNodeView view_parent, const std::string &target_value, const std::set< std::string > &target_types)
Recursively walk input to gather all nodes matching value and types.
static std::string buildOutputString(const std::iterator_traits< InputParameters::iterator >::value_type &p)
void remove(std::string_view)
Specialized factory for generic Action System objects.
bool checkFileReadable(const std::string &filename, bool check_line_endings=false, bool throw_on_unreadable=true, bool check_for_git_lfs_pointer=true)
Checks to see if a file is readable (exists and permissions)
std::string trim(const std::string &str, const std::string &white_space=" \\\)
Standard scripting language trim function.
const std::string & type() const
Get the type of this class.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
void getAllValidParameters(InputParameters &valid_params, const std::string &object_path, const std::string &object_type, std::set< std::string > &obj_act_tasks)
Get all global parameters, action parameters, and object parameters.
const auto & registeredObjects() const
Returns a reference to the map from names to RegistryEntryBase pointers.
bool gatherDocumentFormattingTextEdits(wasp::DataArray &formattingTextEdits, int tab_size, bool insert_spaces)
Gather formatting text edits - specific to this server implemention.
static std::string basicCppType(const std::string &cpp_type)
Utilities for making sense of c++ types.
Holds file and line information.
static AppFactory & instance()
Get the instance of the AppFactory.
std::string isAssociated(const std::string &real_id, bool *is_parent, const std::map< std::string, std::set< std::string >> &alt_map={}) const
Method for determining whether a piece of syntax is associated with an Action an optional syntax map ...
void getActionParameters(InputParameters &valid_params, const std::string &object_path, std::set< std::string > &obj_act_tasks)
Get all action parameters using requested object path to collection.
bool traverseParseTreeAndFillSymbols(wasp::HITNodeView view_parent, wasp::DataObject &data_parent)
Recursively fill document symbols from the given node.
MooseApp & _moose_app
_moose_app - reference to parent application that owns this server
bool addSubblocksToList(wasp::DataArray &completionItems, const std::string &object_path, int replace_line_beg, int replace_char_beg, int replace_line_end, int replace_char_end, const std::string &filtering_prefix, bool request_on_block_decl)
Add subblocks to completion list for request path, line, and column.
bool gatherDocumentCompletionItems(wasp::DataArray &completionItems, bool &is_incomplete, int line, int character)
Gather document completion items - specific to this server implemention.
bool gatherDocumentReferencesLocations(wasp::DataArray &referencesLocations, int line, int character, bool include_declaration)
Gather references locations - specific to this server implemention.
IntRange< T > make_range(T beg, T end)
Holding syntax for parsing input files.
std::size_t _formatting_tab_size
_formatting_tab_size - number of indent spaces for formatting
bool parseDocumentForDiagnostics(wasp::DataArray &diagnosticsList)
Parse document for diagnostics - specific to this server implemention.
bool verifyMooseObjectTask(const std::string &base, const std::string &task) const
Returns a Boolean indicating whether a task is associated with on of the MOOSE pluggable systems (BAS...
bool gatherDocumentDefinitionLocations(wasp::DataArray &definitionLocations, int line, int character)
Gather definition locations - specific to this server implemention.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type...
std::map< std::string, std::string > _path_to_text
_path_to_text - map of document paths to current text strings
bool addLocationNodesToList(wasp::DataArray &defsOrRefsLocations, const SortedLocationNodes &location_nodes)
Add set of nodes sorted by location to definition or reference list.
std::map< std::string, std::set< std::string > > _syntax_to_subblocks
_syntax_to_subblocks - map of syntax paths to valid subblocks
int getCompletionItemKind(const InputParameters &valid_params, const std::string ¶m_name, const std::string &clean_type, bool is_param)
Get completion item kind value that client may use for icon in list.
bool _throw_on_error
Variable to turn on exceptions during mooseError(), should only be used within MOOSE unit tests or wh...
const std::shared_ptr< libMesh::Parallel::Communicator > getCommunicator() const
void getEnumsAndDocs(MooseEnumType &moose_enum_param, std::map< std::string, std::string > &options_and_descs)
Fill map of all options and descriptions if parameter is moose enum.
void ErrorVector unsigned int
std::string formatDocument(wasp::HITNodeView parent, std::size_t &prev_line, std::size_t level)
Recursively walk down whole nodeview tree while formatting document.
void escape(std::string &str)
This function will escape all of the standard C++ escape characters so that they can be printed...
void getExistingInput(wasp::HITNodeView parent_node, std::set< std::string > &existing_params, std::set< std::string > &existing_subblocks)
Get names of parameters and subblocks specified in given input node.
std::map< std::string, std::shared_ptr< MooseApp > > _check_apps
_check_apps - map from document paths to input check applications
std::string prettyCppType(const std::string &cpp_type)