function registerGenerator(name, language, generator, isReadOnly) {
        const tabElement = renderCodeTab(name);
        tabElement.setAttribute('data-tab', name);
        tabsDiv.appendChild(tabElement);

        // Create a monaco editor model for each tab.
        const model = window.monaco.editor.createModel('', language);
        const state = {
          name,
          model,
          language,
          viewState: undefined,
        };

        /**
         * Call the generator, displaying an error message if it fails.
         */
        function generate() {
          let text;
          let generateModel = model;
          try {
            text = generator(workspace);
          } catch (e) {
            console.error(e);
            text = e.message;
            generateModel = errorModel;
            editor.updateOptions({
              wordWrap: true,
            });
          }
          if (
            generateModel.getValue() === text &&
            editor.getModel() === generateModel
          ) {
            return;
          }
          generateModel.pushEditOperations(
            [],
            [{range: generateModel.getFullModelRange(), text}],
            () => null,
          );
          editor.setModel(generateModel);
          editor.setSelection(new window.monaco.Range(0, 0, 0, 0));
        }

        const tab = {
          generate,
          state,
          tabElement,
        };
        return tab;
      }
Register a generator and create a new code tab for it.
@param {string} name The generator label.
@param {string} language The monaco language to use.
@param {function(Blockly.WorkspaceSvg):string} generator
    The Blockly generator.
@param {boolean=} isReadOnly Whether the editor should be set to
    read-only mode.
@returns {!PlaygroundTab} An object that represents the newly created
    tab.