Class KotlinRewriter

java.lang.Object
com.vaadin.copilot.kotlinrewriter.KotlinRewriter
All Implemented Interfaces:
CopilotRewriter<KotlinComponentInfo>

public class KotlinRewriter extends Object implements CopilotRewriter<KotlinComponentInfo>
Rewrites Kotlin view source in response to visual editing.

Only the property operations are implemented: set-component-property and the read that can-be-edited needs. Every other operation throws, and SourceLanguageCapabilities says so, so the frontend disables those actions rather than offering something that fails. Operations move in here and into that capability set together.

Edits are spliced at character offsets rather than printed from a mutated tree: the tree is read-only by design (see KotlinSource), and the practical consequence is the one that matters to a developer — a file Copilot edits comes back byte-identical except on the lines the edit needed.

  • Constructor Details

    • KotlinRewriter

      public KotlinRewriter()
  • Method Details

    • replaceFunctionCall

      public ReplaceResult replaceFunctionCall(KotlinComponentInfo component, String function, Object value)
      Sets a property, replacing the value the source already states or adding a statement where it states none.

      Two behaviours here differ from the Java implementation, both deliberately:

      • An explicit set is preferred over a constructor argument when the source has both. Java replaces the constructor argument first, which for Button("A") followed by button.text = "B" edits the argument and leaves the assignment still winning at runtime — so the panel appears to discard the edit. Editing whatever the panel is showing is the only self-consistent choice, and the panel shows the last set.
      • The variable is never renamed. Java regenerates an auto-generated name from the new text, which means renaming every reference to it; that belongs with the operation that creates auto-generated names in the first place.
      Specified by:
      replaceFunctionCall in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to modify
      function - the setter name
      value - the new value, or null to remove the call
      Returns:
      a result that never carries a rename, per the note above
    • removePropertySetter

      public void removePropertySetter(KotlinComponentInfo component, String setter)
      Description copied from interface: CopilotRewriter
      Removes a property setter call from the component.
      Specified by:
      removePropertySetter in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to modify
      setter - the setter name
    • getPropertyValue

      public Object getPropertyValue(KotlinComponentInfo component, String property)
      Description copied from interface: CopilotRewriter
      Reads a property's value from the source.
      Specified by:
      getPropertyValue in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to read
      property - the property name
      Returns:
      a constant value where the source holds one, otherwise a SourceExpression for something that has to be evaluated, or null if the property is not set
    • addCall

      public void addCall(KotlinComponentInfo component, String function, Object... parameters)
      Still refused, and not because writing a call is hard.

      The only thing that sends add-call is "add event listener", and the parameter it sends is a Java lambda — ComponentEventCollector hands the frontend the template e -> {} — which is not Kotlin syntax. Writing it verbatim would put code in the file that does not compile; the Kotlin idiom is a trailing lambda, sayHello.addClickListener { }. That is a translation problem rather than a value-writing one, so it belongs with its own tests rather than inside the styles work.

      Specified by:
      addCall in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to modify
      function - the method to call
      parameters - the arguments
    • addArguments

      public void addArguments(KotlinComponentInfo component, String function, List<String> arguments)
      Adds arguments to a call, creating it if the component has none.

      For the Lumo paths, which express a badge as class names: name.addClassNames(LumoUtility.Gap.MEDIUM). Arguments already present are left as they are, so a developer's own class names survive.

      Parameters:
      component - the component to add them to
      function - the call's name, as the source spells it
      arguments - the arguments as source text, already rendered and importable
    • removeArguments

      public void removeArguments(KotlinComponentInfo component, String function, Set<String> argumentTexts)
      Removes arguments from a call, and the call with them when nothing is left.

      The counterpart of adding: a badge takes away the class names it owns before writing the new ones, and a addClassNames() with no arguments left is not something to leave behind.

      Parameters:
      component - the component
      function - the call's name
      argumentTexts - the argument spellings to drop, matched as written
    • setArguments

      public void setArguments(KotlinComponentInfo component, String function, Set<String> removing, List<String> adding)
      Takes some arguments out of a call and puts others in, as one edit.

      The operation the badges actually perform: a badge clears the utility class it owns and writes the new one, and doing that as removeArguments followed by addArguments cannot work — the PSI is read-only and never reflects an edit already recorded, so the second call reads the original arguments and records a second replacement of the same range. TextEditBuffer then rejects the pair as overlapping, and had it not, the second edit would have put the removed argument back. Raised in review of #9653, where the two were separate primitives and the documented workflow combined them.

      Arguments are planned for every matching call before any edit is recorded, so a refusal leaves the source untouched. Removal applies to every call of that name; addition goes to the last one, or writes a new call when there is none.

      Parameters:
      component - the component the call is made on
      function - the call's name, as the source spells it
      removing - argument spellings to drop, matched as written
      adding - arguments to add, as source text; one already present is left where it is rather than repeated
    • replaceOrAddCall

      public void replaceOrAddCall(KotlinComponentInfo component, String function, Object... parameters)
      Replaces the arguments of an existing call, or writes the call if there is none.

      Unlike replaceFunctionCall(com.vaadin.copilot.kotlinrewriter.KotlinComponentInfo, java.lang.String, java.lang.Object), which is property-shaped and resolves a JavaBean name, this takes the function as the source spells it. The badge commands need that: setSpacing(false) is a call to make, not a property to set, and the component may not even have a spacing property of the right type.

      The last existing call is the one replaced, for the reason reading a property takes the last declaration: it is the one in effect.

      Specified by:
      replaceOrAddCall in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to modify
      function - the method to call
      parameters - the arguments
    • removeCalls

      public void removeCalls(KotlinComponentInfo component, String function)
      Removes every call of this name made on the component.

      Every one rather than the last: the callers are removals, and Java's gap path deletes any setSpacing statement it finds. Leaving a second in place would let it take effect instead of the change just made.

      Specified by:
      removeCalls in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to modify
      function - the method name
    • setStyles

      public void setStyles(KotlinComponentInfo component, Map<String,String> changes)
      Applies a whole set of style changes in one pass.

      Not a convenience over calling setStyle(com.vaadin.copilot.kotlinrewriter.KotlinComponentInfo, java.lang.String, java.lang.String) repeatedly: the removals have to be decided together. Each is an offset splice, and whether a statement should be deleted outright depends on whether anything on it survives the set — clearing both styles of style.setColor("blue").setFontSize("12px") one at a time would splice out each call and leave a bare sayHello.style behind.

      Parameters:
      component - the component to restyle
      changes - CSS properties, dash-separated, mapped to their new values, or to null to remove them
    • setStylesClearingWhatIsThere

      public void setStylesClearingWhatIsThere(KotlinComponentInfo component, Map<String,String> changes)
      As setStyles(com.vaadin.copilot.kotlinrewriter.KotlinComponentInfo, java.util.Map<java.lang.String, java.lang.String>), but a property that is not set is simply not there.

      For the callers that clear a group before writing it. The badge commands start by taking away every style they own — alignment clears seven properties, gap and padding everything matching their prefixes — and they do that without first asking which of them the source happens to set. Refusing would make the first use of a badge on an unstyled component an error.

      setStyles(com.vaadin.copilot.kotlinrewriter.KotlinComponentInfo, java.util.Map<java.lang.String, java.lang.String>) keeps refusing, because for the inspector it is the right answer: it sends a removal per rule it dropped, and reporting success for a style that was never there would hide a disagreement about which styles the component has.

      Parameters:
      component - the component to restyle
      changes - property to value, with null to clear it if it is set
    • setStyle

      public void setStyle(KotlinComponentInfo component, String property, String value)
      Description copied from interface: CopilotRewriter
      Sets an inline style, or the equivalent utility class when the app uses Lumo.
      Specified by:
      setStyle in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to modify
      property - the CSS property
      value - the CSS value
    • setSizing

      public void setSizing(KotlinComponentInfo component, Map<String,String> changes)
      Description copied from interface: CopilotRewriter
      Sets width and height related properties.
      Specified by:
      setSizing in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to modify
      changes - the properties to set, by name
    • setAlignment

      public void setAlignment(KotlinComponentInfo component, AlignmentValues alignmentValues)
      Description copied from interface: CopilotRewriter
      Sets the component's flexbox alignment properties.
      Specified by:
      setAlignment in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to modify
      alignmentValues - the alignment to apply
    • setGap

      public void setGap(KotlinComponentInfo component, String all, String column, String row)
      Description copied from interface: CopilotRewriter
      Sets the gap between a layout's children.
      Specified by:
      setGap in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the layout to modify
      all - the gap on both axes, or null to set them separately
      column - the column gap
      row - the row gap
    • setPadding

      public void setPadding(KotlinComponentInfo component, String all, String top, String right, String bottom, String left)
      Description copied from interface: CopilotRewriter
      Sets a component's padding.
      Specified by:
      setPadding in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to modify
      all - the padding on all sides, or null to set them separately
      top - the top padding
      right - the right padding
      bottom - the bottom padding
      left - the left padding
    • delete

      public boolean delete(KotlinComponentInfo component)
      Description copied from interface: CopilotRewriter
      Deletes the component, along with the code that only existed to support it.
      Specified by:
      delete in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to delete
      Returns:
      true if the component was deleted
    • moveComponent

      public void moveComponent(KotlinComponentInfo component, KotlinComponentInfo container, KotlinComponentInfo reference, Where where, MoveTemplateOptions options)
      Description copied from interface: CopilotRewriter
      Moves a component into a container, relative to a reference component.
      Specified by:
      moveComponent in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to move
      container - the container to move it into
      reference - the sibling to position against, or null to append
      where - the position relative to the reference
      options - the attach method and add-or-replace behaviour
    • duplicate

      public void duplicate(KotlinComponentInfo component, List<KotlinComponentInfo> children)
      Description copied from interface: CopilotRewriter
      Duplicates a component together with the given children.
      Specified by:
      duplicate in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to duplicate
      children - the children to duplicate with it
    • addComponentUsingTemplate

      public List<KotlinComponentInfo> addComponentUsingTemplate(KotlinComponentInfo referenceComponent, Where where, List<CopilotComponent> template, AddTemplateOptions options)
      Description copied from interface: CopilotRewriter
      Adds components described by a template, as sent when dropping from the palette, pasting, or importing a design.
      Specified by:
      addComponentUsingTemplate in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      referenceComponent - the component to position against
      where - the position relative to the reference
      template - the components to create
      options - how to declare and attach them
      Returns:
      the components that were created
    • mergeAndReplace

      public void mergeAndReplace(List<KotlinComponentInfo> components, CopilotComponent wrapperComponent)
      Description copied from interface: CopilotRewriter
      Wraps the given components in a new container.
      Specified by:
      mergeAndReplace in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      components - the components to wrap
      wrapperComponent - the container to wrap them in
    • extractComponent

      public String extractComponent(KotlinComponentInfo component, IdentityHashMap<KotlinComponentInfo,List<KotlinComponentInfo>> componentChildren, String extractedComponentClassNameSuggestion)
      Description copied from interface: CopilotRewriter
      Extracts a component and its children into a class of their own.
      Specified by:
      extractComponent in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to extract
      componentChildren - the children of each component, keyed by identity because these handles can be records whose equality changes as the source is rewritten
      extractedComponentClassNameSuggestion - the suggested class name
      Returns:
      the name of the class that was created
    • addConstructorParameterToClass

      public String addConstructorParameterToClass(KotlinComponentInfo referenceComponent, String parameterTypeName, String suggestedParameterName, boolean storeAsField)
      Description copied from interface: CopilotRewriter
      Adds a constructor parameter to the class the component is declared in, for injecting a service.
      Specified by:
      addConstructorParameterToClass in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      referenceComponent - a component in the target class
      parameterTypeName - the parameter's type
      suggestedParameterName - the suggested parameter name
      storeAsField - whether to also store the parameter in a field
      Returns:
      the parameter name that was used
    • addComment

      public void addComment(KotlinComponentInfo component, String comment, CommentType commentType)
      Description copied from interface: CopilotRewriter
      Adds a comment next to the component.
      Specified by:
      addComment in interface CopilotRewriter<KotlinComponentInfo>
      Parameters:
      component - the component to comment on
      comment - the comment text
      commentType - whether to write a line or block comment