Преглед изворни кода

Merge pull request #2400 from ellisonbg/markdown-code-blocks

Markdown code block fixes
Brian E. Granger пре 8 година
родитељ
комит
92f2040cee

+ 25 - 38
packages/coreutils/src/markdowncodeblocks.ts

@@ -8,7 +8,7 @@
 export
 namespace MarkdownCodeBlocks {
   export
-  const markdownMarkers: string[] = ["```", "~~~~", "`"]
+  const CODE_BLOCK_MARKER = "```";
   const markdownExtensions: string[] = [
     '.markdown',
     '.mdown',
@@ -60,58 +60,45 @@ namespace MarkdownCodeBlocks {
     }
 
     const lines = text.split("\n");
-    const codeSnippets: MarkdownCodeBlock[] = [];
-    var currentCode = null;
+    const codeBlocks: MarkdownCodeBlock[] = [];
+    var currentBlock = null;
     for (var lineIndex = 0; lineIndex < lines.length; lineIndex++) {
       const line = lines[lineIndex];
-      const marker = findNextMarker(line);
-      const lineContainsMarker = marker != '';
-      const constructingSnippet = currentCode != null;
-      //skip this line if it is not part of any code snippet and doesn't contain a marker
-      if (!lineContainsMarker && !constructingSnippet) {
+      const lineContainsMarker = line.indexOf(CODE_BLOCK_MARKER) === 0;
+      const constructingBlock = currentBlock != null;
+      // Skip this line if it is not part of any code block and doesn't contain a marker.
+      if (!lineContainsMarker && !constructingBlock) {
         continue;
       }
 
-      //check if we are already constructing a code snippet
-      if (!constructingSnippet) {
-        //start constructing
-        currentCode = new MarkdownCodeBlock(lineIndex);
+      // Check if we are already constructing a code block.
+      if (!constructingBlock) {
+        // Start constructing a new code block.
+        currentBlock = new MarkdownCodeBlock(lineIndex);
 
-        //check whether this is a single line code snippet
-        const firstIndex = line.indexOf(marker);
-        const lastIndex = line.lastIndexOf(marker);
+        // Check whether this is a single line code block of the form ```a = 10```.
+        const firstIndex = line.indexOf(CODE_BLOCK_MARKER);
+        const lastIndex = line.lastIndexOf(CODE_BLOCK_MARKER);
         const isSingleLine = firstIndex != lastIndex
         if (isSingleLine) {
-          currentCode.code = line.substring(firstIndex + marker.length, lastIndex);
-          currentCode.endLine = lineIndex;
-          codeSnippets.push(currentCode);
-          currentCode = null;
-        } else {
-          currentCode.code = line.substring(firstIndex + marker.length);
+          currentBlock.code = line.substring(firstIndex + CODE_BLOCK_MARKER.length, lastIndex);
+          currentBlock.endLine = lineIndex;
+          codeBlocks.push(currentBlock);
+          currentBlock = null;
         }
       } else {
-        //already constructing
         if (lineContainsMarker) {
-          currentCode.code += "\n" + line.substring(0, line.indexOf(marker));
-          currentCode.endLine = lineIndex;
-          codeSnippets.push(currentCode);
-          currentCode = null;
+          // End of block, finish it up.
+          currentBlock.endLine = lineIndex-1;
+          codeBlocks.push(currentBlock);
+          currentBlock = null;
         } else {
-          currentCode.code += "\n" + line;
+          // Append the current line.
+          currentBlock.code += line + "\n";
         }
       }
     }
-    return codeSnippets;
+    return codeBlocks;
   }
 
-
-  function findNextMarker(text: string) {
-    for (let marker of markdownMarkers) {
-      const index = text.indexOf(marker);
-      if (index > -1) {
-        return marker;
-      }
-    }
-    return '';
-  }
 }

+ 5 - 13
packages/fileeditor-extension/src/index.ts

@@ -198,6 +198,7 @@ function activate(app: JupyterLab, registry: IDocumentRegistry, restorer: ILayou
 
   commands.addCommand(CommandIDs.runCode, {
     execute: () => {
+      // This will run the current selection or the entire ```fenced``` code block.
       const widget = tracker.currentWidget;
 
       if (!widget) {
@@ -205,7 +206,6 @@ function activate(app: JupyterLab, registry: IDocumentRegistry, restorer: ILayou
       }
 
       let code = '';
-
       const editor = widget.editor;
       const path = widget.context.path;
       const extension = PathExt.extname(path);
@@ -219,9 +219,6 @@ function activate(app: JupyterLab, registry: IDocumentRegistry, restorer: ILayou
         const end = editor.getOffsetAt(selection.end);
 
         code = editor.model.value.text.substring(start, end);
-        if (start === end) {
-          code = editor.getLine(selection.start.line);
-        }
       } else if (MarkdownCodeBlocks.isMarkdown(extension)) {
         const { text } = editor.model.value;
         const blocks = MarkdownCodeBlocks.findMarkdownCodeBlocks(text);
@@ -234,17 +231,12 @@ function activate(app: JupyterLab, registry: IDocumentRegistry, restorer: ILayou
         }
       }
 
-      const { column, line } = editor.getCursorPosition();
       const activate = false;
-
-      // Advance cursor to the next line.
-      if (line + 1 === editor.lineCount) {
-        const text = editor.model.value.text;
-        editor.model.value.text = text + '\n';
+      if (code) {
+        return commands.execute('console:inject', { activate, code, path });
+      } else {
+        return Promise.resolve(void 0);
       }
-      editor.setCursorPosition({ column, line: line + 1 });
-
-      return commands.execute('console:inject', { activate, code, path });
     },
     isEnabled: hasWidget,
     label: 'Run Code'

+ 18 - 69
test/src/coreutils/markdowncodeblocks.spec.ts

@@ -9,6 +9,10 @@ import {
   MarkdownCodeBlocks
 } from '@jupyterlab/coreutils';
 
+const BLOCK1 = "Here is text\n\n```\na = 10\nb = 20\n```\n\nMore text.";
+const BLOCK2 = "Here is text\n\n```a = 10```\n\nMore text.";
+const BLOCK3 = "Here is text\n\n```python\na = 10\nb = 20\n```\n\nMore text.";
+
 
 describe('@jupyterlab/coreutils', () => {
 
@@ -17,85 +21,30 @@ describe('@jupyterlab/coreutils', () => {
     describe('.isMarkdown()', () => {
       it('should return true for a valid markdown extension', () => {
         let isMarkdown = MarkdownCodeBlocks.isMarkdown(".md");
-        expect(isMarkdown).true
+        expect(isMarkdown).true;
       });
 
     });
 
-    function performTest(text: string, startLine: number, endLine: number) {
-      for (let marker of MarkdownCodeBlocks.markdownMarkers) {
-        let markdown1 = marker + text + marker;
-        let cb = MarkdownCodeBlocks.findMarkdownCodeBlocks(markdown1)[0];
-        expect(cb.code).to.equal(text);
-        expect(cb.startLine).to.equal(startLine);
-        expect(cb.endLine).to.equal(endLine);
-      }
-    }
-
     describe('.findMarkdownCodeBlocks()', () => {
-      it('should return the codeblock for all delimiters', () => {
-        performTest("print(\"foobar\");\nprint(\"blahblah\")", 0, 1);
+      it('should find a simple block', () => {
+        let codeblocks = MarkdownCodeBlocks.findMarkdownCodeBlocks(BLOCK1);
+        expect(codeblocks.length).to.equal(1);
+        expect(codeblocks[0].code).to.equal('a = 10\nb = 20\n');
       });
 
-      it('should return all codeblocks for multiline text', () => {
-        let text = `print("foo");
-        import os;
-        print("helloworld!")`;
-        performTest(text, 0, 2);
+      it('should find a single line block', () => {
+        let codeblocks = MarkdownCodeBlocks.findMarkdownCodeBlocks(BLOCK2);
+        expect(codeblocks.length).to.equal(1);
+        expect(codeblocks[0].code).to.equal('a = 10');
       });
 
-      it('should return all codeblocks for text containing multiple delimiters', () => {
-        let text = `
-          pop goes the weasel!
-          \`print("amazing!");\`
-          \`
-          print("amazing!");
-          \`
-          \`print("amazing!");
-          \`
-          \`
-          print("amazing!");\`
-          
-          \`\`\`print("with triple quotes");\`\`\`
-          \`\`\`print("with triple quotes");
-          print("and multiline");
-          \`\`\`
-          \`\`\`
-          print("with triple quotes");
-          \`\`\`
-          \`\`\`
-          print("with triple quotes");\`\`\`
-
-          wheels on the bus go round and round!
-
-          ~~~~print("how about this?");~~~~
-          ~~~~
-          print("how about this?");
-          ~~~~
-          ~~~~
-          print("how about this?");~~~~
-          ~~~~print("how about this?");
-          ~~~~
-        `;
-
-        let codeblocks = MarkdownCodeBlocks.findMarkdownCodeBlocks(text);
-        expect(codeblocks.length).to.equal(12);
-        expect(codeblocks[0].code, 'cb0').to.equal('print("amazing!");')
-        expect(codeblocks[1].code, 'cb1').to.equal('\n          print("amazing!");\n          ')
-        expect(codeblocks[2].code, 'cb2').to.equal('print("amazing!");\n          ')
-        expect(codeblocks[3].code, 'cb3').to.equal('\n          print("amazing!");')
-
-        expect(codeblocks[4].code, 'cb4').to.equal('print("with triple quotes");')
-        expect(codeblocks[5].code, 'cb5').to.equal('print("with triple quotes");\n          print("and multiline");\n          ');
-        expect(codeblocks[6].code, 'cb6').to.equal('\n          print("with triple quotes");\n          ')
-        expect(codeblocks[7].code, 'cb7').to.equal('\n          print("with triple quotes");')
-
-        expect(codeblocks[8].code, 'cb8').to.equal('print("how about this?");')
-        expect(codeblocks[9].code, 'cb9').to.equal('\n          print("how about this?");\n          ')
-        expect(codeblocks[10].code, 'cb10').to.equal('\n          print("how about this?");')
-        expect(codeblocks[11].code, 'cb11').to.equal('print("how about this?");\n          ')
-
+      it('should find a block with a language', () => {
+        let codeblocks = MarkdownCodeBlocks.findMarkdownCodeBlocks(BLOCK1);
+        expect(codeblocks.length).to.equal(1);
+        expect(codeblocks[0].code).to.equal('a = 10\nb = 20\n');
       });
+
     });
 
   });