Monaco-editor: Hiding context menu options based on selected line content

Created on 11 Sep 2018  路  10Comments  路  Source: microsoft/monaco-editor


monaco-editor version: 0.X.Y
Browser: Chrome
OS: windows
Steps or JS usage snippet reproducing the issue:

From the below URL, a new context menu option "My label" is added.
https://microsoft.github.io/monaco-editor/playground.html#interacting-with-the-editor-adding-an-action-to-an-editor-instance

Can i Hide the "My label" option if the selected line is a comment or some other condition.
I have tried with

precondition: "!editorReadOnly",

in the add action, but the precondition works only while creating editor instance, can i update the action dynamically to hide the context menu option or can you suggest me a better way to hide the context menu options?

*question

Most helpful comment

Since this is JavaScript, you can implement whatever you want when we don't have API for each and every thing.

e.g.

const editor = monaco.editor.create(...);
// ...
const contextmenu = editor.getContribution('editor.contrib.contextmenu')
const realMethod = contextmenu._onContextMenu;
contextmenu._onContextMenu = function() {
  console.log('here I am, taking over');
  realMethod.apply(contextmenu, arguments);
};

Good luck!

All 10 comments

You can create your own context key and you can define its value dynamically.

An example that uses context keys can be found here

thanks @alexandrudima for you quick and valuable suggestion, i have tried with command with context key(KeyCode.ContextMenu), but it didn't work, so,i tried with an event > editor.onContextmenu()
which works only once. run the following snippet in the Monaco Editor Playground:

var editor = monaco.editor.create(document.getElementById("container"), {
  value: [
    '',
    'class Example {',
    '\tprivate m:number;',
    '',
    '\tpublic met(): string {',
    '\t\treturn "Hello world!";',
    '\t}',
    '}'
  ].join('\n'),
  language: "typescript"
});
var myCondition1 = editor.createContextKey(/*key name*/'myCondition1', /*default value*/false);
editor.addAction({
  id: 'my-unique-id',
  label: 'My Label!!!',
  keybindings: [
    monaco.KeyMod.CtrlCmd | monaco.KeyCode.F10,
    monaco.KeyMod.chord(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_K, monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_M)
  ],
  precondition: myCondition1.set(true),
  keybindingContext: null,
  contextMenuGroupId: 'navigation',
  contextMenuOrder: 1.5,
  run: function(ed) {
    //alert("i'm running => " + ed.getPosition());
    return null;
 }
});

var myBinding = editor.addCommand(monaco.KeyCode.F9, function() {
  myCondition1.set(false);
});
// Uncomment this for hiding "My Label" option only once.
// editor.onContextMenu(function (e) {
//     var a =editor.getModel().getLineContent(e.target.position.lineNumber);
// var c=editor.getAction('my-unique-id');
// if(a.includes('class')){
//         alert(a);
// c._precondition.expr[0].value=1;
// }else{
// c._precondition.expr[0].value=0;
// }
// c.isSupported(true);
// c.run();
// });

the Result i need is when we select some text we will get format selection option in context menu else that option is hidden in the context menu options

From above:

  ],
  precondition: myCondition1.set(true),
  keybindingContext: null,

That should be:

  ],
  precondition: 'myCondition1',
  keybindingContext: null,

Then, somewhere else in your code you can use myCondition1.set(false); or myCondition1.set(true);

thanks @alexandrudima the condition is working for me. But the problem is, i need to update the precondition value when a user right click's or on context menu opens. I have tried with the below events.

monaco.KeyCode.ContextMenu and

editor.onContextMenu

In the first case, i am unable to get the alert also.
In the second case, when the user right clicks twice, then i am getting the correct output.

var editor = monaco.editor.create(document.getElementById("container"), { value: [ 'class Example {', '\tpublic met(): string {', '\t\treturn "Hello world!";', '\t}', '}' ].join('\n'), language: "typescript" }); var myCondition1 = editor.createContextKey(/*key name*/'myCondition1', /*default value*/false); editor.addAction({ id: 'my-unique-id', label: 'My Label!!!', precondition: 'myCondition1', contextMenuGroupId: 'navigation', contextMenuOrder: 1.5, run: function(ed) { alert("i'm running => " + ed.getPosition()); return null; } }); var myBinding = editor.addCommand(monaco.KeyCode.ContextMenu, function() { var a =editor.getModel().getLineContent(e.target.position.lineNumber); alert("context menu"); if(a.includes('world')){ myCondition1.set(false); }else{ myCondition1.set(true); } }); editor.onContextMenu(function (e) { var a =editor.getModel().getLineContent(e.target.position.lineNumber); if(a.includes('world')){ myCondition1.set(false); }else{ myCondition1.set(true); } });

so please tell me, if there is any better way to hide "my label" item in context menu??

hi
Alexandru.Have you tried this.Please helpin this.

var editor = monaco.editor.create(document.getElementById("container"),
{ value: [
'class Example {',
'\tpublic met(): string {',
'\t\treturn "Hello world!";',
'\t}', '}' ].join('\n'), language: "typescript" });
var myCondition1 = editor.createContextKey(/key name/'myCondition1', /default value/false);
editor.addAction({
id: 'my-unique-id',
label: 'My Label!!!',
precondition: 'myCondition1',
contextMenuGroupId: 'navigation',
contextMenuOrder: 1.5,
run: function(ed) {
alert("i'm running => " + ed.getPosition()); return null; } });

var myBinding = editor.addCommand(monaco.KeyCode.ContextMenu, function()
{
var a =editor.getModel().getLineContent(e.target.position.lineNumber);
alert("context menu");
if(a.includes('world'))
{
myCondition1.set(false);

}else{
myCondition1.set(true);
}
});
editor.onContextMenu(function (e) {
var a =editor.getModel().getLineContent(e.target.position.lineNumber);
if(a.includes('world'))
{
myCondition1.set(false); }else{ myCondition1.set(true); } });

the condition is working for me. But the problem is, i need to update the precondition value when a user right click's or on context menu opens. I have tried with the below events.

monaco.KeyCode.ContextMenu and

editor.onContextMenu

In the first case, i am unable to get the alert also.
In the second case, when the user right clicks twice, then i am getting the correct output.

@alexandrudima Hi.
I've come to need a dynamic context menu as well. The issue with using a context key is that its value is updated after the context menu appear:

const myCondition = editor.createContextKey('myCondition', false);
editor.onContextMenu(function(e) {
    myCondition.set(true);
});
editor.addAction({
    ...
    precondition: 'myCondition',
    ....
});

Using this example on the playground, we can see that when the context menu appears the first time, the custom action is hidden. myCondition.set(true) was executed _after_.

Is there any way to alter the context menu depending on the current line?
I can't seem to find any event that's triggered _before_ the context menu is opened.

+1, expreriencing the same issue as @CyriacBr.

@alexandrudima Hey. I understand you're probably busy with a lot of things, but we'd appreciate if you can guide us how or where to edit the source to alter context keys before the context menu is populated.

@Geloosa Maybe we should open a new issue for visibility?

Since this is JavaScript, you can implement whatever you want when we don't have API for each and every thing.

e.g.

const editor = monaco.editor.create(...);
// ...
const contextmenu = editor.getContribution('editor.contrib.contextmenu')
const realMethod = contextmenu._onContextMenu;
contextmenu._onContextMenu = function() {
  console.log('here I am, taking over');
  realMethod.apply(contextmenu, arguments);
};

Good luck!

@alexandrudima Pretty sweet! I didn't know about getContribution.
That makes monkey-patching a lot easier now! Thanks a lot.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

SoftTimur picture SoftTimur  路  3Comments

aarinsmith picture aarinsmith  路  3Comments

Kedyn picture Kedyn  路  3Comments

chengtie picture chengtie  路  3Comments

inf9144 picture inf9144  路  3Comments