Add generic go-to-definition for file path strings in BRS/BS/XML files#1648
Add generic go-to-definition for file path strings in BRS/BS/XML files#1648
Conversation
Co-authored-by: TwitchBronBron <2544493+TwitchBronBron@users.noreply.github.com>
|
Hey there! I just built a new temporary npm package based on 072beff. You can download it here or install it by running the following command: npm install https://github.com/rokucommunity/brighterscript/releases/download/v0.0.0-packages/brighterscript-0.70.3-copilot-add-go-to-definition-for-script-uri.20260319190736.tgz |
TwitchBronBron
left a comment
There was a problem hiding this comment.
So, for some reason, when I ctrl+hover over the paths, it breaks components, scene, mainscene.brs into separate chunks. any way to mak ethe whole thing a single clickable? Why's it doing that in vscode? Is that under our control? Please fix
|
Hey there! I just built a new temporary npm package based on f6d9243. You can download it here or install it by running the following command: npm install https://github.com/rokucommunity/brighterscript/releases/download/v0.0.0-packages/brighterscript-0.70.3-copilot-add-go-to-definition-for-script-uri.20260319194507.tgz |
Co-authored-by: TwitchBronBron <2544493+TwitchBronBron@users.noreply.github.com>
The path-segment splitting was caused by VS Code's word boundary detection for XML files — when showing the underline for a ctrl+click target, VS Code splits on Fixed in commit |
|
Hey there! I just built a new temporary npm package based on 97b0f09. You can download it here or install it by running the following command: npm install https://github.com/rokucommunity/brighterscript/releases/download/v0.0.0-packages/brighterscript-0.70.3-copilot-add-go-to-definition-for-script-uri.20260319195550.tgz |
TwitchBronBron
left a comment
There was a problem hiding this comment.
Looking better. A few thoughts. I'd like to make this a contributable bsc plugin hook. With the before, provide, after hooks. Similar to other events.
Also, in my typescript projects their clickable import path links are only underlined when I hold ctrl. But these links you're contributing are underlined all the time. Is there a different way of contributing them?
…y underline Co-authored-by: TwitchBronBron <2544493+TwitchBronBron@users.noreply.github.com>
Both addressed in commit Plugin hooks: Added Ctrl-only underline: Removed the LSP |
|
Hey there! I just built a new temporary npm package based on 2a9130a. You can download it here or install it by running the following command: npm install https://github.com/rokucommunity/brighterscript/releases/download/v0.0.0-packages/brighterscript-0.70.3-copilot-add-go-to-definition-for-script-uri.20260320125752.tgz |
TwitchBronBron
left a comment
There was a problem hiding this comment.
What are the reasons for keeping the DocumentLinksProvider if the DefinitionProvider is already handling this? I'd rather let definition provider contribute the links if we can? Can we fully accomplish the ctrl hover feature without actually needing document link provider? (but still keeping the full hover instead of the segmented chunks like i complained about earlier)
TwitchBronBron
left a comment
There was a problem hiding this comment.
Okay. So, now let's make this more flexible. I want it to do the following. Since the DefinitionProvider reacts to a specific file AND position, you should able to handle ANY file path from any ast element. xml, attribute, brs ast, etc.
So when you get the request, look at the item under the cursor. Build a file path for it (i.e. if it's relative, base that on relative to current file), if it's absolute, base that on the pkgPath (or destPath) of the project, handling pkg:/ and libpkg and all the other stuff we already talked about.
This way, we are very generic, as long as it looks like a path, it's clickable. then it doesn't matter what ast it lives in. support this for brs bs and xml files. ensure you've added tests for these use cases.
some good examples are:
poster = createObject('roSGNode", "PosteR")
poster.uri = "./relative/path.jpg"
poster.uri = "pkg:/images/image.jpg"
then xml nodes like Poster who have a uri field, and the Scene node backgroundURI, etc.
… XML attribute values Co-authored-by: TwitchBronBron <2544493+TwitchBronBron@users.noreply.github.com> Agent-Logs-Url: https://github.com/rokucommunity/brighterscript/sessions/d4d2b757-f74c-4e91-9fc0-3b8bcfa0128b
…ix attribute array type Co-authored-by: TwitchBronBron <2544493+TwitchBronBron@users.noreply.github.com> Agent-Logs-Url: https://github.com/rokucommunity/brighterscript/sessions/d4d2b757-f74c-4e91-9fc0-3b8bcfa0128b
Done in commit The BRS/BS files — any XML files — every attribute value across the entire component tree (component-level, Tests cover: |
TwitchBronBron
left a comment
There was a problem hiding this comment.
Make sure you have good handling for when the AST is mangled. we don't want the request failing. So be safe about it.
| private tryGetFilePathLocationLink(pathStr: string, containingFilePkgPath: string, originRange: Range): LocationLink | null { | ||
| // Require a recognised path prefix so we don't accidentally match arbitrary strings | ||
| // (e.g. component names in createObject calls). | ||
| if (!/^(?:pkg:|libpkg:|\.\/|\.\.\/)/i.test(pathStr)) { |
There was a problem hiding this comment.
What about something like uri="MyImage.jpg"? Not sure we can just assume it'll start with one of these. It's probably safe to just build the pkgPath no matter what and verify there's a file with that exact name.
You should also consider files that don't have extensions. For example uri="MyImageWIthoutExt" would work too.
There was a problem hiding this comment.
Done in 693de41. Removed the prefix restriction from tryGetFilePathLocationLink — any non-empty string is now resolved via util.getPkgPathFromTarget and checked against the program's file index. This means uri="MyImage.jpg" (bare name, with or without extension) works. Non-matching strings like "Poster" safely return no result since no file is found. Tests for bare-filename resolution are included.
… add bare-filename tests Co-authored-by: TwitchBronBron <2544493+TwitchBronBron@users.noreply.github.com> Agent-Logs-Url: https://github.com/rokucommunity/brighterscript/sessions/9b2d1051-87c4-45b6-9154-a7e689bd463b
Done in |
|
Hey there! I just built a new temporary npm package based on 7327f93. You can download it here or install it by running the following command: npm install https://github.com/rokucommunity/brighterscript/releases/download/v0.0.0-packages/brighterscript-0.70.3-copilot-add-go-to-definition-for-script-uri.20260320190031.tgz |
TwitchBronBron
left a comment
There was a problem hiding this comment.
have a few more issues to resolve.
- for files that don't exist, it's still building individual segments. And then opening a file? But i would expect the entire link to be clickable, or not clickable at all.

- this doesn't work for images right now, because images aren't actually loaded into brighterscript (by design). So, i'd like you to do the following: 1 if file is loaded in the program (brs/xml/bs...but don't check for extension), then we have the file. if file not loaded into the program, then grab the Program.options.files array, and build a full path of our file based on the dest patterns, and walk through them using rokudeploy to figure out whether that file WOULD match the files array. if yes, then look on disk for the file. but if not match the files array, then do NOT turn it into a link.
…efactor XML attr handler Co-authored-by: TwitchBronBron <2544493+TwitchBronBron@users.noreply.github.com> Agent-Logs-Url: https://github.com/rokucommunity/brighterscript/sessions/378b0bc4-7f8c-443a-9ec5-67c8362244ff
Done in Segmented-hover for non-existent files: Images and other assets: if the file matches the project's Also refactored |
| if (rootDir && files?.length) { | ||
| const srcPath = path.join(rootDir, pkgPath); | ||
| if ( | ||
| rokuDeploy.getDestPath(srcPath, files, rootDir) !== undefined && |
There was a problem hiding this comment.
So, this might not actually be accurate. the srcPath you've created here is actually the destPath of the theoretical image. We need to realistically convert this theoretical destPath of the item back into its srcPath and THEN determine if that file exists. rokuDeploy may not have this functionality, but would be good to look through it.
Also, we can approximate as well. you could look through the {src, dest} objects and do a rough reverse translation to see what src path the file MIGHT be in. I just want to make sure we're not hitting the disk for files that wouldn't initially match. That's expensive for "get defintion" requests.
There was a problem hiding this comment.
Done in dbb9f60. The disk lookup is now a proper reverse-translation:
-
reverseLookupSrcPathtranslates a pkg dest path back to a candidate src path per entry — for string entries it'srootDir + pkgPath, for{ src, dest }entries with globstar it strips thedestprefix and prepends the src glob base (e.g.,{ src: 'assets/**', dest: 'images' }+pkgPath='images/hero.png'→ candidate =rootDir/assets/hero.png). -
Verify before hitting disk: each candidate is passed to
rokuDeploy.getDestPathfirst (pure path computation, no disk I/O). Only if the returned dest matches our expectedpkgPathexactly do we callfsExtra.existsSync. This ensures we never do a disk read for a candidate that wouldn't match.
Added test: remapped { src: 'assets/**', dest: 'images' } with pkg:/images/hero.png correctly resolves to rootDir/assets/hero.png on disk.
…fy before hitting disk Co-authored-by: TwitchBronBron <2544493+TwitchBronBron@users.noreply.github.com> Agent-Logs-Url: https://github.com/rokucommunity/brighterscript/sessions/23c7d943-1957-4a69-b8c1-ed6e72dcb640
|
Hey there! I just built a new temporary npm package based on dbb9f60. You can download it here or install it by running the following command: npm install https://github.com/rokucommunity/brighterscript/releases/download/v0.0.0-packages/brighterscript-0.70.3-copilot-add-go-to-definition-for-script-uri.20260320201719.tgz |
Ctrl+clicking a
uriattribute value in an XML<script>tag did not navigate to the referenced file, unlikeimportstatements in.bsfiles which already supported this. Additionally, VS Code was splitting the URI path on/separators on Ctrl+hover, making each path segment a separate underlined chunk instead of the whole URI being a single link.This has been extended into a fully generic file-path go-to-definition feature: any string that resolves to a known file — in any AST node across
.brs,.bs, and.xmlfiles — is now clickable, including image and asset files not loaded into the BrighterScript program.Changes
DefinitionProvider.ts:tryGetFilePathLocationLinkhelper with a multi-step file resolution strategy:util.getPkgPathFromTargetand checksprogram.getFile()— covers.brs/.bs/.xmlcode files. No path prefix (pkg:/,./, etc.) is required.filesdeploy entries and usesreverseLookupSrcPathto translate each entry's dest path back to a candidate src path (handling globstar patterns and dest remaps such as{ src: 'assets/**', dest: 'images' }). Each candidate is verified withrokuDeploy.getDestPath(pure path computation, no disk I/O) beforefsExtra.existsSyncis called — ensuring disk access only happens for paths that would actually match the deploy pattern. If no verified candidate exists on disk,nullis returned so VS Code gets noLocationLinkand does not show a segmented hover.findSrcPathForPkgPathhelper that drives the reverse-mapping loop.reverseLookupSrcPathhelper that per-entry translates a pkg dest path to a candidate src path: string entries map torootDir + pkgPath;{ src, dest }entries with a globstar strip thedestprefix and prepend the glob base directory.process()in a try-catch so errors from mangled or partially-parsed ASTs are swallowed rather than surfacing to the LSP client.brsFileGetDefinition(): after handlingimportstatements, anyStringLiteraltoken is tried as a file path — if it resolves to a known file (in-program or on disk), go-to-definition navigates there.xmlGetFilePathDefinitionFromAttributes+xmlWalkNodeForFilePath) that walks the entire component tree.xmlGetFilePathDefinitionFromAttributesdelegates totryGetFilePathLocationLinkso both BRS/BS and XML paths share the same resolution logic.LocationLinkobjects includeoriginSelectionRangeset to the full path (excluding quotes), so VS Code underlines the entire URI as a single unit on Ctrl+hover rather than splitting on/separators.interfaces.ts: WidenedProvideDefinitionEvent.definitionsfromLocation[]toArray<Location | LocationLink>so plugins can contributeLocationLinkobjects with full control over highlight ranges.Scope.ts/XmlScope.ts/BrsFile.ts: Updated deprecatedgetDefinitionreturn types toArray<Location | LocationLink>.DefinitionProvider.spec.ts: Added tests for BRSpkg:/,./,../, and bare-name path detection; negative case for non-existent file strings; XML child-nodeuri,backgroundURI, and relative./attributes; mangled BRS and XML AST safety; disk-based image asset lookup for both BRS string literals and XML attributes (hit and miss cases); dest-remapped asset lookup ({ src: 'assets/**', dest: 'images' }correctly resolvespkg:/images/hero.pngto the physicalassets/hero.png).Examples
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.