浏览代码

Clean up the codemirror api

Steven Silvester 8 年之前
父节点
当前提交
03908aad77

+ 20 - 4
packages/codemirror/src/editor.ts

@@ -33,7 +33,7 @@ import {
 } from '@jupyterlab/coreutils';
 
 import {
-  loadModeByMIME
+  Mode
 } from './mode';
 
 import 'codemirror/addon/edit/matchbrackets.js';
@@ -492,7 +492,9 @@ class CodeMirrorEditor implements CodeEditor.IEditor {
   private _onMimeTypeChanged(): void {
     const mime = this._model.mimeType;
     let editor = this._editor;
-    loadModeByMIME(editor, mime);
+    Mode.ensure(mime).then(spec => {
+      editor.setOption('mode', spec.mime);
+    });
     let isCode = (mime !== 'text/plain') && (mime !== 'text/x-ipythongfm');
     editor.setOption('matchBrackets', isCode);
     editor.setOption('autoCloseBrackets', isCode);
@@ -713,6 +715,18 @@ namespace CodeMirrorEditor {
    */
   export
   const DEFAULT_THEME: string = 'jupyter';
+
+  /**
+   * Add a command to CodeMirror.
+   *
+   * @param name - The name of the command to add.
+   *
+   * @param command - The command function.
+   */
+  export
+  function addCommand(name: string, command: (cm: CodeMirror.Editor) => void) {
+    CodeMirror.commands[name] = command;
+  }
 }
 
 
@@ -786,7 +800,9 @@ namespace Private {
 
 /**
  * Add a CodeMirror command to delete until previous non blanking space
- * character or first multiple of 4 tabstop.
+ * character or first multiple of tabsize tabstop.
  */
-CodeMirror.commands['delSpaceToPrevTabStop'] = Private.delSpaceToPrevTabStop;
+CodeMirrorEditor.addCommand(
+  'delSpaceToPrevTabStop'], Private.delSpaceToPrevTabStop
+);
 

+ 6 - 9
packages/codemirror/src/mimetype.ts

@@ -1,9 +1,6 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
 
-import * as CodeMirror
-  from 'codemirror';
-
 import {
   IEditorMimeTypeService
 } from '@jupyterlab/codeeditor';
@@ -13,7 +10,7 @@ import {
 } from '@jupyterlab/coreutils';
 
 import {
-  findMode
+  Mode
 } from '.';
 
 /**
@@ -29,19 +26,19 @@ class CodeMirrorMimeTypeService implements IEditorMimeTypeService {
    */
   getMimeTypeByLanguage(info: nbformat.ILanguageInfoMetadata): string {
     if (info.codemirror_mode) {
-      return findMode(info.codemirror_mode as any).mime;
+      return Mode.find(info.codemirror_mode as any).mime;
     }
-    let mode = CodeMirror.findModeByMIME(info.mimetype || '');
+    let mode = Mode.findByMIME(info.mimetype || '');
     if (mode) {
       return info.mimetype!;
     }
     let ext = info.file_extension || '';
     ext = ext.split('.').slice(-1)[0];
-    mode = CodeMirror.findModeByExtension(ext || '');
+    mode = Mode.findByExtension(ext || '');
     if (mode) {
       return mode.mime;
     }
-    mode = CodeMirror.findModeByName(info.name || '');
+    mode = Mode.findByName(info.name || '');
     return mode ? mode.mime : IEditorMimeTypeService.defaultMimeType;
   }
   /**
@@ -54,7 +51,7 @@ class CodeMirrorMimeTypeService implements IEditorMimeTypeService {
     if (PathExt.extname(path) === '.ipy') {
       return 'text/x-python';
     }
-    const mode = CodeMirror.findModeByFileName(path);
+    const mode = Mode.findByFileName(path);
     return mode ? mode.mime : IEditorMimeTypeService.defaultMimeType;
   }
 }

+ 87 - 95
packages/codemirror/src/mode.ts

@@ -24,110 +24,102 @@ declare var require: any;
 
 
 /**
- * The interface of a codemirror mode.
+ * The namespace for CodeMirror Mode functionality.
  */
 export
-interface IModeSpec {
-  [ key: string ]: string;
-  name?: string;
-  mode: string;
-  mime: string;
-}
-
-
-/**
- * Running a CodeMirror mode outside of an editor.
- */
-export
-function runMode(code: string, mode: string | IModeSpec, el: HTMLElement): void {
-  CodeMirror.runMode(code, mode, el);
-}
-
-
-/**
- * Find a mode name by extension.
- */
-export
-function findModeByExtension(ext: string): string {
-  let mode = CodeMirror.findModeByExtension(ext);
-  return mode && mode.mode;
-}
-
-
-/**
- * Load a codemirror mode by file name.
- */
-export
-function loadModeByFileName(editor: CodeMirror.Editor, filename: string): void {
-  loadInfo(editor, CodeMirror.findModeByFileName(filename));
-}
-
-
-/**
- * Load a codemirror mode by mime type.
- */
-export
-function loadModeByMIME(editor: CodeMirror.Editor, mimetype: string): void {
-  loadInfo(editor, CodeMirror.findModeByMIME(mimetype));
-}
-
-
-/**
- * Load a codemirror mode by mode name.
- */
-export
-function loadModeByName(editor: CodeMirror.Editor, mode: string): void {
-  loadInfo(editor, CodeMirror.findModeByName(mode));
-}
-
+namespace Mode {
+  /**
+   * The interface of a codemirror mode spec.
+   */
+  export
+  interface ISpec {
+    [ key: string ]: string;
+    name?: string;
+    mode: string;
+    mime: string;
+  }
 
-/**
- * Find a codemirror mode by name or CodeMirror spec.
- */
-export
-function findMode(mode: string | IModeSpec): IModeSpec {
-  let modename = (typeof mode === 'string') ? mode :
-      mode.mode || mode.name;
-  let mimetype = (typeof mode !== 'string') ? mode.mime : '';
-
-  return (
-    CodeMirror.findModeByName(modename) ||
-    CodeMirror.findModeByMIME(mimetype) ||
-    CodeMirror.modes['null']
-  );
-}
+  /**
+   * Running a CodeMirror mode outside of an editor.
+   */
+  export
+  function run(code: string, mode: string | ISpec, el: HTMLElement): void {
+    CodeMirror.runMode(code, mode, el);
+  }
 
+  /**
+   * Ensure a codemirror mode is available by name or Codemirror spec.
+   *
+   * @param mode - The mode to ensure.  If it is a string, uses [find]
+   *   to get the appropriate spec.
+   *
+   * @returns A promise that resolves when the mode is available.
+   */
+  export
+  function ensure(mode: string | ISpec): Promise<ISpec> {
+    let spec = find(mode);
+    if (!spec) {
+      return CodeMirror.modes['null'];
+    }
+
+    // Simplest, cheapest check by mode name.
+    if (CodeMirror.modes.hasOwnProperty(spec.mode)) {
+      return Promise.resolve(mode);
+    }
+
+    // Fetch the mode asynchronously.
+    return new Promise<CodeMirror.modespec>((resolve, reject) => {
+      require([`codemirror/mode/${spec.mode}/${spec.mode}.js`], () => {
+        resolve(spec);
+      });
+    });
+  }
 
-/**
- * Require a codemirror mode by name or Codemirror spec.
- */
-export
-function requireMode(mode: string | IModeSpec): Promise<IModeSpec> {
-  let info = findMode(mode);
+  /**
+   * Find a codemirror mode by name or CodeMirror spec.
+   */
+  export
+  function find(mode: string | ISpec): ISpec {
+    let modename = (typeof mode === 'string') ? mode :
+        mode.mode || mode.name;
+    let mimetype = (typeof mode !== 'string') ? mode.mime : '';
+
+    return (
+      CodeMirror.findModeByName(modename) ||
+      CodeMirror.findModeByMIME(mimetype) ||
+      CodeMirror.modes['null']
+    );
+  }
 
-  // Simplest, cheapest check by mode name.
-  if (CodeMirror.modes.hasOwnProperty(info.mode)) {
-    return Promise.resolve(info);
+  /**
+   * Find a codemirror mode by MIME.
+   */
+  export
+  function findByMIME(mime: string): ISpec {
+    return CodeMirror.findModeByMIME(mime);
   }
 
-  // Fetch the mode asynchronously.
-  return new Promise<CodeMirror.modespec>((resolve, reject) => {
-    require([`codemirror/mode/${info.mode}/${info.mode}.js`], () => {
-      resolve(info);
-    });
-  });
-}
+  /**
+   * Find a codemirror mode by name.
+   */
+  export
+  function findByName(mime: string): ISpec {
+    return CodeMirror.findModeByName(mime);
+  }
 
+  /**
+   * Find a codemirror mode by filename.
+   */
+  export
+  function findByFileName(name: string): ISpec {
+    return CodeMirror.findModeByFileName(name);
+  }
 
-/**
- * Load a CodeMirror mode based on a mode spec.
- */
-function loadInfo(editor: CodeMirror.Editor, info: CodeMirror.modespec): void {
-  if (!info) {
-    editor.setOption('mode', 'null');
-    return;
+  /**
+   * Find a codemirror mode by extension.
+   */
+  export
+  function findByExtension(name: string): ISpec {
+    return CodeMirror.findModeByExtension(name);
   }
-  requireMode(info).then(() => {
-    editor.setOption('mode', info.mime);
-  });
 }

+ 2 - 2
packages/docregistry/src/default.ts

@@ -2,7 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  findModeByExtension
+  Mode
 } from '@jupyterlab/codemirror';
 
 import {
@@ -228,7 +228,7 @@ class TextModelFactory implements DocumentRegistry.CodeModelFactory {
    * Get the preferred kernel language given an extension.
    */
   preferredLanguage(ext: string): string {
-    return findModeByExtension(ext.slice(1));
+    return Mode.findByExtension(ext.slice(1)).mode;
   }
 
   private _isDisposed = false;

+ 3 - 3
packages/rendermime/src/widgets.ts

@@ -6,7 +6,7 @@ import {
 } from 'ansi_up';
 
 import {
-  requireMode, runMode, CodeMirrorEditor
+  Mode, CodeMirrorEditor
 } from '@jupyterlab/codemirror';
 
 import * as marked
@@ -479,7 +479,7 @@ namespace Private {
                 return code;
             }
         }
-        requireMode(lang).then(spec => {
+        Mode.ensure(lang).then(spec => {
           let el = document.createElement('div');
           if (!spec) {
               console.log(`No CodeMirror mode: ${lang}`);
@@ -487,7 +487,7 @@ namespace Private {
               return;
           }
           try {
-            runMode(code, spec.mime, el);
+            Mode.run(code, spec.mime, el);
             callback(null, el.innerHTML);
           } catch (err) {
             console.log(`Failed to highlight ${lang} code`, err);