зеркало из https://github.com/microsoft/gather.git
Cleanup: Renamed files and restructured directories
This commit is contained in:
Родитель
973f460aec
Коммит
b1abe3952f
|
@ -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;
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче