How to get autocomplete working for a custom language with Monaco (suggest box no rendering properly)? #513
-
I finally got this somewhat working after several hours: /* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import Editor, { Monaco } from '@monaco-editor/react'
import type monaco from 'monaco-editor'
import React, { useEffect, useState } from 'react'
import styled from 'styled-components'
import draculaTheme from '~/configurations/dracula.monaco.json'
const BEAD = 'bead'
export const configuration: monaco.languages.LanguageConfiguration = {
brackets: [
['{', '}'],
['[', ']'],
['(', ')'],
],
comments: {
lineComment: '#',
},
wordPattern: /\w+/,
}
function createDependencyProposals(
monaco: Monaco,
range: monaco.IRange,
): Array<monaco.languages.CompletionItem> {
return [
{
documentation: 'beautiful',
insertText: 'byut',
kind: monaco.languages.CompletionItemKind.Text,
label: 'beautiful',
range,
},
{
documentation: 'baby',
insertText: 'beb',
kind: monaco.languages.CompletionItemKind.Text,
label: 'baby',
range,
},
]
}
// https://github.com/tatomyr/estimate-it/blob/master/src/components/Estimate/Editor.js
export const languageDef: monaco.languages.IMonarchLanguage = {
defaultToken: '',
start: 'start',
tokenizer: {
keywords: [[/\w+/, 'keyword']],
start: [{ include: '@keywords' }, { include: '@whitespace' }],
whitespace: [[/\s+/, 'white']],
},
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function initializeEditor(monaco: Monaco) {
monaco.editor.defineTheme(
'dracula',
draculaTheme as monaco.editor.IStandaloneThemeData,
)
monaco.languages.register({ id: BEAD })
monaco.languages.setMonarchTokensProvider(
BEAD,
languageDef as monaco.languages.IMonarchLanguage,
)
monaco.languages.setLanguageConfiguration(
BEAD,
configuration as monaco.languages.LanguageConfiguration,
)
const completion = monaco.languages.registerCompletionItemProvider(
{ language: BEAD },
{
provideCompletionItems: function (
model: monaco.editor.ITextModel,
position: monaco.Position,
) {
const range = {
endColumn: position.column,
endLineNumber: position.lineNumber,
startColumn: 1,
startLineNumber: position.lineNumber,
}
console.log(range)
var textUntilPosition = model.getValueInRange(range)
return {
suggestions: createDependencyProposals(monaco, range),
}
return { suggestions: [] }
},
triggerCharacters: ['b'],
},
)
return completion
}
type TextEditorPropsType = {
defaultLanguage: string
height: string | number
lineNumbers?: boolean
onChange?: (string?: string) => void
readOnly?: boolean
value?: string
}
const Container = styled.div(props => ({
background: props.theme.colors.black,
marginBottom: 16,
marginTop: 16,
paddingBottom: 16,
paddingLeft: 16,
paddingTop: 16,
}))
export default function TextEditor({
height,
defaultLanguage,
onChange,
lineNumbers,
readOnly,
value,
}: TextEditorPropsType) {
const [completionDisposable, setCompletionDisposable] =
useState<monaco.IDisposable>()
const handleBeforeMount = (monaco: Monaco) => {
setCompletionDisposable(initializeEditor(monaco))
}
// useEffect(() => {
// ;() => completionDisposable?.dispose()
// }, [completionDisposable])
return (
<Container>
<Editor
height={height}
theme="dracula"
value={value}
language={BEAD}
beforeMount={handleBeforeMount}
onChange={onChange}
onMount={editor => {
editor.focus()
}}
options={{
acceptSuggestionOnEnter: 'on',
autoClosingBrackets: 'always',
contextmenu: false,
cursorStyle: 'line',
fontSize: 16,
hover: {
enabled: true,
},
// inlineSuggest: {
// enabled: true,
// suppressSuggestions: false,
// },
minimap: {
enabled: false,
},
parameterHints: {
enabled: true,
},
quickSuggestions: true,
readOnly,
scrollbar: {
alwaysConsumeMouseWheel: false,
// handleMouseWheel: false,
},
// suggest: {
// selectionMode: 'always',
// shareSuggestSelections: true,
// showKeywords: true,
// showWords: true,
// snippetsPreventQuickSuggestions: false,
// },
suggestOnTriggerCharacters: false,
tabCompletion: 'on',
tabSize: 2,
wordBasedSuggestions: true,
// wordBasedSuggestionsOnlySameLanguage: false,
wordWrap: 'off',
...(lineNumbers
? {}
: {
folding: false,
glyphMargin: false,
lineDecorationsWidth: 0,
lineNumbers: 'off',
lineNumbersMinChars: 0,
}),
}}
/>
</Container>
)
} It is for a markdown-like language, where I want to autocomplete every word (to translate it from English to a fantasy language word). However, it shows up like this:
What am I missing here? I am using Next.js v13.1.5, and I think it handles loading the CSS automatically. For example, I see this in my web debugger:
So I imagine the styles are loading correctly, but why then is the popup all out of place? And why is nothing showing up in the content? Any help or guidance would be greatly appreciated. Thanks for your time and support! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Beta Was this translation helpful? Give feedback.
Alright
unset
on the margin and padding works, I had a global default ofpadding: 0; margin: 0;
before.Yay!
Hope that helps someone stuck in a random rabbit hole like me haha.