Fix IncorrectOperationException and support smart URI rewriting on file move#178
Open
danteay wants to merge 11 commits into
Open
Fix IncorrectOperationException and support smart URI rewriting on file move#178danteay wants to merge 11 commits into
danteay wants to merge 11 commits into
Conversation
When a referenced file is moved via IntelliJ's refactoring, the engine calls bindToElement on all references resolving to that file. PsiReferenceBase throws IncorrectOperationException by default. Implement bindToElement to recompute relative-path and file: URIs to the target's new location; other schemes (pkl:, package:, https:, modulepath:) are not affected by file moves. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When bindToElement is called for a file move and the importing file lives outside the PKL project that owns the moved file, rewrite the import as @<depName>/<path-from-project-root> if the source project declares the target's project as a local dependency. Falls back to a plain relative path when no matching dependency is found or both files share the same PKL project. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three fixes to computeNewRelativeUri: - Use enclosingModule.dependencies() as the primary dependency source so that files inside PKL packages (isInPackage=true) are handled correctly, not just files in local projects. - Fall back to iterating pklProjects.values by URL when module dependencies are unavailable, rather than relying on getPklProject(dir) key lookup which can silently miss projects. - Compare dependency roots by VirtualFile.url (string) instead of VirtualFile identity (==) to avoid mismatches from path-canonicalization differences. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When a file is moved across PKL project boundaries and the source project has not yet declared the target project as a dependency, fall back to the target project's own package name (derived from its packageUri) to build the @<name>/<relPath> import. This produces the correct import format even before the user adds the dependency declaration to their PklProject. Strategy order: 1. Look up a matching declared dependency in the source module (existing) 2. Find target project's package name via pklProjectService packageUri.path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ss projects
When a file is moved into a PKL project whose packageUri has a name (e.g.
"tests"), and the source PklProject does not yet declare that project as a
dependency, automatically insert the dependency entry into the source
PklProject file and use @<name>/<relPath> as the new import URI.
Behaviour summary:
- Strategy 1 (already declared dep): find by root URL match → @name/path, no file change
- Strategy 2 (undeclared dep): derive name from target packageUri, write
["name"] = import("rel/path/PklProject") into source PklProject (skipped
if entry already present), return @name/path
- Relative path fallback: only when either side has no PklProject ancestor
- null (import unchanged): both sides have PklProjects but target has no
packageUri so no dep name can be determined
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When moving a Pkl file across project boundaries causes a new dependency entry to be written into the source PklProject file, automatically schedule `syncProjects()` (pkl project resolve → PklProject.deps.json) via invokeLater so the IDE picks up the new dep without a manual Sync click. A project-level Key flag deduplicates multiple sync requests that can arise when several references are updated in a single refactoring pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After syncProjects() updates pklProjects, IntelliJ's daemon does not automatically re-run annotators because custom ModificationTracker changes do not trigger daemon restarts. This left @dep/path imports showing "unresolved" warnings in open editors even after the sync had fully resolved the new dependency. Add a DaemonCodeAnalyzer.restart() call via invokeLater at the end of syncProjects() so all open editors re-evaluate their import highlights once the updated project state is available. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All PsiReferenceBase subclasses that don't handle file moves threw IncorrectOperationException from the default bindToElement when a move refactoring was performed (e.g. PklUnqualifiedAccessReference, PklSuperAccessReference, PklModuleNameReference, PklSimpleTypeNameReference, PklModuleReference). Add a no-op override that returns the element unchanged, so the refactoring engine can proceed without crashing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract three focused private methods from the monolithic addDependencyToPklProject and computeNewRelativeUri: - findDeclaredDepName: encapsulates strategy-1 dep lookup - findTargetPackageName: encapsulates strategy-2 package name derivation - scheduleSyncIfNeeded: isolates the dedup + invokeLater sync scheduling computeNewRelativeUri now reads as a clear two-strategy decision tree. addDependencyToPklProject is purely about editing the PklProject document. No behavior changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Update copyright year to 2024-2026 and reformat code to satisfy the project's spotless/ktfmt style checker. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove redundant inline comments added in the move-refactoring commits that restate what the code already expresses clearly. Preserve all pre-existing comments. Remove @throws annotations and now-unused IncorrectOperationException imports from the no-op bindToElement overrides. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
08b98e3 to
05ebdeb
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Fix a series of crashes and missing behaviors triggered when moving
.pklfiles via IntelliJ's refactoring engine (drag-and-drop orRefactor > Move).
Why
The default
PsiReferenceBase.bindToElementunconditionally throwsIncorrectOperationException. Because every Pkl reference class(
PklModuleUriReference,PklUnqualifiedAccessReference,PklSuperAccessReference,PklModuleNameReference,PklSimpleTypeNameReference,PklModuleReference) inherits thisdefault, any file move that touched a Pkl source file would crash the
refactoring processor.
Beyond stopping the crash, moves across PKL project boundaries need
special URI handling: a plain relative path would be wrong once the
file lands in a different project, so the URI must use the
@<depName>/<path>project-dependency format instead.Changes
Stop the crash
bindToElementon all sixPsiReferenceBasesubclasses.elementunchanged — these references are unaffected by file location.
PklModuleUriReferencegets a full implementation (see below).Smart URI rewriting in
PklModuleUriReference.bindToElementfile:URIs → replaced with the new absolute VFS URL.path from the new source location.
dependency, rewrite as
@<depName>/<path-from-dep-root>.packageUri(e.g.package://localhost:0/tests@1.0.0→"tests"), insert a new["tests"] = import("…/PklProject")entry into the source
PklProjectfile, and rewrite as@tests/<path>.PklProjectancestor, fall back to aplain relative path.
pkl:,package:,https:,modulepath:) are left unchanged.pklProjectService.syncProjects()viainvokeLatersoPklProject.deps.jsonis regenerated without requiring a manualSync click. A project-level flag deduplicates multiple syncs when
several references are updated in one refactoring pass.
Refresh highlights after sync
DaemonCodeAnalyzer.restart()(viainvokeLater) at the end ofPklProjectService.syncProjects(). Without this,@dep/pathimports kept showing "unresolved" warnings in open editors even after
the sync had fully populated the new dependency, because incrementing
a custom
ModificationTrackerdoes not automatically re-triggerIntelliJ's daemon code analyzer.
Checklist
./gradlew build)