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