packages/insomnia-app/app/ui/components/codemirror/code-editor.js
/**
   * Sets options on the CodeMirror editor while also sanitizing them
   */
Sets options on the CodeMirror editor while also sanitizing them
Sets options on the CodeMirror editor while also sanitizing them
async _codemirrorSetOptions() {
    const {
      mode: rawMode,
      autoCloseBrackets,
      dynamicHeight,
      getAutocompleteConstants,
      getRenderContext,
      hideGutters,
      hideLineNumbers,
      hideScrollbars,
      hintOptions,
      indentSize,
      indentWithTabs,
      infoOptions,
      jumpOptions,
      keyMap,
      lineWrapping,
      lintOptions,
      noDragDrop,
      noLint,
      noMatchBrackets,
      noStyleActiveLine,
      placeholder,
      readOnly,
      tabIndex,
    } = this.props;
    let mode;
    if (this.props.render) {
      mode = { name: 'nunjucks', baseMode: CodeEditor._normalizeMode(rawMode) };
    } else {
      mode = CodeEditor._normalizeMode(rawMode);
    }
    const isYaml = typeof rawMode === 'string' ? rawMode.includes('yaml') : false;
    const actuallyIndentWithTabs = indentWithTabs && !isYaml;
    const options = {
      readOnly: !!readOnly,
      placeholder: placeholder || '',
      mode: mode,
      tabIndex: typeof tabIndex === 'number' ? tabIndex : null,
      dragDrop: !noDragDrop,
      scrollbarStyle: hideScrollbars ? 'null' : 'native',
      styleActiveLine: !noStyleActiveLine,
      lineNumbers: !hideGutters && !hideLineNumbers,
      foldGutter: !hideGutters && !hideLineNumbers,
      lineWrapping: lineWrapping,
      indentWithTabs: actuallyIndentWithTabs,
      matchBrackets: !noMatchBrackets,
      lint: !noLint && !readOnly,
      gutters: [],
    };
    if (!readOnly && keyMap) {
      options.keyMap = keyMap;
    }
    if (indentSize) {
      options.tabSize = indentSize;
      options.indentUnit = indentSize;
    }
    if (!hideGutters && options.lint) {
      options.gutters.push('CodeMirror-lint-markers');
    }
    if (!hideGutters && options.lineNumbers) {
      options.gutters.push('CodeMirror-linenumbers');
    }
    if (!hideGutters && options.foldGutter) {
      options.gutters.push('CodeMirror-foldgutter');
    }
    if (hintOptions) {
      options.hintOptions = hintOptions;
    }
    if (infoOptions) {
      options.info = infoOptions;
    }
    if (jumpOptions) {
      options.jump = jumpOptions;
    }
    if (lintOptions) {
      options.lint = lintOptions;
    }
    if (typeof autoCloseBrackets === 'boolean') {
      options.autoCloseBrackets = autoCloseBrackets;
    }
    if (getRenderContext || getAutocompleteConstants) {
      let getVariables = null;
      let getTags = null;
      if (getRenderContext) {
        getVariables = async () => {
          const context = await getRenderContext();
          const variables = context ? context.keys : [];
          return variables || [];
        };
        getTags = async () => {
          const expandedTags = [];
          for (const tagDef of await getTagDefinitions()) {
            const firstArg = tagDef.args[0];
            if (!firstArg || firstArg.type !== 'enum') {
              expandedTags.push(tagDef);
              continue;
            }
            for (const option of tagDef.args[0].options) {
              const optionName = misc.fnOrString(option.displayName, tagDef.args) || option.name;
              const newDef = clone(tagDef);
              newDef.displayName = `${tagDef.displayName} ⇒ ${optionName}`;
              newDef.args[0].defaultValue = option.value;
              expandedTags.push(newDef);
            }
          }
          return expandedTags;
        };
      }
      options.environmentAutocomplete = {
        getVariables,
        getTags,
        getConstants: getAutocompleteConstants,
      };
    }
    if (dynamicHeight) {
      options.viewportMargin = Infinity;
    }
    const cm = this.codeMirror;
    Object.keys(options).map(key => {
      let shouldSetOption = false;
      if (key === 'jump' || key === 'info' || key === 'lint' || key === 'hintOptions') {
        shouldSetOption = JSON.stringify(options[key]) !== JSON.stringify(cm.options[key]);
      } else if (!deepEqual(options[key], cm.options[key])) {
        shouldSetOption = true;
      }
      if (shouldSetOption) {
        cm.setOption(key, options[key]);
      }
    });
  }
async _codemirrorSetOptions ( ) { const { mode : rawMode , autoCloseBrackets , dynamicHeight , getAutocompleteConstants , getRenderContext , hideGutters , hideLineNumbers , hideScrollbars , hintOptions , indentSize , indentWithTabs , infoOptions , jumpOptions , keyMap , lineWrapping , lintOptions , noDragDrop , noLint , noMatchBrackets , noStyleActiveLine , placeholder , readOnly , tabIndex , } = this . props ; let mode ; if ( this . props . render ) { mode = { name : 'nunjucks' , baseMode : CodeEditor . _normalizeMode ( rawMode ) } ; } else { mode = CodeEditor . _normalizeMode ( rawMode ) ; } const isYaml = typeof rawMode === 'string' ? rawMode . includes ( 'yaml' ) : false ; const actuallyIndentWithTabs = indentWithTabs && ! isYaml ; const options = { readOnly : ! ! readOnly , placeholder : placeholder || '' , mode : mode , tabIndex : typeof tabIndex === 'number' ? tabIndex : null , dragDrop : ! noDragDrop , scrollbarStyle : hideScrollbars ? 'null' : 'native' , styleActiveLine : ! noStyleActiveLine , lineNumbers : ! hideGutters && ! hideLineNumbers , foldGutter : ! hideGutters && ! hideLineNumbers , lineWrapping : lineWrapping , indentWithTabs : actuallyIndentWithTabs , matchBrackets : ! noMatchBrackets , lint : ! noLint && ! readOnly , gutters : [ ] , } ; if ( ! readOnly && keyMap ) { options . keyMap = keyMap ; } if ( indentSize ) { options . tabSize = indentSize ; options . indentUnit = indentSize ; } if ( ! hideGutters && options . lint ) { options . gutters . push ( 'CodeMirror-lint-markers' ) ; } if ( ! hideGutters && options . lineNumbers ) { options . gutters . push ( 'CodeMirror-linenumbers' ) ; } if ( ! hideGutters && options . foldGutter ) { options . gutters . push ( 'CodeMirror-foldgutter' ) ; } if ( hintOptions ) { options . hintOptions = hintOptions ; } if ( infoOptions ) { options . info = infoOptions ; } if ( jumpOptions ) { options . jump = jumpOptions ; } if ( lintOptions ) { options . lint = lintOptions ; } if ( typeof autoCloseBrackets === 'boolean' ) { options . autoCloseBrackets = autoCloseBrackets ; } if ( getRenderContext || getAutocompleteConstants ) { let getVariables = null ; let getTags = null ; if ( getRenderContext ) { getVariables = async ( ) => { const context = await getRenderContext ( ) ; const variables = context ? context . keys : [ ] ; return variables || [ ] ; } ; getTags = async ( ) => { const expandedTags = [ ] ; for ( const tagDef of await getTagDefinitions ( ) ) { const firstArg = tagDef . args [ 0 ] ; if ( ! firstArg || firstArg . type !== 'enum' ) { expandedTags . push ( tagDef ) ; continue ; } for ( const option of tagDef . args [ 0 ] . options ) { const optionName = misc . fnOrString ( option . displayName , tagDef . args ) || option . name ; const newDef = clone ( tagDef ) ; newDef . displayName = ` ${ tagDef . displayName } op tionName}` ; newDef . args [ 0 ] . defaultValue = option . value ; expandedTags . push ( newDef ) ; } } return expandedTags ; } ; } options . environmentAutocomplete = { getVariables , getTags , getConstants : getAutocompleteConstants , } ; } if ( dynamicHeight ) { options . viewportMargin = Infinity ; } const cm = this . codeMirror ; Object . keys ( options ) . map ( key => { let shouldSetOption = false ; if ( key === 'jump' || key === 'info' || key === 'lint' || key === 'hintOptions' ) { shouldSetOption = JSON . stringify ( options [ key ] ) !== JSON . stringify ( cm . options [ key ] ) ; } else if ( ! deepEqual ( options [ key ] , cm . options [ key ] ) ) { shouldSetOption = true ; } if ( shouldSetOption ) { cm . setOption ( key , options [ key ] ) ; } } ) ; }
Sets options on the CodeMirror editor while also sanitizing them
Sets options on the CodeMirror editor while also sanitizing them
// foo bar baz // NOTE: YAML is not valid when indented with Tabs // Only set keyMap if we're not read-only. This is so things like // ctrl-a work on read-only mode. // Setup the hint options // Only allow tags if we have variables too // Strip of charset if there is one // Use stringify here because these could be infinitely recursive due to GraphQL // schemas // Don't set the option if it hasn't changed