Merge pull request #783 from ilesinge/hover_tooltip

Implement optional hover tooltip with function documentation
This commit is contained in:
Felix Roos 2023-11-05 22:10:25 +01:00 committed by GitHub
commit 62eb9ce598
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 90 additions and 2 deletions

View file

@ -26,7 +26,6 @@ export function Autocomplete({ doc }) {
<pre <pre
className="cursor-pointer" className="cursor-pointer"
onMouseDown={(e) => { onMouseDown={(e) => {
console.log('ola!');
navigator.clipboard.writeText(example); navigator.clipboard.writeText(example);
e.stopPropagation(); e.stopPropagation();
}} }}

View file

@ -9,6 +9,7 @@ import _CodeMirror from '@uiw/react-codemirror';
import React, { useCallback, useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import strudelTheme from '../themes/strudel-theme'; import strudelTheme from '../themes/strudel-theme';
import { strudelAutocomplete } from './Autocomplete'; import { strudelAutocomplete } from './Autocomplete';
import { strudelTooltip } from './Tooltip';
import { import {
highlightExtension, highlightExtension,
flashField, flashField,
@ -33,6 +34,7 @@ export default function CodeMirror({
keybindings, keybindings,
isLineNumbersDisplayed, isLineNumbersDisplayed,
isAutoCompletionEnabled, isAutoCompletionEnabled,
isTooltipEnabled,
isLineWrappingEnabled, isLineWrappingEnabled,
fontSize = 18, fontSize = 18,
fontFamily = 'monospace', fontFamily = 'monospace',
@ -94,6 +96,10 @@ export default function CodeMirror({
_extensions.push(autocompletion({ override: [] })); _extensions.push(autocompletion({ override: [] }));
} }
if (isTooltipEnabled) {
_extensions.push(strudelTooltip);
}
_extensions.push([keymap.of({})]); _extensions.push([keymap.of({})]);
if (isLineWrappingEnabled) { if (isLineWrappingEnabled) {
@ -101,7 +107,7 @@ export default function CodeMirror({
} }
return _extensions; return _extensions;
}, [keybindings, isAutoCompletionEnabled, isLineWrappingEnabled]); }, [keybindings, isAutoCompletionEnabled, isTooltipEnabled, isLineWrappingEnabled]);
const basicSetup = useMemo(() => ({ lineNumbers: isLineNumbersDisplayed }), [isLineNumbersDisplayed]); const basicSetup = useMemo(() => ({ lineNumbers: isLineNumbersDisplayed }), [isLineNumbersDisplayed]);

View file

@ -0,0 +1,69 @@
import { createRoot } from 'react-dom/client';
import { hoverTooltip } from '@codemirror/view';
import jsdoc from '../../../../doc.json';
import { Autocomplete } from './Autocomplete';
const getDocLabel = (doc) => doc.name || doc.longname;
let ctrlDown = false;
// Record Control key event to trigger or block the tooltip depending on the state
window.addEventListener(
'keyup',
function (e) {
if (e.key == 'Control') {
ctrlDown = false;
}
},
true,
);
window.addEventListener(
'keydown',
function (e) {
if (e.key == 'Control') {
ctrlDown = true;
}
},
true,
);
export const strudelTooltip = hoverTooltip(
(view, pos, side) => {
// Word selection from CodeMirror Hover Tooltip example https://codemirror.net/examples/tooltip/#hover-tooltips
let { from, to, text } = view.state.doc.lineAt(pos);
let start = pos,
end = pos;
while (start > from && /\w/.test(text[start - from - 1])) {
start--;
}
while (end < to && /\w/.test(text[end - from])) {
end++;
}
if ((start == pos && side < 0) || (end == pos && side > 0)) {
return null;
}
let word = text.slice(start - from, end - from);
// Get entry from Strudel documentation
let entry = jsdoc.docs.filter((doc) => getDocLabel(doc) === word)[0];
if (!entry) {
return null;
}
if (!ctrlDown) {
return null;
}
return {
pos: start,
end,
above: false,
arrow: true,
create(view) {
let dom = document.createElement('div');
dom.className = 'strudel-tooltip';
createRoot(dom).render(<Autocomplete doc={entry} />);
return { dom };
},
};
},
{ hoverTime: 10 },
);

View file

@ -28,3 +28,7 @@
footer { footer {
z-index: 0 !important; z-index: 0 !important;
} }
.strudel-tooltip {
padding: 5px;
}

View file

@ -385,6 +385,7 @@ function SettingsTab({ scheduler }) {
keybindings, keybindings,
isLineNumbersDisplayed, isLineNumbersDisplayed,
isAutoCompletionEnabled, isAutoCompletionEnabled,
isTooltipEnabled,
isLineWrappingEnabled, isLineWrappingEnabled,
fontSize, fontSize,
fontFamily, fontFamily,
@ -457,6 +458,11 @@ function SettingsTab({ scheduler }) {
onChange={(cbEvent) => settingsMap.setKey('isAutoCompletionEnabled', cbEvent.target.checked)} onChange={(cbEvent) => settingsMap.setKey('isAutoCompletionEnabled', cbEvent.target.checked)}
value={isAutoCompletionEnabled} value={isAutoCompletionEnabled}
/> />
<Checkbox
label="Enable tooltips on Ctrl and hover"
onChange={(cbEvent) => settingsMap.setKey('isTooltipEnabled', cbEvent.target.checked)}
value={isTooltipEnabled}
/>
<Checkbox <Checkbox
label="Enable line wrapping" label="Enable line wrapping"
onChange={(cbEvent) => settingsMap.setKey('isLineWrappingEnabled', cbEvent.target.checked)} onChange={(cbEvent) => settingsMap.setKey('isLineWrappingEnabled', cbEvent.target.checked)}

View file

@ -126,6 +126,7 @@ export function Repl({ embedded = false }) {
fontFamily, fontFamily,
isLineNumbersDisplayed, isLineNumbersDisplayed,
isAutoCompletionEnabled, isAutoCompletionEnabled,
isTooltipEnabled,
isLineWrappingEnabled, isLineWrappingEnabled,
panelPosition, panelPosition,
isZen, isZen,
@ -335,6 +336,7 @@ export function Repl({ embedded = false }) {
keybindings={keybindings} keybindings={keybindings}
isLineNumbersDisplayed={isLineNumbersDisplayed} isLineNumbersDisplayed={isLineNumbersDisplayed}
isAutoCompletionEnabled={isAutoCompletionEnabled} isAutoCompletionEnabled={isAutoCompletionEnabled}
isTooltipEnabled={isTooltipEnabled}
isLineWrappingEnabled={isLineWrappingEnabled} isLineWrappingEnabled={isLineWrappingEnabled}
fontSize={fontSize} fontSize={fontSize}
fontFamily={fontFamily} fontFamily={fontFamily}

View file

@ -7,6 +7,7 @@ export const defaultSettings = {
keybindings: 'codemirror', keybindings: 'codemirror',
isLineNumbersDisplayed: true, isLineNumbersDisplayed: true,
isAutoCompletionEnabled: false, isAutoCompletionEnabled: false,
isTooltipEnabled: false,
isLineWrappingEnabled: false, isLineWrappingEnabled: false,
theme: 'strudelTheme', theme: 'strudelTheme',
fontFamily: 'monospace', fontFamily: 'monospace',
@ -26,6 +27,7 @@ export function useSettings() {
isZen: [true, 'true'].includes(state.isZen) ? true : false, isZen: [true, 'true'].includes(state.isZen) ? true : false,
isLineNumbersDisplayed: [true, 'true'].includes(state.isLineNumbersDisplayed) ? true : false, isLineNumbersDisplayed: [true, 'true'].includes(state.isLineNumbersDisplayed) ? true : false,
isAutoCompletionEnabled: [true, 'true'].includes(state.isAutoCompletionEnabled) ? true : false, isAutoCompletionEnabled: [true, 'true'].includes(state.isAutoCompletionEnabled) ? true : false,
isTooltipEnabled: [true, 'true'].includes(state.isTooltipEnabled) ? true : false,
isLineWrappingEnabled: [true, 'true'].includes(state.isLineWrappingEnabled) ? true : false, isLineWrappingEnabled: [true, 'true'].includes(state.isLineWrappingEnabled) ? true : false,
fontSize: Number(state.fontSize), fontSize: Number(state.fontSize),
panelPosition: state.activeFooter !== '' ? state.panelPosition : 'bottom', panelPosition: state.activeFooter !== '' ? state.panelPosition : 'bottom',