GDevelop Core
Core library for developing platforms and tools compatible with GDevelop.
ExpressionCompletionFinder.h
1 /*
2  * GDevelop Core
3  * Copyright 2008-present Florian Rival ([email protected]). All rights
4  * reserved. This project is released under the MIT License.
5  */
6 #pragma once
7 
8 #include <memory>
9 #include <vector>
10 
11 #include "GDCore/Events/Parsers/ExpressionParser2.h"
12 #include "GDCore/Events/Parsers/ExpressionParser2Node.h"
13 #include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
14 #include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
15 #include "GDCore/Events/Parsers/GrammarTerminals.h"
16 #include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
17 #include "GDCore/Extensions/Metadata/InstructionMetadata.h"
18 #include "GDCore/Extensions/Metadata/ValueTypeMetadata.h"
19 #include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
20 #include "GDCore/IDE/Events/ExpressionTypeFinder.h"
21 #include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
22 #include "GDCore/IDE/Events/ExpressionVariablePathFinder.h"
23 #include "GDCore/Project/ProjectScopedContainers.h"
24 #include "GDCore/Project/Variable.h"
25 
26 namespace gd {
27 class Expression;
28 class ObjectsContainer;
29 class Platform;
30 class ParameterMetadata;
31 class ExpressionMetadata;
32 class ObjectConfiguration;
33 } // namespace gd
34 
35 namespace gd {
36 
40 struct GD_CORE_API ExpressionCompletionDescription {
41  public:
49  Object,
50  BehaviorWithPrefix,
51  ExpressionWithPrefix,
52  Variable,
53  TextWithPrefix,
54  Property,
55  Parameter
56  };
57 
63  const gd::String& prefix_,
64  size_t replacementStartPosition_,
65  size_t replacementEndPosition_,
66  const gd::String& objectName_) {
68  BehaviorWithPrefix, replacementStartPosition_, replacementEndPosition_);
69  description.SetPrefix(prefix_);
70  description.SetObjectName(objectName_);
71  return description;
72  }
73 
78  const gd::String& type_,
79  const gd::ParameterMetadata& parameterMetadata_,
80  const gd::String& prefix_,
81  size_t replacementStartPosition_,
82  size_t replacementEndPosition_,
83  const bool isLastParameter_,
84  const gd::String& objectName_ = "") {
85  auto description = ExpressionCompletionDescription(
86  TextWithPrefix, replacementStartPosition_, replacementEndPosition_);
87  description.SetObjectName(objectName_);
88  description.SetType(type_);
89  description.SetPrefix(prefix_);
90  description.SetIsLastParameter(isLastParameter_);
91  description.SetParameterMetadata(parameterMetadata_);
92  return description;
93  }
94 
100  const gd::String& type_,
101  const gd::String& prefix_,
102  size_t replacementStartPosition_,
103  size_t replacementEndPosition_,
104  const gd::String& objectName_ = "",
105  const gd::String& behaviorName_ = "") {
106  ExpressionCompletionDescription description(ExpressionWithPrefix,
107  replacementStartPosition_,
108  replacementEndPosition_);
109  description.SetObjectName(objectName_);
110  description.SetBehaviorName(behaviorName_);
111  description.SetType(type_);
112  description.SetPrefix(prefix_);
113  return description;
114  }
115 
117  bool operator==(const ExpressionCompletionDescription& other) const {
118  return completionKind == other.completionKind && type == other.type &&
119  variableType == other.variableType && prefix == other.prefix &&
120  objectName == other.objectName && completion == other.completion &&
121  behaviorName == other.behaviorName;
122  };
123 
125  CompletionKind GetCompletionKind() const { return completionKind; }
126 
131  const gd::String& GetType() const { return type; }
132 
133  ExpressionCompletionDescription& SetType(const gd::String& type_) {
134  type = type_;
135  return *this;
136  }
137 
141  gd::Variable::Type GetVariableType() const { return variableType; }
142 
143  ExpressionCompletionDescription& SetVariableType(
144  gd::Variable::Type variableType_) {
145  variableType = variableType_;
146  return *this;
147  }
148 
152  gd::VariablesContainer::SourceType GetVariableScope() const {
153  return variableScope;
154  }
155 
157  SetVariableScope(gd::VariablesContainer::SourceType variableScope_) {
158  variableScope = variableScope_;
159  return *this;
160  }
161 
165  const gd::String& GetPrefix() const { return prefix; }
166 
167  ExpressionCompletionDescription& SetPrefix(const gd::String& prefix_) {
168  prefix = prefix_;
169  return *this;
170  }
171 
175  const gd::String& GetCompletion() const { return completion; }
176 
177  ExpressionCompletionDescription& SetCompletion(
178  const gd::String& completion_) {
179  completion = completion_;
180  return *this;
181  }
182 
187  const gd::String& GetObjectName() const { return objectName; }
188 
189  ExpressionCompletionDescription& SetObjectName(
190  const gd::String& objectName_) {
191  objectName = objectName_;
192  return *this;
193  }
194 
202  const gd::String& GetBehaviorName() const { return behaviorName; }
203 
204  ExpressionCompletionDescription& SetBehaviorName(
205  const gd::String& behaviorName_) {
206  behaviorName = behaviorName_;
207  return *this;
208  }
209 
216  isExact = isExact_;
217  return *this;
218  }
219 
225  bool IsExact() const { return isExact; }
226 
231  return replacementStartPosition;
232  }
233 
237  size_t GetReplacementEndPosition() const { return replacementEndPosition; }
238 
243  isLastParameter = isLastParameter_;
244  return *this;
245  }
246 
250  bool IsLastParameter() const { return isLastParameter; }
251 
257  const gd::ParameterMetadata& parameterMetadata_) {
258  parameterMetadata = &parameterMetadata_;
259  return *this;
260  }
261 
265  bool HasParameterMetadata() const {
266  return parameterMetadata != &badParameterMetadata;
267  }
268 
274  return *parameterMetadata;
275  }
276 
282  const gd::ObjectConfiguration* objectConfiguration_) {
283  objectConfiguration = objectConfiguration_;
284  if (!objectConfiguration) objectConfiguration = &badObjectConfiguration;
285  return *this;
286  }
287 
291  bool HasObjectConfiguration() const {
292  return objectConfiguration != &badObjectConfiguration;
293  }
294 
300  return *objectConfiguration;
301  }
302 
303  gd::String ToString() const {
304  return "{ " + gd::String::From(GetCompletionKind()) + ", " +
305  (GetType() || "no type") + ", " +
306  gd::String::From(GetVariableType()) + ", " +
307  (GetPrefix() || "no prefix") + ", " +
308  (GetCompletion() || "no completion") + ", " +
309  (GetObjectName() || "no object name") + ", " +
310  (GetBehaviorName() || "no behavior name") + ", " +
311  (IsExact() ? "exact" : "non-exact") + ", " +
312  (IsLastParameter() ? "last parameter" : "not last parameter") +
313  ", " +
314  (HasParameterMetadata() ? "with parameter metadata"
315  : "no parameter metadata") +
316  ", " +
317  (HasObjectConfiguration() ? "with object configuration"
318  : "no object configuration") +
319  " }";
320  }
321 
324 
325  ExpressionCompletionDescription(CompletionKind completionKind_,
326  size_t replacementStartPosition_,
327  size_t replacementEndPosition_)
328  : completionKind(completionKind_),
329  variableType(gd::Variable::Number),
330  variableScope(gd::VariablesContainer::Unknown),
331  replacementStartPosition(replacementStartPosition_),
332  replacementEndPosition(replacementEndPosition_),
333  isExact(false),
334  isLastParameter(false),
335  parameterMetadata(&badParameterMetadata),
336  objectConfiguration(&badObjectConfiguration) {}
337 
338  private:
339  CompletionKind completionKind;
340  gd::Variable::Type variableType = gd::Variable::Unknown;
341  gd::VariablesContainer::SourceType variableScope = gd::VariablesContainer::Unknown;
342  gd::String type;
343  gd::String prefix;
344  gd::String completion;
345  size_t replacementStartPosition = 0;
346  size_t replacementEndPosition = 0;
347  gd::String objectName;
348  gd::String behaviorName;
349  bool isExact = false;
350  bool isLastParameter = false;
351  const gd::ParameterMetadata* parameterMetadata = &badParameterMetadata;
352  const gd::ObjectConfiguration* objectConfiguration = &badObjectConfiguration;
353 
354  static const gd::ParameterMetadata badParameterMetadata;
355  static const gd::ObjectConfiguration badObjectConfiguration;
356 };
357 
361 GD_CORE_API std::ostream& operator<<(
362  std::ostream& os, ExpressionCompletionDescription const& value);
363 
369 class GD_CORE_API ExpressionCompletionFinder
370  : public ExpressionParser2NodeWorker {
371  public:
376  static std::vector<ExpressionCompletionDescription>
378  const gd::Platform& platform,
379  const gd::ProjectScopedContainers& projectScopedContainers,
380  const gd::String& rootType,
381  gd::ExpressionNode& node,
382  size_t searchedPosition) {
383  gd::ExpressionNodeLocationFinder finder(searchedPosition);
384  node.Visit(finder);
385  gd::ExpressionNode* nodeAtLocation = finder.GetNode();
386 
387  if (nodeAtLocation == nullptr) {
388  std::vector<ExpressionCompletionDescription> emptyCompletions;
389  return emptyCompletions;
390  }
391 
392  gd::ExpressionNode* maybeParentNodeAtLocation = finder.GetParentNode();
393  gd::ExpressionCompletionFinder autocompletionProvider(
394  platform,
395  projectScopedContainers,
396  rootType,
397  searchedPosition,
398  maybeParentNodeAtLocation);
399  nodeAtLocation->Visit(autocompletionProvider);
400  return autocompletionProvider.GetCompletionDescriptions();
401  }
402 
406  const std::vector<ExpressionCompletionDescription>&
408  return completions;
409  };
410 
411  virtual ~ExpressionCompletionFinder(){};
412 
413  protected:
414  void OnVisitSubExpressionNode(SubExpressionNode& node) override {
415  auto type = gd::ExpressionTypeFinder::GetType(
416  platform, projectScopedContainers, rootType, node);
417 
418  AddCompletionsForAllIdentifiersMatchingSearch("", type);
419  completions.push_back(
421  type, "", searchedPosition + 1, searchedPosition + 1));
422  }
423  void OnVisitOperatorNode(OperatorNode& node) override {
424  // No completions.
425  }
426  void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
428  platform, projectScopedContainers, rootType, node);
429 
430  AddCompletionsForAllIdentifiersMatchingSearch("", type);
431  completions.push_back(
433  type, "", searchedPosition + 1, searchedPosition + 1));
434  }
435  void OnVisitNumberNode(NumberNode& node) override {
436  // No completions
437  }
438 
439  void OnVisitTextNode(TextNode& node) override {
440  // Completions are searched in the case the text node is a parameter of a
441  // function call.
442  FunctionCallNode* functionCall =
443  dynamic_cast<FunctionCallNode*>(maybeParentNodeAtLocation);
444  if (functionCall != nullptr) {
445  int parameterIndex = -1;
446  for (int i = 0; i < functionCall->parameters.size(); i++) {
447  if (functionCall->parameters.at(i).get() == &node) {
448  parameterIndex = i;
449  break;
450  }
451  }
452  if (parameterIndex < 0) {
453  return;
454  }
455  // Search the parameter metadata index skipping invisible ones.
456  size_t visibleParameterIndex = 0;
457  size_t metadataParameterIndex =
459  functionCall->objectName, functionCall->behaviorName);
460  const auto& objectsContainersList =
461  projectScopedContainers.GetObjectsContainersList();
462  const gd::ExpressionMetadata& metadata =
463  MetadataProvider::GetFunctionCallMetadata(
464  platform, objectsContainersList, *functionCall);
465 
466  const gd::ParameterMetadata *parameterMetadata = nullptr;
467  while (metadataParameterIndex <
468  metadata.GetParameters().GetParametersCount()) {
469  if (!metadata.GetParameters()
470  .GetParameter(metadataParameterIndex)
471  .IsCodeOnly()) {
472  if (visibleParameterIndex == parameterIndex) {
473  parameterMetadata =
474  &metadata.GetParameters().GetParameter(metadataParameterIndex);
475  }
476  visibleParameterIndex++;
477  }
478  metadataParameterIndex++;
479  }
480  const int visibleParameterCount = visibleParameterIndex;
481  if (parameterMetadata == nullptr) {
482  // There are too many parameters in the expression, this text node is
483  // not actually linked to a parameter expected by the function call.
484  return;
485  }
486 
487  const gd::String& type = parameterMetadata->GetType();
488  if (type == "string") {
489  // No completions for an arbitrary string.
490  return;
491  }
492 
493  bool isLastParameter = parameterIndex == visibleParameterCount - 1;
495  type,
496  *parameterMetadata,
497  node.text,
498  node.location.GetStartPosition(),
499  node.location.GetEndPosition(),
500  isLastParameter,
501  functionCall->objectName));
502  }
503  }
504  void OnVisitVariableNode(VariableNode& node) override {
505  const auto& objectsContainersList =
506  projectScopedContainers.GetObjectsContainersList();
508  platform, projectScopedContainers, rootType, node);
509 
510  // Only attempt to complete with the children of the variable
511  // if it's the last child (no more `.AnotherVariable` written after).
512  bool eagerlyCompleteIfExactMatch = node.child == nullptr;
513 
515  if (type == "globalvar" || type == "scenevar") {
516  const auto* variablesContainer =
517  type == "globalvar"
518  ? projectScopedContainers.GetVariablesContainersList()
519  .GetTopMostVariablesContainer()
520  : projectScopedContainers.GetVariablesContainersList()
521  .GetBottomMostVariablesContainer();
522  if (variablesContainer) {
523  AddCompletionsForVariablesMatchingSearch(
524  *variablesContainer, "", node.name, node.nameLocation,
525  eagerlyCompleteIfExactMatch);
526  }
527  } else if (type == "objectvar") {
529  platform, objectsContainersList, rootObjectName, node);
530 
531  AddCompletionsForObjectOrGroupVariablesMatchingSearch(
532  objectsContainersList, objectName, "", node.name, node.nameLocation,
533  eagerlyCompleteIfExactMatch);
534  }
535  } else {
536  AddCompletionsForObjectsAndVariablesMatchingSearch(
537  node.name, type, node.nameLocation, eagerlyCompleteIfExactMatch);
538  }
539  }
540  void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
541  VariableAndItsParent variableAndItsParent =
542  gd::ExpressionVariablePathFinder::GetLastParentOfNode(
543  platform, projectScopedContainers, node);
544 
545  const auto typeAndExtraInfo = gd::ExpressionTypeFinder::GetTypeAndExtraInfo(
546  platform, projectScopedContainers, rootType, node);
547  const auto type = typeAndExtraInfo.type;
548  const auto extraInfo = typeAndExtraInfo.extraInfo;
549 
550  // If no child, we're at the end of a variable (like `GrandChild` in
551  // `Something.Child.GrandChild`) so we can complete eagerly children if we
552  // can.
553  gd::String eagerlyCompleteForVariableName =
554  node.child == nullptr ? node.name : "";
555  AddCompletionsForChildrenVariablesOf(variableAndItsParent, extraInfo,
556  node.nameLocation,
557  eagerlyCompleteForVariableName);
558  }
559  void OnVisitVariableBracketAccessorNode(
560  VariableBracketAccessorNode& node) override {}
561  void OnVisitIdentifierNode(IdentifierNode& node) override {
562  const auto& objectsContainersList =
563  projectScopedContainers.GetObjectsContainersList();
564 
565  const auto typeAndExtraInfo = gd::ExpressionTypeFinder::GetTypeAndExtraInfo(
566  platform, projectScopedContainers, rootType, node);
567  const auto type = typeAndExtraInfo.type;
568  const auto extraInfo = typeAndExtraInfo.extraInfo;
569 
571  // Only show completions of objects if an object is required.
572  AddCompletionsForObjectMatchingSearch(
573  node.identifierName, type, node.location);
575  if (type == "globalvar" || type == "scenevar") {
576  const auto* variablesContainer =
577  type == "globalvar"
578  ? projectScopedContainers.GetVariablesContainersList()
579  .GetTopMostVariablesContainer()
580  : projectScopedContainers.GetVariablesContainersList()
581  .GetBottomMostVariablesContainer();
582  if (variablesContainer) {
583  if (IsCaretOn(node.identifierNameDotLocation) ||
584  IsCaretOn(node.childIdentifierNameLocation)) {
585  // Complete a potential child variable:
586  if (variablesContainer->Has(node.identifierName)) {
587  AddCompletionsForChildrenVariablesOf(
588  variablesContainer->Get(node.identifierName), extraInfo,
589  node.childIdentifierNameLocation, node.childIdentifierName);
590  }
591  } else {
592  // Complete a root variable of the scene or project.
593 
594  // Don't attempt to complete children variables if there is
595  // already a dot written (`MyVariable.`).
596  bool eagerlyCompleteIfPossible =
597  !node.identifierNameDotLocation.IsValid();
598  AddCompletionsForVariablesMatchingSearch(
599  *variablesContainer, extraInfo, node.identifierName,
600  node.identifierNameLocation, eagerlyCompleteIfPossible);
601  }
602  }
603  } else if (type == "objectvar") {
605  platform, objectsContainersList, rootObjectName, node);
606 
607  if (IsCaretOn(node.identifierNameDotLocation) ||
608  IsCaretOn(node.childIdentifierNameLocation)) {
609  // Complete a potential child variable:
610  const auto* variablesContainer =
611  objectsContainersList.GetObjectOrGroupVariablesContainer(
612  objectName);
613  if (variablesContainer &&
614  variablesContainer->Has(node.identifierName)) {
615  AddCompletionsForChildrenVariablesOf(
616  variablesContainer->Get(node.identifierName), extraInfo,
617  node.childIdentifierNameLocation, node.childIdentifierName);
618  }
619  } else {
620  // Complete a root variable of the object.
621 
622  // Don't attempt to complete children variables if there is
623  // already a dot written (`MyVariable.`).
624  bool eagerlyCompleteIfPossible =
625  !node.identifierNameDotLocation.IsValid();
626  AddCompletionsForObjectOrGroupVariablesMatchingSearch(
627  objectsContainersList, objectName, extraInfo, node.identifierName,
628  node.identifierNameLocation, eagerlyCompleteIfPossible);
629  }
630  }
631  } else {
632  // Object function, behavior name, variable, object variable.
633  if (IsCaretOn(node.identifierNameLocation)) {
634  // Don't attempt to complete children variables if there is
635  // already a dot written (`MyVariable.`).
636  bool eagerlyCompleteIfPossible =
637  !node.identifierNameDotLocation.IsValid();
638  AddCompletionsForAllIdentifiersMatchingSearch(
639  node.identifierName,
640  type,
641  extraInfo,
642  node.identifierNameLocation,
643  eagerlyCompleteIfPossible);
644  if (!node.identifierNameDotLocation.IsValid() &&
645  !gd::ValueTypeMetadata::IsTypeExpression("variable", type)) {
646  completions.push_back(
648  type, node.identifierName,
649  node.identifierNameLocation.GetStartPosition(),
650  node.identifierNameLocation.GetEndPosition()));
651  }
652  } else if (IsCaretOn(node.identifierNameDotLocation) ||
653  IsCaretOn(node.childIdentifierNameLocation)) {
654  // Might be:
655  // - An object variable, object behavior or object expression.
656  // - Or a variable with a child.
657  projectScopedContainers.MatchIdentifierWithName<void>(
658  node.identifierName,
659  [&]() {
660  // This is an object.
661  const gd::String& objectName = node.identifierName;
662  AddCompletionsForObjectOrGroupVariablesMatchingSearch(
663  objectsContainersList, objectName, extraInfo,
664  node.childIdentifierName, node.childIdentifierNameLocation,
665  true);
666 
667  completions.push_back(
669  node.childIdentifierName,
670  node.childIdentifierNameLocation.GetStartPosition(),
671  node.childIdentifierNameLocation.GetEndPosition(),
672  objectName));
673  completions.push_back(
675  type,
676  node.childIdentifierName,
677  node.childIdentifierNameLocation.GetStartPosition(),
678  node.childIdentifierNameLocation.GetEndPosition(),
679  objectName));
680  },
681  [&]() {
682  // This is a variable.
683  VariableAndItsParent variableAndItsParent =
684  gd::ExpressionVariablePathFinder::GetLastParentOfNode(
685  platform, projectScopedContainers, node);
686 
687  AddCompletionsForChildrenVariablesOf(
688  variableAndItsParent,
689  extraInfo,
690  node.childIdentifierNameLocation,
691  node.childIdentifierName);
692  },
693  [&]() {
694  // Ignore properties here.
695  // There is no support for "children" of properties.
696  },
697  [&]() {
698  // Ignore parameters here.
699  // There is no support for "children" of parameters.
700  },
701  [&]() {
702  // Ignore unrecognised identifiers here.
703  });
704  }
705  }
706  }
707  void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
709  platform, projectScopedContainers, rootType, node);
710  if (!node.behaviorFunctionName.empty() ||
711  node.behaviorNameNamespaceSeparatorLocation.IsValid()) {
712  // Behavior function (or behavior function being written, with the
713  // function name missing)
714  if (IsCaretOn(node.objectNameLocation)) {
715  AddCompletionsForObjectMatchingSearch(
716  node.objectName, type, node.objectNameLocation);
717  } else if (IsCaretOn(node.objectNameDotLocation) ||
718  IsCaretOn(node.objectFunctionOrBehaviorNameLocation)) {
719  completions.push_back(
721  node.objectFunctionOrBehaviorName,
722  node.objectFunctionOrBehaviorNameLocation.GetStartPosition(),
723  node.objectFunctionOrBehaviorNameLocation.GetEndPosition(),
724  node.objectName));
725  } else if (IsCaretOn(node.behaviorNameNamespaceSeparatorLocation) ||
726  IsCaretOn(node.behaviorFunctionNameLocation)) {
727  completions.push_back(
729  type,
730  node.behaviorFunctionName,
731  node.behaviorFunctionNameLocation.GetStartPosition(),
732  node.behaviorFunctionNameLocation.GetEndPosition(),
733  node.objectName,
734  node.objectFunctionOrBehaviorName));
735  }
736  } else {
737  // Object function or behavior name
738  if (IsCaretOn(node.objectNameLocation)) {
739  AddCompletionsForObjectMatchingSearch(
740  node.objectName, type, node.objectNameLocation);
741  } else if (IsCaretOn(node.objectNameDotLocation) ||
742  IsCaretOn(node.objectFunctionOrBehaviorNameLocation)) {
743  completions.push_back(
745  node.objectFunctionOrBehaviorName,
746  node.objectFunctionOrBehaviorNameLocation.GetStartPosition(),
747  node.objectFunctionOrBehaviorNameLocation.GetEndPosition(),
748  node.objectName));
749  completions.push_back(
751  type,
752  node.objectFunctionOrBehaviorName,
753  node.objectFunctionOrBehaviorNameLocation.GetStartPosition(),
754  node.objectFunctionOrBehaviorNameLocation.GetEndPosition(),
755  node.objectName));
756  }
757  }
758  }
759  void OnVisitFunctionCallNode(FunctionCallNode& node) override {
761  platform, projectScopedContainers, rootType, node);
762  bool isCaretOnParenthesis = IsCaretOn(node.openingParenthesisLocation) ||
763  IsCaretOn(node.closingParenthesisLocation);
764 
765  if (!node.behaviorName.empty()) {
766  // Behavior function
767  if (IsCaretOn(node.objectNameLocation)) {
768  AddCompletionsForObjectMatchingSearch(
769  node.objectName, type, node.objectNameLocation);
770  } else if (IsCaretOn(node.objectNameDotLocation) ||
771  IsCaretOn(node.behaviorNameLocation)) {
772  completions.push_back(
774  node.behaviorName,
775  node.behaviorNameLocation.GetStartPosition(),
776  node.behaviorNameLocation.GetEndPosition(),
777  node.objectName));
778  } else {
779  completions.push_back(
781  type,
782  node.functionName,
783  node.functionNameLocation.GetStartPosition(),
784  node.functionNameLocation.GetEndPosition(),
785  node.objectName,
786  node.behaviorName)
787  .SetIsExact(isCaretOnParenthesis));
788  }
789  } else if (!node.objectName.empty()) {
790  // Object function
791  if (IsCaretOn(node.objectNameLocation)) {
792  AddCompletionsForObjectMatchingSearch(
793  node.objectName, type, node.objectNameLocation);
794  } else {
795  // Add completions for behaviors, because we could imagine that the user
796  // wants to move from an object function to a behavior function, and so
797  // need behavior completions. Do this unless we're on the parenthesis
798  // (at which point we're only showing informative message about the
799  // function).
800  if (!isCaretOnParenthesis) {
801  completions.push_back(
803  node.functionName,
804  node.objectNameLocation.GetStartPosition(),
805  node.objectNameLocation.GetEndPosition(),
806  node.objectName));
807  }
808 
809  completions.push_back(
811  type,
812  node.functionName,
813  node.functionNameLocation.GetStartPosition(),
814  node.functionNameLocation.GetEndPosition(),
815  node.objectName)
816  .SetIsExact(isCaretOnParenthesis));
817  }
818  } else {
819  // Free function
820  completions.push_back(
822  type,
823  node.functionName,
824  node.functionNameLocation.GetStartPosition(),
825  node.functionNameLocation.GetEndPosition())
826  .SetIsExact(isCaretOnParenthesis));
827  }
828  }
829  void OnVisitEmptyNode(EmptyNode& node) override {
831  platform, projectScopedContainers, rootType, node);
832 
833  AddCompletionsForAllIdentifiersMatchingSearch(
834  node.text, type, "", node.location);
835  completions.push_back(
837  type,
838  node.text,
839  node.location.GetStartPosition(),
840  node.location.GetEndPosition()));
841  }
842 
843  private:
844  bool IsCaretOn(const ExpressionParserLocation& location,
845  bool inclusive = false) {
846  if (!location.IsValid()) return false;
847 
848  return (location.GetStartPosition() <= searchedPosition &&
849  ((!inclusive && searchedPosition < location.GetEndPosition()) ||
850  (inclusive && searchedPosition <= location.GetEndPosition())));
851  }
852 
857  bool IsIdentifierSafe(const gd::String& name) {
858  if (name.empty()) return false;
859 
860  for (auto character : name) {
861  if (!GrammarTerminals::IsAllowedInIdentifier(character)) {
862  return false;
863  }
864  }
865 
866  return true;
867  }
868 
869  void AddCompletionsForChildrenVariablesOf(
870  VariableAndItsParent variableAndItsParent,
871  const gd::String& variableTypeConstraint,
872  const ExpressionParserLocation& location,
873  gd::String eagerlyCompleteForVariableName = "") {
874  if (variableAndItsParent.parentVariable) {
875  AddCompletionsForChildrenVariablesOf(*variableAndItsParent.parentVariable,
876  variableTypeConstraint, location,
877  eagerlyCompleteForVariableName);
878  } else if (variableAndItsParent.parentVariablesContainer) {
879  AddCompletionsForVariablesMatchingSearch(
880  *variableAndItsParent.parentVariablesContainer,
881  variableTypeConstraint, "", location);
882  }
883  }
884 
885  void AddCompletionsForChildrenVariablesOf(
886  const gd::Variable& variable,
887  const gd::String& variableTypeConstraint,
888  const ExpressionParserLocation& location,
889  gd::String eagerlyCompleteForVariableName = "") {
890  if (variable.GetType() == gd::Variable::Structure) {
891  for (const auto& name : variable.GetAllChildrenNames()) {
892  if (!IsIdentifierSafe(name)) continue;
893 
894  const auto& childVariable = variable.GetChild(name);
895 
896  bool isCollection =
897  (childVariable.GetType() == gd::Variable::Type::Structure ||
898  childVariable.GetType() == gd::Variable::Type::Array);
899  // Primitive children might be found inside collection children.
900  // So, we always show children that are collections.
901  if (variableTypeConstraint != "collection" || isCollection) {
902  ExpressionCompletionDescription description(
903  ExpressionCompletionDescription::Variable,
904  location.GetStartPosition(),
905  location.GetEndPosition());
906  description.SetCompletion(name);
907  description.SetVariableType(childVariable.GetType());
908  completions.push_back(description);
909  }
910 
911  if (name == eagerlyCompleteForVariableName) {
912  AddEagerCompletionForVariableChildren(
913  childVariable, name,
914  // The scope is only displayed with the root variable.
915  gd::VariablesContainer::SourceType::Unknown,
916  variableTypeConstraint, location);
917  }
918  }
919  } else {
920  // TODO: we could do a "comment only completion" to indicate that nothing
921  // can/should be completed?
922  }
923  }
924 
925  void AddEagerCompletionForVariableChildren(
926  const gd::Variable& variable,
927  const gd::String& variableName,
928  const gd::VariablesContainer::SourceType variableScope,
929  const gd::String& variableTypeConstraint,
930  const ExpressionParserLocation& location) {
931  if (variable.GetType() == gd::Variable::Structure) {
932  gd::String prefix = variableName + ".";
933  for (const auto& name : variable.GetAllChildrenNames()) {
934  gd::String completion =
935  IsIdentifierSafe(name)
936  ? (prefix + name)
937  : (variableName + "[" +
938  gd::ExpressionParser2NodePrinter::PrintStringLiteral(name) +
939  "]");
940 
941  const auto& childVariable = variable.GetChild(name);
942 
943  bool isCollection =
944  (childVariable.GetType() == gd::Variable::Type::Structure ||
945  childVariable.GetType() == gd::Variable::Type::Array);
946  // Primitive children might be found inside collection children.
947  // So, we always show children that are collections.
948  if (variableTypeConstraint != "collection" || isCollection) {
949  ExpressionCompletionDescription description(
950  ExpressionCompletionDescription::Variable,
951  location.GetStartPosition(),
952  location.GetEndPosition());
953  description.SetCompletion(completion);
954  description.SetVariableType(childVariable.GetType());
955  description.SetVariableScope(variableScope);
956  completions.push_back(description);
957  }
958  }
959  }
960  if (variable.GetType() == gd::Variable::Structure ||
961  variable.GetType() == gd::Variable::Array) {
962  ExpressionCompletionDescription description(
963  ExpressionCompletionDescription::Variable,
964  location.GetStartPosition(), location.GetEndPosition());
965  description.SetCompletion(variableName + "[]");
966  description.SetVariableType(variable.GetType());
967  description.SetVariableScope(variableScope);
968  completions.push_back(description);
969  }
970  }
971 
972  void AddCompletionsForVariablesMatchingSearch(
973  const gd::VariablesContainer& variablesContainer,
974  const gd::String& variableTypeConstraint,
975  const gd::String& search,
976  const ExpressionParserLocation& location,
977  bool eagerlyCompleteIfExactMatch = false) {
978  variablesContainer.ForEachVariableMatchingSearch(
979  search,
980  [&](const gd::String& variableName, const gd::Variable& variable) {
981  ExpressionCompletionDescription description(
982  ExpressionCompletionDescription::Variable,
983  location.GetStartPosition(),
984  location.GetEndPosition());
985  description.SetCompletion(variableName);
986  description.SetVariableType(variable.GetType());
987  description.SetVariableScope(variablesContainer.GetSourceType());
988  completions.push_back(description);
989 
990  if (eagerlyCompleteIfExactMatch && variableName == search) {
991  AddEagerCompletionForVariableChildren(
992  variable, variableName, variablesContainer.GetSourceType(),
993  variableTypeConstraint, location);
994  }
995  });
996  }
997 
998  void AddCompletionsForObjectOrGroupVariablesMatchingSearch(
999  const gd::ObjectsContainersList& objectsContainersList,
1000  const gd::String& objectOrGroupName,
1001  const gd::String& variableTypeConstraint,
1002  const gd::String& search,
1003  const ExpressionParserLocation& location,
1004  bool eagerlyCompleteIfExactMatch) {
1005  objectsContainersList.ForEachObjectOrGroupVariableMatchingSearch(
1006  objectOrGroupName, search,
1007  [&](const gd::String &variableName, const gd::Variable &variable) {
1008  bool isCollection =
1009  (variable.GetType() == gd::Variable::Type::Structure ||
1010  variable.GetType() == gd::Variable::Type::Array);
1011  // Primitive children might be found inside collection children.
1012  // So, we always show children that are collections.
1013  if (variableTypeConstraint != "collection" || isCollection) {
1014  ExpressionCompletionDescription description(
1015  ExpressionCompletionDescription::Variable,
1016  location.GetStartPosition(), location.GetEndPosition());
1017  description.SetCompletion(variableName);
1018  description.SetVariableType(variable.GetType());
1019  description.SetVariableScope(gd::VariablesContainer::Object);
1020  completions.push_back(description);
1021  }
1022  if (eagerlyCompleteIfExactMatch && variableName == search) {
1023  AddEagerCompletionForVariableChildren(
1024  variable, variableName, gd::VariablesContainer::Object,
1025  variableTypeConstraint, location);
1026  }
1027  });
1028  }
1029 
1030  void AddCompletionsForObjectMatchingSearch(
1031  const gd::String& search,
1032  const gd::String& type,
1033  const ExpressionParserLocation& location) {
1034  projectScopedContainers.GetObjectsContainersList()
1035  .ForEachNameMatchingSearch(
1036  search,
1037  [&](const gd::String& name,
1038  const gd::ObjectConfiguration* objectConfiguration) {
1039  ExpressionCompletionDescription description(
1040  ExpressionCompletionDescription::Object,
1041  location.GetStartPosition(),
1042  location.GetEndPosition());
1043  description.SetObjectConfiguration(objectConfiguration);
1044  description.SetCompletion(name);
1045  description.SetType(type);
1046  completions.push_back(description);
1047  });
1048  }
1049 
1050  void AddCompletionsForObjectsAndVariablesMatchingSearch(
1051  const gd::String& search,
1052  const gd::String& type,
1053  const ExpressionParserLocation& location,
1054  bool eagerlyCompleteIfExactMatch) {
1055  projectScopedContainers.ForEachIdentifierMatchingSearch(
1056  search,
1057  [&](const gd::String& objectName,
1058  const ObjectConfiguration* objectConfiguration) {
1059  ExpressionCompletionDescription description(
1060  ExpressionCompletionDescription::Object,
1061  location.GetStartPosition(),
1062  location.GetEndPosition());
1063  description.SetObjectConfiguration(objectConfiguration);
1064  description.SetCompletion(objectName);
1065  description.SetType(type);
1066  completions.push_back(description);
1067  },
1068  [&](const gd::String& variableName, const gd::Variable& variable) {
1069  ExpressionCompletionDescription description(
1070  ExpressionCompletionDescription::Variable,
1071  location.GetStartPosition(),
1072  location.GetEndPosition());
1073  description.SetCompletion(variableName);
1074  description.SetVariableType(variable.GetType());
1075  auto variableScope =
1076  projectScopedContainers.GetVariablesContainersList()
1077  .GetVariablesContainerFromVariableOrPropertyOrParameterName(
1078  variableName)
1079  .GetSourceType();
1080  description.SetVariableScope(variableScope);
1081  completions.push_back(description);
1082 
1083  if (eagerlyCompleteIfExactMatch && variableName == search) {
1084  AddEagerCompletionForVariableChildren(
1085  variable, variableName, variableScope, "", location);
1086  }
1087  },
1088  [&](const gd::NamedPropertyDescriptor& property) {
1089  // Ignore properties here.
1090  },
1091  [&](const gd::ParameterMetadata& parameter) {
1092  // Ignore parameters here.
1093  });
1094  }
1095 
1096  void AddCompletionsForAllIdentifiersMatchingSearch(const gd::String& search,
1097  const gd::String& type) {
1098  AddCompletionsForAllIdentifiersMatchingSearch(
1099  search, type, "",
1100  ExpressionParserLocation(searchedPosition + 1, searchedPosition + 1));
1101  }
1102 
1103  void AddCompletionsForAllIdentifiersMatchingSearch(
1104  const gd::String& search,
1105  const gd::String& type,
1106  const gd::String& extraInfo,
1107  const ExpressionParserLocation& location,
1108  bool eagerlyCompleteIfExactMatch = false) {
1109  projectScopedContainers.ForEachIdentifierMatchingSearch(
1110  search,
1111  [&](const gd::String &objectName,
1112  const ObjectConfiguration *objectConfiguration) {
1113  if (gd::ValueTypeMetadata::IsTypeExpression("variable", type)) {
1114  return;
1115  }
1116  ExpressionCompletionDescription description(
1117  ExpressionCompletionDescription::Object,
1118  location.GetStartPosition(),
1119  location.GetEndPosition());
1120  description.SetObjectConfiguration(objectConfiguration);
1121  description.SetCompletion(objectName);
1122  description.SetType(type);
1123  completions.push_back(description);
1124  },
1125  [&](const gd::String &variableName, const gd::Variable &variable) {
1126  bool isCollection =
1127  (variable.GetType() == gd::Variable::Type::Structure ||
1128  variable.GetType() == gd::Variable::Type::Array);
1129  // Primitive children might be found inside collection children.
1130  // So, we always show children that are collections.
1131  if (extraInfo == "collection" && !isCollection) {
1132  return;
1133  }
1134  ExpressionCompletionDescription description(
1135  ExpressionCompletionDescription::Variable,
1136  location.GetStartPosition(),
1137  location.GetEndPosition());
1138  description.SetCompletion(variableName);
1139  description.SetVariableType(variable.GetType());
1140  auto variableScope =
1141  projectScopedContainers.GetVariablesContainersList()
1142  .GetVariablesContainerFromVariableOrPropertyOrParameterName(
1143  variableName)
1144  .GetSourceType();
1145  description.SetVariableScope(variableScope);
1146  completions.push_back(description);
1147 
1148  if (eagerlyCompleteIfExactMatch && variableName == search) {
1149  AddEagerCompletionForVariableChildren(
1150  variable, variableName, variableScope, extraInfo, location);
1151  }
1152  },
1153  [&](const gd::NamedPropertyDescriptor &property) {
1154  if (extraInfo == "collection") {
1155  return;
1156  }
1158  property.GetType());
1159  if (gd::ValueTypeMetadata::IsTypeValue("number", propertyType) ||
1160  gd::ValueTypeMetadata::IsTypeValue("string", propertyType)) {
1161  ExpressionCompletionDescription description(
1162  ExpressionCompletionDescription::Property,
1163  location.GetStartPosition(), location.GetEndPosition());
1164  description.SetCompletion(property.GetName());
1165  description.SetType(property.GetType());
1166  completions.push_back(description);
1167  }
1168  },
1169  [&](const gd::ParameterMetadata &parameter) {
1170  if (extraInfo == "collection") {
1171  return;
1172  }
1173  if (parameter.GetValueTypeMetadata().IsNumber() ||
1174  parameter.GetValueTypeMetadata().IsString()) {
1175  ExpressionCompletionDescription description(
1176  ExpressionCompletionDescription::Parameter,
1177  location.GetStartPosition(), location.GetEndPosition());
1178  description.SetCompletion(parameter.GetName());
1179  description.SetType(parameter.GetType());
1180  completions.push_back(description);
1181  }
1182  });
1183  }
1184 
1185  ExpressionCompletionFinder(
1186  const gd::Platform& platform_,
1187  const gd::ProjectScopedContainers& projectScopedContainers_,
1188  const gd::String& rootType_,
1189  size_t searchedPosition_,
1190  gd::ExpressionNode* maybeParentNodeAtLocation_)
1191  : searchedPosition(searchedPosition_),
1192  maybeParentNodeAtLocation(maybeParentNodeAtLocation_),
1193  platform(platform_),
1194  projectScopedContainers(projectScopedContainers_),
1195  rootType(rootType_),
1196  rootObjectName("") // Always empty, might be changed if variable fields
1197  // in the editor are changed to use completion.
1198  {};
1199 
1200  std::vector<ExpressionCompletionDescription> completions;
1201  size_t searchedPosition;
1202  gd::ExpressionNode* maybeParentNodeAtLocation;
1203 
1204  const gd::Platform& platform;
1205  const gd::ProjectScopedContainers& projectScopedContainers;
1206  const gd::String rootType;
1207  const gd::String rootObjectName;
1208 };
1209 
1210 } // namespace gd
Returns the list of completion descriptions for an expression node.
Definition: ExpressionCompletionFinder.h:370
const std::vector< ExpressionCompletionDescription > & GetCompletionDescriptions()
Return the completions found for the visited node.
Definition: ExpressionCompletionFinder.h:407
static std::vector< ExpressionCompletionDescription > GetCompletionDescriptionsFor(const gd::Platform &platform, const gd::ProjectScopedContainers &projectScopedContainers, const gd::String &rootType, gd::ExpressionNode &node, size_t searchedPosition)
Given the expression, find the node at the specified location and returns completions for it.
Definition: ExpressionCompletionFinder.h:377
Describe user-friendly information about an expression, its parameters and the function name as well ...
Definition: ExpressionMetadata.h:47
Find the deepest node at the specified location in an expression.
Definition: ExpressionNodeLocationFinder.h:30
ExpressionNode * GetParentNode()
Return the parent of deepest node found at the search position, if any.
Definition: ExpressionNodeLocationFinder.h:74
ExpressionNode * GetNode()
Return the deepest node found at the search position, if any.
Definition: ExpressionNodeLocationFinder.h:68
static size_t WrittenParametersFirstIndex(const gd::String &objectName, const gd::String &behaviorName)
Definition: ExpressionParser2.h:80
The interface for any worker class ("visitor" pattern) that want to interact with the nodes of a pars...
Definition: ExpressionParser2NodeWorker.h:36
static const gd::TypeAndExtraInfo GetTypeAndExtraInfo(const gd::Platform &platform, const gd::ProjectScopedContainers &projectScopedContainers, const gd::String &rootType, gd::ExpressionNode &node)
Helper function to find the type of the expression or sub-expression that a given node represents.
Definition: ExpressionTypeFinder.h:70
static const gd::String GetType(const gd::Platform &platform, const gd::ProjectScopedContainers &projectScopedContainers, const gd::String &rootType, gd::ExpressionNode &node)
Helper function to find the type of the expression or sub-expression that a given node represents.
Definition: ExpressionTypeFinder.h:56
const gd::String & GetObjectName()
Get all the errors.
Definition: ExpressionVariableOwnerFinder.h:75
Used to describe a property shown in a property grid.
Definition: NamedPropertyDescriptor.h:21
Base class used to represent an object configuration. For example, this can be the animations in a sp...
Definition: ObjectConfiguration.h:38
Represent an object of a platform.
Definition: Object.h:39
A list of objects containers, useful for accessing objects in a scoped way, along with methods to acc...
Definition: ObjectsContainersList.h:29
void ForEachObjectOrGroupVariableMatchingSearch(const gd::String &objectOrGroupName, const gd::String &search, std::function< void(const gd::String &variableName, const gd::Variable &variable)> fn) const
Call the callback for each variable of the object (or group) matching the search passed in parameter.
Definition: ObjectsContainersList.cpp:274
gd::ParameterMetadata & GetParameter(const gd::String &name)
Get the function with the specified name.
Definition: ParameterMetadataContainer.h:44
std::size_t GetParametersCount() const
Return the number of functions.
Definition: ParameterMetadataContainer.h:79
Describe a parameter of an instruction (action, condition) or of an expression: type,...
Definition: ParameterMetadata.h:27
static bool IsObject(const gd::String &parameterType)
Return true if the type of the parameter is representing one object (or more, i.e: an object group).
Definition: ParameterMetadata.h:208
bool IsCodeOnly() const
Return true if the parameter is only meant to be completed during compilation and must not be display...
Definition: ParameterMetadata.h:144
const gd::String & GetType() const
Return the type of the parameter.
Definition: ParameterMetadata.h:61
Base class for implementing a platform.
Definition: Platform.h:42
Holds references to variables, objects, properties and other containers.
Definition: ProjectScopedContainers.h:36
String represents an UTF8 encoded string.
Definition: String.h:33
static String From(T value)
Method to create a gd::String from a number (float, double, int, ...)
Definition: String.h:221
void push_back(value_type character)
Add a character (from its codepoint) at the end of the String.
Definition: String.cpp:223
bool empty() const
Returns true if the string is empty.
Definition: String.h:157
static bool IsTypeExpression(const gd::String &type, const gd::String &parameterType)
Return true if the type is an expression of the given type from the caller point of view.
Definition: ValueTypeMetadata.h:219
static const gd::String & ConvertPropertyTypeToValueType(const gd::String &propertyType)
Return the ValueTypeMetadata name for a property type.
Definition: ValueTypeMetadata.cpp:130
static bool IsTypeLegacyPreScopedVariable(const gd::String &type)
Return true if the type is a variable but from a specific scope (scene, project or object)....
Definition: ValueTypeMetadata.h:178
static bool IsTypeValue(const gd::String &type, const gd::String &parameterType)
Return true if the type is a value of the given primitive type from the function events point of view...
Definition: ValueTypeMetadata.h:280
Defines a variable which can be used by an object, a layout or a project.
Definition: Variable.h:29
Type
Definition: Variable.h:32
Variable & GetChild(const gd::String &name)
Return the child with the specified name.
Definition: Variable.cpp:149
Type GetType() const
Get the type of the variable.
Definition: Variable.h:64
std::vector< gd::String > GetAllChildrenNames() const
Get the names of all children.
Definition: Variable.cpp:383
Class defining a container for gd::Variable.
Definition: VariablesContainer.h:29
void ForEachVariableMatchingSearch(const gd::String &search, std::function< void(const gd::String &name, const gd::Variable &variable)> fn) const
Call the callback for each variable with a name matching the specified search.
Definition: VariablesContainer.cpp:177
bool IsAllowedInIdentifier(gd::String::value_type character)
Definition: GrammarTerminals.h:110
Definition: CommonTools.h:24
std::ostream & operator<<(std::ostream &os, ExpressionCompletionDescription const &value)
Turn an ExpressionCompletionDescription to a string.
Definition: ExpressionCompletionFinder.cpp:19
Describe completions to be shown to the user.
Definition: ExpressionCompletionFinder.h:40
const gd::String & GetCompletion() const
Return the completion that must be inserted.
Definition: ExpressionCompletionFinder.h:175
const gd::String & GetPrefix() const
Return the prefix that must be completed.
Definition: ExpressionCompletionFinder.h:165
bool operator==(const ExpressionCompletionDescription &other) const
Definition: ExpressionCompletionFinder.h:117
ExpressionCompletionDescription()
Definition: ExpressionCompletionFinder.h:323
bool IsExact() const
Check if the completion description is exact, i.e: it's not used to complete anything....
Definition: ExpressionCompletionFinder.h:225
const gd::String & GetObjectName() const
Return the object name, if completing an object expression or a behavior.
Definition: ExpressionCompletionFinder.h:187
ExpressionCompletionDescription & SetObjectConfiguration(const gd::ObjectConfiguration *objectConfiguration_)
Set the object configuration, in the case the completion is about an object.
Definition: ExpressionCompletionFinder.h:281
ExpressionCompletionDescription & SetParameterMetadata(const gd::ParameterMetadata &parameterMetadata_)
Set the parameter metadata, in the case the completion is about a parameter of a function call.
Definition: ExpressionCompletionFinder.h:256
gd::VariablesContainer::SourceType GetVariableScope() const
Return the scope of the variable, for a variable completion.
Definition: ExpressionCompletionFinder.h:152
static ExpressionCompletionDescription ForBehaviorWithPrefix(const gd::String &prefix_, size_t replacementStartPosition_, size_t replacementEndPosition_, const gd::String &objectName_)
Create a completion for a behavior with the given prefix, for the specified object.
Definition: ExpressionCompletionFinder.h:62
bool HasParameterMetadata() const
Check if the completion is about a parameter of a function call.
Definition: ExpressionCompletionFinder.h:265
ExpressionCompletionDescription & SetIsLastParameter(bool isLastParameter_)
Set if the expression is the last child of a function call.
Definition: ExpressionCompletionFinder.h:242
const gd::ObjectConfiguration & GetObjectConfiguration() const
Return the parameter metadata, if the completion is about a object. Returns an empty configuration ot...
Definition: ExpressionCompletionFinder.h:299
CompletionKind
Definition: ExpressionCompletionFinder.h:48
size_t GetReplacementStartPosition() const
Return the first character index of the autocompleted part.
Definition: ExpressionCompletionFinder.h:230
const gd::String & GetBehaviorName() const
Return the behavior name, if completing an object behavior expression.
Definition: ExpressionCompletionFinder.h:202
gd::Variable::Type GetVariableType() const
Return the type of the variable, for a variable completion.
Definition: ExpressionCompletionFinder.h:141
size_t GetReplacementEndPosition() const
Return the first character index after the autocompleted part.
Definition: ExpressionCompletionFinder.h:237
static ExpressionCompletionDescription ForTextWithPrefix(const gd::String &type_, const gd::ParameterMetadata &parameterMetadata_, const gd::String &prefix_, size_t replacementStartPosition_, size_t replacementEndPosition_, const bool isLastParameter_, const gd::String &objectName_="")
Create a completion for a text with the given prefix.
Definition: ExpressionCompletionFinder.h:77
CompletionKind GetCompletionKind() const
Return the kind of the completion.
Definition: ExpressionCompletionFinder.h:125
const gd::String & GetType() const
Return the type of the completion (same type as types supported in expressions). For properties,...
Definition: ExpressionCompletionFinder.h:131
ExpressionCompletionDescription & SetIsExact(bool isExact_)
Set if the completion description is exact, i.e: it's not used to complete anything....
Definition: ExpressionCompletionFinder.h:215
bool HasObjectConfiguration() const
Check if the completion is about an object.
Definition: ExpressionCompletionFinder.h:291
static ExpressionCompletionDescription ForExpressionWithPrefix(const gd::String &type_, const gd::String &prefix_, size_t replacementStartPosition_, size_t replacementEndPosition_, const gd::String &objectName_="", const gd::String &behaviorName_="")
Create a completion for an expression (free, object or behavior expression) with the given prefix.
Definition: ExpressionCompletionFinder.h:99
const gd::ParameterMetadata & GetParameterMetadata() const
Return the parameter metadata, if the completion is about a parameter of a function call....
Definition: ExpressionCompletionFinder.h:273
bool IsLastParameter() const
Check if the expression is the last child of a function call.
Definition: ExpressionCompletionFinder.h:250
The base node, from which all nodes in the tree of an expression inherits from.
Definition: ExpressionParser2Node.h:101