halirutan / Wolfram-Language-IntelliJ-Plugin-Archive

Wolfram Language and Mathematica plugin for IntelliJ IDEA.
https://wlplugin.halirutan.de/
Other
193 stars 26 forks source link

Feature: Go to message #130

Closed szhorvat closed 5 years ago

szhorvat commented 5 years ago

I would find it useful to be able to jump directly to the definition of a message.

For example, I am editing a piece of code like this:

If[problem,
    Message[MySym::foo];
    Throw[$Failed]
]

I would like to be able to jump directly from the use MySym::foo within Message to its definition:

MySym::foo = "There was a problem with the call to MySym.";

Of course, we can already jump to the definitions of MySym, which includes the definition of MySym::foo. For most people, this should be sufficient.

My use case is admittedly a bit special. I have a symbol that I use for all messages that come from LibraryLink code. Unfortunately, it is difficult to issue symbol-specific messages from C code (LibraryLink) in a useful way. Thus in the IGraph/M package, all such messages as attached to the symbol IGraphM.

As a result, the IGraphM::... message definitions are scattered throughout multiple locations in multiple files. Therefore, the standard Go To Declaration is not always sufficient.

I realize that to implement such a command, you would need to choose to implement one of the existing actions provided by IDEA, and I am not sure which is the best for this purpose (go to definition, go to declaration, etc.). However, some means to go directly to the message text would be very useful for me. Perhaps there is a different way that I do not know about.

halirutan commented 5 years ago

Do you know the joke with the doctor and the patient where the doctor says "I have good news and bad news", and the patient answers "OK, give me the good news first." The doctor says "The good news is that very soon an entirely new and deadly disease will be named after you". Here the situation is similar.

The good news is that I have implemented a "Goto message" that always acts when you press the usual Ctrl+B when the cursor is somewhere over ::myTag in mySymbol::myTag. The bad news is that it won't solve an underlying problem which is that navigation breaks when definitions are scattered across several files. This is exactly the situation you face.

I believe I can fix this because it is already solved for Find usages but I need to look over this with a clear head. This issue is the reason why you don't see the IGraphM:: definitions which are in a different file when you use Goto declaration.

szhorvat commented 5 years ago

What I've forgotten about (and therefore didn't mention above) is that it is possible to use

Message[undefinedSymbol::mess]

if General::mess exists.

Example:

image

Thus it should be anticipated that some messages that are being used seem to have no definition.

szhorvat commented 5 years ago

The bad news is that it won't solve an underlying problem which is that navigation breaks when definitions are scattered across several files.

I noticed this, i.e. that only those IGraphM:: messages are listed that are in the current file.

Luckily, it seems that at least in IGraph/M, most messages that are used in file X are also defined in file X. Thus being able to navigate to the message definition within file X is already very useful. (It is common that the same message is issued from several sub-functions, so the message definition is still not near the message usage even within the same file. Therefore the feature is extremely useful even with the limitation of having to stay within a file.)

It's good to keep in mind that most of what I said is specific to IGraph/M. Other packages likely have a different organization. @kubaPod's input may be useful too.

kubaPod commented 5 years ago

From my perspective it is a nice to have feature.

From my experience with other projects it at least nice to have too, at least for some of them. A good example is GitLink/Messages:

https://github.com/WolframResearch/GitLink/blob/master/GitLink/Kernel/Messages.wl

Even though they are in one place it is a separate file and different heads are used. Still, go to file and search for a message name is a valid workaround.

szhorvat commented 5 years ago

One notable feature of that file from GitLink is that it actually makes many General:: definitions. I never did that (because of the risk of collisions). I just relied on existing General:: messages such as invopt.

A perfect implementation might look for General::bar when foo::bar cannot be found. But this is getting complicated really quickly ...

@halirutan At this point I'd say that these small improvements should be of low priority. What you mention that you have already implemented covers most of my uses at least ...

halirutan commented 5 years ago

Alright, I published an update to the beta channel. Here is my general feedback using the IGraphM package as an example

  1. If you are inside CommunityDetection.m and go on IGraphM::mixed (defined in IGraphM.m) to use Ctrl+B, this won't work, because inside this file, there are definitions for, e.g. IGraphM::invcomm. This means the plugin thinks the symbol IGraphM is defined in this file and not imported from another package. The solution would be to bind a symbol to a context, which would be the correct way and not to a file. However, finding the correct context must then be done on each keystroke during the reparse and it would mean inspecting the whole file. Another solution would be to ignore the context scope entirely and just assume all non-local and non-builtin symbols in a project are visible. The latter solution, while wrong, would mean a lot of freedom during development.

  2. If you hit Ctrl+B on a message that is defined within the file or you have not given the symbol any other definitions inside this file (you are using it as "imported" symbol), then it will jump directly to the definition.

  3. I extended the file index to not only look for ::usage messages, but for all messages. That means these instances will now appear when you use Goto Symbol (Ctrl+ Alt + Shift+N). For IGraphM, this hits the nail I guess

img