diff --git a/src/renderer/addEditorTooltips.tsx b/src/renderer/addEditorTooltips.tsx index ea42b96..6323052 100644 --- a/src/renderer/addEditorTooltips.tsx +++ b/src/renderer/addEditorTooltips.tsx @@ -1,30 +1,39 @@ import { Ace, require as acequire } from 'ace-builds'; +import { ReactNode } from 'react'; import { createRoot } from 'react-dom/client'; +import readApiCall from './readApiCall'; const { HoverTooltip } = acequire('ace/tooltip'); const { TokenIterator } = acequire('ace/token_iterator'); +const apiHelpComponents: { + [matchText: string]: () => ReactNode; +}[] = { + 'Robot.get_value': () => ( +
+ Documentation for Robot.get_value method. +
+ ), + 'Robot': () => ( +
+ Documentation for Robot object. +
+ ), +}; + export default function addEditorTooltips(editor: Ace.Editor) { const tooltip = new HoverTooltip(); + const node = document.createElement('div'); + const root = createRoot(node); + const maxMatchTextLength = Math.max(...Object.keys(apiHelpComponents).map(s => s.length)); tooltip.setDataProvider((event: any, _editor: Ace.Editor) => { const pos: Ace.Position = event.getDocumentPosition(); const range = editor.session.getWordRange(pos.row, pos.column); - const node = document.createElement('div'); - const root = createRoot(node); - root.render( - Hello world! - ); - const observer = new MutationObserver((_mutations) => { - if (!document.contains(node)) { - observer.disconnect(); - root.unmount(); - } - }); - observer.observe(document, { - childList: true, - subtree: true, - }); - tooltip.showForRange(editor, range, node, event); + const result = readApiCall(editor.getSession(), range.end, maxMatchTextLength); + if (!result.isInterrupted && result.text in apiHelpComponents) { + root.render(apiHelpComponents[result.text]()); + tooltip.showForRange(editor, range, node, event); + } }); tooltip.addToEditor(editor); } diff --git a/src/renderer/readApiCall.ts b/src/renderer/readApiCall.ts index 3c76db9..a503e3c 100644 --- a/src/renderer/readApiCall.ts +++ b/src/renderer/readApiCall.ts @@ -9,11 +9,12 @@ const { TokenIterator } = acequire('ace/token_iterator'); * are ignored, and string collections continues on the other side of the comment. * @param session - the Ace editing session to use to read the editor contents. * @param pos - the position to start reading behind. - * @param minLength - the minimum length of text to read. + * @param minLength - the minimum length in characters of text to read. A whole number of tokens + * will always be read, but reading is stopped after reading at least this many characters. * @return The text of the read "API call" and whether the text was interrupted, i.e. interspersed * with a comment or starting on a different line than the cursor position. */ -export default (session: Ace.Session, pos: Ace.Position, minLength: number): { +export default (session: Ace.EditSession, pos: Ace.Position, minLength: number): { text: string; isInterrupted: boolean; } => {