Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions editor/blockIndicator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import {GutterMarker, gutter} from "@codemirror/view";
import {BlockMetadata, blockMetadataField} from "./blockMetadata";

export class BlockIndicator extends GutterMarker {
constructor(private className: string) {
super();
}
toDOM() {
const div = document.createElement("div");
div.className = this.className;
return div;
}
}

const indicatorMarkers = {
output: {
head: new BlockIndicator("cm-block-indicator output head"),
tail: new BlockIndicator("cm-block-indicator output tail"),
sole: new BlockIndicator("cm-block-indicator output head tail"),
body: new BlockIndicator("cm-block-indicator output"),
},
source: {
head: new BlockIndicator("cm-block-indicator source head"),
tail: new BlockIndicator("cm-block-indicator source tail"),
sole: new BlockIndicator("cm-block-indicator source head tail"),
body: new BlockIndicator("cm-block-indicator source"),
},
error: {
head: new BlockIndicator("cm-block-indicator error head"),
tail: new BlockIndicator("cm-block-indicator error tail"),
sole: new BlockIndicator("cm-block-indicator error head tail"),
body: new BlockIndicator("cm-block-indicator error"),
},
};

export const blockIndicator = gutter({
class: "cm-blockIndicators",
lineMarker(view, line) {
const blocks = view.state.field(blockMetadataField, false);
if (blocks === undefined) return null;
const index = findEnclosingBlock(blocks, line.from);
if (index === null) return null;
const currentLine = view.state.doc.lineAt(line.from).number;
const sourceFirstLine = view.state.doc.lineAt(blocks[index].source.from).number;
const group = blocks[index].error
? indicatorMarkers.error
: currentLine < sourceFirstLine
? indicatorMarkers.output
: indicatorMarkers.source;
const blockFirstLine = view.state.doc.lineAt(blocks[index].from).number;
const blockLastLine = view.state.doc.lineAt(blocks[index].to).number;
if (blockFirstLine === currentLine) {
return blockLastLine === currentLine ? group.sole : group.head;
} else if (blockLastLine === currentLine) {
return group.tail;
} else {
return group.body;
}
},
initialSpacer() {
return indicatorMarkers.source.body;
},
});

function findEnclosingBlock(blocks: BlockMetadata[], pos: number): number | null {
let left = 0;
let right = blocks.length - 1;

while (left <= right) {
const middle = (left + right) >>> 1;
const pivot = blocks[middle];
if (pos < pivot.from) {
right = middle - 1;
} else if (pos > pivot.to) {
left = middle + 1;
} else {
return middle;
}
}

return null;
}
Loading