Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy paste multiple nodes #10194

Merged
merged 32 commits into from
Jun 11, 2024
Merged

Conversation

vitvakatu
Copy link
Contributor

Pull Request Description

Closes #9424

copy.paste.multiple.mp4

Important Notes

Checklist

Please ensure that the following checklist has been satisfied before submitting the PR:

  • The documentation has been updated, if necessary.
  • Screenshots/screencasts have been attached, if there are any visual changes. For interactive or animated visual changes, a screencast is preferred.
  • All code follows the
    Scala,
    Java,
    TypeScript,
    and
    Rust
    style guides. In case you are using a language not listed above, follow the Rust style guide.
  • Unit tests have been written where possible.

@vitvakatu vitvakatu added CI: No changelog needed Do not require a changelog entry for this PR. -gui labels Jun 6, 2024
@vitvakatu vitvakatu self-assigned this Jun 6, 2024
) {
/** Copy the content of the selected node to the clipboard. */
function copySelectionToClipboard() {
const nodes = new Array<Node>()
for (const id of toValue(selected)) {
const edit = graphStore.startEdit()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

startEdit is a somewhat expensive operation that should only be needed for editing. pickInCodeOrder could use the current syncModule by default, so that snapshotting the module here is not required.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding was that starting editing is cheap, but applying changes is expensive. Unfortunately, we don’t have any documentation where it will be explained.

Removed the usage of the mutable module here in favor of syncModule inside of pickInCodeOrder.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does have some cost--it has to copy the state of the module.

/** Iterate over code lines, return node IDs from `ids` set in the order of code positions. */
function pickInCodeOrder(edit: MutableModule, ids: Set<NodeId>): NodeId[] {
const result: NodeId[] = []
const body = edit.getVersion(unwrap(getExecutedMethodAst(edit))).bodyAsBlock()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not clear from the name or documentation why this function mutates the body.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, it does not. bodyAsBlock is not available for immutable Ast, so I hope current implementation is correct. Could you please take a look at it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bodyAsBlock does mutate--if the body is inline, it converts it to a single-line block. When a MutableBodyBlock isn't needed, there's a different helper for iterating the expressions of a function--suggested in the new review.

pattern: IdentifierOrOperatorIdentifier,
to: IdentifierOrOperatorIdentifier,
) {
const expr = module.getVersion(expression) ?? expression
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a strange fallback. Why not accept expression as a MutableAst and then use expression.module to get the module?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it was copied from substituteQualifiedName nearby. Fixed both methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kazcw please take a look at my usage of mutableChild in this module. I didn’t find better way of getting mutable ast from children().

Copy link
Contributor

@kazcw kazcw Jun 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That works. Alternatively MutableAst could define a mutableChildren that works by casting the iterator returned by children (the MutableAst knows that its module is a MutableModule, and all children of a mutable module are mutable).

app/gui2/src/util/ast/abstract.ts Outdated Show resolved Hide resolved
app/gui2/src/util/ast/abstract.ts Outdated Show resolved Hide resolved
app/gui2/src/composables/nodeCreation.ts Outdated Show resolved Hide resolved
app/gui2/src/composables/nodeCreation.ts Outdated Show resolved Hide resolved
@vitvakatu vitvakatu removed the CI: No changelog needed Do not require a changelog entry for this PR. label Jun 7, 2024
@vitvakatu vitvakatu requested a review from kazcw June 7, 2024 12:39
} else if (expr instanceof PropertyAccess && expr.lhs instanceof Ident) {
if (expr instanceof MutableIdent && expr.code() === pattern) {
expr.setToken(to)
} else if (expr instanceof MutablePropertyAccess && expr.lhs != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The != null check should be inside the instanceof PropertyAccess conditional--a PropertyAccess can be an operator section like .foo and we still shouldn't change the RHS (needs another test).

function pickInCodeOrder(ids: Set<NodeId>): NodeId[] {
assert(syncModule.value != null)
const func = unwrap(getExecutedMethodAst(syncModule.value))
const lines = func.body instanceof Ast.BodyBlock ? func.body.lines : []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function has bodyExpressions that does the right thing if the function is single-line.

/** Iterate over code lines, return node IDs from `ids` set in the order of code positions. */
function pickInCodeOrder(edit: MutableModule, ids: Set<NodeId>): NodeId[] {
const result: NodeId[] = []
const body = edit.getVersion(unwrap(getExecutedMethodAst(edit))).bodyAsBlock()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bodyAsBlock does mutate--if the body is inline, it converts it to a single-line block. When a MutableBodyBlock isn't needed, there's a different helper for iterating the expressions of a function--suggested in the new review.

@vitvakatu vitvakatu added the CI: Ready to merge This PR is eligible for automatic merge label Jun 10, 2024
@mergify mergify bot merged commit e502023 into develop Jun 11, 2024
36 checks passed
@mergify mergify bot deleted the wip/vitvakatu/copy-paste-multiple-nodes branch June 11, 2024 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
-gui CI: Ready to merge This PR is eligible for automatic merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Copy/Paste mutiple components
2 participants