Issues embedding editor in block inlay

Answered

I'm trying to embed a Swing component into an editor using a block inlay. The component contains, among other things, an embedded editor. I'm having some problems with this:

  1. I'm using EditorComponentInlaysManager to handle the components. I've copied it to my code with the intention of modifying it, but currently my copy is the same as the one in the community source. My first issue is that when I first insert the component there's just blank space in the editor, sized appropriately for the inserted component. If I then resize the editor slightly the component appears - it seems it's not correctly painted when it's first inserted.
  2. My component has a configuration toolbar along the top, including some components such as checkboxes. When I hover over these, the mouse pointer is still set to the editor caret, presumably because these components appear inside the enclosing editor. How can I fix this?
  3. Related, when I insert the component I focus the embedded editor. This seems to work since the caret is blinking in the embedded editor and static in the enclosing editor, however all keystrokes are sent to the enclosing editor. What's the best way to handle this?
0
17 comments

Hi, Colin
Which version of the IntelliJ sources are you using? Some of the sizing issues were globally fixed recently.

Having some code examples would also be great - I can't tell exactly what is going wrong without the code, but I can try and guess how it can be fixed:

1. You can try and call `revalidate()` on the component after adding it.

2. Not sure what can be wrong here without the code.

3. To prevent keystrokes being handled by the host editor you need to put a certain client property in the component you wish to really handle the keystroke:

component.putClientProperty(UIUtil.HIDE_EDITOR_FROM_DATA_CONTEXT_PROPERTY, true)
1

Hi Ivan,

Thanks, sorry for the late reply. I've created a little test project with an action that shows what I've been doing. The repo is here: https://github.com/cursive-ide/component-inlay-example. This project adds an "Add Component Test" action which can be invoked by searching from it from any editor. This doesn't include either of your fixes above, the code is just what I originally had tried.

0

Following up here, I've tried both fixes suggested above. The revalidate() change didn't do anything that I could see, it definitely didn't fix the problem with the component not appearing until the editor is resized. The client property stopped the outer editor receiving the keystrokes, but many of the special keystrokes (enter, arrow keys, backspace/delete) don't work in the embedded editor.

0

Thank you for the code snippet, it definitely helped.

Unfortunately I couldn't solve the issue with initial appearance. Stragest thing is that it only works this way before the first inlay "fix" for an editor. So if you add multiple inlays to an editor they are not painted, but if you resize an editor - they all appear at once and all subsequent inlays are painted immediately.

As for the cursor issue - the fix is pretty easy - you just have to manually set the cursor on the panel you are adding as an inlay like this:

panel.cursor = Cursor.getDefaultCursor()

And the keystroke issue is tricky as well. All actions are being "bubbled" to and consumed by the host editor and there's no easy way to hide it from action data context without hiding the actual embedded editor.
There's a solution, though. You can use `EditorTextField` and do something similiar to

com.intellij.util.ui.codereview.timeline.comment.SubmittableTextField#createTextField
0

Thanks for looking at this, Ivan.

The initial appearance issue is really weird. As I mentioned, the EditorComponentInlaysManager is just a copy of the one in the community source - I think that one is used for adding code review comment widgets in the diff views. Could you ping the developers responsible for that and ask them if they had to do anything to deal with this problem?

I'll look at the EditorTextField suggestion and try it out, thanks.

0

I've also just tried the EditorTextField fix and pushed the changes to the repo. It doesn't seem to work, the editor looks strange (it's uses a variable width font) and the special keystrokes are still bubbled up to the containing editor.

0

That would be me, unfortunately - "developers responsible for that". And in review comments this issue was fixed a long time ago.

I've tried the updated action and it indeed doesn't work as expected. Will look into that. There are probably some differences in how a usual editor and diff editor handle data context.

0

Having spent some time looking at this I have a question - do you need a really full-fledged editor in an inlay or a simple text editor like "JTextArea" would suffice?

0

I think I do, but I might be wrong. This is for a macroexpander in Cursive. Clojure code uses a lot of macros, and this tool allows the user to interactively view the expansion of a particular macro, and then recursively expand its subforms. Currently I do this in a popup but it's something of a pain, and the inlays seemed like a good fit. The view is not editable, I create it as a viewer, but I do use RangeHighlighters to highlight the text area that was just expanded if the user has interactively expanded a subform visible in the editor. I guess I could create the JTextArea such that the styling matches the code editor and try to improvise something around the RangeHighlighter, but it seems like a lot of work when the editor provides all that for free.

0

Ok. Will try to find some solution. It will probably require platform changes, so I can't say when it will be implemented.

0

Thanks Ivan, I appreciate it. If you have any suggestions for the component not appearing when added, that would be great too, since that doesn't seem to be related to the editor problem. In that test repo I just tried only adding the toolbar component rather than the enclosing JPanel with the editor, and it still didn't appear until the editor was resized. This is probably my biggest blocker since I'd like to use inlays for other functionality involving Swing components too.

0

I spent some time debugging this, and it looked like a problem with the clip bounds. My swing-fu is pretty weak, but I think it's related to the EditorTextWidthWatcher in EditorComponentInlaysManager. So after adding the component, I did this:

val viewport = (editor as? EditorImpl)?.scrollPane?.viewport
viewport?.dispatchEvent(ComponentEvent(viewport, ComponentEvent.COMPONENT_RESIZED))

That seems to fix it, but seems pretty hacky. I think I could also dispatch COMPONENT_HIDDEN or COMPONENT_SHOWN and get the same effect. I'd be interested to know if there's a more appropriate fix for this. I pushed this workaround to the test repo too.

0

Ah. Found the issue with sizing and it's very simple to fix. Just invoke `updateWidthForAllInlays` in `EditorTextWidthWatcher.init`.
It wasn't needed for reviews bc the manager is created before the Editor is shown, but here the manager is created for the existing editor and the width is not recalculated and remains 0.

0

Unfortunately that's a platform class which I don't have duplicated in my code, the only one I've moved over is EditorComponentInlaysManager. So I think the hack that I posted above is probably the best solution since it essentially invokes updateWidthForAllInlays via the event. This might also provoke a bunch of other updates I guess, but I can't see a better way to do it.

0

EditorTextWidthWatcher is an inner class of EditorComponentInlaysManager, so you should have it as well. invoking width update in a constrcutor shouldn't have any side effects.

0

Ugh, you are absolutely correct, of course - thank you!

0

Colin Fleming, thanks for the example repo. It has been helpful with the creation of the inlay I've been working on. I'm having the same issues with capturing the enter and delete keys. Were you able to figure out how to solve it and/or were there issues created to track it?

1

Please sign in to leave a comment.