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]

  • fr235.lang.heb = ../../resources-heb
    Each of the lines (as the warning also tells) looks the same, with a different "old" device. It is related to the fact that the old watches didn't yet have Hebrew support.
    The problem is the same when I do the same without optimization:
    If I have the above line then I get the warning, if I don't have it then the "default" behaviour (whatever that is) works. I think that the default is that fr235 doesn't have Hebrew, so it doesn't have the above line Slight smile
    Ah here's a better way to understand it maybe:
    My monkey.jungle file ("grepped" for hun and heb) would look like:
    fr230.lang.hun = resources-memory16K/resources-hun
    # there's no similar line for heb

    and I think "your code" added voluntarily:
    fr235.lang.heb = ../../resources-heb
     
    This doesn't break functionality because mokeyc knows that this device doesn't support Hebrew, thus displays the warning. 
  • Ok, great. That is the problem I found. And yes, it doesn't break anything, its just noise. I should have a fix shortly.

  • v2.0.11 is now posted at https://marketplace.visualstudio.com/items?itemName=markw65.prettier-extension-monkeyc, and should fix both your issues.

    It also turns Toybox references into clickable links to the documentation, and fixes various other minor bugs.

  • The warnings are gone Slight smile

    The toybox links work partially. It seems to work for using and import and extends, but not always when it's used in code. For example these don't work:

    class MyApp extends App.AppBase {
    function initialize() {
      AppBase.initialize(); // doesn't work
      
      var msg = new Ant.Message() as Ant.Message;
      msg.messageId = Ant.MSG_ID_BROADCAST_DATA;
      var data = [0, 0, 0, 0, 1, 0, 1, 72];
      msg.setPayload(data); // this doesn't work
    }
    function foo() {  
      WatchUi.requestUpdate(); // this doesn't work
    }
    However if there is something that's even more missing is that the click doesn't work on methods between 2 files from the project:

    A.mc:
    class A {
        var mB as B;
        function a() {
            mB = new B();
            b.foo(); // this doesn't work
        }
    }
    B.mc:
    class B {
        function foo() {}
    }
  • Actually I was thinking about this and maybe we would want to do the exact opposite :)

    I think it'll be better to change every line that you remove to an empty line. The reason is that that way the line numbers in the original and the optimized code remain the same, and that is very important, especially because we only save the source code in git, and when a month later there's an error in ERA Viewer then we won't be able to find anything if you removed lines...

  • I think it'll be better to change every line that you remove to an empty line

    Thats actually what I'd like to do ideally. But I'm relying on prettier (via my prettier plugin) to output the code, and it has its own ideas on how to format the results. Even if you've formatted the original code with prettier, the output will still change because of line length differences (eg because Graphics.COLOR_BLACK becomes 0 as Toybox.Graphics.ColorValue).

    So I'd need to write a whole new formatter from scratch (I based my AST on estree, which is what the javascript prettier printer uses, so that 95% of the printing is handled by the bulitin javascript formatter). Its definitely something I'm thinking about, but not very high on my priorities right now.

    A partial solution to your ERA Viewer problem would be to create an export-for-release task, and set its "outputPath" property to "releases" (for example). Then when you run it, all the generated files will go to "releases", rather than "bin/optimized", and you could then commit the optimized source once for each release.

  • AppBase.initialize(); // doesn't work

    This looks like a bug. It's not injecting the name of the superclass into the classes name space.

    msg.setPayload(data); // this doesn't work

    b.foo(); // this doesn't work

    This is currently a feature. I'm not doing any type analysis, so I don't know that msg is an Ant.Message, so I don't know what setPayload refers to. I've considered adding a "Trust type declarations" option, which would help in the second case (once you fix the typo), but not the first (local variables can't have type declarations). This is also why you can't rename class variables and methods, but you can rename Module variables and methods, for example.

    I am thinking about writing my own type checker, partly to solve this issue, but mostly because Garmin's is so bad...

    WatchUi.requestUpdate(); // this doesn't work
    I just tried adding this one to my code, and it worked. I'm investigating some issues where changes to the code don't always seem to get picked up, maybe that's what happened?

     

  • I think the Generate Optimized Project stopped working

  • local variables can have type as well:

    class Foo {
     function bar() {}
    }
    function foo (a as Foo) {
     var b = new Foo() as Foo;
     var c as Foo;
     a.bar();
     c = new Foo();
     b.bar();
     c.bar();
     var d = new Foo();
     // d is not a type with type, so it can change:
     d = "String";
    }


    All the above except d are examples of local variables with type.

    Regarding: WatchUi.requestUpdate();
    Can this be because WatchUI is not imported or used? (I mean no: using Toybox.WatchUI). Though it's interesting how this even compiles then, but it does work :)

  • local variables can have type as well

    Actually, they can't. Or rather, they *have* types, but they can't be declared as being constrained to a particular type (the way that global, module, or class variables can).

    var b = new Foo() as Foo;

    This is just redundantly casting new Foo() to type Foo. You can assign anything you like to b on the next line. Yes, Garmin's type checker knows that b is of type Foo, and propagates that information (with or without the "as Foo") to later uses. But unless and until I also implement a similar type checker, I won't know what type b is at later points in the program.

    var c as Foo;

    ERROR: <device>: foo.mc:6: Invalid explicit typing of a local variable. Local variable types are inferred.

    That pretty much says it all...

    Can this be because WatchUI is not imported or used?

    Maybe... import and using apply globally (ie across all files). They're runtime constructs, so as long as you import WatchUI in one file, its available in all of them (much like "var myGlobal;" is available across all files). In fact, using/import is *very* similar to var WatchUI = $.Toybox.WatchUI;

    But my analysis should work the same way; so if you *do* have a using/import elsewhere in your project, it should still know what WatchUI is referring to (quickly checking that here seems to confirm that it works).