Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

I didn't find a way to show some custom suggestion as well as Monaco default suggestion. #1850

Closed
akshay-zz opened this issue Feb 27, 2020 · 13 comments
Assignees
Labels
feature-request Request for new features or functionality help wanted Issues identified as good community contribution opportunities suggest

Comments

@akshay-zz
Copy link

akshay-zz commented Feb 27, 2020

Actually I'm looking into a way in which I can achieve all these following cases.
1 - I can provide only custom suggestions. If no suggestion is present. Then nothing(blank) should be shown as suggestion.
2 - I can provide only Monaco default suggestion(words existing in the editor).
3 - I can provide custom suggestion + Monaco default suggestion(words existing in the editor).

What's the current existing behavior?
1 - I can achieve first case by returning a suggestion or a blank suggestion.
2 - I can achieve second case by not returning any suggestion(not even the blank suggestion object).

Is there's a way to achieve third case?

@alexdima alexdima added suggest help wanted Issues identified as good community contribution opportunities labels Feb 27, 2020
@alexdima
Copy link
Member

I don't believe 3 is currently doable.

But from reading the code here -- https://github.com/microsoft/vscode/blob/8758dc9dddf95f358eb93c969353e5cf245ed1e4/src/vs/editor/contrib/suggest/suggest.ts#L180-L181 -- I can deduce that the word completion provider is in a different group than the custom completion provider and once you return a result, the process stops and it doesn't get invoked.

I could not figure out what creates the grouping, but I can see here -- https://github.com/microsoft/vscode/blob/8758dc9dddf95f358eb93c969353e5cf245ed1e4/src/vs/editor/common/services/editorWorkerServiceImpl.ts#L76 -- that the word completion provider is registered with * as a selector.

You could potentially try to register your completion provider with * as well, and then check the passed in model and check if it has your language and only return results if it is your language... Perhaps that would make it that your custom completion provider is placed in the same group as the default word completion provider?

@akshay-zz
Copy link
Author

akshay-zz commented Feb 28, 2020

Thanks for the help. I will look into this.

@alexdima alexdima added the feature-request Request for new features or functionality label Feb 28, 2020
@zhengshengliang
Copy link

hi, akshay-zz, did you find any ways to solve this problem?

@zhengshengliang
Copy link

zhengshengliang commented Mar 3, 2020

I meet this same problem in my project!wish your repley, thx!

@akshay-zz
Copy link
Author

hi, akshay-zz, did you find any ways to solve this problem?

Right now I'm not working into this. But soon will try to achieve this as per hint given by @alexdima .

@akshay-zz
Copy link
Author

akshay-zz commented Mar 17, 2020

I think something like this could help. I haven't tested the else part. Right now I'm not working on this. But if someone can try to achieve this and share with us, then that would be great. Even thought this trick does not satisfy third case completely. But I think this will help and by doing little work around by summing up word suggestion and server suggestion we can achieve the third case.

monaco.languages.registerCompletionItemProvider('csharp', {
			triggerCharacters:["."],
			autoIndent:true,
			provideCompletionItems: function(model, position) {
				var word = model.getWordUntilPosition(position);
				var range = {
				startLineNumber: position.lineNumber,
				endLineNumber: position.lineNumber,
				startColumn: word.startColumn,
				endColumn: word.endColumn
			};
                       // hit server only when dot is pressed (not for any other character)
			if ((word.word).length<1 ) {
				// fetch suggestion from server
				var pos = getLengthTillWhereCusrorIsPresent(position);

				return fetchSuggestion(pos).then(function(res) {
						return {
							suggestions:res
						}
			})
			} else {
				// give suggestion from cache
				//return { suggestions : createDependencyProposals() }


				var word = model.getWordAtPosition(position);
				var replace = !word ? Range.fromPositions(position) : new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);
				var insert = replace.setEndPosition(position.lineNumber, position.column);

				const client = this._workerManager.withWorker();
				const words =  client.textualSuggest(model.uri, position);

				if (!words) {
					return undefined;
				}
				return {
					suggestions: words.map((word): modes.CompletionItem => {
						return {
							kind: modes.CompletionItemKind.Text,
							label: word,
							insertText: word,
							range: { insert, replace }
						};
					})
				};
			} // else end
		}
	});

Haven't tested else part and quite sure will fail. Just added to give a approach if anyone love to work on this. Else part code is taken from here

@Pranomvignesh
Copy link
Contributor

Pranomvignesh commented Jun 15, 2020

I think something like this could help. I haven't tested the else part. Right now I'm not working on this. But if someone can try to achieve this and share with us, then that would be great. Even thought this trick does not satisfy third case completely. But I think this will help and by doing little work around by summing up word suggestion and server suggestion we can achieve the third case.

monaco.languages.registerCompletionItemProvider('csharp', {
			triggerCharacters:["."],
			autoIndent:true,
			provideCompletionItems: function(model, position) {
				var word = model.getWordUntilPosition(position);
				var range = {
				startLineNumber: position.lineNumber,
				endLineNumber: position.lineNumber,
				startColumn: word.startColumn,
				endColumn: word.endColumn
			};
                       // hit server only when dot is pressed (not for any other character)
			if ((word.word).length<1 ) {
				// fetch suggestion from server
				var pos = getLengthTillWhereCusrorIsPresent(position);

				return fetchSuggestion(pos).then(function(res) {
						return {
							suggestions:res
						}
			})
			} else {
				// give suggestion from cache
				//return { suggestions : createDependencyProposals() }


				var word = model.getWordAtPosition(position);
				var replace = !word ? Range.fromPositions(position) : new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);
				var insert = replace.setEndPosition(position.lineNumber, position.column);

				const client = this._workerManager.withWorker();
				const words =  client.textualSuggest(model.uri, position);

				if (!words) {
					return undefined;
				}
				return {
					suggestions: words.map((word): modes.CompletionItem => {
						return {
							kind: modes.CompletionItemKind.Text,
							label: word,
							insertText: word,
							range: { insert, replace }
						};
					})
				};
			} // else end
		}
	});

Haven't tested else part and quite sure will fail. Just added to give a approach if anyone love to work on this. Else part code is taken from here

@akshay-zz This code is not working as the 'this' in const client = this._workerManager.withWorker(); doesnt point to 'WordBasedCompletionItemProvider' and thus it throws error

@akshay-zz
Copy link
Author

Haven't tested else part and quite sure will fail. Just added to give a approach if anyone love to work on this. Else part code is taken from here.

@Pranomvignesh I never said it will work.

@Pranomvignesh
Copy link
Contributor

Pranomvignesh commented Jun 15, 2020

@akshay-zz I just added my point about why the else part will fail, so that in future the users wont need to work it out to find out what went wrong

@DineshKarri443
Copy link

Has any one able to find a solution for this ? I am also stuck looking for a solution for scenario 3.

@cnayan
Copy link

cnayan commented Jan 3, 2021

I came up with this hack...not the most efficient, but does the job.
I have my snippets combined with words already typed in the editor.

https://gist.github.com/cnayan/23cfde150a83f33a5e4da3b59284ea2b

@DineshKarri443
Copy link

DineshKarri443 commented Jan 3, 2021

The below simple method (could be a hack ) worked for me without much tweaking and merging. Copy paste to monaco playground to check it in action. I used the "range" property. I had to disable consistent-return of eslint as there is nothing in the else part of the "if" check ( I believe you can return empty array [] there and check ).

    monaco.languages.registerCompletionItemProvider('java', {
      provideCompletionItems: (model, position) => {
        const wordBeforePosition = model.getWordUntilPosition({
          lineNumber: position.lineNumber,
          column: position.column - 1,
        });

        const wordUntilPosition = model.getWordUntilPosition(position);
        if (wordBeforePosition.word.trim() === '' ||  wordUntilPosition.word.trim() === '') {
          const keywords = completionTriggerKeywords;

          const suggestions = keywords.map(id => ({
            label: id.label,
            kind: id.kind,
            description: id.description,
            documentation: id.description,
            insertText: id.insertText,
            detail: id.description,
            insertTextRules: id.insertTextRules,
            range: {
              startLineNumber: position.lineNumber,
              startColumn: wordUntilPosition.startColumn,
              endLineNumber: position.lineNumber,
              endColumn: wordUntilPosition.endColumn - 1,
            },
          }));
          return {suggestions};
        }
      },
    });

const completionTriggerKeywords = [
  {
    label: 'Test1',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'Test1',
    description: '1.1, 1.2, 1.3',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  },
  {
    label: 'Test2',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'Test2',
    description: '2.1',
  },
  {
    label: 'Test3',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'Test3',
    description: '3.1, 3.2, 3.3',
  },
  {
    label: 'Test4',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'Test4',
    description: '4.1',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  },
  {
    label: 'Test5',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'Test5',
    description: '5.1',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  },
  {
    label: 'Test6',
    kind: monaco.languages.CompletionItemKind.Function,
    insertText: 'Test6',
    description: '6.1',
    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  },
];


monaco.editor.create(document.getElementById("container"), {
    value: " ",
    language: "java"
});


There could be some unseen issues, but this could be a good starter for someone looking for a solution.

@xixingya
Copy link

Hello,is there a good solution for this issue?

@microsoft microsoft locked and limited conversation to collaborators Mar 13, 2023
@hediet hediet converted this issue into discussion #3824 Mar 13, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
feature-request Request for new features or functionality help wanted Issues identified as good community contribution opportunities suggest
Projects
None yet
Development

No branches or pull requests

8 participants