Big update to prettier-extension-monkeyc

I've posted about prettier-extension-monkeyc before, but I've added a bunch of new features that developers will probably like (well, I've been missing them, so maybe you have too).

The new features it implements for VSCode include:

  • Goto Definition. Point at a symbol, Ctrl/Cmd click, and it will take you to the definition. Or F12
  • Goto References. Right click on a symbol and select "Goto References". It will show you all the references. Or Shift-F12
  • Peek Definition/Peek References. Same as above, but in a popup window so you don't lose your place in the original document.
  • Rename Symbol. Right click on a local, function, class or module name, and select "Rename Symbol". It will rename all the references. It doesn't yet work for class members/methods.
  • Goto Symbol. Type Ctrl/Cmd-Shift-O and pick a symbol from the drop down (which has a hierarchical view of all symbols in the current file). This also appears as an outline across the top of the file.
  • Open Symbol By Name. Type Ctrl/Cmd-T, then start typing letters from a symbol name. A drop down will be populated with all matching symbols from anywhere in your project.

Older features include a prettier based formatter for monkeyc, and a monkeyc optimizer that will build/run/export an optimized version of your project.

[edit: My last couple of replies seem to have just disappeared, and the whole conversation seems to be in a jumbled order, so tldr: there's a new test-release at https://github.com/markw65/prettier-extension-monkeyc/releases/tag/v2.0.9 which seems to work for me on linux. I'll do more verification tomorrow, and push a proper update to the vscode store once I'm sure everything is working]

  • Theoretically, could an aggressive optimizer improve performance by aliasing all qualified names with a `$.generatedA.generatedAC` where it generates an N-level deep set of modules which store references to everything the program uses?

    Thinking out loud: You want to minimize lookup times, and each lookup is a linear top-to-bottom scan of that namespace.  If a namespace gets too big, then scans slow down.  If you alias everything to a single global scope `$.generatedIdentifierA`, `$.generatedIdentifierB`, etc. then the linear scan of that namespace is slow.

    Symbols are integers under the hood, and I always assumed that looking up a symbol in any given scope would have O(1) time complexity (using hash tables or something similar.)

    I could be wrong tho.

  • Theoretically, could an aggressive optimizer improve performance by aliasing all qualified names with a `$.generatedA.generatedAC` where it generates an N-level deep set of modules which store references to everything the program uses?

    I suppose its possible, but I think there are unlikely to be substantial gains.

    Currently, if you import a module, then that module's name is looked up by the getm opcode, which looks in a special table. I'm not sure how that lookup works; it would make sense for it to be organized as a hash table - but I wouldn't be surprised if it's linear. Note that '$' is always looked up in this table. (this only applies to the thing that was actually imported - contained modules can also be referenced by unqualified name, but that's just syntactic sugar).

    So if that is a hash table, then the fastest possible way to lookup modules is to import them, and then look them up by unqualified name.

    But that would still leave a linear search for the function or whatever in the module. So maybe creating lots of modules with very few entries in each one would be the way to go.

    And if getm does a linear lookup, then yes, keeping the global module nearly empty (Toybox, Rez, plus the root of your tree), with the rest of the tree branching from there might be the fastest.

    But remember that lookups in each table happen in "native" code, while each step of the tree is a bytecode (or two), and interpreting bytecode presumably has a fairly high overhead. So you're probably going to need to weight it heavily towards large modules, and a small tree depth.

  • Following the theme on non-default project structure, I have a question. Is there a way to force restart project (and with the recent changes, the whole workspace) analysis?

    I have directory with generated sources as sourcePath, and it is analyzed by the plugin, which is what I expect. However, during build process, this directory is completely removed and is recreated from scratch, and every time I do build, the number of errors, such as "undefined symbol", raises to almost 1K, which is also OK, as source files for these symbols do not exist for a short period of time, but after build is finished and all sources are refreshed, the number of errors almost never returns back to the normal value. Sometimes, it helps to manually edit generated file afterwards, like adding a whitespace, but this method is unreliable, and is barely usable for a large number of generated source files.

    The issue I'm fighting with may be caused by the fact, that I'm using Docker, that, as I think, may skip some file system events, and NodeJS/VSCode/plugin may not know, that source files are back, and the analysis can be performed again. But it looks a bit strange, that removal of files is detected almost instantly, but creation of the same amount of files is completely ignored. I must say, I have no issues with manual adding/removing/changing single source files, and the errors are always relevant to the current state, so the issue is only with such bulk updates.

    Now I have to restart VSCode or reopen workspace after each build, that is not very convenient. I'd be glad to have a possibility to force run analysis from command palette or something similar.

  • Now I have to restart VSCode or reopen workspace after each build, that is not very convenient. I'd be glad to have a possibility to force run analysis from command palette or something similar.

    Not exactly what you want, but you could use "Developer: Reload Window" from the command palette. It's faster and would require fewer clicks/keystrokes.

  • Not exactly what you want, but you could use "Developer: Reload Window"

    "Developer: Restart Extension Host" is probably less disruptive, and should have the same result.

    But yes, I'm aware that the live analysis doesn't always keep up. It's trying to de-bounce updates so that it doesn't keep updating while you're typing, but there's definitely a bug, I've just not found it yet...

  • OK, I'll be using one of these Developer commands, until (if ever) I find something better.

    Thanks for the workaround!

  • v2.0.103 is out

  • I have a barrel, that uses device personality classes, like "Rez.Styles.system_size__screen.width" for getting screen width, etc. But it is not possible to call "barrelbuild" without having "Undefined symbol ':Styles' detected." and "Undefined symbol ':system_size__screen' detected.". This happens, because "barrelbuild" tries to build barrel not only for all devices in barrels' manifest but also for some generic "no-device" device with the same supported min API level and fails, as this "no-device" doesn't have styles in barrel's "bin/gen/no-device/source/Rez.mcgen" file. I fix this by adding MSS file with the following content:

    system_size__screen {
        width: 1;
    }

    Width value is irrelevant, and it will be automatically overridden by the actual screen width from device specific "Rez.mcgen" file during regular "monkeyc" call. I add this MSS just to make "barrelbuild" happy.

    This works for unoptimized builds, and I see real values, but PMC optimizes "Rez.Styles.system_size__screen.width" to "1".

    Is there anything, that can be done to avoid or fix (I'm not sure, whether it is right to fix such kind of stuff) this, except for using jungle file dependency?

  • This definitely sounds like a bug. If it's resolving system_size_screen.width to 1, it must be resolving the personality files incorrectly.

    At the least it should see multiple definitions, and not try to optimize. But what I would expect to happen by default is that devices with different personalities should be in different "groups" in the output; so there should never be multiple definitions.

    I'll see what I can find...

  • This definitely sounds like a bug.

    I agree, but this is the bug of my fix for Garmin's bug. I wasn't sure, whether you want to support this or not (and, if not, I understand, why).

    At the least it should see multiple definitions, and not try to optimize.

    I saw this behavior when I was trying to create test case for custom personality classes, created from scratch, so sometimes it works as intended.

    Here is a test project: barrel-personality.zip. "Run App" prints actual screen width to console. "Run Optimized" prints "1" (the value from fake MSS).