import { h, Component } from 'preact'; import CodeMirror from '../CodeMirror'; import 'codemirror/addon/edit/matchbrackets.js'; import 'codemirror/addon/edit/matchtags.js'; import 'codemirror/addon/edit/closebrackets.js'; import 'codemirror/addon/edit/closetag.js'; import 'codemirror/addon/comment/comment.js'; import 'codemirror/addon/fold/foldcode.js'; import 'codemirror/addon/fold/foldgutter.js'; import 'codemirror/addon/fold/xml-fold.js'; import 'codemirror/addon/fold/indent-fold.js'; import 'codemirror/addon/fold/comment-fold.js'; import 'codemirror/addon/fold/brace-fold.js'; import 'codemirror/addon/hint/show-hint.js'; import 'codemirror/addon/hint/javascript-hint.js'; import 'codemirror/addon/hint/xml-hint.js'; import 'codemirror/addon/hint/html-hint.js'; import 'codemirror/addon/hint/css-hint.js'; import 'codemirror/addon/selection/active-line.js'; import 'codemirror/addon/search/searchcursor.js'; import 'codemirror/addon/search/search.js'; import 'codemirror/addon/dialog/dialog.js'; import 'codemirror/addon/search/jump-to-line.js'; import 'codemirror/mode/xml/xml.js'; import 'codemirror/mode/css/css.js'; import 'codemirror/mode/javascript/javascript.js'; import 'codemirror/mode/htmlmixed/htmlmixed.js'; import 'codemirror/keymap/sublime.js'; import 'codemirror/keymap/vim.js'; import 'code-blast-codemirror/code-blast.js'; import emmet from '@emmetio/codemirror-plugin'; import { prettify } from '../utils'; emmet(CodeMirror); export default class UserCodeMirror extends Component { componentDidMount() { this.initEditor(); } shouldComponentUpdate(nextProps) { if (nextProps.prefs !== this.props.prefs) { const { prefs } = nextProps; this.cm.setOption('indentWithTabs', prefs.indentWith !== 'spaces'); this.cm.setOption( 'blastCode', prefs.isCodeBlastOn ? { effect: 2, shake: false } : false ); this.cm.setOption('theme', prefs.editorTheme); this.cm.setOption('indentUnit', +prefs.indentSize); this.cm.setOption('tabSize', +prefs.indentSize); this.cm.setOption('keyMap', prefs.keymap); this.cm.setOption('lineWrapping', prefs.lineWrap); this.cm.refresh(); } return false; } initEditor() { const { options, prefs } = this.props; this.cm = CodeMirror.fromTextArea(this.textarea, { mode: options.mode, lineNumbers: true, lineWrapping: !!prefs.lineWrap, autofocus: options.autofocus || false, autoCloseBrackets: true, autoCloseTags: true, matchBrackets: true, matchTags: options.matchTags || false, tabMode: 'indent', keyMap: prefs.keyMap || 'sublime', theme: prefs.editorTheme || 'monokai', lint: !!options.lint, tabSize: +prefs.indentSize || 2, indentWithTabs: prefs.indentWith !== 'spaces', indentUnit: +prefs.indentSize, foldGutter: true, styleActiveLine: true, gutters: options.gutters || [], // cursorScrollMargin: '20', has issue with scrolling profile: options.profile || '', extraKeys: { Up: function(editor) { // Stop up/down keys default behavior when saveditempane is open // if (isSavedItemsPaneOpen) { // return; // } CodeMirror.commands.goLineUp(editor); }, Down: function(editor) { // if (isSavedItemsPaneOpen) { // return; // } CodeMirror.commands.goLineDown(editor); }, 'Shift-Tab': function(editor) { if (options.prettier) { prettify({ content: editor.getValue(), type: options.prettierParser }).then(formattedCode => editor.setValue(formattedCode)); } else { CodeMirror.commands.indentAuto(editor); } }, Tab: function(editor) { if (options.emmet) { const didEmmetWork = editor.execCommand('emmetExpandAbbreviation'); if (didEmmetWork === true) { return; } } const input = $('[data-setting=indentWith]:checked'); if ( !editor.somethingSelected() && (!prefs.indentWith || prefs.indentWith === 'spaces') ) { // softtabs adds spaces. This is required because by default tab key will put tab, but we want // to indent with spaces if `spaces` is preferred mode of indentation. // `somethingSelected` needs to be checked otherwise, all selected code is replaced with softtab. CodeMirror.commands.insertSoftTab(editor); } else { CodeMirror.commands.defaultTab(editor); } }, Enter: 'emmetInsertLineBreak' } }); this.cm.on('focus', editor => { if (typeof this.props.onFocus === 'function') this.props.onFocus(editor); }); this.cm.on('change', this.props.onChange); this.cm.addKeyMap({ 'Ctrl-Space': 'autocomplete' }); this.cm.on('inputRead', (editor, input) => { // Process further If this has autocompletition on and also the global // autocomplete setting is on. if (!this.props.options.noAutocomplete && this.props.prefs.autoComplete) { if ( input.origin !== '+input' || input.text[0] === ';' || input.text[0] === ',' || input.text[0] === ' ' ) { return; } CodeMirror.commands.autocomplete(this.cm, null, { completeSingle: false }); } }); this.props.onCreation(this.cm); } render() { return (