|
@@ -96,6 +96,21 @@ function activate(app: JupyterLab, registry: IDocumentRegistry, restorer: ILayou
|
|
|
shell
|
|
|
});
|
|
|
|
|
|
+ const markdownMarkers: string[] = ["```", "~~~~", "`"]
|
|
|
+ const markdownExtensions: string[] = [
|
|
|
+ '.markdown',
|
|
|
+ '.mdown',
|
|
|
+ '.mkdn',
|
|
|
+ '.md',
|
|
|
+ '.mkd',
|
|
|
+ '.mdwn',
|
|
|
+ '.mdtxt',
|
|
|
+ '.mdtext',
|
|
|
+ '.text',
|
|
|
+ '.txt',
|
|
|
+ '.Rmd'
|
|
|
+ ];
|
|
|
+
|
|
|
let lineNumbers = true;
|
|
|
let wordWrap = true;
|
|
|
|
|
@@ -174,6 +189,95 @@ function activate(app: JupyterLab, registry: IDocumentRegistry, restorer: ILayou
|
|
|
return tracker.currentWidget !== null;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ class CodeSnippet {
|
|
|
+ startLine: number;
|
|
|
+ endLine: number;
|
|
|
+ code: string;
|
|
|
+ constructor(startLine: number) {
|
|
|
+ this.startLine = startLine;
|
|
|
+ this.code = "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function findNextMarker(text: string) {
|
|
|
+ for (let marker of markdownMarkers) {
|
|
|
+ const index = text.indexOf(marker);
|
|
|
+ if (index > -1) {
|
|
|
+ return marker;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * Construct all code snippets from current text
|
|
|
+ * (this could be potentially optimized if we can cache and detect differences)
|
|
|
+ */
|
|
|
+ function findCodeSnippets(): CodeSnippet[] {
|
|
|
+ let widget = tracker.currentWidget;
|
|
|
+ if (!widget) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ const lines = widget.editor.model.value.text.split("\n");
|
|
|
+ const codeSnippets: CodeSnippet[] = [];
|
|
|
+ var currentCode = 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) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ //check if we are already constructing a code snippet
|
|
|
+ if (!constructingSnippet) {
|
|
|
+ //start constructing
|
|
|
+ currentCode = new CodeSnippet(lineIndex);
|
|
|
+
|
|
|
+ //check whether this is a single line code snippet
|
|
|
+ const firstIndex = line.indexOf(marker);
|
|
|
+ const lastIndex = line.lastIndexOf(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);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //already constructing
|
|
|
+ if (lineContainsMarker) {
|
|
|
+ currentCode.code += "\n" + line.substring(0, line.indexOf(marker));
|
|
|
+ currentCode.endLine = lineIndex;
|
|
|
+ codeSnippets.push(currentCode);
|
|
|
+ currentCode = null;
|
|
|
+ } else {
|
|
|
+ currentCode.code += "\n" + line;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return codeSnippets;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** To detect if there is no current selection */
|
|
|
+ function hasSelection(): boolean {
|
|
|
+ let widget = tracker.currentWidget;
|
|
|
+ if (!widget) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const editor = widget.editor;
|
|
|
+ const selection = editor.getSelection();
|
|
|
+ if (selection.start.column == selection.end.column &&
|
|
|
+ selection.start.line == selection.end.line) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
commands.addCommand(CommandIDs.lineNumbers, {
|
|
|
execute: toggleLineNums,
|
|
|
isEnabled: hasWidget,
|
|
@@ -211,18 +315,33 @@ function activate(app: JupyterLab, registry: IDocumentRegistry, restorer: ILayou
|
|
|
if (!widget) {
|
|
|
return;
|
|
|
}
|
|
|
- // Get the selected code from the editor.
|
|
|
+
|
|
|
+ var code = ""
|
|
|
const editor = widget.editor;
|
|
|
- const selection = editor.getSelection();
|
|
|
- const start = editor.getOffsetAt(selection.start);
|
|
|
- const end = editor.getOffsetAt(selection.end);
|
|
|
- let targetText = editor.model.value.text.substring(start, end);
|
|
|
- if (start == end) {
|
|
|
- targetText = editor.getLine(selection.start.line);
|
|
|
+ const extension = widget.context.path.substring(widget.context.path.lastIndexOf("."));
|
|
|
+ if (!hasSelection() && markdownExtensions.indexOf(extension) > -1) {
|
|
|
+ var snippets = findCodeSnippets();
|
|
|
+ for (let codeSnippet of snippets) {
|
|
|
+ if (codeSnippet.startLine <= editor.getSelection().start.line &&
|
|
|
+ editor.getSelection().start.line <= codeSnippet.endLine) {
|
|
|
+ code = codeSnippet.code;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // Get the selected code from the editor.
|
|
|
+ const selection = editor.getSelection();
|
|
|
+ const start = editor.getOffsetAt(selection.start);
|
|
|
+ const end = editor.getOffsetAt(selection.end);
|
|
|
+ code = editor.model.value.text.substring(start, end);
|
|
|
+ if (start == end) {
|
|
|
+ code = editor.getLine(selection.start.line);
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
const options: JSONObject = {
|
|
|
path: widget.context.path,
|
|
|
- code: targetText,
|
|
|
+ code: code,
|
|
|
activate: false
|
|
|
};
|
|
|
// Advance cursor to the next line.
|