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