Cleanup: Renamed files and restructured directories

This commit is contained in:
Andrew Head 2019-02-27 19:47:56 -08:00
Родитель 973f460aec
Коммит b1abe3952f
72 изменённых файлов: 437 добавлений и 808 удалений

Просмотреть файл

@ -13,14 +13,14 @@
"homepage": "https://microsoft.github.io/gather/",
"scripts": {
"build": "npm run build:parser && tsc",
"build:parser": "node ./node_modules/jison/lib/cli.js --outfile src/parsers/python/python3.js src/parsers/python/python3.jison",
"build:parser": "node ./node_modules/jison/lib/cli.js --outfile src/analysis/parse/python/python3.js src/analysis/parse/python/python3.jison",
"watch": "tsc -w",
"prepack": "npm run build",
"test": "karma start src/test/karma.conf.js",
"test:debug": "karma start src/test/karma.debug.conf.js",
"clean": "rm -rf lib/"
},
"main": "lib/lab/index.js",
"main": "lib/main/main.js",
"jupyterlab": {
"extension": true,
"schemaDir": "schema"

Просмотреть файл

Просмотреть файл

@ -1,6 +1,6 @@
import * as ast from '../parsers/python/python_parser';
import { Set } from './Set';
import { IDataflow } from './DataflowAnalysis';
import * as ast from '../parse/python/python-parser';
import { IDataflow } from './data-flow';
import { Set } from './set';
export class Block {

Просмотреть файл

@ -1,7 +1,7 @@
import * as ast from '../parsers/python/python_parser';
import { Block, ControlFlowGraph } from './ControlFlowAnalysis';
import { Set, StringSet } from './Set';
import { SlicerConfig } from './SlicerConfig';
import * as ast from '../parse/python/python-parser';
import { Block, ControlFlowGraph } from './control-flow';
import { Set, StringSet } from './set';
import { SlicerConfig } from './slice-config';
/**
* Use a shared dataflow analyzer object for all dataflow analysis / querying for defs and uses.

Просмотреть файл

@ -1,7 +1,8 @@
import { ICell, CellSlice } from "../packages/cell";
import { ProgramBuilder, CellProgram } from "./ProgramBuilder";
import { LocationSet, slice } from "./Slice";
import { DataflowAnalyzer } from "./DataflowAnalysis";
import { ICell } from "../../model/cell";
import { CellSlice } from "../../model/cellslice";
import { DataflowAnalyzer } from "./data-flow";
import { CellProgram, ProgramBuilder } from "./program-builder";
import { LocationSet, slice } from "./slice";
/**
* A record of when a cell was executed.

Просмотреть файл

@ -1,8 +1,8 @@
import { NumberSet } from "./Set";
import * as ast from "../parsers/python/python_parser";
import { MagicsRewriter } from "./MagicsRewriter";
import { ICell } from "../packages/cell/model";
import { Ref, DataflowAnalyzer } from "./DataflowAnalysis";
import { ICell } from "../../model/cell";
import * as ast from "../parse/python/python-parser";
import { DataflowAnalyzer, Ref } from "./data-flow";
import { MagicsRewriter } from "./rewrite-magics";
import { NumberSet } from "./set";
/**
* Maps to find out what line numbers over a program correspond to what cells.

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -1,4 +1,4 @@
import { ReferenceType } from "./DataflowAnalysis";
import { ReferenceType } from "./data-flow";
/**
* Configuration with hints on how to slice.

Просмотреть файл

@ -1,7 +1,7 @@
import { NumberSet, range, Set } from "./Set";
import { ControlFlowGraph } from "./ControlFlowAnalysis";
import { ILocation, parse, IModule } from "../parsers/python/python_parser";
import { DataflowAnalyzer } from "./DataflowAnalysis";
import { ILocation, IModule, parse } from "../parse/python/python-parser";
import { ControlFlowGraph } from "./control-flow";
import { DataflowAnalyzer } from "./data-flow";
import { NumberSet, range, Set } from "./set";
export enum DataflowDirection { Forward, Backward };

Просмотреть файл

@ -1,86 +0,0 @@
import { ICodeCellModel, CodeCellModel } from "@jupyterlab/cells";
import { IOutputModel } from "@jupyterlab/rendermime";
import { UUID } from "@phosphor/coreutils";
import { nbformat } from "@jupyterlab/coreutils";
import { AbstractCell } from "../packages/cell";
/**
* Abstract interface to data of a Jupyter Lab code cell.
*/
export class LabCell extends AbstractCell {
constructor(model: ICodeCellModel) {
super();
this._model = model;
}
get model(): ICodeCellModel {
return this._model;
}
get id(): string {
return this._model.id;
}
get persistentId(): string {
if (!this._model.metadata.has("persistent_id")) {
this._model.metadata.set("persistent_id", UUID.uuid4());
}
return this._model.metadata.get("persistent_id") as string;
}
get text(): string {
return this._model.value.text;
}
set text(text: string) {
this._model.value.text = text;
}
get executionCount(): number {
return this._model.executionCount;
}
set executionCount(count: number) {
this._model.executionCount = count;
}
get isCode(): boolean {
return this._model.type == "code";
}
get hasError(): boolean {
return this.output.some(o => o.type === 'error');
}
get output(): IOutputModel[] {
let outputs = [];
if (this._model.outputs) {
for (let i = 0; i < this._model.outputs.length; i++) {
outputs.push(this._model.outputs.get(i));
}
return outputs;
}
}
get outputs(): nbformat.IOutput[] {
return this.output.map((output) => output.toJSON());
}
get gathered(): boolean {
return this._model.metadata.get("gathered") as boolean;
}
deepCopy(): LabCell {
return new LabCell(new CodeCellModel({ id: this.id, cell: this.model.toJSON() }));
}
serialize(): any {
return this._model.toJSON();
}
is_cell: boolean = true;
is_outputter_cell: boolean = true;
private _model: ICodeCellModel;
}

Просмотреть файл

@ -1,8 +1,8 @@
import { GatherModel } from "../packages/gather";
import { IObservableList } from "@jupyterlab/observables";
import { ICellModel, CodeCellModel } from "@jupyterlab/cells";
import { LabCell } from "./LabCell";
import { CodeCellModel, ICellModel } from "@jupyterlab/cells";
import { NotebookPanel } from "@jupyterlab/notebook";
import { IObservableList } from "@jupyterlab/observables";
import { GatherModel } from "../model";
import { LabCell } from "../model/cell";
export class ExecutionLogger {

Просмотреть файл

@ -2,13 +2,13 @@ import { Clipboard as JupyterClipboard } from "@jupyterlab/apputils";
import { nbformat } from "@jupyterlab/coreutils";
import { DocumentManager } from "@jupyterlab/docmanager";
import { IDocumentWidget } from "@jupyterlab/docregistry";
import { FileEditor } from "@jupyterlab/fileeditor";
import { INotebookTracker, NotebookPanel } from "@jupyterlab/notebook";
import { Kernel } from "@jupyterlab/services";
import { OutputSelection } from "../packages/gather";
import { SlicedExecution } from "../slicing/ExecutionSlicer";
import { FileEditor } from "@jupyterlab/fileeditor";
import { ISignal, Signal } from "@phosphor/signaling";
import { JSONObject } from "@phosphor/coreutils";
import { ISignal, Signal } from "@phosphor/signaling";
import { SlicedExecution } from "../analysis/slice/log-slicer";
import { OutputSelection } from "../model";
/**
* Listens to changes to the clipboard.

Просмотреть файл

@ -1,28 +1,26 @@
import { JupyterLab, JupyterLabPlugin } from '@jupyterlab/application';
import { ICommandPalette } from '@jupyterlab/apputils';
import { ISettingRegistry } from '@jupyterlab/coreutils';
import { DocumentManager, IDocumentManager } from '@jupyterlab/docmanager';
import { DocumentRegistry } from '@jupyterlab/docregistry';
import { INotebookModel, INotebookTracker, NotebookPanel } from '@jupyterlab/notebook';
import { JSONObject } from '@phosphor/coreutils';
import { DisposableDelegate, IDisposable } from '@phosphor/disposable';
import { loadHistory as loadHistory } from '../history/load';
import { storeHistory } from '../history/store';
import { MarkerManager } from '../packages/cell';
import { GatherController, GatherModel, GatherState } from '../packages/gather';
import { DataflowAnalyzer } from '../slicing/DataflowAnalysis';
import { ExecutionLogSlicer } from '../slicing/ExecutionSlicer';
import { log, initLogger } from '../utils/log';
import { ExecutionLogger } from './execution-logger';
import { GatherModelRegistry, getGatherModelForActiveNotebook } from './gather-registry';
import { NotifactionExtension as NotificationExtension } from './notification';
import { ResultsHighlighter } from './results';
import '../../style/index.css';
import '../../style/lab-vars.css';
import { Clipboard } from './gather-actions';
import { ISettingRegistry } from '@jupyterlab/coreutils';
import { initToolbar } from './toolbar';
import { Widget } from '@phosphor/widgets';
import '../../style/index.css';
import { DataflowAnalyzer } from '../analysis/slice/data-flow';
import { ExecutionLogSlicer } from '../analysis/slice/log-slicer';
import { GatherController, GatherModel, GatherState, SliceSelection } from '../model';
import { GatherModelRegistry, getGatherModelForActiveNotebook } from '../model/gather-registry';
import { NotifactionExtension as NotificationExtension } from '../overlay/notification';
import { ResultsHighlighter } from '../overlay/result-highlighter';
import { initToolbar } from '../overlay/toolbar';
import { MarkerManager } from '../overlay/variable-markers';
import { loadHistory as loadHistory } from '../persistence/load';
import { storeHistory } from '../persistence/store';
import { initLogger, log } from '../util/log';
import { ExecutionLogger } from './execution-logger';
import { Clipboard } from './gather-actions';
const extension: JupyterLabPlugin<void> = {
@ -82,7 +80,7 @@ export class CodeGatheringExtension implements DocumentRegistry.IWidgetExtension
log("Button: Clicked gather to notebook with selections", {
selectedDefs: gatherModel.selectedDefs,
selectedOutputs: gatherModel.selectedOutputs });
gatherModel.addChosenSlices(...gatherModel.selectedSlices.map(sel => sel.slice));
gatherModel.addChosenSlices(...gatherModel.selectedSlices.map((sel: SliceSelection) => sel.slice));
gatherModel.requestStateChange(GatherState.GATHER_TO_CLIPBOARD);
}
@ -93,7 +91,7 @@ export class CodeGatheringExtension implements DocumentRegistry.IWidgetExtension
log("Button: Clicked gather to notebook with selections", {
selectedDefs: gatherModel.selectedDefs,
selectedOutputs: gatherModel.selectedOutputs });
gatherModel.addChosenSlices(...gatherModel.selectedSlices.map(sel => sel.slice));
gatherModel.addChosenSlices(...gatherModel.selectedSlices.map((sel: SliceSelection) => sel.slice));
gatherModel.requestStateChange(GatherState.GATHER_TO_NOTEBOOK);
}
}
@ -105,7 +103,7 @@ export class CodeGatheringExtension implements DocumentRegistry.IWidgetExtension
log("Button: Clicked gather to script with selections", {
selectedDefs: gatherModel.selectedDefs,
selectedOutputs: gatherModel.selectedOutputs });
gatherModel.addChosenSlices(...gatherModel.selectedSlices.map(sel => sel.slice));
gatherModel.addChosenSlices(...gatherModel.selectedSlices.map((sel: SliceSelection) => sel.slice));
gatherModel.requestStateChange(GatherState.GATHER_TO_SCRIPT);
}
}

Просмотреть файл

@ -1,6 +1,7 @@
import { LocationSet } from "../../slicing/Slice";
import { nbformat } from "@jupyterlab/coreutils";
import { UUID } from "@phosphor/coreutils";
import { CodeCellModel, ICodeCellModel } from "@jupyterlab/cells";
import { IOutputModel } from "@jupyterlab/rendermime";
/**
* Generic interface for accessing data about a code cell.
@ -151,80 +152,82 @@ export function instanceOfICell(object: any): object is ICell {
}
/**
* A slice of a cell.
* Abstract interface to data of a Jupyter Lab code cell.
*/
export class CellSlice {
export class LabCell extends AbstractCell {
/**
* Construct an instance of a cell slice.
*/
constructor(cell: ICell, slice: LocationSet, executionTime?: Date) {
this.cell = cell;
this._slice = slice;
this.executionTime = executionTime;
constructor(model: ICodeCellModel) {
super();
this._model = model;
}
get model(): ICodeCellModel {
return this._model;
}
/**
* Get the text in the slice of a cell.
*/
get textSlice(): string {
return this.getTextSlice(false);
get id(): string {
return this._model.id;
}
/**
* Get the text of all lines in a slice (no deletions from lines).
*/
get textSliceLines(): string {
return this.getTextSlice(true);
get persistentId(): string {
if (!this._model.metadata.has("persistent_id")) {
this._model.metadata.set("persistent_id", UUID.uuid4());
}
return this._model.metadata.get("persistent_id") as string;
}
private getTextSlice(fullLines: boolean): string {
let sliceLocations = this.slice.items;
let textLines = this.cell.text.split("\n");
return sliceLocations.sort((l1, l2) => l1.first_line - l2.first_line)
.map(loc => {
return textLines.map((line, index0) => {
let index = index0 + 1;
let left, right;
if (index == loc.first_line) {
left = loc.first_column;
}
if (index == loc.last_line) {
right = loc.last_column;
}
if (index > loc.first_line) {
left = 0;
}
if (index < loc.last_line) {
right = line.length;
}
if (left != undefined && right != undefined) {
if (fullLines) {
return line.slice(0, line.length);
} else {
return line.slice(left, right);
}
}
return "";
}).filter(text => text != "").join("\n");
}).filter(text => text != "").join("\n");
get text(): string {
return this._model.value.text;
}
/**
* Get the slice.
*/
get slice(): LocationSet {
return this._slice;
set text(text: string) {
this._model.value.text = text;
}
/**
* Set the slice.
*/
set slice(slice: LocationSet) {
this._slice = slice;
get executionCount(): number {
return this._model.executionCount;
}
readonly cell: ICell;
readonly executionTime: Date;
private _slice: LocationSet;
set executionCount(count: number) {
this._model.executionCount = count;
}
get isCode(): boolean {
return this._model.type == "code";
}
get hasError(): boolean {
return this.output.some(o => o.type === 'error');
}
get output(): IOutputModel[] {
let outputs = [];
if (this._model.outputs) {
for (let i = 0; i < this._model.outputs.length; i++) {
outputs.push(this._model.outputs.get(i));
}
return outputs;
}
}
get outputs(): nbformat.IOutput[] {
return this.output.map((output) => output.toJSON());
}
get gathered(): boolean {
return this._model.metadata.get("gathered") as boolean;
}
deepCopy(): LabCell {
return new LabCell(new CodeCellModel({ id: this.id, cell: this.model.toJSON() }));
}
serialize(): any {
return this._model.toJSON();
}
is_cell: boolean = true;
is_outputter_cell: boolean = true;
private _model: ICodeCellModel;
}

81
src/model/cellslice.ts Normal file
Просмотреть файл

@ -0,0 +1,81 @@
import { ICell } from "./cell";
import { LocationSet } from "../analysis/slice/slice";
/**
* A slice of a cell.
*/
export class CellSlice {
/**
* Construct an instance of a cell slice.
*/
constructor(cell: ICell, slice: LocationSet, executionTime?: Date) {
this.cell = cell;
this._slice = slice;
this.executionTime = executionTime;
}
/**
* Get the text in the slice of a cell.
*/
get textSlice(): string {
return this.getTextSlice(false);
}
/**
* Get the text of all lines in a slice (no deletions from lines).
*/
get textSliceLines(): string {
return this.getTextSlice(true);
}
private getTextSlice(fullLines: boolean): string {
let sliceLocations = this.slice.items;
let textLines = this.cell.text.split("\n");
return sliceLocations.sort((l1, l2) => l1.first_line - l2.first_line)
.map(loc => {
return textLines.map((line, index0) => {
let index = index0 + 1;
let left, right;
if (index == loc.first_line) {
left = loc.first_column;
}
if (index == loc.last_line) {
right = loc.last_column;
}
if (index > loc.first_line) {
left = 0;
}
if (index < loc.last_line) {
right = line.length;
}
if (left != undefined && right != undefined) {
if (fullLines) {
return line.slice(0, line.length);
} else {
return line.slice(left, right);
}
}
return "";
}).filter(text => text != "").join("\n");
}).filter(text => text != "").join("\n");
}
/**
* Get the slice.
*/
get slice(): LocationSet {
return this._slice;
}
/**
* Set the slice.
*/
set slice(slice: LocationSet) {
this._slice = slice;
}
readonly cell: ICell;
readonly executionTime: Date;
private _slice: LocationSet;
}

Просмотреть файл

@ -1,11 +1,11 @@
import { IGatherObserver, GatherModel, GatherModelEvent, GatherEventData, GatherState } from ".";
import { ExecutionLogSlicer } from "../../slicing/ExecutionSlicer";
import { DefSelection, OutputSelection } from "./selections";
import { LocationSet } from "../../slicing/Slice";
import { log } from "../../utils/log";
import { NotebookOpener, ScriptOpener, Clipboard } from "../../lab/gather-actions";
import { DocumentManager } from "@jupyterlab/docmanager";
import { INotebookTracker } from "@jupyterlab/notebook";
import { GatherEventData, GatherModel, GatherModelEvent, GatherState, IGatherObserver } from ".";
import { ExecutionLogSlicer } from "../analysis/slice/log-slicer";
import { LocationSet } from "../analysis/slice/slice";
import { Clipboard, NotebookOpener, ScriptOpener } from "../main/gather-actions";
import { log } from "../util/log";
import { DefSelection, OutputSelection } from "./selections";
/**
* Controller for updating the gather model.

Просмотреть файл

@ -1,7 +1,7 @@
import { INotebookTracker, INotebookModel } from "@jupyterlab/notebook";
import { GatherModel } from "../packages/gather";
import { INotebookModel, INotebookTracker } from "@jupyterlab/notebook";
import { UUID } from "@phosphor/coreutils";
import { log } from "util";
import { GatherModel } from ".";
export function getGatherModelForActiveNotebook(notebooks: INotebookTracker,
gatherModelRegistry: GatherModelRegistry): GatherModel | null {

Просмотреть файл

@ -1,3 +1,3 @@
export * from './model';
export * from './controller';
export * from './selections';
export * from './model';
export * from './selections';

Просмотреть файл

@ -1,8 +1,8 @@
import { DefSelection, SliceSelection, EditorDef, OutputSelection, CellOutput } from "./selections";
import { ICell } from "../cell";
import { log } from "../../utils/log";
import { SlicedExecution, ExecutionLogSlicer } from "../../slicing/ExecutionSlicer";
import { CellProgram } from "../../slicing/ProgramBuilder";
import { ICell } from "./cell";
import { log } from "../util/log";
import { SlicedExecution, ExecutionLogSlicer } from "../analysis/slice/log-slicer";
import { CellProgram } from "../analysis/slice/program-builder";
/**
* Available states for the gathering application.

Просмотреть файл

@ -1,6 +1,6 @@
import { Ref } from "../../slicing/DataflowAnalysis";
import { ICell } from "../cell";
import { SlicedExecution } from "../../slicing/ExecutionSlicer";
import { Ref } from "../analysis/slice/data-flow";
import { SlicedExecution } from "../analysis/slice/log-slicer";
import { ICell } from "./cell";
/**
* A user's selection.

Просмотреть файл

@ -1,9 +1,8 @@
import { NotebookPanel } from "@jupyterlab/notebook";
import { Cell, CodeCell, isCodeCellModel } from "@jupyterlab/cells";
import { ICell } from "../packages/cell";
import CodeMirror from "codemirror";
import { CodeMirrorEditor } from "@jupyterlab/codemirror";
import { LabCell } from "./LabCell";
import { NotebookPanel } from "@jupyterlab/notebook";
import CodeMirror from "codemirror";
import { ICell, LabCell } from "../model/cell";
/**
* Finds the HTML elements in a notebook corresponding to a cell. Useful for looking up HTML

Просмотреть файл

@ -1,7 +1,7 @@
import { DocumentRegistry } from "@jupyterlab/docregistry";
import { NotebookPanel, INotebookModel } from "@jupyterlab/notebook";
import { IDisposable, DisposableDelegate } from "@phosphor/disposable";
import { NotificationWidget } from "../packages/notification";
import { INotebookModel, NotebookPanel } from "@jupyterlab/notebook";
import { DisposableDelegate, IDisposable } from "@phosphor/disposable";
import { NotificationWidget } from "../widgets/notification";
export class NotifactionExtension implements DocumentRegistry.IWidgetExtension<NotebookPanel, INotebookModel> {
private notificationWidget: NotificationWidget;

Просмотреть файл

@ -1,10 +1,10 @@
import { MarkerManager } from "../packages/cell";
import { GatherModel } from "../packages/gather";
import { NotebookPanel, Notebook } from "@jupyterlab/notebook";
import { IClientSession } from "@jupyterlab/apputils";
import { CodeCellModel, ICellModel } from "@jupyterlab/cells";
import { Notebook, NotebookPanel } from "@jupyterlab/notebook";
import { IObservableList } from "@jupyterlab/observables";
import { ICellModel, CodeCellModel } from "@jupyterlab/cells";
import { LabCell } from "./LabCell";
import { MarkerManager } from "./variable-markers";
import { GatherModel } from "../model";
import { LabCell } from "../model/cell";
/**
* Highlights gatherable entities.

Просмотреть файл

@ -1,9 +1,9 @@
import { GatherModel, IGatherObserver, GatherModelEvent, GatherEventData, GatherState } from "../packages/gather";
import { Widget, PanelLayout } from "@phosphor/widgets";
import { log } from "../utils/log";
import { ToolbarButton, ToolbarButtonComponent } from "@jupyterlab/apputils";
import { NotebookPanel } from "@jupyterlab/notebook";
import { CodeGatheringExtension } from ".";
import { PanelLayout, Widget } from "@phosphor/widgets";
import { log } from "../util/log";
import { GatherEventData, GatherModel, GatherModelEvent, GatherState, IGatherObserver } from "../model";
import { CodeGatheringExtension } from "../main/main";
/**
* Class for highlighted buttons.

Просмотреть файл

@ -2,14 +2,14 @@
* Helpers for marking up CodeMirror editors.
*/
import { NotebookPanel } from "@jupyterlab/notebook";
import { LineHandle } from "../../../node_modules/@types/codemirror";
import { NotebookElementFinder } from "../../lab/element-finder";
import { ILocation, ISyntaxNode } from "../../parsers/python/python_parser";
import { Ref, SymbolType } from "../../slicing/DataflowAnalysis";
import { SlicedExecution } from "../../slicing/ExecutionSlicer";
import { log } from "../../utils/log";
import { CellOutput, DefSelection, EditorDef, GatherEventData, GatherModel, GatherModelEvent, IGatherObserver, OutputSelection } from "../gather";
import { ICell } from "./model";
import { LineHandle } from "codemirror";
import { ICell } from "../model/cell";
import { ILocation, ISyntaxNode } from "../analysis/parse/python/python-parser";
import { Ref, SymbolType } from "../analysis/slice/data-flow";
import { SlicedExecution } from "../analysis/slice/log-slicer";
import { log } from "../util/log";
import { CellOutput, DefSelection, EditorDef, GatherEventData, GatherModel, GatherModelEvent, IGatherObserver, OutputSelection } from "../model";
import { NotebookElementFinder } from "./element-finder";
/**
* Class for a highlighted, clickable output.
@ -303,7 +303,7 @@ export class MarkerManager implements IGatherObserver {
let numLines = 0;
// Batch the highlight operations for each cell to spend less time updating cell height.
editor.operation(() => {
sliceLocations.items.forEach(loc => {
sliceLocations.items.forEach((loc:ILocation) => {
for (let lineNumber = loc.first_line - 1; lineNumber <= loc.last_line -1; lineNumber++) {
numLines += 1;
let lineHandle = editor.addLineClass(lineNumber, "background", DEPENDENCY_CLASS);

Просмотреть файл

@ -1,2 +0,0 @@
export * from './model';
export * from './markers';

Просмотреть файл

@ -1,21 +0,0 @@
import { SlicedExecution } from "../../slicing/ExecutionSlicer";
/**
* An interface for opening new notebooks.
*/
export interface INotebookOpener {
/**
* Open a new notebook containing the slice.
*/
openNotebookForSlice: (slice: SlicedExecution) => void;
}
/**
* An interface for opening new scripts.
*/
export interface IScriptOpener {
/**
* Open a new script containing the slice.
*/
openScriptForSlice: (slice: SlicedExecution) => void;
}

Просмотреть файл

@ -1,278 +0,0 @@
import { PanelLayout } from '@phosphor/widgets';
import { Widget } from '@phosphor/widgets';
import { ISlicedCellModel } from './model';
import CodeMirror = require('codemirror');
import 'codemirror/addon/scroll/simplescrollbars';
import 'codemirror/addon/scroll/simplescrollbars.css';
// The HTML class names used in these widgets
const SLICED_CELL_CLASS = 'jp-SlicedCell';
const DIFFED_SLICED_CELL_CLASS = 'jp-DiffedSlicedCell';
const SLICED_CELL_EDITOR_CLASS = 'jp-SlicedCell-editor';
const DIFFED_CELL_BEFORE_TEXT_CLASS = 'jp-DiffedCell-editor-beforetext';
const DIFFED_CELL_BEFORE_BACKGROUND_CLASS = 'jp-DiffedCell-editor-beforebackground';
const DIFFED_CELL_AFTER_TEXT_CLASS = 'jp-DiffedCell-editor-aftertext';
const DIFFED_CELL_CHANGED_TEXT_CLASS = 'jp-DiffedCell-editor-changedtext';
const CELL_AREA_CLASS = 'jp-CellArea';
/**
* A widget for showing a cell with a code slice.
*/
export class SlicedCell extends Widget {
protected editor: CodeMirror.Editor = null;
protected codeMirrorWidget: Widget;
readonly model: ISlicedCellModel;
constructor(options: SlicedCell.IOptions) {
super();
this.addClass(SLICED_CELL_CLASS);
this.model = options.model;
let codeMirrorElement = document.createElement("div");
let codeMirror = CodeMirror(codeMirrorElement, {
value: this.model.sourceCode,
mode: "python",
readOnly: "nocursor", // don't allow interaction with cell's contents
scrollbarStyle: "simple" // show simple (thin) scrollbar
});
let codeMirrorWidget = new Widget({ node: codeMirror.getWrapperElement() });
this.editor = codeMirror;
this.codeMirrorWidget = codeMirrorWidget;
codeMirrorWidget.addClass(SLICED_CELL_EDITOR_CLASS);
let layout = (this.layout = new PanelLayout());
layout.addWidget(codeMirrorWidget);
this.initializeEditor();
// Add a class to all text that doesn't belong in the slice.
/*
let codeMirrorDoc = editor.getDoc();
let rangeStart = 0;
this.model.sliceRanges.forEach(function(sliceRange: CharacterRange) {
if (sliceRange.start > rangeStart) {
codeMirrorDoc.markText(
codeMirrorDoc.posFromIndex(rangeStart),
codeMirrorDoc.posFromIndex(sliceRange.start),
{ className: SLICED_CELL_OUTOFSLICE_TEXT_CLASS }
);
}
rangeStart = sliceRange.end;
});
codeMirrorDoc.markText(
codeMirrorDoc.posFromIndex(rangeStart),
{ line: codeMirrorDoc.lastLine() + 1, ch: 0 },
{ className: SLICED_CELL_OUTOFSLICE_TEXT_CLASS }
);
*/
}
initializeEditor() {
// XXX: If I don't call this method with a delay, the text doesn't appear.
let codeMirrorEditor: CodeMirror.Editor = this.editor;
setTimeout(function () {
codeMirrorEditor.refresh();
}, 1);
}
dispose() {
// Do nothing if already disposed.
if (this.isDisposed) {
return;
}
this.editor = null;
super.dispose();
}
}
export namespace SlicedCell {
export interface IOptions {
model: ISlicedCellModel;
}
}
/**
* A widget for showing a cell with a code slice, diff'd to another cell.
*/
export class DiffedSlicedCell extends SlicedCell {
constructor(options: SlicedCell.IOptions) {
super(options);
this.addClass(DIFFED_SLICED_CELL_CLASS);
let codeMirrorDoc: CodeMirror.Doc = this.editor.getDoc();
// Mark up differences
for (let beforeLine of this.model.diff.beforeLines) {
this.editor.addLineClass(beforeLine - 1, "background",
DIFFED_CELL_BEFORE_BACKGROUND_CLASS);
this.editor.addLineClass(beforeLine - 1, "wrap",
DIFFED_CELL_BEFORE_TEXT_CLASS);
}
for (let afterLine of this.model.diff.afterLines) {
this.editor.addLineClass(afterLine - 1, "background",
DIFFED_CELL_AFTER_TEXT_CLASS)
}
for (let loc of this.model.diff.changeLocations) {
codeMirrorDoc.markText(
{ line: loc.first_line - 1, ch: loc.first_column },
{ line: loc.last_line - 1, ch: loc.last_column },
{ className: DIFFED_CELL_CHANGED_TEXT_CLASS }
);
let versionClass;
if (this.model.diff.beforeLines.indexOf(loc.first_line) !== -1) {
versionClass = DIFFED_CELL_BEFORE_TEXT_CLASS;
} else if (this.model.diff.afterLines.indexOf(loc.first_line) !== -1) {
versionClass = DIFFED_CELL_AFTER_TEXT_CLASS;
}
codeMirrorDoc.markText(
{ line: loc.first_line - 1, ch: loc.first_column },
{ line: loc.last_line - 1, ch: loc.last_column },
{ className: versionClass }
)
}
// let linesToShow: Array<number> = new Array<number>();
/*
this.model.diff.updatedRanges.forEach(function(range: CharacterRange) {
// Build a list of lines that should be showing in the cell.
let startPosition: CodeMirror.Position = codeMirrorDoc.posFromIndex(range.start);
let endPosition: CodeMirror.Position = codeMirrorDoc.posFromIndex(range.end + 1);
for (let i = startPosition.line - CONTEXT_SIZE; i <= endPosition.line + CONTEXT_SIZE; i++) {
if (i < codeMirrorDoc.firstLine() || i > codeMirrorDoc.lastLine()) continue;
if (linesToShow.indexOf(i) == -1) {
linesToShow.push(i);
}
}
// Highlight all cell text that was updated in the diff.
codeMirrorDoc.markText(startPosition, endPosition,
{ className: SLICED_CELL_UPDATED_TEXT_CLASS });
});
linesToShow.sort(function(a, b) { return a - b; });
*/
// Add a class to all text that wasn't changed.
/*
this.model.diff.sameRanges.forEach(function(range: CharacterRange) {
codeMirrorDoc.markText(
codeMirrorDoc.posFromIndex(range.start),
codeMirrorDoc.posFromIndex(range.end + 1),
{ className: SLICED_CELL_UNCHANGED_TEXT_CLASS }
);
});
// Make a list of what lines to hide.
let hiddenLineRanges: Array<[number, number]> = new Array<[number, number]>();
let hiddenRangeStart: number = -1;
for (let i = codeMirrorDoc.firstLine(); i <= codeMirrorDoc.lastLine(); i++) {
if (linesToShow.indexOf(i) == -1 && hiddenRangeStart == -1) {
hiddenRangeStart = i;
} else if (linesToShow.indexOf(i) !== -1 && hiddenRangeStart !== -1) {
hiddenLineRanges.push([hiddenRangeStart, i]);
hiddenRangeStart = -1;
}
}
if (hiddenRangeStart !== -1) {
hiddenLineRanges.push([hiddenRangeStart, codeMirrorDoc.lastLine() + 1]);
}
let revealMarkers: Array<CodeMirror.TextMarker> = new Array<CodeMirror.TextMarker>();
let editor: CodeMirror.Editor = this._editor;
// Hide all of the hidden lines.
let hideRange = function(from: CodeMirror.Position, to: CodeMirror.Position) {
let replacement: HTMLElement = document.createElement('span');
replacement.classList.add(SLICED_CELL_HIDE_TEXT_CLASS);
replacement.textContent = "... click to show hidden lines ...";
let hideMarker: CodeMirror.TextMarker = codeMirrorDoc.markText(from, to, { replacedWith: replacement });
// When someone clicks on a hidden line, reveal it.
replacement.onclick = function(event: MouseEvent) {
hideMarker.clear();
// If we don't refresh the editor, some of the hidden code might not get shown.
editor.refresh();
// Add a marker to the revealed code, so we can hide it again.
let revealMarker: CodeMirror.TextMarker = codeMirrorDoc.markText(
from, to, { className: SLICED_CELL_REVEAL_TEXT_CLASS });
revealMarkers.push(revealMarker);
// This prevents the event by getting handled by the editor, which might detect
// this as a click on the `revealMarker` and hide the text again.
event.stopPropagation();
}
};
hiddenLineRanges.forEach(function(lineRange: [number, number]) {
// If the line ends with "\n", don't hide the last character; keep it for prettiness.
let endIndex = codeMirrorDoc.indexFromPos({ line: lineRange[1], ch: 0 });
if (codeMirrorDoc.getValue()[endIndex - 1] == '\n') {
endIndex -= 1;
}
hideRange({ line: lineRange[0], ch: 0 }, codeMirrorDoc.posFromIndex(endIndex));
});
// Whenever someone clicks on hidden lines that were revealed, hide them again.
editor.getWrapperElement().onclick = function(event: MouseEvent) {
let clickPosition: CodeMirror.Position = editor.coordsChar({ left: event.clientX, top: event.clientY });
for (let marker of editor.getDoc().findMarksAt(clickPosition)) {
let markerIndex = revealMarkers.indexOf(marker);
if (markerIndex !== -1) {
let range = marker.find();
marker.clear();
revealMarkers.splice(markerIndex, 1);
hideRange(range.from, range.to);
}
}
}
*/
// TODO(andrewhead): set this as a configuration parameter.
// If there is no new code in this cell, hide it.
// if (linesToShow.length == 0) {
// this.hide();
// }
}
}
export namespace CellArea {
export interface IOptions {
model: ISlicedCellModel;
showDiff: boolean;
}
}
/**
* A cell area widget, which hosts a prompt and a cell editor widget.
*/
export class CellArea extends Widget {
readonly model: ISlicedCellModel;
constructor(options: CellArea.IOptions) {
super()
this.addClass(CELL_AREA_CLASS);
// let model = (this.model = options.model);
// let prompt = (this._prompt = new InputPrompt());
// prompt.executionCount = model.executionCount ? model.executionCount.toString() : "";
// prompt.addClass(INPUT_AREA_PROMPT_CLASS);
let layout = (this.layout = new PanelLayout());
// layout.addWidget(prompt);
let cellOptions: SlicedCell.IOptions = {
model: options.model
};
if (options.showDiff) {
layout.addWidget(new SlicedCell(cellOptions));
} else {
layout.addWidget(new DiffedSlicedCell(cellOptions));
}
}
}

2
src/parsers/python/.gitignore поставляемый
Просмотреть файл

@ -1,2 +0,0 @@
pyscript/
*.js

Просмотреть файл

@ -1,9 +0,0 @@
x = 1
if x > 2:
x += 3
elif x < 3:
y = x
elif x > 10:
y = 2*x
else:
print(x)

Просмотреть файл

@ -1,7 +0,0 @@
x=4
y = 2
q = 3
for i in range(1,x):
y += i
y
z = y*2

Просмотреть файл

@ -1,41 +0,0 @@
import * as fs from 'fs';
import * as ast from '../python_parser';
import { ControlFlowGraph } from '../../../slicing/ControlFlowAnalysis';
import { DataflowAnalyzer } from '../../../slicing/DataflowAnalysis';
let printCfg = false;
let printAst = false;
let printDf = false;
for (let i = 2; i < process.argv.length; i++) {
if (process.argv[i].startsWith('-')) {
switch (process.argv[i].toLowerCase()) {
case '-a': printAst = true; break;
case '-c': printCfg = true; break;
case '-d': printDf = true; break;
}
continue;
}
const path = process.argv[i];
const text = fs.readFileSync(path).toString().replace(/\r\n/g, '\n');
const tree = ast.parse(text);
if (printAst) {
console.log(JSON.stringify(tree, null, 2));
}
const cfg = new ControlFlowGraph(tree);
if (printCfg) {
cfg.print();
}
const analyzer = new DataflowAnalyzer();
const dfa = analyzer.analyze(cfg);
if (printDf) {
dfa.flows.items.forEach(({ fromNode, toNode }) => {
console.log(fromNode.location.first_line, '->', toNode.location.first_line);
});
}
}

Просмотреть файл

@ -1,3 +0,0 @@
a = 1
b = 2
c = a + b

Просмотреть файл

@ -1,15 +0,0 @@
x=1
try:
x += 2
if x > 10:
raise Exception()
except IOError:
print('file')
except:
print('oops')
else:
print(x)
x = 4
finally:
y = x
z = y

Просмотреть файл

@ -1,6 +0,0 @@
a=1
a=b=c=12
c+=2
with A() as a, B() as b:
x=a+b
y=b-a

Просмотреть файл

@ -1,9 +1,9 @@
import { INotebookModel } from "@jupyterlab/notebook";
import { JSONArray, JSONExt, JSONObject } from "@phosphor/coreutils";
import { log } from "util";
import { SimpleCell } from "../packages/cell";
import { CellExecution } from "../slicing/ExecutionSlicer";
import { GatherModel } from "../packages/gather";
import { CellExecution } from "../analysis/slice/log-slicer";
import { SimpleCell } from "../model/cell";
import { GatherModel } from "../model";
/**
* Key for accessing execution history in Jupyter notebook metadata.

Просмотреть файл

@ -1,7 +1,7 @@
import { ExecutionLogSlicer } from "../slicing/ExecutionSlicer";
import { INotebookModel } from "@jupyterlab/notebook";
import { JSONArray, JSONObject } from "@phosphor/coreutils";
import { ExecutionLogSlicer } from "../analysis/slice/log-slicer";
import { EXECUTION_HISTORY_METADATA_KEY } from "./load";
import { JSONObject, JSONArray } from "@phosphor/coreutils";
interface CellExecutionJson extends JSONObject {
executionTime: string;

Просмотреть файл

@ -1,70 +0,0 @@
export type DifferenceKind = 'same' | 'insertion' | 'deletion' | 'substitution';
export interface Difference<T> {
kind: DifferenceKind,
source?: T,
target?: T
}
function editCost(e: DifferenceKind): number {
return e === 'same' ? 0 : 1;
}
// Levenshtein distance (http://http://en.wikipedia.org/wiki/Levenshtein_distance)
/* Here's an example of using it to diff cells:
* const diffed = slices.map((slice, i) =>
* getDifferences(slice, foils[i], sameCodeCells)
* .filter(d => d.kind !== 'same')
* .map(d => d.source)
* .filter(s => s));
*/
export function getDifferences<T>(sourceList: T[], targetList: T[], same?: (a: T, b: T) => boolean): Difference<T>[] {
if (!same) { same = (a, b) => a === b; }
var sourceCount = sourceList.length;
var targetCount = targetList.length;
const edits: Difference<T>[][][] = [];
const cost: number[][] = [];
for (let i = 0; i < sourceCount + 1; i++) {
edits[i] = [];
cost[i] = [];
for (let j = 0; j < targetCount + 1; j++) {
edits[i][j] = [];
cost[i][j] = 0;
}
}
for (let i = 1; i <= sourceCount; i++) {
edits[i][0] = edits[i - 1][0].concat({ kind: 'deletion', source: sourceList[i - 1] });
cost[i][0] = i * editCost('deletion');
}
for (let j = 1; j <= targetCount; j++) {
edits[0][j] = edits[0][j - 1].concat({ kind: 'insertion', target: targetList[j - 1] });
cost[0][j] = j * editCost('insertion');
}
for (let j = 1; j <= targetCount; j++)
for (let i = 1; i <= sourceCount; i++) {
if (same(sourceList[i - 1], targetList[j - 1])) {
edits[i][j] = edits[i - 1][j - 1].concat({ kind: 'same', source: sourceList[i - 1], target: targetList[j - 1] });
cost[i][j] = cost[i - 1][j - 1] + editCost('same');
}
else {
edits[i][j] = edits[i - 1][j].concat({ kind: 'deletion', source: sourceList[i - 1] });
cost[i][j] = cost[i - 1][j] + editCost('deletion');
if (cost[i][j - 1] < cost[i][j]) {
edits[i][j] = edits[i][j - 1].concat({ kind: 'insertion', target: targetList[j - 1] });
cost[i][j] = cost[i][j - 1] + editCost('insertion');
}
if (cost[i - 1][j - 1] < cost[i][j]) {
edits[i][j] = edits[i - 1][j - 1].concat({ kind: 'substitution', source: sourceList[i - 1], target: targetList[j - 1] });
cost[i][j] = cost[i - 1][j - 1] + editCost('substitution');
}
}
}
return edits[sourceCount][targetCount];
}

Просмотреть файл

@ -1,10 +1,9 @@
import { DataflowAnalyzer, Ref, SymbolType, RefSet, IDataflow, ReferenceType } from "../slicing/DataflowAnalysis";
import { parse } from '../parsers/python/python_parser';
import { ControlFlowGraph } from '../slicing/ControlFlowAnalysis';
import { expect } from "chai";
import { Set, StringSet } from "../slicing/Set";
import { SlicerConfig, FunctionConfig } from "../slicing/SlicerConfig";
import { ISyntaxNode } from "../parsers/python/python_parser";
import { ISyntaxNode, parse } from '../analysis/parse/python/python-parser';
import { ControlFlowGraph } from '../analysis/slice/control-flow';
import { DataflowAnalyzer, IDataflow, Ref, ReferenceType, RefSet, SymbolType } from "../analysis/slice/data-flow";
import { Set, StringSet } from "../analysis/slice/set";
import { FunctionConfig, SlicerConfig } from "../analysis/slice/slice-config";
// High-level tests on dataflow as a sanity check.

Просмотреть файл

@ -1,6 +1,7 @@
import { expect } from 'chai';
import { CellSlice, SimpleCell } from '../packages/cell';
import { LocationSet } from '../slicing/Slice';
import { LocationSet } from '../analysis/slice/slice';
import { SimpleCell } from '../model/cell';
import { CellSlice } from '../model/cellslice';
describe('CellSlice', () => {

Просмотреть файл

@ -1,6 +1,6 @@
import { ControlFlowGraph } from "../slicing/ControlFlowAnalysis";
import { parse } from "../parsers/python/python_parser";
import { expect } from "chai";
import { parse } from "../analysis/parse/python/python-parser";
import { ControlFlowGraph } from "../analysis/slice/control-flow";
describe('ControlFlowGraph', () => {

Просмотреть файл

@ -1,5 +1,5 @@
import { expect } from "chai";
import { computeTextDiff } from "../packages/history/diff";
import { computeTextDiff } from "../widgets/history/diff";
describe('textdiff', () => {

Просмотреть файл

@ -1,63 +0,0 @@
import { getDifferences } from "../slicing/EditDistance";
import { expect } from "chai";
describe('diff tests', () => {
function same<T>(x: T) { return { kind: 'same', source: x, target: x }; }
function same2<T>(x: T, y: T) { return { kind: 'same', source: x, target: y }; }
function sub<T>(x: T, y: T) { return { kind: 'substitution', source: x, target: y }; }
function ins<T>(x: T) { return { kind: 'insertion', target: x }; }
function del<T>(x: T) { return { kind: 'deletion', source: x }; }
describe('string diff tests', () => {
function seq(s: string): string[] { return s.split(''); }
it('should handle no difference', () => {
const result = getDifferences(seq("hello"), seq("hello"));
expect(result).to.deep.equal([same('h'), same('e'), same('l'), same('l'), same('o')]);
});
it('should handle end difference', () => {
const result = getDifferences(seq("coal"), seq("coat"));
expect(result).to.deep.equal([same('c'), same('o'), same('a'), sub('l', 't')]);
});
it('should handle empty difference', () => {
const result = getDifferences([], []);
expect(result).to.be.an('array').that.is.empty;
});
it('should handle deletion', () => {
const result = getDifferences(seq("x"), []);
expect(result).to.deep.equal([del('x')]);
});
it('should handle insertion', () => {
const result = getDifferences([], seq("x"));
expect(result).to.deep.equal([ins('x')]);
});
it('should handle initial insertion', () => {
const result = getDifferences(seq("bc"), seq("abc"));
expect(result).to.deep.equal([ins('a'), same('b'), same('c')]);
});
it('should handle internal insertion and deletion', () => {
const result = getDifferences(seq("qxyz"), seq("qabxy"));
expect(result).to.deep.equal([same('q'), ins('a'), ins('b'), same('x'), same('y'), del('z')]);
});
it('should handle head/tail insertion and deletion', () => {
const result = getDifferences(seq("xyz"), seq("abxy"));
expect(result).to.deep.equal([ins('a'), ins('b'), same('x'), same('y'), del('z')]);
});
})
describe('number diff tests', () => {
it('should handle initial deletions', () => {
const result = getDifferences([0, 0, 1, 2, 3], [1, 2, 3]);
expect(result).to.deep.equal([del(0), del(0), same(1), same(2), same(3)]);
});
it('should handle user-defined same function', () => {
const result = getDifferences([0, 0, 1, 2, 3], [3, 6, 2], (i, j) => i % 2 === j % 2);
expect(result).to.deep.equal([del(0), del(0), same2(1, 3), same2(2, 6), sub(3, 2)]);
});
});
});

Просмотреть файл

@ -1,5 +1,5 @@
import { expect } from "chai";
import { MagicsRewriter, TimeLineMagicRewriter, MatchPosition, PylabLineMagicRewriter } from "../slicing/MagicsRewriter";
import { MagicsRewriter, MatchPosition, PylabLineMagicRewriter, TimeLineMagicRewriter } from "../analysis/slice/rewrite-magics";
describe('MagicsRewriter', () => {

Просмотреть файл

@ -1,7 +1,8 @@
import { expect } from "chai";
import { LocationSet } from "../slicing/Slice";
import { SlicedExecution } from "../slicing/ExecutionSlicer";
import { ICell, CellSlice, SimpleCell } from "../packages/cell";
import { SlicedExecution } from "../analysis/slice/log-slicer";
import { LocationSet } from "../analysis/slice/slice";
import { ICell, SimpleCell } from "../model/cell";
import { CellSlice } from "../model/cellslice";
describe('SlicedExecution', () => {

Просмотреть файл

@ -1,6 +1,5 @@
// import * as python3 from '../parsers/python/python3';
import { parse, walk, IDict } from '../parsers/python/python_parser';
import { expect } from 'chai';
import { IDict, parse, walk } from '../analysis/parse/python/python-parser';
describe('python parser', () => {

Просмотреть файл

@ -1,6 +1,6 @@
import { expect } from "chai";
import { ProgramBuilder } from "../slicing/ProgramBuilder";
import { ICell, SimpleCell } from '../packages/cell';
import { ProgramBuilder } from "../analysis/slice/program-builder";
import { ICell, SimpleCell } from '../model/cell';
describe('program builder', () => {

Просмотреть файл

@ -1,6 +1,6 @@
import { expect } from "chai";
import { parse } from '../parsers/python/python_parser';
import { slice, LocationSet } from "../slicing/Slice";
import { parse } from '../analysis/parse/python/python-parser';
import { LocationSet, slice } from "../analysis/slice/slice";
describe('slices', () => {

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -1,12 +1,13 @@
import { HistoryModel } from './model';
import { RevisionModel } from '../revision/model';
import { CodeVersionModel } from '../codeversion/model';
import { SlicedCellModel } from '../slicedcell/model';
import { SlicedExecution } from '../../slicing/ExecutionSlicer';
import { ICell, CellSlice } from '../cell/model';
import { computeTextDiff } from './diff';
import { GatherModel } from '../gather';
import { nbformat } from '@jupyterlab/coreutils';
import { SlicedExecution } from '../../analysis/slice/log-slicer';
import { GatherModel } from '../../model';
import { ICell } from '../../model/cell';
import { CellSlice } from '../../model/cellslice';
import { CodeVersionModel } from '../codeversion/model';
import { RevisionModel } from '../revision/model';
import { SlicedCellModel } from '../slicedcell/model';
import { computeTextDiff } from './diff';
import { HistoryModel } from './model';
/**

Просмотреть файл

@ -1,5 +1,5 @@
import { CharacterRange } from "../codeversion";
import { ILocation } from "../../parsers/python/python_parser";
import { ILocation } from "../../analysis/parse/python/python-parser";
import { diff_match_patch } from 'diff-match-patch';

Просмотреть файл

@ -1,3 +1,3 @@
export * from './compute';
export * from './model';
export * from './widget';
export * from './compute';

Просмотреть файл

Просмотреть файл

@ -1,7 +1,6 @@
import { PanelLayout } from '@phosphor/widgets';
import { Widget } from '@phosphor/widgets';
import { PanelLayout, Widget } from '@phosphor/widgets';
import { IOutputRenderer, Revision } from '../revision';
import { IHistoryModel } from './model';
import { Revision, IOutputRenderer } from '../revision';
/**
* The class name added to history viewer widgets

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -1,7 +1,7 @@
import { ICodeVersionModel } from '../codeversion/model';
import { SlicedExecution } from '../../slicing/ExecutionSlicer';
import { GatherModel } from '../gather';
import { nbformat } from '@jupyterlab/coreutils';
import { SlicedExecution } from '../../analysis/slice/log-slicer';
import { ICodeVersionModel } from '../codeversion/model';
import { GatherModel } from '../../model';
/**
* The definition of a model object for a code version.

Просмотреть файл

@ -1,11 +1,10 @@
import { PanelLayout } from '@phosphor/widgets';
import { Widget } from '@phosphor/widgets';
import { IRevisionModel } from './model';
import { CodeVersion } from '../codeversion';
import { GatherState } from '../gather';
import { log } from '../../utils/log';
import { getRelativeTime } from '../../utils/date';
import { nbformat } from '@jupyterlab/coreutils';
import { PanelLayout, Widget } from '@phosphor/widgets';
import { getRelativeTime } from '../../util/date';
import { log } from '../../util/log';
import { CodeVersion } from '../codeversion';
import { GatherState } from '../../model';
import { IRevisionModel } from './model';
// HTML element classes for rendered revisions

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -0,0 +1,151 @@
import { PanelLayout } from '@phosphor/widgets';
import { Widget } from '@phosphor/widgets';
import { ISlicedCellModel } from './model';
import CodeMirror = require('codemirror');
import 'codemirror/addon/scroll/simplescrollbars';
import 'codemirror/addon/scroll/simplescrollbars.css';
// The HTML class names used in these widgets
const SLICED_CELL_CLASS = 'jp-SlicedCell';
const DIFFED_SLICED_CELL_CLASS = 'jp-DiffedSlicedCell';
const SLICED_CELL_EDITOR_CLASS = 'jp-SlicedCell-editor';
const DIFFED_CELL_BEFORE_TEXT_CLASS = 'jp-DiffedCell-editor-beforetext';
const DIFFED_CELL_BEFORE_BACKGROUND_CLASS = 'jp-DiffedCell-editor-beforebackground';
const DIFFED_CELL_AFTER_TEXT_CLASS = 'jp-DiffedCell-editor-aftertext';
const DIFFED_CELL_CHANGED_TEXT_CLASS = 'jp-DiffedCell-editor-changedtext';
const CELL_AREA_CLASS = 'jp-CellArea';
/**
* A widget for showing a cell with a code slice.
*/
export class SlicedCell extends Widget {
protected editor: CodeMirror.Editor = null;
protected codeMirrorWidget: Widget;
readonly model: ISlicedCellModel;
constructor(options: SlicedCell.IOptions) {
super();
this.addClass(SLICED_CELL_CLASS);
this.model = options.model;
let codeMirrorElement = document.createElement("div");
let codeMirror = CodeMirror(codeMirrorElement, {
value: this.model.sourceCode,
mode: "python",
readOnly: "nocursor", // don't allow interaction with cell's contents
scrollbarStyle: "simple" // show simple (thin) scrollbar
});
let codeMirrorWidget = new Widget({ node: codeMirror.getWrapperElement() });
this.editor = codeMirror;
this.codeMirrorWidget = codeMirrorWidget;
codeMirrorWidget.addClass(SLICED_CELL_EDITOR_CLASS);
let layout = (this.layout = new PanelLayout());
layout.addWidget(codeMirrorWidget);
this.initializeEditor();
}
initializeEditor() {
// XXX: If I don't call this method with a delay, the text doesn't appear.
let codeMirrorEditor: CodeMirror.Editor = this.editor;
setTimeout(function () {
codeMirrorEditor.refresh();
}, 1);
}
dispose() {
// Do nothing if already disposed.
if (this.isDisposed) {
return;
}
this.editor = null;
super.dispose();
}
}
export namespace SlicedCell {
export interface IOptions {
model: ISlicedCellModel;
}
}
/**
* A widget for showing a cell with a code slice, diff'd to another cell.
*/
export class DiffedSlicedCell extends SlicedCell {
constructor(options: SlicedCell.IOptions) {
super(options);
this.addClass(DIFFED_SLICED_CELL_CLASS);
let codeMirrorDoc: CodeMirror.Doc = this.editor.getDoc();
// Mark up differences
for (let beforeLine of this.model.diff.beforeLines) {
this.editor.addLineClass(beforeLine - 1, "background",
DIFFED_CELL_BEFORE_BACKGROUND_CLASS);
this.editor.addLineClass(beforeLine - 1, "wrap",
DIFFED_CELL_BEFORE_TEXT_CLASS);
}
for (let afterLine of this.model.diff.afterLines) {
this.editor.addLineClass(afterLine - 1, "background",
DIFFED_CELL_AFTER_TEXT_CLASS)
}
for (let loc of this.model.diff.changeLocations) {
codeMirrorDoc.markText(
{ line: loc.first_line - 1, ch: loc.first_column },
{ line: loc.last_line - 1, ch: loc.last_column },
{ className: DIFFED_CELL_CHANGED_TEXT_CLASS }
);
let versionClass;
if (this.model.diff.beforeLines.indexOf(loc.first_line) !== -1) {
versionClass = DIFFED_CELL_BEFORE_TEXT_CLASS;
} else if (this.model.diff.afterLines.indexOf(loc.first_line) !== -1) {
versionClass = DIFFED_CELL_AFTER_TEXT_CLASS;
}
codeMirrorDoc.markText(
{ line: loc.first_line - 1, ch: loc.first_column },
{ line: loc.last_line - 1, ch: loc.last_column },
{ className: versionClass }
)
}
}
}
export namespace CellArea {
export interface IOptions {
model: ISlicedCellModel;
showDiff: boolean;
}
}
/**
* A cell area widget, which hosts a prompt and a cell editor widget.
*/
export class CellArea extends Widget {
readonly model: ISlicedCellModel;
constructor(options: CellArea.IOptions) {
super()
this.addClass(CELL_AREA_CLASS);
let layout = (this.layout = new PanelLayout());
let cellOptions: SlicedCell.IOptions = {
model: options.model
};
if (options.showDiff) {
layout.addWidget(new SlicedCell(cellOptions));
} else {
layout.addWidget(new DiffedSlicedCell(cellOptions));
}
}
}