فهرست منبع

Add python file support (#117)

Adds a table of contents for python scripts (.py) files, 
with imports, classes and methods displayed. 

Fixes #9
Martha Cryan 5 سال پیش
والد
کامیت
1b892970fe

+ 5 - 0
packages/toc/src/extension.ts

@@ -17,6 +17,7 @@ import {
   createLatexGenerator,
   createNotebookGenerator,
   createMarkdownGenerator,
+  createPythonGenerator,
   createRenderedMarkdownGenerator
 } from './generators';
 import {
@@ -92,6 +93,10 @@ function activateTOC(
   const latexGenerator = createLatexGenerator(editorTracker);
   registry.add(latexGenerator);
 
+  // Create a Python generator:
+  const pythonGenerator = createPythonGenerator(editorTracker);
+  registry.add(pythonGenerator);
+
   // Update the ToC when the active widget changes:
   labShell.currentChanged.connect(onConnect);
 

+ 1 - 0
packages/toc/src/generators/index.ts

@@ -5,3 +5,4 @@
 export * from './latex';
 export * from './markdown';
 export * from './notebook';
+export * from './python';

+ 101 - 0
packages/toc/src/generators/python/index.ts

@@ -0,0 +1,101 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import { IDocumentWidget } from '@jupyterlab/docregistry';
+import { FileEditor, IEditorTracker } from '@jupyterlab/fileeditor';
+import { TableOfContentsRegistry as Registry } from '../../registry';
+import { IHeading } from '../../utils/headings';
+import { render } from './render';
+
+/**
+ * Generates a table of contents.
+ *
+ * @private
+ * @param editor - editor widget
+ * @returns a list of headings
+ */
+function generate(editor: IDocumentWidget<FileEditor>): IHeading[] {
+  // Split the text into lines:
+  let lines = editor.content.model.value.text.split('\n') as Array<any>;
+
+  // Iterate over the lines to get the heading level and text for each line:
+  let headings: IHeading[] = [];
+  let processingImports = false;
+  for (let i = 0; i < lines.length; i++) {
+    let line = lines[i].trim();
+    if (line.indexOf('def ') === 0) {
+      processingImports = false;
+      headings.push({
+        text: line.slice(0, -1),
+        level: 2,
+        onClick: onClick(i)
+      });
+    } else if (line.indexOf('class ') === 0) {
+      processingImports = false;
+      headings.push({
+        text: line.slice(0, -1),
+        level: 1,
+        onClick: onClick(i)
+      });
+    } else if (line.indexOf('import ') == 0 && !processingImports) {
+      processingImports = true;
+      headings.push({
+        text: line,
+        level: 2,
+        onClick: onClick(i)
+      });
+    }
+  }
+  return headings;
+
+  /**
+   * Returns a "click" handler.
+   *
+   * @private
+   * @param line - line number
+   * @returns click handler
+   */
+  function onClick(line: number) {
+    return () => {
+      editor.content.editor.setCursorPosition({
+        line: line,
+        column: 0
+      });
+    };
+  }
+}
+
+/**
+ * Returns a boolean indicating whether this ToC generator is enabled.
+ *
+ * @private
+ * @param editor - editor widget
+ * @returns boolean indicating whether this ToC generator is enabled
+ */
+function isEnabled(editor: IDocumentWidget<FileEditor>) {
+  let mime = editor.content.model.mimeType;
+  return mime === 'application/x-python-code' || mime === 'text/x-python';
+}
+
+/**
+ * Returns a ToC generator for Python files.
+ *
+ * @private
+ * @param tracker - file editor tracker
+ * @returns ToC generator capable of parsing Python files
+ */
+function createPythonGenerator(
+  tracker: IEditorTracker
+): Registry.IGenerator<IDocumentWidget<FileEditor>> {
+  return {
+    tracker,
+    isEnabled: isEnabled,
+    itemRenderer: render,
+    generate: generate
+  };
+}
+
+/**
+ * Exports.
+ */
+export { createPythonGenerator };

+ 23 - 0
packages/toc/src/generators/python/render.tsx

@@ -0,0 +1,23 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import * as React from 'react';
+import { IHeading } from '../../utils/headings';
+
+/**
+ * Renders a Python table of contents item.
+ *
+ * @private
+ * @param item - numbered heading
+ * @returns rendered item
+ */
+function render(item: IHeading) {
+  let fontSizeClass = 'toc-level-size-' + item.level;
+
+  return <span className={fontSizeClass}> {item.text} </span>;
+}
+
+/**
+ * Exports.
+ */
+export { render };