diff --git a/client/modules/IDE/actions/ide.js b/client/modules/IDE/actions/ide.js
index 80a43443bc..ad16cd9a5d 100644
--- a/client/modules/IDE/actions/ide.js
+++ b/client/modules/IDE/actions/ide.js
@@ -236,23 +236,10 @@ export function hideErrorModal() {
};
}
-export function hideRuntimeErrorWarning() {
- return {
- type: ActionTypes.HIDE_RUNTIME_ERROR_WARNING
- };
-}
-
-export function showRuntimeErrorWarning() {
- return {
- type: ActionTypes.SHOW_RUNTIME_ERROR_WARNING
- };
-}
-
export function startSketch() {
return (dispatch, getState) => {
dispatch(clearConsole());
dispatch(startVisualSketch());
- dispatch(showRuntimeErrorWarning());
const state = getState();
dispatchMessage({
type: MessageTypes.SKETCH,
diff --git a/client/modules/IDE/components/ConsoleInput.jsx b/client/modules/IDE/components/ConsoleInput.jsx
index 3806db0381..41fc729d4b 100644
--- a/client/modules/IDE/components/ConsoleInput.jsx
+++ b/client/modules/IDE/components/ConsoleInput.jsx
@@ -1,6 +1,16 @@
import PropTypes from 'prop-types';
-import React, { useRef, useEffect, useState } from 'react';
-import CodeMirror from 'codemirror';
+import React, { useRef, useEffect } from 'react';
+import { EditorState } from '@codemirror/state';
+import { EditorView, highlightSpecialChars, keymap } from '@codemirror/view';
+import {
+ bracketMatching,
+ syntaxHighlighting,
+ defaultHighlightStyle
+} from '@codemirror/language';
+import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
+import { defaultKeymap, history, historyKeymap } from '@codemirror/commands';
+import { javascript } from '@codemirror/lang-javascript';
+
import { useDispatch } from 'react-redux';
import { Encode } from 'console-feed';
@@ -11,31 +21,24 @@ import { dispatchMessage, MessageTypes } from '../../../utils/dispatcher';
// heavily inspired by
// https://github.com/codesandbox/codesandbox-client/blob/92a1131f4ded6f7d9c16945dc7c18aa97c8ada27/packages/app/src/app/components/Preview/DevTools/Console/Input/index.tsx
+// TODO(connie): Add theme support?
function ConsoleInput({ theme, fontSize }) {
- const [commandHistory, setCommandHistory] = useState([]);
- const [commandCursor, setCommandCursor] = useState(-1);
+ const commandHistory = useRef([]);
+ const commandCursor = useRef(-1);
const codemirrorContainer = useRef(null);
- const cmInstance = useRef(null);
+ const cmView = useRef(null);
const dispatch = useDispatch();
useEffect(() => {
- cmInstance.current = CodeMirror(codemirrorContainer.current, {
- theme: `p5-${theme}`,
- scrollbarStyle: null,
- keymap: 'sublime',
- mode: 'javascript',
- inputStyle: 'contenteditable'
- });
- }, []);
-
- useEffect(() => {
- const handleEnterKey = (cm, e) => {
- if (e.key === 'Enter' && !e.shiftKey) {
- e.preventDefault();
- e.stopPropagation();
-
- const value = cm.getValue().trim();
- if (value === '') return;
+ const enterKeymap = {
+ key: 'Enter',
+ shiftKey: () => false, // Treat like a normal Enter key press if the Shift key is held down.
+ preventDefault: true,
+ stopPropogation: true,
+ run: (view) => {
+ const value = view.state.doc.toString().trim();
+ if (value === '' || view.state.selection.main.empty === false)
+ return false;
const messages = [
{ log: Encode({ method: 'command', data: [value] }) }
@@ -48,77 +51,91 @@ function ConsoleInput({ theme, fontSize }) {
});
dispatch(dispatchConsoleEvent(consoleEvent));
- cm.setValue('');
- setCommandHistory([value, ...commandHistory]);
- setCommandCursor(-1);
- }
- };
-
- if (cmInstance.current) {
- cmInstance.current.on('keydown', handleEnterKey);
- }
-
- return () => {
- if (cmInstance.current) {
- cmInstance.current.off('keydown', handleEnterKey);
+ view.dispatch({
+ changes: { from: 0, to: view.state.doc.length, insert: '' }
+ });
+ commandHistory.current.unshift(value);
+ commandCursor.current = -1;
+ return true;
}
};
- }, [commandHistory]);
- useEffect(() => {
- const handleUpArrowKey = (cm, e) => {
- if (e.key === 'ArrowUp') {
- const lineNumber = cm.getDoc().getCursor().line;
- if (lineNumber !== 0) return;
+ const upArrowKeymap = {
+ key: 'ArrowUp',
+ run: (view) => {
+ // Just let the cursor go up if we have a multiline input
+ // and the cursor isn't at the first line.
+ const currentLine = view.state.doc.lineAt(
+ view.state.selection.main.head
+ ).number;
+ // CM lines are 1-indexed, so the first line is 1.
+ if (currentLine > 1) return false;
const newCursor = Math.min(
- commandCursor + 1,
- commandHistory.length - 1
+ commandCursor.current + 1,
+ commandHistory.current.length - 1
);
- cm.setValue(commandHistory[newCursor] || '');
- const cursorPos = cm.getDoc().getLine(0).length - 1;
- cm.getDoc().setCursor({ line: 0, ch: cursorPos });
- setCommandCursor(newCursor);
- }
- };
-
- if (cmInstance.current) {
- cmInstance.current.on('keydown', handleUpArrowKey);
- }
-
- return () => {
- if (cmInstance.current) {
- cmInstance.current.off('keydown', handleUpArrowKey);
+ const newValue = commandHistory.current[newCursor] || '';
+ view.dispatch({
+ changes: { from: 0, to: view.state.doc.length, insert: newValue }
+ });
+ const newCursorPos = newValue.length;
+ view.dispatch({
+ selection: { anchor: newCursorPos, head: newCursorPos }
+ });
+ commandCursor.current = newCursor;
+ return true;
}
};
- }, [commandCursor, commandHistory]);
- useEffect(() => {
- const handleArrowDownKey = (cm, e) => {
- if (e.key === 'ArrowDown') {
- const lineNumber = cm.getDoc().getCursor().line;
- const lineCount = cm.lineCount();
- if (lineNumber + 1 !== lineCount) return;
-
- const newCursor = Math.max(commandCursor - 1, -1);
- cm.setValue(commandHistory[newCursor] || '');
- const newLine = cm.getDoc().getLine(lineCount - 1);
- const cursorPos = newLine ? newLine.length - 1 : 1;
- cm.getDoc().setCursor({ line: lineCount - 1, ch: cursorPos });
- setCommandCursor(newCursor);
+ const downArrowKeymap = {
+ key: 'ArrowDown',
+ run: (view) => {
+ // Just let the cursor go down if we have a multiline input
+ // and the cursor isn't at the last line.
+ const currentLine = view.state.doc.lineAt(
+ view.state.selection.main.head
+ ).number;
+ const docLength = view.state.doc.lines;
+ if (currentLine !== docLength) return false;
+
+ const newCursor = Math.max(commandCursor.current - 1, -1);
+ const newValue = commandHistory.current[newCursor] || '';
+ view.dispatch({
+ changes: { from: 0, to: view.state.doc.length, insert: newValue }
+ });
+ const newCursorPos = newValue.length;
+ view.dispatch({
+ selection: { anchor: newCursorPos, head: newCursorPos }
+ });
+ commandCursor.current = newCursor;
+ return true;
}
};
- if (cmInstance.current) {
- cmInstance.current.on('keydown', handleArrowDownKey);
- }
-
- return () => {
- if (cmInstance.current) {
- cmInstance.current.off('keydown', handleArrowDownKey);
- }
- };
- }, [commandCursor, commandHistory]);
+ const cmState = EditorState.create({
+ extensions: [
+ history(),
+ highlightSpecialChars(),
+ bracketMatching(),
+ closeBrackets(),
+ syntaxHighlighting(defaultHighlightStyle),
+ javascript(),
+ keymap.of([
+ enterKeymap,
+ upArrowKeymap,
+ downArrowKeymap,
+ ...defaultKeymap,
+ ...closeBracketsKeymap,
+ ...historyKeymap
+ ])
+ ]
+ });
+ cmView.current = new EditorView({
+ state: cmState,
+ parent: codemirrorContainer.current
+ });
+ }, []);
return (
diff --git a/client/modules/IDE/components/Editor/codemirror.js b/client/modules/IDE/components/Editor/codemirror.js
new file mode 100644
index 0000000000..1e44007f84
--- /dev/null
+++ b/client/modules/IDE/components/Editor/codemirror.js
@@ -0,0 +1,240 @@
+import { useRef, useEffect } from 'react';
+import { EditorView, lineNumbers as lineNumbersExt } from '@codemirror/view';
+import { autocompletion, closeBrackets } from '@codemirror/autocomplete';
+import { debounce } from 'lodash';
+import { openSearchPanel } from '@codemirror/search';
+import { saveLocalBackup } from '../../utils/localBackup';
+
+import {
+ getFileMode,
+ createNewFileState,
+ updateFileStates
+} from './utils/fileState';
+import { createAutocompleteOptions } from './utils/extensionCustomStyles';
+import { useEffectWithComparison } from '../../hooks/custom-hooks';
+import { tidyCodeWithPrettier } from './utils/tidier';
+
+// ----- GENERAL TODOS (in order of priority) -----
+// - revisit keymap differences, esp around sublime
+// - emmet doesn't trigger if text is copy pasted in
+// - need to re-implement emmet auto rename tag
+// - clike addon
+
+/** This is a custom React hook that manages CodeMirror state. */
+export default function useCodeMirror({
+ project,
+ lineNumbers,
+ linewrap,
+ autocloseBracketsQuotes,
+ setUnsavedChanges,
+ setCurrentLine,
+ updateFileContent,
+ file,
+ files,
+ autorefresh,
+ clearConsole,
+ startSketch,
+ autocompleteHinter,
+ fontSize,
+ onUpdateLinting,
+ referenceBaseUrl
+}) {
+ // The codemirror instance.
+ const cmView = useRef();
+ // The current codemirror files.
+ const fileStates = useRef();
+
+ // We store values used by the debounced onChange callback in a ref.
+ // Otherwise it can hold onto stale React state
+ const onChangeStateRef = useRef({});
+ onChangeStateRef.current = {
+ fileId: file.id,
+ autorefresh,
+ project,
+ files
+ };
+
+ // When the file changes, update the file content and save status.
+ function onChange() {
+ const state = onChangeStateRef.current;
+
+ setUnsavedChanges(true);
+ updateFileContent(state.fileId, cmView.current.state.doc.toString());
+
+ // Save a local backup to localStorage for crash recovery (#3891).
+ // This ensures work is recoverable even if the tab crashes
+ // (e.g. from an infinite loop) before the server autosave fires.
+ const projectId = state.project?.id || 'unsaved';
+ saveLocalBackup(projectId, state.files);
+
+ if (state.autorefresh) {
+ clearConsole();
+ startSketch();
+ }
+ }
+ // Call onChange at most once every second.
+ const debouncedOnChange = debounce(onChange, 1000);
+
+ // This is called when the CM view updates.
+ function onViewUpdate(updateView) {
+ const { state } = updateView;
+
+ // TODO - check if need to subtract one
+ setCurrentLine(state.doc.lineAt(state.selection.main.head).number);
+
+ if (updateView.docChanged) {
+ debouncedOnChange();
+ }
+ }
+
+ // When the container component enters the DOM, we want this function
+ // to be called so we can setup the CodeMirror instance with the container.
+ function setupCodeMirrorOnContainerMounted(container) {
+ cmView.current = new EditorView({
+ parent: container
+ });
+ }
+
+ // When the component unmounts, we want to clean up the CodeMirror instance.
+ function teardownCodeMirror() {
+ if (cmView.current) {
+ cmView.current.destroy();
+ cmView.current = null;
+ }
+ }
+
+ // When settings change, we pass those changes into CodeMirror.
+ useEffect(() => {
+ const reconfigureEffect = (fileState) =>
+ fileState.fontSizeCpt.reconfigure(
+ EditorView.theme({ '&': { fontSize: `${fontSize}px` } })
+ );
+ updateFileStates({
+ fileStates: fileStates.current,
+ cmView: cmView.current,
+ file,
+ reconfigureEffect
+ });
+ }, [fontSize]);
+ useEffect(() => {
+ const reconfigureEffect = (fileState) =>
+ fileState.lineWrappingCpt.reconfigure(
+ linewrap ? EditorView.lineWrapping : []
+ );
+ updateFileStates({
+ fileStates: fileStates.current,
+ cmView: cmView.current,
+ file,
+ reconfigureEffect
+ });
+ }, [linewrap]);
+ useEffect(() => {
+ const reconfigureEffect = (fileState) =>
+ fileState.lineNumbersCpt.reconfigure(lineNumbers ? lineNumbersExt() : []);
+ updateFileStates({
+ fileStates: fileStates.current,
+ cmView: cmView.current,
+ file,
+ reconfigureEffect
+ });
+ }, [lineNumbers]);
+ useEffect(() => {
+ const reconfigureEffect = (fileState) =>
+ fileState.closeBracketsCpt.reconfigure(
+ autocloseBracketsQuotes ? closeBrackets() : []
+ );
+ updateFileStates({
+ fileStates: fileStates.current,
+ cmView: cmView.current,
+ file,
+ reconfigureEffect
+ });
+ }, [autocloseBracketsQuotes]);
+ useEffect(() => {
+ const reconfigureEffect = (fileState) =>
+ fileState.autocompleteCpt.reconfigure(
+ autocompleteHinter
+ ? autocompletion(createAutocompleteOptions(referenceBaseUrl))
+ : []
+ );
+ updateFileStates({
+ fileStates: fileStates.current,
+ cmView: cmView.current,
+ file,
+ reconfigureEffect
+ });
+ }, [autocompleteHinter, referenceBaseUrl]);
+
+ // Initializes the files as CodeMirror states.
+ function initializeDocuments() {
+ if (!fileStates.current) {
+ fileStates.current = {};
+ }
+
+ files.forEach((currentFile) => {
+ if (
+ currentFile.name !== 'root' &&
+ !(currentFile.id in fileStates.current)
+ ) {
+ fileStates.current[currentFile.id] = createNewFileState(
+ currentFile.name,
+ currentFile.content,
+ {
+ linewrap,
+ lineNumbers,
+ autocloseBracketsQuotes,
+ autocomplete: autocompleteHinter,
+ onUpdateLinting,
+ onViewUpdate,
+ referenceBaseUrl,
+ fontSize
+ }
+ );
+ }
+ });
+ }
+
+ // When the files change, reinitialize the documents.
+ useEffect(initializeDocuments, [files]);
+
+ // When the file changes, make the CodeMirror call to swap out the document.
+ useEffectWithComparison(
+ (_, prevProps) => {
+ // We need to save the previous CodeMirror state so we can restore it
+ // when we switch back to it.
+ const previousState = cmView.current.state;
+ if (Array.isArray(prevProps) && prevProps.length > 0 && previousState) {
+ const prevId = prevProps[0];
+ fileStates.current[prevId].cmState = previousState;
+ }
+
+ const { cmState } = fileStates.current[file.id];
+ cmView.current.setState(cmState);
+ },
+ [file.id]
+ );
+
+ const getContent = () => {
+ const content = cmView.current.state.doc.toString();
+ const updatedFile = Object.assign({}, file, { content });
+ return updatedFile;
+ };
+
+ const showSearch = () => {
+ openSearchPanel(cmView.current);
+ };
+
+ const tidyCode = () => {
+ const fileMode = getFileMode(file.name);
+ tidyCodeWithPrettier(cmView.current, fileMode);
+ };
+
+ return {
+ setupCodeMirrorOnContainerMounted,
+ teardownCodeMirror,
+ getContent,
+ tidyCode,
+ showSearch,
+ codemirrorView: cmView
+ };
+}
diff --git a/client/modules/IDE/components/Editor/index.jsx b/client/modules/IDE/components/Editor/index.jsx
index 4bbfffc1f4..f7996020f5 100644
--- a/client/modules/IDE/components/Editor/index.jsx
+++ b/client/modules/IDE/components/Editor/index.jsx
@@ -1,55 +1,13 @@
-// TODO: convert to functional component
-
import PropTypes from 'prop-types';
-import React from 'react';
-import CodeMirror from 'codemirror';
-import Fuse from 'fuse.js';
-import emmet from '@emmetio/codemirror-plugin';
-import prettier from 'prettier/standalone';
-import babelParser from 'prettier/parser-babel';
-import htmlParser from 'prettier/parser-html';
-import cssParser from 'prettier/parser-postcss';
+import React, { useCallback, useEffect, useRef, useState } from 'react';
import { withTranslation } from 'react-i18next';
import StackTrace from 'stacktrace-js';
-import 'codemirror/mode/css/css';
-import 'codemirror/mode/clike/clike';
-import 'codemirror/addon/selection/active-line';
-import 'codemirror/addon/lint/lint';
-import 'codemirror/addon/lint/javascript-lint';
-import 'codemirror/addon/lint/css-lint';
-import 'codemirror/addon/lint/html-lint';
-import 'codemirror/addon/fold/brace-fold';
-import 'codemirror/addon/fold/comment-fold';
-import 'codemirror/addon/fold/foldcode';
-import 'codemirror/addon/fold/foldgutter';
-import 'codemirror/addon/fold/indent-fold';
-import 'codemirror/addon/fold/xml-fold';
-import 'codemirror/addon/comment/comment';
-import 'codemirror/keymap/sublime';
-import 'codemirror/addon/search/searchcursor';
-import 'codemirror/addon/search/matchesonscrollbar';
-import 'codemirror/addon/search/match-highlighter';
-import 'codemirror/addon/search/jump-to-line';
-import 'codemirror/addon/edit/matchbrackets';
-import 'codemirror/addon/edit/closebrackets';
-import 'codemirror/addon/selection/mark-selection';
-import 'codemirror/addon/hint/css-hint';
-import 'codemirror-colorpicker';
-import { JSHINT } from 'jshint';
-import { CSSLint } from 'csslint';
-import { HTMLHint } from 'htmlhint';
import classNames from 'classnames';
import { debounce } from 'lodash';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import MediaQuery from 'react-responsive';
-import '../../../../utils/htmlmixed';
-import '../../../../utils/p5-javascript';
-import { metaKey } from '../../../../utils/metaKey';
-import '../show-hint';
-import * as hinter from '../../../../utils/p5-hinter';
-import '../../../../utils/codemirror-search';
import beepUrl from '../../../../sounds/audioAlert.mp3';
import RightArrowIcon from '../../../../images/right-arrow.svg';
@@ -72,704 +30,219 @@ import UnsavedChangesIndicator from '../UnsavedChangesIndicator';
import { EditorContainer, EditorHolder } from './MobileEditor';
import { FolderIcon } from '../../../../common/icons';
import { IconButton } from '../../../../common/IconButton';
-import { saveLocalBackup } from '../../utils/localBackup';
-
-import contextAwareHinter from '../../../../utils/contextAwareHinter';
-import showRenameDialog from '../../../../utils/showRenameDialog';
-import handleRename from '../../../../utils/rename-variable';
-import { jumpToDefinition } from '../../../../utils/jump-to-definition';
-import { ensureAriaLiveRegion } from '../../../../utils/ScreenReaderHelper';
-import { isMac } from '../../../../utils/device';
-
-emmet(CodeMirror);
-
-window.JSHINT = JSHINT;
-window.CSSLint = CSSLint;
-window.HTMLHint = HTMLHint;
-const INDENTATION_AMOUNT = 2;
-
-class Editor extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- currentLine: 1
- };
- this._cm = null;
- this.tidyCode = this.tidyCode.bind(this);
-
- this.updateLintingMessageAccessibility = debounce((annotations) => {
- this.props.clearLintMessage();
- annotations.forEach((x) => {
- if (x.from.line > -1) {
- this.props.updateLintMessage(x.severity, x.from.line + 1, x.message);
- }
- });
- if (this.props.lintMessages.length > 0 && this.props.lintWarning) {
- this.beep.play();
- }
- }, 2000);
- this.showFind = this.showFind.bind(this);
- this.showReplace = this.showReplace.bind(this);
- this.getContent = this.getContent.bind(this);
- this.updateFileContent = this.updateFileContent.bind(this);
- }
+import useCodeMirror from './codemirror';
- componentDidMount() {
- this.beep = new Audio(beepUrl);
- ensureAriaLiveRegion();
- // this.widgets = [];
- this._cm = CodeMirror(this.codemirrorContainer, {
- theme: `p5-${this.props.theme}`,
- lineNumbers: this.props.lineNumbers,
- styleActiveLine: true,
- inputStyle: 'contenteditable',
- lineWrapping: this.props.linewrap,
- fixedGutter: false,
- foldGutter: true,
- foldOptions: { widget: '\u2026' },
- gutters: ['CodeMirror-foldgutter', 'CodeMirror-lint-markers'],
- keyMap: 'sublime',
- highlightSelectionMatches: true, // highlight current search match
- matchBrackets: true,
- emmet: {
- preview: ['html'],
- markTagPairs: true,
- autoRenameTags: true
- },
- autoCloseBrackets: this.props.autocloseBracketsQuotes,
- styleSelectedText: true,
- lint: {
- onUpdateLinting: (annotations) => {
- this.updateLintingMessageAccessibility(annotations);
- },
- options: {
- asi: true,
- eqeqeq: false,
- '-W041': false,
- esversion: 11
- }
- },
- colorpicker: {
- type: 'sketch',
- mode: 'edit'
- }
- });
+import {
+ addErrorDecoration,
+ removeErrorDecorations
+} from './utils/consoleErrorDecoration';
- this.hinter = new Fuse(hinter.p5Hinter, {
- threshold: 0.05,
- keys: ['text']
- });
+// temporary until p5.js 2.0 becomes default
+// checks if sketch is using p5.js 2.0 to pass correct base url for autocomplete hinter reference
+export function getReferenceBaseUrl(htmlFile) {
+ const html = htmlFile?.content || '';
- delete this._cm.options.lint.options.errors;
+ const isV2 =
+ /https:\/\/beta\.p5js\.org\b/i.test(html) || /\bp5(@|-)2\./i.test(html);
- this._cm.getWrapperElement().addEventListener('click', (e) => {
- const isCtrlClick = isMac() ? e.metaKey : e.ctrlKey;
+ return isV2 ? 'https://beta.p5js.org' : 'https://p5js.org';
+}
- if (isCtrlClick) {
- const pos = this._cm.coordsChar({ left: e.clientX, top: e.clientY });
- jumpToDefinition.call(this, pos);
+function Editor({
+ provideController,
+ files,
+ file,
+ project,
+ linewrap,
+ lineNumbers,
+ closeProjectOptions,
+ setSelectedFile,
+ setUnsavedChanges,
+ lintMessages,
+ lintWarning,
+ clearLintMessage,
+ updateLintMessage,
+ updateFileContent,
+ autorefresh,
+ clearConsole,
+ startSketch,
+ autocompleteHinter,
+ autocloseBracketsQuotes,
+ fontSize,
+ consoleEvents,
+ expandConsole,
+ isExpanded,
+ htmlFile,
+ t,
+ collapseSidebar,
+ expandSidebar
+}) {
+ const [currentLine, setCurrentLine] = useState(1);
+ const beep = useRef();
+
+ const updateLintingMessageAccessibility = debounce((annotations) => {
+ clearLintMessage();
+ annotations.forEach((x) => {
+ if (x.from.line > -1) {
+ updateLintMessage(x.severity, x.from.line + 1, x.message);
}
});
-
- const renameKey = isMac() ? 'Ctrl-F2' : 'F2';
-
- const replaceCommand =
- metaKey === 'Ctrl' ? `${metaKey}-H` : `${metaKey}-Option-F`;
- this._cm.setOption('extraKeys', {
- Tab: (cm) => {
- if (!cm.execCommand('emmetExpandAbbreviation')) return;
- // might need to specify and indent more?
- const selection = cm.doc.getSelection();
- if (selection.length > 0) {
- cm.execCommand('indentMore');
- } else {
- cm.replaceSelection(' '.repeat(INDENTATION_AMOUNT));
- }
- },
- Enter: 'emmetInsertLineBreak',
- Esc: 'emmetResetAbbreviation',
- [`Shift-${metaKey}-E`]: (cm) => {
- cm.getInputField().blur();
- },
- [renameKey]: (cm) => this.renameVariable(cm),
- [`Shift-Tab`]: false,
- [`${metaKey}-Enter`]: () => null,
- [`Shift-${metaKey}-Enter`]: () => null,
- [`${metaKey}-F`]: 'findPersistent',
- [`Shift-${metaKey}-F`]: this.tidyCode,
- [`${metaKey}-G`]: 'findPersistentNext',
- [`Shift-${metaKey}-G`]: 'findPersistentPrev',
- [replaceCommand]: 'replace',
- // Cassie Tarakajian: If you don't set a default color, then when you
- // choose a color, it deletes characters inline. This is a
- // hack to prevent that.
- [`${metaKey}-K`]: (cm, event) =>
- cm.state.colorpicker.popup_color_picker({ length: 0 }),
- [`${metaKey}-.`]: 'toggleComment' // Note: most adblockers use the shortcut ctrl+.
- });
-
- this.initializeDocuments(this.props.files);
- this._cm.swapDoc(this._docs[this.props.file.id]);
-
- this._cm.on(
- 'change',
- debounce(() => {
- this.props.setUnsavedChanges(true);
- this.props.hideRuntimeErrorWarning();
- this.props.updateFileContent(this.props.file.id, this._cm.getValue());
-
- // Save a local backup to localStorage for crash recovery (#3891).
- // This ensures work is recoverable even if the tab crashes
- // (e.g. from an infinite loop) before the server autosave fires.
- const projectId = this.props.project?.id || 'unsaved';
- saveLocalBackup(projectId, this.props.files);
-
- if (this.props.autorefresh) {
- this.props.clearConsole();
- this.props.startSketch();
- }
- }, 1000)
- );
-
- if (this._cm) {
- this._cm.on('keyup', this.handleKeyUp);
+ if (lintMessages.length > 0 && lintWarning) {
+ beep.play();
}
-
- // Mobile autocomplete support (CM5 IME + contenteditable input)
- const triggerHint = (cm) => {
- const mode = cm.getOption('mode');
- if (mode !== 'css' && mode !== 'javascript') return;
-
- const cursor = cm.getCursor();
- const token = cm.getTokenAt(cursor);
-
- // Android keyboards often append a trailing space after each word.
- // When that happens, stripping the space so the hinter sees the word.
- if (token.string === ' ' && cursor.ch > 0 && cursor.ch === token.end) {
- const prevToken = cm.getTokenAt({
- line: cursor.line,
- ch: cursor.ch - 1
- });
- if (prevToken.string && /[a-z]/i.test(prevToken.string)) {
- cm.replaceRange(
- '',
- { line: cursor.line, ch: cursor.ch - 1 },
- cursor,
- '+trimHint'
- );
- this.showHint(cm);
- return;
- }
- }
- if (token.string && /[a-z]/i.test(token.string)) {
- this.showHint(cm);
- }
- };
-
- // Desktop: fires on each keystroke via CM5's textarea input path.
- this._cm.on('change', (_cm, changeObj) => {
- if (changeObj.origin !== '+input') return;
- if (/[a-z]/i.test(changeObj.text.join(''))) {
- triggerHint(_cm);
- }
+ }, 2000);
+
+ // The useCodeMirror hook manages CodeMirror state and returns
+ // a reference to the actual CM instance.
+ const {
+ setupCodeMirrorOnContainerMounted,
+ teardownCodeMirror,
+ codemirrorView,
+ getContent,
+ tidyCode,
+ showSearch
+ } = useCodeMirror({
+ project,
+ lineNumbers,
+ linewrap,
+ autocloseBracketsQuotes,
+ setUnsavedChanges,
+ updateFileContent,
+ file,
+ files,
+ autorefresh,
+ clearConsole,
+ startSketch,
+ autocompleteHinter,
+ fontSize,
+ updateLintingMessageAccessibility,
+ setCurrentLine,
+ referenceBaseUrl: getReferenceBaseUrl(htmlFile)
+ });
+
+ // Lets the parent component access file content-specific functionality...
+ useEffect(() => {
+ provideController({
+ tidyCode,
+ getContent,
+ showSearch
});
+ }, [tidyCode, showSearch, getContent]);
- // Mobile (word commit): fires when a composed word is accepted.
- this._compositionEndHandler = () => {
- setTimeout(() => {
- if (this._cm) triggerHint(this._cm);
- }, 150);
- };
- this._cm
- .getInputField()
- .addEventListener('compositionend', this._compositionEndHandler);
-
- // Mobile (per-character): forces CM5 to process composing text
- // during typing so autocomplete appears before keyboard dismissal.
- this._compositionFlushTimer = null;
- this._compositionUpdateHandler = (e) => {
- if (!e.data || !/[a-z]/i.test(e.data)) return;
- clearTimeout(this._compositionFlushTimer);
- this._compositionFlushTimer = setTimeout(() => {
- const display = this._cm && this._cm.display;
- if (display && display.input && display.input.composing) {
- display.input.composing.done = true;
- display.input.readFromDOMSoon();
- }
- }, 200);
- };
- this._cm
- .getInputField()
- .addEventListener('compositionupdate', this._compositionUpdateHandler);
-
- this._cm.getWrapperElement().style[
- 'font-size'
- ] = `${this.props.fontSize}px`;
-
- this.props.provideController({
- tidyCode: this.tidyCode,
- showFind: this.showFind,
- showReplace: this.showReplace,
- getContent: this.getContent,
- updateFileContent: this.updateFileContent
- });
- }
-
- componentWillUpdate(nextProps) {
- // check if files have changed
- if (this.props.files[0].id !== nextProps.files[0].id) {
- // then need to make CodeMirror documents
- this.initializeDocuments(nextProps.files);
- }
- if (this.props.files.length !== nextProps.files.length) {
- this.initializeDocuments(nextProps.files);
- }
- }
-
- componentDidUpdate(prevProps) {
- if (this.props.file.id !== prevProps.file.id) {
- const fileMode = this.getFileMode(this.props.file.name);
- if (fileMode === 'javascript') {
- // Define the new Emmet configuration based on the file mode
- const emmetConfig = {
- preview: ['html'],
- markTagPairs: false,
- autoRenameTags: true
- };
- this._cm.setOption('emmet', emmetConfig);
- }
- const oldDoc = this._cm.swapDoc(this._docs[this.props.file.id]);
- this._docs[prevProps.file.id] = oldDoc;
- this._cm.focus();
-
- if (!prevProps.unsavedChanges) {
- setTimeout(() => this.props.setUnsavedChanges(false), 400);
- }
- } else if (this.getContent().content !== this.props.file.content) {
- // TODO: make this not break regular edits!
- // this._cm.setValue(this.props.file.content);
- }
- if (this.props.fontSize !== prevProps.fontSize) {
- this._cm.getWrapperElement().style[
- 'font-size'
- ] = `${this.props.fontSize}px`;
- }
- if (this.props.linewrap !== prevProps.linewrap) {
- this._cm.setOption('lineWrapping', this.props.linewrap);
- }
- if (this.props.theme !== prevProps.theme) {
- this._cm.setOption('theme', `p5-${this.props.theme}`);
- }
- if (this.props.lineNumbers !== prevProps.lineNumbers) {
- this._cm.setOption('lineNumbers', this.props.lineNumbers);
- }
- if (
- this.props.autocloseBracketsQuotes !== prevProps.autocloseBracketsQuotes
- ) {
- this._cm.setOption(
- 'autoCloseBrackets',
- this.props.autocloseBracketsQuotes
- );
- }
- if (this.props.autocompleteHinter !== prevProps.autocompleteHinter) {
- if (!this.props.autocompleteHinter) {
- // close the hinter window once the preference is turned off
- CodeMirror.showHint(this._cm, () => {}, {});
- }
- }
-
- if (this.props.runtimeErrorWarningVisible) {
- if (this.props.consoleEvents.length !== prevProps.consoleEvents.length) {
- this.props.consoleEvents.forEach((consoleEvent) => {
- if (consoleEvent.method === 'error') {
- // It doesn't work if you create a new Error, but this works
- // LOL
- const errorObj = { stack: consoleEvent.data[0].toString() };
- StackTrace.fromError(errorObj).then((stackLines) => {
- this.props.expandConsole();
- const line = stackLines.find(
- (l) => l.fileName && l.fileName.startsWith('/')
- );
- if (!line) return;
- const fileNameArray = line.fileName.split('/');
- const fileName = fileNameArray.slice(-1)[0];
- const filePath = fileNameArray.slice(0, -1).join('/');
- const fileWithError = this.props.files.find(
- (f) => f.name === fileName && f.filePath === filePath
- );
- this.props.setSelectedFile(fileWithError.id);
- this._cm.addLineClass(
- line.lineNumber - 1,
- 'background',
- 'line-runtime-error'
- );
- });
- }
- });
- } else {
- for (let i = 0; i < this._cm.lineCount(); i += 1) {
- this._cm.removeLineClass(i, 'background', 'line-runtime-error');
- }
- }
- }
-
- if (this.props.file.id !== prevProps.file.id) {
- for (let i = 0; i < this._cm.lineCount(); i += 1) {
- this._cm.removeLineClass(i, 'background', 'line-runtime-error');
- }
- }
-
- this.props.provideController({
- tidyCode: this.tidyCode,
- showFind: this.showFind,
- showReplace: this.showReplace,
- getContent: this.getContent,
- updateFileContent: this.updateFileContent
- });
- }
-
- componentWillUnmount() {
- if (this._cm) {
- this._cm.off('keyup', this.handleKeyUp);
- const inputField = this._cm.getInputField();
- if (this._compositionEndHandler) {
- inputField.removeEventListener(
- 'compositionend',
- this._compositionEndHandler
- );
- }
- if (this._compositionUpdateHandler) {
- inputField.removeEventListener(
- 'compositionupdate',
- this._compositionUpdateHandler
- );
- }
- clearTimeout(this._compositionFlushTimer);
- }
- this.props.provideController(null);
- }
-
- getFileMode(fileName) {
- let mode;
- if (fileName.match(/.+\.js$/i)) {
- mode = 'javascript';
- } else if (fileName.match(/.+\.css$/i)) {
- mode = 'css';
- } else if (fileName.match(/.+\.(html|xml)$/i)) {
- mode = 'htmlmixed';
- } else if (fileName.match(/.+\.json$/i)) {
- mode = 'application/json';
- } else if (fileName.match(/.+\.(frag|glsl)$/i)) {
- mode = 'x-shader/x-fragment';
- } else if (fileName.match(/.+\.(vert|stl|mtl)$/i)) {
- mode = 'x-shader/x-vertex';
- } else {
- mode = 'text/plain';
- }
- return mode;
- }
-
- getContent() {
- const content = this._cm.getValue();
- const updatedFile = Object.assign({}, this.props.file, { content });
- return updatedFile;
- }
-
- updateFileContent(id, src) {
- const file = this._docs[id];
- if (file) {
- this._docs[id] = CodeMirror.Doc(src, this._docs[id].modeOption);
- if (id === this.props.file.id) {
- this._cm.swapDoc(this._docs[id]);
- }
- }
- }
-
- handleKeyUp = () => {
- const lineNumber = parseInt(this._cm.getCursor().line + 1, 10);
- this.setState({ currentLine: lineNumber });
- };
-
- showFind() {
- this._cm.execCommand('findPersistent');
- }
-
- // temporary until p5.js 2.0 becomes default
- // checks if sketch is using p5.js 2.0 to pass correct base url for autocomplete hinter reference
- getReferenceBaseUrl = () => {
- const html = this.props.htmlFile?.content || '';
-
- const isV2 =
- /https:\/\/beta\.p5js\.org\b/i.test(html) || /\bp5(@|-)2\./i.test(html);
-
- return isV2 ? 'https://beta.p5js.org' : 'https://p5js.org';
- };
-
- showHint(_cm) {
- if (!_cm) return;
+ // When the CM container div mounts, we set up CodeMirror.
+ const onContainerMounted = useCallback(setupCodeMirrorOnContainerMounted, []);
- if (!this.props.autocompleteHinter) {
- CodeMirror.showHint(_cm, () => {}, {});
- return;
- }
-
- let focusedLinkElement = null;
+ // This is acting as a "componentDidMount" call where it runs once
+ // at the start and never again. It also provides a cleanup function.
+ useEffect(() => {
+ beep.current = new Audio(beepUrl);
- const setFocusedLinkElement = (set) => {
- if (set && !focusedLinkElement) {
- const activeItemLink = document.querySelector(
- `.CodeMirror-hint-active a`
- );
- if (activeItemLink) {
- focusedLinkElement = activeItemLink;
- focusedLinkElement.classList.add('focused-hint-link');
- focusedLinkElement.parentElement.parentElement.classList.add(
- 'unfocused'
- );
- }
- }
+ return () => {
+ provideController(null);
+ teardownCodeMirror();
};
-
- const removeFocusedLinkElement = () => {
- if (focusedLinkElement) {
- focusedLinkElement.classList.remove('focused-hint-link');
- focusedLinkElement.parentElement.parentElement.classList.remove(
- 'unfocused'
+ }, []);
+
+ // Updates the runtime error console.
+ useEffect(() => {
+ const consoleErrors = consoleEvents.filter((e) => e.method === 'error');
+
+ if (consoleErrors.length > 0) {
+ const firstError = consoleErrors[0];
+ const errorObj = { stack: firstError.data[0].toString() };
+ StackTrace.fromError(errorObj).then((stackLines) => {
+ expandConsole();
+ const line = stackLines.find(
+ (l) => l.fileName && l.fileName.startsWith('/')
);
- focusedLinkElement = null;
- return true;
- }
- return false;
- };
-
- const hintOptions = {
- _fontSize: this.props.fontSize,
- referenceBaseUrl: this.getReferenceBaseUrl(),
- completeSingle: false,
- extraKeys: {
- 'Shift-Right': (cm, e) => {
- const activeItemLink = document.querySelector(
- `.CodeMirror-hint-active a`
- );
- if (activeItemLink) activeItemLink.click();
- },
- Right: (cm, e) => setFocusedLinkElement(true),
- Left: (cm, e) => removeFocusedLinkElement(),
- Up: (cm, e) => {
- const onLink = removeFocusedLinkElement();
- e.moveFocus(-1);
- setFocusedLinkElement(onLink);
- },
- Down: (cm, e) => {
- const onLink = removeFocusedLinkElement();
- e.moveFocus(1);
- setFocusedLinkElement(onLink);
- },
- Enter: (cm, e) => {
- if (focusedLinkElement) focusedLinkElement.click();
- else e.pick();
- }
- },
- closeOnUnfocus: false
- };
-
- const triggerHints = () => {
- if (_cm.options.mode === 'javascript') {
- CodeMirror.showHint(
- _cm,
- () => {
- const c = _cm.getCursor();
- const token = _cm.getTokenAt(c);
- const hints = contextAwareHinter(_cm, { hinter: this.hinter });
- return {
- list: hints,
- from: CodeMirror.Pos(c.line, token.start),
- to: CodeMirror.Pos(c.line, c.ch)
- };
- },
- hintOptions
+ if (!line) return;
+ const fileNameArray = line.fileName.split('/');
+ const fileName = fileNameArray.slice(-1)[0];
+ const filePath = fileNameArray.slice(0, -1).join('/');
+ const fileWithError = files.find(
+ (f) => f.name === fileName && f.filePath === filePath
);
- } else if (_cm.options.mode === 'css') {
- CodeMirror.showHint(_cm, CodeMirror.hint.css, hintOptions);
- }
- };
-
- setTimeout(triggerHints, 0);
- }
-
- showReplace() {
- this._cm.execCommand('replace');
- }
-
- prettierFormatWithCursor(parser, plugins) {
- try {
- const { formatted, cursorOffset } = prettier.formatWithCursor(
- this._cm.doc.getValue(),
- {
- cursorOffset: this._cm.doc.indexFromPos(this._cm.doc.getCursor()),
- parser,
- plugins
- }
- );
- const { left, top } = this._cm.getScrollInfo();
- this._cm.doc.setValue(formatted);
- this._cm.focus();
- this._cm.doc.setCursor(this._cm.doc.posFromIndex(cursorOffset));
- this._cm.scrollTo(left, top);
- } catch (error) {
- console.error(error);
- }
- }
-
- tidyCode() {
- const mode = this._cm.getOption('mode');
- if (mode === 'javascript') {
- this.prettierFormatWithCursor('babel', [babelParser]);
- } else if (mode === 'css') {
- this.prettierFormatWithCursor('css', [cssParser]);
- } else if (mode === 'htmlmixed') {
- this.prettierFormatWithCursor('html', [htmlParser]);
- }
- }
-
- renameVariable(cm) {
- const cursorCoords = cm.cursorCoords(true, 'page');
- const selection = cm.getSelection();
- const pos = cm.getCursor(); // or selection start
- const token = cm.getTokenAt(pos);
- const tokenType = token.type;
- if (!selection) {
- return;
+ setSelectedFile(fileWithError.id);
+ addErrorDecoration(codemirrorView.current, line.lineNumber);
+ });
+ } else {
+ removeErrorDecorations(codemirrorView.current);
}
-
- const sel = cm.listSelections()[0];
- const fromPos =
- CodeMirror.cmpPos(sel.anchor, sel.head) <= 0 ? sel.anchor : sel.head;
-
- showRenameDialog(
- cm,
- fromPos,
- tokenType,
- cursorCoords,
- selection,
- (newName) => {
- if (newName && newName.trim() !== '' && newName !== selection) {
- handleRename(fromPos, selection, newName, cm);
- }
- }
- );
- }
-
- initializeDocuments(files) {
- this._docs = {};
- files.forEach((file) => {
- if (file.name !== 'root') {
- this._docs[file.id] = CodeMirror.Doc(
- file.content,
- this.getFileMode(file.name)
- ); // eslint-disable-line
- }
- });
- }
-
- render() {
- const editorSectionClass = classNames({
- editor: true,
- 'sidebar--contracted': !this.props.isExpanded
- });
-
- const editorHolderClass = classNames({
- 'editor-holder': true,
- 'editor-holder--hidden':
- this.props.file.fileType === 'folder' || this.props.file.url
- });
-
- const { currentLine } = this.state;
-
- return (
-
- {(matches) =>
- matches ? (
-
-
-
-
-
-
- {this.props.file.name}
-
-
-
-
-
- {
- this.codemirrorContainer = element;
+ }, [consoleEvents]);
+
+ const editorSectionClass = classNames({
+ editor: true,
+ 'sidebar--contracted': !isExpanded
+ });
+
+ const editorHolderClass = classNames({
+ 'editor-holder': true,
+ 'editor-holder--hidden': file.fileType === 'folder' || file.url
+ });
+
+ return (
+
+ {(matches) =>
+ matches ? (
+
+
+
+
+
+
+ {file.name}
+
+
+
+
+
+
+ {file.url ? : null}
+
+
+ ) : (
+
+
+
+
+ {file.name}
+
+
+
+
+
+ {file.url ? (
+
) : null}
- ) : (
-
-
-
-
- {this.props.file.name}
-
-
-
-
- {
- this.codemirrorContainer = element;
- }}
- />
- {this.props.file.url ? (
-
- ) : null}
-
-
-
- )
- }
-
- );
- }
+
+ )
+ }
+
+ );
}
Editor.propTypes = {
@@ -807,8 +280,6 @@ Editor.propTypes = {
setUnsavedChanges: PropTypes.func.isRequired,
startSketch: PropTypes.func.isRequired,
autorefresh: PropTypes.bool.isRequired,
- theme: PropTypes.string.isRequired,
- unsavedChanges: PropTypes.bool.isRequired,
files: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
@@ -816,16 +287,14 @@ Editor.propTypes = {
content: PropTypes.string.isRequired
})
).isRequired,
+ isExpanded: PropTypes.bool.isRequired,
htmlFile: PropTypes.shape({
content: PropTypes.string
}),
- isExpanded: PropTypes.bool.isRequired,
collapseSidebar: PropTypes.func.isRequired,
closeProjectOptions: PropTypes.func.isRequired,
expandSidebar: PropTypes.func.isRequired,
clearConsole: PropTypes.func.isRequired,
- hideRuntimeErrorWarning: PropTypes.func.isRequired,
- runtimeErrorWarningVisible: PropTypes.bool.isRequired,
provideController: PropTypes.func.isRequired,
t: PropTypes.func.isRequired,
setSelectedFile: PropTypes.func.isRequired,
diff --git a/client/modules/IDE/components/Editor/utils/completionPreview.js b/client/modules/IDE/components/Editor/utils/completionPreview.js
new file mode 100644
index 0000000000..8293735d7e
--- /dev/null
+++ b/client/modules/IDE/components/Editor/utils/completionPreview.js
@@ -0,0 +1,114 @@
+import { StateField, RangeSetBuilder } from '@codemirror/state';
+import { Decoration, EditorView, WidgetType } from '@codemirror/view';
+import { selectedCompletion, completionStatus } from '@codemirror/autocomplete';
+
+/**
+ * Creates a "ghost" of what the completion would look like, for autocomplete selections.
+ *
+ * This is currently only used in conjection with p5Javascript language support,
+ * but it could be moved to stateUtils and used with other languages as well.
+ */
+class GhostTextWidget extends WidgetType {
+ constructor(text) {
+ super();
+ this.text = text;
+ }
+
+ eq(other) {
+ return other.text === this.text;
+ }
+
+ toDOM() {
+ const span = document.createElement('span');
+ span.className = 'cm-ghostCompletion';
+ span.textContent = this.text;
+ return span;
+ }
+
+ ignoreEvent() {
+ return true;
+ }
+}
+
+function getCurrentWord(state) {
+ const { from, to, empty } = state.selection.main;
+ if (!empty) return null;
+
+ const line = state.doc.lineAt(from);
+ const before = line.text.slice(0, from - line.from);
+ const match = before.match(/\w+$/);
+
+ if (!match) return null;
+
+ const word = match[0];
+ return {
+ text: word,
+ from: from - word.length,
+ to
+ };
+}
+
+function buildGhostText(state) {
+ // only show ghost text if autocomplete is on,
+ // user is typing, and if preview matches typed text
+
+ if (completionStatus(state) !== 'active') return null;
+
+ const selected = selectedCompletion(state);
+ if (!selected) return null;
+
+ const word = getCurrentWord(state);
+ if (!word) return null;
+
+ const preview = selected.preview || selected.label;
+ if (!preview) return null;
+
+ if (!preview.toLowerCase().startsWith(word.text.toLowerCase())) return null;
+
+ const remainder = preview.slice(word.text.length);
+ if (!remainder) return null;
+
+ return {
+ pos: word.to,
+ text: remainder
+ };
+}
+
+const ghostTextField = StateField.define({
+ create(state) {
+ return Decoration.none;
+ },
+
+ update(deco, tr) {
+ const decorationBuilder = new RangeSetBuilder();
+ const ghost = buildGhostText(tr.state);
+
+ if (ghost) {
+ decorationBuilder.add(
+ ghost.pos,
+ ghost.pos,
+ Decoration.widget({
+ widget: new GhostTextWidget(ghost.text),
+ side: 1
+ })
+ );
+ }
+
+ return decorationBuilder.finish();
+ },
+
+ provide: (field) => EditorView.decorations.from(field)
+});
+
+export const completionPreviewTheme = EditorView.theme({
+ '.cm-ghostCompletion': {
+ opacity: '0.55',
+ fontStyle: 'italic',
+ pointerEvents: 'none',
+ whiteSpace: 'pre'
+ }
+});
+
+export function completionPreview() {
+ return [ghostTextField, completionPreviewTheme];
+}
diff --git a/client/modules/IDE/components/Editor/utils/consoleErrorDecoration.js b/client/modules/IDE/components/Editor/utils/consoleErrorDecoration.js
new file mode 100644
index 0000000000..ce3890bcca
--- /dev/null
+++ b/client/modules/IDE/components/Editor/utils/consoleErrorDecoration.js
@@ -0,0 +1,52 @@
+import { StateField, StateEffect } from '@codemirror/state';
+import { EditorView, Decoration } from '@codemirror/view';
+
+// Effects for communicating with the state field
+const ADD_ERROR_DECORATION = StateEffect.define();
+const FILTER_ERROR_DECORATION = StateEffect.define();
+
+// An extension for managing error line decorations
+// Mostly adapted from the Marked Text demo in https://codemirror.net/docs/migration/
+// You can affect this by calling addErrorDecoration and removeErrorDecorations
+export const errorDecorationStateField = StateField.define({
+ // Start with an empty set of decorations
+ create() {
+ return Decoration.none;
+ },
+ // This is called whenever the editor updates
+ update(value, transaction) {
+ // Move the decorations to account for document changes
+ let newValue = value.map(transaction.changes);
+ for (let i = 0; i < transaction.effects.length; i++) {
+ const effect = transaction.effects[i];
+ if (effect.is(ADD_ERROR_DECORATION))
+ newValue = newValue.update({ add: effect.value, sort: true });
+ else if (effect.is(FILTER_ERROR_DECORATION))
+ newValue = newValue.update({ filter: effect.value });
+ }
+ return newValue;
+ },
+ // Indicate that this field provides a set of decorations
+ provide: (f) => EditorView.decorations.from(f)
+});
+
+const ERROR_DECORATION = Decoration.line({
+ class: 'cm-errorLine' // Defined in _editor.scss
+});
+
+// Add an error decoration to a specific line number
+export function addErrorDecoration(view, lineNumber) {
+ const docLineNumber = view.state.doc.line(lineNumber);
+ view.dispatch({
+ effects: ADD_ERROR_DECORATION.of([
+ ERROR_DECORATION.range(docLineNumber.from)
+ ])
+ });
+}
+
+// Remove all error decorations
+export function removeErrorDecorations(view) {
+ view.dispatch({
+ effects: FILTER_ERROR_DECORATION.of(() => false)
+ });
+}
diff --git a/client/modules/IDE/components/Editor/utils/extensionCustomStyles.js b/client/modules/IDE/components/Editor/utils/extensionCustomStyles.js
new file mode 100644
index 0000000000..47585d6572
--- /dev/null
+++ b/client/modules/IDE/components/Editor/utils/extensionCustomStyles.js
@@ -0,0 +1,113 @@
+/**
+ * This file contains utility functions for creating custom styled
+ * elements for our CodeMirror extensions. */
+
+/**
+ * Returns completion options configured for autocomplete.
+ * This gets passed into the autocomplete extension in
+ * stateUtils when creating a new file state.
+ */
+export const createAutocompleteOptions = (referenceBaseUrl) => ({
+ selectOnOpen: false,
+ tooltipClass: () => 'CodeMirror-hints',
+ closeOnBlur: false,
+ icons: false,
+
+ // handle css classes
+ optionClass(completion) {
+ let className = 'CodeMirror-hint';
+
+ if (completion.type) {
+ className += ` hint-type-${completion.type}`;
+ }
+
+ if (completion.p5DocPath) {
+ className += ' has-doc-link';
+ }
+
+ return className;
+ },
+
+ addToOptions: [
+ {
+ position: 60,
+ render(completion) {
+ const kind = document.createElement('span');
+ kind.className = 'cm-completionKind';
+ kind.textContent = completion.kindLabel || completion.type || '';
+ return kind;
+ }
+ },
+ {
+ position: 80,
+ render(completion, state, view) {
+ if (!completion.p5DocPath) return null;
+
+ const link = document.createElement('a');
+ link.className = 'cm-completionRefLink';
+ link.href = `${referenceBaseUrl}/reference/p5/${completion.p5DocPath}`;
+ link.target = '_blank';
+ link.rel = 'noopener noreferrer';
+ link.tabIndex = -1;
+ link.setAttribute('aria-label', `Open ${completion.label} reference`);
+
+ link.innerHTML = `
+
open ${completion.label} reference
+
➔
+ `;
+
+ link.addEventListener('mousedown', (event) => {
+ event.preventDefault();
+ event.stopPropagation();
+ });
+
+ link.addEventListener('click', (event) => {
+ event.stopPropagation();
+ });
+
+ link.addEventListener('keydown', (event) => {
+ if (event.key === 'ArrowLeft' || event.key === 'Escape') {
+ event.preventDefault();
+ event.stopPropagation();
+ link.classList.remove('focused-hint-link');
+ view.focus();
+ }
+ });
+
+ return link;
+ }
+ },
+ {
+ position: 100,
+ render(completion) {
+ if (!completion.blacklisted) return null;
+
+ const warning = document.createElement('div');
+ warning.className = 'cm-completionWarning';
+
+ const icon = document.createElement('span');
+ icon.className = 'cm-completionWarningIcon';
+ icon.setAttribute('aria-hidden', 'true');
+ icon.textContent = '⚠️';
+
+ const text = document.createElement('span');
+ text.className = 'cm-completionWarningText';
+ text.textContent = 'use with caution in this context';
+
+ warning.appendChild(icon);
+ warning.appendChild(text);
+
+ return warning;
+ }
+ }
+ ]
+});
+
+/** Used in the fold gutter extension. */
+export function createFoldMarker(open) {
+ // Uses window.document explicitly to avoid shadowing by the `document`
+ // parameter in createNewFileState below.
+ const span = window.document.createElement('span');
+ span.className = open ? 'cm-fold-open' : 'cm-fold-closed';
+ return span;
+}
diff --git a/client/modules/IDE/components/Editor/utils/fileState.js b/client/modules/IDE/components/Editor/utils/fileState.js
new file mode 100644
index 0000000000..49961dc357
--- /dev/null
+++ b/client/modules/IDE/components/Editor/utils/fileState.js
@@ -0,0 +1,286 @@
+import { EditorState, Compartment } from '@codemirror/state';
+import {
+ EditorView,
+ lineNumbers as lineNumbersExt,
+ highlightActiveLine,
+ highlightActiveLineGutter,
+ gutters,
+ keymap,
+ highlightSpecialChars,
+ drawSelection,
+ dropCursor,
+ rectangularSelection,
+ crosshairCursor
+} from '@codemirror/view';
+import {
+ foldGutter,
+ bracketMatching,
+ indentOnInput,
+ syntaxHighlighting
+} from '@codemirror/language';
+import { autocompletion, closeBrackets } from '@codemirror/autocomplete';
+import { highlightSelectionMatches, search } from '@codemirror/search';
+import { history } from '@codemirror/commands';
+import { lintGutter, linter } from '@codemirror/lint';
+import {
+ expandAbbreviation,
+ abbreviationTracker
+} from '@emmetio/codemirror6-plugin';
+
+import { css } from '@codemirror/lang-css';
+import { html } from '@codemirror/lang-html';
+import { json } from '@codemirror/lang-json';
+import { xml } from '@codemirror/lang-xml';
+import { emmetConfig } from '@emmetio/codemirror6-plugin';
+import { color as colorPicker } from '@connieye/codemirror-color-picker';
+
+import { p5JavaScript } from './p5JavaScript';
+import { highlightStyle } from './highlightStyle';
+import { errorDecorationStateField } from './consoleErrorDecoration';
+import {
+ makeCssLinter,
+ makeHtmlLinter,
+ makeJsonLinter,
+ makeJavascriptLinter
+} from './linters';
+import { emmetKeymaps, buildKeymaps } from './keymaps';
+import {
+ createAutocompleteOptions,
+ createFoldMarker
+} from './extensionCustomStyles';
+
+// ----- TODOS -----
+// - shader syntax highlighting
+
+/** Detects what mode the file is based on the name. */
+export function getFileMode(fileName) {
+ let mode;
+ if (fileName.match(/.+\.js$/i)) {
+ mode = 'javascript';
+ } else if (fileName.match(/.+\.css$/i)) {
+ mode = 'css';
+ } else if (fileName.match(/.+\.(html)$/i)) {
+ mode = 'html';
+ } else if (fileName.match(/.+\.(xml)$/i)) {
+ mode = 'xml';
+ } else if (fileName.match(/.+\.json$/i)) {
+ mode = 'application/json';
+ } else if (fileName.match(/.+\.(frag|glsl)$/i)) {
+ mode = 'x-shader/x-fragment';
+ } else if (fileName.match(/.+\.(vert|stl|mtl)$/i)) {
+ mode = 'x-shader/x-vertex';
+ } else {
+ mode = 'text/plain';
+ }
+ return mode;
+}
+
+function getFileLanguage(fileName) {
+ const fileMode = getFileMode(fileName);
+
+ switch (fileMode) {
+ case 'javascript':
+ return p5JavaScript;
+ case 'css':
+ return css;
+ case 'html':
+ return html;
+ case 'xml':
+ return xml;
+ case 'application/json':
+ return json;
+ default:
+ return null;
+ }
+}
+
+function getFileLinter(fileName, callback) {
+ const fileMode = getFileMode(fileName);
+
+ switch (fileMode) {
+ case 'javascript':
+ return makeJavascriptLinter();
+ case 'html':
+ return linter(makeHtmlLinter(callback));
+ case 'css':
+ return linter(makeCssLinter(callback));
+ case 'application/json':
+ return linter(makeJsonLinter(callback));
+ default:
+ return null;
+ }
+}
+
+function getFileEmmetConfig(fileName) {
+ const fileMode = getFileMode(fileName);
+
+ switch (fileMode) {
+ case 'html':
+ return emmetConfig.of({ syntax: 'html' });
+ case 'css':
+ return emmetConfig.of({ syntax: 'css' });
+ default:
+ return null;
+ }
+}
+
+/**
+ * Creates a new CodeMirror editor state with configurations,
+ * extensions, and keymaps tailored to the file type and settings.
+ *
+ * Returns a "file state" object containing the CodeMirror state and compartments.
+ */
+export function createNewFileState(filename, document, settings) {
+ const {
+ linewrap,
+ lineNumbers,
+ autocomplete,
+ autocloseBracketsQuotes,
+ onUpdateLinting,
+ onViewUpdate,
+ referenceBaseUrl,
+ fontSize
+ } = settings;
+ const lineNumbersCpt = new Compartment();
+ const lineWrappingCpt = new Compartment();
+ const closeBracketsCpt = new Compartment();
+ const autocompleteCpt = new Compartment();
+ const fontSizeCpt = new Compartment();
+
+ // Depending on the file mode, we have a different tidier function.
+ // Keep this binding local to each file state so modes don't accumulate
+ // across files via a shared module-level array.
+ const mode = getFileMode(filename);
+
+ const keymaps = buildKeymaps(mode);
+
+ // https://github.com/codemirror/basic-setup/blob/main/src/codemirror.ts
+ const extensions = [
+ // The first few extensions can be toggled on or off.
+ fontSizeCpt.of(EditorView.theme({ '&': { fontSize: `${fontSize}px` } })),
+ lineNumbersCpt.of(lineNumbers ? lineNumbersExt() : []),
+ lineWrappingCpt.of(linewrap ? EditorView.lineWrapping : []),
+ closeBracketsCpt.of(autocloseBracketsQuotes ? closeBrackets() : []),
+ autocompleteCpt.of(
+ autocomplete
+ ? autocompletion(createAutocompleteOptions(referenceBaseUrl))
+ : []
+ ),
+
+ // Everything below here should always be on.
+ history(),
+ search(),
+ // Highlight extensions
+ highlightActiveLine(),
+ highlightActiveLineGutter(),
+ highlightSpecialChars(),
+ highlightSelectionMatches(),
+ syntaxHighlighting(highlightStyle),
+ // Selection extensions
+ drawSelection(),
+ rectangularSelection(),
+ dropCursor(),
+ crosshairCursor(),
+ EditorState.allowMultipleSelections.of(true),
+ // Gutter extensions
+ gutters({ fixed: false }),
+ foldGutter({ markerDOM: createFoldMarker }),
+ // Misc extensions
+ indentOnInput(),
+ bracketMatching(),
+ errorDecorationStateField,
+
+ // Setup the event listeners on the CodeMirror instance.
+ EditorView.updateListener.of(onViewUpdate)
+ ];
+
+ // Only enable the color picker for Javascript and CSS, which
+ // have both been tested.
+ if (mode === 'javascript' || mode === 'css') {
+ extensions.push(colorPicker);
+ }
+
+ const fileLanguage = getFileLanguage(filename);
+ const fileLinter = getFileLinter(filename, onUpdateLinting);
+ const fileEmmetConfig = getFileEmmetConfig(filename);
+
+ if (fileLanguage) {
+ extensions.push(fileLanguage());
+ }
+ if (fileLinter) {
+ extensions.push(fileLinter);
+ extensions.push(lintGutter());
+ }
+
+ // If it's HTML or CSS, we add some emmet-specific configs.
+ if (fileEmmetConfig) {
+ extensions.push(fileEmmetConfig);
+ extensions.push(abbreviationTracker());
+ extensions.push(
+ EditorView.domEventHandlers({
+ paste(event, view) {
+ setTimeout(() => {
+ expandAbbreviation(view);
+ }, 0);
+ }
+ })
+ );
+ keymaps.push(emmetKeymaps);
+ }
+
+ // Now add the keymaps...
+ extensions.push(keymap.of(keymaps.flat()));
+
+ // Create the state with document content if we have it.
+ const stateOptions = {
+ extensions
+ };
+ if (document) {
+ stateOptions.doc = document;
+ }
+
+ const cmState = EditorState.create(stateOptions);
+ return {
+ cmState,
+ lineNumbersCpt,
+ lineWrappingCpt,
+ closeBracketsCpt,
+ autocompleteCpt,
+ fontSizeCpt
+ };
+}
+
+/**
+ * Given a reconfigure effect, this function will update all
+ * of the file states.
+ *
+ * We need to do this whenever the settings like line numbers
+ * change, so it will get called in the useEffect hooks.
+ */
+export function updateFileStates({
+ fileStates,
+ cmView,
+ file: currentFile,
+ reconfigureEffect
+}) {
+ if (!fileStates) return;
+
+ Object.entries(fileStates).forEach(([fileId, fileState]) => {
+ // Either grab the current state from the view or saved in the fileStates.
+ let { cmState } = fileState;
+ if (fileId === currentFile.id) {
+ cmState = cmView.state;
+ }
+
+ // Apply the new effects and grab the new state.
+ const { state: newCmState } = cmState.update({
+ effects: reconfigureEffect(fileState)
+ });
+
+ // Save the new states and update the view for the currently open file.
+ fileStates[fileId].cmState = newCmState;
+ if (fileId === currentFile.id) {
+ cmView.setState(newCmState);
+ }
+ });
+}
diff --git a/client/modules/IDE/components/Editor/utils/fileState.test.js b/client/modules/IDE/components/Editor/utils/fileState.test.js
new file mode 100644
index 0000000000..6b032fb4ae
--- /dev/null
+++ b/client/modules/IDE/components/Editor/utils/fileState.test.js
@@ -0,0 +1,272 @@
+/**
+ * @jest-environment jsdom
+ */
+import { EditorView, runScopeHandlers } from '@codemirror/view';
+import { createNewFileState, getFileMode } from './fileState';
+
+const defaultSettings = {
+ linewrap: false,
+ lineNumbers: false,
+ autocomplete: false,
+ autocloseBracketsQuotes: false,
+ onUpdateLinting: () => {},
+ onViewUpdate: () => {},
+ referenceBaseUrl: 'https://p5js.org'
+};
+
+function mountFile(filename, doc) {
+ const { cmState } = createNewFileState(filename, doc, defaultSettings);
+ const parent = document.createElement('div');
+ document.body.appendChild(parent);
+ const view = new EditorView({ state: cmState, parent });
+ return view;
+}
+
+function pressTidyShortcut(view) {
+ const event = new KeyboardEvent('keydown', {
+ key: 'F',
+ code: 'KeyF',
+ shiftKey: true,
+ ctrlKey: true
+ });
+ runScopeHandlers(view, event, 'editor');
+}
+
+describe('createNewFileState — Tidy keyboard shortcut', () => {
+ afterEach(() => {
+ document.body.innerHTML = '';
+ });
+
+ // Regression test for https://github.com/processing/p5.js-web-editor/issues/4093
+ // Each file's Shift-Mod-F binding must only tidy with its own mode, regardless
+ // of the order in which the file states were created.
+ it('tidies each file with its own mode regardless of creation order', () => {
+ const jsView = mountFile('sketch.js', `function foo(){console.log("hi")}`);
+ const cssView = mountFile('style.css', `body{margin:0;padding:0;}`);
+ const htmlView = mountFile('index.html', `hello`);
+
+ pressTidyShortcut(jsView);
+ pressTidyShortcut(cssView);
+ pressTidyShortcut(htmlView);
+
+ expect(jsView.state.doc.toString()).toBe(
+ 'function foo() {\n console.log("hi");\n}\n'
+ );
+ expect(cssView.state.doc.toString()).toBe(
+ 'body {\n margin: 0;\n padding: 0;\n}\n'
+ );
+ expect(htmlView.state.doc.toString()).toBe(
+ '\n \n hello\n \n\n'
+ );
+ });
+});
+
+describe('createNewFileState - Settings', () => {
+ it('Enables line wrap', () => {
+ const fileName = 'file1.js';
+ const content = ``;
+ const settings = {
+ linewrap: true,
+ lineNumbers: true,
+ autocomplete: false,
+ autocloseBracketsQuotes: false,
+ onUpdateLinting: jest.fn(),
+ onViewUpdate: jest.fn()
+ };
+ const result = createNewFileState(fileName, content, settings);
+
+ const parent = document.createElement('div');
+ const cmView = new EditorView({ state: result.cmState, parent });
+ const div = parent.querySelector('.cm-lineWrapping');
+
+ expect(div).not.toBeNull();
+ cmView.destroy();
+ });
+
+ it('Disable line wrap', () => {
+ const fileName = 'file1.js';
+ const content = ``;
+ const settings = {
+ linewrap: false,
+ lineNumbers: true,
+ autocomplete: false,
+ autocloseBracketsQuotes: false,
+ onUpdateLinting: jest.fn(),
+ onViewUpdate: jest.fn()
+ };
+ const result = createNewFileState(fileName, content, settings);
+
+ const parent = document.createElement('div');
+ const cmView = new EditorView({ state: result.cmState, parent });
+ const div = parent.querySelector('.cm-lineWrapping');
+
+ expect(div).toBeNull();
+ cmView.destroy();
+ });
+
+ it('Enables line numbers', () => {
+ const fileName = 'file1.js';
+ const content = ``;
+ const settings = {
+ linewrap: false,
+ lineNumbers: true,
+ autocomplete: false,
+ autocloseBracketsQuotes: false,
+ onUpdateLinting: jest.fn(),
+ onViewUpdate: jest.fn()
+ };
+ const result = createNewFileState(fileName, content, settings);
+
+ const parent = document.createElement('div');
+ const cmView = new EditorView({ state: result.cmState, parent });
+ const div = parent.querySelector('.cm-lineNumbers');
+
+ expect(div).not.toBeNull();
+ cmView.destroy();
+ });
+
+ it('Disable line numbers', () => {
+ const fileName = 'file1.js';
+ const content = ``;
+ const settings = {
+ linewrap: false,
+ lineNumbers: false,
+ autocomplete: false,
+ autocloseBracketsQuotes: false,
+ onUpdateLinting: jest.fn(),
+ onViewUpdate: jest.fn()
+ };
+ const result = createNewFileState(fileName, content, settings);
+
+ const parent = document.createElement('div');
+ const cmView = new EditorView({ state: result.cmState, parent });
+ const div = parent.querySelector('.cm-lineNumbers');
+
+ expect(div).toBeNull();
+ cmView.destroy();
+ });
+
+ it('Enables autoclose brackets and quotes', () => {
+ const fileName = 'file1.js';
+ const content = ``;
+ const settings = {
+ linewrap: false,
+ lineNumbers: false,
+ autocomplete: false,
+ autocloseBracketsQuotes: true,
+ onUpdateLinting: jest.fn(),
+ onViewUpdate: jest.fn()
+ };
+
+ const result = createNewFileState(fileName, content, settings);
+
+ expect(result.closeBracketsCpt.get(result.cmState).length).toBeGreaterThan(
+ 0
+ );
+ });
+
+ it('Disable autoclose brackets and quotes', () => {
+ const fileName = 'file1.js';
+ const content = ``;
+ const settings = {
+ linewrap: false,
+ lineNumbers: false,
+ autocomplete: false,
+ autocloseBracketsQuotes: false,
+ onUpdateLinting: jest.fn(),
+ onViewUpdate: jest.fn()
+ };
+
+ const result = createNewFileState(fileName, content, settings);
+
+ expect(result.closeBracketsCpt.get(result.cmState).length).toBe(0);
+ });
+});
+
+describe('getFileMode', () => {
+ it('Returns correct javascript file mode', () => {
+ const fileName = 'file1.js';
+ const mode = getFileMode(fileName);
+ const expectedMode = 'javascript';
+
+ expect(mode).toBe(expectedMode);
+ });
+
+ it('Returns correct css file mode', () => {
+ const fileName = 'file1.css';
+ const mode = getFileMode(fileName);
+ const expectedMode = 'css';
+
+ expect(mode).toBe(expectedMode);
+ });
+
+ it('Returns correct html file mode', () => {
+ const fileName = 'file1.html';
+ const mode = getFileMode(fileName);
+ const expectedMode = 'html';
+
+ expect(mode).toBe(expectedMode);
+ });
+
+ it('Returns correct xml file mode', () => {
+ const fileName = 'file1.xml';
+ const mode = getFileMode(fileName);
+ const expectedMode = 'xml';
+
+ expect(mode).toBe(expectedMode);
+ });
+
+ it('Returns correct json file mode', () => {
+ const fileName = 'file1.json';
+ const mode = getFileMode(fileName);
+ const expectedMode = 'application/json';
+
+ expect(mode).toBe(expectedMode);
+ });
+
+ it('Returns correct frag|glsl file mode', () => {
+ const fileName = 'file1.frag';
+ const fileName2 = 'file2.glsl';
+ const mode = getFileMode(fileName);
+ const mode2 = getFileMode(fileName2);
+ const expectedMode = 'x-shader/x-fragment';
+
+ expect(mode).toBe(expectedMode);
+ expect(mode2).toBe(expectedMode);
+ });
+
+ it('Returns correct vert|stl|mtl file mode', () => {
+ const fileName = 'file1.vert';
+ const fileName2 = 'file2.stl';
+ const fileName3 = 'file3.mtl';
+ const mode = getFileMode(fileName);
+ const mode2 = getFileMode(fileName2);
+ const mode3 = getFileMode(fileName3);
+ const expectedMode = 'x-shader/x-vertex';
+
+ expect(mode).toBe(expectedMode);
+ expect(mode2).toBe(expectedMode);
+ expect(mode3).toBe(expectedMode);
+ });
+
+ it('Returns plain text otherwise file mode', () => {
+ const fileName = 'file1.py';
+ const mode = getFileMode(fileName);
+ const expectedMode = 'text/plain';
+ expect(mode).toBe(expectedMode);
+ });
+
+ it('Empty fileName', () => {
+ const fileName = '';
+ const mode = getFileMode(fileName);
+ const expectedMode = 'text/plain';
+ expect(mode).toBe(expectedMode);
+ });
+
+ it('Unknown fileName', () => {
+ const fileName = 'file1.xyz';
+ const mode = getFileMode(fileName);
+ const expectedMode = 'text/plain';
+ expect(mode).toBe(expectedMode);
+ });
+});
diff --git a/client/modules/IDE/components/Editor/utils/highlightStyle.js b/client/modules/IDE/components/Editor/utils/highlightStyle.js
new file mode 100644
index 0000000000..c7c589869b
--- /dev/null
+++ b/client/modules/IDE/components/Editor/utils/highlightStyle.js
@@ -0,0 +1,54 @@
+import { HighlightStyle } from '@codemirror/language';
+import { tags } from '@lezer/highlight';
+
+export const highlightStyle = HighlightStyle.define([
+ { tag: tags.comment, class: 'cm-comment' },
+ { tag: tags.lineComment, class: 'cm-comment' },
+ { tag: tags.blockComment, class: 'cm-comment' },
+ { tag: tags.docComment, class: 'cm-comment' },
+ { tag: tags.docString, class: 'cm-comment' },
+ { tag: tags.name, class: 'cm-variable' },
+ { tag: tags.variableName, class: 'cm-variable' },
+ { tag: tags.typeName, class: 'cm-variable' },
+ { tag: tags.className, class: 'cm-variable' },
+ { tag: tags.string, class: 'cm-string' },
+ { tag: tags.character, class: 'cm-string' },
+ { tag: tags.attributeName, class: 'cm-string' },
+ { tag: tags.regexp, class: 'cm-regexp' },
+ { tag: tags.number, class: 'cm-number' },
+ { tag: tags.integer, class: 'cm-number' },
+ { tag: tags.float, class: 'cm-number' },
+ { tag: tags.atom, class: 'cm-atom' },
+ { tag: tags.bool, class: 'cm-atom' },
+ { tag: tags.null, class: 'cm-atom' },
+ { tag: tags.keyword, class: 'cm-keyword' },
+ { tag: tags.self, class: 'cm-keyword' },
+ { tag: tags.function, class: 'cm-keyword' },
+ { tag: tags.operator, class: 'cm-operator' },
+ { tag: tags.operatorKeyword, class: 'cm-operator' },
+ { tag: tags.controlKeyword, class: 'cm-operator' },
+ { tag: tags.derefOperator, class: 'cm-operator' },
+ { tag: tags.arithmeticOperator, class: 'cm-operator' },
+ { tag: tags.logicOperator, class: 'cm-operator' },
+ { tag: tags.bitwiseOperator, class: 'cm-operator' },
+ { tag: tags.compareOperator, class: 'cm-operator' },
+ { tag: tags.updateOperator, class: 'cm-operator' },
+ { tag: tags.typeOperator, class: 'cm-operator' },
+ { tag: tags.controlOperator, class: 'cm-operator' },
+ { tag: tags.definitionKeyword, class: 'cm-keyword' },
+ { tag: tags.tagName, class: 'cm-tag' },
+ { tag: tags.heading, class: 'cm-tag' },
+ { tag: tags.heading1, class: 'cm-tag' },
+ { tag: tags.heading2, class: 'cm-tag' },
+ { tag: tags.heading3, class: 'cm-tag' },
+ { tag: tags.heading4, class: 'cm-tag' },
+ { tag: tags.heading5, class: 'cm-tag' },
+ { tag: tags.heading6, class: 'cm-tag' },
+ { tag: tags.list, class: 'cm-tag' },
+ { tag: tags.quote, class: 'cm-tag' },
+ { tag: tags.emphasis, class: 'cm-tag' },
+ { tag: tags.strong, class: 'cm-tag' },
+ { tag: tags.link, class: 'cm-tag' },
+ { tag: tags.propertyName, class: 'cm-property' },
+ { tag: tags.attributeName, class: 'cm-attribute' }
+]);
diff --git a/client/modules/IDE/components/Editor/utils/keymaps.js b/client/modules/IDE/components/Editor/utils/keymaps.js
new file mode 100644
index 0000000000..545058bec1
--- /dev/null
+++ b/client/modules/IDE/components/Editor/utils/keymaps.js
@@ -0,0 +1,136 @@
+import {
+ completionStatus,
+ selectedCompletionIndex,
+ closeBracketsKeymap
+} from '@codemirror/autocomplete';
+import {
+ insertTab,
+ indentLess,
+ defaultKeymap,
+ historyKeymap
+} from '@codemirror/commands';
+import { foldKeymap } from '@codemirror/language';
+import { searchKeymap } from '@codemirror/search';
+import { expandAbbreviation } from '@emmetio/codemirror6-plugin';
+import { tidyCodeWithPrettier } from './tidier';
+
+function getColorPickerAtSelection(view) {
+ const { head } = view.state.selection.main;
+ const { node } = view.domAtPos(head);
+
+ const startEl =
+ node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
+
+ const lineEl = startEl?.closest('.cm-line');
+
+ return (
+ lineEl?.querySelector('input[type="color"]:not(:disabled)') ||
+ view.contentDOM.querySelector('input[type="color"]:not(:disabled)')
+ );
+}
+
+export function focusOnReferenceArrow(view) {
+ if (completionStatus(view.state) !== 'active') return false;
+
+ const selectedIndex = selectedCompletionIndex(view.state);
+ if (selectedIndex == null || selectedIndex < 0) return false;
+
+ const tooltip = view.dom.querySelector('.cm-tooltip-autocomplete');
+ if (!tooltip) return false;
+
+ const options = tooltip.querySelectorAll('li.CodeMirror-hint');
+ const selectedOption = options[selectedIndex];
+ if (!selectedOption) return false;
+
+ const link = selectedOption.querySelector('.cm-completionRefLink');
+ if (!link) return false;
+
+ link.focus();
+ link.classList.add('focused-hint-link');
+
+ const cleanup = () => {
+ link.classList.remove('focused-hint-link');
+ link.removeEventListener('blur', cleanup);
+ };
+ link.addEventListener('blur', cleanup);
+
+ return true;
+}
+
+export function openColorPickerWithKeyboard(view) {
+ const picker = getColorPickerAtSelection(view);
+
+ if (!picker || picker.disabled) {
+ return false;
+ }
+
+ picker.focus();
+
+ if (typeof picker.showPicker === 'function') {
+ picker.showPicker();
+ } else {
+ picker.click();
+ }
+ return true;
+}
+
+// Extra custom keymaps.
+// TODO: We need to add sublime mappings + other missing extra mappings here.
+export const extraKeymaps = [
+ {
+ key: 'Mod-Enter',
+ run: () => true
+ },
+ { key: 'ArrowRight', run: focusOnReferenceArrow },
+ { key: 'Tab', run: insertTab, shift: indentLess }
+];
+
+export const emmetKeymaps = [{ key: 'Tab', run: expandAbbreviation }];
+
+function createColorPickerKeymap(mode) {
+ const colorPickerKeymap = [];
+ if (mode === 'css' || mode === 'javascript') {
+ colorPickerKeymap.push({
+ key: 'Mod-k',
+ run: (view) => openColorPickerWithKeyboard(view)
+ });
+ }
+ return colorPickerKeymap;
+}
+
+function createFileTidyKeymap(mode) {
+ // Make a keymap for both uppercase and lowercase F, since
+ // browsers can differ in which one they send for the Shift-Mod-F shortcut.
+ return [
+ {
+ key: 'Shift-Mod-F',
+ run: (cmView) => {
+ tidyCodeWithPrettier(cmView, mode);
+ return true;
+ }
+ },
+ {
+ key: 'Shift-Mod-f',
+ run: (cmView) => {
+ tidyCodeWithPrettier(cmView, mode);
+ return true;
+ }
+ }
+ ];
+}
+
+export function buildKeymaps(mode) {
+ const colorPickerKeymap = createColorPickerKeymap(mode);
+ const fileTidyKeymap = createFileTidyKeymap(mode);
+
+ return [
+ extraKeymaps,
+ colorPickerKeymap,
+ fileTidyKeymap,
+ closeBracketsKeymap,
+ defaultKeymap,
+ historyKeymap,
+ foldKeymap,
+ searchKeymap
+ ];
+}
diff --git a/client/modules/IDE/components/Editor/utils/linters.js b/client/modules/IDE/components/Editor/utils/linters.js
new file mode 100644
index 0000000000..f00afccf67
--- /dev/null
+++ b/client/modules/IDE/components/Editor/utils/linters.js
@@ -0,0 +1,108 @@
+import { jsonParseLinter } from '@codemirror/lang-json';
+import { linter } from '@codemirror/lint';
+import { HTMLHint } from 'htmlhint';
+import { CSSLint } from 'csslint';
+import { esLint } from '@codemirror/lang-javascript';
+import { Linter as ESLinter } from 'eslint-linter-browserify';
+
+// https://github.com/codemirror/codemirror5/blob/master/addon/lint/html-lint.js
+const HTMLHINT_OPTIONS = {
+ 'tagname-lowercase': true,
+ 'attr-lowercase': true,
+ 'attr-value-double-quotes': true,
+ 'doctype-first': false,
+ 'tag-pair': true,
+ 'spec-char-escape': true,
+ 'id-unique': true,
+ 'src-not-empty': true,
+ 'attr-no-duplication': true
+};
+
+const ESLINT_CONFIG = {
+ languageOptions: {
+ ecmaVersion: 2021
+ },
+ rules: {
+ semi: 'off',
+ eqeqeq: 'off'
+ }
+};
+
+const eslint = new ESLinter();
+
+export function makeJavascriptLinter() {
+ return linter(esLint(eslint, ESLINT_CONFIG));
+}
+
+export function makeCssLinter(callback) {
+ return (view) => {
+ const documentContent = view.state.doc.toString();
+ const { messages } = CSSLint.verify(documentContent, {});
+ const diagnostics = [];
+
+ messages.forEach((message) => {
+ if (!message) return;
+
+ const {
+ line: messageLine,
+ col: messageCharacter,
+ type: messageType,
+ message: messageText
+ } = message;
+ const cmLine = view.state.doc.line(messageLine);
+
+ const start = cmLine.from + messageCharacter - 1;
+ const end = cmLine.to;
+
+ diagnostics.push({
+ from: start,
+ to: end,
+ severity: messageType,
+ message: messageText
+ });
+ });
+
+ if (callback) callback(diagnostics);
+ return diagnostics;
+ };
+}
+
+export function makeHtmlLinter(callback) {
+ return (view) => {
+ const documentContent = view.state.doc.toString();
+ const messages = HTMLHint.verify(documentContent, HTMLHINT_OPTIONS) || [];
+ const diagnostics = [];
+
+ messages.forEach((message) => {
+ if (!message) return;
+
+ const {
+ line: messageLine,
+ col: messageCharacter,
+ type: messageType,
+ message: messageText
+ } = message;
+ const cmLine = view.state.doc.line(messageLine);
+
+ // TODO: Can we to do the to/from smarter?
+ diagnostics.push({
+ from: cmLine.from + messageCharacter - 1,
+ to: cmLine.from + messageCharacter,
+ severity: messageType,
+ message: messageText
+ });
+ });
+
+ if (callback) callback(diagnostics);
+ return diagnostics;
+ };
+}
+
+export function makeJsonLinter(callback) {
+ const baseJsonLinter = jsonParseLinter();
+ return (view) => {
+ const diagnostics = baseJsonLinter(view);
+ if (callback) callback(diagnostics);
+ return diagnostics;
+ };
+}
diff --git a/client/modules/IDE/components/Editor/utils/p5JavaScript.js b/client/modules/IDE/components/Editor/utils/p5JavaScript.js
new file mode 100644
index 0000000000..c24b1de059
--- /dev/null
+++ b/client/modules/IDE/components/Editor/utils/p5JavaScript.js
@@ -0,0 +1,79 @@
+import { LanguageSupport, syntaxTree } from '@codemirror/language';
+import { javascript } from '@codemirror/lang-javascript';
+import { ViewPlugin, Decoration } from '@codemirror/view';
+import { RangeSetBuilder } from '@codemirror/state';
+import { p5Hinter } from '../../../../../utils/p5-hinter';
+import { completionPreview } from './completionPreview';
+import contextAwareHinter from '../../../../../utils/contextAwareHinter';
+import {
+ p5FunctionKeywords,
+ p5VariableKeywords
+} from '../../../../../utils/p5-keywords';
+
+const p5Functions = new Set(Object.keys(p5FunctionKeywords));
+const p5Variables = new Set(Object.keys(p5VariableKeywords));
+
+const p5FunctionMark = Decoration.mark({ class: 'cm-p5-function' });
+const p5VariableMark = Decoration.mark({ class: 'cm-p5-variable' });
+
+// Used to add highlighting to the p5-specific keywords.
+function buildHighlightDecorations(view) {
+ const builder = new RangeSetBuilder();
+ view.visibleRanges.forEach(({ from, to }) => {
+ syntaxTree(view.state).iterate({
+ from,
+ to,
+ enter(node) {
+ const isVariable = node.name === 'VariableName';
+ const isDefinition = node.name === 'VariableDefinition';
+ if (!isVariable && !isDefinition) return;
+ const name = view.state.doc.sliceString(node.from, node.to);
+ if (p5Functions.has(name)) {
+ builder.add(node.from, node.to, p5FunctionMark);
+ } else if (p5Variables.has(name)) {
+ builder.add(node.from, node.to, p5VariableMark);
+ }
+ }
+ });
+ });
+ return builder.finish();
+}
+
+const p5Highlight = ViewPlugin.fromClass(
+ class {
+ constructor(view) {
+ this.decorations = buildHighlightDecorations(view);
+ }
+
+ update(update) {
+ if (update.docChanged || update.viewportChanged) {
+ this.decorations = buildHighlightDecorations(update.view);
+ }
+ }
+ },
+ { decorations: (v) => v.decorations }
+);
+
+function addCompletions(context) {
+ const word = context.matchBefore(/\w*/);
+ const isValidWord = word?.text && word.text.trim().length >= 2;
+ if (!isValidWord && !context.explicit) {
+ return null;
+ }
+
+ return contextAwareHinter(context, {
+ hints: p5Hinter
+ });
+}
+
+export function p5JavaScript() {
+ const jsLang = javascript();
+ return new LanguageSupport(jsLang.language, [
+ jsLang.extension,
+ jsLang.language.data.of({
+ autocomplete: addCompletions
+ }),
+ completionPreview(),
+ p5Highlight
+ ]);
+}
diff --git a/client/modules/IDE/components/Editor/utils/tidier.test.ts b/client/modules/IDE/components/Editor/utils/tidier.test.ts
new file mode 100644
index 0000000000..babb27c8b2
--- /dev/null
+++ b/client/modules/IDE/components/Editor/utils/tidier.test.ts
@@ -0,0 +1,67 @@
+import { EditorState } from '@codemirror/state';
+import { EditorView } from '@codemirror/view';
+import { tidyCodeWithPrettier } from './tidier';
+
+describe('tidyCodeWithPrettier', () => {
+ function createEditor(content: string) {
+ const state = EditorState.create({ doc: content });
+ return new EditorView({ state });
+ }
+
+ function getDocText(cmView: EditorView) {
+ return cmView.state.doc.toString();
+ }
+
+ function getCursor(cmView: EditorView) {
+ return cmView.state.selection.main.head;
+ }
+
+ it('formats JavaScript correctly and keeps cursor stable', () => {
+ const messyJs = `function foo(){console.log("hi")}`;
+ const cmView = createEditor(messyJs);
+ cmView.dispatch({ selection: { anchor: 14 } });
+
+ tidyCodeWithPrettier(cmView, 'javascript');
+
+ const expectedJs = 'function foo() {\n console.log("hi");\n}\n';
+ expect(getDocText(cmView)).toBe(expectedJs);
+
+ const newCursor = getCursor(cmView);
+ expect(newCursor).toBeGreaterThan(0);
+ });
+
+ it('formats HTML correctly and keeps cursor stable', () => {
+ const messyHtml = `hello`;
+ const cmView = createEditor(messyHtml);
+ tidyCodeWithPrettier(cmView, 'html');
+
+ const expectedHtml = '\n \n hello\n \n\n';
+ expect(getDocText(cmView)).toBe(expectedHtml);
+ });
+
+ it('formats CSS correctly and keeps cursor stable', () => {
+ const messyCss = `body{margin:0;padding:0;}`;
+ const cmView = createEditor(messyCss);
+
+ tidyCodeWithPrettier(cmView, 'css');
+
+ const expectedCss = 'body {\n margin: 0;\n padding: 0;\n}\n';
+ expect(getDocText(cmView)).toBe(expectedCss);
+ });
+
+ it('handles an empty document without errors', () => {
+ const cmView = createEditor('');
+ expect(() => tidyCodeWithPrettier(cmView, 'javascript')).not.toThrow();
+ expect(getDocText(cmView)).toBe('');
+ });
+
+ it('leaves the cursor unmoved if the code is already formatted', () => {
+ const cleanCode = 'function foo() {}\n';
+ const cmView = createEditor(cleanCode);
+ cmView.dispatch({ selection: { anchor: 5 } });
+
+ tidyCodeWithPrettier(cmView, 'javascript');
+
+ expect(getCursor(cmView)).toBe(5);
+ });
+});
diff --git a/client/modules/IDE/components/Editor/utils/tidier.ts b/client/modules/IDE/components/Editor/utils/tidier.ts
new file mode 100644
index 0000000000..41fdb24572
--- /dev/null
+++ b/client/modules/IDE/components/Editor/utils/tidier.ts
@@ -0,0 +1,44 @@
+import prettier from 'prettier/standalone';
+import babelParser from 'prettier/parser-babel';
+import htmlParser from 'prettier/parser-html';
+import cssParser from 'prettier/parser-postcss';
+import type { EditorView } from '@codemirror/view';
+import type { Plugin } from 'prettier';
+
+type ParserTypes = 'babel' | 'html' | 'css';
+type FormatMode = 'html' | 'css' | 'javascript';
+
+function prettierFormatWithCursor(
+ parser: ParserTypes,
+ plugins: Plugin[],
+ cmView: EditorView
+) {
+ const { doc } = cmView.state;
+ const cursorOffset = cmView.state.selection.main.head;
+ const {
+ formatted,
+ cursorOffset: newCursorOffset
+ } = prettier.formatWithCursor(doc.toString(), {
+ cursorOffset,
+ parser,
+ plugins
+ });
+
+ cmView.dispatch({
+ changes: { from: 0, to: doc.length, insert: formatted },
+ selection: { anchor: newCursorOffset }
+ });
+
+ cmView.focus();
+}
+
+/** Runs prettier on the codemirror instance, depending on the mode. */
+export function tidyCodeWithPrettier(cmView: EditorView, mode: FormatMode) {
+ if (mode === 'javascript') {
+ prettierFormatWithCursor('babel', [babelParser], cmView);
+ } else if (mode === 'css') {
+ prettierFormatWithCursor('css', [cssParser], cmView);
+ } else if (mode === 'html') {
+ prettierFormatWithCursor('html', [htmlParser], cmView);
+ }
+}
diff --git a/client/modules/IDE/components/Header/MobileNav.jsx b/client/modules/IDE/components/Header/MobileNav.jsx
index 2ef0ff3026..b055b62be8 100644
--- a/client/modules/IDE/components/Header/MobileNav.jsx
+++ b/client/modules/IDE/components/Header/MobileNav.jsx
@@ -427,7 +427,7 @@ const MoreMenu = () => {
{t('Nav.Edit.TidyCode')}
-
+
{t('Nav.Edit.Find')}
{t('Nav.Sketch.Title')}
diff --git a/client/modules/IDE/components/Header/Nav.jsx b/client/modules/IDE/components/Header/Nav.jsx
index cc53134bbe..c29a42821a 100644
--- a/client/modules/IDE/components/Header/Nav.jsx
+++ b/client/modules/IDE/components/Header/Nav.jsx
@@ -169,8 +169,6 @@ const ProjectMenu = () => {
shareSketch
} = useSketchActions();
- const replaceCommand =
- metaKey === 'Ctrl' ? `${metaKeyName}+H` : `${metaKeyName}+⌥+F`;
const newFileCommand =
metaKey === 'Ctrl' ? `${metaKeyName}+Alt+N` : `${metaKeyName}+⌥+N`;
@@ -264,18 +262,24 @@ const ProjectMenu = () => {
-
+ {
+ cmRef.current?.tidyCode();
+ }}
+ >
{t('Nav.Edit.TidyCode')}
{metaKeyName}+Shift+F
-
+ {
+ cmRef.current?.showSearch();
+ }}
+ >
{t('Nav.Edit.Find')}
{metaKeyName}+F
-
- {t('Nav.Edit.Replace')}
- {replaceCommand}
-
-
- Replace
-
- Ctrl+H
-
-
1) return;
- // By default, don't allow completion when something is selected.
- // A hint function can have a `supportsSelection` property to
- // indicate that it can handle selections.
- if (this.somethingSelected()) {
- if (!options.hint.supportsSelection) return;
- // Don't try with cross-line selections
- // if selection spans multiple lines, bail out
- for (var i = 0; i < selections.length; i++)
- if (selections[i].head.line != selections[i].anchor.line) return;
- }
-
- if (this.state.completionActive) this.state.completionActive.close(); // close an already active autocomplete session if active
- // create a new completion object and saves it to this.state.completionActive
- var completion = (this.state.completionActive = new Completion(
- this,
- options
- ));
- if (!completion.options.hint) return; // safety check to ensure hint is valid
-
- CodeMirror.signal(this, 'startCompletion', this); // emits a signal; fires a startCompletion event on editor instance
- completion.update(true);
- });
-
- CodeMirror.defineExtension('closeHint', function () {
- if (this.state.completionActive) this.state.completionActive.close();
- });
-
- // defines a constructor function
- function Completion(cm, options) {
- this.cm = cm;
- this.options = options;
- this.widget = null; // will hold a reference to the dropdown menu that shows suggestions
- this.debounce = 0;
- this.tick = 0;
- this.startPos = this.cm.getCursor('start'); // startPos is a {line,ch} object used to remember where hinting started
- // startLen is the len of the line minus length of any selected text
- this.startLen =
- this.cm.getLine(this.startPos.line).length -
- this.cm.getSelection().length;
-
- if (this.options.updateOnCursorActivity) {
- var self = this; // stores ref to this as self so it can be accessed inside the nested function
- // adds an event listener to the editor; called when the cursor moves
- cm.on(
- 'cursorActivity',
- (this.activityFunc = function () {
- self.cursorActivity();
- })
- );
- }
- }
-
- var requestAnimationFrame =
- window.requestAnimationFrame ||
- function (fn) {
- return setTimeout(fn, 1000 / 60);
- };
- var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
-
- Completion.prototype = {
- close: function () {
- if (!this.active()) return;
- this.cm.state.completionActive = null;
- this.tick = null;
- // removes the current activity listener
- if (this.options.updateOnCursorActivity) {
- this.cm.off('cursorActivity', this.activityFunc);
- }
- // signals and removes the widget
- if (this.widget && this.data) CodeMirror.signal(this.data, 'close');
- if (this.widget) this.widget.close();
- // emits a completition end event
- CodeMirror.signal(this.cm, 'endCompletion', this.cm);
- },
-
- active: function () {
- return this.cm.state.completionActive == this;
- },
-
- pick: function (data, i) {
- // selects an item from the suggestion list
- var completion = data.list[i],
- self = this;
-
- this.cm.operation(function () {
- const name = completion.item?.text;
-
- if (completion.hint) {
- completion.hint(self.cm, data, completion);
- } else {
- self.cm.replaceRange(
- getText(completion),
- completion.from || data.from,
- completion.to || data.to,
- 'complete'
- );
- }
- // signals that a hint was picked and scrolls to it
- CodeMirror.signal(data, 'pick', completion);
- self.cm.scrollIntoView();
- });
- // closes widget if closeOnPick is enabled
- if (this.options.closeOnPick) {
- this.close();
- }
- },
-
- cursorActivity: function () {
- // if a debounce is scheduled, cancel it to avoid outdated updates
- if (this.debounce) {
- cancelAnimationFrame(this.debounce);
- this.debounce = 0;
- }
-
- var identStart = this.startPos;
- if (this.data) {
- identStart = this.data.from;
- }
-
- var pos = this.cm.getCursor(),
- line = this.cm.getLine(pos.line);
- if (
- pos.line != this.startPos.line ||
- line.length - pos.ch != this.startLen - this.startPos.ch ||
- pos.ch < identStart.ch ||
- this.cm.somethingSelected() ||
- !pos.ch ||
- this.options.closeCharacters.test(line.charAt(pos.ch - 1))
- ) {
- this.close();
- } else {
- var self = this;
- this.debounce = requestAnimationFrame(function () {
- self.update();
- });
- if (this.widget) this.widget.disable();
- }
- },
-
- update: function (first) {
- if (this.tick == null) return;
- var self = this,
- myTick = ++this.tick;
- fetchHints(this.options.hint, this.cm, this.options, function (data) {
- if (self.tick == myTick) self.finishUpdate(data, first);
- });
- },
-
- finishUpdate: function (data, first) {
- if (this.data) CodeMirror.signal(this.data, 'update');
-
- var picked =
- (this.widget && this.widget.picked) ||
- (first && this.options.completeSingle);
- if (this.widget) this.widget.close();
-
- this.data = data;
-
- if (data && data.list.length) {
- if (picked && data.list.length == 1) {
- this.pick(data, 0);
- } else {
- this.widget = new Widget(this, data);
- CodeMirror.signal(data, 'shown');
- }
- }
- }
- };
-
- function parseOptions(cm, pos, options) {
- var editor = cm.options.hintOptions;
- var out = {};
- // copies all default hint settings into out
- for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
- if (editor)
- for (var prop in editor)
- if (editor[prop] !== undefined) out[prop] = editor[prop];
- if (options)
- for (var prop in options)
- if (options[prop] !== undefined) out[prop] = options[prop];
- if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos);
- return out;
- }
- // extracts the visible text from a completion entry
- function getText(completion) {
- if (typeof completion === 'string') return completion;
- else return completion.item.text;
- }
-
- // builds a key mapping object to define keyboard behavior for autocomplete
- function buildKeyMap(completion, handle) {
- var baseMap = {
- Up: function () {
- handle.moveFocus(-1);
- },
- Down: function () {
- handle.moveFocus(1);
- },
- PageUp: function () {
- handle.moveFocus(-handle.menuSize() + 1, true);
- },
- PageDown: function () {
- handle.moveFocus(handle.menuSize() - 1, true);
- },
- Home: function () {
- handle.setFocus(0);
- },
- End: function () {
- handle.setFocus(handle.length - 1);
- },
- Enter: handle.pick,
- Tab: handle.pick,
- Esc: handle.close
- };
- // checks if the user is on macOS and adds shortcuts accordingly
- var mac = /Mac/.test(navigator.platform);
-
- if (mac) {
- baseMap['Ctrl-P'] = function () {
- handle.moveFocus(-1);
- };
- baseMap['Ctrl-N'] = function () {
- handle.moveFocus(1);
- };
- }
-
- // user defined custom key bindings
- var custom = completion.options.customKeys;
- var ourMap = custom ? {} : baseMap;
- function addBinding(key, val) {
- var bound;
- if (typeof val != 'string')
- bound = function (cm) {
- return val(cm, handle);
- };
- // This mechanism is deprecated
- else if (baseMap.hasOwnProperty(val)) bound = baseMap[val];
- else bound = val;
- ourMap[key] = bound;
- }
- // apply all custom key bindings and extraKeys
- if (custom)
- for (var key in custom)
- if (custom.hasOwnProperty(key)) addBinding(key, custom[key]);
- var extra = completion.options.extraKeys;
- if (extra)
- for (var key in extra)
- if (extra.hasOwnProperty(key)) addBinding(key, extra[key]);
- return ourMap;
- }
-
- // hintsElement is the parent for hints and el is the clicked element within that container
- function displayHint(name, type, p5, isBlacklistedFunction, referenceBaseUrl) {
- const base = referenceBaseUrl || 'https://p5js.org';
- const refName = typeof p5 === 'string' ? p5 : name;
-
- const linkOrPlaceholder = p5
- ? `
- open ${name} reference
- ➔
- `
- : `
- no reference for ${name}
- `;
-
- const hintHTML = `
- ${name}
- ${type}
- ${linkOrPlaceholder}
-
`;
-
- if (isBlacklistedFunction) {
- return `
- ${hintHTML}
-
⚠️use with caution in this context
-
`;
- } else {
- return `${hintHTML}
`;
- }
- }
-
-
- function getInlineHintSuggestion(cm, focus, token) {
- let tokenLength = token.string.length;
- if (token.string === '.') {
- tokenLength -= 1;
- }
- const name = focus.item?.text;
-
- const suggestionItem = focus.item;
- // builds the remainder of the suggestion excluding what user already typed
- const baseCompletion = `${suggestionItem.text.slice(
- tokenLength
- )}`;
- if (suggestionItem.type !== 'fun') return baseCompletion;
-
- // for functions
- return (
- baseCompletion +
- '(' +
- (suggestionItem.params && suggestionItem.params.length
- ? suggestionItem.params.map(({ p, o }) => (o ? `[${p}]` : p)).join(', ')
- : '') +
- ')'
- );
- }
-
- // clears existing inline hint (like the part is suggested)
- function removeInlineHint(cm) {
- if (cm.state.inlineHint) {
- cm.state.inlineHint.clear();
- cm.state.inlineHint = null;
- }
- }
-
- function changeInlineHint(cm, focus) {
- removeInlineHint(cm);
-
- const cursor = cm.getCursor();
- const token = cm.getTokenAt(cursor);
-
- if (token && focus.item) {
- const suggestionHTML = getInlineHintSuggestion(cm, focus, token);
-
- const widgetElement = document.createElement('span');
- widgetElement.className = 'autocomplete-inline-hinter';
- widgetElement.innerHTML = suggestionHTML;
-
- const widget = cm.setBookmark(cursor, { widget: widgetElement });
- cm.state.inlineHint = widget;
- cm.setCursor(cursor);
- }
- }
-
- // defines the autocomplete dropdown ui; renders the suggestions
- // completion = the autocomplete context having cm and options
- // data = object with the list of suggestions
- function Widget(completion, data) {
- this.id = 'cm-complete-' + Math.floor(Math.random(1e6));
- this.completion = completion;
- this.data = data;
- this.picked = false;
- var widget = this,
- cm = completion.cm;
- var ownerDocument = cm.getInputField().ownerDocument;
- var parentWindow = ownerDocument.defaultView || ownerDocument.parentWindow;
-
- var fontSize = completion.options._fontSize;
-
- var hints = (this.hints = ownerDocument.createElement('ul'));
- hints.setAttribute('role', 'listbox');
- hints.setAttribute('aria-expanded', 'true');
- hints.id = this.id;
- var theme = completion.cm.options.theme;
- hints.className = 'CodeMirror-hints ' + theme;
- this.selectedHint = data.selectedHint || 0;
-
- const referenceBaseUrl = completion.options.referenceBaseUrl || 'https://p5js.org';
-
- // Show inline hint
- changeInlineHint(cm, data.list[this.selectedHint]);
-
- var completions = data.list;
- for (var i = 0; i < completions.length; ++i) {
- const cur = completions[i];
-
- const elt = ownerDocument.createElement('li');
- elt.className =
- HINT_ELEMENT_CLASS +
- (i !== this.selectedHint ? '' : ' ' + ACTIVE_HINT_ELEMENT_CLASS) +
- (cur.isBlacklisted ? ' blacklisted' : '');
-
- if (cur.className != null)
- elt.className = cur.className + ' ' + elt.className;
-
- if (i === this.selectedHint) elt.setAttribute('aria-selected', 'true');
- elt.id = this.id + '-' + i;
- elt.setAttribute('role', 'option');
- elt.hintId = i;
-
- if (cur.render) {
- cur.render(elt, data, cur);
- } else {
- const name = getText(cur);
- if (cur.item && cur.item.type) {
- cur.displayText = displayHint(
- name,
- cur.item.type,
- cur.item.p5,
- cur.isBlacklisted,
- referenceBaseUrl
- );
- }
-
- elt.innerHTML =
- cur.displayText || `${name}`;
- }
-
- hints.appendChild(elt);
- }
-
- var container = completion.options.container || ownerDocument.body;
- var pos = cm.cursorCoords(
- completion.options.alignWithWord ? data.from : null
- );
- var left = pos.left,
- top = pos.bottom,
- below = true;
- var offsetLeft = 0,
- offsetTop = 0;
- if (container !== ownerDocument.body) {
- // We offset the cursor position because left and top are relative to the offsetParent's top left corner.
- var isContainerPositioned =
- ['absolute', 'relative', 'fixed'].indexOf(
- parentWindow.getComputedStyle(container).position
- ) !== -1;
- var offsetParent = isContainerPositioned
- ? container
- : container.offsetParent;
- var offsetParentPosition = offsetParent.getBoundingClientRect();
- var bodyPosition = ownerDocument.body.getBoundingClientRect();
- offsetLeft =
- offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft;
- offsetTop =
- offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop;
- }
- hints.style.left = left - offsetLeft + 'px';
- hints.style.top = top - offsetTop + 'px';
-
- // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
- var winW =
- parentWindow.innerWidth ||
- Math.max(
- ownerDocument.body.offsetWidth,
- ownerDocument.documentElement.offsetWidth
- );
- var winH =
- parentWindow.innerHeight ||
- Math.max(
- ownerDocument.body.offsetHeight,
- ownerDocument.documentElement.offsetHeight
- );
- container.appendChild(hints);
- cm.getInputField().setAttribute('aria-autocomplete', 'list');
- cm.getInputField().setAttribute('aria-owns', this.id);
- cm.getInputField().setAttribute(
- 'aria-activedescendant',
- this.id + '-' + this.selectedHint
- );
-
- var box = completion.options.moveOnOverlap
- ? hints.getBoundingClientRect()
- : new DOMRect();
- var scrolls = completion.options.paddingForScrollbar
- ? hints.scrollHeight > hints.clientHeight + 1
- : false;
-
- // Compute in the timeout to avoid reflow on init
- var startScroll;
- setTimeout(function () {
- startScroll = cm.getScrollInfo();
- });
-
- var overlapY = box.bottom - winH;
- if (overlapY > 0) {
- var height = box.bottom - box.top,
- curTop = pos.top - (pos.bottom - box.top);
- if (curTop - height > 0) {
- // Fits above cursor
- hints.style.top = (top = pos.top - height - offsetTop) + 'px';
- below = false;
- } else if (height > winH) {
- hints.style.height = winH - 5 + 'px';
- hints.style.top = (top = pos.bottom - box.top - offsetTop) + 'px';
- var cursor = cm.getCursor();
- if (data.from.ch != cursor.ch) {
- pos = cm.cursorCoords(cursor);
- hints.style.left = (left = pos.left - offsetLeft) + 'px';
- box = hints.getBoundingClientRect();
- }
- }
- }
- var overlapX = box.right - winW;
- if (scrolls) overlapX += cm.display.nativeBarWidth;
- if (overlapX > 0) {
- if (box.right - box.left > winW) {
- hints.style.width = winW - 5 + 'px';
- overlapX -= box.right - box.left - winW;
- }
- hints.style.left = (left = pos.left - overlapX - offsetLeft) + 'px';
- }
- // if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)
- // node.style.paddingRight = cm.display.nativeBarWidth + "px"
-
- cm.addKeyMap(
- (this.keyMap = buildKeyMap(completion, {
- moveFocus: function (n, avoidWrap) {
- return widget.changeActive(widget.selectedHint + n, avoidWrap);
- },
- setFocus: function (n) {
- return widget.changeActive(n);
- },
- menuSize: function () {
- return widget.screenAmount();
- },
- length: completions.length,
- close: function () {
- completion.close();
- },
- pick: function () {
- widget.pick();
- },
- data: data
- }))
- );
-
- if (completion.options.closeOnUnfocus) {
- var closingOnBlur;
- cm.on(
- 'blur',
- (this.onBlur = function () {
- closingOnBlur = setTimeout(function () {
- completion.close();
- }, 100);
- })
- );
- cm.on(
- 'focus',
- (this.onFocus = function () {
- clearTimeout(closingOnBlur);
- })
- );
- }
-
- cm.on(
- 'scroll',
- (this.onScroll = function () {
- var curScroll = cm.getScrollInfo(),
- editor = cm.getWrapperElement().getBoundingClientRect();
- if (!startScroll) startScroll = cm.getScrollInfo();
- var newTop = top + startScroll.top - curScroll.top;
- var point =
- newTop -
- (parentWindow.pageYOffset ||
- (ownerDocument.documentElement || ownerDocument.body).scrollTop);
- if (!below) point += hints.offsetHeight;
- if (point <= editor.top || point >= editor.bottom)
- return completion.close();
- hints.style.top = newTop + 'px';
- hints.style.left = left + startScroll.left - curScroll.left + 'px';
- })
- );
-
- function getHintElement(container, el) {
- while (el && el !== container && el.hintId == null) {
- el = el.parentNode;
- }
- return el;
- }
-
- CodeMirror.on(hints, 'dblclick', function (e) {
- var t = getHintElement(hints, e.target || e.srcElement);
- if (t && t.hintId != null) {
- widget.changeActive(t.hintId);
- widget.pick();
- }
- });
-
- CodeMirror.on(hints, 'click', function (e) {
- var t = getHintElement(hints, e.target || e.srcElement);
- if (t && t.hintId != null) {
- widget.changeActive(t.hintId);
- if (completion.options.completeOnSingleClick) widget.pick();
- }
- });
-
- CodeMirror.on(hints, 'mousedown', function () {
- setTimeout(function () {
- cm.focus();
- }, 20);
- });
-
- // The first hint doesn't need to be scrolled to on init
- var selectedHintRange = this.getSelectedHintRange();
- if (selectedHintRange.from !== 0 || selectedHintRange.to !== 0) {
- this.scrollToActive();
- }
-
- CodeMirror.signal(
- data,
- 'select',
- completions[this.selectedHint],
- hints.childNodes[this.selectedHint]
- );
- return true;
- }
-
- Widget.prototype = {
- close: function () {
- if (this.completion.widget != this) return;
- this.completion.widget = null;
- if (this.hints.parentNode) this.hints.parentNode.removeChild(this.hints);
- this.completion.cm.removeKeyMap(this.keyMap);
- var input = this.completion.cm.getInputField();
- input.removeAttribute('aria-activedescendant');
- input.removeAttribute('aria-owns');
-
- var cm = this.completion.cm;
- if (this.completion.options.closeOnUnfocus) {
- cm.off('blur', this.onBlur);
- cm.off('focus', this.onFocus);
- }
- cm.off('scroll', this.onScroll);
-
- removeInlineHint(cm);
- },
-
- disable: function () {
- this.completion.cm.removeKeyMap(this.keyMap);
- var widget = this;
- this.keyMap = {
- Enter: function () {
- widget.picked = true;
- }
- };
- this.completion.cm.addKeyMap(this.keyMap);
- },
-
- pick: function () {
- this.completion.pick(this.data, this.selectedHint);
- },
-
- changeActive: function (i, avoidWrap) {
- if (i >= this.data.list.length)
- i = avoidWrap ? this.data.list.length - 1 : 0;
- else if (i < 0) i = avoidWrap ? 0 : this.data.list.length - 1;
-
- if (this.selectedHint == i) {
- changeInlineHint(this.completion.cm, this.data.list[this.selectedHint]);
- return this.data.list[this.selectedHint];
- }
-
- var node = this.hints.childNodes[this.selectedHint];
- if (node) {
- node.className = node.className.replace(
- ' ' + ACTIVE_HINT_ELEMENT_CLASS,
- ''
- );
- node.removeAttribute('aria-selected');
- }
- node = this.hints.childNodes[(this.selectedHint = i)];
- node.className += ' ' + ACTIVE_HINT_ELEMENT_CLASS;
- node.setAttribute('aria-selected', 'true');
- this.completion.cm
- .getInputField()
- .setAttribute('aria-activedescendant', node.id);
- this.scrollToActive();
- CodeMirror.signal(
- this.data,
- 'select',
- this.data.list[this.selectedHint],
- node
- );
-
- changeInlineHint(this.completion.cm, this.data.list[this.selectedHint]);
- return this.data.list[this.selectedHint];
- },
-
- scrollToActive: function () {
- var selectedHintRange = this.getSelectedHintRange();
- var node1 = this.hints.childNodes[selectedHintRange.from];
- var node2 = this.hints.childNodes[selectedHintRange.to];
- var firstNode = this.hints.firstChild;
- if (node1.offsetTop < this.hints.scrollTop)
- this.hints.scrollTop = node1.offsetTop - firstNode.offsetTop;
- else if (
- node2.offsetTop + node2.offsetHeight >
- this.hints.scrollTop + this.hints.clientHeight
- )
- this.hints.scrollTop =
- node2.offsetTop +
- node2.offsetHeight -
- this.hints.clientHeight +
- firstNode.offsetTop;
- },
-
- screenAmount: function () {
- return (
- Math.floor(
- this.hints.clientHeight / this.hints.firstChild.offsetHeight
- ) || 1
- );
- },
-
- getSelectedHintRange: function () {
- var margin = this.completion.options.scrollMargin || 0;
- return {
- from: Math.max(0, this.selectedHint - margin),
- to: Math.min(this.data.list.length - 1, this.selectedHint + margin)
- };
- }
- };
-
- function applicableHelpers(cm, helpers) {
- if (!cm.somethingSelected()) return helpers;
- var result = [];
- for (var i = 0; i < helpers.length; i++)
- if (helpers[i].supportsSelection) result.push(helpers[i]);
- return result;
- }
-
- function fetchHints(hint, cm, options, callback) {
- if (hint.async) {
- hint(cm, callback, options);
- } else {
- var result = hint(cm, options);
- if (result && result.then) result.then(callback);
- else callback(result);
- }
- }
-
- function resolveAutoHints(cm, pos) {
- var helpers = cm.getHelpers(pos, 'hint'),
- words;
- if (helpers.length) {
- var resolved = function (cm, callback, options) {
- var app = applicableHelpers(cm, helpers);
- function run(i) {
- if (i == app.length) return callback(null);
- fetchHints(app[i], cm, options, function (result) {
- if (result && result.list.length > 0) callback(result);
- else run(i + 1);
- });
- }
- run(0);
- };
- resolved.async = true;
- resolved.supportsSelection = true;
- return resolved;
- } else if ((words = cm.getHelper(cm.getCursor(), 'hintWords'))) {
- return function (cm) {
- return CodeMirror.hint.fromList(cm, { words: words });
- };
- } else if (CodeMirror.hint.anyword) {
- return function (cm, options) {
- return CodeMirror.hint.anyword(cm, options);
- };
- } else {
- return function () {};
- }
- }
-
- CodeMirror.registerHelper('hint', 'auto', {
- resolve: resolveAutoHints
- });
-
- CodeMirror.registerHelper('hint', 'fromList', function (cm, options) {
- var cur = cm.getCursor(),
- token = cm.getTokenAt(cur);
- var term,
- from = CodeMirror.Pos(cur.line, token.start),
- to = cur;
- if (
- token.start < cur.ch &&
- /\w/.test(token.string.charAt(cur.ch - token.start - 1))
- ) {
- term = token.string.substr(0, cur.ch - token.start);
- } else {
- term = '';
- from = cur;
- }
- var found = [];
- for (var i = 0; i < options.words.length; i++) {
- var word = options.words[i];
- if (word.slice(0, term.length) == term) found.push(word);
- }
-
- if (found.length) return { list: found, from: from, to: to };
- });
-
- CodeMirror.commands.autocomplete = CodeMirror.showHint;
-
- var defaultOptions = {
- hint: CodeMirror.hint.auto,
- completeSingle: true,
- alignWithWord: true,
- closeCharacters: /[\s()\[\]{};:>,]/,
- closeOnPick: true,
- closeOnUnfocus: true,
- updateOnCursorActivity: true,
- completeOnSingleClick: true,
- container: null,
- customKeys: null,
- extraKeys: null,
- paddingForScrollbar: true,
- moveOnOverlap: true
- };
-
- CodeMirror.defineOption('hintOptions', null);
-});
diff --git a/client/modules/IDE/reducers/ide.js b/client/modules/IDE/reducers/ide.js
index 8d45b8b50a..64765cac5b 100644
--- a/client/modules/IDE/reducers/ide.js
+++ b/client/modules/IDE/reducers/ide.js
@@ -22,7 +22,6 @@ const initialState = {
justOpenedProject: false,
previousPath: '/',
errorType: undefined,
- runtimeErrorWarningVisible: false,
parentId: undefined
};
@@ -111,10 +110,6 @@ const ide = (state = initialState, action) => {
return Object.assign({}, state, { errorType: action.modalType });
case ActionTypes.HIDE_ERROR_MODAL:
return Object.assign({}, state, { errorType: undefined });
- case ActionTypes.HIDE_RUNTIME_ERROR_WARNING:
- return Object.assign({}, state, { runtimeErrorWarningVisible: false });
- case ActionTypes.SHOW_RUNTIME_ERROR_WARNING:
- return Object.assign({}, state, { runtimeErrorWarningVisible: true });
case ActionTypes.OPEN_UPLOAD_FILE_MODAL:
return Object.assign({}, state, {
uploadFileModalVisible: true,
diff --git a/client/styles/abstracts/_variables.scss b/client/styles/abstracts/_variables.scss
index 46bdd7bc1b..5a595d14a1 100644
--- a/client/styles/abstracts/_variables.scss
+++ b/client/styles/abstracts/_variables.scss
@@ -6,33 +6,68 @@ $p5js-pink-opacity: #ed225d80;
$p5js-active-pink: #f10046;
$white: #fff;
$black: #000;
-$yellow: #F5DC23;
-$dodgerblue: #1E90FF;
-$p5-contrast-pink: #FFA9D9;
+$yellow: #f5dc23;
+$dodgerblue: #1e90ff;
+$p5-contrast-pink: #ffa9d9;
-$outline-color: #0F9DD7;
+$outline-color: #0f9dd7;
// Grayscale values
-$lightest: #FFF; // primary
-$lighter: #FBFBFB;
+$lightest: #fff; // primary
+$lighter: #fbfbfb;
-$light: #F0F0F0; // primary
-$medium-light: #D9D9D9;
-$middle-light: #A6A6A6;
+$light: #f0f0f0; // primary
+$medium-light: #d9d9d9;
+$middle-light: #a6a6a6;
// $middle-gray: #7D7D7D; // primary
$middle-gray: #747474; // primary
$middle-dark: #666;
-$medium-dark: #4D4D4D;
+$medium-dark: #4d4d4d;
$dark: #333; // primary
-$darker: #1C1C1C;
+$darker: #1c1c1c;
$darkest: #000;
+// Light highlight styles
+$p5-light-selected: $medium-light;
+$p5-light-activeline: #cfcfcf44;
+$p5-light-brown: #7a5a3a;
+$p5-light-black: #333333;
+$p5-light-pink: #d52889;
+$p5-light-gray: #666;
+$p5-light-blue: #0b7ca9;
+$p5-light-orange: #a06801;
+$p5-light-lightgray: $middle-gray;
+$p5-light-green: #47820a;
+
+// Dark highlight styles
+$p5-dark-selected: $medium-dark;
+$p5-dark-activeline: #cfcfcf22;
+$p5-dark-pink: #de4a9b;
+$p5-dark-gray: #9b9b9b;
+$p5-dark-lightblue: #0f9dd7;
+$p5-dark-white: #fdfdfd;
+$p5-dark-orange: #ee9900;
+$p5-dark-green: #58a10b;
+$p5-dark-goldbrown: #b58318;
+
+// Contrast highlight styles
+$p5-contrast-selected: $middle-dark;
+$p5-contrast-activeline: #333333aa;
+$p5-contrast-white: #fdfdfd;
+$p5-contrast-lightgray: #c1c1c1;
+$p5-contrast-blue: #00ffff;
+$p5-contrast-green: #2de9b6;
+$p5-contrast-yellow: #f5dc23;
+$p5-contrast-orange: #ffa95d;
+$p5-contrast-pink: #ffa9d9;
+
$themes: (
light: (
- admonition-background: #E4F8FF,
- admonition-border: #22C8ED,
+ activeline-background-color: $p5-light-activeline,
+ admonition-background: #e4f8ff,
+ admonition-border: #22c8ed,
admonition-text: #075769,
background-color: $lighter,
button-active-color: $lightest,
@@ -44,9 +79,9 @@ $themes: (
button-hover-color: $lightest,
button-nav-inactive-color: $middle-gray,
button-secondary-background-color: $medium-light,
- codefold-icon-closed: url("../images/triangle-arrow-right.svg?byUrl"),
- codefold-icon-open: url("../images/triangle-arrow-down.svg?byUrl"),
- console-active-arrow-color: #0071AD,
+ codefold-icon-closed: url('../images/triangle-arrow-right.svg?byUrl'),
+ codefold-icon-open: url('../images/triangle-arrow-down.svg?byUrl'),
+ console-active-arrow-color: #0071ad,
console-arrow-color: $middle-gray,
console-background-color: $light,
console-color: $darker,
@@ -63,13 +98,26 @@ $themes: (
form-secondary-title-color: $medium-dark,
form-title-color: rgba(51, 51, 51, 0.87),
heavy-text-color: $darker,
+ highlight-style-comment-color: $p5-light-lightgray,
+ highlight-style-variable-color: $p5-light-blue,
+ highlight-style-string-color: $p5-light-green,
+ highlight-style-regexp-color: $p5-light-orange,
+ highlight-style-number-color: $p5-light-black,
+ highlight-style-atom-color: $p5-light-pink,
+ highlight-style-keyword-color: $p5-light-brown,
+ highlight-style-operator-color: $p5-light-brown,
+ highlight-style-def-color: $p5-light-blue,
+ highlight-style-tag-color: $p5-light-pink,
+ highlight-style-property-color: $p5-light-black,
+ highlight-style-attribute-color: $p5-light-black,
+ highlight-style-matching-selection-background-color: $p5js-pink-opacity,
hint-arrow-background-active-color: $p5js-active-pink,
hint-arrow-background-color: #ed225ddd,
hint-arrow-color: $lightest,
hint-arrow-focus-outline-color: $middle-dark,
hint-background-color: $white,
- hint-fun-active-border-bottom-color: #0B7CA9,
- hint-fun-text-color: #0B7CA9,
+ hint-fun-active-border-bottom-color: #0b7ca9,
+ hint-fun-text-color: #0b7ca9,
hint-inline-text-color-light: $middle-light,
hint-inline-text-color: $middle-gray,
hint-item-active-background-color: $middle-gray,
@@ -79,12 +127,12 @@ $themes: (
hint-item-active-type-text-color: $white,
hint-item-border-bottom-color: $white,
hint-item-hover-background-color: #f4f4f4,
- hint-keyword-text-color: #7A5A3A,
+ hint-keyword-text-color: #7a5a3a,
hint-no-link-background-color: $medium-light,
hint-text-color: $dark,
hint-type-text-color: $medium-dark,
- hint-var-active-border-bottom-color: #D52889,
- hint-var-text-color: #D52889,
+ hint-var-active-border-bottom-color: #d52889,
+ hint-var-text-color: #d52889,
icon-color: $middle-gray,
icon-hover-color: $darker,
icon-toast-hover-color: $lightest,
@@ -115,9 +163,10 @@ $themes: (
search-hover-background-color: $medium-dark,
search-hover-text-color: $lightest,
secondary-text-color: $medium-dark,
+ selected-background-color: $p5-light-selected,
shadow-color: rgba(0, 0, 0, 0.16),
table-button-active-color: $lightest,
- table-button-background-active-color: #00A1D3,
+ table-button-background-active-color: #00a1d3,
table-button-background-color: $middle-gray,
table-button-background-hover-color: $p5js-pink,
table-button-color: $lightest,
@@ -127,12 +176,13 @@ $themes: (
toast-background-color: $medium-dark,
toast-text-color: $lightest,
toolbar-button-background-color: $medium-light,
- toolbar-button-color: $dark,
+ toolbar-button-color: $dark
),
dark: (
- admonition-background: #105A7F,
- admonition-border: #22C8ED,
- admonition-text: #FFFFFF,
+ activeline-background-color: $p5-dark-activeline,
+ admonition-background: #105a7f,
+ admonition-border: #22c8ed,
+ admonition-text: #ffffff,
background-color: $darker,
button-active-color: $lightest,
button-background-active-color: $p5js-active-pink,
@@ -143,9 +193,9 @@ $themes: (
button-hover-color: $lightest,
button-nav-inactive-color: $middle-light,
button-secondary-background-color: $medium-dark,
- codefold-icon-closed: url("../images/triangle-arrow-right-white.svg?byUrl"),
- codefold-icon-open: url("../images/triangle-arrow-down-white.svg?byUrl"),
- console-active-arrow-color: #097BB3,
+ codefold-icon-closed: url('../images/triangle-arrow-right-white.svg?byUrl'),
+ codefold-icon-open: url('../images/triangle-arrow-down-white.svg?byUrl'),
+ console-active-arrow-color: #097bb3,
console-arrow-color: $medium-light,
console-background-color: $dark,
console-color: $lightest,
@@ -161,13 +211,26 @@ $themes: (
form-secondary-title-color: $medium-light,
form-title-color: $lightest,
heavy-text-color: $lightest,
+ highlight-style-comment-color: $p5-dark-gray,
+ highlight-style-variable-color: $p5-dark-lightblue,
+ highlight-style-string-color: $p5-dark-green,
+ highlight-style-regexp-color: $p5-dark-orange,
+ highlight-style-number-color: $p5-dark-white,
+ highlight-style-atom-color: $p5-dark-pink,
+ highlight-style-keyword-color: $p5-dark-goldbrown,
+ highlight-style-operator-color: $p5-dark-goldbrown,
+ highlight-style-def-color: $p5-dark-lightblue,
+ highlight-style-tag-color: $p5-dark-pink,
+ highlight-style-property-color: $p5-dark-white,
+ highlight-style-attribute-color: $p5-dark-lightblue,
+ highlight-style-matching-selection-background-color: $p5js-pink-opacity,
hint-arrow-background-active-color: $p5js-active-pink,
hint-arrow-background-color: #ed225ddd,
hint-arrow-color: $lightest,
hint-arrow-focus-outline-color: #cfcfcf,
hint-background-color: $darker,
- hint-fun-active-border-bottom-color: #0F9DD7,
- hint-fun-text-color: #0F9DD7,
+ hint-fun-active-border-bottom-color: #0f9dd7,
+ hint-fun-text-color: #0f9dd7,
hint-inline-text-color-light: $middle-gray,
hint-inline-text-color: #cfcfcf,
hint-item-active-background-color: #cfcfcf,
@@ -177,12 +240,12 @@ $themes: (
hint-item-active-type-text-color: $darker,
hint-item-border-bottom-color: $darker,
hint-item-hover-background-color: $medium-dark,
- hint-keyword-text-color: #B58318,
+ hint-keyword-text-color: #b58318,
hint-no-link-background-color: $medium-dark,
hint-text-color: $light,
hint-type-text-color: $light,
- hint-var-active-border-bottom-color: #DE4A9B,
- hint-var-text-color: #DE4A9B,
+ hint-var-active-border-bottom-color: #de4a9b,
+ hint-var-text-color: #de4a9b,
icon-color: $middle-light,
icon-hover-color: $lightest,
icon-toast-hover-color: $lightest,
@@ -213,9 +276,10 @@ $themes: (
search-hover-background-color: $p5js-pink,
search-hover-text-color: $lightest,
secondary-text-color: $medium-light,
+ selected-background-color: $p5-dark-selected,
shadow-color: rgba(0, 0, 0, 0.16),
table-button-active-color: $lightest,
- table-button-background-active-color: #00A1D3,
+ table-button-background-active-color: #00a1d3,
table-button-background-color: $middle-gray,
table-button-background-hover-color: $p5js-pink,
table-button-color: $lightest,
@@ -225,11 +289,12 @@ $themes: (
toast-background-color: $medium-light,
toast-text-color: $dark,
toolbar-button-background-color: $medium-dark,
- toolbar-button-color: $lightest,
+ toolbar-button-color: $lightest
),
contrast: (
+ activeline-background-color: $p5-contrast-activeline,
admonition-background: #000000,
- admonition-border: #22C8ED,
+ admonition-border: #22c8ed,
admonition-text: #ffffff,
background-color: $darker,
button-active-color: $dark,
@@ -241,8 +306,8 @@ $themes: (
button-hover-color: $dark,
button-nav-inactive-color: $light,
button-secondary-background-color: $medium-dark,
- codefold-icon-closed: url("../images/triangle-arrow-right-white.svg?byUrl"),
- codefold-icon-open: url("../images/triangle-arrow-down-white.svg?byUrl"),
+ codefold-icon-closed: url('../images/triangle-arrow-right-white.svg?byUrl'),
+ codefold-icon-open: url('../images/triangle-arrow-down-white.svg?byUrl'),
console-active-arrow-color: $dodgerblue,
console-arrow-color: $lightest,
console-background-color: $dark,
@@ -258,13 +323,26 @@ $themes: (
form-secondary-title-color: $medium-light,
form-title-color: $lightest,
heavy-text-color: $yellow,
- hint-arrow-background-active-color: #F5DC23,
- hint-arrow-background-color: #F5DC23DD,
+ highlight-style-comment-color: $p5-contrast-lightgray,
+ highlight-style-variable-color: $p5-contrast-blue,
+ highlight-style-string-color: $p5-contrast-green,
+ highlight-style-regexp-color: $p5-contrast-green,
+ highlight-style-number-color: $p5-contrast-pink,
+ highlight-style-atom-color: $p5-contrast-pink,
+ highlight-style-keyword-color: $p5-contrast-yellow,
+ highlight-style-operator-color: $p5-contrast-lightgray,
+ highlight-style-def-color: $p5-contrast-blue,
+ highlight-style-tag-color: $p5-contrast-orange,
+ highlight-style-property-color: $p5-contrast-white,
+ highlight-style-attribute-color: $p5-contrast-white,
+ highlight-style-matching-selection-background-color: $medium-dark,
+ hint-arrow-background-active-color: #f5dc23,
+ hint-arrow-background-color: #f5dc23dd,
hint-arrow-color: $darker,
hint-arrow-focus-outline-color: $lighter,
hint-background-color: $darkest,
hint-fun-active-border-bottom-color: none,
- hint-fun-text-color: #00FFFF,
+ hint-fun-text-color: #00ffff,
hint-inline-text-color-light: $middle-gray,
hint-inline-text-color: #cfcfcf,
hint-item-active-background-color: unset,
@@ -274,12 +352,12 @@ $themes: (
hint-item-active-type-text-color: $lighter,
hint-item-border-bottom-color: $medium-dark,
hint-item-hover-background-color: $dark,
- hint-keyword-text-color: #F5DC23,
+ hint-keyword-text-color: #f5dc23,
hint-no-link-background-color: $medium-dark,
hint-text-color: $medium-light,
hint-type-text-color: $middle-light,
hint-var-active-border-bottom-color: none,
- hint-var-text-color: #FFA9D9,
+ hint-var-text-color: #ffa9d9,
icon-color: $medium-light,
icon-hover-color: $yellow,
icon-toast-hover-color: $yellow,
@@ -310,9 +388,10 @@ $themes: (
search-hover-background-color: $yellow,
search-hover-text-color: $dark,
secondary-text-color: $lighter,
+ selected-background-color: $p5-contrast-selected,
shadow-color: rgba(0, 0, 0, 0.16),
table-button-active-color: $dark,
- table-button-background-active-color: #00FFFF,
+ table-button-background-active-color: #00ffff,
table-button-background-color: $middle-gray,
table-button-background-hover-color: $yellow,
table-button-color: $dark,
@@ -322,6 +401,6 @@ $themes: (
toast-background-color: $medium-light,
toast-text-color: $darker,
toolbar-button-background-color: $medium-light,
- toolbar-button-color: $dark,
+ toolbar-button-color: $dark
)
);
diff --git a/client/styles/components/_editor.scss b/client/styles/components/_editor.scss
index 0aab1d4b9f..e01e2095f8 100644
--- a/client/styles/components/_editor.scss
+++ b/client/styles/components/_editor.scss
@@ -1,378 +1,220 @@
@use "sass:math";
-.CodeMirror {
+.cm-editor {
font-family: Inconsolata, monospace;
height: 100%;
-}
-
-.CodeMirror-linenumbers {
- padding-right: #{math.div(10, $base-font-size)}rem;
-}
-.CodeMirror-linenumber {
- width: #{math.div(32, $base-font-size)}rem;
- left: #{math.div(-3, $base-font-size)}rem !important;
@include themify() {
- color: getThemifyVariable("inactive-text-color");
+ color: getThemifyVariable('primary-text-color');
}
-}
-
-.CodeMirror-lines {
- padding-top: #{math.div(25, $base-font-size)}rem;
-}
-
-pre.CodeMirror-line {
- padding-left: #{math.div(5, $base-font-size)}rem;
-}
-
-.CodeMirror-gutter-wrapper {
- right: 100%;
- top: 0;
- bottom: 0;
-}
-
-.CodeMirror-lint-marker-warning,
-.CodeMirror-lint-marker-error,
-.CodeMirror-lint-marker-multiple {
- background-image: none;
- width: #{math.div(49, $base-font-size)}rem;
- position: absolute;
- height: 100%;
- right: 100%;
-}
-
-.CodeMirror-lint-message-error,
-.CodeMirror-lint-message-warning {
- background-image: none;
- padding-left: inherit;
-}
-.CodeMirror-lint-marker-warning {
- background-color: rgb(255, 190, 5);
-}
+ .cm-scroller {
+ font-family: Inconsolata, monospace;
+ line-height: 1.2;
+ }
-.CodeMirror-lint-marker-error {
- background-color: rgb(255, 95, 82);
-}
+ .cm-content {
+ padding-top: #{math.div(25, $base-font-size)}rem;
+
+ .cm-activeLine {
+ // Needed to place the active line highlight behind the selection highlight.
+ position: relative;
+ background-color: transparent;
+
+ &::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: -10;
+
+ @include themify() {
+ background-color: getThemifyVariable('activeline-background-color');
+ }
+ }
+ }
-.CodeMirror-gutter-elt:not(.CodeMirror-linenumber) {
- opacity: 0.2;
- width: #{math.div(49, $base-font-size)}rem !important;
- height: 100%;
- left: 49px !important;
- // background-color: rgb(255, 95, 82);
-}
+ .cm-errorLine.cm-activeLine,
+ .cm-errorLine {
+ background-color: rgb(255 95 82 / 30%);
+ }
+ }
+ .cm-focused > .cm-scroller .cm-selectionLayer .cm-selectionBackground,
+ .cm-selectionLayer .cm-selectionBackground,
+ ::selection {
+ @include themify() {
+ background-color: getThemifyVariable(
+ 'selected-background-color'
+ ) !important;
+ }
+ }
-.CodeMirror-lint-tooltip {
- @include themify() {
- background-color: getThemifyVariable("modal-background-color");
- border: 1px solid getThemifyVariable("modal-border-color");
- box-shadow: 0 12px 12px getThemifyVariable("shadow-color");
- color: getThemifyVariable("primary-text-color");
+ .cm-cursorLayer .cm-cursor {
+ @include themify() {
+ border-left-color: getThemifyVariable('primary-text-color');
+ }
}
- border-radius: 2px;
- font-family: Montserrat, sans-serif;
}
-.CodeMirror-gutters {
+.cm-gutters {
@include themify() {
- background-color: getThemifyVariable("editor-gutter-color");
- border-color: getThemifyVariable("ide-border-color");
+ background-color: getThemifyVariable('editor-gutter-color');
+ border-color: getThemifyVariable('ide-border-color');
}
- // left: 0 !important;
width: #{math.div(48, $base-font-size)}rem;
-}
-
-/*
- Search dialog
-*/
+ position: relative;
-.CodeMirror-dialog {
- position: fixed;
- top: 0;
- left: 50%;
- margin-left: #{math.div(-552 * 0.5, $base-font-size)}rem;
-
- @media (max-width: 770px) {
- left: 0;
- right: 0;
- width: 100%;
- margin-left: 0;
+ .cm-gutter {
+ z-index: 1;
}
- z-index: 10;
-
- width: 580px;
- font-family: Montserrat, sans-serif;
-
- padding: #{math.div(8, $base-font-size)}rem #{math.div(10, $base-font-size)}rem #{math.div(5, $base-font-size)}rem #{math.div(9, $base-font-size)}rem;
-
- border-radius: 2px;
-
- @include themify() {
- background-color: getThemifyVariable("modal-background-color");
- box-shadow: 0 12px 12px 0 getThemifyVariable("shadow-color");
- border: solid 0.5px getThemifyVariable("modal-border-color");
+ .cm-lineNumbers {
+ @include themify() {
+ color: getThemifyVariable('inactive-text-color');
+ }
+ pointer-events: none;
}
-}
-
-.CodeMirror-find-popup-container {
- display: flex;
- flex-wrap: wrap;
- justify-content: space-between;
-}
-
-.Toggle-replace-btn-div {
- height: #{math.div(40, $base-font-size)}rem;
- padding: 0;
-}
-.Toggle-replace-btn-div > button {
- width: 100%;
- height: 100%;
-}
-
-.CodeMirror-search-results {
- margin: 0 #{math.div(20, $base-font-size)}rem;
- width: #{math.div(75, $base-font-size)}rem;
- font-size: #{math.div(12, $base-font-size)}rem;
-}
-
-.CodeMirror-find-controls {
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: space-between;
- height: #{math.div(35, $base-font-size)}rem;
-}
-.CodeMirror-search-inputs {
- width: 30%;
- margin-left: 10px;
-}
-.CodeMirror-replace-div {
- display: flex;
- justify-content: flex-start;
- align-items: center;
-}
-.CodeMirror-search-controls {
- width: 60%;
- display: flex;
- flex-wrap: wrap-reverse;
- justify-content: flex-start;
- align-items: flex-end;
-}
-.CodeMirror-replace-controls {
- display: flex;
- margin-left: #{math.div(10, $base-font-size)}rem;
-}
-
-.CodeMirror-replace-options {
- width: #{math.div(552, $base-font-size)}rem;
- height: #{math.div(65, $base-font-size)}rem;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-.CodeMirror-replace-options button {
- width: #{math.div(200, $base-font-size)}rem;
-}
+ .cm-activeLineGutter {
+ background-color: transparent;
+ }
-.CodeMirror-search-title {
- display: block;
- margin-bottom: #{math.div(12, $base-font-size)}rem;
+ .cm-gutter-lint {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ z-index: 0;
- font-size: #{math.div(21, $base-font-size)}rem;
- font-weight: bold;
-}
+ .cm-activeLineGutter {
+ @include themify() {
+ background-color: getThemifyVariable('active-line-background-color');
+ }
+ }
-.CodeMirror-search-field {
- display: block;
- width: 100%;
- max-width: #{math.div(166, $base-font-size)}rem;
- margin-bottom: #{math.div(4, $base-font-size)}rem;
- @include themify() {
- color: getThemifyVariable("input-text-color");
- background-color: getThemifyVariable("input-secondary-background-color");
- border: solid 0.5px getThemifyVariable("button-border-color");
- &::placeholder {
- color: getThemifyVariable("inactive-text-color");
+ .cm-gutterElement {
+ padding: 0;
}
}
-}
-
-.CodeMirror-search-nav {
- display: flex;
- align-items: center;
-}
-.CodeMirror-search-count {
- display: block;
- height: #{math.div(20, $base-font-size)}rem;
- text-align: right;
-}
-
-.CodeMirror-search-actions {
- display: flex;
- justify-content: space-between;
-}
+ .cm-lint-marker {
+ content: '';
+ width: 100%;
+ height: 100%;
+ opacity: 0.2;
-.CodeMirror-search-modifiers {
- display: flex;
- justify-content: flex-end;
- align-items: center;
- margin-left: #{math.div(10, $base-font-size)}rem;
+ &.cm-lint-marker-error {
+ background-color: rgb(255, 95, 82);
+ }
- @media (max-width: 579px) {
- display: none;
+ &.cm-lint-marker-warning {
+ background-color: rgb(255, 190, 5);
+ }
}
}
-.CodeMirror-regexp-button,
-.CodeMirror-case-button,
-.CodeMirror-word-button {
+.cm-tooltip-lint {
@include themify() {
- // @extend %button;
- padding: #{math.div(2, $base-font-size)}rem #{math.div(7, $base-font-size)}rem;
- border: 2px solid transparent;
- &:hover {
- border-color: getThemifyVariable("button-border-color");
- }
+ background-color: getThemifyVariable('modal-background-color');
+ border: 1px solid getThemifyVariable('modal-border-color');
+ box-shadow: 0 12px 12px getThemifyVariable('shadow-color');
+ color: getThemifyVariable('primary-text-color');
}
- width: #{math.div(35, $base-font-size)}rem;
- height: #{math.div(35, $base-font-size)}rem;
-
- & + & {
- margin-left: #{math.div(3, $base-font-size)}rem;
- }
-
- word-break: keep-all;
- white-space: nowrap;
-}
-
-.CodeMirror-regexp-button .label,
-.CodeMirror-case-button .label,
-.CodeMirror-word-button .label {
- @extend %hidden-element;
+ border-radius: 2px;
+ font-family: Montserrat, sans-serif;
}
-[aria-checked="true"] {
+/** Search dialog */
+.cm-search.cm-panel {
@include themify() {
- color: getThemifyVariable("heavy-text-color");
- background-color: getThemifyVariable("button-secondary-background-color");
- border-color: getThemifyVariable("button-border-color");
+ color: getThemifyVariable('primary-text-color');
+ background-color: getThemifyVariable('modal-background-color');
+ box-shadow: 0 12px 12px 0 getThemifyVariable('shadow-color');
+ border: solid 0.5px getThemifyVariable('modal-border-color');
}
-}
-
-/*
- Previous / Next buttons
-*/
+ font-family: Montserrat, sans-serif;
-// Visually hide button text
-.CodeMirror-search-button .label {
- @extend %hidden-element;
-}
+ .cm-button {
+ @include themify() {
+ @extend %link;
+ color: getThemifyVariable('secondary-text-color');
+ &:hover {
+ color: getThemifyVariable('logo-color');
+ }
+ }
+ background: transparent;
+ border: none;
+ font-size: 1rem;
+ }
-.CodeMirror-search-button {
- margin-right: #{math.div(10, $base-font-size)}rem;
+ input.cm-textfield {
+ @include themify() {
+ color: getThemifyVariable('input-text-color');
+ background-color: getThemifyVariable('input-secondary-background-color');
+ border: solid 0.5px getThemifyVariable('button-border-color');
+ &::placeholder {
+ color: getThemifyVariable('inactive-text-color');
+ }
+ }
+ }
}
-.CodeMirror-search-match {
- background: gold;
- border-top: #{math.div(1, $base-font-size)}rem solid orange;
- border-bottom: #{math.div(1, $base-font-size)}rem solid orange;
- box-sizing: border-box;
- opacity: 0.5;
+// CM5: .CodeMirror-foldgutter-open, .CodeMirror-foldgutter-folded
+.cm-foldGutter {
+ padding-right: #{math.div(3, $base-font-size)}rem;
}
-/*
- Close button
-*/
-.CodeMirror-close-button-container {
+.cm-foldGutter .cm-gutterElement {
+ cursor: pointer;
display: flex;
align-items: center;
+ justify-content: center;
}
-// foldgutter
-.CodeMirror-foldmarker {
- text-shadow:
- -1px 0 #ed225d,
- 0 1px #ed225d,
- 1px 0 #ed225d,
- 0 -1px #ed225d;
- color: #fff;
- /* background-color: rgba(237, 34, 93, 0.42); */
- /* border-radius: 3px; */
- font-weight: bold;
- font-family: arial;
- line-height: 0.3;
- cursor: pointer;
- opacity: 0.75;
-}
-.CodeMirror-foldgutter {
- width: 2.7em;
-}
-.CodeMirror-foldgutter-open,
-.CodeMirror-foldgutter-folded {
- cursor: pointer;
- padding-bottom: 0.4em;
- text-align: right;
- line-height: 1;
-}
-.CodeMirror-foldgutter-open:after {
- content: "\25BE";
-}
-.CodeMirror-foldgutter-folded:after {
- content: "\25B8";
-}
-
-.CodeMirror-foldgutter-open,
-.CodeMirror-foldgutter-folded {
- position: absolute;
- right: 100%;
+// CM5: .CodeMirror-foldgutter-open:after / .CodeMirror-foldgutter-folded:after
+.cm-fold-open,
+.cm-fold-closed {
+ display: inline-block;
+ width: #{math.div(10, $base-font-size)}rem;
+ height: #{math.div(10, $base-font-size)}rem;
+ background-size: #{math.div(10, $base-font-size)}rem #{math.div(
+ 10,
+ $base-font-size
+ )}rem;
+ background-repeat: no-repeat;
+ background-position: center center;
+ opacity: 0.4;
}
-.CodeMirror-foldgutter-open:after {
+.cm-fold-open {
@include themify() {
- background-image: getThemifyVariable("codefold-icon-open");
+ background-image: getThemifyVariable('codefold-icon-open');
}
}
-.CodeMirror-foldgutter-folded:after {
+.cm-fold-closed {
@include themify() {
- background-image: getThemifyVariable("codefold-icon-closed");
+ background-image: getThemifyVariable('codefold-icon-closed');
}
}
-.CodeMirror-foldgutter-folded:after,
-.CodeMirror-foldgutter-open:after {
- background-size: 10px 10px;
- content: "";
- padding-left: 15px;
- background-repeat: no-repeat;
- background-position: center center;
-}
-
-.CodeMirror-foldmarker {
- text-shadow: none;
- border-radius: 5px;
- opacity: 1;
- font-weight: normal;
+// CM5: .CodeMirror-foldmarker
+.cm-foldPlaceholder {
display: inline-block;
vertical-align: middle;
height: 0.85em;
line-height: 0.7;
+ border-radius: 5px;
padding: 0 #{math.div(5, $base-font-size)}rem;
font-family: serif;
-}
-
-.line-runtime-error + .CodeMirror-activeline-gutter {
- background-color: rgb(255, 95, 82);
- opacity: 0.3;
-}
+ cursor: pointer;
+ opacity: 0.75;
-.line-runtime-error {
- background-color: rgb(255, 95, 82) !important;
- opacity: 0.3;
+ @include themify() {
+ background-color: getThemifyVariable('primary-text-color');
+ color: getThemifyVariable('background-color');
+ }
}
.editor-holder {
@@ -380,7 +222,7 @@ pre.CodeMirror-line {
width: 100%;
position: absolute;
@include themify() {
- border: 1px solid getThemifyVariable("ide-border-color");
+ border: 1px solid getThemifyVariable('ide-border-color');
}
&.editor-holder--hidden .CodeMirror {
display: none;
@@ -393,7 +235,7 @@ pre.CodeMirror-line {
.editor__file-name {
@include themify() {
- color: getThemifyVariable("primary-text-color");
+ color: getThemifyVariable('primary-text-color');
}
height: #{math.div(29, $base-font-size)}rem;
padding-top: #{math.div(7, $base-font-size)}rem;
@@ -406,7 +248,7 @@ pre.CodeMirror-line {
.editor__library-version {
@include themify() {
- color: getThemifyVariable("primary-text-color");
+ color: getThemifyVariable('primary-text-color');
}
position: absolute;
top: 0;
@@ -422,41 +264,140 @@ pre.CodeMirror-line {
}
/** Inline abbreviation preview */
-
-.emmet-abbreviation-preview {
+.emmet-preview.cm-tooltip {
@extend %modal;
- position: absolute;
@include themify() {
- background: getThemifyVariable("background-color");
+ background: getThemifyVariable('background-color');
}
- & .CodeMirror-lines {
+ .cm-content {
padding: 0;
}
- & .CodeMirror {
- height: auto;
- max-width: #{math.div(400, $base-font-size)}rem;
- max-height: #{math.div(300, $base-font-size)}rem;
- border: none;
+}
+
+// Used for comment, lineComment, blockComment, docComment, docString
+.cm-comment {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-comment-color');
}
}
-.emmet-abbreviation-preview:not(.has-error) .emmet-abbreviation-preview-error {
- display: none;
+// Used for name, variableName, typeName
+.cm-variable {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-variable-color');
+ }
+}
+
+// Used for string, character, attributeValue
+.cm-string {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-string-color');
+ }
+}
+
+// Used for regexp
+.cm-regexp {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-regexp-color');
+ }
+}
+
+// Used for number, integer, float
+.cm-number {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-number-color');
+ }
+}
+
+// Used for bool, atom, null
+.cm-atom {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-atom-color');
+ }
+}
+
+// Used for keyword, self, function, className
+.cm-keyword {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-keyword-color');
+ }
+}
+
+// Used for operatorKeyword, controlKeyword, operator, derefOperator, arithmeticOperator,
+// logicOperator, bitwiseOperator, compareOperator, updateOperator, typeOperator
+// controlOperator
+.cm-operator {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-operator-color');
+ }
}
-.emmet-abbreviation-preview.has-error .CodeMirror {
- display: none;
+// Used for definitionKeyword, definition, const, local
+.cm-def {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-def-color');
+ }
}
-.emmet-abbreviation-preview .CodeMirror-cursors {
- visibility: hidden !important;
+// tagName, heading, heading1, heading2, heading3, heading4, heading5, heading6,
+// list, quote, emphasis, strong, link
+.cm-tag {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-tag-color');
+ }
}
-.emmet-abbreviation-preview .emmet-error-snippet-message {
- padding: 5px;
+// Used for propertyName
+.cm-property {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-property-color');
+ }
}
-.emmet-open-tag,
-.emmet-close-tag {
- text-decoration: underline;
+// Used for attributeName
+.cm-attribute {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-attribute-color');
+ }
+}
+
+// Unassigned Lezer tags: literal, escape, color, url, unit, modifier, punctuation,
+// separator, bracket, angleBracket, squareBracket, paren, brace, content
+// contentSeparator, monospace, strikethrough, inserted, deleted, changed, invalid, meta,
+// documentMeta, annotation, processingInstruction, standard, special, macroName
+
+// CM6 uses EditorView.theme() instead of cm-s-* classes, so the p5 highlight styles
+// from the CM5 theme files do not apply. These rules replicate them for CM6.
+.cm-p5-function,
+.cm-p5-function .cm-variable {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-variable-color');
+ font-weight: bold;
+ }
+}
+
+.cm-p5-variable,
+.cm-p5-variable .cm-variable {
+ @include themify() {
+ color: getThemifyVariable('highlight-style-atom-color');
+ }
+}
+
+// Additional matching selection styling
+.cm-matchingBracket {
+ @include themify() {
+ outline: 1px solid getThemifyVariable('primary-text-color');
+ outline-offset: 1px;
+ background-color: transparent !important;
+ }
+}
+
+.cm-selectionMatch,
+.cm-searchMatch,
+.cm-searchMatch-selected {
+ @include themify() {
+ background-color: getThemifyVariable(
+ 'highlight-style-matching-selection-background-color'
+ );
+ }
}
diff --git a/client/styles/components/_hints.scss b/client/styles/components/_hints.scss
index 7084b460e7..2c22413ed0 100644
--- a/client/styles/components/_hints.scss
+++ b/client/styles/components/_hints.scss
@@ -1,276 +1,250 @@
@use "sass:math";
-.CodeMirror-hints {
- position: absolute;
- z-index: 10;
- overflow: hidden;
- list-style: none;
-
- margin: 0;
- padding: 0;
-
+.cm-tooltip-autocomplete.CodeMirror-hints {
box-shadow: 0 0 #{math.div(18, $base-font-size)}rem 0 rgba(0, 0, 0, 0.16);
border: #{math.div(1, $base-font-size)}rem solid #A6A6A6;
-
- font-size: 100%;
font-family: Inconsolata, monospace;
-
- width: 20rem;
- max-height: 20rem;
- overflow-y: auto;
-
- transform-origin: top left;
+ font-size: 1rem;
@include themify() {
background: getThemifyVariable('hint-background-color');
+ color: getThemifyVariable('hint-text-color');
+ }
- .CodeMirror-hint {
- color: getThemifyVariable('hint-text-color');
- border-bottom: #{math.div(1, $base-font-size)}rem solid getThemifyVariable('hint-item-border-bottom-color');
+ ul {
+ @include themify() {
+ background: getThemifyVariable('hint-background-color');
}
+ }
- .hint-container {
- display: flex;
- align-items: center;
- flex-direction: column;
- justify-content: center;
- width: 100%;
- height: 100%;
+ li.CodeMirror-hint {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto #{math.div(40, $base-font-size)}rem;
+ align-items: center;
+ min-height: #{math.div(24, $base-font-size)}rem;
+ font-weight: 500;
- // Widen the entire row only if a warning is present
- &.has-warning {
- width: 100%; // Let it fill the parent .CodeMirror-hint width
- max-width: 24rem;
- }
+ @include themify() {
+ background: getThemifyVariable('hint-background-color');
+ color: getThemifyVariable('hint-text-color');
+ border-bottom: #{math.div(1, $base-font-size)}rem solid
+ getThemifyVariable('hint-item-border-bottom-color');
}
- .hint-main {
- display: flex;
- justify-content: space-between;
- align-items: center;
- flex-grow: 1;
- padding: 0 0.5rem;
- width: 100%;
- height: 100%;
- // position: relative; // optional, only if you want absolutely-positioned children
+ &:hover:not([aria-selected='true']) {
+ @include themify() {
+ background: getThemifyVariable('hint-item-hover-background-color');
+ }
}
- .hint-main a {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 2rem;
- height: 100%;
- padding: 0;
- // margin-left: auto;
- text-align: center;
- text-decoration: none;
- font-size: 1.2rem;
- }
+ &[aria-selected='true'] {
+ @include themify() {
+ background: getThemifyVariable('hint-item-active-background-color');
+ color: getThemifyVariable('hint-item-active-text-color');
+ outline: getThemifyVariable('hint-item-active-outline');
+ outline-offset: getThemifyVariable('hint-item-active-outline-offset');
+ }
- .hint-name {
- font-size: 1.2rem;
- font-weight: bold;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
+ .cm-completionKind {
+ @include themify() {
+ color: getThemifyVariable('hint-item-active-type-text-color');
+ }
+ }
- .hint-type {
- font-size: 1rem;
- font-weight: normal;
- color: #999;
- margin-left: 1rem;
- margin-right: 2.5rem; // leaves space for the arrow icon
- white-space: nowrap;
- flex-shrink: 0;
+ .cm-completionMatchedText {
+ color: inherit;
+ }
}
- // Warning box
- .blacklist-warning {
- background-color: #fff3cd;
- border: 1px solid #ffc107;
- color: #856404;
- padding: 6px 10px;
- border-radius: 4px;
- font-size: 0.85rem;
- margin: 0.25rem 0.5rem 0 0.5rem;
- width: calc(100% - 1rem); // Match padding
- box-sizing: border-box;
- }
-
- .fun-name, .obj-name {
- color: getThemifyVariable('hint-fun-text-color');
- }
-
- .var-name, .boolean-name {
- color: getThemifyVariable('hint-var-text-color');
+ &.blacklisted {
+ height: auto;
+ min-height: 3.2rem; // enough to show the warning + content
}
+ }
- .keyword-name {
- color: getThemifyVariable('hint-keyword-text-color');
- }
-
- .hint-type {
+ .cm-completionLabel {
+ grid-column: 1;
+ justify-self: start;
+ margin-left: #{math.div(12, $base-font-size)}rem;
+ line-height: 1.1;
+ font-weight: 600;
+ color: inherit;
+ background: transparent;
+ }
+
+ .cm-completionMatchedText {
+ color: inherit;
+ text-decoration: none;
+ font-weight: inherit;
+ }
+
+ .cm-completionDetail {
+ display: none;
+ }
+
+ .cm-completionKind {
+ grid-column: 2;
+ justify-self: end;
+ padding-right: #{math.div(28, $base-font-size)}rem;
+ font-size: 0.8rem;
+
+ @include themify() {
color: getThemifyVariable('hint-type-text-color');
- margin-right: #{math.div(10, $base-font-size)}rem;
}
-
- a {
- color: getThemifyVariable('hint-arrow-color');
+ }
+
+ .cm-completionRefLink {
+ grid-column: 3;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ align-self: stretch;
+ width: 75%;
+ text-decoration: none;
+
+ @include themify() {
background: getThemifyVariable('hint-arrow-background-color');
+ color: getThemifyVariable('hint-arrow-color');
+ }
- &:hover, &:active, &.focused-hint-link {
+ &:hover,
+ &:active,
+ &.focused-hint-link {
+ @include themify() {
background: getThemifyVariable('hint-arrow-background-active-color');
}
+ }
+
+ &.focused-hint-link {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ align-self: stretch;
- &.focused-hint-link {
- outline: #{math.div(3, $base-font-size)}rem solid getThemifyVariable('hint-arrow-focus-outline-color');
+ @include themify() {
+ outline: #{math.div(3, $base-font-size)}rem solid
+ getThemifyVariable('hint-arrow-focus-outline-color');
outline-offset: #{math.div(-3, $base-font-size)}rem;
}
}
+ }
- .no-link-placeholder {
+ .cm-completionRefLink--disabled,
+ li:not(.has-doc-link) .cm-completionRefLink {
+ @include themify() {
background: getThemifyVariable('hint-no-link-background-color');
- pointer-events: none;
+ color: getThemifyVariable('hint-arrow-color');
}
-
- li.CodeMirror-hint-active:not(.unfocused) {
- background: getThemifyVariable('hint-item-active-background-color');
- outline: getThemifyVariable('hint-item-active-outline');
- outline-offset: getThemifyVariable('hint-item-active-outline-offset');
-
- // .fun-item {
- // border-bottom: #{2 / $base-font-size}rem solid getThemifyVariable('hint-fun-active-border-bottom-color');
- // }
-
- // .var-item {
- // border-bottom: #{2 / $base-font-size}rem solid getThemifyVariable('hint-var-active-border-bottom-color');
- // }
+ }
- .hint-name {
- color: getThemifyVariable('hint-item-active-text-color');
+ // label colors
+ li.hint-type-method,
+ li.hint-type-obj {
+ .cm-completionLabel,
+ .cm-completionMatchedText {
+ @include themify() {
+ color: getThemifyVariable('hint-fun-text-color');
}
+ }
+ }
- .fun-name, .obj-name {
- background-color: getThemifyVariable('hint-fun-text-color');
- }
-
- .var-name, .boolean-name {
- background-color: getThemifyVariable('hint-var-text-color');
+ li.hint-type-variable,
+ li.hint-type-constant,
+ li.hint-type-boolean {
+ .cm-completionLabel,
+ .cm-completionMatchedText {
+ @include themify() {
+ color: getThemifyVariable('hint-var-text-color');
}
+ }
+ }
- .keyword-name {
- background-color: getThemifyVariable('hint-keyword-text-color');
- }
-
- .hint-type, .plain-hint-item {
- color: getThemifyVariable('hint-item-active-type-text-color');
+ li.hint-type-keyword {
+ .cm-completionLabel,
+ .cm-completionMatchedText {
+ @include themify() {
+ color: getThemifyVariable('hint-keyword-text-color');
}
}
-
- .CodeMirror-hint:hover:not(.CodeMirror-hint-active) {
- background: getThemifyVariable('hint-item-hover-background-color');
- }
}
- .CodeMirror-hint {
- display: flex;
- align-items: center;
- justify-content: space-between;
-
- position: relative;
- margin: 0;
- padding: 0;
- height: 2rem;
- white-space: pre;
- cursor: pointer;
-
- &:has(.focused-hint-link) {
- z-index: 999;
+ // highlighted completion label colors
+ li.hint-type-method[aria-selected='true'],
+ li.hint-type-obj[aria-selected='true'] {
+ .cm-completionLabel {
+ @include themify() {
+ background: getThemifyVariable('hint-fun-text-color');
+ color: getThemifyVariable('hint-item-active-text-color');
+ border-bottom: #{math.div(1, $base-font-size)}rem solid
+ getThemifyVariable('hint-fun-active-border-bottom-color');
+ }
}
+ }
- &:only-child, &:last-child {
- border-bottom: none !important;
+ li.hint-type-variable[aria-selected='true'],
+ li.hint-type-constant[aria-selected='true'],
+ li.hint-type-boolean[aria-selected='true'] {
+ .cm-completionLabel {
+ @include themify() {
+ background: getThemifyVariable('hint-var-text-color');
+ color: getThemifyVariable('hint-item-active-text-color');
+ border-bottom: #{math.div(1, $base-font-size)}rem solid
+ getThemifyVariable('hint-var-active-border-bottom-color');
+ }
}
+ }
- p {
- display: flex;
- width: 100%;
- height: 100%;
- }
-
- .hint-name, .plain-hint-item {
- display: flex;
- align-items: center;
- padding: 0 0.5rem;
- width: min-content;
- font-size: 1.2rem;
- line-height: 100%;
- font-weight: bold;
- }
-
- .hint-type {
- margin: 0.5rem 2.4rem 0.5rem auto;
- font-size: 1rem;
- line-height: 100%;
- font-weight: normal;
+ li.hint-type-keyword[aria-selected='true'] {
+ .cm-completionLabel {
+ @include themify() {
+ background: getThemifyVariable('hint-keyword-text-color');
+ color: getThemifyVariable('hint-item-active-text-color');
+ }
}
+ }
- .hint-hidden {
- @extend %hidden-element;
- }
-
- a, .no-link-placeholder {
- // position: absolute;
- top: 0;
- right: 0;
- height: 100%;
- width: calc(2rem - #{math.div(1, $base-font-size)}rem);
- margin: 0;
- padding-top: 0.4rem;
- font-size: 1.2rem;
- line-height: 100%;
- text-align: center;
- outline: none;
- z-index: 1;
- }
-
- a:focus, a:active {
- outline: 0;
- }
+ .cm-completionWarning {
+ grid-column: 1 / 4;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.35rem;
+ width: fit-content;
+ margin: 0.35rem 0.75rem 0.5rem 0.75rem;
+ padding: 0.32rem 0.55rem;
+ border: 1px solid #d9a300;
+ border-radius: 0.45rem;
+ background: #f3e7b7;
+ color: #9a6b00;
+ font-size: 0.8rem;
+ line-height: 1.1;
+ white-space: nowrap;
}
- .CodeMirror-hint.blacklisted {
- height: auto;
- min-height: 3.2rem; // enough to show the warning + content
+ .cm-completionWarningIcon {
+ flex: 0 0 auto;
+ font-size: 1rem;
}
-}
-// Inline hinter
-.CodeMirror-widget {
- line-height: inherit;
+ .cm-completionWarningText {
+ line-height: 1.1;
+ }
- @include themify() {
- .autocomplete-inline-hinter {
- // make the border left look like a cursor and animate like a cursor
- // border-left: #{1.2 / $base-font-size}rem solid getThemifyVariable(hint-inline-text-color);
- // animation: inline-hint-caret-blink 1s step-end infinite;
- pointer-events: none;
-
- .inline-hinter-suggestion {
- color: getThemifyVariable(hint-inline-text-color);
- font-style: italic;
- }
+ .cm-ghostCompletion {
+ @include themify() {
+ color: getThemifyVariable('hint-inline-text-color');
+ }
+ }
- .inline-hinter-suggestion-light {
- color: getThemifyVariable(hint-inline-text-color-light);
- font-style: italic;
- }
+ .cm-ghostCompletion.cm-ghostCompletion--light {
+ @include themify() {
+ color: getThemifyVariable('hint-inline-text-color-light');
}
}
-}
-@keyframes inline-hint-caret-blink {
- 50% { border-color: transparent; }
+ .hint-hidden {
+ @include themify() {
+ @extend %hidden-element;
+ display: none;
+ }
+ }
}
diff --git a/client/styles/components/_p5-contrast-codemirror-theme.scss b/client/styles/components/_p5-contrast-codemirror-theme.scss
deleted file mode 100644
index 93c604d0cc..0000000000
--- a/client/styles/components/_p5-contrast-codemirror-theme.scss
+++ /dev/null
@@ -1,152 +0,0 @@
-// brown: #6C4D13
-// black: #333
-// blue: #0F9DD7
-// pink: #D9328F
-// gray: #999999
-// dark blue: #318094
-// white: #fdfdfd
-
-//numbers
-//light gray: #f4f4f4
-//dark gray: #b5b5b5
-
-@use "sass:math";
-
-$p5-contrast-black: #1C1C1C;
-$p5-contrast-gray: #A0A0A0;
-$p5-contrast-white: #FDFDFD;
-$p5-contrast-darkgray: #333333;
-$p5-contrast-lightgray: #C1C1C1;
-$p5-contrast-blue: #00FFFF;
-$p5-contrast-green: #2DE9B6;
-$p5-contrast-yellow: #F5DC23;
-$p5-contrast-orange: #FFA95D;
-$p5-contrast-pink: #FFA9D9;
-
-$p5-contrast-gutter: #454545;
-$p5-contrast-number: #FDFDFD;
-$p5-contrast-selected: $middle-dark;
-$p5-contrast-activeline: #999999;
-
-.cm-s-p5-contrast {
- background-color: $p5-contrast-black;
- color: $p5-contrast-white;
-}
-
-.cm-s-p5-contrast span .cm-comment {
- color: $p5-contrast-lightgray;
-}
-
-.cm-s-p5-contrast span .cm-def {
- color: $p5-contrast-blue;
-}
-
-.cm-s-p5-contrast span .cm-string {
- color: $p5-contrast-green;
-}
-
-.cm-s-p5-contrast span .cm-string-2 {
- color: $p5-contrast-green;
-}
-
-.cm-s-p5-contrast span .cm-number {
- color: $p5-contrast-pink;
-}
-
-.cm-s-p5-contrast span .cm-keyword {
- color: $p5-contrast-yellow;
-}
-
-.cm-s-p5-contrast span .cm-variable {
- color: $p5-contrast-white;
-}
-
-.cm-s-p5-contrast span .cm-variable-2 {
- color: $p5-contrast-white;
-}
-
-.cm-s-p5-contrast span .cm-property {
- color: $p5-contrast-white;
-}
-
-.cm-s-p5-contrast span .cm-atom {
- color: $p5-contrast-pink;
-}
-
-.cm-s-p5-contrast span .cm-operator {
- color: $p5-contrast-lightgray;
-}
-
-.cm-s-p5-contrast .cm-linenumber {
- color: $p5-contrast-number;
-}
-
-.cm-s-p5-contrast {
- .CodeMirror-selected { background: $p5-contrast-selected; }
- .CodeMirror-focused .CodeMirror-selected { background: $p5-contrast-selected; }
- .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: $p5-contrast-selected; }
- .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: $p5-contrast-selected; }
-}
-
-.cm-s-p5-contrast .CodeMirror-activeline-background {
- background-color: $dark;
-}
-
-.cm-s-p5-contrast .CodeMirror-activeline-gutter {
- background-color: $dark;
- border-right: 1px solid $middle-dark;
-}
-
-.cm-s-p5-contrast .cm-error {
- color: #f00;
-}
-
-.cm-s-p5-contrast span .CodeMirror-matchingbracket {
- outline: 1px solid $p5-contrast-lightgray;
- outline-offset: 1px;
- color: $p5-contrast-white !important;
-}
-
-.cm-s-p5-contrast span .cm-qualifier {
- color: $p5-contrast-yellow;
-}
-
-.cm-s-p5-contrast span .cm-tag {
- color: $p5-contrast-orange;
-}
-
-.cm-s-p5-contrast span .cm-builtin {
- color: $p5-contrast-yellow;
-}
-
-.cm-s-p5-contrast span .cm-attribute {
- color: $p5-contrast-white;
-}
-
-.cm-s-p5-contrast .cm-p5-function {
- color: $p5-contrast-blue;
-}
-
-.cm-s-p5-contrast .cm-p5-variable {
- color: $p5-contrast-pink;
- font-weight: bold;
-}
-
-.cm-s-p5-contrast .CodeMirror-foldmarker {
- background-color: white;
- color: #333;
-}
-
-.cm-s-p5-contrast .CodeMirror-cursor {
- border-left: 1px solid $p5-contrast-white;
-}
-
-.cm-s-p5-contrast .cm-searching {
- // background-color: $p5js-pink-opacity;
- background-color: $medium-dark;
-}
-
-.cm-s-p5-contrast .cm-searching.CodeMirror-selectedtext {
- // background-color: $medium-dark;
- outline: #{math.div(1, $base-font-size)}rem solid $p5-contrast-white;
-}
diff --git a/client/styles/components/_p5-dark-codemirror-theme.scss b/client/styles/components/_p5-dark-codemirror-theme.scss
deleted file mode 100644
index 77940fa188..0000000000
--- a/client/styles/components/_p5-dark-codemirror-theme.scss
+++ /dev/null
@@ -1,151 +0,0 @@
-// brown: #6C4D13
-// black: #333
-// blue: #0F9DD7
-// pink: #D9328F
-// gray: #999999
-// dark blue: #318094
-// white: #fdfdfd
-
-//numbers
-//light gray: #f4f4f4
-//dark gray: #b5b5b5
-
-$p5-dark-lightbrown: #A67F59;
-$p5-light-green: #42F48F;
-$p5-dark-black: #1C1C1C;
-$p5-dark-pink: #DE4A9B;
-$p5-dark-gray: #9B9B9B;
-$p5-dark-lightblue: #0F9DD7;
-$p5-dark-darkblue: #318094;
-$p5-dark-white: #FDFDFD;
-$p5-dark-orange: #EE9900;
-$p5-dark-lightgray: #E0D7D1;
-$p5-dark-darkgray: #666666;
-$p5-dark-green: #58a10b;
-$p5-dark-goldbrown: #b58318;
-
-$p5-dark-gutter: #f4f4f4;
-$p5-dark-number: #b5b5b5;
-$p5-dark-selected: $medium-dark;
-$p5-dark-activeline: rgb(207, 207, 207);
-
-$p5-dark-error: #df3a3d;
-
-.cm-s-p5-dark {
- background-color: $p5-dark-black;
- color: $p5-dark-white;
-}
-
-.cm-s-p5-dark span.cm-comment {
- color: $p5-dark-gray;
-}
-
-.cm-s-p5-dark span.cm-def {
- color: $p5-dark-lightblue;
-}
-
-.cm-s-p5-dark span.cm-string {
- color: $p5-dark-green;
-}
-
-.cm-s-p5-dark span.cm-string-2 {
- color: $p5-dark-orange;
-}
-
-.cm-s-p5-dark span.cm-number {
- color: $p5-dark-white;
-}
-
-.cm-s-p5-dark span.cm-keyword {
- color: $p5-dark-goldbrown;
-}
-
-.cm-s-p5-dark span.cm-variable {
- color: $p5-dark-lightblue;
-}
-
-.cm-s-p5-dark span.cm-variable-2 {
- color: $p5-dark-white;
-}
-
-.cm-s-p5-dark span.cm-property {
- color: $p5-dark-white;
-}
-
-.cm-s-p5-dark span.cm-atom {
- color: $p5-dark-pink;
-}
-
-.cm-s-p5-dark span.cm-operator {
- color: $p5-dark-white;
-}
-
-.cm-s-p5-dark .cm-linenumber {
- color: $p5-dark-number;
-}
-
-.cm-s-p5-dark {
- .CodeMirror-selected { background: $p5-dark-selected; }
- .CodeMirror-focused .CodeMirror-selected { background: $p5-dark-selected; }
- .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: $p5-dark-selected; }
- .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: $p5-dark-selected; }
-}
-
-.cm-s-p5-dark .CodeMirror-activeline-background {
- background-color: $dark;
-}
-
-.cm-s-p5-dark .CodeMirror-activeline-gutter {
- background-color: $dark;
- border-right: 1px solid $middle-dark;
-}
-
-.cm-s-p5-dark span.CodeMirror-matchingbracket {
- outline: 1px solid $p5-dark-gray;
- outline-offset: 1px;
- color: $p5-dark-white !important;
-}
-
-.cm-s-p5-dark span.cm-qualifier {
- color: $p5-dark-lightblue;
-}
-
-.cm-s-p5-dark span.cm-tag {
- color: $p5-dark-pink;
-}
-
-.cm-s-p5-dark span.cm-error {
- color: $p5-dark-error;
-}
-
-.cm-s-p5-dark span.cm-builtin {
- color: $p5-dark-lightblue;
- font-weight: bold;
-}
-
-.cm-s-p5-dark span.cm-attribute {
- color: $p5-dark-lightblue;
-}
-
-.cm-s-p5-dark .cm-p5-function {
- color: $p5-dark-lightblue;
- font-weight: bold !important;
-}
-
-.cm-s-p5-dark .cm-p5-variable {
- color: $p5-dark-pink;
- font-weight: bold;
-}
-
-.cm-s-p5-dark .CodeMirror-foldmarker {
- background-color: white;
- color: #333;
-}
-
-.cm-s-p5-dark .CodeMirror-cursor {
- border-left: 1px solid $p5-dark-white;
-}
-
-.cm-s-p5-dark .cm-searching {
- background-color: $p5js-pink-opacity;
-}
diff --git a/client/styles/components/_p5-light-codemirror-theme.scss b/client/styles/components/_p5-light-codemirror-theme.scss
deleted file mode 100644
index c2e8062865..0000000000
--- a/client/styles/components/_p5-light-codemirror-theme.scss
+++ /dev/null
@@ -1,144 +0,0 @@
-// brown: #6C4D13
-// black: #333
-// blue: #0F9DD7
-// pink: #D9328F
-// gray: #999999
-// dark blue: #318094
-// white: #fdfdfd
-
-//numbers
-//light gray: #f4f4f4
-//dark gray: #b5b5b5
-
-$p5-light-brown: #7A5A3A;
-$p5-light-black: #333333;
-$p5-light-pink: #D52889;
-$p5-light-gray: #666;
-$p5-light-blue: #0B7CA9;
-$p5-light-white: $lighter;
-$p5-light-orange: #A06801;
-$p5-light-lightgray: $middle-gray;
-$p5-light-green: #47820A;
-
-
-$p5-light-gutter: #f4f4f4;
-$p5-light-number: #b5b5b5;
-$p5-light-selected: $medium-light;
-$p5-light-activeline: rgb(207, 207, 207);
-
-.cm-s-p5-light {
- background-color: $p5-light-white;
- color: $p5-light-black;
-}
-
-.cm-s-p5-light span .cm-comment {
- color: $p5-light-lightgray;
-}
-
-.cm-s-p5-light span .cm-def {
- color: $p5-light-blue;
-}
-
-.cm-s-p5-light span .cm-string {
- color: $p5-light-green;
-}
-
-.cm-s-p5-light span .cm-string-2 {
- color: $p5-light-orange;
-}
-
-.cm-s-p5-light span .cm-number {
- color: $p5-light-black;
-}
-
-.cm-s-p5-light .cm-keyword {
- color: $p5-light-brown;
-}
-
-.cm-s-p5-light span .cm-variable {
- color: $p5-light-blue;
-}
-
-.cm-s-p5-light span .cm-variable2 {
- color: $p5-light-black;
-}
-
-.cm-s-p5-light span .cm-property {
- color: $p5-light-black;
-}
-
-.cm-s-p5-light span .cm-atom {
- color: $p5-light-pink;
-}
-
-.cm-s-p5-light span .cm-operator {
- color: $p5-light-brown;
-}
-
-.cm-s-p5-light .cm-linenumber {
- color: $p5-light-number;
-}
-
-.cm-s-p5-light {
- .CodeMirror-selected { background: $p5-light-selected; }
- .CodeMirror-focused .CodeMirror-selected { background: $p5-light-selected; }
- .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: $p5-light-selected; }
- .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: $p5-light-selected; }
-}
-
-.cm-s-p5-light .CodeMirror-activeline-background {
- background-color: $light;
-}
-
-.cm-s-p5-light .CodeMirror-activeline-gutter {
- background-color: $light;
- border-right: 1px solid $medium-light;
-}
-
-.cm-s-p5-light .cm-error {
- color: #f00;
-}
-
-.cm-s-p5-light span .CodeMirror-matchingbracket {
- outline: 1px solid $p5-light-gray;
- outline-offset: 1px;
- color: $p5-light-black !important;
-}
-
-.cm-s-p5-light span .cm-qualifier {
- color: $p5-light-blue;
-}
-
-.cm-s-p5-light span .cm-tag {
- color: $p5-light-pink;
-}
-
-.cm-s-p5-light span .cm-builtin {
- color: $p5-light-blue;
-}
-
-.cm-s-p5-light span .cm-attribute {
- color: $p5-light-black;
-}
-
-.cm-s-p5-light .cm-p5-function {
- color: $p5-light-blue;
- font-weight: bold;
-}
-
-.cm-s-p5-light .cm-p5-variable {
- color: $p5-light-pink;
-}
-
-.cm-s-p5-light .CodeMirror-foldmarker {
- background-color: #333;
- color: white;
-}
-
-.cm-s-p5-light .CodeMirror-cursor {
- border-left: 1px solid $p5-light-black;
-}
-
-.cm-s-p5-light .cm-searching {
- background-color: $p5js-pink-opacity;
-}
diff --git a/client/styles/main.scss b/client/styles/main.scss
index 400da75bfb..3d1a0cbe07 100644
--- a/client/styles/main.scss
+++ b/client/styles/main.scss
@@ -6,15 +6,9 @@
@import 'base/reset';
@import 'base/base';
-@import '~codemirror/lib/codemirror';
-@import '~codemirror/addon/lint/lint';
-@import '~codemirror-colorpicker/addon/codemirror-colorpicker';
@import '~dropzone/dist/dropzone';
@import '~primer-tooltips/build/build';
-@import 'components/p5-light-codemirror-theme';
-@import 'components/p5-dark-codemirror-theme';
-@import 'components/p5-contrast-codemirror-theme';
@import 'components/account';
@import 'components/api-key';
@import 'components/editor';
diff --git a/client/testData/testReduxStore.ts b/client/testData/testReduxStore.ts
index 0a150ea2ef..91b50ff177 100644
--- a/client/testData/testReduxStore.ts
+++ b/client/testData/testReduxStore.ts
@@ -46,7 +46,6 @@ const initialTestState: RootState = {
justOpenedProject: false,
previousPath: '/',
errorType: undefined,
- runtimeErrorWarningVisible: true,
parentId: undefined
},
files: initialFilesState(),
diff --git a/client/utils/codemirror-search.js b/client/utils/codemirror-search.js
deleted file mode 100644
index 3ed3116a63..0000000000
--- a/client/utils/codemirror-search.js
+++ /dev/null
@@ -1,830 +0,0 @@
-/* eslint-disable */
-// CodeMirror, copyright (c) by Marijn Haverbeke and others
-// Distributed under an MIT license: http://codemirror.net/LICENSE
-
-// Define search commands. Depends on dialog.js or another
-// implementation of the openDialog method.
-
-// Replace works a little oddly -- it will do the replace on the next
-// Ctrl-G (or whatever is bound to findNext) press. You prevent a
-// replace by making sure the match is no longer selected when hitting
-// Ctrl-G.
-import i18n from '../i18n';
-import CodeMirror from 'codemirror';
-import triangleArrowRight from '../images/triangle-arrow-right.svg?byContent';
-import triangleArrowDown from '../images/triangle-arrow-down.svg?byContent';
-import downArrow from '../images/down-arrow.svg?byContent';
-import upArrow from '../images/up-arrow.svg?byContent';
-import exitIcon from '../images/exit.svg?byContent';
-
-function searchOverlay(query, caseInsensitive) {
- if (typeof query == 'string') {
- query = new RegExp(
- query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'),
- caseInsensitive ? 'gi' : 'g'
- );
- } else if (!query.global) {
- query = new RegExp(query.source, query.ignoreCase ? 'gi' : 'g');
- }
-
- return {
- token: function (stream) {
- query.lastIndex = stream.pos;
- var match = query.exec(stream.string);
- if (match && match.index == stream.pos) {
- stream.pos += match[0].length || 1;
- return 'searching';
- } else if (match) {
- stream.pos = match.index;
- } else {
- stream.skipToEnd();
- }
- }
- };
-}
-
-function SearchState() {
- this.posFrom = this.posTo = this.lastQuery = this.query = null;
- this.overlay = null;
- this.regexp = false;
- this.caseInsensitive = true;
- this.wholeWord = false;
- this.replaceStarted = false;
- this.lastFileName =
- document.querySelector('.editor__file-name span')?.innerText || null;
-}
-
-function getSearchState(cm) {
- return cm.state.search || (cm.state.search = new SearchState());
-}
-
-function getSearchCursor(cm, query, pos) {
- // Heuristic: if the query string is all lowercase, do a case insensitive search.
- return cm.getSearchCursor(query, pos, getSearchState(cm).caseInsensitive);
-}
-
-function watchFileChanges(cm, searchState, searchField) {
- let observer = null;
-
- function setupObserver() {
- var fileNameElement = document.querySelector('.editor__file-name span');
-
- if (!fileNameElement) {
- setTimeout(setupObserver, 500);
- return;
- }
-
- if (observer) {
- return;
- }
-
- observer = new MutationObserver(() => {
- if (searchField.value.length > 1) {
- startSearch(cm, searchState, searchField.value);
- }
- });
-
- observer.observe(fileNameElement, { characterData: true, subtree: true });
- }
-
- function disconnectObserver() {
- if (observer) {
- observer.disconnect();
- observer = null;
- }
- }
-
- setupObserver();
-
- setInterval(() => {
- var searchDialog = document.querySelector('.CodeMirror-dialog');
- if (!searchDialog && observer) {
- disconnectObserver();
- return;
- } else if (searchDialog && !observer) {
- setupObserver();
- }
- }, 500);
-}
-
-function isMouseClick(event) {
- if (event.detail > 0) return true;
- else return false;
-}
-
-function persistentDialog(cm, text, deflt, onEnter, replaceOpened, onKeyDown) {
- var searchField = document.getElementsByClassName(
- 'CodeMirror-search-field'
- )[0];
- if (!searchField) {
- cm.openDialog(text, onEnter, {
- value: deflt,
- selectValueOnOpen: true,
- closeOnEnter: false,
- onClose: function () {
- clearSearch(cm);
- },
- onKeyDown: onKeyDown,
- closeOnBlur: false
- });
-
- searchField = document.getElementById('Find-input-field');
-
- var dialog = document.getElementsByClassName('CodeMirror-dialog')[0];
- var closeButton = dialog.getElementsByClassName('close')[0];
-
- var state = getSearchState(cm);
-
- watchFileChanges(cm, getSearchState(cm), searchField);
-
- CodeMirror.on(searchField, 'keyup', function (e) {
- state.replaceStarted = false;
- if (e.keyCode !== 13 && searchField.value.length > 1) {
- startSearch(cm, getSearchState(cm), searchField.value);
- } else if (searchField.value.length < 1) {
- cm.display.wrapper.querySelector(
- '.CodeMirror-search-results'
- ).innerText = i18n.t('CodemirrorFindAndReplace.NoResults');
- }
- });
-
- CodeMirror.on(closeButton, 'click', function () {
- dialog.parentNode.removeChild(dialog);
- clearSearch(cm);
- cm.focus();
- });
-
- var upArrow = dialog.getElementsByClassName('up-arrow')[0];
- CodeMirror.on(upArrow, 'click', function () {
- if (searchField.value.trim() === '') {
- searchField.focus();
- } else {
- cm.focus();
- CodeMirror.commands.findPrev(cm);
- searchField.blur();
- }
- });
-
- var downArrow = dialog.getElementsByClassName('down-arrow')[0];
- CodeMirror.on(downArrow, 'click', function () {
- if (searchField.value.trim() === '') {
- searchField.focus();
- } else {
- cm.focus();
- CodeMirror.commands.findNext(cm);
- searchField.blur();
- }
- });
-
- var regexpButton = dialog.getElementsByClassName(
- 'CodeMirror-regexp-button'
- )[0];
- CodeMirror.on(regexpButton, 'click', function (event) {
- var state = getSearchState(cm);
- state.regexp = toggle(regexpButton);
- startSearch(cm, getSearchState(cm), searchField.value);
- if (isMouseClick(event)) searchField.focus();
- });
-
- toggle(regexpButton, state.regexp);
-
- var caseSensitiveButton = dialog.getElementsByClassName(
- 'CodeMirror-case-button'
- )[0];
- CodeMirror.on(caseSensitiveButton, 'click', function (event) {
- var state = getSearchState(cm);
- state.caseInsensitive = !toggle(caseSensitiveButton);
- startSearch(cm, getSearchState(cm), searchField.value);
- if (isMouseClick(event)) searchField.focus();
- });
-
- toggle(caseSensitiveButton, !state.caseInsensitive);
-
- var wholeWordButton = dialog.getElementsByClassName(
- 'CodeMirror-word-button'
- )[0];
- CodeMirror.on(wholeWordButton, 'click', function (event) {
- var state = getSearchState(cm);
- state.wholeWord = toggle(wholeWordButton);
- startSearch(cm, getSearchState(cm), searchField.value);
- if (isMouseClick(event)) searchField.focus();
- });
-
- toggle(wholeWordButton, state.wholeWord);
-
- function toggle(el, initialState) {
- var currentState, nextState;
-
- if (initialState == null) {
- currentState = el.getAttribute('aria-checked') === 'true';
- nextState = !currentState;
- } else {
- nextState = initialState;
- }
-
- el.setAttribute('aria-checked', nextState);
- return nextState;
- }
-
- function toggleReplace(open) {
- var toggleButtonHeightOpened = '80px',
- toggleButtonHeightClosed = '40px';
-
- if (open) {
- replaceFieldDiv.style.display = replaceControlsDiv.style.display = '';
- toggleReplaceBtnDiv.style.height = toggleButtonHeightOpened;
- toggleReplaceBtn.style.height = toggleButtonHeightOpened;
- toggleReplaceBtn.innerHTML = triangleArrowDown;
- } else {
- replaceFieldDiv.style.display = replaceControlsDiv.style.display =
- 'none';
- toggleReplaceBtnDiv.style.height = toggleButtonHeightClosed;
- toggleReplaceBtn.style.height = toggleButtonHeightClosed;
- toggleReplaceBtn.innerHTML = triangleArrowRight;
- }
- }
-
- var toggleReplaceBtnDiv = document.getElementById('Btn-Toggle-replace-div');
- var toggleReplaceBtn = document.getElementById('Btn-Toggle-replace');
- var replaceFieldDiv = document.getElementById('Replace-input-div');
- var replaceControlsDiv = document.getElementById('Replace-controls-div');
- if (replaceOpened) {
- toggleReplace(true);
- }
- CodeMirror.on(toggleReplaceBtn, 'click', function () {
- if (replaceFieldDiv.style.display === 'none') {
- toggleReplace(true);
- } else {
- toggleReplace(false);
- }
- });
-
- var replaceField = document.getElementById('Replace-input-field');
- CodeMirror.on(replaceField, 'keyup', function (e) {
- var state = getSearchState(cm);
- var query = parseQuery(searchField.value, state);
- var withText = parseString(replaceField.value);
- if (e.keyCode === 13) {
- // if enter
- var cursor = getSearchCursor(cm, query, cm.getCursor('from'));
- var start = cursor.from();
- var match = cursor.findNext();
- if (!match) {
- cursor = getSearchCursor(cm, query);
- if (
- !(match = cursor.findNext()) ||
- (start &&
- cursor.from().line == start.line &&
- cursor.from().ch == start.ch)
- )
- return;
- }
- cm.setSelection(cursor.from(), cursor.to());
- state.replaceStarted = true;
- doReplace(match, cursor, query, withText);
- }
- });
-
- function doReplace(match, cursor, query, withText) {
- cursor.replace(
- typeof query == 'string'
- ? withText
- : withText.replace(/\$(\d)/g, function (_, i) {
- return match[i];
- })
- );
- cursor.findNext();
- // cm.focus();
- CodeMirror.commands.findNext(cm);
- // searchField.blur();
- }
-
- var doReplaceButton = document.getElementById('Btn-replace');
- CodeMirror.on(doReplaceButton, 'click', function (e) {
- if (!searchField.value) {
- searchField.focus();
- return;
- }
- var state = getSearchState(cm);
- var query = parseQuery(searchField.value, state);
- var withText = parseString(replaceField.value);
- if (state.replaceStarted) {
- var cursor = getSearchCursor(cm, query, cm.getCursor('from'));
- var match = cursor.findNext();
- if (match) {
- cm.setSelection(cursor.from(), cursor.to());
- doReplace(match, cursor, query, withText);
- doReplaceButton.focus();
- }
- } else {
- startSearch(cm, state, searchField.value);
- state.replaceStarted = true;
- cm.focus();
- CodeMirror.commands.findNext(cm);
- searchField.blur();
- doReplaceButton.focus();
- }
- });
-
- var doReplaceAllButton = document.getElementById('Btn-replace-all');
- CodeMirror.on(doReplaceAllButton, 'click', function (e) {
- if (!searchField.value) {
- searchField.focus();
- return;
- }
- var state = getSearchState(cm);
- var query = parseQuery(searchField.value, state);
- var withText = parseString(replaceField.value);
- if (searchField.value.length > 1) {
- state.replaceStarted = true;
- }
- if (state.replaceStarted) {
- replaceAll(cm, query, withText);
- state.replaceStarted = false;
- } else {
- startSearch(cm, state, searchField.value);
- state.replaceStarted = true;
- }
- });
- } else {
- searchField.value = deflt;
-
- searchField.focus();
- searchField.select();
- }
-}
-
-function dialog(cm, text, shortText, deflt, f) {
- if (cm.openDialog)
- cm.openDialog(text, f, { value: deflt, selectValueOnOpen: true });
- else f(prompt(shortText, deflt));
-}
-
-function parseString(string) {
- return string.replace(/\\(.)/g, function (_, ch) {
- if (ch == 'n') return '\n';
- if (ch == 'r') return '\r';
- return ch;
- });
-}
-
-function parseQuery(query, state) {
- var emptyQuery = 'x^'; // matches nothing
- if (query === '') {
- query = emptyQuery;
- } else {
- if (state.regexp === false) {
- query = parseString(query);
- query = query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
- }
- if (state.wholeWord) {
- query = '\\b' + query + '\\b';
- }
- }
-
- var regexp;
- try {
- regexp = new RegExp(query, state.caseInsensitive ? 'gi' : 'g');
- } catch (e) {
- regexp = new RegExp(emptyQuery, 'g');
- }
- // If the resulting regexp will match everything, do not use it
- if (regexp.test('')) {
- return new RegExp(emptyQuery, 'g');
- }
- return regexp;
-}
-
-function startSearch(cm, state, query) {
- var searchDialog = document.querySelector('.CodeMirror-dialog');
- if (searchDialog) {
- // check if the file has changed
- let currentFileName = document.querySelector('.editor__file-name span')
- ?.innerText;
-
- if (state.lastFileName !== currentFileName) {
- state.lastFileName = currentFileName;
- state.queryText = null;
- state.lastQuery = null;
- state.query = null;
- cm.removeOverlay(state.overlay);
- state.overlay = null;
-
- if (searchDialog) {
- cm.display.wrapper.querySelector(
- '.CodeMirror-search-results'
- ).innerText = '0/0';
- }
- }
-
- state.queryText = query;
- state.lastQuery = query;
- state.query = parseQuery(query, state);
- cm.removeOverlay(state.overlay, state.caseInsensitive);
- state.overlay = searchOverlay(state.query, state.caseInsensitive);
- cm.addOverlay(state.overlay);
- if (cm.showMatchesOnScrollbar) {
- if (state.annotate) {
- state.annotate.clear();
- state.annotate = null;
- }
- state.annotate = cm.showMatchesOnScrollbar(
- state.query,
- state.caseInsensitive
- );
- }
-
- var cursor = getSearchCursor(cm, state.query);
- cursor.findNext();
- var num_match = cm.state.search.annotate.matches.length;
- if (num_match == 0) {
- cm.display.wrapper.querySelector(
- '.CodeMirror-search-results'
- ).innerText = i18n.t('CodemirrorFindAndReplace.NoResults');
- cm.removeOverlay(state.overlay, state.caseInsensitive);
- } else {
- var next =
- cm.state.search.annotate.matches.findIndex((s) => {
- return (
- s.from.ch === cursor.from().ch && s.from.line === cursor.from().line
- );
- }) + 1;
- var text_match = next + '/' + num_match;
- cm.display.wrapper.querySelector(
- '.CodeMirror-search-results'
- ).innerText = text_match;
- }
- }
-}
-
-function doSearch(cm, rev, persistent, immediate, ignoreQuery) {
- var state = getSearchState(cm);
- if (!ignoreQuery && state.query) {
- return findNext(cm, rev);
- }
- var q = cm.getSelection() || state.lastQuery;
- var queryDialog = getQueryDialog();
- if (persistent && cm.openDialog) {
- var hiding = null;
- var searchNext = function (query, event) {
- CodeMirror.e_stop(event);
- if (!query) return;
- if (query != state.queryText) {
- startSearch(cm, state, query);
- state.posFrom = state.posTo = cm.getCursor();
- }
- if (hiding) hiding.style.opacity = 1;
- findNext(cm, event.shiftKey, function (_, to) {
- var dialog;
- if (
- to.line < 3 &&
- document.querySelector &&
- (dialog = cm.display.wrapper.querySelector('.CodeMirror-dialog')) &&
- dialog.getBoundingClientRect().bottom - 4 >
- cm.cursorCoords(to, 'window').top
- )
- (hiding = dialog).style.opacity = 0.4;
- });
- };
- persistentDialog(
- cm,
- queryDialog,
- q,
- searchNext,
- false,
- function (event, query) {
- var keyName = CodeMirror.keyName(event);
- var cmd = CodeMirror.keyMap[cm.getOption('keyMap')][keyName];
- if (!cmd) cmd = cm.getOption('extraKeys')[keyName];
- if (
- cmd == 'findNext' ||
- cmd == 'findPrev' ||
- cmd == 'findPersistentNext' ||
- cmd == 'findPersistentPrev'
- ) {
- CodeMirror.e_stop(event);
- startSearch(cm, getSearchState(cm), query);
- cm.execCommand(cmd);
- } else if (cmd == 'find' || cmd == 'findPersistent') {
- CodeMirror.e_stop(event);
- searchNext(query, event);
- }
- }
- );
- if (immediate && q) {
- startSearch(cm, state, q);
- findNext(cm, rev);
- }
- cm.on('change', function () {
- var state = getSearchState(cm);
- if (state.query) {
- startSearch(cm, state, state.queryText);
- }
- });
- } else {
- dialog(cm, queryDialog, 'Search for:', q, function (query) {
- if (query && !state.query)
- cm.operation(function () {
- startSearch(cm, state, query);
- state.posFrom = state.posTo = cm.getCursor();
- findNext(cm, rev);
- });
- });
- }
-}
-
-function doFindAndReplace(
- cm,
- rev,
- persistent,
- immediate,
- ignoreQuery,
- replaceOpened
-) {
- var state = getSearchState(cm);
- if (!ignoreQuery && state.query) {
- return findNext(cm, rev);
- }
- var q = cm.getSelection() || state.lastQuery;
- var queryDialog = getQueryDialog();
- if (persistent && cm.openDialog) {
- var hiding = null;
- var searchNext = function (query, event) {
- CodeMirror.e_stop(event);
- if (!query) return;
- if (query != state.queryText) {
- startSearch(cm, state, query);
- state.posFrom = state.posTo = cm.getCursor();
- }
- if (hiding) hiding.style.opacity = 1;
- findNext(cm, event.shiftKey, function (_, to) {
- var dialog;
- if (
- to.line < 3 &&
- document.querySelector &&
- (dialog = cm.display.wrapper.querySelector('.CodeMirror-dialog')) &&
- dialog.getBoundingClientRect().bottom - 4 >
- cm.cursorCoords(to, 'window').top
- )
- (hiding = dialog).style.opacity = 1;
- });
- };
- persistentDialog(
- cm,
- queryDialog,
- q,
- searchNext,
- replaceOpened,
- function (event, query) {
- var keyName = CodeMirror.keyName(event);
- var cmd = CodeMirror.keyMap[cm.getOption('keyMap')][keyName];
- if (!cmd) cmd = cm.getOption('extraKeys')[keyName];
- if (
- cmd == 'findNext' ||
- cmd == 'findPrev' ||
- cmd == 'findPersistentNext' ||
- cmd == 'findPersistentPrev'
- ) {
- CodeMirror.e_stop(event);
- startSearch(cm, getSearchState(cm), query);
- cm.execCommand(cmd);
- } else if (cmd == 'find' || cmd == 'findPersistent') {
- CodeMirror.e_stop(event);
- searchNext(query, event);
- }
- }
- );
- if (immediate && q) {
- startSearch(cm, state, q);
- findNext(cm, rev);
- }
- } else {
- dialog(cm, queryDialog, 'Search for:', q, function (query) {
- if (query && !state.query)
- cm.operation(function () {
- startSearch(cm, state, query);
- state.posFrom = state.posTo = cm.getCursor();
- findNext(cm, rev);
- });
- });
- }
-}
-
-function findNext(cm, rev, callback) {
- cm.operation(function () {
- var state = getSearchState(cm);
- var cursor = getSearchCursor(
- cm,
- state.query,
- rev ? state.posFrom : state.posTo
- );
- if (!cursor.find(rev)) {
- cursor = getSearchCursor(
- cm,
- state.query,
- rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0)
- );
- if (!cursor.find(rev)) {
- cm.display.wrapper.querySelector(
- '.CodeMirror-search-results'
- ).innerText = i18n.t('CodemirrorFindAndReplace.NoResults');
- return;
- }
- }
- cm.setSelection(cursor.from(), cursor.to());
- cm.scrollIntoView(
- { from: cursor.from(), to: cursor.to() },
- cm.getScrollInfo().clientHeight / 2
- );
- state.posFrom = cursor.from();
- state.posTo = cursor.to();
- var num_match = cm.state.search.annotate.matches.length;
- var next =
- cm.state.search.annotate.matches.findIndex(
- (s) =>
- s.from.ch === cursor.from().ch && s.from.line === cursor.from().line
- ) + 1;
- var text_match = next + '/' + num_match;
- cm.display.wrapper.querySelector(
- '.CodeMirror-search-results'
- ).innerText = text_match;
- if (callback) callback(cursor.from(), cursor.to());
- });
-}
-
-function clearSearch(cm) {
- cm.operation(function () {
- var state = getSearchState(cm);
- state.replaceStarted = false;
- if (!state.query) return;
- state.query = state.queryText = null;
- cm.removeOverlay(state.overlay);
- if (state.annotate) {
- state.annotate.clear();
- state.annotate = null;
- }
- });
-}
-
-function replaceAll(cm, query, text) {
- cm.operation(function () {
- for (var cursor = getSearchCursor(cm, query); cursor.findNext(); ) {
- if (typeof query != 'string') {
- var match = cm.getRange(cursor.from(), cursor.to()).match(query);
- cursor.replace(
- text.replace(/\$(\d)/g, function (_, i) {
- return match[i];
- })
- );
- } else cursor.replace(text);
- }
- });
-}
-
-var getQueryDialog = function () {
- return `
-
- `;
-};
-
-// CodeMirror.commands.findPersistent = function(cm) {doFindAndReplace(cm, false, true, false, true, false);};
-// CodeMirror.commands.findPersistentNext = function(cm) {doFindAndReplace(cm, false, true, false, true, false);};
-// CodeMirror.commands.findPersistentPrev = function(cm) {doFindAndReplace(cm, false, true, false, true, false);};
-// CodeMirror.commands.findNext = doFindAndReplace;
-// CodeMirror.commands.findPrev = function(cm) {doFindAndReplace(cm, true);};
-// CodeMirror.commands.clearSearch = clearSearch;
-// CodeMirror.commands.replace = function(cm) { doFindAndReplace(cm, false, true, false, true, true); };
-
-CodeMirror.commands.find = function (cm) {
- doSearch(cm);
-};
-CodeMirror.commands.findPersistent = function (cm) {
- doSearch(cm, false, true, false, true);
-};
-CodeMirror.commands.findPersistentNext = function (cm) {
- doSearch(cm, false, true, true);
-};
-CodeMirror.commands.findPersistentPrev = function (cm) {
- doSearch(cm, true, true, true);
-};
-CodeMirror.commands.findNext = doSearch;
-CodeMirror.commands.findPrev = function (cm) {
- doSearch(cm, true);
-};
-CodeMirror.commands.clearSearch = clearSearch;
-CodeMirror.commands.replace = function (cm) {
- doFindAndReplace(cm, false, true, false, true, true);
-};
-CodeMirror.commands.replaceAll = function (cm) {
- doFindAndReplace(cm, true);
-};
diff --git a/client/utils/contextAwareHinter.js b/client/utils/contextAwareHinter.js
index a90b88cd0e..f9fc11be39 100644
--- a/client/utils/contextAwareHinter.js
+++ b/client/utils/contextAwareHinter.js
@@ -4,17 +4,145 @@ import classMap from './p5-instance-methods-and-creators.json';
const scopeMap = require('./p5-scope-function-access-map.json');
-function getExpressionBeforeCursor(cm) {
- const cursor = cm.getCursor();
- const line = cm.getLine(cursor.line);
- const uptoCursor = line.slice(0, cursor.ch);
+function getCurrentWordInfo(context) {
+ const word = context.matchBefore(/\w*/);
+
+ if (!word) {
+ return {
+ text: '',
+ from: context.pos,
+ to: context.pos
+ };
+ }
+
+ return {
+ text: word.text || '',
+ from: word.from,
+ to: context.pos
+ };
+}
+
+function getExpressionBeforeCursor(state, pos) {
+ const line = state.doc.lineAt(pos);
+ const uptoCursor = line.text.slice(0, pos - line.from);
const match = uptoCursor.match(
/([a-zA-Z_$][\w$]*(?:\.[a-zA-Z_$][\w$]*)*)\.(?:[a-zA-Z_$][\w$]*)?$/
);
return match ? match[1] : null;
}
-export default function contextAwareHinter(cm, options = {}) {
+function getTypedMemberInfo(state, pos) {
+ const line = state.doc.lineAt(pos);
+ const uptoCursor = line.text.slice(0, pos - line.from);
+ const dotMatch = uptoCursor.match(/\.([a-zA-Z_$][\w$]*)?$/);
+
+ if (!dotMatch) {
+ return {
+ typed: '',
+ from: pos,
+ to: pos
+ };
+ }
+
+ const typed = dotMatch[1] || '';
+ const methodStart = pos - dotMatch[0].length + 1;
+
+ return {
+ typed,
+ from: methodStart,
+ to: pos
+ };
+}
+
+function formatPreview(label, params = []) {
+ if (!params.length) return `${label}()`;
+
+ return `${label}(${params
+ .map((param) => (param.o ? `[${param.p}]` : param.p))
+ .join(', ')})`;
+}
+
+function makeBaseHintLookup(hints) {
+ const byLabel = new Map();
+
+ hints.forEach((hint) => {
+ if (hint?.label) {
+ byLabel.set(hint.label, hint);
+ }
+ });
+
+ return byLabel;
+}
+
+function buildMethodOption(methodName, baseHint, range) {
+ const params = baseHint?.params || [];
+
+ return {
+ label: methodName,
+ type: 'method',
+ kindLabel: baseHint?.kindLabel || 'fun',
+ params,
+ p5DocPath: baseHint?.p5DocPath,
+ preview: baseHint?.preview || formatPreview(methodName, params),
+ from: range.from,
+ to: range.to
+ };
+}
+
+function buildVarOrFunctionOption({
+ name,
+ isFunc,
+ userDefinedFunctionMetadata,
+ blacklist,
+ range
+}) {
+ const fnMeta = userDefinedFunctionMetadata[name];
+ const params = fnMeta?.params || [];
+
+ let preview;
+
+ if (isFunc) {
+ if (fnMeta?.text) {
+ preview = formatPreview(fnMeta.text, params);
+ } else {
+ preview = formatPreview(name, params);
+ }
+ } else {
+ preview = undefined;
+ }
+
+ const isBlacklisted = blacklist.includes(name);
+
+ return {
+ label: fnMeta?.text || name,
+ type: isFunc ? 'method' : 'variable',
+ kindLabel: isFunc ? 'fun' : 'var',
+ params,
+ p5DocPath: undefined,
+ preview,
+ blacklisted: isBlacklisted,
+ warning: isBlacklisted ? '⚠️ use with caution in this context' : null,
+ from: range.from,
+ to: range.to
+ };
+}
+
+function buildGlobalHintOption(hint, blacklist, range) {
+ return {
+ ...hint,
+ blacklisted: blacklist.includes(hint.label),
+ warning: blacklist.includes(hint.label)
+ ? '⚠️ use with caution in this context'
+ : null,
+ from: range.from,
+ to: range.to
+ };
+}
+
+export default function contextAwareHinter(context, { hints = [] } = {}) {
+ const { state, pos } = context;
+ const cm = state.doc.toString();
+
const {
variableToP5ClassMap = {},
scopeToDeclaredVarsMap = {},
@@ -22,12 +150,9 @@ export default function contextAwareHinter(cm, options = {}) {
userDefinedClassMetadata = {}
} = p5CodeAstAnalyzer(cm) || {};
- const { hinter } = options;
- if (!hinter || typeof hinter.search !== 'function') {
- return [];
- }
+ const baseHintLookup = makeBaseHintLookup(hints);
- const baseExpression = getExpressionBeforeCursor(cm);
+ const baseExpression = getExpressionBeforeCursor(state, pos);
if (baseExpression) {
const className = variableToP5ClassMap[baseExpression];
@@ -38,61 +163,36 @@ export default function contextAwareHinter(cm, options = {}) {
let methods = [];
if (userClassEntry?.methods) {
- const { methods: userMethods } = userClassEntry;
- methods = userMethods;
+ methods = userClassEntry.methods;
} else if (className && classMap[className]?.methods) {
- const { methods: classMethods } = classMap[className];
- methods = classMethods;
+ methods = classMap[className].methods;
} else {
return [];
}
- const cursor = cm.getCursor();
- const lineText = cm.getLine(cursor.line);
- const dotMatch = lineText
- .slice(0, cursor.ch)
- .match(/\.([a-zA-Z_$][\w$]*)?$/);
-
- let from = cursor;
- if (dotMatch) {
- const fullMatch = dotMatch[0];
- const methodStart = cursor.ch - fullMatch.length + 1;
- from = { line: cursor.line, ch: methodStart };
- } else {
- from = cursor;
- }
-
- const to = { line: cursor.line, ch: cursor.ch };
- const typed = dotMatch?.[1]?.toLowerCase() || '';
-
- const methodHints = methods
- .filter((method) => method.toLowerCase().startsWith(typed))
- .map((method) => ({
- item: {
- text: method,
- type: 'fun',
- isMethod: true
- },
- displayText: method,
- from,
- to
- }));
-
- return methodHints;
+ const memberInfo = getTypedMemberInfo(state, pos);
+ const typedLower = memberInfo.typed.toLowerCase();
+
+ const options = methods
+ .filter((method) => method.toLowerCase().startsWith(typedLower))
+ .map((method) =>
+ buildMethodOption(method, baseHintLookup.get(method), memberInfo)
+ );
+
+ return {
+ from: memberInfo.from,
+ to: memberInfo.to,
+ options,
+ filter: false
+ };
}
- const { line, ch } = cm.getCursor();
- const { string } = cm.getTokenAt({ line, ch });
- const currentWord = string.trim();
-
- const currentContext = getContext(cm);
- const allHints = hinter.search(currentWord);
+ const wordInfo = getCurrentWordInfo(context);
+ const lowerCurrentWord = wordInfo.text.toLowerCase();
- // const whitelist = scopeMap[currentContext]?.whitelist || [];
+ const currentContext = getContext(cm, pos);
const blacklist = scopeMap[currentContext]?.blacklist || [];
- const lowerCurrentWord = currentWord.toLowerCase();
-
function isInScope(varName) {
return Object.entries(scopeToDeclaredVarsMap).some(
([scope, vars]) =>
@@ -103,13 +203,13 @@ export default function contextAwareHinter(cm, options = {}) {
const allVarNames = Array.from(
new Set(
Object.values(scopeToDeclaredVarsMap)
- .map((s) => Object.keys(s))
+ .map((scopeVars) => Object.keys(scopeVars))
.flat()
.filter((name) => typeof name === 'string')
)
);
- const varHints = allVarNames
+ const localOptions = allVarNames
.filter(
(varName) =>
varName.toLowerCase().startsWith(lowerCurrentWord) && isInScope(varName)
@@ -120,70 +220,58 @@ export default function contextAwareHinter(cm, options = {}) {
(!scopeToDeclaredVarsMap[currentContext]?.[varName] &&
scopeToDeclaredVarsMap.global?.[varName] === 'fun');
- const baseItem = isFunc
- ? { ...userDefinedFunctionMetadata[varName] }
- : {
- text: varName,
- type: 'var',
- params: [],
- p5: false
- };
-
- return {
- item: baseItem,
- isBlacklisted: blacklist.includes(varName)
- };
+ return buildVarOrFunctionOption({
+ name: varName,
+ isFunc,
+ userDefinedFunctionMetadata,
+ blacklist,
+ range: wordInfo
+ });
});
- const filteredHints = allHints
+ const globalOptions = hints
.filter(
- (h) =>
- h &&
- h.item &&
- typeof h.item.text === 'string' &&
- h.item.text.toLowerCase().startsWith(lowerCurrentWord)
+ (hint) =>
+ hint &&
+ typeof hint.label === 'string' &&
+ hint.label.toLowerCase().startsWith(lowerCurrentWord)
)
- .map((hint) => {
- const name = hint.item?.text || '';
- const isBlacklisted = blacklist.includes(name);
-
- return {
- ...hint,
- isBlacklisted
- };
- });
+ .map((hint) => buildGlobalHintOption(hint, blacklist, wordInfo));
- const combinedHints = [...varHints, ...filteredHints];
+ const combinedOptions = [...localOptions, ...globalOptions];
const typePriority = {
- fun: 0,
- var: 1,
+ method: 0,
+ variable: 1,
keyword: 2,
- other: 3
+ constant: 3,
+ boolean: 4,
+ obj: 5,
+ other: 6
};
- const sorted = combinedHints.sort((a, b) => {
- const nameA = a.item?.text || '';
- const nameB = b.item?.text || '';
- const typeA = a.item?.type || 'other';
- const typeB = b.item?.type || 'other';
-
- const isBlacklistedA = a.isBlacklisted ? 1 : 0;
- const isBlacklistedB = b.isBlacklisted ? 1 : 0;
-
- const typeScoreA = typePriority[typeA] ?? typePriority.other;
- const typeScoreB = typePriority[typeB] ?? typePriority.other;
+ combinedOptions.sort((a, b) => {
+ const isBlacklistedA = a.blacklisted ? 1 : 0;
+ const isBlacklistedB = b.blacklisted ? 1 : 0;
if (isBlacklistedA !== isBlacklistedB) {
return isBlacklistedA - isBlacklistedB;
}
- if (typeScoreA !== typeScoreB) {
- return typeScoreA - typeScoreB;
+ const typeA = typePriority[a.type] ?? typePriority.other;
+ const typeB = typePriority[b.type] ?? typePriority.other;
+
+ if (typeA !== typeB) {
+ return typeA - typeB;
}
- return nameA.localeCompare(nameB);
+ return a.label.localeCompare(b.label);
});
- return sorted;
+ return {
+ from: wordInfo.from,
+ to: wordInfo.to,
+ options: combinedOptions,
+ filter: false
+ };
}
diff --git a/client/utils/getContext.js b/client/utils/getContext.js
index beddef71f7..2e9a11ebdc 100644
--- a/client/utils/getContext.js
+++ b/client/utils/getContext.js
@@ -1,11 +1,7 @@
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
-export default function getContext(_cm) {
- const code = _cm.getValue();
- const cursor = _cm.getCursor();
- const offset = _cm.indexFromPos(cursor);
-
+export default function getContext(code, pos) {
let ast;
try {
ast = parser.parse(code, {
@@ -21,7 +17,7 @@ export default function getContext(_cm) {
traverse(ast, {
Function(path) {
const { node } = path;
- if (offset >= node.start && offset <= node.end) {
+ if (pos >= node.start && pos <= node.end) {
if (node.id && node.id.name) {
context = node.id.name;
} else {
diff --git a/client/utils/htmlmixed.js b/client/utils/htmlmixed.js
deleted file mode 100644
index 23a0eacf05..0000000000
--- a/client/utils/htmlmixed.js
+++ /dev/null
@@ -1,153 +0,0 @@
-// CodeMirror, copyright (c) by Marijn Haverbeke and others
-// Distributed under an MIT license: http://codemirror.net/LICENSE
-/* eslint-disable */
-
-(function(mod) {
- if (typeof exports == "object" && typeof module == "object") // CommonJS
- mod(require("codemirror"), require("codemirror/mode/xml/xml"), require("./p5-javascript"), require("codemirror/mode/css/css"));
- else if (typeof define == "function" && define.amd) // AMD
- define(["codemirror", "codemirror/mode/xml/xml", "./p5-javascript", "codemirror/mode/css/css"], mod);
- else // Plain browser env
- mod(CodeMirror);
-})(function(CodeMirror) {
- "use strict";
-
- var defaultTags = {
- script: [
- ["lang", /(javascript|babel)/i, "javascript"],
- ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i, "javascript"],
- ["type", /./, "text/plain"],
- [null, null, "javascript"]
- ],
- style: [
- ["lang", /^css$/i, "css"],
- ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"],
- ["type", /./, "text/plain"],
- [null, null, "css"]
- ]
- };
-
- function maybeBackup(stream, pat, style) {
- var cur = stream.current(), close = cur.search(pat);
- if (close > -1) {
- stream.backUp(cur.length - close);
- } else if (cur.match(/<\/?$/)) {
- stream.backUp(cur.length);
- if (!stream.match(pat, false)) stream.match(cur);
- }
- return style;
- }
-
- var attrRegexpCache = {};
- function getAttrRegexp(attr) {
- var regexp = attrRegexpCache[attr];
- if (regexp) return regexp;
- return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*");
- }
-
- function getAttrValue(text, attr) {
- var match = text.match(getAttrRegexp(attr))
- return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : ""
- }
-
- function getTagRegexp(tagName, anchored) {
- return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i");
- }
-
- function addTags(from, to) {
- for (var tag in from) {
- var dest = to[tag] || (to[tag] = []);
- var source = from[tag];
- for (var i = source.length - 1; i >= 0; i--)
- dest.unshift(source[i])
- }
- }
-
- function findMatchingMode(tagInfo, tagText) {
- for (var i = 0; i < tagInfo.length; i++) {
- var spec = tagInfo[i];
- if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2];
- }
- }
-
- CodeMirror.defineMode("htmlmixed", function (config, parserConfig) {
- var htmlMode = CodeMirror.getMode(config, {
- name: "xml",
- htmlMode: true,
- multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
- multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag
- });
-
- var tags = {};
- var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes;
- addTags(defaultTags, tags);
- if (configTags) addTags(configTags, tags);
- if (configScript) for (var i = configScript.length - 1; i >= 0; i--)
- tags.script.unshift(["type", configScript[i].matches, configScript[i].mode])
-
- function html(stream, state) {
- var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName
- if (tag && !/[<>\s\/]/.test(stream.current()) &&
- (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) &&
- tags.hasOwnProperty(tagName)) {
- state.inTag = tagName + " "
- } else if (state.inTag && tag && />$/.test(stream.current())) {
- var inTag = /^([\S]+) (.*)/.exec(state.inTag)
- state.inTag = null
- var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2])
- var mode = CodeMirror.getMode(config, modeSpec)
- var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false);
- state.token = function (stream, state) {
- if (stream.match(endTagA, false)) {
- state.token = html;
- state.localState = state.localMode = null;
- return null;
- }
- return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState));
- };
- state.localMode = mode;
- state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, ""));
- } else if (state.inTag) {
- state.inTag += stream.current()
- if (stream.eol()) state.inTag += " "
- }
- return style;
- };
-
- return {
- startState: function () {
- var state = CodeMirror.startState(htmlMode);
- return {token: html, inTag: null, localMode: null, localState: null, htmlState: state};
- },
-
- copyState: function (state) {
- var local;
- if (state.localState) {
- local = CodeMirror.copyState(state.localMode, state.localState);
- }
- return {token: state.token, inTag: state.inTag,
- localMode: state.localMode, localState: local,
- htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
- },
-
- token: function (stream, state) {
- return state.token(stream, state);
- },
-
- indent: function (state, textAfter) {
- if (!state.localMode || /^\s*<\//.test(textAfter))
- return htmlMode.indent(state.htmlState, textAfter);
- else if (state.localMode.indent)
- return state.localMode.indent(state.localState, textAfter);
- else
- return CodeMirror.Pass;
- },
-
- innerMode: function (state) {
- return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
- }
- };
- }, "xml", "javascript", "css");
-
- CodeMirror.defineMIME("text/html", "htmlmixed");
-});
diff --git a/client/utils/p5-hinter.js b/client/utils/p5-hinter.js
index 25d68c59f2..dee7c9870b 100644
--- a/client/utils/p5-hinter.js
+++ b/client/utils/p5-hinter.js
@@ -1,1734 +1,3 @@
/* eslint-disable */
/* generated: do not edit! helper file for hinter. generated by update-p5-hinter script */
-exports.p5Hinter = [
- {
- text: 'describe',
- type: 'fun',
- params: [
- { p: 'text', o: false },
- { p: 'display', o: true }
- ],
- p5: true
- },
- {
- text: 'describeElement',
- type: 'fun',
- params: [
- { p: 'name', o: false },
- { p: 'text', o: false },
- { p: 'display', o: true }
- ],
- p5: true
- },
- {
- text: 'textOutput',
- type: 'fun',
- params: [{ p: 'display', o: true }],
- p5: true
- },
- {
- text: 'gridOutput',
- type: 'fun',
- params: [{ p: 'display', o: true }],
- p5: true
- },
- { text: 'alpha', type: 'fun', params: [{ p: 'color', o: false }], p5: true },
- { text: 'blue', type: 'fun', params: [{ p: 'color', o: false }], p5: true },
- {
- text: 'brightness',
- type: 'fun',
- params: [{ p: 'color', o: false }],
- p5: true
- },
- { text: 'color', type: 'fun', p5: true },
- { text: 'green', type: 'fun', params: [{ p: 'color', o: false }], p5: true },
- { text: 'hue', type: 'fun', params: [{ p: 'color', o: false }], p5: true },
- {
- text: 'lerpColor',
- type: 'fun',
- params: [
- { p: 'c1', o: false },
- { p: 'c2', o: false },
- { p: 'amt', o: false }
- ],
- p5: true
- },
- {
- text: 'lightness',
- type: 'fun',
- params: [{ p: 'color', o: false }],
- p5: true
- },
- { text: 'red', type: 'fun', params: [{ p: 'color', o: false }], p5: true },
- {
- text: 'saturation',
- type: 'fun',
- params: [{ p: 'color', o: false }],
- p5: true
- },
- {
- text: 'beginClip',
- type: 'fun',
- params: [{ p: 'options', o: true }],
- p5: true
- },
- { text: 'endClip', type: 'fun', p5: true },
- {
- text: 'clip',
- type: 'fun',
- params: [
- { p: 'callback', o: false },
- { p: 'options', o: true }
- ],
- p5: true
- },
- { text: 'background', type: 'fun', p5: true },
- {
- text: 'clear',
- type: 'fun',
- params: [
- { p: 'r', o: true },
- { p: 'g', o: true },
- { p: 'b', o: true },
- { p: 'a', o: true }
- ],
- p5: true
- },
- { text: 'colorMode', type: 'fun', p5: true },
- { text: 'fill', type: 'fun', p5: true },
- { text: 'noFill', type: 'fun', p5: true },
- { text: 'noStroke', type: 'fun', p5: true },
- { text: 'stroke', type: 'fun', p5: true },
- {
- text: 'erase',
- type: 'fun',
- params: [
- { p: 'strengthFill', o: true },
- { p: 'strengthStroke', o: true }
- ],
- p5: true
- },
- { text: 'noErase', type: 'fun', p5: true },
- {
- text: 'arc',
- type: 'fun',
- params: [
- { p: 'x', o: false },
- { p: 'y', o: false },
- { p: 'w', o: false },
- { p: 'h', o: false },
- { p: 'start', o: false },
- { p: 'stop', o: false },
- { p: 'mode', o: true },
- { p: 'detail', o: true }
- ],
- p5: true
- },
- { text: 'ellipse', type: 'fun', p5: true },
- {
- text: 'circle',
- type: 'fun',
- params: [
- { p: 'x', o: false },
- { p: 'y', o: false },
- { p: 'd', o: false }
- ],
- p5: true
- },
- { text: 'line', type: 'fun', p5: true },
- { text: 'point', type: 'fun', p5: true },
- { text: 'quad', type: 'fun', p5: true },
- { text: 'rect', type: 'fun', p5: true },
- {
- text: 'square',
- type: 'fun',
- params: [
- { p: 'x', o: false },
- { p: 'y', o: false },
- { p: 's', o: false },
- { p: 'tl', o: true },
- { p: 'tr', o: true },
- { p: 'br', o: true },
- { p: 'bl', o: true }
- ],
- p5: true
- },
- {
- text: 'triangle',
- type: 'fun',
- params: [
- { p: 'x1', o: false },
- { p: 'y1', o: false },
- { p: 'x2', o: false },
- { p: 'y2', o: false },
- { p: 'x3', o: false },
- { p: 'y3', o: false }
- ],
- p5: true
- },
- {
- text: 'ellipseMode',
- type: 'fun',
- params: [{ p: 'mode', o: false }],
- p5: true
- },
- { text: 'noSmooth', type: 'fun', p5: true },
- {
- text: 'rectMode',
- type: 'fun',
- params: [{ p: 'mode', o: false }],
- p5: true
- },
- { text: 'smooth', type: 'fun', p5: true },
- {
- text: 'strokeCap',
- type: 'fun',
- params: [{ p: 'cap', o: false }],
- p5: true
- },
- {
- text: 'strokeJoin',
- type: 'fun',
- params: [{ p: 'join', o: false }],
- p5: true
- },
- {
- text: 'strokeWeight',
- type: 'fun',
- params: [{ p: 'weight', o: false }],
- p5: true
- },
- { text: 'bezier', type: 'fun', p5: true },
- {
- text: 'bezierDetail',
- type: 'fun',
- params: [{ p: 'detail', o: false }],
- p5: true
- },
- {
- text: 'bezierPoint',
- type: 'fun',
- params: [
- { p: 'a', o: false },
- { p: 'b', o: false },
- { p: 'c', o: false },
- { p: 'd', o: false },
- { p: 't', o: false }
- ],
- p5: true
- },
- {
- text: 'bezierTangent',
- type: 'fun',
- params: [
- { p: 'a', o: false },
- { p: 'b', o: false },
- { p: 'c', o: false },
- { p: 'd', o: false },
- { p: 't', o: false }
- ],
- p5: true
- },
- { text: 'curve', type: 'fun', p5: true },
- {
- text: 'curveDetail',
- type: 'fun',
- params: [{ p: 'resolution', o: false }],
- p5: true
- },
- {
- text: 'curveTightness',
- type: 'fun',
- params: [{ p: 'amount', o: false }],
- p5: true
- },
- {
- text: 'curvePoint',
- type: 'fun',
- params: [
- { p: 'a', o: false },
- { p: 'b', o: false },
- { p: 'c', o: false },
- { p: 'd', o: false },
- { p: 't', o: false }
- ],
- p5: true
- },
- {
- text: 'curveTangent',
- type: 'fun',
- params: [
- { p: 'a', o: false },
- { p: 'b', o: false },
- { p: 'c', o: false },
- { p: 'd', o: false },
- { p: 't', o: false }
- ],
- p5: true
- },
- { text: 'beginContour', type: 'fun', p5: true },
- {
- text: 'beginShape',
- type: 'fun',
- params: [{ p: 'kind', o: true }],
- p5: true
- },
- { text: 'bezierVertex', type: 'fun', p5: true },
- { text: 'curveVertex', type: 'fun', p5: true },
- { text: 'endContour', type: 'fun', p5: true },
- {
- text: 'endShape',
- type: 'fun',
- params: [
- { p: 'mode', o: true },
- { p: 'count', o: true }
- ],
- p5: true
- },
- { text: 'quadraticVertex', type: 'fun', p5: true },
- { text: 'vertex', type: 'fun', p5: true },
- { text: 'normal', type: 'fun', p5: true },
- { text: 'VERSION', type: 'var', params: [], p5: true },
- { text: 'P2D', type: 'var', params: [], p5: true },
- { text: 'WEBGL', type: 'var', params: [], p5: true },
- { text: 'WEBGL2', type: 'var', params: [], p5: true },
- { text: 'ARROW', type: 'var', params: [], p5: true },
- { text: 'CROSS', type: 'var', params: [], p5: true },
- { text: 'HAND', type: 'var', params: [], p5: true },
- { text: 'MOVE', type: 'var', params: [], p5: true },
- { text: 'TEXT', type: 'var', params: [], p5: true },
- { text: 'WAIT', type: 'var', params: [], p5: true },
- { text: 'HALF_PI', type: 'var', params: [], p5: true },
- { text: 'PI', type: 'var', params: [], p5: true },
- { text: 'QUARTER_PI', type: 'var', params: [], p5: true },
- { text: 'TAU', type: 'var', params: [], p5: true },
- { text: 'TWO_PI', type: 'var', params: [], p5: true },
- { text: 'DEGREES', type: 'var', params: [], p5: true },
- { text: 'RADIANS', type: 'var', params: [], p5: true },
- { text: 'CORNER', type: 'var', params: [], p5: true },
- { text: 'CORNERS', type: 'var', params: [], p5: true },
- { text: 'RADIUS', type: 'var', params: [], p5: true },
- { text: 'RIGHT', type: 'var', params: [], p5: true },
- { text: 'LEFT', type: 'var', params: [], p5: true },
- { text: 'CENTER', type: 'var', params: [], p5: true },
- { text: 'TOP', type: 'var', params: [], p5: true },
- { text: 'BOTTOM', type: 'var', params: [], p5: true },
- { text: 'BASELINE', type: 'var', params: [], p5: true },
- { text: 'POINTS', type: 'var', params: [], p5: true },
- { text: 'LINES', type: 'var', params: [], p5: true },
- { text: 'LINE_STRIP', type: 'var', params: [], p5: true },
- { text: 'LINE_LOOP', type: 'var', params: [], p5: true },
- { text: 'TRIANGLES', type: 'var', params: [], p5: true },
- { text: 'TRIANGLE_FAN', type: 'var', params: [], p5: true },
- { text: 'TRIANGLE_STRIP', type: 'var', params: [], p5: true },
- { text: 'QUADS', type: 'var', params: [], p5: true },
- { text: 'QUAD_STRIP', type: 'var', params: [], p5: true },
- { text: 'TESS', type: 'var', params: [], p5: true },
- { text: 'CLOSE', type: 'var', params: [], p5: true },
- { text: 'OPEN', type: 'var', params: [], p5: true },
- { text: 'CHORD', type: 'var', params: [], p5: true },
- { text: 'PIE', type: 'var', params: [], p5: true },
- { text: 'PROJECT', type: 'var', params: [], p5: true },
- { text: 'SQUARE', type: 'var', params: [], p5: true },
- { text: 'ROUND', type: 'var', params: [], p5: true },
- { text: 'BEVEL', type: 'var', params: [], p5: true },
- { text: 'MITER', type: 'var', params: [], p5: true },
- { text: 'RGB', type: 'var', params: [], p5: true },
- { text: 'HSB', type: 'var', params: [], p5: true },
- { text: 'HSL', type: 'var', params: [], p5: true },
- { text: 'AUTO', type: 'var', params: [], p5: true },
- { text: 'ALT', type: 'var', params: [], p5: true },
- { text: 'BACKSPACE', type: 'var', params: [], p5: true },
- { text: 'CONTROL', type: 'var', params: [], p5: true },
- { text: 'DELETE', type: 'var', params: [], p5: true },
- { text: 'DOWN_ARROW', type: 'var', params: [], p5: true },
- { text: 'ENTER', type: 'var', params: [], p5: true },
- { text: 'ESCAPE', type: 'var', params: [], p5: true },
- { text: 'LEFT_ARROW', type: 'var', params: [], p5: true },
- { text: 'OPTION', type: 'var', params: [], p5: true },
- { text: 'RETURN', type: 'var', params: [], p5: true },
- { text: 'RIGHT_ARROW', type: 'var', params: [], p5: true },
- { text: 'SHIFT', type: 'var', params: [], p5: true },
- { text: 'TAB', type: 'var', params: [], p5: true },
- { text: 'UP_ARROW', type: 'var', params: [], p5: true },
- { text: 'BLEND', type: 'var', params: [], p5: true },
- { text: 'REMOVE', type: 'var', params: [], p5: true },
- { text: 'ADD', type: 'var', params: [], p5: true },
- { text: 'DARKEST', type: 'var', params: [], p5: true },
- { text: 'LIGHTEST', type: 'var', params: [], p5: true },
- { text: 'DIFFERENCE', type: 'var', params: [], p5: true },
- { text: 'SUBTRACT', type: 'var', params: [], p5: true },
- { text: 'EXCLUSION', type: 'var', params: [], p5: true },
- { text: 'MULTIPLY', type: 'var', params: [], p5: true },
- { text: 'SCREEN', type: 'var', params: [], p5: true },
- { text: 'REPLACE', type: 'var', params: [], p5: true },
- { text: 'OVERLAY', type: 'var', params: [], p5: true },
- { text: 'HARD_LIGHT', type: 'var', params: [], p5: true },
- { text: 'SOFT_LIGHT', type: 'var', params: [], p5: true },
- { text: 'DODGE', type: 'var', params: [], p5: true },
- { text: 'BURN', type: 'var', params: [], p5: true },
- { text: 'THRESHOLD', type: 'var', params: [], p5: true },
- { text: 'GRAY', type: 'var', params: [], p5: true },
- { text: 'OPAQUE', type: 'var', params: [], p5: true },
- { text: 'INVERT', type: 'var', params: [], p5: true },
- { text: 'POSTERIZE', type: 'var', params: [], p5: true },
- { text: 'DILATE', type: 'var', params: [], p5: true },
- { text: 'ERODE', type: 'var', params: [], p5: true },
- { text: 'BLUR', type: 'var', params: [], p5: true },
- { text: 'NORMAL', type: 'var', params: [], p5: true },
- { text: 'ITALIC', type: 'var', params: [], p5: true },
- { text: 'BOLD', type: 'var', params: [], p5: true },
- { text: 'BOLDITALIC', type: 'var', params: [], p5: true },
- { text: 'CHAR', type: 'var', params: [], p5: true },
- { text: 'WORD', type: 'var', params: [], p5: true },
- { text: 'LINEAR', type: 'var', params: [], p5: true },
- { text: 'QUADRATIC', type: 'var', params: [], p5: true },
- { text: 'BEZIER', type: 'var', params: [], p5: true },
- { text: 'CURVE', type: 'var', params: [], p5: true },
- { text: 'STROKE', type: 'var', params: [], p5: true },
- { text: 'FILL', type: 'var', params: [], p5: true },
- { text: 'TEXTURE', type: 'var', params: [], p5: true },
- { text: 'IMMEDIATE', type: 'var', params: [], p5: true },
- { text: 'IMAGE', type: 'var', params: [], p5: true },
- { text: 'NEAREST', type: 'var', params: [], p5: true },
- { text: 'REPEAT', type: 'var', params: [], p5: true },
- { text: 'CLAMP', type: 'var', params: [], p5: true },
- { text: 'MIRROR', type: 'var', params: [], p5: true },
- { text: 'FLAT', type: 'var', params: [], p5: true },
- { text: 'SMOOTH', type: 'var', params: [], p5: true },
- { text: 'LANDSCAPE', type: 'var', params: [], p5: true },
- { text: 'PORTRAIT', type: 'var', params: [], p5: true },
- { text: 'GRID', type: 'var', params: [], p5: true },
- { text: 'AXES', type: 'var', params: [], p5: true },
- { text: 'LABEL', type: 'var', params: [], p5: true },
- { text: 'FALLBACK', type: 'var', params: [], p5: true },
- { text: 'CONTAIN', type: 'var', params: [], p5: true },
- { text: 'COVER', type: 'var', params: [], p5: true },
- { text: 'UNSIGNED_BYTE', type: 'var', params: [], p5: true },
- { text: 'UNSIGNED_INT', type: 'var', params: [], p5: true },
- { text: 'FLOAT', type: 'var', params: [], p5: true },
- { text: 'HALF_FLOAT', type: 'var', params: [], p5: true },
- { text: 'RGBA', type: 'var', params: [], p5: true },
- {
- text: 'print',
- type: 'fun',
- params: [{ p: 'contents', o: false }],
- p5: true
- },
- { text: 'frameCount', type: 'var', params: [], p5: true },
- { text: 'deltaTime', type: 'var', params: [], p5: true },
- { text: 'focused', type: 'var', params: [], p5: true },
- {
- text: 'cursor',
- type: 'fun',
- params: [
- { p: 'type', o: false },
- { p: 'x', o: true },
- { p: 'y', o: true }
- ],
- p5: true
- },
- { text: 'frameRate', type: 'fun', p5: true },
- { text: 'getTargetFrameRate', type: 'fun', p5: true },
- { text: 'noCursor', type: 'fun', p5: true },
- { text: 'webglVersion', type: 'var', params: [], p5: true },
- { text: 'displayWidth', type: 'var', params: [], p5: true },
- { text: 'displayHeight', type: 'var', params: [], p5: true },
- { text: 'windowWidth', type: 'var', params: [], p5: true },
- { text: 'windowHeight', type: 'var', params: [], p5: true },
- {
- text: 'windowResized',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- { text: 'width', type: 'var', params: [], p5: true },
- { text: 'height', type: 'var', params: [], p5: true },
- {
- text: 'fullscreen',
- type: 'fun',
- params: [{ p: 'val', o: true }],
- p5: true
- },
- { text: 'pixelDensity', type: 'fun', p5: true },
- { text: 'displayDensity', type: 'fun', p5: true },
- { text: 'getURL', type: 'fun', p5: true },
- { text: 'getURLPath', type: 'fun', p5: true },
- { text: 'getURLParams', type: 'fun', p5: true },
- { text: 'preload', type: 'fun', p5: true },
- { text: 'setup', type: 'fun', p5: true },
- { text: 'draw', type: 'fun', p5: true },
- { text: 'remove', type: 'fun', p5: true },
- { text: 'disableFriendlyErrors', type: 'var', params: [], p5: true },
- { text: 'createCanvas', type: 'fun', p5: true },
- {
- text: 'resizeCanvas',
- type: 'fun',
- params: [
- { p: 'width', o: false },
- { p: 'height', o: false },
- { p: 'noRedraw', o: true }
- ],
- p5: true
- },
- { text: 'noCanvas', type: 'fun', p5: true },
- { text: 'createGraphics', type: 'fun', p5: true },
- {
- text: 'createFramebuffer',
- type: 'fun',
- params: [{ p: 'options', o: true }],
- p5: true
- },
- {
- text: 'clearDepth',
- type: 'fun',
- params: [{ p: 'depth', o: true }],
- p5: true
- },
- {
- text: 'blendMode',
- type: 'fun',
- params: [{ p: 'mode', o: false }],
- p5: true
- },
- { text: 'drawingContext', type: 'var', params: [], p5: true },
- { text: 'noLoop', type: 'fun', p5: true },
- { text: 'loop', type: 'fun', p5: true },
- { text: 'isLooping', type: 'fun', p5: true },
- { text: 'push', type: 'fun', p5: true },
- { text: 'pop', type: 'fun', p5: true },
- { text: 'redraw', type: 'fun', params: [{ p: 'n', o: true }], p5: true },
- {
- text: 'p5',
- type: 'fun',
- params: [
- { p: 'sketch', o: false },
- { p: 'node', o: false }
- ],
- p5: true
- },
- { text: 'applyMatrix', type: 'fun', p5: true },
- { text: 'resetMatrix', type: 'fun', p5: true },
- {
- text: 'rotate',
- type: 'fun',
- params: [
- { p: 'angle', o: false },
- { p: 'axis', o: true }
- ],
- p5: true
- },
- {
- text: 'rotateX',
- type: 'fun',
- params: [{ p: 'angle', o: false }],
- p5: true
- },
- {
- text: 'rotateY',
- type: 'fun',
- params: [{ p: 'angle', o: false }],
- p5: true
- },
- {
- text: 'rotateZ',
- type: 'fun',
- params: [{ p: 'angle', o: false }],
- p5: true
- },
- { text: 'scale', type: 'fun', p5: true },
- { text: 'shearX', type: 'fun', params: [{ p: 'angle', o: false }], p5: true },
- { text: 'shearY', type: 'fun', params: [{ p: 'angle', o: false }], p5: true },
- { text: 'translate', type: 'fun', p5: true },
- {
- text: 'storeItem',
- type: 'fun',
- params: [
- { p: 'key', o: false },
- { p: 'value', o: false }
- ],
- p5: true
- },
- { text: 'getItem', type: 'fun', params: [{ p: 'key', o: false }], p5: true },
- { text: 'clearStorage', type: 'fun', p5: true },
- {
- text: 'removeItem',
- type: 'fun',
- params: [{ p: 'key', o: false }],
- p5: true
- },
- { text: 'createStringDict', type: 'fun', p5: true },
- { text: 'createNumberDict', type: 'fun', p5: true },
- {
- text: 'select',
- type: 'fun',
- params: [
- { p: 'selectors', o: false },
- { p: 'container', o: true }
- ],
- p5: true
- },
- {
- text: 'selectAll',
- type: 'fun',
- params: [
- { p: 'selectors', o: false },
- { p: 'container', o: true }
- ],
- p5: true
- },
- { text: 'removeElements', type: 'fun', p5: true },
- { text: 'changed', type: 'fun', params: [{ p: 'fxn', o: false }], p5: true },
- { text: 'input', type: 'fun', params: [{ p: 'fxn', o: false }], p5: true },
- {
- text: 'createDiv',
- type: 'fun',
- params: [{ p: 'html', o: true }],
- p5: true
- },
- { text: 'createP', type: 'fun', params: [{ p: 'html', o: true }], p5: true },
- {
- text: 'createSpan',
- type: 'fun',
- params: [{ p: 'html', o: true }],
- p5: true
- },
- { text: 'createImg', type: 'fun', p5: true },
- {
- text: 'createA',
- type: 'fun',
- params: [
- { p: 'href', o: false },
- { p: 'html', o: false },
- { p: 'target', o: true }
- ],
- p5: true
- },
- {
- text: 'createSlider',
- type: 'fun',
- params: [
- { p: 'min', o: false },
- { p: 'max', o: false },
- { p: 'value', o: true },
- { p: 'step', o: true }
- ],
- p5: true
- },
- {
- text: 'createButton',
- type: 'fun',
- params: [
- { p: 'label', o: false },
- { p: 'value', o: true }
- ],
- p5: true
- },
- {
- text: 'createCheckbox',
- type: 'fun',
- params: [
- { p: 'label', o: true },
- { p: 'value', o: true }
- ],
- p5: true
- },
- { text: 'createSelect', type: 'fun', p5: true },
- { text: 'createRadio', type: 'fun', p5: true },
- {
- text: 'createColorPicker',
- type: 'fun',
- params: [{ p: 'value', o: true }],
- p5: true
- },
- { text: 'createInput', type: 'fun', p5: true },
- {
- text: 'createFileInput',
- type: 'fun',
- params: [
- { p: 'callback', o: false },
- { p: 'multiple', o: true }
- ],
- p5: true
- },
- {
- text: 'createVideo',
- type: 'fun',
- params: [
- { p: 'src', o: false },
- { p: 'callback', o: true }
- ],
- p5: true
- },
- {
- text: 'createAudio',
- type: 'fun',
- params: [
- { p: 'src', o: true },
- { p: 'callback', o: true }
- ],
- p5: true
- },
- {
- text: 'createCapture',
- type: 'fun',
- params: [
- { p: 'type', o: true },
- { p: 'flipped', o: true },
- { p: 'callback', o: true }
- ],
- p5: true
- },
- {
- text: 'createElement',
- type: 'fun',
- params: [
- { p: 'tag', o: false },
- { p: 'content', o: true }
- ],
- p5: true
- },
- { text: 'deviceOrientation', type: 'var', params: [], p5: true },
- { text: 'accelerationX', type: 'var', params: [], p5: true },
- { text: 'accelerationY', type: 'var', params: [], p5: true },
- { text: 'accelerationZ', type: 'var', params: [], p5: true },
- { text: 'pAccelerationX', type: 'var', params: [], p5: true },
- { text: 'pAccelerationY', type: 'var', params: [], p5: true },
- { text: 'pAccelerationZ', type: 'var', params: [], p5: true },
- { text: 'rotationX', type: 'var', params: [], p5: true },
- { text: 'rotationY', type: 'var', params: [], p5: true },
- { text: 'rotationZ', type: 'var', params: [], p5: true },
- { text: 'pRotationX', type: 'var', params: [], p5: true },
- { text: 'pRotationY', type: 'var', params: [], p5: true },
- { text: 'pRotationZ', type: 'var', params: [], p5: true },
- { text: 'turnAxis', type: 'var', params: [], p5: true },
- {
- text: 'setMoveThreshold',
- type: 'fun',
- params: [{ p: 'value', o: false }],
- p5: true
- },
- {
- text: 'setShakeThreshold',
- type: 'fun',
- params: [{ p: 'value', o: false }],
- p5: true
- },
- { text: 'deviceMoved', type: 'fun', p5: true },
- { text: 'deviceTurned', type: 'fun', p5: true },
- { text: 'deviceShaken', type: 'fun', p5: true },
- { text: 'keyIsPressed', type: 'var', params: [], p5: true },
- { text: 'key', type: 'var', params: [], p5: true },
- { text: 'keyCode', type: 'var', params: [], p5: true },
- {
- text: 'keyPressed',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- {
- text: 'keyReleased',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- {
- text: 'keyTyped',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- {
- text: 'keyIsDown',
- type: 'fun',
- params: [{ p: 'code', o: false }],
- p5: true
- },
- { text: 'movedX', type: 'var', params: [], p5: true },
- { text: 'movedY', type: 'var', params: [], p5: true },
- { text: 'mouseX', type: 'var', params: [], p5: true },
- { text: 'mouseY', type: 'var', params: [], p5: true },
- { text: 'pmouseX', type: 'var', params: [], p5: true },
- { text: 'pmouseY', type: 'var', params: [], p5: true },
- { text: 'winMouseX', type: 'var', params: [], p5: true },
- { text: 'winMouseY', type: 'var', params: [], p5: true },
- { text: 'pwinMouseX', type: 'var', params: [], p5: true },
- { text: 'pwinMouseY', type: 'var', params: [], p5: true },
- { text: 'mouseButton', type: 'var', params: [], p5: true },
- { text: 'mouseIsPressed', type: 'var', params: [], p5: true },
- {
- text: 'mouseMoved',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- {
- text: 'mouseDragged',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- {
- text: 'mousePressed',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- {
- text: 'mouseReleased',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- {
- text: 'mouseClicked',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- {
- text: 'doubleClicked',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- {
- text: 'mouseWheel',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- { text: 'requestPointerLock', type: 'fun', p5: true },
- { text: 'exitPointerLock', type: 'fun', p5: true },
- { text: 'touches', type: 'var', params: [], p5: true },
- {
- text: 'touchStarted',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- {
- text: 'touchMoved',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- {
- text: 'touchEnded',
- type: 'fun',
- params: [{ p: 'event', o: true }],
- p5: true
- },
- {
- text: 'createImage',
- type: 'fun',
- params: [
- { p: 'width', o: false },
- { p: 'height', o: false }
- ],
- p5: true
- },
- { text: 'saveCanvas', type: 'fun', p5: true },
- {
- text: 'saveFrames',
- type: 'fun',
- params: [
- { p: 'filename', o: false },
- { p: 'extension', o: false },
- { p: 'duration', o: false },
- { p: 'framerate', o: false },
- { p: 'callback', o: true }
- ],
- p5: true
- },
- {
- text: 'loadImage',
- type: 'fun',
- params: [
- { p: 'path', o: false },
- { p: 'successCallback', o: true },
- { p: 'failureCallback', o: true }
- ],
- p5: true
- },
- {
- text: 'saveGif',
- type: 'fun',
- params: [
- { p: 'filename', o: false },
- { p: 'duration', o: false },
- { p: 'options', o: true }
- ],
- p5: true
- },
- { text: 'image', type: 'fun', p5: true },
- { text: 'tint', type: 'fun', p5: true },
- { text: 'noTint', type: 'fun', p5: true },
- {
- text: 'imageMode',
- type: 'fun',
- params: [{ p: 'mode', o: false }],
- p5: true
- },
- { text: 'pixels', type: 'var', params: [], p5: true },
- { text: 'blend', type: 'fun', p5: true },
- { text: 'copy', type: 'fun', p5: true },
- { text: 'filter', type: 'fun', p5: true },
- { text: 'get', type: 'fun', p5: true },
- { text: 'loadPixels', type: 'fun', p5: true },
- {
- text: 'set',
- type: 'fun',
- params: [
- { p: 'x', o: false },
- { p: 'y', o: false },
- { p: 'c', o: false }
- ],
- p5: true
- },
- {
- text: 'updatePixels',
- type: 'fun',
- params: [
- { p: 'x', o: true },
- { p: 'y', o: true },
- { p: 'w', o: true },
- { p: 'h', o: true }
- ],
- p5: true
- },
- {
- text: 'loadJSON',
- type: 'fun',
- params: [
- { p: 'path', o: false },
- { p: 'successCallback', o: true },
- { p: 'errorCallback', o: true }
- ],
- p5: true
- },
- {
- text: 'loadStrings',
- type: 'fun',
- params: [
- { p: 'path', o: false },
- { p: 'successCallback', o: true },
- { p: 'errorCallback', o: true }
- ],
- p5: true
- },
- {
- text: 'loadTable',
- type: 'fun',
- params: [
- { p: 'filename', o: false },
- { p: 'extension', o: true },
- { p: 'header', o: true },
- { p: 'callback', o: true },
- { p: 'errorCallback', o: true }
- ],
- p5: true
- },
- {
- text: 'loadXML',
- type: 'fun',
- params: [
- { p: 'path', o: false },
- { p: 'successCallback', o: true },
- { p: 'errorCallback', o: true }
- ],
- p5: true
- },
- {
- text: 'loadBytes',
- type: 'fun',
- params: [
- { p: 'file', o: false },
- { p: 'callback', o: true },
- { p: 'errorCallback', o: true }
- ],
- p5: true
- },
- { text: 'httpGet', type: 'fun', p5: true },
- { text: 'httpPost', type: 'fun', p5: true },
- { text: 'httpDo', type: 'fun', p5: true },
- {
- text: 'createWriter',
- type: 'fun',
- params: [
- { p: 'name', o: false },
- { p: 'extension', o: true }
- ],
- p5: true
- },
- {
- text: 'save',
- type: 'fun',
- params: [
- { p: 'objectOrFilename', o: true },
- { p: 'filename', o: true },
- { p: 'options', o: true }
- ],
- p5: true
- },
- {
- text: 'saveJSON',
- type: 'fun',
- params: [
- { p: 'json', o: false },
- { p: 'filename', o: false },
- { p: 'optimize', o: true }
- ],
- p5: true
- },
- {
- text: 'saveStrings',
- type: 'fun',
- params: [
- { p: 'list', o: false },
- { p: 'filename', o: false },
- { p: 'extension', o: true },
- { p: 'isCRLF', o: true }
- ],
- p5: true
- },
- {
- text: 'saveTable',
- type: 'fun',
- params: [
- { p: 'Table', o: false },
- { p: 'filename', o: false },
- { p: 'options', o: true }
- ],
- p5: true
- },
- { text: 'abs', type: 'fun', params: [{ p: 'n', o: false }], p5: true },
- { text: 'ceil', type: 'fun', params: [{ p: 'n', o: false }], p5: true },
- {
- text: 'constrain',
- type: 'fun',
- params: [
- { p: 'n', o: false },
- { p: 'low', o: false },
- { p: 'high', o: false }
- ],
- p5: true
- },
- { text: 'dist', type: 'fun', p5: true },
- { text: 'exp', type: 'fun', params: [{ p: 'n', o: false }], p5: true },
- { text: 'floor', type: 'fun', params: [{ p: 'n', o: false }], p5: true },
- {
- text: 'lerp',
- type: 'fun',
- params: [
- { p: 'start', o: false },
- { p: 'stop', o: false },
- { p: 'amt', o: false }
- ],
- p5: true
- },
- { text: 'log', type: 'fun', params: [{ p: 'n', o: false }], p5: true },
- {
- text: 'mag',
- type: 'fun',
- params: [
- { p: 'x', o: false },
- { p: 'y', o: false }
- ],
- p5: true
- },
- {
- text: 'map',
- type: 'fun',
- params: [
- { p: 'value', o: false },
- { p: 'start1', o: false },
- { p: 'stop1', o: false },
- { p: 'start2', o: false },
- { p: 'stop2', o: false },
- { p: 'withinBounds', o: true }
- ],
- p5: true
- },
- { text: 'max', type: 'fun', p5: true },
- { text: 'min', type: 'fun', p5: true },
- {
- text: 'norm',
- type: 'fun',
- params: [
- { p: 'value', o: false },
- { p: 'start', o: false },
- { p: 'stop', o: false }
- ],
- p5: true
- },
- {
- text: 'pow',
- type: 'fun',
- params: [
- { p: 'n', o: false },
- { p: 'e', o: false }
- ],
- p5: true
- },
- {
- text: 'round',
- type: 'fun',
- params: [
- { p: 'n', o: false },
- { p: 'decimals', o: true }
- ],
- p5: true
- },
- { text: 'sq', type: 'fun', params: [{ p: 'n', o: false }], p5: true },
- { text: 'sqrt', type: 'fun', params: [{ p: 'n', o: false }], p5: true },
- { text: 'fract', type: 'fun', params: [{ p: 'n', o: false }], p5: true },
- {
- text: 'createVector',
- type: 'fun',
- params: [
- { p: 'x', o: true },
- { p: 'y', o: true },
- { p: 'z', o: true }
- ],
- p5: true
- },
- {
- text: 'noise',
- type: 'fun',
- params: [
- { p: 'x', o: false },
- { p: 'y', o: true },
- { p: 'z', o: true }
- ],
- p5: true
- },
- {
- text: 'noiseDetail',
- type: 'fun',
- params: [
- { p: 'lod', o: false },
- { p: 'falloff', o: false }
- ],
- p5: true
- },
- {
- text: 'noiseSeed',
- type: 'fun',
- params: [{ p: 'seed', o: false }],
- p5: true
- },
- {
- text: 'randomSeed',
- type: 'fun',
- params: [{ p: 'seed', o: false }],
- p5: true
- },
- { text: 'random', type: 'fun', p5: true },
- {
- text: 'randomGaussian',
- type: 'fun',
- params: [
- { p: 'mean', o: true },
- { p: 'sd', o: true }
- ],
- p5: true
- },
- { text: 'acos', type: 'fun', params: [{ p: 'value', o: false }], p5: true },
- { text: 'asin', type: 'fun', params: [{ p: 'value', o: false }], p5: true },
- { text: 'atan', type: 'fun', params: [{ p: 'value', o: false }], p5: true },
- {
- text: 'atan2',
- type: 'fun',
- params: [
- { p: 'y', o: false },
- { p: 'x', o: false }
- ],
- p5: true
- },
- { text: 'cos', type: 'fun', params: [{ p: 'angle', o: false }], p5: true },
- { text: 'sin', type: 'fun', params: [{ p: 'angle', o: false }], p5: true },
- { text: 'tan', type: 'fun', params: [{ p: 'angle', o: false }], p5: true },
- {
- text: 'degrees',
- type: 'fun',
- params: [{ p: 'radians', o: false }],
- p5: true
- },
- {
- text: 'radians',
- type: 'fun',
- params: [{ p: 'degrees', o: false }],
- p5: true
- },
- { text: 'angleMode', type: 'fun', p5: true },
- { text: 'textAlign', type: 'fun', p5: true },
- { text: 'textLeading', type: 'fun', p5: true },
- { text: 'textSize', type: 'fun', p5: true },
- { text: 'textStyle', type: 'fun', p5: true },
- {
- text: 'textWidth',
- type: 'fun',
- params: [{ p: 'str', o: false }],
- p5: true
- },
- { text: 'textAscent', type: 'fun', p5: true },
- { text: 'textDescent', type: 'fun', p5: true },
- {
- text: 'textWrap',
- type: 'fun',
- params: [{ p: 'style', o: false }],
- p5: true
- },
- {
- text: 'loadFont',
- type: 'fun',
- params: [
- { p: 'path', o: false },
- { p: 'successCallback', o: true },
- { p: 'failureCallback', o: true }
- ],
- p5: true
- },
- {
- text: 'text',
- type: 'fun',
- params: [
- { p: 'str', o: false },
- { p: 'x', o: false },
- { p: 'y', o: false },
- { p: 'maxWidth', o: true },
- { p: 'maxHeight', o: true }
- ],
- p5: true
- },
- { text: 'textFont', type: 'fun', p5: true },
- {
- text: 'append',
- type: 'fun',
- params: [
- { p: 'array', o: false },
- { p: 'value', o: false }
- ],
- p5: true
- },
- { text: 'arrayCopy', type: 'fun', p5: true },
- {
- text: 'concat',
- type: 'fun',
- params: [
- { p: 'a', o: false },
- { p: 'b', o: false }
- ],
- p5: true
- },
- { text: 'reverse', type: 'fun', params: [{ p: 'list', o: false }], p5: true },
- { text: 'shorten', type: 'fun', params: [{ p: 'list', o: false }], p5: true },
- {
- text: 'shuffle',
- type: 'fun',
- params: [
- { p: 'array', o: false },
- { p: 'bool', o: true }
- ],
- p5: true
- },
- {
- text: 'sort',
- type: 'fun',
- params: [
- { p: 'list', o: false },
- { p: 'count', o: true }
- ],
- p5: true
- },
- {
- text: 'splice',
- type: 'fun',
- params: [
- { p: 'list', o: false },
- { p: 'value', o: false },
- { p: 'position', o: false }
- ],
- p5: true
- },
- {
- text: 'subset',
- type: 'fun',
- params: [
- { p: 'list', o: false },
- { p: 'start', o: false },
- { p: 'count', o: true }
- ],
- p5: true
- },
- { text: 'float', type: 'fun', p5: true },
- { text: 'int', type: 'fun', p5: true },
- { text: 'str', type: 'fun', params: [{ p: 'n', o: false }], p5: true },
- { text: 'boolean', type: 'fun', p5: true },
- { text: 'byte', type: 'fun', p5: true },
- { text: 'char', type: 'fun', p5: true },
- { text: 'unchar', type: 'fun', p5: true },
- { text: 'hex', type: 'fun', p5: true },
- { text: 'unhex', type: 'fun', p5: true },
- {
- text: 'join',
- type: 'fun',
- params: [
- { p: 'list', o: false },
- { p: 'separator', o: false }
- ],
- p5: true
- },
- {
- text: 'match',
- type: 'fun',
- params: [
- { p: 'str', o: false },
- { p: 'regexp', o: false }
- ],
- p5: true
- },
- {
- text: 'matchAll',
- type: 'fun',
- params: [
- { p: 'str', o: false },
- { p: 'regexp', o: false }
- ],
- p5: true
- },
- { text: 'nf', type: 'fun', p5: true },
- { text: 'nfc', type: 'fun', p5: true },
- { text: 'nfp', type: 'fun', p5: true },
- { text: 'nfs', type: 'fun', p5: true },
- {
- text: 'split',
- type: 'fun',
- params: [
- { p: 'value', o: false },
- { p: 'delim', o: false }
- ],
- p5: true
- },
- {
- text: 'splitTokens',
- type: 'fun',
- params: [
- { p: 'value', o: false },
- { p: 'delim', o: true }
- ],
- p5: true
- },
- { text: 'trim', type: 'fun', p5: true },
- { text: 'day', type: 'fun', p5: true },
- { text: 'hour', type: 'fun', p5: true },
- { text: 'minute', type: 'fun', p5: true },
- { text: 'millis', type: 'fun', p5: true },
- { text: 'month', type: 'fun', p5: true },
- { text: 'second', type: 'fun', p5: true },
- { text: 'year', type: 'fun', p5: true },
- { text: 'beginGeometry', type: 'fun', p5: true },
- { text: 'endGeometry', type: 'fun', p5: true },
- {
- text: 'buildGeometry',
- type: 'fun',
- params: [{ p: 'callback', o: false }],
- p5: true
- },
- {
- text: 'freeGeometry',
- type: 'fun',
- params: [{ p: 'geometry', o: false }],
- p5: true
- },
- {
- text: 'plane',
- type: 'fun',
- params: [
- { p: 'width', o: true },
- { p: 'height', o: true },
- { p: 'detailX', o: true },
- { p: 'detailY', o: true }
- ],
- p5: true
- },
- {
- text: 'box',
- type: 'fun',
- params: [
- { p: 'width', o: true },
- { p: 'height', o: true },
- { p: 'depth', o: true },
- { p: 'detailX', o: true },
- { p: 'detailY', o: true }
- ],
- p5: true
- },
- {
- text: 'sphere',
- type: 'fun',
- params: [
- { p: 'radius', o: true },
- { p: 'detailX', o: true },
- { p: 'detailY', o: true }
- ],
- p5: true
- },
- {
- text: 'cylinder',
- type: 'fun',
- params: [
- { p: 'radius', o: true },
- { p: 'height', o: true },
- { p: 'detailX', o: true },
- { p: 'detailY', o: true },
- { p: 'bottomCap', o: true },
- { p: 'topCap', o: true }
- ],
- p5: true
- },
- {
- text: 'cone',
- type: 'fun',
- params: [
- { p: 'radius', o: true },
- { p: 'height', o: true },
- { p: 'detailX', o: true },
- { p: 'detailY', o: true },
- { p: 'cap', o: true }
- ],
- p5: true
- },
- {
- text: 'ellipsoid',
- type: 'fun',
- params: [
- { p: 'radiusX', o: true },
- { p: 'radiusY', o: true },
- { p: 'radiusZ', o: true },
- { p: 'detailX', o: true },
- { p: 'detailY', o: true }
- ],
- p5: true
- },
- {
- text: 'torus',
- type: 'fun',
- params: [
- { p: 'radius', o: true },
- { p: 'tubeRadius', o: true },
- { p: 'detailX', o: true },
- { p: 'detailY', o: true }
- ],
- p5: true
- },
- {
- text: 'orbitControl',
- type: 'fun',
- params: [
- { p: 'sensitivityX', o: true },
- { p: 'sensitivityY', o: true },
- { p: 'sensitivityZ', o: true },
- { p: 'options', o: true }
- ],
- p5: true
- },
- { text: 'debugMode', type: 'fun', p5: true },
- { text: 'noDebugMode', type: 'fun', p5: true },
- { text: 'ambientLight', type: 'fun', p5: true },
- { text: 'specularColor', type: 'fun', p5: true },
- { text: 'directionalLight', type: 'fun', p5: true },
- { text: 'pointLight', type: 'fun', p5: true },
- {
- text: 'imageLight',
- type: 'fun',
- params: [{ p: 'img', o: false }],
- p5: true
- },
- { text: 'panorama', type: 'fun', params: [{ p: 'img', o: false }], p5: true },
- { text: 'lights', type: 'fun', p5: true },
- {
- text: 'lightFalloff',
- type: 'fun',
- params: [
- { p: 'constant', o: false },
- { p: 'linear', o: false },
- { p: 'quadratic', o: false }
- ],
- p5: true
- },
- { text: 'spotLight', type: 'fun', p5: true },
- { text: 'noLights', type: 'fun', p5: true },
- { text: 'loadModel', type: 'fun', p5: true },
- { text: 'model', type: 'fun', params: [{ p: 'model', o: false }], p5: true },
- {
- text: 'loadShader',
- type: 'fun',
- params: [
- { p: 'vertFilename', o: false },
- { p: 'fragFilename', o: false },
- { p: 'successCallback', o: true },
- { p: 'failureCallback', o: true }
- ],
- p5: true
- },
- {
- text: 'createShader',
- type: 'fun',
- params: [
- { p: 'vertSrc', o: false },
- { p: 'fragSrc', o: false }
- ],
- p5: true
- },
- {
- text: 'createFilterShader',
- type: 'fun',
- params: [{ p: 'fragSrc', o: false }],
- p5: true
- },
- { text: 'shader', type: 'fun', params: [{ p: 's', o: false }], p5: true },
- { text: 'resetShader', type: 'fun', p5: true },
- { text: 'texture', type: 'fun', params: [{ p: 'tex', o: false }], p5: true },
- {
- text: 'textureMode',
- type: 'fun',
- params: [{ p: 'mode', o: false }],
- p5: true
- },
- {
- text: 'textureWrap',
- type: 'fun',
- params: [
- { p: 'wrapX', o: false },
- { p: 'wrapY', o: true }
- ],
- p5: true
- },
- { text: 'normalMaterial', type: 'fun', p5: true },
- { text: 'ambientMaterial', type: 'fun', p5: true },
- { text: 'emissiveMaterial', type: 'fun', p5: true },
- { text: 'specularMaterial', type: 'fun', p5: true },
- {
- text: 'shininess',
- type: 'fun',
- params: [{ p: 'shine', o: false }],
- p5: true
- },
- {
- text: 'metalness',
- type: 'fun',
- params: [{ p: 'metallic', o: false }],
- p5: true
- },
- {
- text: 'camera',
- type: 'fun',
- params: [
- { p: 'x', o: true },
- { p: 'y', o: true },
- { p: 'z', o: true },
- { p: 'centerX', o: true },
- { p: 'centerY', o: true },
- { p: 'centerZ', o: true },
- { p: 'upX', o: true },
- { p: 'upY', o: true },
- { p: 'upZ', o: true }
- ],
- p5: true
- },
- {
- text: 'perspective',
- type: 'fun',
- params: [
- { p: 'fovy', o: true },
- { p: 'aspect', o: true },
- { p: 'near', o: true },
- { p: 'far', o: true }
- ],
- p5: true
- },
- { text: 'linePerspective', type: 'fun', p5: true },
- {
- text: 'ortho',
- type: 'fun',
- params: [
- { p: 'left', o: true },
- { p: 'right', o: true },
- { p: 'bottom', o: true },
- { p: 'top', o: true },
- { p: 'near', o: true },
- { p: 'far', o: true }
- ],
- p5: true
- },
- {
- text: 'frustum',
- type: 'fun',
- params: [
- { p: 'left', o: true },
- { p: 'right', o: true },
- { p: 'bottom', o: true },
- { p: 'top', o: true },
- { p: 'near', o: true },
- { p: 'far', o: true }
- ],
- p5: true
- },
- { text: 'createCamera', type: 'fun', p5: true },
- {
- text: 'setCamera',
- type: 'fun',
- params: [{ p: 'cam', o: false }],
- p5: true
- },
- { text: 'setAttributes', type: 'fun', p5: true },
- { text: 'getAudioContext', type: 'fun', p5: true },
- {
- text: 'userStartAudio',
- type: 'fun',
- params: [
- { p: 'elements', o: true },
- { p: 'callback', o: true }
- ],
- p5: true
- },
- { text: 'getOutputVolume', type: 'fun', p5: true },
- {
- text: 'outputVolume',
- type: 'fun',
- params: [
- { p: 'volume', o: false },
- { p: 'rampTime', o: true },
- { p: 'timeFromNow', o: true }
- ],
- p5: true
- },
- { text: 'soundOut', type: 'var', params: [], p5: true },
- { text: 'sampleRate', type: 'fun', p5: true },
- {
- text: 'freqToMidi',
- type: 'fun',
- params: [{ p: 'frequency', o: false }],
- p5: true
- },
- {
- text: 'midiToFreq',
- type: 'fun',
- params: [{ p: 'midiNote', o: false }],
- p5: true
- },
- {
- text: 'soundFormats',
- type: 'fun',
- params: [{ p: 'formats', o: true }],
- p5: true
- },
- {
- text: 'saveSound',
- type: 'fun',
- params: [
- { p: 'soundFile', o: false },
- { p: 'fileName', o: false }
- ],
- p5: true
- },
- {
- text: 'loadSound',
- type: 'fun',
- params: [
- { p: 'path', o: false },
- { p: 'successCallback', o: true },
- { p: 'errorCallback', o: true },
- { p: 'whileLoading', o: true }
- ],
- p5: true
- },
- {
- text: 'createConvolver',
- type: 'fun',
- params: [
- { p: 'path', o: false },
- { p: 'callback', o: true },
- { p: 'errorCallback', o: true }
- ],
- p5: true
- },
- {
- text: 'setBPM',
- type: 'fun',
- params: [
- { p: 'BPM', o: false },
- { p: 'rampTime', o: false }
- ],
- p5: true
- },
- { text: 'true', type: 'boolean', p5: 'boolean' },
- { text: 'false', type: 'boolean', p5: 'boolean' },
- { text: 'await', type: 'keyword', p5: false },
- { text: 'break', type: 'keyword', p5: false },
- { text: 'case', type: 'keyword', p5: false },
- { text: 'catch', type: 'keyword', p5: false },
- { text: 'class', type: 'keyword', p5: 'class' },
- { text: 'const', type: 'keyword', p5: 'const' },
- { text: 'continue', type: 'keyword', p5: false },
- { text: 'debugger', type: 'keyword', p5: false },
- { text: 'default', type: 'keyword', p5: false },
- { text: 'delete', type: 'keyword', p5: false },
- { text: 'do', type: 'keyword', p5: false },
- { text: 'else', type: 'keyword', p5: 'if-else' },
- { text: 'export', type: 'keyword', p5: false },
- { text: 'extends', type: 'keyword', p5: false },
- { text: 'finally', type: 'keyword', p5: false },
- { text: 'for', type: 'keyword', p5: 'for' },
- { text: 'function', type: 'keyword', p5: 'function' },
- { text: 'if', type: 'keyword', p5: 'if-else' },
- { text: 'import', type: 'keyword', p5: false },
- { text: 'in', type: 'keyword', p5: false },
- { text: 'instanceof', type: 'keyword', p5: false },
- { text: 'new', type: 'keyword', p5: false },
- { text: 'return', type: 'keyword', p5: 'return' },
- { text: 'super', type: 'keyword', p5: false },
- { text: 'switch', type: 'keyword', p5: false },
- { text: 'this', type: 'keyword', p5: false },
- { text: 'throw', type: 'keyword', p5: false },
- { text: 'try', type: 'keyword', p5: false },
- { text: 'typeof', type: 'keyword', p5: false },
- { text: 'var', type: 'keyword', p5: false },
- { text: 'void', type: 'keyword', p5: false },
- { text: 'while', type: 'keyword', p5: 'while' },
- { text: 'with', type: 'keyword', p5: false },
- { text: 'yield', type: 'keyword', p5: false },
- { text: 'let', type: 'keyword', p5: 'let' },
- { text: 'Array', type: 'obj', p5: false },
- { text: 'Boolean', type: 'obj', p5: false },
- { text: 'Date', type: 'obj', p5: false },
- { text: 'Error', type: 'obj', p5: false },
- { text: 'Function', type: 'obj', p5: false },
- { text: 'JSON', type: 'obj', p5: 'JSON' },
- { text: 'Math', type: 'obj', p5: false },
- { text: 'Number', type: 'obj', p5: false },
- { text: 'Object', type: 'obj', p5: false },
- { text: 'RegExp', type: 'obj', p5: false },
- { text: 'String', type: 'obj', p5: false },
- { text: 'Promise', type: 'obj', p5: false },
- { text: 'Set', type: 'obj', p5: false },
- { text: 'Map', type: 'obj', p5: false },
- { text: 'Symbol', type: 'obj', p5: false },
- { text: 'WeakMap', type: 'obj', p5: false },
- { text: 'WeakSet', type: 'obj', p5: false },
- { text: 'ArrayBuffer', type: 'obj', p5: false },
- { text: 'DataView', type: 'obj', p5: false },
- { text: 'Int32Array', type: 'obj', p5: false },
- { text: 'Uint32Array', type: 'obj', p5: false },
- { text: 'Float32Array', type: 'obj', p5: false },
- { text: 'window', type: 'obj', p5: false },
- { text: 'document', type: 'obj', p5: false },
- { text: 'navigator', type: 'obj', p5: false },
- { text: 'console', type: 'obj', p5: 'console' },
- { text: 'localStorage', type: 'obj', p5: false },
- { text: 'sessionStorage', type: 'obj', p5: false },
- { text: 'history', type: 'obj', p5: false },
- { text: 'location', type: 'obj', p5: false }
-];
+exports.p5Hinter = [{"label":"describe","type":"method","kindLabel":"fun","params":[{"p":"text","o":false},{"p":"display","o":true}],"preview":"describe(text, [display])","p5DocPath":"describe"},{"label":"describeElement","type":"method","kindLabel":"fun","params":[{"p":"name","o":false},{"p":"text","o":false},{"p":"display","o":true}],"preview":"describeElement(name, text, [display])","p5DocPath":"describeElement"},{"label":"textOutput","type":"method","kindLabel":"fun","params":[{"p":"display","o":true}],"preview":"textOutput([display])","p5DocPath":"textOutput"},{"label":"gridOutput","type":"method","kindLabel":"fun","params":[{"p":"display","o":true}],"preview":"gridOutput([display])","p5DocPath":"gridOutput"},{"label":"alpha","type":"method","kindLabel":"fun","params":[{"p":"color","o":false}],"preview":"alpha(color)","p5DocPath":"alpha"},{"label":"blue","type":"method","kindLabel":"fun","params":[{"p":"color","o":false}],"preview":"blue(color)","p5DocPath":"blue"},{"label":"brightness","type":"method","kindLabel":"fun","params":[{"p":"color","o":false}],"preview":"brightness(color)","p5DocPath":"brightness"},{"label":"color","type":"method","kindLabel":"fun","preview":"color()","p5DocPath":"color"},{"label":"green","type":"method","kindLabel":"fun","params":[{"p":"color","o":false}],"preview":"green(color)","p5DocPath":"green"},{"label":"hue","type":"method","kindLabel":"fun","params":[{"p":"color","o":false}],"preview":"hue(color)","p5DocPath":"hue"},{"label":"lerpColor","type":"method","kindLabel":"fun","params":[{"p":"c1","o":false},{"p":"c2","o":false},{"p":"amt","o":false}],"preview":"lerpColor(c1, c2, amt)","p5DocPath":"lerpColor"},{"label":"paletteLerp","type":"method","kindLabel":"fun","params":[{"p":"colors_stops","o":false},{"p":"amt","o":false}],"preview":"paletteLerp(colors_stops, amt)","p5DocPath":"paletteLerp"},{"label":"lightness","type":"method","kindLabel":"fun","params":[{"p":"color","o":false}],"preview":"lightness(color)","p5DocPath":"lightness"},{"label":"red","type":"method","kindLabel":"fun","params":[{"p":"color","o":false}],"preview":"red(color)","p5DocPath":"red"},{"label":"saturation","type":"method","kindLabel":"fun","params":[{"p":"color","o":false}],"preview":"saturation(color)","p5DocPath":"saturation"},{"label":"beginClip","type":"method","kindLabel":"fun","params":[{"p":"options","o":true}],"preview":"beginClip([options])","p5DocPath":"beginClip"},{"label":"endClip","type":"method","kindLabel":"fun","preview":"endClip()","p5DocPath":"endClip"},{"label":"clip","type":"method","kindLabel":"fun","params":[{"p":"callback","o":false},{"p":"options","o":true}],"preview":"clip(callback, [options])","p5DocPath":"clip"},{"label":"background","type":"method","kindLabel":"fun","preview":"background()","p5DocPath":"background"},{"label":"clear","type":"method","kindLabel":"fun","params":[{"p":"r","o":true},{"p":"g","o":true},{"p":"b","o":true},{"p":"a","o":true}],"preview":"clear([r], [g], [b], [a])","p5DocPath":"clear"},{"label":"colorMode","type":"method","kindLabel":"fun","preview":"colorMode()","p5DocPath":"colorMode"},{"label":"fill","type":"method","kindLabel":"fun","preview":"fill()","p5DocPath":"fill"},{"label":"noFill","type":"method","kindLabel":"fun","preview":"noFill()","p5DocPath":"noFill"},{"label":"noStroke","type":"method","kindLabel":"fun","preview":"noStroke()","p5DocPath":"noStroke"},{"label":"stroke","type":"method","kindLabel":"fun","preview":"stroke()","p5DocPath":"stroke"},{"label":"erase","type":"method","kindLabel":"fun","params":[{"p":"strengthFill","o":true},{"p":"strengthStroke","o":true}],"preview":"erase([strengthFill], [strengthStroke])","p5DocPath":"erase"},{"label":"noErase","type":"method","kindLabel":"fun","preview":"noErase()","p5DocPath":"noErase"},{"label":"arc","type":"method","kindLabel":"fun","params":[{"p":"x","o":false},{"p":"y","o":false},{"p":"w","o":false},{"p":"h","o":false},{"p":"start","o":false},{"p":"stop","o":false},{"p":"mode","o":true},{"p":"detail","o":true}],"preview":"arc(x, y, w, h, start, stop, [mode], [detail])","p5DocPath":"arc"},{"label":"ellipse","type":"method","kindLabel":"fun","preview":"ellipse()","p5DocPath":"ellipse"},{"label":"circle","type":"method","kindLabel":"fun","params":[{"p":"x","o":false},{"p":"y","o":false},{"p":"d","o":false}],"preview":"circle(x, y, d)","p5DocPath":"circle"},{"label":"line","type":"method","kindLabel":"fun","preview":"line()","p5DocPath":"line"},{"label":"point","type":"method","kindLabel":"fun","preview":"point()","p5DocPath":"point"},{"label":"quad","type":"method","kindLabel":"fun","preview":"quad()","p5DocPath":"quad"},{"label":"rect","type":"method","kindLabel":"fun","preview":"rect()","p5DocPath":"rect"},{"label":"square","type":"method","kindLabel":"fun","params":[{"p":"x","o":false},{"p":"y","o":false},{"p":"s","o":false},{"p":"tl","o":true},{"p":"tr","o":true},{"p":"br","o":true},{"p":"bl","o":true}],"preview":"square(x, y, s, [tl], [tr], [br], [bl])","p5DocPath":"square"},{"label":"triangle","type":"method","kindLabel":"fun","params":[{"p":"x1","o":false},{"p":"y1","o":false},{"p":"x2","o":false},{"p":"y2","o":false},{"p":"x3","o":false},{"p":"y3","o":false}],"preview":"triangle(x1, y1, x2, y2, x3, y3)","p5DocPath":"triangle"},{"label":"ellipseMode","type":"method","kindLabel":"fun","params":[{"p":"mode","o":false}],"preview":"ellipseMode(mode)","p5DocPath":"ellipseMode"},{"label":"noSmooth","type":"method","kindLabel":"fun","preview":"noSmooth()","p5DocPath":"noSmooth"},{"label":"rectMode","type":"method","kindLabel":"fun","params":[{"p":"mode","o":false}],"preview":"rectMode(mode)","p5DocPath":"rectMode"},{"label":"smooth","type":"method","kindLabel":"fun","preview":"smooth()","p5DocPath":"smooth"},{"label":"strokeCap","type":"method","kindLabel":"fun","params":[{"p":"cap","o":false}],"preview":"strokeCap(cap)","p5DocPath":"strokeCap"},{"label":"strokeJoin","type":"method","kindLabel":"fun","params":[{"p":"join","o":false}],"preview":"strokeJoin(join)","p5DocPath":"strokeJoin"},{"label":"strokeWeight","type":"method","kindLabel":"fun","params":[{"p":"weight","o":false}],"preview":"strokeWeight(weight)","p5DocPath":"strokeWeight"},{"label":"bezier","type":"method","kindLabel":"fun","preview":"bezier()","p5DocPath":"bezier"},{"label":"bezierDetail","type":"method","kindLabel":"fun","params":[{"p":"detail","o":false}],"preview":"bezierDetail(detail)","p5DocPath":"bezierDetail"},{"label":"bezierPoint","type":"method","kindLabel":"fun","params":[{"p":"a","o":false},{"p":"b","o":false},{"p":"c","o":false},{"p":"d","o":false},{"p":"t","o":false}],"preview":"bezierPoint(a, b, c, d, t)","p5DocPath":"bezierPoint"},{"label":"bezierTangent","type":"method","kindLabel":"fun","params":[{"p":"a","o":false},{"p":"b","o":false},{"p":"c","o":false},{"p":"d","o":false},{"p":"t","o":false}],"preview":"bezierTangent(a, b, c, d, t)","p5DocPath":"bezierTangent"},{"label":"curve","type":"method","kindLabel":"fun","preview":"curve()","p5DocPath":"curve"},{"label":"curveDetail","type":"method","kindLabel":"fun","params":[{"p":"resolution","o":false}],"preview":"curveDetail(resolution)","p5DocPath":"curveDetail"},{"label":"curveTightness","type":"method","kindLabel":"fun","params":[{"p":"amount","o":false}],"preview":"curveTightness(amount)","p5DocPath":"curveTightness"},{"label":"curvePoint","type":"method","kindLabel":"fun","params":[{"p":"a","o":false},{"p":"b","o":false},{"p":"c","o":false},{"p":"d","o":false},{"p":"t","o":false}],"preview":"curvePoint(a, b, c, d, t)","p5DocPath":"curvePoint"},{"label":"curveTangent","type":"method","kindLabel":"fun","params":[{"p":"a","o":false},{"p":"b","o":false},{"p":"c","o":false},{"p":"d","o":false},{"p":"t","o":false}],"preview":"curveTangent(a, b, c, d, t)","p5DocPath":"curveTangent"},{"label":"beginContour","type":"method","kindLabel":"fun","preview":"beginContour()","p5DocPath":"beginContour"},{"label":"beginShape","type":"method","kindLabel":"fun","params":[{"p":"kind","o":true}],"preview":"beginShape([kind])","p5DocPath":"beginShape"},{"label":"bezierVertex","type":"method","kindLabel":"fun","preview":"bezierVertex()","p5DocPath":"bezierVertex"},{"label":"curveVertex","type":"method","kindLabel":"fun","preview":"curveVertex()","p5DocPath":"curveVertex"},{"label":"endContour","type":"method","kindLabel":"fun","preview":"endContour()","p5DocPath":"endContour"},{"label":"endShape","type":"method","kindLabel":"fun","params":[{"p":"mode","o":true},{"p":"count","o":true}],"preview":"endShape([mode], [count])","p5DocPath":"endShape"},{"label":"quadraticVertex","type":"method","kindLabel":"fun","preview":"quadraticVertex()","p5DocPath":"quadraticVertex"},{"label":"vertex","type":"method","kindLabel":"fun","preview":"vertex()","p5DocPath":"vertex"},{"label":"normal","type":"method","kindLabel":"fun","preview":"normal()","p5DocPath":"normal"},{"label":"VERSION","type":"constant","kindLabel":"const","params":[],"preview":"VERSION","p5DocPath":"VERSION"},{"label":"P2D","type":"constant","kindLabel":"const","params":[],"preview":"P2D","p5DocPath":"P2D"},{"label":"WEBGL","type":"constant","kindLabel":"const","params":[],"preview":"WEBGL","p5DocPath":"WEBGL"},{"label":"WEBGL2","type":"constant","kindLabel":"const","params":[],"preview":"WEBGL2","p5DocPath":"WEBGL2"},{"label":"ARROW","type":"constant","kindLabel":"const","params":[],"preview":"ARROW","p5DocPath":"ARROW"},{"label":"CROSS","type":"constant","kindLabel":"const","params":[],"preview":"CROSS","p5DocPath":"CROSS"},{"label":"HAND","type":"constant","kindLabel":"const","params":[],"preview":"HAND","p5DocPath":"HAND"},{"label":"MOVE","type":"constant","kindLabel":"const","params":[],"preview":"MOVE","p5DocPath":"MOVE"},{"label":"TEXT","type":"constant","kindLabel":"const","params":[],"preview":"TEXT","p5DocPath":"TEXT"},{"label":"WAIT","type":"constant","kindLabel":"const","params":[],"preview":"WAIT","p5DocPath":"WAIT"},{"label":"HALF_PI","type":"constant","kindLabel":"const","params":[],"preview":"HALF_PI","p5DocPath":"HALF_PI"},{"label":"PI","type":"constant","kindLabel":"const","params":[],"preview":"PI","p5DocPath":"PI"},{"label":"QUARTER_PI","type":"constant","kindLabel":"const","params":[],"preview":"QUARTER_PI","p5DocPath":"QUARTER_PI"},{"label":"TAU","type":"constant","kindLabel":"const","params":[],"preview":"TAU","p5DocPath":"TAU"},{"label":"TWO_PI","type":"constant","kindLabel":"const","params":[],"preview":"TWO_PI","p5DocPath":"TWO_PI"},{"label":"DEGREES","type":"constant","kindLabel":"const","params":[],"preview":"DEGREES","p5DocPath":"DEGREES"},{"label":"RADIANS","type":"constant","kindLabel":"const","params":[],"preview":"RADIANS","p5DocPath":"RADIANS"},{"label":"CORNER","type":"constant","kindLabel":"const","params":[],"preview":"CORNER","p5DocPath":"CORNER"},{"label":"CORNERS","type":"constant","kindLabel":"const","params":[],"preview":"CORNERS","p5DocPath":"CORNERS"},{"label":"RADIUS","type":"constant","kindLabel":"const","params":[],"preview":"RADIUS","p5DocPath":"RADIUS"},{"label":"RIGHT","type":"constant","kindLabel":"const","params":[],"preview":"RIGHT","p5DocPath":"RIGHT"},{"label":"LEFT","type":"constant","kindLabel":"const","params":[],"preview":"LEFT","p5DocPath":"LEFT"},{"label":"CENTER","type":"constant","kindLabel":"const","params":[],"preview":"CENTER","p5DocPath":"CENTER"},{"label":"TOP","type":"constant","kindLabel":"const","params":[],"preview":"TOP","p5DocPath":"TOP"},{"label":"BOTTOM","type":"constant","kindLabel":"const","params":[],"preview":"BOTTOM","p5DocPath":"BOTTOM"},{"label":"BASELINE","type":"constant","kindLabel":"const","params":[],"preview":"BASELINE","p5DocPath":"BASELINE"},{"label":"POINTS","type":"constant","kindLabel":"const","params":[],"preview":"POINTS","p5DocPath":"POINTS"},{"label":"LINES","type":"constant","kindLabel":"const","params":[],"preview":"LINES","p5DocPath":"LINES"},{"label":"LINE_STRIP","type":"constant","kindLabel":"const","params":[],"preview":"LINE_STRIP","p5DocPath":"LINE_STRIP"},{"label":"LINE_LOOP","type":"constant","kindLabel":"const","params":[],"preview":"LINE_LOOP","p5DocPath":"LINE_LOOP"},{"label":"TRIANGLES","type":"constant","kindLabel":"const","params":[],"preview":"TRIANGLES","p5DocPath":"TRIANGLES"},{"label":"TRIANGLE_FAN","type":"constant","kindLabel":"const","params":[],"preview":"TRIANGLE_FAN","p5DocPath":"TRIANGLE_FAN"},{"label":"TRIANGLE_STRIP","type":"constant","kindLabel":"const","params":[],"preview":"TRIANGLE_STRIP","p5DocPath":"TRIANGLE_STRIP"},{"label":"QUADS","type":"constant","kindLabel":"const","params":[],"preview":"QUADS","p5DocPath":"QUADS"},{"label":"QUAD_STRIP","type":"constant","kindLabel":"const","params":[],"preview":"QUAD_STRIP","p5DocPath":"QUAD_STRIP"},{"label":"TESS","type":"constant","kindLabel":"const","params":[],"preview":"TESS","p5DocPath":"TESS"},{"label":"CLOSE","type":"constant","kindLabel":"const","params":[],"preview":"CLOSE","p5DocPath":"CLOSE"},{"label":"OPEN","type":"constant","kindLabel":"const","params":[],"preview":"OPEN","p5DocPath":"OPEN"},{"label":"CHORD","type":"constant","kindLabel":"const","params":[],"preview":"CHORD","p5DocPath":"CHORD"},{"label":"PIE","type":"constant","kindLabel":"const","params":[],"preview":"PIE","p5DocPath":"PIE"},{"label":"PROJECT","type":"constant","kindLabel":"const","params":[],"preview":"PROJECT","p5DocPath":"PROJECT"},{"label":"SQUARE","type":"constant","kindLabel":"const","params":[],"preview":"SQUARE","p5DocPath":"SQUARE"},{"label":"ROUND","type":"constant","kindLabel":"const","params":[],"preview":"ROUND","p5DocPath":"ROUND"},{"label":"BEVEL","type":"constant","kindLabel":"const","params":[],"preview":"BEVEL","p5DocPath":"BEVEL"},{"label":"MITER","type":"constant","kindLabel":"const","params":[],"preview":"MITER","p5DocPath":"MITER"},{"label":"RGB","type":"constant","kindLabel":"const","params":[],"preview":"RGB","p5DocPath":"RGB"},{"label":"HSB","type":"constant","kindLabel":"const","params":[],"preview":"HSB","p5DocPath":"HSB"},{"label":"HSL","type":"constant","kindLabel":"const","params":[],"preview":"HSL","p5DocPath":"HSL"},{"label":"AUTO","type":"constant","kindLabel":"const","params":[],"preview":"AUTO","p5DocPath":"AUTO"},{"label":"ALT","type":"constant","kindLabel":"const","params":[],"preview":"ALT","p5DocPath":"ALT"},{"label":"BACKSPACE","type":"constant","kindLabel":"const","params":[],"preview":"BACKSPACE","p5DocPath":"BACKSPACE"},{"label":"CONTROL","type":"constant","kindLabel":"const","params":[],"preview":"CONTROL","p5DocPath":"CONTROL"},{"label":"DELETE","type":"constant","kindLabel":"const","params":[],"preview":"DELETE","p5DocPath":"DELETE"},{"label":"DOWN_ARROW","type":"constant","kindLabel":"const","params":[],"preview":"DOWN_ARROW","p5DocPath":"DOWN_ARROW"},{"label":"ENTER","type":"constant","kindLabel":"const","params":[],"preview":"ENTER","p5DocPath":"ENTER"},{"label":"ESCAPE","type":"constant","kindLabel":"const","params":[],"preview":"ESCAPE","p5DocPath":"ESCAPE"},{"label":"LEFT_ARROW","type":"constant","kindLabel":"const","params":[],"preview":"LEFT_ARROW","p5DocPath":"LEFT_ARROW"},{"label":"OPTION","type":"constant","kindLabel":"const","params":[],"preview":"OPTION","p5DocPath":"OPTION"},{"label":"RETURN","type":"constant","kindLabel":"const","params":[],"preview":"RETURN","p5DocPath":"RETURN"},{"label":"RIGHT_ARROW","type":"constant","kindLabel":"const","params":[],"preview":"RIGHT_ARROW","p5DocPath":"RIGHT_ARROW"},{"label":"SHIFT","type":"constant","kindLabel":"const","params":[],"preview":"SHIFT","p5DocPath":"SHIFT"},{"label":"TAB","type":"constant","kindLabel":"const","params":[],"preview":"TAB","p5DocPath":"TAB"},{"label":"UP_ARROW","type":"constant","kindLabel":"const","params":[],"preview":"UP_ARROW","p5DocPath":"UP_ARROW"},{"label":"BLEND","type":"constant","kindLabel":"const","params":[],"preview":"BLEND","p5DocPath":"BLEND"},{"label":"REMOVE","type":"constant","kindLabel":"const","params":[],"preview":"REMOVE","p5DocPath":"REMOVE"},{"label":"ADD","type":"constant","kindLabel":"const","params":[],"preview":"ADD","p5DocPath":"ADD"},{"label":"DARKEST","type":"constant","kindLabel":"const","params":[],"preview":"DARKEST","p5DocPath":"DARKEST"},{"label":"LIGHTEST","type":"constant","kindLabel":"const","params":[],"preview":"LIGHTEST","p5DocPath":"LIGHTEST"},{"label":"DIFFERENCE","type":"constant","kindLabel":"const","params":[],"preview":"DIFFERENCE","p5DocPath":"DIFFERENCE"},{"label":"SUBTRACT","type":"constant","kindLabel":"const","params":[],"preview":"SUBTRACT","p5DocPath":"SUBTRACT"},{"label":"EXCLUSION","type":"constant","kindLabel":"const","params":[],"preview":"EXCLUSION","p5DocPath":"EXCLUSION"},{"label":"MULTIPLY","type":"constant","kindLabel":"const","params":[],"preview":"MULTIPLY","p5DocPath":"MULTIPLY"},{"label":"SCREEN","type":"constant","kindLabel":"const","params":[],"preview":"SCREEN","p5DocPath":"SCREEN"},{"label":"REPLACE","type":"constant","kindLabel":"const","params":[],"preview":"REPLACE","p5DocPath":"REPLACE"},{"label":"OVERLAY","type":"constant","kindLabel":"const","params":[],"preview":"OVERLAY","p5DocPath":"OVERLAY"},{"label":"HARD_LIGHT","type":"constant","kindLabel":"const","params":[],"preview":"HARD_LIGHT","p5DocPath":"HARD_LIGHT"},{"label":"SOFT_LIGHT","type":"constant","kindLabel":"const","params":[],"preview":"SOFT_LIGHT","p5DocPath":"SOFT_LIGHT"},{"label":"DODGE","type":"constant","kindLabel":"const","params":[],"preview":"DODGE","p5DocPath":"DODGE"},{"label":"BURN","type":"constant","kindLabel":"const","params":[],"preview":"BURN","p5DocPath":"BURN"},{"label":"THRESHOLD","type":"constant","kindLabel":"const","params":[],"preview":"THRESHOLD","p5DocPath":"THRESHOLD"},{"label":"GRAY","type":"constant","kindLabel":"const","params":[],"preview":"GRAY","p5DocPath":"GRAY"},{"label":"OPAQUE","type":"constant","kindLabel":"const","params":[],"preview":"OPAQUE","p5DocPath":"OPAQUE"},{"label":"INVERT","type":"constant","kindLabel":"const","params":[],"preview":"INVERT","p5DocPath":"INVERT"},{"label":"POSTERIZE","type":"constant","kindLabel":"const","params":[],"preview":"POSTERIZE","p5DocPath":"POSTERIZE"},{"label":"DILATE","type":"constant","kindLabel":"const","params":[],"preview":"DILATE","p5DocPath":"DILATE"},{"label":"ERODE","type":"constant","kindLabel":"const","params":[],"preview":"ERODE","p5DocPath":"ERODE"},{"label":"BLUR","type":"constant","kindLabel":"const","params":[],"preview":"BLUR","p5DocPath":"BLUR"},{"label":"NORMAL","type":"constant","kindLabel":"const","params":[],"preview":"NORMAL","p5DocPath":"NORMAL"},{"label":"ITALIC","type":"constant","kindLabel":"const","params":[],"preview":"ITALIC","p5DocPath":"ITALIC"},{"label":"BOLD","type":"constant","kindLabel":"const","params":[],"preview":"BOLD","p5DocPath":"BOLD"},{"label":"BOLDITALIC","type":"constant","kindLabel":"const","params":[],"preview":"BOLDITALIC","p5DocPath":"BOLDITALIC"},{"label":"CHAR","type":"constant","kindLabel":"const","params":[],"preview":"CHAR","p5DocPath":"CHAR"},{"label":"WORD","type":"constant","kindLabel":"const","params":[],"preview":"WORD","p5DocPath":"WORD"},{"label":"LINEAR","type":"constant","kindLabel":"const","params":[],"preview":"LINEAR","p5DocPath":"LINEAR"},{"label":"QUADRATIC","type":"constant","kindLabel":"const","params":[],"preview":"QUADRATIC","p5DocPath":"QUADRATIC"},{"label":"BEZIER","type":"constant","kindLabel":"const","params":[],"preview":"BEZIER","p5DocPath":"BEZIER"},{"label":"CURVE","type":"constant","kindLabel":"const","params":[],"preview":"CURVE","p5DocPath":"CURVE"},{"label":"STROKE","type":"constant","kindLabel":"const","params":[],"preview":"STROKE","p5DocPath":"STROKE"},{"label":"FILL","type":"constant","kindLabel":"const","params":[],"preview":"FILL","p5DocPath":"FILL"},{"label":"TEXTURE","type":"constant","kindLabel":"const","params":[],"preview":"TEXTURE","p5DocPath":"TEXTURE"},{"label":"IMMEDIATE","type":"constant","kindLabel":"const","params":[],"preview":"IMMEDIATE","p5DocPath":"IMMEDIATE"},{"label":"IMAGE","type":"constant","kindLabel":"const","params":[],"preview":"IMAGE","p5DocPath":"IMAGE"},{"label":"NEAREST","type":"constant","kindLabel":"const","params":[],"preview":"NEAREST","p5DocPath":"NEAREST"},{"label":"REPEAT","type":"constant","kindLabel":"const","params":[],"preview":"REPEAT","p5DocPath":"REPEAT"},{"label":"CLAMP","type":"constant","kindLabel":"const","params":[],"preview":"CLAMP","p5DocPath":"CLAMP"},{"label":"MIRROR","type":"constant","kindLabel":"const","params":[],"preview":"MIRROR","p5DocPath":"MIRROR"},{"label":"FLAT","type":"constant","kindLabel":"const","params":[],"preview":"FLAT","p5DocPath":"FLAT"},{"label":"SMOOTH","type":"constant","kindLabel":"const","params":[],"preview":"SMOOTH","p5DocPath":"SMOOTH"},{"label":"LANDSCAPE","type":"constant","kindLabel":"const","params":[],"preview":"LANDSCAPE","p5DocPath":"LANDSCAPE"},{"label":"PORTRAIT","type":"constant","kindLabel":"const","params":[],"preview":"PORTRAIT","p5DocPath":"PORTRAIT"},{"label":"GRID","type":"constant","kindLabel":"const","params":[],"preview":"GRID","p5DocPath":"GRID"},{"label":"AXES","type":"constant","kindLabel":"const","params":[],"preview":"AXES","p5DocPath":"AXES"},{"label":"LABEL","type":"constant","kindLabel":"const","params":[],"preview":"LABEL","p5DocPath":"LABEL"},{"label":"FALLBACK","type":"constant","kindLabel":"const","params":[],"preview":"FALLBACK","p5DocPath":"FALLBACK"},{"label":"CONTAIN","type":"constant","kindLabel":"const","params":[],"preview":"CONTAIN","p5DocPath":"CONTAIN"},{"label":"COVER","type":"constant","kindLabel":"const","params":[],"preview":"COVER","p5DocPath":"COVER"},{"label":"UNSIGNED_BYTE","type":"constant","kindLabel":"const","params":[],"preview":"UNSIGNED_BYTE","p5DocPath":"UNSIGNED_BYTE"},{"label":"UNSIGNED_INT","type":"constant","kindLabel":"const","params":[],"preview":"UNSIGNED_INT","p5DocPath":"UNSIGNED_INT"},{"label":"FLOAT","type":"constant","kindLabel":"const","params":[],"preview":"FLOAT","p5DocPath":"FLOAT"},{"label":"HALF_FLOAT","type":"constant","kindLabel":"const","params":[],"preview":"HALF_FLOAT","p5DocPath":"HALF_FLOAT"},{"label":"RGBA","type":"constant","kindLabel":"const","params":[],"preview":"RGBA","p5DocPath":"RGBA"},{"label":"print","type":"method","kindLabel":"fun","params":[{"p":"contents","o":false}],"preview":"print(contents)","p5DocPath":"print"},{"label":"frameCount","type":"variable","kindLabel":"var","params":[],"preview":"frameCount","p5DocPath":"frameCount"},{"label":"deltaTime","type":"variable","kindLabel":"var","params":[],"preview":"deltaTime","p5DocPath":"deltaTime"},{"label":"focused","type":"variable","kindLabel":"var","params":[],"preview":"focused","p5DocPath":"focused"},{"label":"cursor","type":"method","kindLabel":"fun","params":[{"p":"type","o":false},{"p":"x","o":true},{"p":"y","o":true}],"preview":"cursor(type, [x], [y])","p5DocPath":"cursor"},{"label":"frameRate","type":"method","kindLabel":"fun","preview":"frameRate()","p5DocPath":"frameRate"},{"label":"getTargetFrameRate","type":"method","kindLabel":"fun","preview":"getTargetFrameRate()","p5DocPath":"getTargetFrameRate"},{"label":"noCursor","type":"method","kindLabel":"fun","preview":"noCursor()","p5DocPath":"noCursor"},{"label":"webglVersion","type":"variable","kindLabel":"var","params":[],"preview":"webglVersion","p5DocPath":"webglVersion"},{"label":"displayWidth","type":"variable","kindLabel":"var","params":[],"preview":"displayWidth","p5DocPath":"displayWidth"},{"label":"displayHeight","type":"variable","kindLabel":"var","params":[],"preview":"displayHeight","p5DocPath":"displayHeight"},{"label":"windowWidth","type":"variable","kindLabel":"var","params":[],"preview":"windowWidth","p5DocPath":"windowWidth"},{"label":"windowHeight","type":"variable","kindLabel":"var","params":[],"preview":"windowHeight","p5DocPath":"windowHeight"},{"label":"windowResized","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"windowResized([event])","p5DocPath":"windowResized"},{"label":"width","type":"variable","kindLabel":"var","params":[],"preview":"width","p5DocPath":"width"},{"label":"height","type":"variable","kindLabel":"var","params":[],"preview":"height","p5DocPath":"height"},{"label":"fullscreen","type":"method","kindLabel":"fun","params":[{"p":"val","o":true}],"preview":"fullscreen([val])","p5DocPath":"fullscreen"},{"label":"pixelDensity","type":"method","kindLabel":"fun","preview":"pixelDensity()","p5DocPath":"pixelDensity"},{"label":"displayDensity","type":"method","kindLabel":"fun","preview":"displayDensity()","p5DocPath":"displayDensity"},{"label":"getURL","type":"method","kindLabel":"fun","preview":"getURL()","p5DocPath":"getURL"},{"label":"getURLPath","type":"method","kindLabel":"fun","preview":"getURLPath()","p5DocPath":"getURLPath"},{"label":"getURLParams","type":"method","kindLabel":"fun","preview":"getURLParams()","p5DocPath":"getURLParams"},{"label":"preload","type":"method","kindLabel":"fun","preview":"preload()","p5DocPath":"preload"},{"label":"setup","type":"method","kindLabel":"fun","preview":"setup()","p5DocPath":"setup"},{"label":"draw","type":"method","kindLabel":"fun","preview":"draw()","p5DocPath":"draw"},{"label":"remove","type":"method","kindLabel":"fun","preview":"remove()","p5DocPath":"remove"},{"label":"disableFriendlyErrors","type":"variable","kindLabel":"var","params":[],"preview":"disableFriendlyErrors","p5DocPath":"disableFriendlyErrors"},{"label":"createCanvas","type":"method","kindLabel":"fun","preview":"createCanvas()","p5DocPath":"createCanvas"},{"label":"resizeCanvas","type":"method","kindLabel":"fun","params":[{"p":"width","o":false},{"p":"height","o":false},{"p":"noRedraw","o":true}],"preview":"resizeCanvas(width, height, [noRedraw])","p5DocPath":"resizeCanvas"},{"label":"noCanvas","type":"method","kindLabel":"fun","preview":"noCanvas()","p5DocPath":"noCanvas"},{"label":"createGraphics","type":"method","kindLabel":"fun","preview":"createGraphics()","p5DocPath":"createGraphics"},{"label":"createFramebuffer","type":"method","kindLabel":"fun","params":[{"p":"options","o":true}],"preview":"createFramebuffer([options])","p5DocPath":"createFramebuffer"},{"label":"clearDepth","type":"method","kindLabel":"fun","params":[{"p":"depth","o":true}],"preview":"clearDepth([depth])","p5DocPath":"clearDepth"},{"label":"blendMode","type":"method","kindLabel":"fun","params":[{"p":"mode","o":false}],"preview":"blendMode(mode)","p5DocPath":"blendMode"},{"label":"drawingContext","type":"variable","kindLabel":"var","params":[],"preview":"drawingContext","p5DocPath":"drawingContext"},{"label":"noLoop","type":"method","kindLabel":"fun","preview":"noLoop()","p5DocPath":"noLoop"},{"label":"loop","type":"method","kindLabel":"fun","preview":"loop()","p5DocPath":"loop"},{"label":"isLooping","type":"method","kindLabel":"fun","preview":"isLooping()","p5DocPath":"isLooping"},{"label":"push","type":"method","kindLabel":"fun","preview":"push()","p5DocPath":"push"},{"label":"pop","type":"method","kindLabel":"fun","preview":"pop()","p5DocPath":"pop"},{"label":"redraw","type":"method","kindLabel":"fun","params":[{"p":"n","o":true}],"preview":"redraw([n])","p5DocPath":"redraw"},{"label":"p5","type":"method","kindLabel":"fun","params":[{"p":"sketch","o":false},{"p":"node","o":false}],"preview":"p5(sketch, node)","p5DocPath":"p5"},{"label":"applyMatrix","type":"method","kindLabel":"fun","preview":"applyMatrix()","p5DocPath":"applyMatrix"},{"label":"resetMatrix","type":"method","kindLabel":"fun","preview":"resetMatrix()","p5DocPath":"resetMatrix"},{"label":"rotate","type":"method","kindLabel":"fun","params":[{"p":"angle","o":false},{"p":"axis","o":true}],"preview":"rotate(angle, [axis])","p5DocPath":"rotate"},{"label":"rotateX","type":"method","kindLabel":"fun","params":[{"p":"angle","o":false}],"preview":"rotateX(angle)","p5DocPath":"rotateX"},{"label":"rotateY","type":"method","kindLabel":"fun","params":[{"p":"angle","o":false}],"preview":"rotateY(angle)","p5DocPath":"rotateY"},{"label":"rotateZ","type":"method","kindLabel":"fun","params":[{"p":"angle","o":false}],"preview":"rotateZ(angle)","p5DocPath":"rotateZ"},{"label":"scale","type":"method","kindLabel":"fun","preview":"scale()","p5DocPath":"scale"},{"label":"shearX","type":"method","kindLabel":"fun","params":[{"p":"angle","o":false}],"preview":"shearX(angle)","p5DocPath":"shearX"},{"label":"shearY","type":"method","kindLabel":"fun","params":[{"p":"angle","o":false}],"preview":"shearY(angle)","p5DocPath":"shearY"},{"label":"translate","type":"method","kindLabel":"fun","preview":"translate()","p5DocPath":"translate"},{"label":"storeItem","type":"method","kindLabel":"fun","params":[{"p":"key","o":false},{"p":"value","o":false}],"preview":"storeItem(key, value)","p5DocPath":"storeItem"},{"label":"getItem","type":"method","kindLabel":"fun","params":[{"p":"key","o":false}],"preview":"getItem(key)","p5DocPath":"getItem"},{"label":"clearStorage","type":"method","kindLabel":"fun","preview":"clearStorage()","p5DocPath":"clearStorage"},{"label":"removeItem","type":"method","kindLabel":"fun","params":[{"p":"key","o":false}],"preview":"removeItem(key)","p5DocPath":"removeItem"},{"label":"createStringDict","type":"method","kindLabel":"fun","preview":"createStringDict()","p5DocPath":"createStringDict"},{"label":"createNumberDict","type":"method","kindLabel":"fun","preview":"createNumberDict()","p5DocPath":"createNumberDict"},{"label":"select","type":"method","kindLabel":"fun","params":[{"p":"selectors","o":false},{"p":"container","o":true}],"preview":"select(selectors, [container])","p5DocPath":"select"},{"label":"selectAll","type":"method","kindLabel":"fun","params":[{"p":"selectors","o":false},{"p":"container","o":true}],"preview":"selectAll(selectors, [container])","p5DocPath":"selectAll"},{"label":"removeElements","type":"method","kindLabel":"fun","preview":"removeElements()","p5DocPath":"removeElements"},{"label":"changed","type":"method","kindLabel":"fun","params":[{"p":"fxn","o":false}],"preview":"changed(fxn)","p5DocPath":"changed"},{"label":"input","type":"method","kindLabel":"fun","params":[{"p":"fxn","o":false}],"preview":"input(fxn)","p5DocPath":"input"},{"label":"createDiv","type":"method","kindLabel":"fun","params":[{"p":"html","o":true}],"preview":"createDiv([html])","p5DocPath":"createDiv"},{"label":"createP","type":"method","kindLabel":"fun","params":[{"p":"html","o":true}],"preview":"createP([html])","p5DocPath":"createP"},{"label":"createSpan","type":"method","kindLabel":"fun","params":[{"p":"html","o":true}],"preview":"createSpan([html])","p5DocPath":"createSpan"},{"label":"createImg","type":"method","kindLabel":"fun","preview":"createImg()","p5DocPath":"createImg"},{"label":"createA","type":"method","kindLabel":"fun","params":[{"p":"href","o":false},{"p":"html","o":false},{"p":"target","o":true}],"preview":"createA(href, html, [target])","p5DocPath":"createA"},{"label":"createSlider","type":"method","kindLabel":"fun","params":[{"p":"min","o":false},{"p":"max","o":false},{"p":"value","o":true},{"p":"step","o":true}],"preview":"createSlider(min, max, [value], [step])","p5DocPath":"createSlider"},{"label":"createButton","type":"method","kindLabel":"fun","params":[{"p":"label","o":false},{"p":"value","o":true}],"preview":"createButton(label, [value])","p5DocPath":"createButton"},{"label":"createCheckbox","type":"method","kindLabel":"fun","params":[{"p":"label","o":true},{"p":"value","o":true}],"preview":"createCheckbox([label], [value])","p5DocPath":"createCheckbox"},{"label":"createSelect","type":"method","kindLabel":"fun","preview":"createSelect()","p5DocPath":"createSelect"},{"label":"createRadio","type":"method","kindLabel":"fun","preview":"createRadio()","p5DocPath":"createRadio"},{"label":"createColorPicker","type":"method","kindLabel":"fun","params":[{"p":"value","o":true}],"preview":"createColorPicker([value])","p5DocPath":"createColorPicker"},{"label":"createInput","type":"method","kindLabel":"fun","preview":"createInput()","p5DocPath":"createInput"},{"label":"createFileInput","type":"method","kindLabel":"fun","params":[{"p":"callback","o":false},{"p":"multiple","o":true}],"preview":"createFileInput(callback, [multiple])","p5DocPath":"createFileInput"},{"label":"createVideo","type":"method","kindLabel":"fun","params":[{"p":"src","o":false},{"p":"callback","o":true}],"preview":"createVideo(src, [callback])","p5DocPath":"createVideo"},{"label":"createAudio","type":"method","kindLabel":"fun","params":[{"p":"src","o":true},{"p":"callback","o":true}],"preview":"createAudio([src], [callback])","p5DocPath":"createAudio"},{"label":"createCapture","type":"method","kindLabel":"fun","params":[{"p":"type","o":true},{"p":"flipped","o":true},{"p":"callback","o":true}],"preview":"createCapture([type], [flipped], [callback])","p5DocPath":"createCapture"},{"label":"createElement","type":"method","kindLabel":"fun","params":[{"p":"tag","o":false},{"p":"content","o":true}],"preview":"createElement(tag, [content])","p5DocPath":"createElement"},{"label":"deviceOrientation","type":"variable","kindLabel":"var","params":[],"preview":"deviceOrientation","p5DocPath":"deviceOrientation"},{"label":"accelerationX","type":"variable","kindLabel":"var","params":[],"preview":"accelerationX","p5DocPath":"accelerationX"},{"label":"accelerationY","type":"variable","kindLabel":"var","params":[],"preview":"accelerationY","p5DocPath":"accelerationY"},{"label":"accelerationZ","type":"variable","kindLabel":"var","params":[],"preview":"accelerationZ","p5DocPath":"accelerationZ"},{"label":"pAccelerationX","type":"variable","kindLabel":"var","params":[],"preview":"pAccelerationX","p5DocPath":"pAccelerationX"},{"label":"pAccelerationY","type":"variable","kindLabel":"var","params":[],"preview":"pAccelerationY","p5DocPath":"pAccelerationY"},{"label":"pAccelerationZ","type":"variable","kindLabel":"var","params":[],"preview":"pAccelerationZ","p5DocPath":"pAccelerationZ"},{"label":"rotationX","type":"variable","kindLabel":"var","params":[],"preview":"rotationX","p5DocPath":"rotationX"},{"label":"rotationY","type":"variable","kindLabel":"var","params":[],"preview":"rotationY","p5DocPath":"rotationY"},{"label":"rotationZ","type":"variable","kindLabel":"var","params":[],"preview":"rotationZ","p5DocPath":"rotationZ"},{"label":"pRotationX","type":"variable","kindLabel":"var","params":[],"preview":"pRotationX","p5DocPath":"pRotationX"},{"label":"pRotationY","type":"variable","kindLabel":"var","params":[],"preview":"pRotationY","p5DocPath":"pRotationY"},{"label":"pRotationZ","type":"variable","kindLabel":"var","params":[],"preview":"pRotationZ","p5DocPath":"pRotationZ"},{"label":"turnAxis","type":"variable","kindLabel":"var","params":[],"preview":"turnAxis","p5DocPath":"turnAxis"},{"label":"setMoveThreshold","type":"method","kindLabel":"fun","params":[{"p":"value","o":false}],"preview":"setMoveThreshold(value)","p5DocPath":"setMoveThreshold"},{"label":"setShakeThreshold","type":"method","kindLabel":"fun","params":[{"p":"value","o":false}],"preview":"setShakeThreshold(value)","p5DocPath":"setShakeThreshold"},{"label":"deviceMoved","type":"method","kindLabel":"fun","preview":"deviceMoved()","p5DocPath":"deviceMoved"},{"label":"deviceTurned","type":"method","kindLabel":"fun","preview":"deviceTurned()","p5DocPath":"deviceTurned"},{"label":"deviceShaken","type":"method","kindLabel":"fun","preview":"deviceShaken()","p5DocPath":"deviceShaken"},{"label":"keyIsPressed","type":"variable","kindLabel":"var","params":[],"preview":"keyIsPressed","p5DocPath":"keyIsPressed"},{"label":"key","type":"variable","kindLabel":"var","params":[],"preview":"key","p5DocPath":"key"},{"label":"keyCode","type":"variable","kindLabel":"var","params":[],"preview":"keyCode","p5DocPath":"keyCode"},{"label":"keyPressed","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"keyPressed([event])","p5DocPath":"keyPressed"},{"label":"keyReleased","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"keyReleased([event])","p5DocPath":"keyReleased"},{"label":"keyTyped","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"keyTyped([event])","p5DocPath":"keyTyped"},{"label":"keyIsDown","type":"method","kindLabel":"fun","params":[{"p":"code","o":false}],"preview":"keyIsDown(code)","p5DocPath":"keyIsDown"},{"label":"movedX","type":"variable","kindLabel":"var","params":[],"preview":"movedX","p5DocPath":"movedX"},{"label":"movedY","type":"variable","kindLabel":"var","params":[],"preview":"movedY","p5DocPath":"movedY"},{"label":"mouseX","type":"variable","kindLabel":"var","params":[],"preview":"mouseX","p5DocPath":"mouseX"},{"label":"mouseY","type":"variable","kindLabel":"var","params":[],"preview":"mouseY","p5DocPath":"mouseY"},{"label":"pmouseX","type":"variable","kindLabel":"var","params":[],"preview":"pmouseX","p5DocPath":"pmouseX"},{"label":"pmouseY","type":"variable","kindLabel":"var","params":[],"preview":"pmouseY","p5DocPath":"pmouseY"},{"label":"winMouseX","type":"variable","kindLabel":"var","params":[],"preview":"winMouseX","p5DocPath":"winMouseX"},{"label":"winMouseY","type":"variable","kindLabel":"var","params":[],"preview":"winMouseY","p5DocPath":"winMouseY"},{"label":"pwinMouseX","type":"variable","kindLabel":"var","params":[],"preview":"pwinMouseX","p5DocPath":"pwinMouseX"},{"label":"pwinMouseY","type":"variable","kindLabel":"var","params":[],"preview":"pwinMouseY","p5DocPath":"pwinMouseY"},{"label":"mouseButton","type":"variable","kindLabel":"var","params":[],"preview":"mouseButton","p5DocPath":"mouseButton"},{"label":"mouseIsPressed","type":"variable","kindLabel":"var","params":[],"preview":"mouseIsPressed","p5DocPath":"mouseIsPressed"},{"label":"mouseMoved","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"mouseMoved([event])","p5DocPath":"mouseMoved"},{"label":"mouseDragged","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"mouseDragged([event])","p5DocPath":"mouseDragged"},{"label":"mousePressed","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"mousePressed([event])","p5DocPath":"mousePressed"},{"label":"mouseReleased","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"mouseReleased([event])","p5DocPath":"mouseReleased"},{"label":"mouseClicked","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"mouseClicked([event])","p5DocPath":"mouseClicked"},{"label":"doubleClicked","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"doubleClicked([event])","p5DocPath":"doubleClicked"},{"label":"mouseWheel","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"mouseWheel([event])","p5DocPath":"mouseWheel"},{"label":"requestPointerLock","type":"method","kindLabel":"fun","preview":"requestPointerLock()","p5DocPath":"requestPointerLock"},{"label":"exitPointerLock","type":"method","kindLabel":"fun","preview":"exitPointerLock()","p5DocPath":"exitPointerLock"},{"label":"touches","type":"variable","kindLabel":"var","params":[],"preview":"touches","p5DocPath":"touches"},{"label":"touchStarted","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"touchStarted([event])","p5DocPath":"touchStarted"},{"label":"touchMoved","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"touchMoved([event])","p5DocPath":"touchMoved"},{"label":"touchEnded","type":"method","kindLabel":"fun","params":[{"p":"event","o":true}],"preview":"touchEnded([event])","p5DocPath":"touchEnded"},{"label":"createImage","type":"method","kindLabel":"fun","params":[{"p":"width","o":false},{"p":"height","o":false}],"preview":"createImage(width, height)","p5DocPath":"createImage"},{"label":"saveCanvas","type":"method","kindLabel":"fun","preview":"saveCanvas()","p5DocPath":"saveCanvas"},{"label":"saveFrames","type":"method","kindLabel":"fun","params":[{"p":"filename","o":false},{"p":"extension","o":false},{"p":"duration","o":false},{"p":"framerate","o":false},{"p":"callback","o":true}],"preview":"saveFrames(filename, extension, duration, framerate, [callback])","p5DocPath":"saveFrames"},{"label":"loadImage","type":"method","kindLabel":"fun","params":[{"p":"path","o":false},{"p":"successCallback","o":true},{"p":"failureCallback","o":true}],"preview":"loadImage(path, [successCallback], [failureCallback])","p5DocPath":"loadImage"},{"label":"saveGif","type":"method","kindLabel":"fun","params":[{"p":"filename","o":false},{"p":"duration","o":false},{"p":"options","o":true}],"preview":"saveGif(filename, duration, [options])","p5DocPath":"saveGif"},{"label":"image","type":"method","kindLabel":"fun","preview":"image()","p5DocPath":"image"},{"label":"tint","type":"method","kindLabel":"fun","preview":"tint()","p5DocPath":"tint"},{"label":"noTint","type":"method","kindLabel":"fun","preview":"noTint()","p5DocPath":"noTint"},{"label":"imageMode","type":"method","kindLabel":"fun","params":[{"p":"mode","o":false}],"preview":"imageMode(mode)","p5DocPath":"imageMode"},{"label":"pixels","type":"variable","kindLabel":"var","params":[],"preview":"pixels","p5DocPath":"pixels"},{"label":"blend","type":"method","kindLabel":"fun","preview":"blend()","p5DocPath":"blend"},{"label":"copy","type":"method","kindLabel":"fun","preview":"copy()","p5DocPath":"copy"},{"label":"filter","type":"method","kindLabel":"fun","preview":"filter()","p5DocPath":"filter"},{"label":"get","type":"method","kindLabel":"fun","preview":"get()","p5DocPath":"get"},{"label":"loadPixels","type":"method","kindLabel":"fun","preview":"loadPixels()","p5DocPath":"loadPixels"},{"label":"set","type":"method","kindLabel":"fun","params":[{"p":"x","o":false},{"p":"y","o":false},{"p":"c","o":false}],"preview":"set(x, y, c)","p5DocPath":"set"},{"label":"updatePixels","type":"method","kindLabel":"fun","params":[{"p":"x","o":true},{"p":"y","o":true},{"p":"w","o":true},{"p":"h","o":true}],"preview":"updatePixels([x], [y], [w], [h])","p5DocPath":"updatePixels"},{"label":"loadJSON","type":"method","kindLabel":"fun","params":[{"p":"path","o":false},{"p":"successCallback","o":true},{"p":"errorCallback","o":true}],"preview":"loadJSON(path, [successCallback], [errorCallback])","p5DocPath":"loadJSON"},{"label":"loadStrings","type":"method","kindLabel":"fun","params":[{"p":"path","o":false},{"p":"successCallback","o":true},{"p":"errorCallback","o":true}],"preview":"loadStrings(path, [successCallback], [errorCallback])","p5DocPath":"loadStrings"},{"label":"loadTable","type":"method","kindLabel":"fun","params":[{"p":"filename","o":false},{"p":"extension","o":true},{"p":"header","o":true},{"p":"callback","o":true},{"p":"errorCallback","o":true}],"preview":"loadTable(filename, [extension], [header], [callback], [errorCallback])","p5DocPath":"loadTable"},{"label":"loadXML","type":"method","kindLabel":"fun","params":[{"p":"path","o":false},{"p":"successCallback","o":true},{"p":"errorCallback","o":true}],"preview":"loadXML(path, [successCallback], [errorCallback])","p5DocPath":"loadXML"},{"label":"loadBytes","type":"method","kindLabel":"fun","params":[{"p":"file","o":false},{"p":"callback","o":true},{"p":"errorCallback","o":true}],"preview":"loadBytes(file, [callback], [errorCallback])","p5DocPath":"loadBytes"},{"label":"httpGet","type":"method","kindLabel":"fun","preview":"httpGet()","p5DocPath":"httpGet"},{"label":"httpPost","type":"method","kindLabel":"fun","preview":"httpPost()","p5DocPath":"httpPost"},{"label":"httpDo","type":"method","kindLabel":"fun","preview":"httpDo()","p5DocPath":"httpDo"},{"label":"createWriter","type":"method","kindLabel":"fun","params":[{"p":"name","o":false},{"p":"extension","o":true}],"preview":"createWriter(name, [extension])","p5DocPath":"createWriter"},{"label":"save","type":"method","kindLabel":"fun","params":[{"p":"objectOrFilename","o":true},{"p":"filename","o":true},{"p":"options","o":true}],"preview":"save([objectOrFilename], [filename], [options])","p5DocPath":"save"},{"label":"saveJSON","type":"method","kindLabel":"fun","params":[{"p":"json","o":false},{"p":"filename","o":false},{"p":"optimize","o":true}],"preview":"saveJSON(json, filename, [optimize])","p5DocPath":"saveJSON"},{"label":"saveStrings","type":"method","kindLabel":"fun","params":[{"p":"list","o":false},{"p":"filename","o":false},{"p":"extension","o":true},{"p":"isCRLF","o":true}],"preview":"saveStrings(list, filename, [extension], [isCRLF])","p5DocPath":"saveStrings"},{"label":"saveTable","type":"method","kindLabel":"fun","params":[{"p":"Table","o":false},{"p":"filename","o":false},{"p":"options","o":true}],"preview":"saveTable(Table, filename, [options])","p5DocPath":"saveTable"},{"label":"abs","type":"method","kindLabel":"fun","params":[{"p":"n","o":false}],"preview":"abs(n)","p5DocPath":"abs"},{"label":"ceil","type":"method","kindLabel":"fun","params":[{"p":"n","o":false}],"preview":"ceil(n)","p5DocPath":"ceil"},{"label":"constrain","type":"method","kindLabel":"fun","params":[{"p":"n","o":false},{"p":"low","o":false},{"p":"high","o":false}],"preview":"constrain(n, low, high)","p5DocPath":"constrain"},{"label":"dist","type":"method","kindLabel":"fun","preview":"dist()","p5DocPath":"dist"},{"label":"exp","type":"method","kindLabel":"fun","params":[{"p":"n","o":false}],"preview":"exp(n)","p5DocPath":"exp"},{"label":"floor","type":"method","kindLabel":"fun","params":[{"p":"n","o":false}],"preview":"floor(n)","p5DocPath":"floor"},{"label":"lerp","type":"method","kindLabel":"fun","params":[{"p":"start","o":false},{"p":"stop","o":false},{"p":"amt","o":false}],"preview":"lerp(start, stop, amt)","p5DocPath":"lerp"},{"label":"log","type":"method","kindLabel":"fun","params":[{"p":"n","o":false}],"preview":"log(n)","p5DocPath":"log"},{"label":"mag","type":"method","kindLabel":"fun","params":[{"p":"x","o":false},{"p":"y","o":false}],"preview":"mag(x, y)","p5DocPath":"mag"},{"label":"map","type":"method","kindLabel":"fun","params":[{"p":"value","o":false},{"p":"start1","o":false},{"p":"stop1","o":false},{"p":"start2","o":false},{"p":"stop2","o":false},{"p":"withinBounds","o":true}],"preview":"map(value, start1, stop1, start2, stop2, [withinBounds])","p5DocPath":"map"},{"label":"max","type":"method","kindLabel":"fun","preview":"max()","p5DocPath":"max"},{"label":"min","type":"method","kindLabel":"fun","preview":"min()","p5DocPath":"min"},{"label":"norm","type":"method","kindLabel":"fun","params":[{"p":"value","o":false},{"p":"start","o":false},{"p":"stop","o":false}],"preview":"norm(value, start, stop)","p5DocPath":"norm"},{"label":"pow","type":"method","kindLabel":"fun","params":[{"p":"n","o":false},{"p":"e","o":false}],"preview":"pow(n, e)","p5DocPath":"pow"},{"label":"round","type":"method","kindLabel":"fun","params":[{"p":"n","o":false},{"p":"decimals","o":true}],"preview":"round(n, [decimals])","p5DocPath":"round"},{"label":"sq","type":"method","kindLabel":"fun","params":[{"p":"n","o":false}],"preview":"sq(n)","p5DocPath":"sq"},{"label":"sqrt","type":"method","kindLabel":"fun","params":[{"p":"n","o":false}],"preview":"sqrt(n)","p5DocPath":"sqrt"},{"label":"fract","type":"method","kindLabel":"fun","params":[{"p":"n","o":false}],"preview":"fract(n)","p5DocPath":"fract"},{"label":"createVector","type":"method","kindLabel":"fun","params":[{"p":"x","o":true},{"p":"y","o":true},{"p":"z","o":true}],"preview":"createVector([x], [y], [z])","p5DocPath":"createVector"},{"label":"noise","type":"method","kindLabel":"fun","params":[{"p":"x","o":false},{"p":"y","o":true},{"p":"z","o":true}],"preview":"noise(x, [y], [z])","p5DocPath":"noise"},{"label":"noiseDetail","type":"method","kindLabel":"fun","params":[{"p":"lod","o":false},{"p":"falloff","o":false}],"preview":"noiseDetail(lod, falloff)","p5DocPath":"noiseDetail"},{"label":"noiseSeed","type":"method","kindLabel":"fun","params":[{"p":"seed","o":false}],"preview":"noiseSeed(seed)","p5DocPath":"noiseSeed"},{"label":"randomSeed","type":"method","kindLabel":"fun","params":[{"p":"seed","o":false}],"preview":"randomSeed(seed)","p5DocPath":"randomSeed"},{"label":"random","type":"method","kindLabel":"fun","preview":"random()","p5DocPath":"random"},{"label":"randomGaussian","type":"method","kindLabel":"fun","params":[{"p":"mean","o":true},{"p":"sd","o":true}],"preview":"randomGaussian([mean], [sd])","p5DocPath":"randomGaussian"},{"label":"acos","type":"method","kindLabel":"fun","params":[{"p":"value","o":false}],"preview":"acos(value)","p5DocPath":"acos"},{"label":"asin","type":"method","kindLabel":"fun","params":[{"p":"value","o":false}],"preview":"asin(value)","p5DocPath":"asin"},{"label":"atan","type":"method","kindLabel":"fun","params":[{"p":"value","o":false}],"preview":"atan(value)","p5DocPath":"atan"},{"label":"atan2","type":"method","kindLabel":"fun","params":[{"p":"y","o":false},{"p":"x","o":false}],"preview":"atan2(y, x)","p5DocPath":"atan2"},{"label":"cos","type":"method","kindLabel":"fun","params":[{"p":"angle","o":false}],"preview":"cos(angle)","p5DocPath":"cos"},{"label":"sin","type":"method","kindLabel":"fun","params":[{"p":"angle","o":false}],"preview":"sin(angle)","p5DocPath":"sin"},{"label":"tan","type":"method","kindLabel":"fun","params":[{"p":"angle","o":false}],"preview":"tan(angle)","p5DocPath":"tan"},{"label":"degrees","type":"method","kindLabel":"fun","params":[{"p":"radians","o":false}],"preview":"degrees(radians)","p5DocPath":"degrees"},{"label":"radians","type":"method","kindLabel":"fun","params":[{"p":"degrees","o":false}],"preview":"radians(degrees)","p5DocPath":"radians"},{"label":"angleMode","type":"method","kindLabel":"fun","preview":"angleMode()","p5DocPath":"angleMode"},{"label":"textAlign","type":"method","kindLabel":"fun","preview":"textAlign()","p5DocPath":"textAlign"},{"label":"textLeading","type":"method","kindLabel":"fun","preview":"textLeading()","p5DocPath":"textLeading"},{"label":"textSize","type":"method","kindLabel":"fun","preview":"textSize()","p5DocPath":"textSize"},{"label":"textStyle","type":"method","kindLabel":"fun","preview":"textStyle()","p5DocPath":"textStyle"},{"label":"textWidth","type":"method","kindLabel":"fun","params":[{"p":"str","o":false}],"preview":"textWidth(str)","p5DocPath":"textWidth"},{"label":"textAscent","type":"method","kindLabel":"fun","preview":"textAscent()","p5DocPath":"textAscent"},{"label":"textDescent","type":"method","kindLabel":"fun","preview":"textDescent()","p5DocPath":"textDescent"},{"label":"textWrap","type":"method","kindLabel":"fun","params":[{"p":"style","o":false}],"preview":"textWrap(style)","p5DocPath":"textWrap"},{"label":"loadFont","type":"method","kindLabel":"fun","params":[{"p":"path","o":false},{"p":"successCallback","o":true},{"p":"failureCallback","o":true}],"preview":"loadFont(path, [successCallback], [failureCallback])","p5DocPath":"loadFont"},{"label":"text","type":"method","kindLabel":"fun","params":[{"p":"str","o":false},{"p":"x","o":false},{"p":"y","o":false},{"p":"maxWidth","o":true},{"p":"maxHeight","o":true}],"preview":"text(str, x, y, [maxWidth], [maxHeight])","p5DocPath":"text"},{"label":"textFont","type":"method","kindLabel":"fun","preview":"textFont()","p5DocPath":"textFont"},{"label":"append","type":"method","kindLabel":"fun","params":[{"p":"array","o":false},{"p":"value","o":false}],"preview":"append(array, value)","p5DocPath":"append"},{"label":"arrayCopy","type":"method","kindLabel":"fun","preview":"arrayCopy()","p5DocPath":"arrayCopy"},{"label":"concat","type":"method","kindLabel":"fun","params":[{"p":"a","o":false},{"p":"b","o":false}],"preview":"concat(a, b)","p5DocPath":"concat"},{"label":"reverse","type":"method","kindLabel":"fun","params":[{"p":"list","o":false}],"preview":"reverse(list)","p5DocPath":"reverse"},{"label":"shorten","type":"method","kindLabel":"fun","params":[{"p":"list","o":false}],"preview":"shorten(list)","p5DocPath":"shorten"},{"label":"shuffle","type":"method","kindLabel":"fun","params":[{"p":"array","o":false},{"p":"bool","o":true}],"preview":"shuffle(array, [bool])","p5DocPath":"shuffle"},{"label":"sort","type":"method","kindLabel":"fun","params":[{"p":"list","o":false},{"p":"count","o":true}],"preview":"sort(list, [count])","p5DocPath":"sort"},{"label":"splice","type":"method","kindLabel":"fun","params":[{"p":"list","o":false},{"p":"value","o":false},{"p":"position","o":false}],"preview":"splice(list, value, position)","p5DocPath":"splice"},{"label":"subset","type":"method","kindLabel":"fun","params":[{"p":"list","o":false},{"p":"start","o":false},{"p":"count","o":true}],"preview":"subset(list, start, [count])","p5DocPath":"subset"},{"label":"float","type":"method","kindLabel":"fun","preview":"float()","p5DocPath":"float"},{"label":"int","type":"method","kindLabel":"fun","preview":"int()","p5DocPath":"int"},{"label":"str","type":"method","kindLabel":"fun","params":[{"p":"n","o":false}],"preview":"str(n)","p5DocPath":"str"},{"label":"boolean","type":"method","kindLabel":"fun","preview":"boolean()","p5DocPath":"boolean"},{"label":"byte","type":"method","kindLabel":"fun","preview":"byte()","p5DocPath":"byte"},{"label":"char","type":"method","kindLabel":"fun","preview":"char()","p5DocPath":"char"},{"label":"unchar","type":"method","kindLabel":"fun","preview":"unchar()","p5DocPath":"unchar"},{"label":"hex","type":"method","kindLabel":"fun","preview":"hex()","p5DocPath":"hex"},{"label":"unhex","type":"method","kindLabel":"fun","preview":"unhex()","p5DocPath":"unhex"},{"label":"join","type":"method","kindLabel":"fun","params":[{"p":"list","o":false},{"p":"separator","o":false}],"preview":"join(list, separator)","p5DocPath":"join"},{"label":"match","type":"method","kindLabel":"fun","params":[{"p":"str","o":false},{"p":"regexp","o":false}],"preview":"match(str, regexp)","p5DocPath":"match"},{"label":"matchAll","type":"method","kindLabel":"fun","params":[{"p":"str","o":false},{"p":"regexp","o":false}],"preview":"matchAll(str, regexp)","p5DocPath":"matchAll"},{"label":"nf","type":"method","kindLabel":"fun","preview":"nf()","p5DocPath":"nf"},{"label":"nfc","type":"method","kindLabel":"fun","preview":"nfc()","p5DocPath":"nfc"},{"label":"nfp","type":"method","kindLabel":"fun","preview":"nfp()","p5DocPath":"nfp"},{"label":"nfs","type":"method","kindLabel":"fun","preview":"nfs()","p5DocPath":"nfs"},{"label":"split","type":"method","kindLabel":"fun","params":[{"p":"value","o":false},{"p":"delim","o":false}],"preview":"split(value, delim)","p5DocPath":"split"},{"label":"splitTokens","type":"method","kindLabel":"fun","params":[{"p":"value","o":false},{"p":"delim","o":true}],"preview":"splitTokens(value, [delim])","p5DocPath":"splitTokens"},{"label":"trim","type":"method","kindLabel":"fun","preview":"trim()","p5DocPath":"trim"},{"label":"day","type":"method","kindLabel":"fun","preview":"day()","p5DocPath":"day"},{"label":"hour","type":"method","kindLabel":"fun","preview":"hour()","p5DocPath":"hour"},{"label":"minute","type":"method","kindLabel":"fun","preview":"minute()","p5DocPath":"minute"},{"label":"millis","type":"method","kindLabel":"fun","preview":"millis()","p5DocPath":"millis"},{"label":"month","type":"method","kindLabel":"fun","preview":"month()","p5DocPath":"month"},{"label":"second","type":"method","kindLabel":"fun","preview":"second()","p5DocPath":"second"},{"label":"year","type":"method","kindLabel":"fun","preview":"year()","p5DocPath":"year"},{"label":"beginGeometry","type":"method","kindLabel":"fun","preview":"beginGeometry()","p5DocPath":"beginGeometry"},{"label":"endGeometry","type":"method","kindLabel":"fun","preview":"endGeometry()","p5DocPath":"endGeometry"},{"label":"buildGeometry","type":"method","kindLabel":"fun","params":[{"p":"callback","o":false}],"preview":"buildGeometry(callback)","p5DocPath":"buildGeometry"},{"label":"freeGeometry","type":"method","kindLabel":"fun","params":[{"p":"geometry","o":false}],"preview":"freeGeometry(geometry)","p5DocPath":"freeGeometry"},{"label":"plane","type":"method","kindLabel":"fun","params":[{"p":"width","o":true},{"p":"height","o":true},{"p":"detailX","o":true},{"p":"detailY","o":true}],"preview":"plane([width], [height], [detailX], [detailY])","p5DocPath":"plane"},{"label":"box","type":"method","kindLabel":"fun","params":[{"p":"width","o":true},{"p":"height","o":true},{"p":"depth","o":true},{"p":"detailX","o":true},{"p":"detailY","o":true}],"preview":"box([width], [height], [depth], [detailX], [detailY])","p5DocPath":"box"},{"label":"sphere","type":"method","kindLabel":"fun","params":[{"p":"radius","o":true},{"p":"detailX","o":true},{"p":"detailY","o":true}],"preview":"sphere([radius], [detailX], [detailY])","p5DocPath":"sphere"},{"label":"cylinder","type":"method","kindLabel":"fun","params":[{"p":"radius","o":true},{"p":"height","o":true},{"p":"detailX","o":true},{"p":"detailY","o":true},{"p":"bottomCap","o":true},{"p":"topCap","o":true}],"preview":"cylinder([radius], [height], [detailX], [detailY], [bottomCap], [topCap])","p5DocPath":"cylinder"},{"label":"cone","type":"method","kindLabel":"fun","params":[{"p":"radius","o":true},{"p":"height","o":true},{"p":"detailX","o":true},{"p":"detailY","o":true},{"p":"cap","o":true}],"preview":"cone([radius], [height], [detailX], [detailY], [cap])","p5DocPath":"cone"},{"label":"ellipsoid","type":"method","kindLabel":"fun","params":[{"p":"radiusX","o":true},{"p":"radiusY","o":true},{"p":"radiusZ","o":true},{"p":"detailX","o":true},{"p":"detailY","o":true}],"preview":"ellipsoid([radiusX], [radiusY], [radiusZ], [detailX], [detailY])","p5DocPath":"ellipsoid"},{"label":"torus","type":"method","kindLabel":"fun","params":[{"p":"radius","o":true},{"p":"tubeRadius","o":true},{"p":"detailX","o":true},{"p":"detailY","o":true}],"preview":"torus([radius], [tubeRadius], [detailX], [detailY])","p5DocPath":"torus"},{"label":"orbitControl","type":"method","kindLabel":"fun","params":[{"p":"sensitivityX","o":true},{"p":"sensitivityY","o":true},{"p":"sensitivityZ","o":true},{"p":"options","o":true}],"preview":"orbitControl([sensitivityX], [sensitivityY], [sensitivityZ], [options])","p5DocPath":"orbitControl"},{"label":"debugMode","type":"method","kindLabel":"fun","preview":"debugMode()","p5DocPath":"debugMode"},{"label":"noDebugMode","type":"method","kindLabel":"fun","preview":"noDebugMode()","p5DocPath":"noDebugMode"},{"label":"ambientLight","type":"method","kindLabel":"fun","preview":"ambientLight()","p5DocPath":"ambientLight"},{"label":"specularColor","type":"method","kindLabel":"fun","preview":"specularColor()","p5DocPath":"specularColor"},{"label":"directionalLight","type":"method","kindLabel":"fun","preview":"directionalLight()","p5DocPath":"directionalLight"},{"label":"pointLight","type":"method","kindLabel":"fun","preview":"pointLight()","p5DocPath":"pointLight"},{"label":"imageLight","type":"method","kindLabel":"fun","params":[{"p":"img","o":false}],"preview":"imageLight(img)","p5DocPath":"imageLight"},{"label":"panorama","type":"method","kindLabel":"fun","params":[{"p":"img","o":false}],"preview":"panorama(img)","p5DocPath":"panorama"},{"label":"lights","type":"method","kindLabel":"fun","preview":"lights()","p5DocPath":"lights"},{"label":"lightFalloff","type":"method","kindLabel":"fun","params":[{"p":"constant","o":false},{"p":"linear","o":false},{"p":"quadratic","o":false}],"preview":"lightFalloff(constant, linear, quadratic)","p5DocPath":"lightFalloff"},{"label":"spotLight","type":"method","kindLabel":"fun","preview":"spotLight()","p5DocPath":"spotLight"},{"label":"noLights","type":"method","kindLabel":"fun","preview":"noLights()","p5DocPath":"noLights"},{"label":"loadModel","type":"method","kindLabel":"fun","preview":"loadModel()","p5DocPath":"loadModel"},{"label":"model","type":"method","kindLabel":"fun","params":[{"p":"model","o":false}],"preview":"model(model)","p5DocPath":"model"},{"label":"createModel","type":"method","kindLabel":"fun","preview":"createModel()","p5DocPath":"createModel"},{"label":"loadShader","type":"method","kindLabel":"fun","params":[{"p":"vertFilename","o":false},{"p":"fragFilename","o":false},{"p":"successCallback","o":true},{"p":"failureCallback","o":true}],"preview":"loadShader(vertFilename, fragFilename, [successCallback], [failureCallback])","p5DocPath":"loadShader"},{"label":"createShader","type":"method","kindLabel":"fun","params":[{"p":"vertSrc","o":false},{"p":"fragSrc","o":false},{"p":"options","o":true}],"preview":"createShader(vertSrc, fragSrc, [options])","p5DocPath":"createShader"},{"label":"createFilterShader","type":"method","kindLabel":"fun","params":[{"p":"fragSrc","o":false}],"preview":"createFilterShader(fragSrc)","p5DocPath":"createFilterShader"},{"label":"shader","type":"method","kindLabel":"fun","params":[{"p":"s","o":false}],"preview":"shader(s)","p5DocPath":"shader"},{"label":"baseMaterialShader","type":"method","kindLabel":"fun","preview":"baseMaterialShader()","p5DocPath":"baseMaterialShader"},{"label":"baseNormalShader","type":"method","kindLabel":"fun","preview":"baseNormalShader()","p5DocPath":"baseNormalShader"},{"label":"baseColorShader","type":"method","kindLabel":"fun","preview":"baseColorShader()","p5DocPath":"baseColorShader"},{"label":"baseStrokeShader","type":"method","kindLabel":"fun","preview":"baseStrokeShader()","p5DocPath":"baseStrokeShader"},{"label":"resetShader","type":"method","kindLabel":"fun","preview":"resetShader()","p5DocPath":"resetShader"},{"label":"texture","type":"method","kindLabel":"fun","params":[{"p":"tex","o":false}],"preview":"texture(tex)","p5DocPath":"texture"},{"label":"textureMode","type":"method","kindLabel":"fun","params":[{"p":"mode","o":false}],"preview":"textureMode(mode)","p5DocPath":"textureMode"},{"label":"textureWrap","type":"method","kindLabel":"fun","params":[{"p":"wrapX","o":false},{"p":"wrapY","o":true}],"preview":"textureWrap(wrapX, [wrapY])","p5DocPath":"textureWrap"},{"label":"normalMaterial","type":"method","kindLabel":"fun","preview":"normalMaterial()","p5DocPath":"normalMaterial"},{"label":"ambientMaterial","type":"method","kindLabel":"fun","preview":"ambientMaterial()","p5DocPath":"ambientMaterial"},{"label":"emissiveMaterial","type":"method","kindLabel":"fun","preview":"emissiveMaterial()","p5DocPath":"emissiveMaterial"},{"label":"specularMaterial","type":"method","kindLabel":"fun","preview":"specularMaterial()","p5DocPath":"specularMaterial"},{"label":"shininess","type":"method","kindLabel":"fun","params":[{"p":"shine","o":false}],"preview":"shininess(shine)","p5DocPath":"shininess"},{"label":"metalness","type":"method","kindLabel":"fun","params":[{"p":"metallic","o":false}],"preview":"metalness(metallic)","p5DocPath":"metalness"},{"label":"camera","type":"method","kindLabel":"fun","params":[{"p":"x","o":true},{"p":"y","o":true},{"p":"z","o":true},{"p":"centerX","o":true},{"p":"centerY","o":true},{"p":"centerZ","o":true},{"p":"upX","o":true},{"p":"upY","o":true},{"p":"upZ","o":true}],"preview":"camera([x], [y], [z], [centerX], [centerY], [centerZ], [upX], [upY], [upZ])","p5DocPath":"camera"},{"label":"perspective","type":"method","kindLabel":"fun","params":[{"p":"fovy","o":true},{"p":"aspect","o":true},{"p":"near","o":true},{"p":"far","o":true}],"preview":"perspective([fovy], [aspect], [near], [far])","p5DocPath":"perspective"},{"label":"linePerspective","type":"method","kindLabel":"fun","preview":"linePerspective()","p5DocPath":"linePerspective"},{"label":"ortho","type":"method","kindLabel":"fun","params":[{"p":"left","o":true},{"p":"right","o":true},{"p":"bottom","o":true},{"p":"top","o":true},{"p":"near","o":true},{"p":"far","o":true}],"preview":"ortho([left], [right], [bottom], [top], [near], [far])","p5DocPath":"ortho"},{"label":"frustum","type":"method","kindLabel":"fun","params":[{"p":"left","o":true},{"p":"right","o":true},{"p":"bottom","o":true},{"p":"top","o":true},{"p":"near","o":true},{"p":"far","o":true}],"preview":"frustum([left], [right], [bottom], [top], [near], [far])","p5DocPath":"frustum"},{"label":"createCamera","type":"method","kindLabel":"fun","preview":"createCamera()","p5DocPath":"createCamera"},{"label":"setCamera","type":"method","kindLabel":"fun","params":[{"p":"cam","o":false}],"preview":"setCamera(cam)","p5DocPath":"setCamera"},{"label":"setAttributes","type":"method","kindLabel":"fun","preview":"setAttributes()","p5DocPath":"setAttributes"},{"label":"getAudioContext","type":"method","kindLabel":"fun","preview":"getAudioContext()","p5DocPath":"getAudioContext"},{"label":"userStartAudio","type":"method","kindLabel":"fun","params":[{"p":"elements","o":true},{"p":"callback","o":true}],"preview":"userStartAudio([elements], [callback])","p5DocPath":"userStartAudio"},{"label":"getOutputVolume","type":"method","kindLabel":"fun","preview":"getOutputVolume()","p5DocPath":"getOutputVolume"},{"label":"outputVolume","type":"method","kindLabel":"fun","params":[{"p":"volume","o":false},{"p":"rampTime","o":true},{"p":"timeFromNow","o":true}],"preview":"outputVolume(volume, [rampTime], [timeFromNow])","p5DocPath":"outputVolume"},{"label":"soundOut","type":"variable","kindLabel":"var","params":[],"preview":"soundOut","p5DocPath":"soundOut"},{"label":"sampleRate","type":"method","kindLabel":"fun","preview":"sampleRate()","p5DocPath":"sampleRate"},{"label":"freqToMidi","type":"method","kindLabel":"fun","params":[{"p":"frequency","o":false}],"preview":"freqToMidi(frequency)","p5DocPath":"freqToMidi"},{"label":"midiToFreq","type":"method","kindLabel":"fun","params":[{"p":"midiNote","o":false}],"preview":"midiToFreq(midiNote)","p5DocPath":"midiToFreq"},{"label":"soundFormats","type":"method","kindLabel":"fun","params":[{"p":"formats","o":true}],"preview":"soundFormats([formats])","p5DocPath":"soundFormats"},{"label":"saveSound","type":"method","kindLabel":"fun","params":[{"p":"soundFile","o":false},{"p":"fileName","o":false}],"preview":"saveSound(soundFile, fileName)","p5DocPath":"saveSound"},{"label":"loadSound","type":"method","kindLabel":"fun","params":[{"p":"path","o":false},{"p":"successCallback","o":true},{"p":"errorCallback","o":true},{"p":"whileLoading","o":true}],"preview":"loadSound(path, [successCallback], [errorCallback], [whileLoading])","p5DocPath":"loadSound"},{"label":"createConvolver","type":"method","kindLabel":"fun","params":[{"p":"path","o":false},{"p":"callback","o":true},{"p":"errorCallback","o":true}],"preview":"createConvolver(path, [callback], [errorCallback])","p5DocPath":"createConvolver"},{"label":"setBPM","type":"method","kindLabel":"fun","params":[{"p":"BPM","o":false},{"p":"rampTime","o":false}],"preview":"setBPM(BPM, rampTime)","p5DocPath":"setBPM"},{"label":"true","type":"boolean","kindLabel":"bool","params":[],"preview":"true","p5DocPath":"boolean"},{"label":"false","type":"boolean","kindLabel":"bool","params":[],"preview":"false","p5DocPath":"boolean"},{"label":"await","type":"keyword","kindLabel":"keyword","params":[],"preview":"await"},{"label":"class","type":"keyword","kindLabel":"keyword","params":[],"preview":"class","p5DocPath":"class"},{"label":"const","type":"keyword","kindLabel":"keyword","params":[],"preview":"const","p5DocPath":"const"},{"label":"else","type":"keyword","kindLabel":"keyword","params":[],"preview":"else","p5DocPath":"if-else"},{"label":"export","type":"keyword","kindLabel":"keyword","params":[],"preview":"export"},{"label":"for","type":"keyword","kindLabel":"keyword","params":[],"preview":"for","p5DocPath":"for"},{"label":"function","type":"keyword","kindLabel":"keyword","params":[],"preview":"function","p5DocPath":"function"},{"label":"if","type":"keyword","kindLabel":"keyword","params":[],"preview":"if","p5DocPath":"if-else"},{"label":"return","type":"keyword","kindLabel":"keyword","params":[],"preview":"return","p5DocPath":"return"},{"label":"while","type":"keyword","kindLabel":"keyword","params":[],"preview":"while","p5DocPath":"while"},{"label":"with","type":"keyword","kindLabel":"keyword","params":[],"preview":"with"},{"label":"let","type":"keyword","kindLabel":"keyword","params":[],"preview":"let","p5DocPath":"let"},{"label":"Array","type":"obj","kindLabel":"obj","params":[],"preview":"Array"},{"label":"Boolean","type":"obj","kindLabel":"obj","params":[],"preview":"Boolean"},{"label":"Date","type":"obj","kindLabel":"obj","params":[],"preview":"Date"},{"label":"Error","type":"obj","kindLabel":"obj","params":[],"preview":"Error"},{"label":"Function","type":"obj","kindLabel":"obj","params":[],"preview":"Function"},{"label":"JSON","type":"obj","kindLabel":"obj","params":[],"preview":"JSON","p5DocPath":"JSON"},{"label":"Math","type":"obj","kindLabel":"obj","params":[],"preview":"Math"},{"label":"Number","type":"obj","kindLabel":"obj","params":[],"preview":"Number"},{"label":"Object","type":"obj","kindLabel":"obj","params":[],"preview":"Object"},{"label":"RegExp","type":"obj","kindLabel":"obj","params":[],"preview":"RegExp"},{"label":"String","type":"obj","kindLabel":"obj","params":[],"preview":"String"},{"label":"Promise","type":"obj","kindLabel":"obj","params":[],"preview":"Promise"},{"label":"Set","type":"obj","kindLabel":"obj","params":[],"preview":"Set"},{"label":"Map","type":"obj","kindLabel":"obj","params":[],"preview":"Map"},{"label":"Symbol","type":"obj","kindLabel":"obj","params":[],"preview":"Symbol"},{"label":"WeakMap","type":"obj","kindLabel":"obj","params":[],"preview":"WeakMap"},{"label":"WeakSet","type":"obj","kindLabel":"obj","params":[],"preview":"WeakSet"},{"label":"ArrayBuffer","type":"obj","kindLabel":"obj","params":[],"preview":"ArrayBuffer"},{"label":"DataView","type":"obj","kindLabel":"obj","params":[],"preview":"DataView"},{"label":"Int32Array","type":"obj","kindLabel":"obj","params":[],"preview":"Int32Array"},{"label":"Uint32Array","type":"obj","kindLabel":"obj","params":[],"preview":"Uint32Array"},{"label":"Float32Array","type":"obj","kindLabel":"obj","params":[],"preview":"Float32Array"},{"label":"window","type":"obj","kindLabel":"obj","params":[],"preview":"window"},{"label":"document","type":"obj","kindLabel":"obj","params":[],"preview":"document"},{"label":"navigator","type":"obj","kindLabel":"obj","params":[],"preview":"navigator"},{"label":"console","type":"obj","kindLabel":"obj","params":[],"preview":"console","p5DocPath":"console"},{"label":"localStorage","type":"obj","kindLabel":"obj","params":[],"preview":"localStorage"},{"label":"sessionStorage","type":"obj","kindLabel":"obj","params":[],"preview":"sessionStorage"},{"label":"history","type":"obj","kindLabel":"obj","params":[],"preview":"history"},{"label":"location","type":"obj","kindLabel":"obj","params":[],"preview":"location"}];
diff --git a/client/utils/p5CodeAstAnalyzer.js b/client/utils/p5CodeAstAnalyzer.js
index 5aaa5ec7be..3307af8c5a 100644
--- a/client/utils/p5CodeAstAnalyzer.js
+++ b/client/utils/p5CodeAstAnalyzer.js
@@ -24,8 +24,7 @@ let lastValidResult = {
userDefinedClassMetadata: {}
};
-function _p5CodeAstAnalyzer(_cm) {
- const code = _cm.getValue();
+function _p5CodeAstAnalyzer(code) {
let ast;
try {
@@ -153,8 +152,7 @@ function _p5CodeAstAnalyzer(_cm) {
expr.left.object.type === 'ThisExpression' &&
expr.left.property.type === 'Identifier'
) {
- const propName = expr.left.property.name;
- classInfo.fields.add(propName);
+ classInfo.fields.add(expr.left.property.name);
}
},
@@ -165,8 +163,7 @@ function _p5CodeAstAnalyzer(_cm) {
callee.object.type === 'ThisExpression' &&
callee.property.type === 'Identifier'
) {
- const methodName = callee.property.name;
- classInfo.fields.add(methodName);
+ classInfo.fields.add(callee.property.name);
}
}
},
diff --git a/package-lock.json b/package-lock.json
index a0757fe864..f199bc3e2d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,8 +15,23 @@
"@babel/parser": "^7.27.5",
"@babel/register": "^7.14.5",
"@babel/traverse": "^7.27.4",
+ "@codemirror/autocomplete": "^6.18.6",
+ "@codemirror/commands": "^6.8.1",
+ "@codemirror/lang-css": "^6.3.1",
+ "@codemirror/lang-html": "^6.4.9",
+ "@codemirror/lang-javascript": "^6.2.3",
+ "@codemirror/lang-json": "^6.0.1",
+ "@codemirror/lang-xml": "^6.1.0",
+ "@codemirror/language": "^6.11.0",
+ "@codemirror/lint": "^6.8.5",
+ "@codemirror/search": "^6.5.11",
+ "@codemirror/state": "^6.5.2",
+ "@codemirror/view": "^6.40.0",
+ "@connieye/codemirror-color-picker": "^1.0.3",
"@emmetio/codemirror-plugin": "^1.2.4",
+ "@emmetio/codemirror6-plugin": "^0.4.0",
"@gatsbyjs/webpack-hot-middleware": "^2.25.3",
+ "@lezer/highlight": "^1.2.3",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.11",
"@redux-devtools/core": "^3.11.0",
"@redux-devtools/dock-monitor": "^3.0.1",
@@ -34,8 +49,7 @@
"bson-objectid": "^2.0.3",
"classnames": "^2.3.1",
"clipboard": "^1.7.1",
- "codemirror": "^5.62.0",
- "codemirror-colorpicker": "^1.9.72",
+ "codemirror": "^6.0.1",
"connect-mongo": "^5.1.0",
"console-feed": "^3.2.0",
"cookie-parser": "^1.4.5",
@@ -49,6 +63,7 @@
"dropzone": "^4.3.0",
"escape-string-regexp": "^1.0.5",
"escodegen": "^2.1.0",
+ "eslint-linter-browserify": "^10.0.3",
"eslint-scope": "^8.4.0",
"eslint-webpack-plugin": "^3.1.1",
"express": "^4.22.1",
@@ -58,7 +73,7 @@
"friendly-words": "^1.2.1",
"fuse.js": "^6.6.2",
"history": "^4.10.1",
- "htmlhint": "^0.15.1",
+ "htmlhint": "^0.15.2",
"i18next": "^19.9.2",
"i18next-http-backend": "^1.2.6",
"is-url": "^1.2.4",
@@ -171,6 +186,7 @@
"@types/nodemailer": "^7.0.1",
"@types/nodemailer-mailgun-transport": "^1.4.6",
"@types/passport": "^1.0.17",
+ "@types/prettier": "^2.7.3",
"@types/react": "^16.14.0",
"@types/react-dom": "^16.9.25",
"@types/react-helmet": "^6.1.11",
@@ -5967,6 +5983,172 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
+ "node_modules/@codemirror/autocomplete": {
+ "version": "6.20.3",
+ "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.3.tgz",
+ "integrity": "sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.17.0",
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/commands": {
+ "version": "6.10.3",
+ "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.3.tgz",
+ "integrity": "sha512-JFRiqhKu+bvSkDLI+rUhJwSxQxYb759W5GBezE8Uc8mHLqC9aV/9aTC7yJSqCtB3F00pylrLCwnyS91Ap5ej4Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.6.0",
+ "@codemirror/view": "^6.27.0",
+ "@lezer/common": "^1.1.0"
+ }
+ },
+ "node_modules/@codemirror/lang-css": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
+ "integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@lezer/common": "^1.0.2",
+ "@lezer/css": "^1.1.7"
+ }
+ },
+ "node_modules/@codemirror/lang-html": {
+ "version": "6.4.11",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz",
+ "integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/lang-css": "^6.0.0",
+ "@codemirror/lang-javascript": "^6.0.0",
+ "@codemirror/language": "^6.4.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.17.0",
+ "@lezer/common": "^1.0.0",
+ "@lezer/css": "^1.1.0",
+ "@lezer/html": "^1.3.12"
+ }
+ },
+ "node_modules/@codemirror/lang-javascript": {
+ "version": "6.2.5",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.5.tgz",
+ "integrity": "sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/language": "^6.6.0",
+ "@codemirror/lint": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.17.0",
+ "@lezer/common": "^1.0.0",
+ "@lezer/javascript": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/lang-json": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz",
+ "integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@lezer/json": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/lang-xml": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.1.0.tgz",
+ "integrity": "sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/language": "^6.4.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "@lezer/common": "^1.0.0",
+ "@lezer/xml": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/language": {
+ "version": "6.12.3",
+ "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.3.tgz",
+ "integrity": "sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.23.0",
+ "@lezer/common": "^1.5.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0",
+ "style-mod": "^4.0.0"
+ }
+ },
+ "node_modules/@codemirror/lint": {
+ "version": "6.9.6",
+ "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.6.tgz",
+ "integrity": "sha512-6Kp7r6XfCi/D/5sdXieMfg9pJU1bUEx96WITuLU6ESaKizCz0QHFMjY/TaFSbigDdEAIgi93itLBIUETP4oK+A==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.42.0",
+ "crelt": "^1.0.5"
+ }
+ },
+ "node_modules/@codemirror/search": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.0.tgz",
+ "integrity": "sha512-ZvGm99wc/s2cITtMT15LFdn8aH/aS+V+DqyGq/N5ZlV5vWtH+nILvC2nw0zX7ByNoHHDZ2IxxdW38O0tc5nVHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.37.0",
+ "crelt": "^1.0.5"
+ }
+ },
+ "node_modules/@codemirror/state": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.6.0.tgz",
+ "integrity": "sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@marijn/find-cluster-break": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/view": {
+ "version": "6.43.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.0.tgz",
+ "integrity": "sha512-V7ZCLQO3Jus9hzh2jVCCPW3mO4IBMr43O37PqSUYautJSnnJF41YlgLw21x0fLJTYvJ+Vkm6Gp+qKGH9pltgXA==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.6.0",
+ "crelt": "^1.0.6",
+ "style-mod": "^4.1.0",
+ "w3c-keyname": "^2.2.4"
+ }
+ },
+ "node_modules/@connieye/codemirror-color-picker": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@connieye/codemirror-color-picker/-/codemirror-color-picker-1.0.3.tgz",
+ "integrity": "sha512-e22W5t1kT8l0MCvYayax51QFdhEr/6P+TMb6+gEpDuEeNpIoxK9NE1aLrFUCgN8fhsefv1qo8bfr4BbL/od2Pw==",
+ "license": "MIT",
+ "dependencies": {
+ "colors-named": "^1.0.0",
+ "colors-named-hex": "^1.0.0",
+ "hsl-matcher": "^1.2.3"
+ },
+ "peerDependencies": {
+ "@codemirror/language": ">=6.0.0",
+ "@codemirror/state": ">=6.0.0",
+ "@codemirror/view": ">=6.40.0"
+ }
+ },
"node_modules/@csstools/convert-colors": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz",
@@ -5985,11 +6167,62 @@
"node": ">=10.0.0"
}
},
+ "node_modules/@emmetio/abbreviation": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz",
+ "integrity": "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==",
+ "license": "MIT",
+ "dependencies": {
+ "@emmetio/scanner": "^1.0.4"
+ }
+ },
"node_modules/@emmetio/codemirror-plugin": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@emmetio/codemirror-plugin/-/codemirror-plugin-1.2.4.tgz",
"integrity": "sha512-wVw2gqI6X+uVWYVRtTVymzTgbo4hEZIcPCNj4xrXw4l/+L3Qa+tAC/yf+Xy9nenRPCqRq0RLqGiQL+Qf/wYE9Q=="
},
+ "node_modules/@emmetio/codemirror6-plugin": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@emmetio/codemirror6-plugin/-/codemirror6-plugin-0.4.0.tgz",
+ "integrity": "sha512-ZP3W8JvN0cEFTdsrcKPIBg/K9sadE15g//TfubPXfM28ZxUp3SwNASbRfRLRQmPyP73+pAZzLqeOwACUUz/oAw==",
+ "dependencies": {
+ "@emmetio/math-expression": "^1.0.5",
+ "emmet": "^2.4.11"
+ },
+ "peerDependencies": {
+ "@codemirror/autocomplete": "^6.17.0",
+ "@codemirror/commands": "^6.6.0",
+ "@codemirror/lang-css": "^6.2.1",
+ "@codemirror/lang-html": "^6.4.9",
+ "@codemirror/language": "^6.10.2",
+ "@codemirror/state": "^6.4.1",
+ "@codemirror/view": "^6.29.1"
+ }
+ },
+ "node_modules/@emmetio/css-abbreviation": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.8.tgz",
+ "integrity": "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==",
+ "license": "MIT",
+ "dependencies": {
+ "@emmetio/scanner": "^1.0.4"
+ }
+ },
+ "node_modules/@emmetio/math-expression": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@emmetio/math-expression/-/math-expression-1.0.5.tgz",
+ "integrity": "sha512-qf5SXD/ViS04rXSeDg9CRGM10xLC9dVaKIbMHrrwxYr5LNB/C0rOfokhGSBwnVQKcidLmdRJeNWH1V1tppZ84Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@emmetio/scanner": "^1.0.4"
+ }
+ },
+ "node_modules/@emmetio/scanner": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.4.tgz",
+ "integrity": "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==",
+ "license": "MIT"
+ },
"node_modules/@emotion/cache": {
"version": "10.0.29",
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz",
@@ -7763,6 +7996,91 @@
"integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==",
"dev": true
},
+ "node_modules/@lezer/common": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz",
+ "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==",
+ "license": "MIT"
+ },
+ "node_modules/@lezer/css": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.3.tgz",
+ "integrity": "sha512-RzBo8r+/6QJeow7aPHIpGVIH59xTcJXp399820gZoMo9noQDRVpJLheIBUicYwKcsbOYoBRoLZlf2720dG/4Tg==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.3.0"
+ }
+ },
+ "node_modules/@lezer/highlight": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
+ "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.3.0"
+ }
+ },
+ "node_modules/@lezer/html": {
+ "version": "1.3.13",
+ "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.13.tgz",
+ "integrity": "sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/javascript": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz",
+ "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.1.3",
+ "@lezer/lr": "^1.3.0"
+ }
+ },
+ "node_modules/@lezer/json": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
+ "integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/lr": {
+ "version": "1.4.10",
+ "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.10.tgz",
+ "integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@lezer/xml": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.6.tgz",
+ "integrity": "sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "node_modules/@marijn/find-cluster-break": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
+ "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
+ "license": "MIT"
+ },
"node_modules/@mdx-js/react": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-2.3.0.tgz",
@@ -13718,6 +14036,13 @@
"@types/express": "*"
}
},
+ "node_modules/@types/prettier": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz",
+ "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/pretty-hrtime": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@types/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
@@ -16760,16 +17085,18 @@
}
},
"node_modules/codemirror": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.0.tgz",
- "integrity": "sha512-Xnl3304iCc8nyVZuRkzDVVwc794uc9QNX0UcPGeNic1fbzkSrO4l4GVXho9tRNKBgPYZXgocUqXyfIv3BILhCQ=="
- },
- "node_modules/codemirror-colorpicker": {
- "version": "1.9.80",
- "resolved": "https://registry.npmjs.org/codemirror-colorpicker/-/codemirror-colorpicker-1.9.80.tgz",
- "integrity": "sha512-7lGqNxf5haBJXLnVR1ynPiPkN2d1Whm0jdy8Z9QsSOhRWVyK2C2ihgm1dX4DCks57ht/jKMdpL9lYv+zAphxWQ==",
- "peerDependencies": {
- "codemirror": "^5.48.0"
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
+ "integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/commands": "^6.0.0",
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/lint": "^6.0.0",
+ "@codemirror/search": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0"
}
},
"node_modules/collect-v8-coverage": {
@@ -16821,6 +17148,30 @@
"integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
"dev": true
},
+ "node_modules/colors-named": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/colors-named/-/colors-named-1.0.5.tgz",
+ "integrity": "sha512-xaspf9oddAOqP2LYNOgp8E3BwAzugrdO9J1kDNS5ySrzTgV9hrXGBt5w87ioLEr2pM4Ukt+GKedvzaLRxpv8pA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://jaywcjlove.github.io/#/sponsor"
+ }
+ },
+ "node_modules/colors-named-hex": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/colors-named-hex/-/colors-named-hex-1.0.4.tgz",
+ "integrity": "sha512-X+Enw/2fFAgDRhUac69cRO/RJvHnWDBBrP8J1sJuEU16Buiiu8PPpJP4abSo0V+fJbkfwmQITE6zKx/SBJERGw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://jaywcjlove.github.io/#/sponsor"
+ }
+ },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -17327,6 +17678,12 @@
"node": ">=8"
}
},
+ "node_modules/crelt": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
+ "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
+ "license": "MIT"
+ },
"node_modules/cross-env": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.1.tgz",
@@ -19302,6 +19659,22 @@
"url": "https://github.com/sindresorhus/emittery?sponsor=1"
}
},
+ "node_modules/emmet": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/emmet/-/emmet-2.4.11.tgz",
+ "integrity": "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==",
+ "license": "MIT",
+ "workspaces": [
+ "./packages/scanner",
+ "./packages/abbreviation",
+ "./packages/css-abbreviation",
+ "./"
+ ],
+ "dependencies": {
+ "@emmetio/abbreviation": "^2.3.3",
+ "@emmetio/css-abbreviation": "^2.1.8"
+ }
+ },
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -19863,6 +20236,12 @@
"ms": "^2.1.1"
}
},
+ "node_modules/eslint-linter-browserify": {
+ "version": "10.4.1",
+ "resolved": "https://registry.npmjs.org/eslint-linter-browserify/-/eslint-linter-browserify-10.4.1.tgz",
+ "integrity": "sha512-mIs4xbUDjkijfVNs3F973k7HPJ0MhQZ77PotlaCX9xUbI/jwgv5sAh+O2mgKr6j3CM2aaGlbdvRFOyycN5VZxg==",
+ "license": "MIT"
+ },
"node_modules/eslint-module-utils": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
@@ -21964,6 +22343,18 @@
"react-is": "^16.7.0"
}
},
+ "node_modules/hsl-matcher": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/hsl-matcher/-/hsl-matcher-1.2.4.tgz",
+ "integrity": "sha512-tS7XnJS33Egirm+6cI+Z/kH/aVZt94uxGlJxOZlGql2/yqbAzPg3zHHnTnVN4cVpoJnEYEGq+LE3iXbuUIe8BA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16.0.0"
+ },
+ "funding": {
+ "url": "https://jaywcjlove.github.io/#/sponsor"
+ }
+ },
"node_modules/html-encoding-sniffer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
@@ -34521,6 +34912,12 @@
"webpack": "^5.0.0"
}
},
+ "node_modules/style-mod": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz",
+ "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==",
+ "license": "MIT"
+ },
"node_modules/style-to-object": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz",
@@ -35614,6 +36011,12 @@
"browser-process-hrtime": "^1.0.0"
}
},
+ "node_modules/w3c-keyname": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
+ "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
+ "license": "MIT"
+ },
"node_modules/walker": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
@@ -40928,6 +41331,154 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
+ "@codemirror/autocomplete": {
+ "version": "6.20.3",
+ "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.3.tgz",
+ "integrity": "sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g==",
+ "requires": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.17.0",
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "@codemirror/commands": {
+ "version": "6.10.3",
+ "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.3.tgz",
+ "integrity": "sha512-JFRiqhKu+bvSkDLI+rUhJwSxQxYb759W5GBezE8Uc8mHLqC9aV/9aTC7yJSqCtB3F00pylrLCwnyS91Ap5ej4Q==",
+ "requires": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.6.0",
+ "@codemirror/view": "^6.27.0",
+ "@lezer/common": "^1.1.0"
+ }
+ },
+ "@codemirror/lang-css": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
+ "integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
+ "requires": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@lezer/common": "^1.0.2",
+ "@lezer/css": "^1.1.7"
+ }
+ },
+ "@codemirror/lang-html": {
+ "version": "6.4.11",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz",
+ "integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==",
+ "requires": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/lang-css": "^6.0.0",
+ "@codemirror/lang-javascript": "^6.0.0",
+ "@codemirror/language": "^6.4.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.17.0",
+ "@lezer/common": "^1.0.0",
+ "@lezer/css": "^1.1.0",
+ "@lezer/html": "^1.3.12"
+ }
+ },
+ "@codemirror/lang-javascript": {
+ "version": "6.2.5",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.5.tgz",
+ "integrity": "sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==",
+ "requires": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/language": "^6.6.0",
+ "@codemirror/lint": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.17.0",
+ "@lezer/common": "^1.0.0",
+ "@lezer/javascript": "^1.0.0"
+ }
+ },
+ "@codemirror/lang-json": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz",
+ "integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==",
+ "requires": {
+ "@codemirror/language": "^6.0.0",
+ "@lezer/json": "^1.0.0"
+ }
+ },
+ "@codemirror/lang-xml": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.1.0.tgz",
+ "integrity": "sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==",
+ "requires": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/language": "^6.4.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0",
+ "@lezer/common": "^1.0.0",
+ "@lezer/xml": "^1.0.0"
+ }
+ },
+ "@codemirror/language": {
+ "version": "6.12.3",
+ "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.3.tgz",
+ "integrity": "sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==",
+ "requires": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.23.0",
+ "@lezer/common": "^1.5.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0",
+ "style-mod": "^4.0.0"
+ }
+ },
+ "@codemirror/lint": {
+ "version": "6.9.6",
+ "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.6.tgz",
+ "integrity": "sha512-6Kp7r6XfCi/D/5sdXieMfg9pJU1bUEx96WITuLU6ESaKizCz0QHFMjY/TaFSbigDdEAIgi93itLBIUETP4oK+A==",
+ "requires": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.42.0",
+ "crelt": "^1.0.5"
+ }
+ },
+ "@codemirror/search": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.0.tgz",
+ "integrity": "sha512-ZvGm99wc/s2cITtMT15LFdn8aH/aS+V+DqyGq/N5ZlV5vWtH+nILvC2nw0zX7ByNoHHDZ2IxxdW38O0tc5nVHg==",
+ "requires": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.37.0",
+ "crelt": "^1.0.5"
+ }
+ },
+ "@codemirror/state": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.6.0.tgz",
+ "integrity": "sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==",
+ "requires": {
+ "@marijn/find-cluster-break": "^1.0.0"
+ }
+ },
+ "@codemirror/view": {
+ "version": "6.43.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.0.tgz",
+ "integrity": "sha512-V7ZCLQO3Jus9hzh2jVCCPW3mO4IBMr43O37PqSUYautJSnnJF41YlgLw21x0fLJTYvJ+Vkm6Gp+qKGH9pltgXA==",
+ "requires": {
+ "@codemirror/state": "^6.6.0",
+ "crelt": "^1.0.6",
+ "style-mod": "^4.1.0",
+ "w3c-keyname": "^2.2.4"
+ }
+ },
+ "@connieye/codemirror-color-picker": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@connieye/codemirror-color-picker/-/codemirror-color-picker-1.0.3.tgz",
+ "integrity": "sha512-e22W5t1kT8l0MCvYayax51QFdhEr/6P+TMb6+gEpDuEeNpIoxK9NE1aLrFUCgN8fhsefv1qo8bfr4BbL/od2Pw==",
+ "requires": {
+ "colors-named": "^1.0.0",
+ "colors-named-hex": "^1.0.0",
+ "hsl-matcher": "^1.2.3"
+ }
+ },
"@csstools/convert-colors": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz",
@@ -40940,11 +41491,49 @@
"integrity": "sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==",
"dev": true
},
+ "@emmetio/abbreviation": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz",
+ "integrity": "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==",
+ "requires": {
+ "@emmetio/scanner": "^1.0.4"
+ }
+ },
"@emmetio/codemirror-plugin": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@emmetio/codemirror-plugin/-/codemirror-plugin-1.2.4.tgz",
"integrity": "sha512-wVw2gqI6X+uVWYVRtTVymzTgbo4hEZIcPCNj4xrXw4l/+L3Qa+tAC/yf+Xy9nenRPCqRq0RLqGiQL+Qf/wYE9Q=="
},
+ "@emmetio/codemirror6-plugin": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@emmetio/codemirror6-plugin/-/codemirror6-plugin-0.4.0.tgz",
+ "integrity": "sha512-ZP3W8JvN0cEFTdsrcKPIBg/K9sadE15g//TfubPXfM28ZxUp3SwNASbRfRLRQmPyP73+pAZzLqeOwACUUz/oAw==",
+ "requires": {
+ "@emmetio/math-expression": "^1.0.5",
+ "emmet": "^2.4.11"
+ }
+ },
+ "@emmetio/css-abbreviation": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.8.tgz",
+ "integrity": "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==",
+ "requires": {
+ "@emmetio/scanner": "^1.0.4"
+ }
+ },
+ "@emmetio/math-expression": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@emmetio/math-expression/-/math-expression-1.0.5.tgz",
+ "integrity": "sha512-qf5SXD/ViS04rXSeDg9CRGM10xLC9dVaKIbMHrrwxYr5LNB/C0rOfokhGSBwnVQKcidLmdRJeNWH1V1tppZ84Q==",
+ "requires": {
+ "@emmetio/scanner": "^1.0.4"
+ }
+ },
+ "@emmetio/scanner": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.4.tgz",
+ "integrity": "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA=="
+ },
"@emotion/cache": {
"version": "10.0.29",
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz",
@@ -42213,6 +42802,82 @@
"integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==",
"dev": true
},
+ "@lezer/common": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz",
+ "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ=="
+ },
+ "@lezer/css": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.3.tgz",
+ "integrity": "sha512-RzBo8r+/6QJeow7aPHIpGVIH59xTcJXp399820gZoMo9noQDRVpJLheIBUicYwKcsbOYoBRoLZlf2720dG/4Tg==",
+ "requires": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.3.0"
+ }
+ },
+ "@lezer/highlight": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
+ "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==",
+ "requires": {
+ "@lezer/common": "^1.3.0"
+ }
+ },
+ "@lezer/html": {
+ "version": "1.3.13",
+ "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.13.tgz",
+ "integrity": "sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==",
+ "requires": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "@lezer/javascript": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz",
+ "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==",
+ "requires": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.1.3",
+ "@lezer/lr": "^1.3.0"
+ }
+ },
+ "@lezer/json": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
+ "integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
+ "requires": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "@lezer/lr": {
+ "version": "1.4.10",
+ "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.10.tgz",
+ "integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==",
+ "requires": {
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "@lezer/xml": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.6.tgz",
+ "integrity": "sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==",
+ "requires": {
+ "@lezer/common": "^1.2.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0"
+ }
+ },
+ "@marijn/find-cluster-break": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
+ "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g=="
+ },
"@mdx-js/react": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-2.3.0.tgz",
@@ -46503,6 +47168,12 @@
"@types/express": "*"
}
},
+ "@types/prettier": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz",
+ "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==",
+ "dev": true
+ },
"@types/pretty-hrtime": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@types/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
@@ -48779,15 +49450,18 @@
"dev": true
},
"codemirror": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.0.tgz",
- "integrity": "sha512-Xnl3304iCc8nyVZuRkzDVVwc794uc9QNX0UcPGeNic1fbzkSrO4l4GVXho9tRNKBgPYZXgocUqXyfIv3BILhCQ=="
- },
- "codemirror-colorpicker": {
- "version": "1.9.80",
- "resolved": "https://registry.npmjs.org/codemirror-colorpicker/-/codemirror-colorpicker-1.9.80.tgz",
- "integrity": "sha512-7lGqNxf5haBJXLnVR1ynPiPkN2d1Whm0jdy8Z9QsSOhRWVyK2C2ihgm1dX4DCks57ht/jKMdpL9lYv+zAphxWQ==",
- "requires": {}
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
+ "integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
+ "requires": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/commands": "^6.0.0",
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/lint": "^6.0.0",
+ "@codemirror/search": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0"
+ }
},
"collect-v8-coverage": {
"version": "1.0.2",
@@ -48838,6 +49512,16 @@
"integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
"dev": true
},
+ "colors-named": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/colors-named/-/colors-named-1.0.5.tgz",
+ "integrity": "sha512-xaspf9oddAOqP2LYNOgp8E3BwAzugrdO9J1kDNS5ySrzTgV9hrXGBt5w87ioLEr2pM4Ukt+GKedvzaLRxpv8pA=="
+ },
+ "colors-named-hex": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/colors-named-hex/-/colors-named-hex-1.0.4.tgz",
+ "integrity": "sha512-X+Enw/2fFAgDRhUac69cRO/RJvHnWDBBrP8J1sJuEU16Buiiu8PPpJP4abSo0V+fJbkfwmQITE6zKx/SBJERGw=="
+ },
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -49204,6 +49888,11 @@
}
}
},
+ "crelt": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
+ "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="
+ },
"cross-env": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.1.tgz",
@@ -50595,6 +51284,15 @@
"integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
"dev": true
},
+ "emmet": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/emmet/-/emmet-2.4.11.tgz",
+ "integrity": "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==",
+ "requires": {
+ "@emmetio/abbreviation": "^2.3.3",
+ "@emmetio/css-abbreviation": "^2.1.8"
+ }
+ },
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -51216,6 +51914,11 @@
}
}
},
+ "eslint-linter-browserify": {
+ "version": "10.4.1",
+ "resolved": "https://registry.npmjs.org/eslint-linter-browserify/-/eslint-linter-browserify-10.4.1.tgz",
+ "integrity": "sha512-mIs4xbUDjkijfVNs3F973k7HPJ0MhQZ77PotlaCX9xUbI/jwgv5sAh+O2mgKr6j3CM2aaGlbdvRFOyycN5VZxg=="
+ },
"eslint-module-utils": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
@@ -52531,6 +53234,11 @@
"react-is": "^16.7.0"
}
},
+ "hsl-matcher": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/hsl-matcher/-/hsl-matcher-1.2.4.tgz",
+ "integrity": "sha512-tS7XnJS33Egirm+6cI+Z/kH/aVZt94uxGlJxOZlGql2/yqbAzPg3zHHnTnVN4cVpoJnEYEGq+LE3iXbuUIe8BA=="
+ },
"html-encoding-sniffer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
@@ -61686,6 +62394,11 @@
"dev": true,
"requires": {}
},
+ "style-mod": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz",
+ "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ=="
+ },
"style-to-object": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz",
@@ -62483,6 +63196,11 @@
"browser-process-hrtime": "^1.0.0"
}
},
+ "w3c-keyname": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
+ "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="
+ },
"walker": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
diff --git a/package.json b/package.json
index 2a8c3ca370..7034823448 100644
--- a/package.json
+++ b/package.json
@@ -66,7 +66,12 @@
"displayName": "client",
"testEnvironment": "jsdom",
"transform": {
- "^.+\\.[jt]sx?$": "babel-jest"
+ "\\.[jt]sx?$": [
+ "babel-jest",
+ {
+ "configFile": "./.babelrc"
+ }
+ ]
},
"moduleFileExtensions": [
"ts",
@@ -83,6 +88,9 @@
"^.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)(|\\?byContent|\\?byUrl)$": "/client/__mocks__/fileMock.js",
"\\.(css|less|scss)$": "/client/__mocks__/styleMock.js"
},
+ "transformIgnorePatterns": [
+ "/node_modules/(?!colors-named|colors-named-hex|hsl-matcher|@emmetio/)"
+ ],
"testMatch": [
"/client/**/*.test.(js|jsx|ts|tsx)"
]
@@ -145,6 +153,7 @@
"@types/nodemailer": "^7.0.1",
"@types/nodemailer-mailgun-transport": "^1.4.6",
"@types/passport": "^1.0.17",
+ "@types/prettier": "^2.7.3",
"@types/react": "^16.14.0",
"@types/react-dom": "^16.9.25",
"@types/react-helmet": "^6.1.11",
@@ -210,8 +219,23 @@
"@babel/parser": "^7.27.5",
"@babel/register": "^7.14.5",
"@babel/traverse": "^7.27.4",
+ "@codemirror/autocomplete": "^6.18.6",
+ "@codemirror/commands": "^6.8.1",
+ "@codemirror/lang-css": "^6.3.1",
+ "@codemirror/lang-html": "^6.4.9",
+ "@codemirror/lang-javascript": "^6.2.3",
+ "@codemirror/lang-json": "^6.0.1",
+ "@codemirror/lang-xml": "^6.1.0",
+ "@codemirror/language": "^6.11.0",
+ "@codemirror/lint": "^6.8.5",
+ "@codemirror/search": "^6.5.11",
+ "@codemirror/state": "^6.5.2",
+ "@codemirror/view": "^6.40.0",
+ "@connieye/codemirror-color-picker": "^1.0.3",
"@emmetio/codemirror-plugin": "^1.2.4",
+ "@emmetio/codemirror6-plugin": "^0.4.0",
"@gatsbyjs/webpack-hot-middleware": "^2.25.3",
+ "@lezer/highlight": "^1.2.3",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.11",
"@redux-devtools/core": "^3.11.0",
"@redux-devtools/dock-monitor": "^3.0.1",
@@ -229,8 +253,7 @@
"bson-objectid": "^2.0.3",
"classnames": "^2.3.1",
"clipboard": "^1.7.1",
- "codemirror": "^5.62.0",
- "codemirror-colorpicker": "^1.9.72",
+ "codemirror": "^6.0.1",
"connect-mongo": "^5.1.0",
"console-feed": "^3.2.0",
"cookie-parser": "^1.4.5",
@@ -243,6 +266,7 @@
"dotenv": "^2.0.0",
"dropzone": "^4.3.0",
"escape-string-regexp": "^1.0.5",
+ "eslint-linter-browserify": "^10.0.3",
"escodegen": "^2.1.0",
"eslint-scope": "^8.4.0",
"eslint-webpack-plugin": "^3.1.1",
@@ -253,7 +277,7 @@
"friendly-words": "^1.2.1",
"fuse.js": "^6.6.2",
"history": "^4.10.1",
- "htmlhint": "^0.15.1",
+ "htmlhint": "^0.15.2",
"i18next": "^19.9.2",
"i18next-http-backend": "^1.2.6",
"is-url": "^1.2.4",
diff --git a/server/scripts/update-p5-hinter.js b/server/scripts/update-p5-hinter.js
index a6a667eac4..d438c28ca0 100644
--- a/server/scripts/update-p5-hinter.js
+++ b/server/scripts/update-p5-hinter.js
@@ -2,81 +2,90 @@ const fs = require('fs');
const process = require('process');
const axios = require('axios');
-// const getDescription = (d) => {
-// return d.split('\n')[0].replace('', '');
-// };
-
+// TODO: Currently this makes duplicate entries because
+// the default Javascript hinter also has these,
+// but should we keep them around for the p5 reference links?
const reservedKeywords = [
- { name: 'await', p5DocPath: false },
- { name: 'break', p5DocPath: false },
- { name: 'case', p5DocPath: false },
- { name: 'catch', p5DocPath: false },
+ { name: 'await', p5DocPath: undefined },
{ name: 'class', p5DocPath: 'class' },
{ name: 'const', p5DocPath: 'const' },
- { name: 'continue', p5DocPath: false },
- { name: 'debugger', p5DocPath: false },
- { name: 'default', p5DocPath: false },
- { name: 'delete', p5DocPath: false },
- { name: 'do', p5DocPath: false },
{ name: 'else', p5DocPath: 'if-else' },
- { name: 'export', p5DocPath: false },
- { name: 'extends', p5DocPath: false },
- { name: 'finally', p5DocPath: false },
+ { name: 'export', p5DocPath: undefined },
{ name: 'for', p5DocPath: 'for' },
{ name: 'function', p5DocPath: 'function' },
{ name: 'if', p5DocPath: 'if-else' },
- { name: 'import', p5DocPath: false },
- { name: 'in', p5DocPath: false },
- { name: 'instanceof', p5DocPath: false },
- { name: 'new', p5DocPath: false },
{ name: 'return', p5DocPath: 'return' },
- { name: 'super', p5DocPath: false },
- { name: 'switch', p5DocPath: false },
- { name: 'this', p5DocPath: false },
- { name: 'throw', p5DocPath: false },
- { name: 'try', p5DocPath: false },
- { name: 'typeof', p5DocPath: false },
- { name: 'var', p5DocPath: false },
- { name: 'void', p5DocPath: false },
{ name: 'while', p5DocPath: 'while' },
- { name: 'with', p5DocPath: false },
- { name: 'yield', p5DocPath: false },
+ { name: 'with', p5DocPath: undefined },
{ name: 'let', p5DocPath: 'let' }
];
const reservedObjects = [
- { name: 'Array', p5DocPath: false },
- { name: 'Boolean', p5DocPath: false },
- { name: 'Date', p5DocPath: false },
- { name: 'Error', p5DocPath: false },
- { name: 'Function', p5DocPath: false },
+ { name: 'Array', p5DocPath: undefined },
+ { name: 'Boolean', p5DocPath: undefined },
+ { name: 'Date', p5DocPath: undefined },
+ { name: 'Error', p5DocPath: undefined },
+ { name: 'Function', p5DocPath: undefined },
{ name: 'JSON', p5DocPath: 'JSON' },
- { name: 'Math', p5DocPath: false },
- { name: 'Number', p5DocPath: false },
- { name: 'Object', p5DocPath: false },
- { name: 'RegExp', p5DocPath: false },
- { name: 'String', p5DocPath: false },
- { name: 'Promise', p5DocPath: false },
- { name: 'Set', p5DocPath: false },
- { name: 'Map', p5DocPath: false },
- { name: 'Symbol', p5DocPath: false },
- { name: 'WeakMap', p5DocPath: false },
- { name: 'WeakSet', p5DocPath: false },
- { name: 'ArrayBuffer', p5DocPath: false },
- { name: 'DataView', p5DocPath: false },
- { name: 'Int32Array', p5DocPath: false },
- { name: 'Uint32Array', p5DocPath: false },
- { name: 'Float32Array', p5DocPath: false },
- { name: 'window', p5DocPath: false },
- { name: 'document', p5DocPath: false },
- { name: 'navigator', p5DocPath: false },
+ { name: 'Math', p5DocPath: undefined },
+ { name: 'Number', p5DocPath: undefined },
+ { name: 'Object', p5DocPath: undefined },
+ { name: 'RegExp', p5DocPath: undefined },
+ { name: 'String', p5DocPath: undefined },
+ { name: 'Promise', p5DocPath: undefined },
+ { name: 'Set', p5DocPath: undefined },
+ { name: 'Map', p5DocPath: undefined },
+ { name: 'Symbol', p5DocPath: undefined },
+ { name: 'WeakMap', p5DocPath: undefined },
+ { name: 'WeakSet', p5DocPath: undefined },
+ { name: 'ArrayBuffer', p5DocPath: undefined },
+ { name: 'DataView', p5DocPath: undefined },
+ { name: 'Int32Array', p5DocPath: undefined },
+ { name: 'Uint32Array', p5DocPath: undefined },
+ { name: 'Float32Array', p5DocPath: undefined },
+ { name: 'window', p5DocPath: undefined },
+ { name: 'document', p5DocPath: undefined },
+ { name: 'navigator', p5DocPath: undefined },
{ name: 'console', p5DocPath: 'console' },
- { name: 'localStorage', p5DocPath: false },
- { name: 'sessionStorage', p5DocPath: false },
- { name: 'history', p5DocPath: false },
- { name: 'location', p5DocPath: false }
+ { name: 'localStorage', p5DocPath: undefined },
+ { name: 'sessionStorage', p5DocPath: undefined },
+ { name: 'history', p5DocPath: undefined },
+ { name: 'location', p5DocPath: undefined }
];
+function getKindLabel(type) {
+ switch (type) {
+ case 'method':
+ return 'fun';
+ case 'variable':
+ return 'var';
+ case 'constant':
+ return 'const';
+ case 'keyword':
+ return 'kw';
+ case 'boolean':
+ return 'bool';
+ case 'obj':
+ return 'obj';
+ default:
+ return type;
+ }
+}
+
+// create ghost text preview for methods
+function makePreview(label, type, params = []) {
+ const formattedParams = params
+ .map((param) => (param.o ? `[${param.p}]` : param.p))
+ .join(', ');
+
+ if (type === 'method') {
+ return `${label}(${formattedParams})`;
+ }
+
+ return label;
+}
+
+// TODO: add back in reference version switching depending user's p5.js version
axios
.get('https://p5js.org/reference/data.json')
.then((response) => {
@@ -92,49 +101,60 @@ axios
obj.name &&
obj.itemtype
) {
- let type;
+ let itemType;
let params = [];
if (obj.itemtype === 'method') {
- type = 'fun';
+ itemType = 'method';
params = obj.params?.map((param) => ({
p: param.name, // param name
o: param.optional ?? false // optional
}));
} else if (obj.itemtype === 'property') {
- type = 'var';
- } else type = 'attr';
+ itemType = obj.module === 'Constants' ? 'constant' : 'variable';
+ } else itemType = 'attr';
p5Keywords.push({
- text: obj.name,
- type,
+ label: obj.name,
+ type: itemType,
+ kindLabel: getKindLabel(itemType),
params,
- p5: true
+ preview: makePreview(obj.name, itemType, params),
+ p5DocPath: obj.name
});
}
});
['true', 'false'].forEach((bol) => {
p5Keywords.push({
- text: bol,
+ label: bol,
type: 'boolean',
- p5: 'boolean'
+ kindLabel: 'bool',
+ params: [],
+ preview: bol,
+ p5DocPath: 'boolean'
});
});
reservedKeywords.forEach((keyword) => {
p5Keywords.push({
- text: keyword.name,
+ label: keyword.name,
type: 'keyword',
- p5: keyword.p5DocPath
+ kindLabel: 'keyword',
+ params: [],
+ preview: keyword.name,
+ p5DocPath: keyword.p5DocPath
});
});
reservedObjects.forEach((keyword) => {
p5Keywords.push({
- text: keyword.name,
+ label: keyword.name,
type: 'obj',
- p5: keyword.p5DocPath
+ kindLabel: 'obj',
+ params: [],
+ preview: keyword.name,
+ p5DocPath: keyword.p5DocPath
});
});