Vscode ca65 intellisense extension
-
hobbett
- Posts: 11
- Joined: Thu Sep 04, 2025 10:33 pm
Re: Vscode ca65 intellisense extension
BTW, I noticed the smb3 project uses a lot of imported symbols without declaring them as imports. I've added a setting in 1.5.1 called `ca65.implicitImports` that enables the ca65 `--auto-import` flag for diagnostics and treats not-yet-imported symbols as already-imported in the autocompletion. Hopefully you find this useful instead of having to add many import statements at the top of each file.
-
segaloco
- Posts: 911
- Joined: Fri Aug 25, 2023 11:56 am
Re: Vscode ca65 intellisense extension
Yeah I'm doing it UNIX style with the -U option on the command-line. Basically anything marked export is thrown in the global symbol table and any unidentified symbols are marked external automatically and then edited at link time. I'm not sure why this is so uncommon in 6502 but this is the norm in basically every other assembly language I've worked with.
Edit: Just one last thing, I don't know if this is related, but one thing I'm still not getting is resolution of external references:
On the right is the global definition of main, as indicated by the export, but when searching references, it doesn't list the reference in the start.s file. Furthermore, when right clicking on main in start and trying to navigate the reference, it doesn't find the exported reference in the main.s file. Not sure if this is the scenario you were referring to but at least as of right now with 1.5.1 I can't seem to navigate to an exported symbol in another assembly unit. My two cents is I would catalog all the exported symbols throughout the workspace and any symbols in the current file that cannot be resolved in its own unit (i.e. in the file or included headers) should instead refer to whatever version of that symbol was marked export.
Granted, there are three big difficulties I could see here:
1. If you have any foreign code in your workspace, say a reference copy of other code, anything like that, those files and their exports could also get swept up. I mention this because I often keep a "raw" folder in my disassembly workspace with symlinks to my other projects so I can quickly refer to other disassemblies of my own. In this case, all of that code would also be in the "workspace" technically. Since your extension isn't looking at a Makefile in the root folder, it wouldn't seem that it has a way to know what files are and are not part of the actual build.
2. It is possible to reuse an exported name locally in an assembly unit if the declaration is in scope. This will be handled at assemble time and never make it to the linker. So long as the extension does the same, seeks out local symbols first, *then* only goes to exports when a symbol hasn't been found in the current assembly unit.
3. Multiple linker units in the same project. I don't think you mentioned any linker script involvement in how your extension works, it is entirely possible a codebase is made up of several linker runs that are then concatenated together. I prefer to put all my banks in one linker script so that I do have one single global export namespace, which imo is ideal for this and other analytical matters, but I could see folks doing a script per-bank too. Granted, this makes cross-bank linkage incredibly difficult, but there are a lot of patterns I see in assembly coding that simply add work to people's lives. Either way, without knowledge of at the very least a linker script, it would be hard in a multi-script environment to both determine that there are multiple global namespaces, one per linker run, and then determine where different objects fall. Heck, however irresponsible, one could even use the same segment names across multiple link runs, meaning you can't tell alone from the file whether it belongs to link run A, B, etc. only the ld65 command-line in the Makefile would tell you that.
Either way, in light of all of that, this is simply all the more impressive of a project.
Edit: Just one last thing, I don't know if this is related, but one thing I'm still not getting is resolution of external references:
On the right is the global definition of main, as indicated by the export, but when searching references, it doesn't list the reference in the start.s file. Furthermore, when right clicking on main in start and trying to navigate the reference, it doesn't find the exported reference in the main.s file. Not sure if this is the scenario you were referring to but at least as of right now with 1.5.1 I can't seem to navigate to an exported symbol in another assembly unit. My two cents is I would catalog all the exported symbols throughout the workspace and any symbols in the current file that cannot be resolved in its own unit (i.e. in the file or included headers) should instead refer to whatever version of that symbol was marked export.
Granted, there are three big difficulties I could see here:
1. If you have any foreign code in your workspace, say a reference copy of other code, anything like that, those files and their exports could also get swept up. I mention this because I often keep a "raw" folder in my disassembly workspace with symlinks to my other projects so I can quickly refer to other disassemblies of my own. In this case, all of that code would also be in the "workspace" technically. Since your extension isn't looking at a Makefile in the root folder, it wouldn't seem that it has a way to know what files are and are not part of the actual build.
2. It is possible to reuse an exported name locally in an assembly unit if the declaration is in scope. This will be handled at assemble time and never make it to the linker. So long as the extension does the same, seeks out local symbols first, *then* only goes to exports when a symbol hasn't been found in the current assembly unit.
3. Multiple linker units in the same project. I don't think you mentioned any linker script involvement in how your extension works, it is entirely possible a codebase is made up of several linker runs that are then concatenated together. I prefer to put all my banks in one linker script so that I do have one single global export namespace, which imo is ideal for this and other analytical matters, but I could see folks doing a script per-bank too. Granted, this makes cross-bank linkage incredibly difficult, but there are a lot of patterns I see in assembly coding that simply add work to people's lives. Either way, without knowledge of at the very least a linker script, it would be hard in a multi-script environment to both determine that there are multiple global namespaces, one per linker run, and then determine where different objects fall. Heck, however irresponsible, one could even use the same segment names across multiple link runs, meaning you can't tell alone from the file whether it belongs to link run A, B, etc. only the ld65 command-line in the Makefile would tell you that.
Either way, in light of all of that, this is simply all the more impressive of a project.
You do not have the required permissions to view the files attached to this post.
-
segaloco
- Posts: 911
- Joined: Fri Aug 25, 2023 11:56 am
Re: Vscode ca65 intellisense extension
Gah and one more sorry, I don't send these to nitpick, rather I want to help make things better. I found that symbol navigation in "continued" lines seems to not work:
First one in a continuation, I get the reference.
Next one, no such luck, they're from the same enum in the same header file, only difference is I'm using the line continuation pattern to split the OR'd constants across multiple lines.
This feature is indicated by the ".linecont +" option at the top of the file. I'd generally avoid that sort of extension but I was getting tired of long lines of OR'd constants but do want constants to be in terms of symbols, not flat numbers.
First one in a continuation, I get the reference.
Next one, no such luck, they're from the same enum in the same header file, only difference is I'm using the line continuation pattern to split the OR'd constants across multiple lines.
This feature is indicated by the ".linecont +" option at the top of the file. I'd generally avoid that sort of extension but I was getting tired of long lines of OR'd constants but do want constants to be in terms of symbols, not flat numbers.
You do not have the required permissions to view the files attached to this post.
-
hobbett
- Posts: 11
- Joined: Thu Sep 04, 2025 10:33 pm
Re: Vscode ca65 intellisense extension
Thanks for the feedback! Every "nitpick" you give helps me improve it, so please don't be shy about raising any issues you come across.
I was so focused on the autocompletion portion of `implicitImports` that I totally forgot to handle the reference resolution. I've uploaded 1.5.2 to handle this, please verify if it works for you.
As for line continuations -- yeah those are totally broken for now. Unfortunately I don't think this is a trivial fix -- it'd involve a full rewrite of the parser code because as of right now, the parser is quite fragile. So it will have to go in a later 2.0 release
I was so focused on the autocompletion portion of `implicitImports` that I totally forgot to handle the reference resolution. I've uploaded 1.5.2 to handle this, please verify if it works for you.
As for line continuations -- yeah those are totally broken for now. Unfortunately I don't think this is a trivial fix -- it'd involve a full rewrite of the parser code because as of right now, the parser is quite fragile. So it will have to go in a later 2.0 release
-
segaloco
- Posts: 911
- Joined: Fri Aug 25, 2023 11:56 am
Re: Vscode ca65 intellisense extension
References are now resolving great!
Fantastic stuff, yeah no sweat on the linecont stuff, that is an extension after all, not my first choice but one made for sanity.
Fantastic stuff, yeah no sweat on the linecont stuff, that is an extension after all, not my first choice but one made for sanity.
You do not have the required permissions to view the files attached to this post.
-
hobbett
- Posts: 11
- Joined: Thu Sep 04, 2025 10:33 pm
Re: Vscode ca65 intellisense extension
Thanks for verifying! I've also uploaded 1.5.5 which adds basic support for symbol references in line continuations. This doesn't completely handle line continuations in all cases, like symbol definitions in the continuation, but hopefully it should handle the common cases like in your smb3 project.
-
segaloco
- Posts: 911
- Joined: Fri Aug 25, 2023 11:56 am
Re: Vscode ca65 intellisense extension
Here's a new one: The cheap local label indicators appear to get stuck if such a reference is on the same line as such a label. For example:
In this case, you'll notice that on the line with cheap local label L157, this line contains a bne :+, but the :+ is being checked backwards, not forwards, it says the branch target is the very line we are on, rather than the L158 which is the real target.
Just figured I'd mention this, I've been using the placement of these temp labels to assess better whether I'm grouping structured programming constructs properly.
In this case, you'll notice that on the line with cheap local label L157, this line contains a bne :+, but the :+ is being checked backwards, not forwards, it says the branch target is the very line we are on, rather than the L158 which is the real target.
Just figured I'd mention this, I've been using the placement of these temp labels to assess better whether I'm grouping structured programming constructs properly.
You do not have the required permissions to view the files attached to this post.
-
segaloco
- Posts: 911
- Joined: Fri Aug 25, 2023 11:56 am
Re: Vscode ca65 intellisense extension
Here's another one I noticed:
In this case, I'm finding that memory references inside of macros do not appear to be found. Like here, nmi_rng_ctrl_en, a variable for enabling RNG and controller cycling during NMI, is inside a macro since this is part of display list processing in a few different places. The variable is greyed out in the memory map and right clicking on the variable yields no references. The result is it looks like the variable is unused while scrolling down my memory file, but it really is.
In this case, I'm finding that memory references inside of macros do not appear to be found. Like here, nmi_rng_ctrl_en, a variable for enabling RNG and controller cycling during NMI, is inside a macro since this is part of display list processing in a few different places. The variable is greyed out in the memory map and right clicking on the variable yields no references. The result is it looks like the variable is unused while scrolling down my memory file, but it really is.
You do not have the required permissions to view the files attached to this post.