29 #include "wasphit/HITInterpreter.h" 30 #include "waspcore/utils.h" 31 #include "waspplot/CustomPlotSerialization.h" 40 : _moose_app(moose_app),
41 _connection(
std::make_shared<wasp::lsp::IOStreamConnection>(this)),
42 _formatting_tab_size(0)
52 enableExtension(
"plotting");
53 enableExtension(
"watcherRegistration");
64 std::string parse_file_path = document_path;
65 pcrecpp::RE(
"(.*://)(.*)").Replace(
"\\2", &parse_file_path);
70 const auto diagnostic = [
this, &diagnosticsList, &pass](
const std::string & message,
72 const int start_column,
73 const std::optional<int> end_line = {},
74 const std::optional<int> end_column = {})
76 diagnosticsList.push_back(wasp::DataObject());
77 auto & diagnostic = *diagnosticsList.back().to_object();
78 pass &= wasp::lsp::buildDiagnosticObject(diagnostic,
82 end_line ? *end_line : start_line,
83 end_column ? *end_column : start_column,
91 const auto zero_line_diagnostic = [&diagnostic](
const std::string & message)
92 { diagnostic(message, 0, 0); };
95 const auto hit_node_diagnostic = [&zero_line_diagnostic, &diagnostic, &parse_file_path](
96 const hit::Node *
const node,
const std::string & message)
99 if (!node || node->isRoot() || node->filename() != parse_file_path || !node->line() ||
101 zero_line_diagnostic(message);
104 diagnostic(message, node->line() - 1, node->column() - 1);
108 const auto hit_error_message_diagnostic =
109 [&diagnostic, &zero_line_diagnostic, &parse_file_path](
const hit::ErrorMessage &
err)
115 if (*
err.filename == parse_file_path)
118 if (
err.lineinfo &&
err.lineinfo->start_line &&
err.lineinfo->start_column &&
119 err.lineinfo->end_line &&
err.lineinfo->end_column)
121 diagnostic(
err.message,
122 err.lineinfo->start_line - 1,
123 err.lineinfo->start_column - 1,
124 err.lineinfo->end_line - 1,
125 err.lineinfo->end_column - 1);
135 zero_line_diagnostic(
err.prefixed_message);
141 const auto try_catch = [&hit_error_message_diagnostic,
142 &hit_node_diagnostic,
143 &zero_line_diagnostic](
const auto & action) ->
bool 157 for (
const auto & error_message :
err.error_messages)
158 hit_error_message_diagnostic(error_message);
164 hit_node_diagnostic(
err.getNode(),
err.what());
167 catch (std::exception &
err)
169 zero_line_diagnostic(
err.what());
177 if (command_line->hasArgument(
"--language-server"))
178 command_line->removeArgument(
"--language-server");
179 command_line->addArgument(
"--check-input");
180 command_line->addArgument(
"--error-unused");
181 command_line->addArgument(
"--error");
182 command_line->addArgument(
"--color=off");
183 command_line->addArgument(
"--disable-perf-graph-live");
184 command_line->parse();
187 auto parser = std::make_shared<Parser>(parse_file_path, document_text);
188 mooseAssert(parser->getInputFileNames()[0] == parse_file_path,
"Should be consistent");
189 parser->setCommandLineParams(command_line->buildHitParams());
190 parser->setThrowOnError(
true);
193 const bool parse_success = try_catch([&parser]() { parser->parse(); });
197 if (
auto parser_root_ptr = parser->queryRoot();
198 parser_root_ptr && !parser_root_ptr->getNodeView().is_null())
200 auto it_inserted_pair =
_check_state.emplace(document_path, parser);
201 mooseAssert(it_inserted_pair.second,
"Should not already exist");
202 state = &it_inserted_pair.first->second;
215 app_params.
set<std::shared_ptr<Parser>>(
"_parser") = parser;
216 app_params.
set<std::shared_ptr<CommandLine>>(
"_command_line") = std::move(command_line);
219 std::unique_ptr<MooseApp> app =
nullptr;
220 const auto do_build_app = [
this, &app_params, &app]()
227 if (!try_catch(do_build_app))
235 state->app = std::move(app);
239 if (!try_catch(do_run_app))
255 auto & root = *root_ptr;
258 if (!client_watcher_support)
262 wasp::HITNodeView view_root = root.getNodeView();
263 std::set<std::string> include_paths, filename_vals, resource_uris;
266 view_root.node_pool()->descendant_include_paths(include_paths);
267 for (
const auto & include_path : include_paths)
269 auto normalized = std::filesystem::path(include_path).lexically_normal().string();
271 resource_uris.insert(wasp::lsp::prefixUriScheme(normalized));
276 for (
const auto & filename_val : filename_vals)
278 auto input_path = wasp::lsp::removeUriScheme(document_path);
279 auto input_base = std::filesystem::path(input_path).parent_path();
280 auto fname_path = std::filesystem::path(filename_val);
281 auto fname_absl = fname_path.is_absolute() ? fname_path : (input_base / fname_path);
282 auto normalized = fname_absl.lexically_normal().string();
284 resource_uris.insert(wasp::lsp::prefixUriScheme(normalized));
288 setResourcesForBase(document_path, resource_uris);
295 static const std::set<std::string> filename_types = {
296 "FileName",
"FileNameNoExtension",
"MeshFileName",
"MatrixFileName"};
299 for (
const auto & child : parent)
301 if (child.type() == wasp::OBJECT)
304 wasp::HITNodeView object_node = child;
305 const std::string object_path = object_node.path();
306 wasp::HITNodeView type_node = object_node.first_child_by_name(
"type");
307 const std::string object_type =
308 type_node.is_null() ?
"" : wasp::strip_quotes(hit::extractValue(type_node.data()));
312 std::set<std::string> obj_act_tasks;
316 for (
const auto & child : object_node)
318 if (child.type() == wasp::KEYED_VALUE || child.type() == wasp::ARRAY)
321 wasp::HITNodeView param_node = child;
322 std::string param_name = param_node.name();
328 std::string dirty_type = valid_params.
type(param_name);
330 pcrecpp::RE(
".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace(
"\\1", &clean_type);
333 if (filename_types.count(clean_type))
334 for (
const auto & child : param_node)
335 if (child.type() == wasp::VALUE)
336 filename_vals.insert(child.to_string());
349 bool & is_incomplete,
357 return addSubblocksToList(completionItems,
"/", line, character, line, character,
"",
false);
358 auto & root = *root_ptr;
361 auto is_request_in_open_block = [](wasp::HITNodeView request_context) {
362 return request_context.type() == wasp::OBJECT || request_context.type() == wasp::DOCUMENT_ROOT;
364 auto is_request_on_param_decl = [](wasp::HITNodeView request_context)
366 return request_context.type() == wasp::DECL && request_context.has_parent() &&
367 (request_context.parent().type() == wasp::KEYED_VALUE ||
368 request_context.parent().type() == wasp::ARRAY);
370 auto is_request_on_block_decl = [](wasp::HITNodeView request_context)
372 return request_context.type() == wasp::DECL && request_context.has_parent() &&
373 request_context.parent().type() == wasp::OBJECT;
377 wasp::HITNodeView view_root = root.getNodeView();
378 wasp::HITNodeView request_context;
381 if (line + 1 < (
int)view_root.last_line() ||
382 (line + 1 == (
int)view_root.last_line() && character <= (
int)view_root.last_column()))
383 request_context = wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
389 wasp::findNodeUnderLineColumn(view_root, view_root.last_line(), view_root.last_column());
392 wasp::HITNodeView object_context = request_context;
393 while (object_context.type() != wasp::OBJECT && object_context.has_parent())
394 object_context = object_context.parent();
395 if (request_context.type() == wasp::OBJECT_TERM && object_context.has_parent())
396 object_context = object_context.parent();
397 request_context = object_context;
401 if (is_request_in_open_block(request_context))
403 wasp::HITNodeView backup_context = request_context;
404 for (
int backup_char = character; backup_context == request_context && --backup_char > 0;)
405 backup_context = wasp::findNodeUnderLineColumn(request_context, line + 1, backup_char + 1);
406 if (backup_context.type() == wasp::ASSIGN || backup_context.type() == wasp::OVERRIDE_ASSIGN)
407 request_context = backup_context;
411 int replace_line_beg = line;
412 int replace_char_beg = character;
413 int replace_line_end = line;
414 int replace_char_end = character;
415 std::string filtering_prefix;
416 if (request_context.type() == wasp::DECL || request_context.type() == wasp::VALUE)
419 replace_line_beg = request_context.line() - 1;
420 replace_char_beg = request_context.column() - 1;
421 replace_line_end = request_context.last_line() - 1;
422 replace_char_end = request_context.last_column();
423 filtering_prefix = request_context.data();
426 if (is_request_on_block_decl(request_context) && filtering_prefix.empty())
434 const auto & parent_name = request_context.has_parent() ? request_context.parent().name() :
"";
437 wasp::HITNodeView object_context = request_context;
438 while (object_context.type() != wasp::OBJECT && object_context.has_parent())
439 object_context = object_context.parent();
440 if (is_request_on_block_decl(request_context))
441 object_context = object_context.parent();
442 const std::string & object_path = object_context.path();
443 wasp::HITNodeView type_node = object_context.first_child_by_name(
"type");
444 const std::string & object_type =
445 type_node.is_null() ?
"" : wasp::strip_quotes(hit::extractValue(type_node.data()));
448 std::set<std::string> existing_params, existing_subblocks;
455 std::set<std::string> obj_act_tasks;
463 if (is_request_in_open_block(request_context) || is_request_on_param_decl(request_context))
474 if (is_request_in_open_block(request_context) || is_request_on_param_decl(request_context) ||
475 is_request_on_block_decl(request_context))
483 is_request_on_block_decl(request_context));
486 if ((request_context.type() == wasp::VALUE || request_context.type() == wasp::ASSIGN ||
487 request_context.type() == wasp::OVERRIDE_ASSIGN) &&
501 is_incomplete = !pass;
508 std::set<std::string> & existing_params,
509 std::set<std::string> & existing_subblocks)
512 for (
auto itr = parent_node.begin(); itr != parent_node.end(); itr.next())
514 auto child_node = itr.get();
517 if (child_node.type() == wasp::KEYED_VALUE || child_node.type() == wasp::ARRAY)
518 existing_params.insert(child_node.name());
519 else if (child_node.type() == wasp::OBJECT)
520 existing_subblocks.insert(child_node.name());
526 const std::string & object_path,
527 const std::string & object_type,
528 std::set<std::string> & obj_act_tasks)
538 const std::string & object_path,
539 std::set<std::string> & obj_act_tasks)
546 std::string registered_syntax = syntax.
isAssociated(object_path, &is_parent);
552 auto action_range = syntax.
getActions(registered_syntax);
555 for (
auto action_iter = action_range.first; action_iter != action_range.second; action_iter++)
557 const std::string & action_name = action_iter->second._action;
565 if (action_params.
get<
bool>(
"isObjectAction"))
567 std::set<std::string> tasks_by_actions = action_factory.
getTasksByAction(action_name);
568 obj_act_tasks.insert(tasks_by_actions.begin(), tasks_by_actions.end());
572 action_params.
remove(
"isObjectAction");
576 valid_params += action_params;
583 std::string object_type,
584 const std::set<std::string> & obj_act_tasks)
590 if (object_type.empty() && valid_params.
have_parameter<std::string>(
"type") &&
591 !valid_params.
get<std::string>(
"type").empty())
593 object_type = valid_params.
get<std::string>(
"type");
608 const std::string & moose_base = object_params.
getBase();
610 for (
const auto & obj_act_task : obj_act_tasks)
615 valid_params += object_params;
623 if (valid_params.
have_parameter<std::vector<std::string>>(
"_object_params_set_by_action"))
625 auto names = valid_params.
get<std::vector<std::string>>(
"_object_params_set_by_action");
626 for (
const auto &
name : names)
630 valid_params.
remove(
"_object_params_set_by_action");
637 const std::set<std::string> & existing_params,
638 int replace_line_beg,
639 int replace_char_beg,
640 int replace_line_end,
641 int replace_char_end,
642 const std::string & filtering_prefix)
647 for (
const auto & valid_params_iter : valid_params)
649 const std::string & param_name = valid_params_iter.first;
650 bool deprecated = valid_params.isParamDeprecated(param_name);
651 bool is_private = valid_params.isPrivate(param_name);
654 if (deprecated || is_private || existing_params.count(param_name))
658 if (param_name.rfind(filtering_prefix, 0) != 0)
662 std::string dirty_type = valid_params.type(param_name);
665 std::string doc_string = valid_params.getDocString(param_name);
669 bool is_array = basic_type.compare(0, 6,
"Array:") == 0;
672 pcrecpp::RE(
"(Array:)*(.*)").GlobalReplace(
"\\2", &basic_type);
675 pcrecpp::RE(
".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace(
"\\1", &clean_type);
681 std::string default_value;
684 if (valid_params.isParamValid(param_name))
691 else if (valid_params.hasDefaultCoupledValue(param_name))
693 std::ostringstream oss;
694 oss << valid_params.defaultCoupledValue(param_name);
695 default_value = oss.str();
699 if (basic_type ==
"Boolean" && default_value ==
"1")
700 default_value =
"true";
701 else if (basic_type ==
"Boolean" && default_value ==
"0")
702 default_value =
"false";
705 std::string array_quote = is_array && !default_value.empty() ?
"'" :
"";
709 std::string insert_text;
710 if (client_snippet_support && !default_value.empty())
712 text_format = wasp::lsp::m_text_format_snippet;
713 insert_text = param_name +
" = " + array_quote +
"${1:" + default_value +
"}" + array_quote;
717 text_format = wasp::lsp::m_text_format_plaintext;
718 insert_text = param_name +
" = " + array_quote + default_value + array_quote;
723 completionItems.push_back(wasp::DataObject());
724 wasp::DataObject * item = completionItems.back().to_object();
725 pass &= wasp::lsp::buildCompletionObject(*item,
746 const std::string & object_path,
747 int replace_line_beg,
748 int replace_char_beg,
749 int replace_line_end,
750 int replace_char_end,
751 const std::string & filtering_prefix,
752 bool request_on_block_decl)
757 std::set<std::string> syntax_paths_processed;
764 std::string syntax_path =
"/" + syntax_path_iter.first;
767 if (!syntax_paths_processed.insert(syntax_path).second)
771 for (std::size_t last_sep; (last_sep = syntax_path.find_last_of(
"/")) != std::string::npos;)
773 std::string subblock_name = syntax_path.substr(last_sep + 1);
774 syntax_path = syntax_path.substr(0, last_sep);
786 if (!registered_syntax.empty() || object_path ==
"/")
789 int text_format = client_snippet_support ? wasp::lsp::m_text_format_snippet
790 : wasp::lsp::m_text_format_plaintext;
795 if (subblock_name !=
"*" && subblock_name.rfind(filtering_prefix, 0) != 0)
798 std::string doc_string;
799 std::string insert_text;
803 const std::string full_block_path = object_path +
"/" + subblock_name;
807 if (subblock_name ==
"*")
809 doc_string =
"custom user named block";
810 insert_text = (request_on_block_decl ?
"" :
"[") +
811 (filtering_prefix.size() ? filtering_prefix :
"block_name") +
"]" +
812 req_params +
"\n " + (client_snippet_support ?
"$0" :
"") +
"\n[]";
813 complete_kind = wasp::lsp::m_comp_kind_variable;
817 doc_string =
"application named block";
818 insert_text = (request_on_block_decl ?
"" :
"[") + subblock_name +
"]" + req_params +
819 "\n " + (client_snippet_support ?
"$0" :
"") +
"\n[]";
820 complete_kind = wasp::lsp::m_comp_kind_struct;
824 completionItems.push_back(wasp::DataObject());
825 wasp::DataObject * item = completionItems.back().to_object();
826 pass &= wasp::lsp::buildCompletionObject(*item,
849 const std::set<std::string> & existing_params,
850 const std::set<std::string> & existing_subblocks,
851 const std::string & param_name,
852 const std::set<std::string> & obj_act_tasks,
853 const std::string & object_path,
854 int replace_line_beg,
855 int replace_char_beg,
856 int replace_line_end,
857 int replace_char_end)
863 std::string dirty_type = valid_params.
type(param_name);
868 pcrecpp::RE(
"(Array:)*(.*)").GlobalReplace(
"\\2", &basic_type);
871 pcrecpp::RE(
".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace(
"\\1", &clean_type);
877 std::map<std::string, std::string> options_and_descs;
880 if (param_name ==
"active" || param_name ==
"inactive")
881 for (
const auto & subblock_name : existing_subblocks)
882 options_and_descs[subblock_name] =
"subblock name";
885 else if (basic_type ==
"Boolean")
887 options_and_descs[
"true"];
888 options_and_descs[
"false"];
898 else if (valid_params.
have_parameter<std::vector<MooseEnum>>(param_name))
899 getEnumsAndDocs(valid_params.
get<std::vector<MooseEnum>>(param_name)[0], options_and_descs);
902 else if (param_name ==
"type")
907 const std::string & object_name = objects_iter.first;
908 const InputParameters & object_params = objects_iter.second->buildParameters();
912 req_params += req_params.size() ?
"\n" + std::string(client_snippet_support ?
"$0" :
"") :
"";
917 const std::string & moose_base = object_params.
getBase();
920 for (
const auto & obj_act_task : obj_act_tasks)
926 options_and_descs[object_name + req_params] = type_description;
940 const std::string &
type = associated_types_iter.second;
941 const std::string & path = associated_types_iter.first;
951 wasp::HITNodeView view_root =
getRoot().getNodeView();
954 for (
const auto & input_path : input_path_iter->second)
957 wasp::SIRENInterpreter<> selector;
958 if (!selector.parseString(input_path))
960 wasp::SIRENResultSet<wasp::HITNodeView> results;
961 std::size_t count = selector.evaluate(view_root, results);
964 for (std::size_t i = 0; i < count; i++)
965 if (results.adapted(i).type() == wasp::OBJECT)
966 options_and_descs[results.adapted(i).name()] =
"from /" + input_path;
972 int text_format = client_snippet_support ? wasp::lsp::m_text_format_snippet
973 : wasp::lsp::m_text_format_plaintext;
978 for (
const auto & option_and_desc : options_and_descs)
980 const std::string & insert_text = option_and_desc.first;
981 const std::string & option_name = insert_text.substr(0, insert_text.find(
'\n'));
982 const std::string & description = option_and_desc.second;
985 completionItems.push_back(wasp::DataObject());
986 wasp::DataObject * item = completionItems.back().to_object();
987 pass &= wasp::lsp::buildCompletionObject(*item,
1006 template <
typename MooseEnumType>
1009 std::map<std::string, std::string> & options_and_descs)
1012 const auto & enum_docs = moose_enum_param.getItemDocumentation();
1015 for (
const auto & item : moose_enum_param.items())
1016 options_and_descs[item.name()] = enum_docs.count(item) ? enum_docs.at(item) :
"";
1030 auto & root = *root_ptr;
1033 wasp::HITNodeView view_root = root.getNodeView();
1034 wasp::HITNodeView request_context =
1035 wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
1038 if (request_context.type() != wasp::VALUE)
1042 std::string param_name = request_context.has_parent() ? request_context.parent().name() :
"";
1043 std::string val_string = request_context.last_as_string();
1046 if (param_name ==
"type" && factory.
isRegistered(val_string))
1052 if (!file_line_info.
isValid() ||
1057 auto location_uri = wasp::lsp::m_uri_prefix + file_line_info.
file();
1060 definitionLocations.push_back(wasp::DataObject());
1061 wasp::DataObject * location = definitionLocations.back().to_object();
1062 return wasp::lsp::buildLocationObject(*location,
1065 file_line_info.
line() - 1,
1067 file_line_info.
line() - 1,
1072 wasp::HITNodeView object_context = request_context;
1073 while (object_context.type() != wasp::OBJECT && object_context.has_parent())
1074 object_context = object_context.parent();
1075 const std::string & object_path = object_context.path();
1076 wasp::HITNodeView type_node = object_context.first_child_by_name(
"type");
1077 const std::string & object_type =
1078 type_node.is_null() ?
"" : wasp::strip_quotes(hit::extractValue(type_node.data()));
1084 std::set<std::string> obj_act_tasks;
1091 [](
const wasp::HITNodeView & l,
const wasp::HITNodeView & r)
1093 const std::string & l_file = l.node_pool()->stream_name();
1094 const std::string & r_file = r.node_pool()->stream_name();
1095 return (l_file < r_file || (l_file == r_file && l.line() < r.line()) ||
1096 (l_file == r_file && l.line() == r.line() && l.column() < r.column()));
1100 for (
const auto & valid_params_iter : valid_params)
1102 if (valid_params_iter.first == param_name)
1105 std::string dirty_type = valid_params.type(param_name);
1107 pcrecpp::RE(
".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace(
"\\1", &clean_type);
1116 if (location_nodes.empty() && request_context.has_parent() &&
1117 request_context.parent().child_count_by_name(
"decl"))
1118 location_nodes.insert(request_context.parent().first_child_by_name(
"decl"));
1126 const std::string & clean_type,
1127 const std::string & val_string)
1136 const std::string &
type = associated_types_iter.second;
1137 const std::string & path = associated_types_iter.first;
1150 wasp::HITNodeView view_root =
getRoot().getNodeView();
1153 for (
const auto & input_path : input_path_iter->second)
1156 wasp::SIRENInterpreter<> selector;
1157 if (!selector.parseString(input_path))
1159 wasp::SIRENResultSet<wasp::HITNodeView> results;
1160 std::size_t count = selector.evaluate(view_root, results);
1163 for (std::size_t i = 0; i < count; i++)
1164 if (results.adapted(i).type() == wasp::OBJECT && results.adapted(i).name() == val_string &&
1165 results.adapted(i).child_count_by_name(
"decl"))
1166 location_nodes.insert(results.adapted(i).first_child_by_name(
"decl"));
1177 for (
const auto & location_nodes_iter : location_nodes)
1180 auto location_uri = wasp::lsp::m_uri_prefix + location_nodes_iter.node_pool()->stream_name();
1183 defsOrRefsLocations.push_back(wasp::DataObject());
1184 wasp::DataObject * location = defsOrRefsLocations.back().to_object();
1185 pass &= wasp::lsp::buildLocationObject(*location,
1188 location_nodes_iter.line() - 1,
1189 location_nodes_iter.column() - 1,
1190 location_nodes_iter.last_line() - 1,
1191 location_nodes_iter.last_column());
1207 auto & root = *root_ptr;
1210 wasp::HITNodeView view_root = root.getNodeView();
1211 wasp::HITNodeView request_context =
1212 wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
1215 if ((request_context.type() != wasp::DECL && request_context.type() != wasp::VALUE) ||
1216 !request_context.has_parent() ||
1217 (request_context.parent().type() != wasp::KEYED_VALUE &&
1218 request_context.parent().type() != wasp::ARRAY))
1222 std::string paramkey = request_context.parent().name();
1223 std::string paramval = request_context.last_as_string();
1226 wasp::HITNodeView object_context = request_context;
1227 while (object_context.type() != wasp::OBJECT && object_context.has_parent())
1228 object_context = object_context.parent();
1229 const std::string object_path = object_context.path();
1230 wasp::HITNodeView type_node = object_context.first_child_by_name(
"type");
1231 const std::string object_type =
1232 type_node.is_null() ?
"" : wasp::strip_quotes(hit::extractValue(type_node.data()));
1236 std::set<std::string> obj_act_tasks;
1240 if (request_context.type() == wasp::VALUE && paramkey ==
"type" && factory.
isRegistered(paramval))
1245 const std::string & moose_base = object_params.
getBase();
1246 for (
const auto & obj_act_task : obj_act_tasks)
1258 else if (request_context.type() == wasp::VALUE)
1260 std::map<std::string, std::string> options_and_descs;
1267 else if (valid_params.
have_parameter<std::vector<MooseEnum>>(paramkey))
1268 getEnumsAndDocs(valid_params.
get<std::vector<MooseEnum>>(paramkey)[0], options_and_descs);
1269 if (options_and_descs.count(paramval))
1270 display_text = options_and_descs.find(paramval)->second;
1274 else if (request_context.type() == wasp::DECL && valid_params.
getParametersList().count(paramkey))
1285 bool include_declaration)
1293 auto & root = *root_ptr;
1296 wasp::HITNodeView view_root = root.getNodeView();
1297 wasp::HITNodeView request_context =
1298 wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
1301 if ((request_context.type() != wasp::DECL && request_context.type() != wasp::DOT_SLASH &&
1302 request_context.type() != wasp::LBRACKET && request_context.type() != wasp::RBRACKET) ||
1303 !request_context.has_parent() || request_context.parent().type() != wasp::OBJECT)
1307 const std::string & block_path = request_context.parent().path();
1308 const std::string & block_name = request_context.parent().name();
1314 const std::string & path = associated_types_iter.first;
1315 const std::string &
type = associated_types_iter.second;
1332 [](
const wasp::HITNodeView & l,
const wasp::HITNodeView & r)
1334 const std::string & l_file = l.node_pool()->stream_name();
1335 const std::string & r_file = r.node_pool()->stream_name();
1336 return (l_file < r_file || (l_file == r_file && l.line() < r.line()) ||
1337 (l_file == r_file && l.line() == r.line() && l.column() < r.column()));
1344 if (match_nodes.empty())
1348 if (include_declaration && request_context.parent().child_count_by_name(
"decl"))
1349 match_nodes.insert(request_context.parent().first_child_by_name(
"decl"));
1357 wasp::HITNodeView view_parent,
1358 const std::string & target_value,
1359 const std::set<std::string> & target_types)
1362 for (
const auto & view_child : view_parent)
1365 if (view_child.type() == wasp::VALUE && view_child.to_string() == target_value)
1368 wasp::HITNodeView object_context = view_child;
1369 while (object_context.type() != wasp::OBJECT && object_context.has_parent())
1370 object_context = object_context.parent();
1371 const std::string object_path = object_context.path();
1372 wasp::HITNodeView type_node = object_context.first_child_by_name(
"type");
1373 const std::string object_type =
1374 type_node.is_null() ?
"" : wasp::strip_quotes(hit::extractValue(type_node.data()));
1378 std::set<std::string> obj_act_tasks;
1382 std::string param_name = view_child.has_parent() ? view_child.parent().name() :
"";
1385 std::string dirty_type = valid_params.
type(param_name);
1387 pcrecpp::RE(
".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace(
"\\1", &clean_type);
1390 if (target_types.count(clean_type))
1391 match_nodes.insert(view_child);
1395 if (!view_child.is_leaf())
1406 std::string parse_file_path = document_path;
1407 pcrecpp::RE(
"(.*://)(.*)").Replace(
"\\2", &parse_file_path);
1410 std::stringstream input_errors, input_stream(getDocumentText());
1411 wasp::DefaultHITInterpreter interpreter(input_errors);
1414 if (!interpreter.parseStream(input_stream, parse_file_path))
1418 if (interpreter.root().is_null())
1422 wasp::HITNodeView view_root = interpreter.root();
1423 int document_start_line = view_root.line() - 1;
1424 int document_start_char = view_root.column() - 1;
1425 int document_last_line = view_root.last_line() - 1;
1426 int document_last_char = view_root.last_column();
1430 std::size_t starting_line = view_root.line() - 1;
1431 std::string document_format =
formatDocument(view_root, starting_line, 0);
1434 document_format.erase(0, 1);
1437 formattingTextEdits.push_back(wasp::DataObject());
1438 wasp::DataObject * item = formattingTextEdits.back().to_object();
1439 bool pass = wasp::lsp::buildTextEditObject(*item,
1441 document_start_line,
1442 document_start_char,
1456 auto collapse_spaces = [](std::string string_copy)
1458 pcrecpp::RE(
"\\s+").Replace(
" ", &string_copy);
1463 std::string format_string;
1466 for (
const auto i :
make_range(parent.child_count()))
1469 wasp::HITNodeView child = parent.child_at(i);
1472 auto decl = child.child_count_by_name(
"decl") ? child.first_child_by_name(
"decl").data() :
"";
1475 std::string blank = child.line() > prev_line + 1 ?
"\n" :
"";
1478 if (child.type() == wasp::FILE)
1479 format_string += blank + newline_indent +
MooseUtils::trim(collapse_spaces(child.data()));
1482 else if (child.type() == wasp::COMMENT)
1483 format_string += (child.line() == prev_line ?
" " : blank + newline_indent) +
1487 else if (child.type() == wasp::OBJECT && decl.empty())
1491 else if (child.type() == wasp::OBJECT)
1492 format_string += blank + newline_indent +
"[" + decl +
"]" +
1493 formatDocument(child, prev_line, level + 1) + newline_indent +
"[]";
1496 else if (child.type() == wasp::KEYED_VALUE || child.type() == wasp::ARRAY)
1498 const std::string prefix = newline_indent + decl +
" = ";
1500 const std::string render_val = hit::extractValue(child.data());
1501 std::size_t val_column = child.child_count() > 2 ? child.child_at(2).column() : 0;
1502 std::size_t prefix_len = prefix.size() - 1;
1504 format_string += blank + prefix + hit::formatValue(render_val, val_column, prefix_len);
1508 prev_line = child.last_line();
1512 return format_string;
1522 auto & root = *root_ptr;
1524 wasp::HITNodeView view_root = root.getNodeView();
1529 for (
const auto i :
make_range(view_root.child_count()))
1532 wasp::HITNodeView view_child = view_root.child_at(i);
1535 std::string
name = view_child.name();
1536 int line = view_child.line() - 1;
1537 int column = view_child.column() - 1;
1538 int last_line = view_child.last_line() - 1;
1539 int last_column = view_child.last_column();
1541 std::string detail =
1542 !view_child.first_child_by_name(
"type").is_null()
1543 ? wasp::strip_quotes(hit::extractValue(view_child.first_child_by_name(
"type").data()))
1547 documentSymbols.push_back(wasp::DataObject());
1548 wasp::DataObject * data_child = documentSymbols.back().to_object();
1549 pass &= wasp::lsp::buildDocumentSymbolObject(*data_child,
1573 wasp::DataObject & data_parent)
1576 if (wasp::is_nested_file(view_parent))
1582 for (
const auto i :
make_range(view_parent.child_count()))
1585 wasp::HITNodeView view_child = view_parent.child_at(i);
1588 std::string
name = view_child.name();
1589 int line = view_child.line() - 1;
1590 int column = view_child.column() - 1;
1591 int last_line = view_child.last_line() - 1;
1592 int last_column = view_child.last_column();
1594 std::string detail =
1595 !view_child.first_child_by_name(
"type").is_null()
1596 ? wasp::strip_quotes(hit::extractValue(view_child.first_child_by_name(
"type").data()))
1600 wasp::DataObject & data_child = wasp::lsp::addDocumentSymbolChild(data_parent);
1601 pass &= wasp::lsp::buildDocumentSymbolObject(data_child,
1625 const std::string & param_name,
1626 const std::string & clean_type,
1633 return wasp::lsp::m_comp_kind_event;
1634 else if (param_name ==
"active" || param_name ==
"inactive")
1635 return wasp::lsp::m_comp_kind_class;
1636 else if (clean_type ==
"bool")
1637 return wasp::lsp::m_comp_kind_interface;
1642 return is_param ? wasp::lsp::m_comp_kind_enum : wasp::lsp::m_comp_kind_enum_member;
1643 else if (param_name ==
"type")
1644 return wasp::lsp::m_comp_kind_type_param;
1645 else if (std::find_if(associated_types.begin(),
1646 associated_types.end(),
1647 [&](
const auto & entry)
1648 {
return entry.second == clean_type; }) != associated_types.end())
1649 return wasp::lsp::m_comp_kind_reference;
1651 return is_param ? wasp::lsp::m_comp_kind_keyword : wasp::lsp::m_comp_kind_value;
1658 auto is_boolean = [](wasp::HITNodeView symbol_node)
1662 return (iss >> std::boolalpha >>
convert && !iss.fail());
1664 auto is_number = [](wasp::HITNodeView symbol_node)
1667 std::istringstream iss(symbol_node.last_as_string());
1668 return (iss >>
convert && iss.eof());
1672 if (symbol_node.type() == wasp::OBJECT)
1673 return wasp::lsp::m_symbol_kind_struct;
1674 else if (symbol_node.type() == wasp::FILE)
1675 return wasp::lsp::m_symbol_kind_file;
1676 else if (symbol_node.type() == wasp::ARRAY)
1677 return wasp::lsp::m_symbol_kind_array;
1678 else if (symbol_node.type() == wasp::KEYED_VALUE && symbol_node.name() == std::string(
"type"))
1679 return wasp::lsp::m_symbol_kind_type_param;
1680 else if (symbol_node.type() == wasp::KEYED_VALUE && is_boolean(symbol_node))
1681 return wasp::lsp::m_symbol_kind_boolean;
1682 else if (symbol_node.type() == wasp::KEYED_VALUE && is_number(symbol_node))
1683 return wasp::lsp::m_symbol_kind_number;
1684 else if (symbol_node.type() == wasp::KEYED_VALUE)
1685 return wasp::lsp::m_symbol_kind_key;
1686 else if (symbol_node.type() == wasp::VALUE)
1687 return wasp::lsp::m_symbol_kind_string;
1689 return wasp::lsp::m_symbol_kind_property;
1694 const std::string & subblock_type,
1695 const std::set<std::string> & existing_params,
1696 const std::string & indent_spaces)
1700 std::set<std::string> obj_act_tasks;
1704 std::string required_param_text;
1705 std::size_t param_index = 1;
1706 for (
const auto & valid_params_iter : valid_params)
1709 const std::string & param_name = valid_params_iter.first;
1710 if (!valid_params.isParamDeprecated(param_name) && !valid_params.isPrivate(param_name) &&
1711 !valid_params.isParamValid(param_name) && valid_params.isParamRequired(param_name) &&
1712 !existing_params.count(param_name))
1714 std::string tab_stop = client_snippet_support ?
"$" + std::to_string(param_index++) :
"";
1715 required_param_text +=
"\n" + indent_spaces + param_name +
" = " + tab_stop;
1719 return required_param_text;
1724 const std::string & extensionMethod,
1730 if (extensionMethod ==
"plotting")
1742 auto & root = *root_ptr;
1745 wasp::HITNodeView view_root = root.getNodeView();
1746 wasp::HITNodeView request_context =
1747 wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
1750 wasp::HITNodeView object_context = request_context;
1751 while (object_context.type() != wasp::OBJECT && object_context.has_parent())
1752 object_context = object_context.parent();
1753 const std::string & object_name = object_context.name();
1754 wasp::HITNodeView type_node = object_context.first_child_by_name(
"type");
1755 const std::string & object_type =
1756 type_node.is_null() ?
"" : wasp::strip_quotes(hit::extractValue(type_node.data()));
1764 std::shared_ptr<FEProblemBase> &
problem = app_ptr->actionWarehouse().problemBase();
1769 if (!
problem->hasFunction(object_name))
1773 const auto * pw_func =
dynamic_cast<const PiecewiseBase *
>(&
problem->getFunction(object_name));
1778 if (pw_func->functionSize() == 0)
1782 std::vector<double> graph_keys, graph_vals;
1783 for (std::size_t i = 0; i < pw_func->functionSize(); i++)
1785 graph_keys.push_back(pw_func->domain(i));
1786 graph_vals.push_back(pw_func->range(i));
1790 std::string plot_title = object_name +
" " + object_type +
" Function";
1791 wasp::CustomPlot plot_object;
1793 plottingResponses.push_back(wasp::serializeCustomPlot(plot_object));
1800 const std::string & plot_title,
1801 const std::vector<double> & graph_keys,
1802 const std::vector<double> & graph_vals)
1805 double min_key = *std::min_element(graph_keys.begin(), graph_keys.end());
1806 double max_key = *std::max_element(graph_keys.begin(), graph_keys.end());
1807 double min_val = *std::min_element(graph_vals.begin(), graph_vals.end());
1808 double max_val = *std::max_element(graph_vals.begin(), graph_vals.end());
1811 double pad_factor = 0.05;
1812 double pad_x_axis = (max_key - min_key) * pad_factor;
1813 double pad_y_axis = (max_val - min_val) * pad_factor;
1814 min_key -= pad_x_axis;
1815 max_key += pad_x_axis;
1816 min_val -= pad_y_axis;
1817 max_val += pad_y_axis;
1820 plot_object.title().text(plot_title);
1821 plot_object.title().font().pointsize(18);
1822 plot_object.title().visible(
true);
1823 plot_object.legend().visible(
false);
1826 plot_object.x1Axis().label(
"abscissa values");
1827 plot_object.x1Axis().rangeMin(min_key);
1828 plot_object.x1Axis().rangeMax(max_key);
1829 plot_object.x1Axis().scaleType(wasp::CustomPlot::stLinear);
1830 plot_object.x1Axis().labelType(wasp::CustomPlot::ltNumber);
1831 plot_object.x1Axis().labelFont().pointsize(18);
1832 plot_object.x1Axis().tickLabelFont().pointsize(16);
1835 plot_object.y1Axis().label(
"ordinate values");
1836 plot_object.y1Axis().rangeMin(min_val);
1837 plot_object.y1Axis().rangeMax(max_val);
1838 plot_object.y1Axis().scaleType(wasp::CustomPlot::stLinear);
1839 plot_object.y1Axis().labelType(wasp::CustomPlot::ltNumber);
1840 plot_object.y1Axis().labelFont().pointsize(18);
1841 plot_object.y1Axis().tickLabelFont().pointsize(16);
1844 auto line_graph = std::make_shared<wasp::CustomPlot::Graph>();
1845 line_graph->keys() = graph_keys;
1846 line_graph->values() = graph_vals;
1847 line_graph->scatterShape(wasp::CustomPlot::ssDisc);
1848 plot_object.series().push_back(line_graph);
1858 mooseAssert(&app_ptr->parser() == parser_ptr,
"App should have this parser");
1860 if (
const auto root_ptr = parser_ptr->queryRoot())
1861 if (!root_ptr->getNodeView().is_null())
1871 return it ==
_check_state.end() ? nullptr : &it->second;
1884 return state ? state->parser.get() :
nullptr;
1890 return const_cast<Parser *
>(std::as_const(*this).queryCheckParser());
1897 return state->app.get();
1904 return const_cast<MooseApp *
>(std::as_const(*this).queryCheckApp());
1912 auto & app = *app_ptr;
1914 mooseAssert(&app.parser() ==
queryCheckParser(),
"Parser should be the app's parser");
1917 mooseError(
"MooseServer::getCheckApp(): App not available");
1925 mooseError(
"MooseServer::getRoot(): Root not available");
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
Function base which provides a piecewise approximation to a specified (x,y) point data set...
A MultiMooseEnum object to hold "execute_on" flags.
bool isRegistered(const std::string &obj_name) const
Returns a Boolean indicating whether an object type has been registered.
void addResourcesForDocument()
Add paths from includes and FileName parameters for client to watch.
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.
InputParameters getValidParams(const std::string &name)
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
std::shared_ptr< CommandLine > commandLine() const
Get the command line.
MooseServer(MooseApp &moose_app)
static const std::string main_app_name
The name for the "main" moose application.
void buildLineGraphPlot(wasp::CustomPlot &plot_object, const std::string &plot_title, const std::vector< double > &graph_keys, const std::vector< double > &graph_vals)
Build CustomPlot graph with provided keys, values, and plot title.
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.
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.
const InputParameters & parameters() const
Get the parameters of the object.
std::set< std::string > getTasksByAction(const std::string &action) const
virtual void run()
Run the application.
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.
const hit::Node & getRoot() const
Syntax & syntax()
Returns a writable reference to the syntax object.
bool getHoverDisplayText(std::string &display_text, int line, int character)
Get hover display text - logic specific to this server implemention.
ActionFactory & getActionFactory()
Retrieve a writable reference to the ActionFactory associated with this App.
const CheckState * queryCheckState() const
FileLineInfo getLineInfo(const std::string &name) const
Gets file and line information where an object was initially registered.
Factory & getFactory()
Retrieve a writable reference to the Factory associated with this App.
bool convert(const std::string &str, T &value, const bool throw_on_failure)
Takes the string representation of a value and converts it to the value.
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.
static std::unique_ptr< MooseApp > create(const std::string &app_type, const std::vector< std::string > &cli_args={})
Create an app with no input and command line arguments.
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)
const std::string & name() const
Get the name of the class.
const Parser * queryCheckParser() const
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...
const MooseApp * queryCheckApp() const
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.
virtual Problem & problem()
Deprecated: Return a reference to this Executioner's Problem instance.
const auto & registeredObjects() const
Returns a reference to the map from names to RegistryEntryBase pointers.
Helper for storing the state for a single document.
std::string toLower(std::string name)
Convert supplied string to lower case.
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.
void getFileNameTypeValues(std::set< std::string > &filename_vals, wasp::HITNodeView parent)
Recursively walk input to gather all FileName type parameter values.
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.
bool gatherExtensionResponses(wasp::DataArray &extensionResponses, const std::string &extensionMethod, int line, int character)
Gather extension responses - specific to this server implemention.
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.
Scoped helper for setting Moose::_throw_on_error during this scope.
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 gatherPlottingResponses(wasp::DataArray &plottingResponses, int line, int character)
Build CustomPlot extension responses when method name is plotting.
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...
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
Exception to be thrown whenever we have _throw_on_error set and a mooseError() is emitted...
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.
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
Class for parsing input files.
std::map< std::string, CheckState > _check_state
_check_state - map from document paths to state (parser, app, text)
const hit::Node * queryRoot() const
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::string prettyCppType(const std::string &cpp_type)