https://mooseframework.inl.gov
MooseServer.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "MooseServer.h"
11 #include "Moose.h"
12 #include "AppFactory.h"
13 #include "Syntax.h"
14 #include "ActionFactory.h"
15 #include "Factory.h"
16 #include "InputParameters.h"
17 #include "MooseUtils.h"
18 #include "MooseEnum.h"
19 #include "MultiMooseEnum.h"
20 #include "ExecFlagEnum.h"
21 #include "JsonSyntaxTree.h"
22 #include "FileLineInfo.h"
23 #include "CommandLine.h"
24 #include "Parser.h"
25 #include "FEProblemBase.h"
26 #include "PiecewiseBase.h"
27 #include "pcrecpp.h"
28 #include "hit/hit.h"
29 #include "wasphit/HITInterpreter.h"
30 #include "waspcore/utils.h"
31 #include "waspplot/CustomPlotSerialization.h"
32 #include <algorithm>
33 #include <vector>
34 #include <sstream>
35 #include <iostream>
36 #include <functional>
37 
39  : _moose_app(moose_app),
40  _connection(std::make_shared<wasp::lsp::IOStreamConnection>(this)),
41  _formatting_tab_size(0)
42 {
43  // add all implemented server capabilities to notify client in initialize
44  enableFullSync();
45  enableSymbols();
46  enableCompletion();
47  enableDefinition();
48  enableReferences();
49  enableFormatting();
50  enableHover();
51  enableExtension("plotting");
52 }
53 
54 bool
55 MooseServer::parseDocumentForDiagnostics(wasp::DataArray & diagnosticsList)
56 {
57  // Reset old parsers and applications if we have them
58  if (const auto it = _check_state.find(document_path); it != _check_state.end())
59  _check_state.erase(it);
60 
61  // strip prefix from document uri if it exists to get parse file path
62  std::string parse_file_path = document_path;
63  pcrecpp::RE("(.*://)(.*)").Replace("\\2", &parse_file_path);
64 
65  bool pass = true;
66 
67  // Adds a single diagnostic
68  const auto diagnostic = [this, &diagnosticsList, &pass](const std::string & message,
69  const int start_line,
70  const int start_column,
71  const std::optional<int> end_line = {},
72  const std::optional<int> end_column = {})
73  {
74  diagnosticsList.push_back(wasp::DataObject());
75  auto & diagnostic = *diagnosticsList.back().to_object();
76  pass &= wasp::lsp::buildDiagnosticObject(diagnostic,
77  errors,
78  start_line,
79  start_column,
80  end_line ? *end_line : start_line,
81  end_column ? *end_column : start_column,
82  1,
83  "moose_srv",
84  "check_inp",
85  message);
86  };
87 
88  // Adds a diagnostic on line zero
89  const auto zero_line_diagnostic = [&diagnostic](const std::string & message)
90  { diagnostic(message, 0, 0); };
91 
92  // Adds a diagnostic from a hit node, if the context of the hit node is valid
93  const auto hit_node_diagnostic = [&zero_line_diagnostic, &diagnostic, &parse_file_path](
94  const hit::Node * const node, const std::string & message)
95  {
96  // No node, root node, wrong file, or no line information: line zero diagnostic
97  if (!node || node->isRoot() || node->filename() != parse_file_path || !node->line() ||
98  !node->column())
99  zero_line_diagnostic(message);
100  // Have file and line context, diagnostic there
101  else
102  diagnostic(message, node->line() - 1, node->column() - 1);
103  };
104 
105  // Adds a diagnostic from a hit::ErrorMessage if the context is valid
106  const auto hit_error_message_diagnostic =
107  [&diagnostic, &zero_line_diagnostic, &parse_file_path](const hit::ErrorMessage & err)
108  {
109  // Has a filename
110  if (err.filename)
111  {
112  // For the open file
113  if (*err.filename == parse_file_path)
114  {
115  // Has line information that is valid
116  if (err.lineinfo && err.lineinfo->start_line && err.lineinfo->start_column &&
117  err.lineinfo->end_line && err.lineinfo->end_column)
118  {
119  diagnostic(err.message,
120  err.lineinfo->start_line - 1,
121  err.lineinfo->start_column - 1,
122  err.lineinfo->end_line - 1,
123  err.lineinfo->end_column - 1);
124  return;
125  }
126  }
127  // Has a file but not for this file, no diagnostic
128  else
129  return;
130  }
131 
132  // Don't have a filename, or have a filename that is this file without line info
133  zero_line_diagnostic(err.prefixed_message);
134  };
135 
136  // Runs a try catch loop with the given action, collecting diagnostics
137  // from the known exceptions; returns a bool that is true if we executed
138  // without throwing anything
139  const auto try_catch = [&hit_error_message_diagnostic,
140  &hit_node_diagnostic,
141  &zero_line_diagnostic](const auto & action) -> bool
142  {
143  Moose::ScopedThrowOnError scoped_throw_on_error;
144  bool threw = true;
145 
146  try
147  {
148  action();
149  threw = false;
150  }
151  // Will be thrown from the Parser while building the tree or
152  // by the builder while building the input parameters
153  catch (Parser::Error & err)
154  {
155  for (const auto & error_message : err.error_messages)
156  hit_error_message_diagnostic(error_message);
157  }
158  // Will be thrown by mooseError() when _throw_on_error is set
159  // to true, hopefully with hit node context
160  catch (MooseRuntimeError & err)
161  {
162  hit_node_diagnostic(err.getNode(), err.what());
163  }
164  // General catch all for everything else without context
165  catch (std::exception & err)
166  {
167  zero_line_diagnostic(err.what());
168  }
169 
170  return !threw;
171  };
172 
173  // Setup command line (needed by the Parser)
174  auto command_line = std::make_unique<CommandLine>(_moose_app.commandLine()->getArguments());
175  if (command_line->hasArgument("--language-server"))
176  command_line->removeArgument("--language-server");
177  command_line->addArgument("--check-input");
178  command_line->addArgument("--error-unused");
179  command_line->addArgument("--error");
180  command_line->addArgument("--color=off");
181  command_line->addArgument("--disable-perf-graph-live");
182  command_line->parse();
183 
184  // Setup the parser that will be used in the app
185  auto parser = std::make_shared<Parser>(parse_file_path, document_text);
186  mooseAssert(parser->getInputFileNames()[0] == parse_file_path, "Should be consistent");
187  parser->setCommandLineParams(command_line->buildHitParams());
188  parser->setThrowOnError(true);
189 
190  // Try to parse the document
191  const bool parse_success = try_catch([&parser]() { parser->parse(); });
192  // If the Parser has a valid root, store it because we can use it
193  // in the future (hover text etc with a partially complete document)
194  CheckState * state = nullptr;
195  if (auto parser_root_ptr = parser->queryRoot())
196  if (!parser_root_ptr->getNodeView().is_null())
197  {
198  auto it_inserted_pair = _check_state.emplace(document_path, parser);
199  mooseAssert(it_inserted_pair.second, "Should not already exist");
200  state = &it_inserted_pair.first->second;
201  }
202 
203  // Failed to parse, don't bother building the app. But... we might
204  // have a root node at least!
205  if (!parse_success)
206  return pass;
207 
208  // Setup application options (including the Parser that succeeded)
209  InputParameters app_params = _moose_app.parameters();
210  app_params.set<std::shared_ptr<Parser>>("_parser") = parser;
211  app_params.set<std::shared_ptr<CommandLine>>("_command_line") = std::move(command_line);
212 
213  // Try to instantiate the application
214  std::unique_ptr<MooseApp> app = nullptr;
215  const auto do_build_app = [this, &app_params, &app]()
216  {
219  app_params,
220  _moose_app.getCommunicator()->get());
221  };
222  if (!try_catch(do_build_app))
223  {
224  if (app)
225  app.reset();
226  return pass;
227  }
228 
229  // Store the app
230  state->app = std::move(app);
231 
232  // Run the application, which will run the Builder
233  const auto do_run_app = [this]() { getCheckApp().run(); };
234  if (!try_catch(do_run_app))
235  state->app.reset(); // destroy if we failed to build
236 
237  return pass;
238 }
239 
240 bool
241 MooseServer::updateDocumentTextChanges(const std::string & replacement_text,
242  int /* start_line */,
243  int /* start_character */,
244  int /* end_line */,
245  int /* end_character*/,
246  int /* range_length*/)
247 {
248  // replacement text swaps full document as indicated in server capabilities
249  document_text = replacement_text;
250 
251  return true;
252 }
253 
254 bool
255 MooseServer::gatherDocumentCompletionItems(wasp::DataArray & completionItems,
256  bool & is_incomplete,
257  int line,
258  int character)
259 {
260  auto root_ptr = queryRoot();
261 
262  // add only root level blocks to completion list when parser root is null
263  if (!root_ptr)
264  return addSubblocksToList(completionItems, "/", line, character, line, character, "", false);
265  auto & root = *root_ptr;
266 
267  // lambdas that will be used for checking completion request context type
268  auto is_request_in_open_block = [](wasp::HITNodeView request_context) {
269  return request_context.type() == wasp::OBJECT || request_context.type() == wasp::DOCUMENT_ROOT;
270  };
271  auto is_request_on_param_decl = [](wasp::HITNodeView request_context)
272  {
273  return request_context.type() == wasp::DECL && request_context.has_parent() &&
274  (request_context.parent().type() == wasp::KEYED_VALUE ||
275  request_context.parent().type() == wasp::ARRAY);
276  };
277  auto is_request_on_block_decl = [](wasp::HITNodeView request_context)
278  {
279  return request_context.type() == wasp::DECL && request_context.has_parent() &&
280  request_context.parent().type() == wasp::OBJECT;
281  };
282 
283  // get document tree root used to find node under request line and column
284  wasp::HITNodeView view_root = root.getNodeView();
285  wasp::HITNodeView request_context;
286 
287  // find node under request location if it is not past all defined content
288  if (line + 1 < (int)view_root.last_line() ||
289  (line + 1 == (int)view_root.last_line() && character <= (int)view_root.last_column()))
290  request_context = wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
291 
292  // otherwise find last node in document with last line and column of tree
293  else
294  {
295  request_context =
296  wasp::findNodeUnderLineColumn(view_root, view_root.last_line(), view_root.last_column());
297 
298  // change context to be parent block or grandparent if block terminator
299  wasp::HITNodeView object_context = request_context;
300  while (object_context.type() != wasp::OBJECT && object_context.has_parent())
301  object_context = object_context.parent();
302  if (request_context.type() == wasp::OBJECT_TERM && object_context.has_parent())
303  object_context = object_context.parent();
304  request_context = object_context;
305  }
306 
307  // change context to equal sign if it is preceding node and in open block
308  if (is_request_in_open_block(request_context))
309  {
310  wasp::HITNodeView backup_context = request_context;
311  for (int backup_char = character; backup_context == request_context && --backup_char > 0;)
312  backup_context = wasp::findNodeUnderLineColumn(request_context, line + 1, backup_char + 1);
313  if (backup_context.type() == wasp::ASSIGN || backup_context.type() == wasp::OVERRIDE_ASSIGN)
314  request_context = backup_context;
315  }
316 
317  // use request context type to set up replacement range and prefix filter
318  int replace_line_beg = line;
319  int replace_char_beg = character;
320  int replace_line_end = line;
321  int replace_char_end = character;
322  std::string filtering_prefix;
323  if (request_context.type() == wasp::DECL || request_context.type() == wasp::VALUE)
324  {
325  // completion on existing block name, parameter name, or value replaces
326  replace_line_beg = request_context.line() - 1;
327  replace_char_beg = request_context.column() - 1;
328  replace_line_end = request_context.last_line() - 1;
329  replace_char_end = request_context.last_column();
330  filtering_prefix = request_context.data();
331 
332  // empty block name columns are same as bracket so bump replace columns
333  if (is_request_on_block_decl(request_context) && filtering_prefix.empty())
334  {
335  replace_char_beg++;
336  replace_char_end++;
337  }
338  }
339 
340  // get name of request context direct parent node so it can be used later
341  const auto & parent_name = request_context.has_parent() ? request_context.parent().name() : "";
342 
343  // get object context and value of type parameter for request if provided
344  wasp::HITNodeView object_context = request_context;
345  while (object_context.type() != wasp::OBJECT && object_context.has_parent())
346  object_context = object_context.parent();
347  if (is_request_on_block_decl(request_context))
348  object_context = object_context.parent();
349  const std::string & object_path = object_context.path();
350  wasp::HITNodeView type_node = object_context.first_child_by_name("type");
351  const std::string & object_type =
352  type_node.is_null() ? "" : wasp::strip_quotes(hit::extractValue(type_node.data()));
353 
354  // get set of all parameter and subblock names already specified in input
355  std::set<std::string> existing_params, existing_subblocks;
356  getExistingInput(object_context, existing_params, existing_subblocks);
357 
358  // set used to gather all parameters valid from object context of request
359  InputParameters valid_params = emptyInputParameters();
360 
361  // set used to gather MooseObjectAction tasks to verify object parameters
362  std::set<std::string> obj_act_tasks;
363 
364  // get set of global parameters, action parameters, and object parameters
365  getAllValidParameters(valid_params, object_path, object_type, obj_act_tasks);
366 
367  bool pass = true;
368 
369  // add gathered parameters to completion list with input range and prefix
370  if (is_request_in_open_block(request_context) || is_request_on_param_decl(request_context))
371  pass &= addParametersToList(completionItems,
372  valid_params,
373  existing_params,
374  replace_line_beg,
375  replace_char_beg,
376  replace_line_end,
377  replace_char_end,
378  filtering_prefix);
379 
380  // add all valid subblocks to completion list with input range and prefix
381  if (is_request_in_open_block(request_context) || is_request_on_param_decl(request_context) ||
382  is_request_on_block_decl(request_context))
383  pass &= addSubblocksToList(completionItems,
384  object_path,
385  replace_line_beg,
386  replace_char_beg,
387  replace_line_end,
388  replace_char_end,
389  filtering_prefix,
390  is_request_on_block_decl(request_context));
391 
392  // add valid parameter value options to completion list using input range
393  if ((request_context.type() == wasp::VALUE || request_context.type() == wasp::ASSIGN ||
394  request_context.type() == wasp::OVERRIDE_ASSIGN) &&
395  valid_params.getParametersList().count(parent_name))
396  pass &= addValuesToList(completionItems,
397  valid_params,
398  existing_params,
399  existing_subblocks,
400  parent_name,
401  obj_act_tasks,
402  object_path,
403  replace_line_beg,
404  replace_char_beg,
405  replace_line_end,
406  replace_char_end);
407 
408  is_incomplete = !pass;
409 
410  return pass;
411 }
412 
413 void
414 MooseServer::getExistingInput(wasp::HITNodeView parent_node,
415  std::set<std::string> & existing_params,
416  std::set<std::string> & existing_subblocks)
417 {
418  // gather names of all parameters and subblocks provided in input context
419  for (auto itr = parent_node.begin(); itr != parent_node.end(); itr.next())
420  {
421  auto child_node = itr.get();
422 
423  // add key value or array type as parameter and object type as subblock
424  if (child_node.type() == wasp::KEYED_VALUE || child_node.type() == wasp::ARRAY)
425  existing_params.insert(child_node.name());
426  else if (child_node.type() == wasp::OBJECT)
427  existing_subblocks.insert(child_node.name());
428  }
429 }
430 
431 void
433  const std::string & object_path,
434  const std::string & object_type,
435  std::set<std::string> & obj_act_tasks)
436 {
437  // gather global parameters then action parameters then object parameters
438  valid_params += Moose::Builder::validParams();
439  getActionParameters(valid_params, object_path, obj_act_tasks);
440  getObjectParameters(valid_params, object_type, obj_act_tasks);
441 }
442 
443 void
445  const std::string & object_path,
446  std::set<std::string> & obj_act_tasks)
447 {
448  Syntax & syntax = _moose_app.syntax();
449  ActionFactory & action_factory = _moose_app.getActionFactory();
450 
451  // get registered syntax path identifier using actual object context path
452  bool is_parent;
453  std::string registered_syntax = syntax.isAssociated(object_path, &is_parent);
454 
455  // use is_parent to skip action parameters when not explicitly registered
456  if (!is_parent)
457  {
458  // get action objects associated with registered syntax path identifier
459  auto action_range = syntax.getActions(registered_syntax);
460 
461  // traverse action objects for syntax to gather valid action parameters
462  for (auto action_iter = action_range.first; action_iter != action_range.second; action_iter++)
463  {
464  const std::string & action_name = action_iter->second._action;
465 
466  // use action name to get set of valid parameters from action factory
467  InputParameters action_params = action_factory.getValidParams(action_name);
468 
469  // gather all MooseObjectAction tasks for verifying object parameters
470  if (action_params.have_parameter<bool>("isObjectAction"))
471  {
472  if (action_params.get<bool>("isObjectAction"))
473  {
474  std::set<std::string> tasks_by_actions = action_factory.getTasksByAction(action_name);
475  obj_act_tasks.insert(tasks_by_actions.begin(), tasks_by_actions.end());
476  }
477 
478  // filter parameter from completion list as it is not used in input
479  action_params.remove("isObjectAction");
480  }
481 
482  // add parameters from action to full valid collection being gathered
483  valid_params += action_params;
484  }
485  }
486 }
487 
488 void
490  std::string object_type,
491  const std::set<std::string> & obj_act_tasks)
492 {
493  Syntax & syntax = _moose_app.syntax();
494  Factory & factory = _moose_app.getFactory();
495 
496  // use type parameter default if it exists and is not provided from input
497  if (object_type.empty() && valid_params.have_parameter<std::string>("type") &&
498  !valid_params.get<std::string>("type").empty())
499  {
500  object_type = valid_params.get<std::string>("type");
501 
502  // make type parameter not required in input since it has default value
503  valid_params.makeParamNotRequired("type");
504  }
505 
506  // check if object type has been registered to prevent unregistered error
507  if (factory.isRegistered(object_type))
508  {
509  // use object type to get set of valid parameters registered in factory
510  InputParameters object_params = factory.getValidParams(object_type);
511 
512  // check if object has base associated with any MooseObjectAction tasks
513  if (object_params.hasBase())
514  {
515  const std::string & moose_base = object_params.getBase();
516 
517  for (const auto & obj_act_task : obj_act_tasks)
518  {
519  if (syntax.verifyMooseObjectTask(moose_base, obj_act_task))
520  {
521  // add parameters from object to valid collection if base matches
522  valid_params += object_params;
523  break;
524  }
525  }
526  }
527  }
528 
529  // make parameters from list of those set by action not required in input
530  if (valid_params.have_parameter<std::vector<std::string>>("_object_params_set_by_action"))
531  {
532  auto names = valid_params.get<std::vector<std::string>>("_object_params_set_by_action");
533  for (const auto & name : names)
534  valid_params.makeParamNotRequired(name);
535 
536  // filter parameter from completion list since it is not used for input
537  valid_params.remove("_object_params_set_by_action");
538  }
539 }
540 
541 bool
542 MooseServer::addParametersToList(wasp::DataArray & completionItems,
543  const InputParameters & valid_params,
544  const std::set<std::string> & existing_params,
545  int replace_line_beg,
546  int replace_char_beg,
547  int replace_line_end,
548  int replace_char_end,
549  const std::string & filtering_prefix)
550 {
551  bool pass = true;
552 
553  // walk over collection of all valid parameters and build completion list
554  for (const auto & valid_params_iter : valid_params)
555  {
556  const std::string & param_name = valid_params_iter.first;
557  bool deprecated = valid_params.isParamDeprecated(param_name);
558  bool is_private = valid_params.isPrivate(param_name);
559 
560  // filter out parameters that are deprecated, private, or already exist
561  if (deprecated || is_private || existing_params.count(param_name))
562  continue;
563 
564  // filter out parameters that do not begin with prefix if one was given
565  if (param_name.rfind(filtering_prefix, 0) != 0)
566  continue;
567 
568  // process parameter description and type to use in input default value
569  std::string dirty_type = valid_params.type(param_name);
570  std::string clean_type = MooseUtils::prettyCppType(dirty_type);
571  std::string basic_type = JsonSyntaxTree::basicCppType(clean_type);
572  std::string doc_string = valid_params.getDocString(param_name);
573  MooseUtils::escape(doc_string);
574 
575  // use basic type to decide if parameter is array and quotes are needed
576  bool is_array = basic_type.compare(0, 6, "Array:") == 0;
577 
578  // remove any array prefixes from basic type string and leave base type
579  pcrecpp::RE("(Array:)*(.*)").GlobalReplace("\\2", &basic_type);
580 
581  // prepare clean cpp type string to be used for key to find input paths
582  pcrecpp::RE(".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace("\\1", &clean_type);
583 
584  // decide completion item kind that client may use to display list icon
585  int complete_kind = getCompletionItemKind(valid_params, param_name, clean_type, true);
586 
587  // default value for completion to be built using parameter information
588  std::string default_value;
589 
590  // first if parameter default is set then use it to build default value
591  if (valid_params.isParamValid(param_name))
592  {
593  default_value = JsonSyntaxTree::buildOutputString(valid_params_iter);
594  default_value = MooseUtils::trim(default_value);
595  }
596 
597  // otherwise if parameter has coupled default then use as default value
598  else if (valid_params.hasDefaultCoupledValue(param_name))
599  {
600  std::ostringstream oss;
601  oss << valid_params.defaultCoupledValue(param_name);
602  default_value = oss.str();
603  }
604 
605  // switch 1 to true or 0 to false if boolean parameter as default value
606  if (basic_type == "Boolean" && default_value == "1")
607  default_value = "true";
608  else if (basic_type == "Boolean" && default_value == "0")
609  default_value = "false";
610 
611  // wrap default value with single quotes if it exists and type is array
612  std::string array_quote = is_array && !default_value.empty() ? "'" : "";
613 
614  // choose format of insertion text based on if client supports snippets
615  int text_format;
616  std::string insert_text;
617  if (client_snippet_support && !default_value.empty())
618  {
619  text_format = wasp::lsp::m_text_format_snippet;
620  insert_text = param_name + " = " + array_quote + "${1:" + default_value + "}" + array_quote;
621  }
622  else
623  {
624  text_format = wasp::lsp::m_text_format_plaintext;
625  insert_text = param_name + " = " + array_quote + default_value + array_quote;
626  }
627  // finally build full insertion from parameter name, quote, and default
628 
629  // add parameter label, insert text, and description to completion list
630  completionItems.push_back(wasp::DataObject());
631  wasp::DataObject * item = completionItems.back().to_object();
632  pass &= wasp::lsp::buildCompletionObject(*item,
633  errors,
634  param_name,
635  replace_line_beg,
636  replace_char_beg,
637  replace_line_end,
638  replace_char_end,
639  insert_text,
640  complete_kind,
641  "",
642  doc_string,
643  false,
644  false,
645  text_format);
646  }
647 
648  return pass;
649 }
650 
651 bool
652 MooseServer::addSubblocksToList(wasp::DataArray & completionItems,
653  const std::string & object_path,
654  int replace_line_beg,
655  int replace_char_beg,
656  int replace_line_end,
657  int replace_char_end,
658  const std::string & filtering_prefix,
659  bool request_on_block_decl)
660 {
661  Syntax & syntax = _moose_app.syntax();
662 
663  // set used to prevent reprocessing syntax paths for more than one action
664  std::set<std::string> syntax_paths_processed;
665 
666  // build map of all syntax paths to names for subblocks and save to reuse
667  if (_syntax_to_subblocks.empty())
668  {
669  for (const auto & syntax_path_iter : syntax.getAssociatedActions())
670  {
671  std::string syntax_path = "/" + syntax_path_iter.first;
672 
673  // skip current syntax path if already processed for different action
674  if (!syntax_paths_processed.insert(syntax_path).second)
675  continue;
676 
677  // walk backward through syntax path adding subblock names to parents
678  for (std::size_t last_sep; (last_sep = syntax_path.find_last_of("/")) != std::string::npos;)
679  {
680  std::string subblock_name = syntax_path.substr(last_sep + 1);
681  syntax_path = syntax_path.substr(0, last_sep);
682  _syntax_to_subblocks[syntax_path].insert(subblock_name);
683  }
684  }
685  }
686 
687  // get registered syntax from object path using map of paths to subblocks
688  std::string registered_syntax = syntax.isAssociated(object_path, nullptr, _syntax_to_subblocks);
689 
690  bool pass = true;
691 
692  // walk over subblock names if found or at root and build completion list
693  if (!registered_syntax.empty() || object_path == "/")
694  {
695  // choose format of insertion text based on if client supports snippets
696  int text_format = client_snippet_support ? wasp::lsp::m_text_format_snippet
697  : wasp::lsp::m_text_format_plaintext;
698 
699  for (const auto & subblock_name : _syntax_to_subblocks[registered_syntax])
700  {
701  // filter subblock if it does not begin with prefix and one was given
702  if (subblock_name != "*" && subblock_name.rfind(filtering_prefix, 0) != 0)
703  continue;
704 
705  std::string doc_string;
706  std::string insert_text;
707  int complete_kind;
708 
709  // build required parameter list for each block to use in insert text
710  const std::string full_block_path = object_path + "/" + subblock_name;
711  const std::string req_params = getRequiredParamsText(full_block_path, "", {}, " ");
712 
713  // customize description and insert text for star and named subblocks
714  if (subblock_name == "*")
715  {
716  doc_string = "custom user named block";
717  insert_text = (request_on_block_decl ? "" : "[") +
718  (filtering_prefix.size() ? filtering_prefix : "block_name") + "]" +
719  req_params + "\n " + (client_snippet_support ? "$0" : "") + "\n[]";
720  complete_kind = wasp::lsp::m_comp_kind_variable;
721  }
722  else
723  {
724  doc_string = "application named block";
725  insert_text = (request_on_block_decl ? "" : "[") + subblock_name + "]" + req_params +
726  "\n " + (client_snippet_support ? "$0" : "") + "\n[]";
727  complete_kind = wasp::lsp::m_comp_kind_struct;
728  }
729 
730  // add subblock name, insert text, and description to completion list
731  completionItems.push_back(wasp::DataObject());
732  wasp::DataObject * item = completionItems.back().to_object();
733  pass &= wasp::lsp::buildCompletionObject(*item,
734  errors,
735  subblock_name,
736  replace_line_beg,
737  replace_char_beg,
738  replace_line_end,
739  replace_char_end,
740  insert_text,
741  complete_kind,
742  "",
743  doc_string,
744  false,
745  false,
746  text_format);
747  }
748  }
749 
750  return pass;
751 }
752 
753 bool
754 MooseServer::addValuesToList(wasp::DataArray & completionItems,
755  const InputParameters & valid_params,
756  const std::set<std::string> & existing_params,
757  const std::set<std::string> & existing_subblocks,
758  const std::string & param_name,
759  const std::set<std::string> & obj_act_tasks,
760  const std::string & object_path,
761  int replace_line_beg,
762  int replace_char_beg,
763  int replace_line_end,
764  int replace_char_end)
765 {
766  Syntax & syntax = _moose_app.syntax();
767  Factory & factory = _moose_app.getFactory();
768 
769  // get clean type for path associations and basic type for boolean values
770  std::string dirty_type = valid_params.type(param_name);
771  std::string clean_type = MooseUtils::prettyCppType(dirty_type);
772  std::string basic_type = JsonSyntaxTree::basicCppType(clean_type);
773 
774  // remove any array prefixes from basic type string and replace with base
775  pcrecpp::RE("(Array:)*(.*)").GlobalReplace("\\2", &basic_type);
776 
777  // prepare clean cpp type string to be used for a key to find input paths
778  pcrecpp::RE(".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace("\\1", &clean_type);
779 
780  // decide completion item kind that client may use to display a list icon
781  int complete_kind = getCompletionItemKind(valid_params, param_name, clean_type, false);
782 
783  // map used to gather options and descriptions for value completion items
784  std::map<std::string, std::string> options_and_descs;
785 
786  // first if parameter name is active or inactive then use input subblocks
787  if (param_name == "active" || param_name == "inactive")
788  for (const auto & subblock_name : existing_subblocks)
789  options_and_descs[subblock_name] = "subblock name";
790 
791  // otherwise if parameter type is boolean then use true and false strings
792  else if (basic_type == "Boolean")
793  {
794  options_and_descs["true"];
795  options_and_descs["false"];
796  }
797 
798  // otherwise if parameter type is one of the enums then use valid options
799  else if (valid_params.have_parameter<MooseEnum>(param_name))
800  getEnumsAndDocs(valid_params.get<MooseEnum>(param_name), options_and_descs);
801  else if (valid_params.have_parameter<MultiMooseEnum>(param_name))
802  getEnumsAndDocs(valid_params.get<MultiMooseEnum>(param_name), options_and_descs);
803  else if (valid_params.have_parameter<ExecFlagEnum>(param_name))
804  getEnumsAndDocs(valid_params.get<ExecFlagEnum>(param_name), options_and_descs);
805  else if (valid_params.have_parameter<std::vector<MooseEnum>>(param_name))
806  getEnumsAndDocs(valid_params.get<std::vector<MooseEnum>>(param_name)[0], options_and_descs);
807 
808  // otherwise if parameter name is type then use all verified object names
809  else if (param_name == "type")
810  {
811  // walk over entire set of objects that have been registered in factory
812  for (const auto & objects_iter : factory.registeredObjects())
813  {
814  const std::string & object_name = objects_iter.first;
815  const InputParameters & object_params = objects_iter.second->buildParameters();
816 
817  // build required parameter list for each block to use in insert text
818  std::string req_params = getRequiredParamsText(object_path, object_name, existing_params, "");
819  req_params += req_params.size() ? "\n" + std::string(client_snippet_support ? "$0" : "") : "";
820 
821  // check if object has registered base parameter that can be verified
822  if (!object_params.hasBase())
823  continue;
824  const std::string & moose_base = object_params.getBase();
825 
826  // walk over gathered MooseObjectAction tasks and add if base matches
827  for (const auto & obj_act_task : obj_act_tasks)
828  {
829  if (!syntax.verifyMooseObjectTask(moose_base, obj_act_task))
830  continue;
831  std::string type_description = object_params.getClassDescription();
832  MooseUtils::escape(type_description);
833  options_and_descs[object_name + req_params] = type_description;
834  break;
835  }
836  }
837  }
838 
839  // otherwise if parameter type has any associated syntax then use lookups
840  else
841  {
842  // build map of parameter types to input lookup paths and save to reuse
843  if (_type_to_input_paths.empty())
844  {
845  for (const auto & associated_types_iter : syntax.getAssociatedTypes())
846  {
847  const std::string & type = associated_types_iter.second;
848  const std::string & path = associated_types_iter.first;
849  _type_to_input_paths[type].insert(path);
850  }
851  }
852 
853  // check for input lookup paths that are associated with parameter type
854  const auto & input_path_iter = _type_to_input_paths.find(clean_type);
855 
856  if (input_path_iter != _type_to_input_paths.end())
857  {
858  wasp::HITNodeView view_root = getRoot().getNodeView();
859 
860  // walk over all syntax paths that are associated with parameter type
861  for (const auto & input_path : input_path_iter->second)
862  {
863  // use wasp siren to gather all input values at current lookup path
864  wasp::SIRENInterpreter<> selector;
865  if (!selector.parseString(input_path))
866  continue;
867  wasp::SIRENResultSet<wasp::HITNodeView> results;
868  std::size_t count = selector.evaluate(view_root, results);
869 
870  // walk over results and add each input value found at current path
871  for (std::size_t i = 0; i < count; i++)
872  if (results.adapted(i).type() == wasp::OBJECT)
873  options_and_descs[results.adapted(i).name()] = "from /" + input_path;
874  }
875  }
876  }
877 
878  // choose format of insertion text based on if client has snippet support
879  int text_format = client_snippet_support ? wasp::lsp::m_text_format_snippet
880  : wasp::lsp::m_text_format_plaintext;
881 
882  bool pass = true;
883 
884  // walk over pairs of options with descriptions and build completion list
885  for (const auto & option_and_desc : options_and_descs)
886  {
887  const std::string & insert_text = option_and_desc.first;
888  const std::string & option_name = insert_text.substr(0, insert_text.find('\n'));
889  const std::string & description = option_and_desc.second;
890 
891  // add option name, insertion range, and description to completion list
892  completionItems.push_back(wasp::DataObject());
893  wasp::DataObject * item = completionItems.back().to_object();
894  pass &= wasp::lsp::buildCompletionObject(*item,
895  errors,
896  option_name,
897  replace_line_beg,
898  replace_char_beg,
899  replace_line_end,
900  replace_char_end,
901  insert_text,
902  complete_kind,
903  "",
904  description,
905  false,
906  false,
907  text_format);
908  }
909 
910  return pass;
911 }
912 
913 template <typename MooseEnumType>
914 void
915 MooseServer::getEnumsAndDocs(MooseEnumType & moose_enum_param,
916  std::map<std::string, std::string> & options_and_descs)
917 {
918  // get map that contains any documentation strings provided for each item
919  const auto & enum_docs = moose_enum_param.getItemDocumentation();
920 
921  // walk over enums filling map with options and any provided descriptions
922  for (const auto & item : moose_enum_param.items())
923  options_and_descs[item.name()] = enum_docs.count(item) ? enum_docs.at(item) : "";
924 }
925 
926 bool
927 MooseServer::gatherDocumentDefinitionLocations(wasp::DataArray & definitionLocations,
928  int line,
929  int character)
930 {
931  Factory & factory = _moose_app.getFactory();
932 
933  // return without any definition locations added when parser root is null
934  auto root_ptr = queryRoot();
935  if (!root_ptr)
936  return true;
937  auto & root = *root_ptr;
938 
939  // find hit node for zero based request line and column number from input
940  wasp::HITNodeView view_root = root.getNodeView();
941  wasp::HITNodeView request_context =
942  wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
943 
944  // return without any definition locations added when node not value type
945  if (request_context.type() != wasp::VALUE)
946  return true;
947 
948  // get name of parameter node parent of value and value string from input
949  std::string param_name = request_context.has_parent() ? request_context.parent().name() : "";
950  std::string val_string = request_context.last_as_string();
951 
952  // add source code location if type parameter with registered object name
953  if (param_name == "type" && factory.isRegistered(val_string))
954  {
955  // get file path and line number of source code registering object type
956  FileLineInfo file_line_info = factory.getLineInfo(val_string);
957 
958  // return without any definition locations added if file cannot be read
959  if (!file_line_info.isValid() ||
960  !MooseUtils::checkFileReadable(file_line_info.file(), false, false, false))
961  return true;
962 
963  // add file scheme prefix to front of file path to build definition uri
964  auto location_uri = wasp::lsp::m_uri_prefix + file_line_info.file();
965 
966  // add file uri and zero based line and column range to definition list
967  definitionLocations.push_back(wasp::DataObject());
968  wasp::DataObject * location = definitionLocations.back().to_object();
969  return wasp::lsp::buildLocationObject(*location,
970  errors,
971  location_uri,
972  file_line_info.line() - 1,
973  0,
974  file_line_info.line() - 1,
975  1000);
976  }
977 
978  // get object context and value of type parameter for request if provided
979  wasp::HITNodeView object_context = request_context;
980  while (object_context.type() != wasp::OBJECT && object_context.has_parent())
981  object_context = object_context.parent();
982  const std::string & object_path = object_context.path();
983  wasp::HITNodeView type_node = object_context.first_child_by_name("type");
984  const std::string & object_type =
985  type_node.is_null() ? "" : wasp::strip_quotes(hit::extractValue(type_node.data()));
986 
987  // set used to gather all parameters valid from object context of request
988  InputParameters valid_params = emptyInputParameters();
989 
990  // set used to gather MooseObjectAction tasks to verify object parameters
991  std::set<std::string> obj_act_tasks;
992 
993  // get set of global parameters, action parameters, and object parameters
994  getAllValidParameters(valid_params, object_path, object_type, obj_act_tasks);
995 
996  // set used to gather nodes from input lookups custom sorted by locations
997  SortedLocationNodes location_nodes(
998  [](const wasp::HITNodeView & l, const wasp::HITNodeView & r)
999  {
1000  const std::string & l_file = l.node_pool()->stream_name();
1001  const std::string & r_file = r.node_pool()->stream_name();
1002  return (l_file < r_file || (l_file == r_file && l.line() < r.line()) ||
1003  (l_file == r_file && l.line() == r.line() && l.column() < r.column()));
1004  });
1005 
1006  // gather all lookup path nodes matching value if parameter name is valid
1007  for (const auto & valid_params_iter : valid_params)
1008  {
1009  if (valid_params_iter.first == param_name)
1010  {
1011  // get cpp type and prepare string for use as key finding input paths
1012  std::string dirty_type = valid_params.type(param_name);
1013  std::string clean_type = MooseUtils::prettyCppType(dirty_type);
1014  pcrecpp::RE(".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace("\\1", &clean_type);
1015 
1016  // get set of nodes from associated path lookups matching input value
1017  getInputLookupDefinitionNodes(location_nodes, clean_type, val_string);
1018  break;
1019  }
1020  }
1021 
1022  // add parameter declarator to set if none were gathered by input lookups
1023  if (location_nodes.empty() && request_context.has_parent() &&
1024  request_context.parent().child_count_by_name("decl"))
1025  location_nodes.insert(request_context.parent().first_child_by_name("decl"));
1026 
1027  // add locations to definition list using lookups or parameter declarator
1028  return addLocationNodesToList(definitionLocations, location_nodes);
1029 }
1030 
1031 void
1033  const std::string & clean_type,
1034  const std::string & val_string)
1035 {
1036  Syntax & syntax = _moose_app.syntax();
1037 
1038  // build map from parameter types to input lookup paths and save to reuse
1039  if (_type_to_input_paths.empty())
1040  {
1041  for (const auto & associated_types_iter : syntax.getAssociatedTypes())
1042  {
1043  const std::string & type = associated_types_iter.second;
1044  const std::string & path = associated_types_iter.first;
1045  _type_to_input_paths[type].insert(path);
1046  }
1047  }
1048 
1049  // find set of input lookup paths that are associated with parameter type
1050  const auto & input_path_iter = _type_to_input_paths.find(clean_type);
1051 
1052  // return without any definition locations added when no paths associated
1053  if (input_path_iter == _type_to_input_paths.end())
1054  return;
1055 
1056  // get root node from input to use in input lookups with associated paths
1057  wasp::HITNodeView view_root = getRoot().getNodeView();
1058 
1059  // walk over all syntax paths that are associated with parameter type
1060  for (const auto & input_path : input_path_iter->second)
1061  {
1062  // use wasp siren to gather all nodes from current lookup path in input
1063  wasp::SIRENInterpreter<> selector;
1064  if (!selector.parseString(input_path))
1065  continue;
1066  wasp::SIRENResultSet<wasp::HITNodeView> results;
1067  std::size_t count = selector.evaluate(view_root, results);
1068 
1069  // walk over results and add nodes that have name matching value to set
1070  for (std::size_t i = 0; i < count; i++)
1071  if (results.adapted(i).type() == wasp::OBJECT && results.adapted(i).name() == val_string &&
1072  results.adapted(i).child_count_by_name("decl"))
1073  location_nodes.insert(results.adapted(i).first_child_by_name("decl"));
1074  }
1075 }
1076 
1077 bool
1078 MooseServer::addLocationNodesToList(wasp::DataArray & defsOrRefsLocations,
1079  const SortedLocationNodes & location_nodes)
1080 {
1081  bool pass = true;
1082 
1083  // walk over set of sorted nodes provided to add and build locations list
1084  for (const auto & location_nodes_iter : location_nodes)
1085  {
1086  // add file scheme prefix onto front of file path to build location uri
1087  auto location_uri = wasp::lsp::m_uri_prefix + location_nodes_iter.node_pool()->stream_name();
1088 
1089  // add file uri with zero based line and column range to locations list
1090  defsOrRefsLocations.push_back(wasp::DataObject());
1091  wasp::DataObject * location = defsOrRefsLocations.back().to_object();
1092  pass &= wasp::lsp::buildLocationObject(*location,
1093  errors,
1094  location_uri,
1095  location_nodes_iter.line() - 1,
1096  location_nodes_iter.column() - 1,
1097  location_nodes_iter.last_line() - 1,
1098  location_nodes_iter.last_column());
1099  }
1100 
1101  return pass;
1102 }
1103 
1104 bool
1105 MooseServer::getHoverDisplayText(std::string & display_text, int line, int character)
1106 {
1107  Factory & factory = _moose_app.getFactory();
1108  Syntax & syntax = _moose_app.syntax();
1109 
1110  // return and leave display text as empty string when parser root is null
1111  auto root_ptr = queryRoot();
1112  if (!root_ptr)
1113  return true;
1114  auto & root = *root_ptr;
1115 
1116  // find hit node for zero based request line and column number from input
1117  wasp::HITNodeView view_root = root.getNodeView();
1118  wasp::HITNodeView request_context =
1119  wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
1120 
1121  // return and leave display text as empty string when not on key or value
1122  if ((request_context.type() != wasp::DECL && request_context.type() != wasp::VALUE) ||
1123  !request_context.has_parent() ||
1124  (request_context.parent().type() != wasp::KEYED_VALUE &&
1125  request_context.parent().type() != wasp::ARRAY))
1126  return true;
1127 
1128  // get name of parameter node and value string that is specified in input
1129  std::string paramkey = request_context.parent().name();
1130  std::string paramval = request_context.last_as_string();
1131 
1132  // get object context path and object type value for request if it exists
1133  wasp::HITNodeView object_context = request_context;
1134  while (object_context.type() != wasp::OBJECT && object_context.has_parent())
1135  object_context = object_context.parent();
1136  const std::string object_path = object_context.path();
1137  wasp::HITNodeView type_node = object_context.first_child_by_name("type");
1138  const std::string object_type =
1139  type_node.is_null() ? "" : wasp::strip_quotes(hit::extractValue(type_node.data()));
1140 
1141  // gather global, action, and object parameters in request object context
1142  InputParameters valid_params = emptyInputParameters();
1143  std::set<std::string> obj_act_tasks;
1144  getAllValidParameters(valid_params, object_path, object_type, obj_act_tasks);
1145 
1146  // use class description as display text when request is valid type value
1147  if (request_context.type() == wasp::VALUE && paramkey == "type" && factory.isRegistered(paramval))
1148  {
1149  const InputParameters & object_params = factory.getValidParams(paramval);
1150  if (object_params.hasBase())
1151  {
1152  const std::string & moose_base = object_params.getBase();
1153  for (const auto & obj_act_task : obj_act_tasks)
1154  {
1155  if (syntax.verifyMooseObjectTask(moose_base, obj_act_task))
1156  {
1157  display_text = object_params.getClassDescription();
1158  break;
1159  }
1160  }
1161  }
1162  }
1163 
1164  // use item documentation as display text when request is enum type value
1165  else if (request_context.type() == wasp::VALUE)
1166  {
1167  std::map<std::string, std::string> options_and_descs;
1168  if (valid_params.have_parameter<MooseEnum>(paramkey))
1169  getEnumsAndDocs(valid_params.get<MooseEnum>(paramkey), options_and_descs);
1170  else if (valid_params.have_parameter<MultiMooseEnum>(paramkey))
1171  getEnumsAndDocs(valid_params.get<MultiMooseEnum>(paramkey), options_and_descs);
1172  else if (valid_params.have_parameter<ExecFlagEnum>(paramkey))
1173  getEnumsAndDocs(valid_params.get<ExecFlagEnum>(paramkey), options_and_descs);
1174  else if (valid_params.have_parameter<std::vector<MooseEnum>>(paramkey))
1175  getEnumsAndDocs(valid_params.get<std::vector<MooseEnum>>(paramkey)[0], options_and_descs);
1176  if (options_and_descs.count(paramval))
1177  display_text = options_and_descs.find(paramval)->second;
1178  }
1179 
1180  // use parameter documentation as display text when request is valid name
1181  else if (request_context.type() == wasp::DECL && valid_params.getParametersList().count(paramkey))
1182  display_text = valid_params.getDocString(paramkey);
1183 
1184  MooseUtils::escape(display_text);
1185  return true;
1186 }
1187 
1188 bool
1189 MooseServer::gatherDocumentReferencesLocations(wasp::DataArray & referencesLocations,
1190  int line,
1191  int character,
1192  bool include_declaration)
1193 {
1194  Syntax & syntax = _moose_app.syntax();
1195 
1196  // return without adding any reference locations when parser root is null
1197  auto root_ptr = queryRoot();
1198  if (!root_ptr)
1199  return true;
1200  auto & root = *root_ptr;
1201 
1202  // find hit node for zero based request line and column number from input
1203  wasp::HITNodeView view_root = root.getNodeView();
1204  wasp::HITNodeView request_context =
1205  wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
1206 
1207  // return without adding any references when request not block declarator
1208  if ((request_context.type() != wasp::DECL && request_context.type() != wasp::DOT_SLASH &&
1209  request_context.type() != wasp::LBRACKET && request_context.type() != wasp::RBRACKET) ||
1210  !request_context.has_parent() || request_context.parent().type() != wasp::OBJECT)
1211  return true;
1212 
1213  // get input path and block name of declarator located at request context
1214  const std::string & block_path = request_context.parent().path();
1215  const std::string & block_name = request_context.parent().name();
1216 
1217  // build map from input lookup paths to parameter types and save to reuse
1218  if (_input_path_to_types.empty())
1219  for (const auto & associated_types_iter : syntax.getAssociatedTypes())
1220  {
1221  const std::string & path = associated_types_iter.first;
1222  const std::string & type = associated_types_iter.second;
1223  _input_path_to_types[path].insert(type);
1224  }
1225 
1226  // get registered syntax from block path with map of input paths to types
1227  bool is_parent;
1228  std::string registered_syntax = syntax.isAssociated(block_path, &is_parent, _input_path_to_types);
1229 
1230  // return without adding any references if syntax has no types associated
1231  if (is_parent || !_input_path_to_types.count(registered_syntax))
1232  return true;
1233 
1234  // get set of parameter types which are associated with registered syntax
1235  const std::set<std::string> & target_types = _input_path_to_types.at(registered_syntax);
1236 
1237  // set used to gather nodes collected by value custom sorted by locations
1238  SortedLocationNodes match_nodes(
1239  [](const wasp::HITNodeView & l, const wasp::HITNodeView & r)
1240  {
1241  const std::string & l_file = l.node_pool()->stream_name();
1242  const std::string & r_file = r.node_pool()->stream_name();
1243  return (l_file < r_file || (l_file == r_file && l.line() < r.line()) ||
1244  (l_file == r_file && l.line() == r.line() && l.column() < r.column()));
1245  });
1246 
1247  // walk input recursively and gather all nodes that match value and types
1248  getNodesByValueAndTypes(match_nodes, view_root, block_name, target_types);
1249 
1250  // return without adding any references if no nodes match value and types
1251  if (match_nodes.empty())
1252  return true;
1253 
1254  // add request context node to set if declaration inclusion was specified
1255  if (include_declaration && request_context.parent().child_count_by_name("decl"))
1256  match_nodes.insert(request_context.parent().first_child_by_name("decl"));
1257 
1258  // add locations to references list with nodes that match value and types
1259  return addLocationNodesToList(referencesLocations, match_nodes);
1260 }
1261 
1262 void
1264  wasp::HITNodeView view_parent,
1265  const std::string & target_value,
1266  const std::set<std::string> & target_types)
1267 {
1268  // walk over children of context to gather nodes matching value and types
1269  for (const auto & view_child : view_parent)
1270  {
1271  // check for parameter type match if node is value matching target data
1272  if (view_child.type() == wasp::VALUE && view_child.to_string() == target_value)
1273  {
1274  // get object context path and object type value of node if it exists
1275  wasp::HITNodeView object_context = view_child;
1276  while (object_context.type() != wasp::OBJECT && object_context.has_parent())
1277  object_context = object_context.parent();
1278  const std::string object_path = object_context.path();
1279  wasp::HITNodeView type_node = object_context.first_child_by_name("type");
1280  const std::string object_type =
1281  type_node.is_null() ? "" : wasp::strip_quotes(hit::extractValue(type_node.data()));
1282 
1283  // gather global, action, and object parameters for context of object
1284  InputParameters valid_params = emptyInputParameters();
1285  std::set<std::string> obj_act_tasks;
1286  getAllValidParameters(valid_params, object_path, object_type, obj_act_tasks);
1287 
1288  // get name from parent of current value node which is parameter node
1289  std::string param_name = view_child.has_parent() ? view_child.parent().name() : "";
1290 
1291  // get type of parameter and prepare string to check target set match
1292  std::string dirty_type = valid_params.type(param_name);
1293  std::string clean_type = MooseUtils::prettyCppType(dirty_type);
1294  pcrecpp::RE(".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace("\\1", &clean_type);
1295 
1296  // add input node to collection if its type is also in set of targets
1297  if (target_types.count(clean_type))
1298  match_nodes.insert(view_child);
1299  }
1300 
1301  // recurse deeper into input to search for matches if node has children
1302  if (!view_child.is_leaf())
1303  getNodesByValueAndTypes(match_nodes, view_child, target_value, target_types);
1304  }
1305 }
1306 
1307 bool
1308 MooseServer::gatherDocumentFormattingTextEdits(wasp::DataArray & formattingTextEdits,
1309  int tab_size,
1310  bool /* insert_spaces */)
1311 {
1312  // strip scheme prefix from document uri if it exists for parse file path
1313  std::string parse_file_path = document_path;
1314  pcrecpp::RE("(.*://)(.*)").Replace("\\2", &parse_file_path);
1315 
1316  // input check expanded any brace expressions in cached tree so reprocess
1317  std::stringstream input_errors, input_stream(getDocumentText());
1318  wasp::DefaultHITInterpreter interpreter(input_errors);
1319 
1320  // return without adding any formatting text edits if input parsing fails
1321  if (!interpreter.parseStream(input_stream, parse_file_path))
1322  return true;
1323 
1324  // return without adding any formatting text edits if parser root is null
1325  if (interpreter.root().is_null())
1326  return true;
1327 
1328  // get input root node line and column range to represent entire document
1329  wasp::HITNodeView view_root = interpreter.root();
1330  int document_start_line = view_root.line() - 1;
1331  int document_start_char = view_root.column() - 1;
1332  int document_last_line = view_root.last_line() - 1;
1333  int document_last_char = view_root.last_column();
1334 
1335  // set number of spaces for indentation and build formatted document text
1336  _formatting_tab_size = tab_size;
1337  std::size_t starting_line = view_root.line() - 1;
1338  std::string document_format = formatDocument(view_root, starting_line, 0);
1339 
1340  // add formatted text with whole line and column range to formatting list
1341  formattingTextEdits.push_back(wasp::DataObject());
1342  wasp::DataObject * item = formattingTextEdits.back().to_object();
1343  bool pass = wasp::lsp::buildTextEditObject(*item,
1344  errors,
1345  document_start_line,
1346  document_start_char,
1347  document_last_line,
1348  document_last_char,
1349  document_format);
1350  return pass;
1351 }
1352 
1353 std::string
1354 MooseServer::formatDocument(wasp::HITNodeView parent, std::size_t & prev_line, std::size_t level)
1355 {
1356  // build string of newline and indentation spaces from level and tab size
1357  std::string newline_indent = "\n" + std::string(level * _formatting_tab_size, ' ');
1358 
1359  // lambda to format include data by replacing consecutive spaces with one
1360  auto collapse_spaces = [](std::string string_copy)
1361  {
1362  pcrecpp::RE("\\s+").Replace(" ", &string_copy);
1363  return string_copy;
1364  };
1365 
1366  // formatted string that will be built recursively by appending each call
1367  std::string format_string;
1368 
1369  // walk over all children of this node context and build formatted string
1370  for (const auto i : make_range(parent.child_count()))
1371  {
1372  // walk must be index based to catch file include and skip its children
1373  wasp::HITNodeView child = parent.child_at(i);
1374 
1375  // add blank line if necessary after previous line and before this line
1376  std::string blank = child.line() > prev_line + 1 ? "\n" : "";
1377 
1378  // format include directive with indentation and collapse extra spacing
1379  if (child.type() == wasp::FILE)
1380  format_string += blank + newline_indent + MooseUtils::trim(collapse_spaces(child.data()));
1381 
1382  // format normal comment with indentation and inline comment with space
1383  else if (child.type() == wasp::COMMENT)
1384  format_string += (child.line() == prev_line ? " " : blank + newline_indent) +
1385  MooseUtils::trim(child.data());
1386 
1387  // format object recursively with indentation and without legacy syntax
1388  else if (child.type() == wasp::OBJECT)
1389  format_string += blank + newline_indent + "[" + child.name() + "]" +
1390  formatDocument(child, prev_line, level + 1) + newline_indent + "[]";
1391 
1392  // format keyed value with indentation and calling reusable hit methods
1393  else if (child.type() == wasp::KEYED_VALUE || child.type() == wasp::ARRAY)
1394  {
1395  const std::string prefix = newline_indent + child.name() + " = ";
1396 
1397  const std::string render_val = hit::extractValue(child.data());
1398  std::size_t val_column = child.child_count() > 2 ? child.child_at(2).column() : 0;
1399  std::size_t prefix_len = prefix.size() - 1;
1400 
1401  format_string += blank + prefix + hit::formatValue(render_val, val_column, prefix_len);
1402  }
1403 
1404  // set previous line reference used for blank lines and inline comments
1405  prev_line = child.last_line();
1406  }
1407 
1408  // remove leading newline if this is level zero returning entire document
1409  return level != 0 ? format_string : format_string.substr(1);
1410 }
1411 
1412 bool
1413 MooseServer::gatherDocumentSymbols(wasp::DataArray & documentSymbols)
1414 {
1415  // return prior to starting document symbol tree when parser root is null
1416  auto root_ptr = queryRoot();
1417  if (!root_ptr)
1418  return true;
1419  auto & root = *root_ptr;
1420 
1421  wasp::HITNodeView view_root = root.getNodeView();
1422 
1423  bool pass = true;
1424 
1425  // walk over all children of root node context and build document symbols
1426  for (const auto i : make_range(view_root.child_count()))
1427  {
1428  // walk must be index based to catch file include and skip its children
1429  wasp::HITNodeView view_child = view_root.child_at(i);
1430 
1431  // set up name, zero based line and column range, kind, and detail info
1432  std::string name = view_child.name();
1433  int line = view_child.line() - 1;
1434  int column = view_child.column() - 1;
1435  int last_line = view_child.last_line() - 1;
1436  int last_column = view_child.last_column();
1437  int symbol_kind = getDocumentSymbolKind(view_child);
1438  std::string detail =
1439  !view_child.first_child_by_name("type").is_null()
1440  ? wasp::strip_quotes(hit::extractValue(view_child.first_child_by_name("type").data()))
1441  : "";
1442 
1443  // build document symbol object from node child info and push to array
1444  documentSymbols.push_back(wasp::DataObject());
1445  wasp::DataObject * data_child = documentSymbols.back().to_object();
1446  pass &= wasp::lsp::buildDocumentSymbolObject(*data_child,
1447  errors,
1448  (name.empty() ? "void" : name),
1449  detail,
1450  symbol_kind,
1451  false,
1452  line,
1453  column,
1454  last_line,
1455  last_column,
1456  line,
1457  column,
1458  last_line,
1459  last_column);
1460 
1461  // call method to recursively fill document symbols for each node child
1462  pass &= traverseParseTreeAndFillSymbols(view_child, *data_child);
1463  }
1464 
1465  return pass;
1466 }
1467 
1468 bool
1469 MooseServer::traverseParseTreeAndFillSymbols(wasp::HITNodeView view_parent,
1470  wasp::DataObject & data_parent)
1471 {
1472  // return without adding any children if parent node is file include type
1473  if (wasp::is_nested_file(view_parent))
1474  return true;
1475 
1476  bool pass = true;
1477 
1478  // walk over all children of this node context and build document symbols
1479  for (const auto i : make_range(view_parent.child_count()))
1480  {
1481  // walk must be index based to catch file include and skip its children
1482  wasp::HITNodeView view_child = view_parent.child_at(i);
1483 
1484  // set up name, zero based line and column range, kind, and detail info
1485  std::string name = view_child.name();
1486  int line = view_child.line() - 1;
1487  int column = view_child.column() - 1;
1488  int last_line = view_child.last_line() - 1;
1489  int last_column = view_child.last_column();
1490  int symbol_kind = getDocumentSymbolKind(view_child);
1491  std::string detail =
1492  !view_child.first_child_by_name("type").is_null()
1493  ? wasp::strip_quotes(hit::extractValue(view_child.first_child_by_name("type").data()))
1494  : "";
1495 
1496  // build document symbol object from node child info and push to array
1497  wasp::DataObject & data_child = wasp::lsp::addDocumentSymbolChild(data_parent);
1498  pass &= wasp::lsp::buildDocumentSymbolObject(data_child,
1499  errors,
1500  (name.empty() ? "void" : name),
1501  detail,
1502  symbol_kind,
1503  false,
1504  line,
1505  column,
1506  last_line,
1507  last_column,
1508  line,
1509  column,
1510  last_line,
1511  last_column);
1512 
1513  // call method to recursively fill document symbols for each node child
1514  pass &= traverseParseTreeAndFillSymbols(view_child, data_child);
1515  }
1516 
1517  return pass;
1518 }
1519 
1520 int
1522  const std::string & param_name,
1523  const std::string & clean_type,
1524  bool is_param)
1525 {
1526  // set up completion item kind value that client may use for icon in list
1527  auto associated_types = _moose_app.syntax().getAssociatedTypes();
1528  if (is_param && valid_params.isParamRequired(param_name) &&
1529  !valid_params.isParamValid(param_name))
1530  return wasp::lsp::m_comp_kind_event;
1531  else if (param_name == "active" || param_name == "inactive")
1532  return wasp::lsp::m_comp_kind_class;
1533  else if (clean_type == "bool")
1534  return wasp::lsp::m_comp_kind_interface;
1535  else if (valid_params.have_parameter<MooseEnum>(param_name) ||
1536  valid_params.have_parameter<MultiMooseEnum>(param_name) ||
1537  valid_params.have_parameter<ExecFlagEnum>(param_name) ||
1538  valid_params.have_parameter<std::vector<MooseEnum>>(param_name))
1539  return is_param ? wasp::lsp::m_comp_kind_enum : wasp::lsp::m_comp_kind_enum_member;
1540  else if (param_name == "type")
1541  return wasp::lsp::m_comp_kind_type_param;
1542  else if (std::find_if(associated_types.begin(),
1543  associated_types.end(),
1544  [&](const auto & entry)
1545  { return entry.second == clean_type; }) != associated_types.end())
1546  return wasp::lsp::m_comp_kind_reference;
1547  else
1548  return is_param ? wasp::lsp::m_comp_kind_keyword : wasp::lsp::m_comp_kind_value;
1549 }
1550 
1551 int
1552 MooseServer::getDocumentSymbolKind(wasp::HITNodeView symbol_node)
1553 {
1554  // lambdas that check if parameter is a boolean or number for symbol kind
1555  auto is_boolean = [](wasp::HITNodeView symbol_node)
1556  {
1557  bool convert;
1558  std::istringstream iss(MooseUtils::toLower(symbol_node.last_as_string()));
1559  return (iss >> std::boolalpha >> convert && !iss.fail());
1560  };
1561  auto is_number = [](wasp::HITNodeView symbol_node)
1562  {
1563  double convert;
1564  std::istringstream iss(symbol_node.last_as_string());
1565  return (iss >> convert && iss.eof());
1566  };
1567 
1568  // set up document symbol kind value that client may use for outline icon
1569  if (symbol_node.type() == wasp::OBJECT)
1570  return wasp::lsp::m_symbol_kind_struct;
1571  else if (symbol_node.type() == wasp::FILE)
1572  return wasp::lsp::m_symbol_kind_file;
1573  else if (symbol_node.type() == wasp::ARRAY)
1574  return wasp::lsp::m_symbol_kind_array;
1575  else if (symbol_node.type() == wasp::KEYED_VALUE && symbol_node.name() == std::string("type"))
1576  return wasp::lsp::m_symbol_kind_type_param;
1577  else if (symbol_node.type() == wasp::KEYED_VALUE && is_boolean(symbol_node))
1578  return wasp::lsp::m_symbol_kind_boolean;
1579  else if (symbol_node.type() == wasp::KEYED_VALUE && is_number(symbol_node))
1580  return wasp::lsp::m_symbol_kind_number;
1581  else if (symbol_node.type() == wasp::KEYED_VALUE)
1582  return wasp::lsp::m_symbol_kind_key;
1583  else if (symbol_node.type() == wasp::VALUE)
1584  return wasp::lsp::m_symbol_kind_string;
1585  else
1586  return wasp::lsp::m_symbol_kind_property;
1587 }
1588 
1589 std::string
1590 MooseServer::getRequiredParamsText(const std::string & subblock_path,
1591  const std::string & subblock_type,
1592  const std::set<std::string> & existing_params,
1593  const std::string & indent_spaces)
1594 {
1595  // gather global, action, and object parameters in request object context
1596  InputParameters valid_params = emptyInputParameters();
1597  std::set<std::string> obj_act_tasks;
1598  getAllValidParameters(valid_params, subblock_path, subblock_type, obj_act_tasks);
1599 
1600  // walk over collection of all parameters and build text of ones required
1601  std::string required_param_text;
1602  std::size_t param_index = 1;
1603  for (const auto & valid_params_iter : valid_params)
1604  {
1605  // skip parameter if deprecated, private, defaulted, optional, existing
1606  const std::string & param_name = valid_params_iter.first;
1607  if (!valid_params.isParamDeprecated(param_name) && !valid_params.isPrivate(param_name) &&
1608  !valid_params.isParamValid(param_name) && valid_params.isParamRequired(param_name) &&
1609  !existing_params.count(param_name))
1610  {
1611  std::string tab_stop = client_snippet_support ? "$" + std::to_string(param_index++) : "";
1612  required_param_text += "\n" + indent_spaces + param_name + " = " + tab_stop;
1613  }
1614  }
1615 
1616  return required_param_text;
1617 }
1618 
1619 bool
1620 MooseServer::gatherExtensionResponses(wasp::DataArray & extensionResponses,
1621  const std::string & extensionMethod,
1622  int line,
1623  int character)
1624 {
1625  // use appropriate method to fill response based on extension method name
1626  bool pass = true;
1627  if (extensionMethod == "plotting")
1628  pass = gatherPlottingResponses(extensionResponses, line, character);
1629  return pass;
1630 }
1631 
1632 bool
1633 MooseServer::gatherPlottingResponses(wasp::DataArray & plottingResponses, int line, int character)
1634 {
1635  // return without adding any plot response objects if parser root is null
1636  auto root_ptr = queryRoot();
1637  if (!root_ptr)
1638  return true;
1639  auto & root = *root_ptr;
1640 
1641  // find hit node for zero based request line and column number from input
1642  wasp::HITNodeView view_root = root.getNodeView();
1643  wasp::HITNodeView request_context =
1644  wasp::findNodeUnderLineColumn(view_root, line + 1, character + 1);
1645 
1646  // get object context and value of type parameter for request if provided
1647  wasp::HITNodeView object_context = request_context;
1648  while (object_context.type() != wasp::OBJECT && object_context.has_parent())
1649  object_context = object_context.parent();
1650  const std::string & object_name = object_context.name();
1651  wasp::HITNodeView type_node = object_context.first_child_by_name("type");
1652  const std::string & object_type =
1653  type_node.is_null() ? "" : wasp::strip_quotes(hit::extractValue(type_node.data()));
1654 
1655  // get problem from action warehouse and return without any plots if null
1656  std::shared_ptr<FEProblemBase> & problem = getCheckApp().actionWarehouse().problemBase();
1657  if (!problem)
1658  return true;
1659 
1660  // return without any plots added when request is not from function block
1661  if (!problem->hasFunction(object_name))
1662  return true;
1663 
1664  // get function from problem and return with no plots added if wrong type
1665  const auto * pw_func = dynamic_cast<const PiecewiseBase *>(&problem->getFunction(object_name));
1666  if (!pw_func)
1667  return true;
1668 
1669  // return without adding plot response objects when function size is zero
1670  if (pw_func->functionSize() == 0)
1671  return true;
1672 
1673  // walk over piecewise function and gather keys and values for line graph
1674  std::vector<double> graph_keys, graph_vals;
1675  for (std::size_t i = 0; i < pw_func->functionSize(); i++)
1676  {
1677  graph_keys.push_back(pw_func->domain(i));
1678  graph_vals.push_back(pw_func->range(i));
1679  }
1680 
1681  // build CustomPlot object from function data then serialize for response
1682  std::string plot_title = object_name + " " + object_type + " Function";
1683  wasp::CustomPlot plot_object;
1684  buildLineGraphPlot(plot_object, plot_title, graph_keys, graph_vals);
1685  plottingResponses.push_back(wasp::serializeCustomPlot(plot_object));
1686 
1687  return true;
1688 }
1689 
1690 void
1691 MooseServer::buildLineGraphPlot(wasp::CustomPlot & plot_object,
1692  const std::string & plot_title,
1693  const std::vector<double> & graph_keys,
1694  const std::vector<double> & graph_vals)
1695 {
1696  // axis ranges
1697  double min_key = *std::min_element(graph_keys.begin(), graph_keys.end());
1698  double max_key = *std::max_element(graph_keys.begin(), graph_keys.end());
1699  double min_val = *std::min_element(graph_vals.begin(), graph_vals.end());
1700  double max_val = *std::max_element(graph_vals.begin(), graph_vals.end());
1701 
1702  // widen extents
1703  double pad_factor = 0.05;
1704  double pad_x_axis = (max_key - min_key) * pad_factor;
1705  double pad_y_axis = (max_val - min_val) * pad_factor;
1706  min_key -= pad_x_axis;
1707  max_key += pad_x_axis;
1708  min_val -= pad_y_axis;
1709  max_val += pad_y_axis;
1710 
1711  // plot setup
1712  plot_object.title().text(plot_title);
1713  plot_object.title().font().pointsize(18);
1714  plot_object.title().visible(true);
1715  plot_object.legend().visible(false);
1716 
1717  // plot x-axis
1718  plot_object.x1Axis().label("abscissa values");
1719  plot_object.x1Axis().rangeMin(min_key);
1720  plot_object.x1Axis().rangeMax(max_key);
1721  plot_object.x1Axis().scaleType(wasp::CustomPlot::stLinear);
1722  plot_object.x1Axis().labelType(wasp::CustomPlot::ltNumber);
1723  plot_object.x1Axis().labelFont().pointsize(18);
1724  plot_object.x1Axis().tickLabelFont().pointsize(16);
1725 
1726  // plot y-axis
1727  plot_object.y1Axis().label("ordinate values");
1728  plot_object.y1Axis().rangeMin(min_val);
1729  plot_object.y1Axis().rangeMax(max_val);
1730  plot_object.y1Axis().scaleType(wasp::CustomPlot::stLinear);
1731  plot_object.y1Axis().labelType(wasp::CustomPlot::ltNumber);
1732  plot_object.y1Axis().labelFont().pointsize(18);
1733  plot_object.y1Axis().tickLabelFont().pointsize(16);
1734 
1735  // graph series
1736  auto line_graph = std::make_shared<wasp::CustomPlot::Graph>();
1737  line_graph->keys() = graph_keys;
1738  line_graph->values() = graph_vals;
1739  line_graph->scatterShape(wasp::CustomPlot::ssDisc);
1740  plot_object.series().push_back(line_graph);
1741 }
1742 
1743 const hit::Node *
1745 {
1746  if (const auto parser_ptr = queryCheckParser())
1747  {
1748 #ifndef NDEBUG
1749  if (const auto app_ptr = queryCheckApp())
1750  mooseAssert(&app_ptr->parser() == parser_ptr, "App should have this parser");
1751 #endif
1752  if (const auto root_ptr = parser_ptr->queryRoot())
1753  if (!root_ptr->getNodeView().is_null())
1754  return root_ptr;
1755  }
1756  return nullptr;
1757 }
1758 
1761 {
1762  const auto it = _check_state.find(document_path);
1763  return it == _check_state.end() ? nullptr : &it->second;
1764 }
1765 
1768 {
1769  return const_cast<MooseServer::CheckState *>(std::as_const(*this).queryCheckState());
1770 }
1771 
1772 const Parser *
1774 {
1775  const auto state = queryCheckState();
1776  return state ? state->parser.get() : nullptr;
1777 }
1778 
1779 Parser *
1781 {
1782  return const_cast<Parser *>(std::as_const(*this).queryCheckParser());
1783 }
1784 
1785 const MooseApp *
1787 {
1788  if (auto state = queryCheckState())
1789  return state->app.get();
1790  return nullptr;
1791 }
1792 
1793 MooseApp *
1795 {
1796  return const_cast<MooseApp *>(std::as_const(*this).queryCheckApp());
1797 }
1798 
1799 const std::string *
1801 {
1802  if (const auto parser = queryCheckParser())
1803  {
1804  const auto & text_vector = parser->getInputText();
1805  mooseAssert(text_vector.size() == 1, "Unexpected size");
1806  return &text_vector[0];
1807  }
1808  return nullptr;
1809 }
1810 
1811 MooseApp &
1813 {
1814  if (auto app_ptr = queryCheckApp())
1815  {
1816  auto & app = *app_ptr;
1817  mooseAssert(queryCheckParser(), "Should have a parser");
1818  mooseAssert(&app.parser() == queryCheckParser(), "Parser should be the app's parser");
1819  return app;
1820  }
1821  mooseError("MooseServer::getCheckApp(): App not available");
1822 }
1823 
1824 const hit::Node &
1826 {
1827  if (auto root_ptr = queryRoot())
1828  return *root_ptr;
1829  mooseError("MooseServer::getRoot(): Root not available");
1830 }
1831 
1832 const std::string &
1834 {
1835  if (auto text_ptr = queryDocumentText())
1836  return *text_ptr;
1837  mooseError("MooseServer::getDocumentText(): Document text not available");
1838 }
int getDocumentSymbolKind(wasp::HITNodeView symbol_node)
Get document symbol kind value that client may use for outline icon.
Definition: MooseServer.C:1552
OStreamProxy err
const std::multimap< std::string, std::string > & getAssociatedTypes() const
Get a multimap of registered associations of syntax with type.
Definition: Syntax.C:368
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...
Definition: Syntax.C:328
std::map< std::string, std::set< std::string > > _type_to_input_paths
_type_to_input_paths - map of parameter types to lookup paths
Definition: MooseServer.h:471
Function base which provides a piecewise approximation to a specified (x,y) point data set...
Definition: PiecewiseBase.h:20
A MultiMooseEnum object to hold "execute_on" flags.
Definition: ExecFlagEnum.h:21
bool isRegistered(const std::string &obj_name) const
Returns a Boolean indicating whether an object type has been registered.
Definition: Factory.h:152
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.
Definition: MooseServer.C:1032
const std::multimap< std::string, ActionInfo > & getAssociatedActions() const
Return all Syntax to Action associations.
Definition: Syntax.C:374
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.
Definition: MooseServer.C:1590
std::map< std::string, std::set< std::string > > _input_path_to_types
_type_to_input_paths - map of lookup paths to parameter types
Definition: MooseServer.h:476
std::set< std::string > getParametersList() const
Generic factory class for build all sorts of objects.
Definition: Factory.h:28
const std::string & getDocumentText() const
Definition: MooseServer.C:1833
InputParameters getValidParams(const std::string &name)
Definition: ActionFactory.C:94
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:323
std::shared_ptr< CommandLine > commandLine() const
Get the command line.
Definition: MooseApp.h:411
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
Combine two vector parameters into a single vector of pairs.
MooseServer(MooseApp &moose_app)
Definition: MooseServer.C:38
static const std::string main_app_name
The name for the "main" moose application.
Definition: AppFactory.h:69
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.
Definition: MooseServer.C:1691
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 &param_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.
Definition: MooseServer.C:754
MooseApp & getCheckApp()
Definition: MooseServer.C:1812
bool gatherDocumentSymbols(wasp::DataArray &documentSymbols)
Gather document symbols - specific to this server implemention.
Definition: MooseServer.C:1413
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.
Definition: MooseServer.C:542
const InputParameters & parameters() const
Get the parameters of the object.
Definition: MooseBase.h:127
std::set< std::string > getTasksByAction(const std::string &action) const
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
virtual void run()
Run the application.
Definition: MooseApp.C:2135
static InputParameters validParams()
Parameters that are processed directly by the Parser and are valid anywhere in the input...
Definition: Builder.C:121
InputParameters getValidParams(const std::string &name) const
Get valid parameters for the object.
Definition: Factory.C:68
Base class for MOOSE-based applications.
Definition: MooseApp.h:96
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const hit::Node & getRoot() const
Definition: MooseServer.C:1825
bool hasBase() const
const std::string * queryDocumentText() const
Definition: MooseServer.C:1800
Syntax & syntax()
Returns a writable reference to the syntax object.
Definition: MooseApp.h:218
bool getHoverDisplayText(std::string &display_text, int line, int character)
Get hover display text - logic specific to this server implemention.
Definition: MooseServer.C:1105
int line() const
Definition: FileLineInfo.C:23
ActionFactory & getActionFactory()
Retrieve a writable reference to the ActionFactory associated with this App.
Definition: MooseApp.h:399
const std::string & getBase() const
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.
Definition: MooseServer.C:241
const CheckState * queryCheckState() const
Definition: MooseServer.C:1760
FileLineInfo getLineInfo(const std::string &name) const
Gets file and line information where an object was initially registered.
Definition: Factory.C:260
InputParameters emptyInputParameters()
Factory & getFactory()
Retrieve a writable reference to the Factory associated with this App.
Definition: MooseApp.h:394
std::shared_ptr< FEProblemBase > & problemBase()
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.
Definition: MooseServer.h:48
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.
Definition: MooseServer.C:489
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.
Definition: AppFactory.C:62
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.
Definition: MooseServer.C:1263
static std::string buildOutputString(const std::iterator_traits< InputParameters::iterator >::value_type &p)
const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:99
std::string getDocString(const std::string &name) const
Returns the documentation string for the specified parameter name.
const Parser * queryCheckParser() const
Definition: MooseServer.C:1773
void remove(std::string_view)
Specialized factory for generic Action System objects.
Definition: ActionFactory.h:50
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)
Definition: MooseUtils.C:250
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.
Definition: MooseBase.h:89
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:33
const MooseApp * queryCheckApp() const
Definition: MooseServer.C:1786
ActionWarehouse & actionWarehouse()
Return a writable reference to the ActionWarehouse associated with this app.
Definition: MooseApp.h:204
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.
Definition: MooseServer.C:432
virtual Problem & problem()
Deprecated: Return a reference to this Executioner&#39;s Problem instance.
Definition: Executioner.C:117
const auto & registeredObjects() const
Returns a reference to the map from names to RegistryEntryBase pointers.
Definition: Factory.h:147
Helper for storing the state for a single document.
Definition: MooseServer.h:396
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.
Definition: MooseServer.C:1308
static std::string basicCppType(const std::string &cpp_type)
Utilities for making sense of c++ types.
Holds file and line information.
Definition: FileLineInfo.h:18
static AppFactory & instance()
Get the instance of the AppFactory.
Definition: AppFactory.C:18
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 ...
Definition: Syntax.C:251
void makeParamNotRequired(const std::string &name)
Changes the parameter to not be required.
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.
Definition: MooseServer.C:444
bool traverseParseTreeAndFillSymbols(wasp::HITNodeView view_parent, wasp::DataObject &data_parent)
Recursively fill document symbols from the given node.
Definition: MooseServer.C:1469
bool have_parameter(std::string_view name) const
A wrapper around the Parameters base class method.
bool gatherExtensionResponses(wasp::DataArray &extensionResponses, const std::string &extensionMethod, int line, int character)
Gather extension responses - specific to this server implemention.
Definition: MooseServer.C:1620
MooseApp & _moose_app
_moose_app - reference to parent application that owns this server
Definition: MooseServer.h:451
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.
Definition: MooseServer.C:652
bool gatherDocumentCompletionItems(wasp::DataArray &completionItems, bool &is_incomplete, int line, int character)
Gather document completion items - specific to this server implemention.
Definition: MooseServer.C:255
std::string file() const
Definition: FileLineInfo.C:29
bool isValid() const
Definition: FileLineInfo.C:17
std::string type(const std::string &name) const
Prints the type of the requested parameter by name.
bool gatherDocumentReferencesLocations(wasp::DataArray &referencesLocations, int line, int character, bool include_declaration)
Gather references locations - specific to this server implemention.
Definition: MooseServer.C:1189
Scoped helper for setting Moose::_throw_on_error during this scope.
Definition: Moose.h:294
IntRange< T > make_range(T beg, T end)
Holding syntax for parsing input files.
Definition: Syntax.h:21
std::size_t _formatting_tab_size
_formatting_tab_size - number of indent spaces for formatting
Definition: MooseServer.h:481
bool gatherPlottingResponses(wasp::DataArray &plottingResponses, int line, int character)
Build CustomPlot extension responses when method name is plotting.
Definition: MooseServer.C:1633
bool parseDocumentForDiagnostics(wasp::DataArray &diagnosticsList)
Parse document for diagnostics - specific to this server implemention.
Definition: MooseServer.C:55
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...
Definition: Syntax.C:334
bool isParamRequired(const std::string &name) const
Returns a boolean indicating whether the specified parameter is required or not.
bool gatherDocumentDefinitionLocations(wasp::DataArray &definitionLocations, int line, int character)
Gather definition locations - specific to this server implemention.
Definition: MooseServer.C:927
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type...
std::string getClassDescription() const
Returns the class description.
bool addLocationNodesToList(wasp::DataArray &defsOrRefsLocations, const SortedLocationNodes &location_nodes)
Add set of nodes sorted by location to definition or reference list.
Definition: MooseServer.C:1078
std::map< std::string, std::set< std::string > > _syntax_to_subblocks
_syntax_to_subblocks - map of syntax paths to valid subblocks
Definition: MooseServer.h:466
Exception to be thrown whenever we have _throw_on_error set and a mooseError() is emitted...
Definition: MooseError.h:133
int getCompletionItemKind(const InputParameters &valid_params, const std::string &param_name, const std::string &clean_type, bool is_param)
Get completion item kind value that client may use for icon in list.
Definition: MooseServer.C:1521
const std::shared_ptr< libMesh::Parallel::Communicator > getCommunicator() const
Definition: MooseApp.h:1005
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.
Definition: MooseServer.C:915
void ErrorVector unsigned int
Class for parsing input files.
Definition: Parser.h:87
std::map< std::string, CheckState > _check_state
_check_state - map from document paths to state (parser, app, text)
Definition: MooseServer.h:456
const hit::Node * queryRoot() const
Definition: MooseServer.C:1744
std::string formatDocument(wasp::HITNodeView parent, std::size_t &prev_line, std::size_t level)
Recursively walk down whole nodeview tree while formatting document.
Definition: MooseServer.C:1354
void escape(std::string &str)
This function will escape all of the standard C++ escape characters so that they can be printed...
Definition: MooseUtils.C:203
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.
Definition: MooseServer.C:414
std::string prettyCppType(const std::string &cpp_type)
Definition: MooseUtils.C:1147
bool isParamValid(const std::string &name) const
This method returns parameters that have been initialized in one fashion or another, i.e.