Skip to content

Editor Aspect¶ ⧉

The editor aspect defines the projectional editor of a concept.

General

To learn more about internal editor topics, visit MPS Internals: Editor Development.

What happens when you press F5 in the editor?

F5 in editor ⧉ (Specific Languages' blog)

How can you delete non-existing children, references, or properties from a node?

Switch to the reflective editor and remove the offending parts. There is also an enhancement script ⧉ that can remove properties.

Is there a way to prevent users from adding and removing elements in a list in the MPS editor? The elements in the list should still be editable, but adding/removing shouldn't be allowed.

There are two solutions:

  1. Use a query list with empty insert/delete handlers.
  2. Create an action map/inline action cell with empty blocks for the actions INSERT and INSERT_BEFORE.

I've set a color of type java.awt.Color in a style property query, but the color is different when using the Darcula theme.

The return type of those functions indicates that the return type is java.awt.Color, but the generator maps these colors to theme-dependent colors. The only avoid to avoid these mappings is to use custom factories. here ⧉ contains more information about theme-dependent colors.

What is the difference between an empty cell and a simple constant cell without content?

Both cells work with an internal text line, but the constant cell supports more styling for the text line. The cursor also looks different.

A constant cell supports the cell actions LEFT, RIGHT, LOCALHOME/END,SELECTRIGHT/LEFT, SELECTLOCALHOME/END, COPY, PASTE, CUT, and CLEAR_SELECTION, which it inherits from the internal label cell class. It has methods to validate the text (the only correct text is the specified text in the editor) and synchronize the cell with the model (that means returning to the original text after editing the text).

The empty cell inherits from the basic internal cell, which supports only left and right transformations (LEFT_TRANSFORM, RIGHT_TRANSFORM). It also doesn't support the editable style sheet item, which means no support for editing the text.

An empty cell is a very stripped-down version of a constant cell and also has a somewhat different implementation because of the other base classes.

I have actions for mouse clicks in my language, and they also trigger for right mouse clicks. Can we prevent that generally or by manually/programmatically detecting which mouse button fired the event?

No, the selection manager executes the click action for the selected cell. You will only get this information with the original MouseEvent that the editor does not forward to the editor cell. You can't restore the event. It would be possible to register a new mouse listener for the editor component through an editor extension that not only creates the click action for the selected cell but also saves the mouse button somewhere. The EditorComponent ⧉ contains the original implementation.

I want to create a DSL using diagrams or a visual programming language. Are there any inspirations?

Have a look at Visual Programming Languages - Snapshots | interfacevision.com. This page has a lot of examples of visual programming languages dating back to 1963 up to recent languages like Scratch. MPS Extensions(documentation ⧉) supports diagrams, and you can use them as the base building block of a new language.

Transformation Menu Language | MPS documentation ⧉ describes all the menus that can be influenced. If you use Grammar Cells ⧉ from MPS Extensions ⧉, transformation and substitution menus might not be needed at all. When you use the language, you only need to use empty substitutions menus for concepts that shouldn't be substituable at all.

Explain the different menu-related terms 🔰

  • Menu definitions have two flavors named and default and can be defined in transformation or substitute menus.
    • Default substitutions will replace the default menu that MPS shows.

      Shortcut: Ctrl+Space or Cmd+Space

    Default menu

    • Transformation menus define UI actions that show up in various locations. The menu consists of a list of sections. Each section contains a list of menu parts for a set of locations. At runtime, the menu parts and locations decide the content of the completion menu. The contents of the completion menu are called menu items.
    • Parameterized actions allow calculating a list of elements of a specific type to be shown in the completion menu. They calculate all elements for the substitution menu and influence the node creation. Moreover, they define the selection of where the cursor should be placed.

How do you find out where a substitute menu entry is coming from?

Use the Menu Trace Tool window. Menu Trace Tool Window | MPS contains more information.

How can you add smart references using the transformation menus?

Adding smart references using transformation menus ⧉ (F1RE's blog)

What's the best way to improve the autocomplete description of concepts?

As you can see in the screenshot, the concepts of both opening braces are indistinguishable.

autocompletion myUnion

I can change the description by modifying the short description in the concept structure.

  1. What's the best format to improve these descriptions?
  2. Is this the correct/best way to change the autocomplete concept description?

concept BracketInitializer

autocompletion int16

asked by: @AlexeiQ

Generally, it's up to the users and specific context to decide what makes sense to put into the description text. It should provide additional semantic information to those unfamiliar with the language to help them pick up the right concept from the code completion menu.

The short description in the concept is the original, simple way to provide a static description in the code completion menu. You can also add your substitute action in the substitute menu of the concept (editor aspect) to get complete control over the code completion menu and to be able to generate the text dynamically based on the context.

DataItem SubstituteMenu

data autocompletion

answered by: @wsafonov

Languages

Many languages were developed over the years that help with creating better editor. Most of the language contain custom editor cells that you can use the same way as standard cells such as constant or collections cells. You only need to import the corresponding language in the editor aspect.

I need a specific graphical notation/feature for the editor 🔰

Have a look at the complete extension list ⧉ from MPS Extensions ⧉.

I need hyperlinks 🔰

Use the language com.mbeddr.mpsutil.hyperlink from the mbeddr platform ⧉.

How do you create clickable links?

How can you include non-child relations in the editor?

Use the language com.mbeddr.mpsutil.editor.querylist from MPS Extensions ⧉.

Editor Declaration

This section contains some more advanced topics and questions when defining editors.

Is there a disadvantage to using the indent layout instead of the indent cell mode?

No. There used to be performance issues with bigger models that were fixed in MPS 2021.1 ⧉.

How do you use an empty text for empty cells?

Use empty text for empty cells ⧉ (Specific Languages' blog)

How do you set the cursor to the first editable cell?

editable cell and error_cell

  • (A) What it looks like after creation
  • (B) Initial situation with cursor at (1): pressing Enter leads to (C)

The problem is that in (C), the cursor is at (2), right before a read-only cell, and thus editing or moving to the next cell is impossible. I want the cursor to jump to the first editable cell at position (3).

Structure of the new node in (C):

Kroki

Editor of the new node in (C):

example c:node editor

Usually, you would set the attracts focus property of the cell, where the cursor should be positioned, to attractsFocus or FirstEditableCell. But, since C.2 and C.3 are error cells, the default behavior is to set the cursor in front of the first error cell, which is (C.2).

Therefore, change the first part of your editor to a query list cell (A), which references the "member" in the cell properties (B), and set the read-only property on the query list.

new editor for CompoundInitializerMember

contributed by: @AlexeiQ

Can the selected value of one Java Swing component be accessed from inside another Java Swing component?

Yes: Is it possible to access the selected value of one Java Swing component from inside another Java Swing component? | MPS forum ⧉

How can you access an icon stored in a concept?

Create a new custom cell:

1
2
3
4
5
6
7
8
new AbstractCellProvider() {
    @Override
    public EditorCell createEditorCell(EditorContext p1) {
            EditorCell_Image.createImageCell(context, node, {
                EditorContext context, SNode node => GlobalIconManager.getInstance().getIconFor(concept); 
            });
    }
};

How can you paint the background of specific editor cells with a different color based on the analysis of the model?

  • with the help of a conditional editor
  • by using the class NodeHighlightManager:
1
2
3
4
NodeHighlightManager highlightManager = this.editorComponent.getHighlightManager(); 
EditorMessageOwner messageOwner = this.editorComponent.getHighlightMessagesOwner();
(...)
highlightManager.mark(((SNode) ref), HighlightConstants.INSTANCES_COLOR, "usage", messageOwner);

The second approach performs better because the highlighter runs asynchronously, not during the editor rebuild.

How can you hide a custom cell in the editor? (show if property)

Custom cells expect only a cell provider in the inspector but don't offer the possibility to specify other attributes to set, for example, "show if." How can I hide a custom cell under a specific condition? (MPS-33195 ⧉)

The meta-model allows specifying the show if property and other attributes on a custom cell, and the generator will generate the correct code for it. The editor for the inspector doesn't include it. You can use the reflective editor to specify the condition.

Since these attributes are not visible and you need this knowledge to find them, the alternative for better visibility is to surround the custom cell with a collection and set the show if property on the collection.

contributed by: @AlexeiQ

How do you split child collections?

Advanced editors: splitting child collection in the editor ⧉ (Specific Languages' blog)

How can I show an editor cell only if the edited node/sub-nodes are currently the active selected nodes?

You can implement a cell similar to the cell EditorCell_MathEnd ⧉ in MPS Extensions ⧉.

Editor Hints

Is there a utility class related to editor hints?

Yes, there is in mbeddr: EditorHintHelper ⧉.

How can you set editor hints?

Can I push editor hints with a node attribute?

Create a custom factory cell (available in MPS Extensions ⧉) with a factory method similar to the following:

1
2
3
4
5
factory method(editorContext, node, cell)->EditorCell {
    node<> n = node;
    editorContext.getEditorComponent().getUpdater().addExplicitEditorHintsForNode(n.parent/.getReference(), concept editor hint/HintA/);
    cell
}

Inspector¶ ⧉

As a language developer, you often use the inspector in the editor aspect to set styles, or change macros in the editor aspect. Some projects use the inspector nearly not all, but it can be good solution to not clutter the editor: Move rarely needed information to the Inspector ⧉ (Specific Languages' blog)

How can you open the inspector programmatically?

editorContext.openInspector()

How can you focus on a node in the inspector?

Highlighting constraint errors in the inspector doesn't work.

Known bug (MPS-32350 ⧉). Pressing F5 helps.

Open API

This section contains answers to code-related questions.

How can you open the editor for a node programmatically?

NavigationSupport.getInstance().openNode()

How can you override an arbitrary editor?

Use the language de.slisson.mps.conditionalEditor from MPS Extensions ⧉.

How can you get the font of an editor?

jetbrains.mps.nodeEditor.EditorSettings#getDefaultEditorFont()

How can you subscribe to editor changes?

How do you get the text of an EditorCell programmatically?

EditorCell.renderText().getText()

How can you find out if an editor cell is read-only?

ReadOnlyUtil.isCellsReadOnlyInEditor(this.editorComponent, new singleton<EditorCell>(editorCell))

How do you get an editor for a node as a Java Swing component?

1
2
3
HeadlessEditorComponent component = new HeadlessEditorComponent(#project.getRepository()); 
component.editNode(node);
return component;

How do you get a Project instance for an ActionEvent?

1
2
3
4
5
button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    Project mpsProject = UiUtils.getMpsProjectFromActionEvent(e);
    }
}

How do you get the selection/selected node in the editor?

editorComponent.getSelectionManager().getSelection() / editorContext.getSelectedNode()

How can you select a node in the editor?

1
2
3
editorContext.getSelectionManager().setSelection/pushSelection
// or
editorContext.getNodeEditorComponent().selectNode()

How do you find all open editors?

Finding all open editors ⧉ (Specific Languages' blog)

How do you programmatically collapse editor cells?

1
2
3
4
 EditorCell_Collection.fold()/unfold()

// You can check if it is foldable by calling:
EditorCell_Collection.isFoldable()

Is there a callback/hook when an editor tab closes?

When closing an editor tab, MPS removes the highlighting from all nodes in the editor. I.e., when an editor is opened again for the same root node, all highlighting is gone.

In my code, I want to react to this editor-close event. Can a callback or hook be implemented, which the editor calls when an editor tab is closed?

You can register an EditorComponentCreateListener, that also receives an editorComponentDisposed event (example ⧉).

How can I customize the behavior when pressing the Tab key in the editor?

To override this behavior, you can specify the action NEXT in an action map (MPS source reference). The default action is declared here with its default implementation in NodeEditorActions ⧉(it jumps to the next editable leaf of the editor cell tree).

I am using NodeHighlightManager.mark() to highlight AST nodes. MPS then uses the provided color for the cell's background and a slightly darker shade for an additional border. Can we change this, i.e., only paint the background, but not the border?

Yes, but you must create a class that extends DefaultEditorMessage and overwrites the paintWithColor method. Line 203 ⧉ defined the color of the border. Instead of calling this method:

1
2
3
4
public void mark(SNode node, Color color, String messageText, EditorMessageOwner owner) {
if (node == null) return;
mark(new DefaultEditorMessage(node, color, messageText, owner));
}

You must initialize your message object and supply it to the mark method.


Last update: November 7, 2023

Comments