Skip to content

[Cm 5-> 6 conversion] autocomplete #3582

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

Open
wants to merge 7 commits into
base: develop-codemirror-v6
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions client/modules/IDE/components/Editor/codemirror.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useRef, useEffect } from 'react';
import { EditorView, lineNumbers as lineNumbersExt } from '@codemirror/view';
import { closeBrackets } from '@codemirror/autocomplete';
import { autocompletion, closeBrackets } from '@codemirror/autocomplete';

// TODO: Check what the v6 variants of these addons are.
// import 'codemirror/addon/search/searchcursor';
Expand All @@ -13,7 +13,8 @@ import { debounce } from 'lodash';
import {
getFileMode,
createNewFileState,
updateFileStates
updateFileStates,
AUTOCOMPLETE_OPTIONS
} from './stateUtils';
import { useEffectWithComparison } from '../../hooks/custom-hooks';
import tidyCodeWithPrettier from './tidier';
Expand Down Expand Up @@ -141,6 +142,18 @@ export default function useCodeMirror({
reconfigureEffect
});
}, [autocloseBracketsQuotes]);
useEffect(() => {
const reconfigureEffect = (fileState) =>
fileState.autocompleteCpt.reconfigure(
autocompleteHinter ? autocompletion(AUTOCOMPLETE_OPTIONS) : []
);
updateFileStates({
fileStates: fileStates.current,
cmView: cmView.current,
file,
reconfigureEffect
});
}, [autocompleteHinter]);

// Initializes the files as CodeMirror states.
function initializeDocuments() {
Expand All @@ -160,6 +173,7 @@ export default function useCodeMirror({
linewrap,
lineNumbers,
autocloseBracketsQuotes,
autocomplete: autocompleteHinter,
onUpdateLinting,
onViewUpdate
}
Expand Down
54 changes: 54 additions & 0 deletions client/modules/IDE/components/Editor/p5JavaScript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { LanguageSupport } from '@codemirror/language';
import { javascript } from '@codemirror/lang-javascript';
import { p5Hinter } from '../../../../utils/p5-hinter';

function testCompletions(context) {
const word = context.matchBefore(/\w*/);
if (word.from === word.to && !context.explicit) return null;

function addDomNodeInfo(item) {
const itemCopy = { ...item };

if (item.p5DocPath) {
// TODO: Use the option below to add the p5 link for *all* hints.
// https://codemirror.net/docs/ref/#autocomplete.autocompletion^config.addToOptions
itemCopy.info = () => {
const domNode = document.createElement('a');
domNode.href = `https://p5js.org/reference/p5/${item.p5DocPath}`;
domNode.role = 'link';
domNode.target = '_blank';
domNode.onclick = (event) => event.stopPropagation();
domNode.innerHTML = `
<span class="hint-hidden">open ${item.label} reference</span>
<span aria-hidden="true">&#10132;</span>
`;
return {
dom: domNode,
destroy: () => {
// Cleanup logic if needed
domNode.remove();
}
};
};
}

return itemCopy;
}

const hinterWithDomNodes = p5Hinter.map(addDomNodeInfo);

return {
from: word.from,
options: hinterWithDomNodes
};
}

export default function p5JavaScript() {
const jsLang = javascript();
return new LanguageSupport(jsLang.language, [
jsLang.extension,
jsLang.language.data.of({
autocomplete: testCompletions
})
]);
}
29 changes: 25 additions & 4 deletions client/modules/IDE/components/Editor/stateUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ import {
defaultHighlightStyle
} from '@codemirror/language';
import { highlightSelectionMatches } from '@codemirror/search';
import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
import {
autocompletion,
closeBrackets,
closeBracketsKeymap
} from '@codemirror/autocomplete';
import {
defaultKeymap,
history,
Expand All @@ -36,7 +40,6 @@ import {
abbreviationTracker
} from '@emmetio/codemirror6-plugin';

import { javascript } from '@codemirror/lang-javascript';
import { css } from '@codemirror/lang-css';
import { html } from '@codemirror/lang-html';
import { json } from '@codemirror/lang-json';
Expand All @@ -47,6 +50,7 @@ import { HTMLHint } from 'htmlhint';
import { CSSLint } from 'csslint';
import { emmetConfig } from '@emmetio/codemirror6-plugin';

import p5JavaScript from './p5JavaScript';
import tidyCodeWithPrettier from './tidier';

// ----- TODOS -----
Expand Down Expand Up @@ -83,7 +87,7 @@ function getFileLanguage(fileName) {

switch (fileMode) {
case 'javascript':
return javascript;
return p5JavaScript;
case 'css':
return css;
case 'html':
Expand Down Expand Up @@ -255,6 +259,12 @@ function getFileEmmetConfig(fileName) {
const extraKeymaps = [{ key: 'Tab', run: insertTab, shift: indentLess }];
const emmetKeymaps = [{ key: 'Tab', run: expandAbbreviation }];

export const AUTOCOMPLETE_OPTIONS = {
tooltipClass: () => 'CodeMirror-hints',
optionClass: () => 'CodeMirror-hint',
closeOnBlur: false
};

/**
* Creates a new CodeMirror editor state with configurations,
* extensions, and keymaps tailored to the file type and settings.
Expand All @@ -265,13 +275,15 @@ export function createNewFileState(filename, document, settings) {
const {
linewrap,
lineNumbers,
autocomplete,
autocloseBracketsQuotes,
onUpdateLinting,
onViewUpdate
} = settings;
const lineNumbersCpt = new Compartment();
const lineWrappingCpt = new Compartment();
const closeBracketsCpt = new Compartment();
const autocompleteCpt = new Compartment();

// Depending on the file mode, we have a different tidier function.
const mode = getFileMode(filename);
Expand All @@ -294,6 +306,9 @@ export function createNewFileState(filename, document, settings) {
lineNumbersCpt.of(lineNumbers ? lineNumbersExt() : []),
lineWrappingCpt.of(linewrap ? EditorView.lineWrapping : []),
closeBracketsCpt.of(autocloseBracketsQuotes ? closeBrackets() : []),
autocompleteCpt.of(
autocomplete ? autocompletion(AUTOCOMPLETE_OPTIONS) : []
),

// Everything below here should always be on.
history(),
Expand Down Expand Up @@ -352,7 +367,13 @@ export function createNewFileState(filename, document, settings) {
}

const cmState = EditorState.create(stateOptions);
return { cmState, lineNumbersCpt, lineWrappingCpt, closeBracketsCpt };
return {
cmState,
lineNumbersCpt,
lineWrappingCpt,
closeBracketsCpt,
autocompleteCpt
};
}

/**
Expand Down
Loading