Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

show-hint addon events on editor #3092

Closed
nisargjhaveri opened this issue Feb 18, 2015 · 12 comments
Closed

show-hint addon events on editor #3092

nisargjhaveri opened this issue Feb 18, 2015 · 12 comments

Comments

@nisargjhaveri
Copy link
Contributor

It seems like the "shown", "select", "pick" and "close" events of show-hint addon is fired only on data. No equivalent event for many of these is fired on editor so they are unusable outside the hint provider.

It would be nice to have these or equivalent events fired on editor so that applications can make use of them and don't have to change the addon.

@marijnh
Copy link
Member

marijnh commented Feb 18, 2015

What would you use them for, though? If you don't know what the completion source is, there doesn't seem to be a lot you can do with the "select" and "pick" events. For "shown" and "close", there are already "startCompletion" and "endCompletion" events that are fired on the editor instance.

@nisargjhaveri
Copy link
Contributor Author

Surely, I know the source. But I don't want to edit the source, as it is maintained by someone else. I want to be able to update the source from the upstream.

If I edit the source, I won't be able to update the hint source every now and then to get latest bug fixes and updates.

I want to show some more info about completion hint that is selected. The only way is to update the hint source as of now, but I don't want to change that.

Isn't this a good enough use-case?

@marijnh
Copy link
Member

marijnh commented Feb 18, 2015

You don't have to edit the completion code directly -- you can wrap it in another function that attaches the event handlers.

// Some other code defined CodeMirror.hint.foo

var fooHint = CodeMirror.hint.foo;
CodeMirror.hint.foo = function(cm, options) {
   var result = fooHint(cm, options);
   if (result) CodeMirror.on(result, "pick", function() { /* ... */ });
   return result;
});

@nisargjhaveri
Copy link
Contributor Author

Oh! This may work. Thanks.

But still, I would like some events on editor. This is now just personal opinion as there is a workaround. :)

@marijnh
Copy link
Member

marijnh commented Feb 18, 2015

I disagree -- because pick and select actions need to know what kind of thing is being completed, I don't think it makes sense to support them outside of the context of a given completion object.

@marijnh marijnh closed this as completed Feb 18, 2015
@nisargjhaveri
Copy link
Contributor Author

Fair enough. Thanks.

@jpsduarte
Copy link

Could anyone post the entire code? I'm trying to use this example to get informed when the user select some option of the autocompletion. I have defined a default schema json for the hintOptions but I don't know how to subscribe to it.

@iulianmihai
Copy link

@marijnh
what is fooHint returning? and is necessary to be used in the event?

@adrianheine
Copy link
Contributor

What @marijnh posted was a generic example for amending (CodeMirror.hint) methods. In his case, he wanted to amend a hypothetical function CodeMirror.hint.foo, so he stored the function CodeMirror.hint.foo in a variable fooHint and then overwrote it with another function that first calls the original one (fooHint) and then did additional work (in this case, register an event handler).

@dchacke
Copy link

dchacke commented Feb 11, 2017

Following up on this, it would be very useful to track the appearance of the autocomplete dropdown from outside of a CodeMirror instance.

The above mentioned "shown" could be combined with something like

this.cm.on('endCompletion', function () {
  // autocomplete dropdown disappeared
});

on a CodeMirror instance.

because the abovementioned "close" event does not reliably trigger for me when the autocomplete dropdown disappears.

In any case, I needed a "global" approach (i.e. completely outside of any CodeMirror instance). My case is that I listen to the escape key being pressed, in which case I want to unfocus a form (which includes one or more CodeMirror textareas) - but only if no autosuggest dropdown is being shown.

I got around the issue by doing this for now:

$('body').on('DOMNodeInserted', '.CodeMirror-hints', function () {
  // Autocomplete dropdown is now showing
});

$('body').on('DOMNodeRemoved', '.CodeMirror-hints', function () {
  // Timeout so as to not race with CodeMirror
  // (or a user who too eagerly hits the escape key twice in a row)
  setTimeout(() => {
    // Autocomplete dropdown is now hidden
  }, 1000);
});

But this feels really ugly, and the "DOMNodeInserted" and "DOMNodeRemoved" events are deprecated. The fact that the timeout is necessary is weird also, but otherwise CodeMirror always beat me to it.

Having said all this:
Ideally, there would be global events like

CodeMirror.on('autocompleteShown', function () { ... });

and

CodeMirror.on('autocompleteHidden', function () { ... });

I'm assuming a user can never be in two CodeMirror instances at once, therefore no two autocomplete dropdowns can ever be shown at the same time, and so there would be no need to tie this to an instance.

@davidje13
Copy link

I have just hit a similar requirement to weltschmerz1. I solved it in a slightly different way, because in my use-case I have access to the hint function. Summarising the important parts:

cm.registerHelper('hint', (modeName), (cm, options) => {
  // ... generate data with a list of suggestions

  const CM = cm.constructor;
  CM.on(data, 'shown', CM.signal.bind(cm, cm, 'hint-shown'));
  return data;
});

let isAutocompleting = false;
cm.on('hint-shown', () => {
  isAutocompleting = true;
});
cm.on('endCompletion', () => {
  isAutocompleting = false;
});

This provides an event on the code mirror object named hint-shown which is only fired if the popup actually appears (i.e. it does not fire if we ask for the autocomplete to appear but it has no suggestions, or if it has only 1 suggestion and auto-applies it). The existing endCompletion event is sufficient to detect when it is closed (it will sometimes fire even if the popup wasn't visible in the first place, but for just tracking popup visibility that's fine).

All this is due to the need to track whether an autocomplete popup is currently visible. In my case I need to know this because my editor has a refactor-like mode, where pressing enter advances to the next parameter to edit (therefore the interceptor must preventDefault in order to stop newlines being inserted, but only if the key isn't being used to accept a completion).

My problem would go away if any of the following is provided:

  • Providing the shown event on the CodeMirror object itself (or fixing startCompletion), rather than requiring the hack I described above
  • Or better: a method which returns a boolean for whether the suggestions box is currently visible
  • Or even better: a place where I can intercept key presses only after all plugins have had a chance to intercept them (i.e. just before they would cause a direct text change)

@yanghuanrong
Copy link

Where do I get the "startCompletion" and "endCompletion"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants