$scope.aceLoaded = function()

in zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js [774:1041]


  $scope.aceLoaded = function(_editor) {
    let langTools = ace.require('ace/ext/language_tools');
    let Range = ace.require('ace/range').Range;

    _editor.$blockScrolling = Infinity;
    $scope.editor = _editor;
    $scope.editor.on('input', $scope.aceChanged);
    if (_editor.container.id !== '{{paragraph.id}}_editor') {
      $scope.editor.renderer.setShowGutter($scope.paragraph.config.lineNumbers);
      $scope.editor.setShowFoldWidgets(false);
      $scope.editor.setHighlightActiveLine(false);
      $scope.editor.getSession().setUseWrapMode(true);
      $scope.editor.setTheme('ace/theme/chrome');
      $scope.editor.setReadOnly($scope.isRunning($scope.paragraph) || $scope.isNoteRunning);
      $scope.editor.setHighlightActiveLine($scope.paragraphFocused);

      if ($scope.paragraphFocused) {
        let prefix = getParagraphMagic($scope.paragraph.text);
        let paragraphText = $scope.paragraph.text ? $scope.paragraph.text.trim() : '';

        $scope.editor.focus();
        $scope.goToEnd($scope.editor);
        if (prefix === paragraphText) {
          $timeout(function() {
            $scope.editor.gotoLine(2, 0);
          }, 0);
        }
      }

      autoAdjustEditorHeight(_editor);

      let adjustEditorListener = () => autoAdjustEditorHeight(_editor);
      angular.element(window).resize(adjustEditorListener);
      $scope.$on('$destroy', () => angular.element(window).unbind('resize', adjustEditorListener));

      if (navigator.appVersion.indexOf('Mac') !== -1) {
        $scope.editor.setKeyboardHandler('ace/keyboard/emacs');
        $rootScope.isMac = true;
      } else if (navigator.appVersion.indexOf('Win') !== -1 ||
        navigator.appVersion.indexOf('X11') !== -1 ||
        navigator.appVersion.indexOf('Linux') !== -1) {
        $rootScope.isMac = false;
        // not applying emacs key binding while the binding override Ctrl-v. default behavior of paste text on windows.
      }

      $scope.$on('completionListLength', function(event, data) {
        completionListLength = data;
      });

      $scope.$on('callCompletion', function(event, data) {
        if($scope.paragraphFocused) {
          websocketMsgSrv.completion($scope.paragraph.id, data.buf, data.pos);
        }
      });

      let remoteCompleter = {
        getCompletions: function(editor, session, pos, prefix, callback) {
          let langTools = ace.require('ace/ext/language_tools');
          let defaultKeywords = new Set();

          // eslint-disable-next-line handle-callback-err
          let getDefaultKeywords = function(err, completions) {
            if (completions !== undefined) {
              completions.forEach(function(c) {
                defaultKeywords.add(c.value);
              });
            }
          };
          if (langTools.keyWordCompleter !== undefined) {
            langTools.keyWordCompleter.getCompletions(editor, session, pos, prefix, getDefaultKeywords);
          }

          if (!editor.isFocused()) {
            return;
          }

          pos = session.getTextRange(new Range(0, 0, pos.row, pos.column)).length;
          let buf = session.getValue();

          $rootScope.$broadcast('callCompletion', {buf: buf, pos: pos});

          $scope.$on('completionList', function(event, data) {
            let computeCaption = function(value, meta) {
              let metaLength = meta !== undefined ? meta.length : 0;
              let length = 42;
              let whitespaceLength = 3;
              let ellipses = '...';
              let maxLengthCaption = length - metaLength - whitespaceLength - ellipses.length;
              if (value !== undefined && value.length > maxLengthCaption) {
                return value.substr(0, maxLengthCaption) + ellipses;
              }
              return value;
            };
            if (data.completions) {
              let completions = [];
              for (let c in data.completions) {
                if (data.completions.hasOwnProperty(c)) {
                  let v = data.completions[c];
                  if (v.meta !== undefined && v.meta === 'keyword' && defaultKeywords.has(v.value.trim())) {
                    continue;
                  }
                  completions.push({
                    name: v.name,
                    value: v.value,
                    meta: v.meta,
                    caption: computeCaption(v.name, v.meta),
                    score: 300,
                  });
                }
              }
              $rootScope.$broadcast('completionListLength', completions.length);
              callback(null, completions);
            }
          });
        },
      };

      langTools.setCompleters([remoteCompleter, langTools.keyWordCompleter, langTools.snippetCompleter,
        langTools.textCompleter]);

      $scope.editor.setOptions({
        fontSize: $scope.paragraph.config.fontSize + 'pt',
        enableBasicAutocompletion: true,
        enableSnippets: false,
        enableLiveAutocompletion: false,
      });

      $scope.editor.on('focus', function() {
        handleFocus(true);
      });

      $scope.editor.on('blur', function() {
        handleFocus(false);
        $scope.saveParagraph($scope.paragraph);
      });

      $scope.editor.on('paste', function(e) {
        if (e.text.indexOf('%') === 0) {
          pastePercentSign = true;
        }
      });

      $scope.editor.getSession().on('change', function(e, editSession) {
        autoAdjustEditorHeight(_editor);
      });

      setParagraphMode($scope.editor.getSession(), $scope.editor.getSession().getValue());

      // autocomplete on '.'
      /*
       $scope.editor.commands.on("afterExec", function(e, t) {
       if (e.command.name == "insertstring" && e.args == "." ) {
       var all = e.editor.completers;
       //e.editor.completers = [remoteCompleter];
       e.editor.execCommand("startAutocomplete");
       //e.editor.completers = all;
       }
       });
       */

      // remove binding
      $scope.editor.commands.removeCommand('showSettingsMenu');
      $scope.editor.commands.removeCommand('find');
      $scope.editor.commands.removeCommand('replace');

      let isOption = $rootScope.isMac ? 'option' : 'alt';

      $scope.editor.commands.bindKey('ctrl-' + isOption + '-n.', null);
      $scope.editor.commands.bindKey('ctrl-' + isOption + '-l', null);
      $scope.editor.commands.bindKey('ctrl-' + isOption + '-w', null);
      $scope.editor.commands.bindKey('ctrl-' + isOption + '-a', null);
      $scope.editor.commands.bindKey('ctrl-' + isOption + '-k', null);
      $scope.editor.commands.bindKey('ctrl-' + isOption + '-e', null);
      $scope.editor.commands.bindKey('ctrl-' + isOption + '-t', null);
      $scope.editor.commands.bindKey('ctrl-space', null);

      if ($rootScope.isMac) {
        $scope.editor.commands.bindKey('command-l', null);
      } else {
        $scope.editor.commands.bindKey('ctrl-l', null);
      }

      // autocomplete on 'ctrl+.'
      $scope.editor.commands.bindKey('ctrl-.', 'startAutocomplete');

      // Show autocomplete on tab
      $scope.editor.commands.addCommand({
        name: 'tabAutocomplete',
        bindKey: {
          win: 'tab',
          mac: 'tab',
          sender: 'editor|cli',
        },
        exec: function(env, args, request) {
          let iCursor = $scope.editor.getCursorPosition();
          let currentLine = $scope.editor.session.getLine(iCursor.row);
          let isAllTabs = currentLine.substring(0, iCursor.column - 1).split('').every(function(char) {
            return (char === '\t' || char === ' ');
          });

          // If user has pressed tab on first line char or if isTabCompletion() is false, keep existing behavior
          // If user has pressed tab anywhere in between and editor mode is not %md, show autocomplete
          if (!isAllTabs && iCursor.column && isTabCompletion()) {
            $scope.editor.execCommand('startAutocomplete');
          } else {
            ace.config.loadModule('ace/ext/language_tools', function() {
              $scope.editor.indent();
            });
          }
        },
      });

      let keyBindingEditorFocusAction = function(scrollValue) {
        let numRows = $scope.editor.getSession().getLength();
        let currentRow = $scope.editor.getCursorPosition().row;
        if (currentRow === 0 && scrollValue <= 0) {
          // move focus to previous paragraph
          $scope.$emit('moveFocusToPreviousParagraph', $scope.paragraph.id);
        } else if (currentRow === numRows - 1 && scrollValue >= 0) {
          $scope.$emit('moveFocusToNextParagraph', $scope.paragraph.id);
        } else {
          $scope.scrollToCursor($scope.paragraph.id, scrollValue);
        }
      };

      // handle cursor moves
      $scope.editor.keyBinding.origOnCommandKey = $scope.editor.keyBinding.onCommandKey;
      $scope.editor.keyBinding.onCommandKey = function(e, hashId, keyCode) {
        if ($scope.editor.completer && $scope.editor.completer.activated) { // if autocompleter is active
        } else {
          // fix ace editor focus issue in chrome (textarea element goes to top: -1000px after focused by cursor move)
          if (parseInt(angular.element('#' + $scope.paragraph.id + '_editor > textarea')
              .css('top').replace('px', '')) < 0) {
            let position = $scope.editor.getCursorPosition();
            let cursorPos = $scope.editor.renderer.$cursorLayer.getPixelPosition(position, true);
            angular.element('#' + $scope.paragraph.id + '_editor > textarea').css('top', cursorPos.top);
          }

          let ROW_UP = -1;
          let ROW_DOWN = 1;

          switch (keyCode) {
            case 38:
              if (!e.shiftKey) {
                keyBindingEditorFocusAction(ROW_UP);
              }
              break;
            case 80:
              if (e.ctrlKey && !e.altKey) {
                keyBindingEditorFocusAction(ROW_UP);
              }
              break;
            case 40:
              if (!e.shiftKey) {
                keyBindingEditorFocusAction(ROW_DOWN);
              }
              break;
            case 78:
              if (e.ctrlKey && !e.altKey) {
                keyBindingEditorFocusAction(ROW_DOWN);
              }
              break;
          }
        }
        this.origOnCommandKey(e, hashId, keyCode);
      };
    }
  };