Jelajahi Sumber

Add delSpaceToPrevTabStop from Notebook

Steven Silvester 8 tahun lalu
induk
melakukan
79b4e826c8
2 mengubah file dengan 55 tambahan dan 4 penghapusan
  1. 50 3
      src/codemirror/editor.ts
  2. 5 1
      typings/codemirror/codemirror.d.ts

+ 50 - 3
src/codemirror/editor.ts

@@ -486,10 +486,18 @@ class CodeMirrorEditor implements CodeEditor.IEditor {
    */
   protected _onMimeTypeChanged(): void {
     const mime = this._model.mimeType;
-    loadModeByMIME(this._editor, mime);
+    let editor = this._editor;
+    loadModeByMIME(editor, mime);
     let isCode = (mime !== 'text/plain') && (mime !== 'text/x-ipythongfm');
-    this.editor.setOption('matchBrackets', isCode);
-    this.editor.setOption('autoCloseBrackets', isCode);
+    editor.setOption('matchBrackets', isCode);
+    editor.setOption('autoCloseBrackets', isCode);
+    let extraKeys = editor.getOption('extraKeys');
+    if (isCode) {
+      extraKeys['Backspace'] = 'delSpaceToPrevTabStop';
+    } else {
+      delete extraKeys['Backspace'];
+    }
+    editor.setOption('extraKeys', extraKeys);
   }
 
   /**
@@ -667,6 +675,37 @@ defineSignal(CodeMirrorEditor.prototype, 'completionRequested');
 defineSignal(CodeMirrorEditor.prototype, 'edgeRequested');
 
 
+/**
+ * Add a CodeMirror command to delete until previous non blanking space
+ * character or first multiple of 4 tabstop.
+ */
+CodeMirror.commands['delSpaceToPrevTabStop'] = (cm: CodeMirror.Editor) => {
+  let doc = cm.getDoc();
+  let from = doc.getCursor('from');
+  let to = doc.getCursor('to');
+  let sel = !Private.posEq(from, to);
+  if (sel) {
+    let ranges = doc.listSelections();
+    for (let i = ranges.length - 1; i >= 0; i--) {
+      let head = ranges[i].head;
+      let anchor = ranges[i].anchor;
+      doc.replaceRange('', CodeMirror.Pos(head.line, head.ch), CodeMirror.Pos(anchor.line, anchor.ch));
+    }
+    return;
+  }
+  let cur = doc.getCursor();
+  let tabsize = cm.getOption('tabSize');
+  let chToPrevTabStop = cur.ch - (Math.ceil(cur.ch / tabsize) - 1) * tabsize;
+  from = {ch: cur.ch - chToPrevTabStop, line: cur.line};
+  let select = doc.getRange(from, cur);
+  if (select.match(/^\ +$/) !== null) {
+    doc.replaceRange('', from, cur);
+  } else {
+    CodeMirror.commands['delCharBefore'](cm);
+  }
+};
+
+
 /**
  * The namespace for module private data.
  */
@@ -688,4 +727,12 @@ namespace Private {
     config.theme = (config.theme || DEFAULT_CODEMIRROR_THEME);
     config.indentUnit = config.indentUnit || 4;
   }
+
+  /**
+   * Test whether two CodeMirror positions are equal.
+   */
+  export
+  function posEq(a: CodeMirror.Position, b: CodeMirror.Position): boolean {
+    return a.line === b.line && a.ch === b.ch;
+  };
 }

+ 5 - 1
typings/codemirror/codemirror.d.ts

@@ -34,6 +34,10 @@ declare module CodeMirror {
         [key: string]: any;
     }
 
+    var commands: {
+      [key: string]: any;
+    }
+
     interface modeinfo {
       ext: string[];
       mime: string;
@@ -543,7 +547,7 @@ declare module CodeMirror {
          * or set to the last range if the previous selection had less ranges than the new one.
          * Supports the same options as setSelection.
          */
-        setSelections(ranges: CodeMirror.Selection[], primary?: number, options?: any): void; 
+        setSelections(ranges: CodeMirror.Selection[], primary?: number, options?: any): void;
 
         /** Similar to setSelection , but will, if shift is held or the extending flag is set,
         move the head of the selection while leaving the anchor at its current place.