@webwriter/code
Version:
Write and run code as a code cell. Supports several languages (HTML/CSS/JS, TypeScript, Python).
68 lines (61 loc) • 2.17 kB
text/typescript
import { Line, RangeSet, StateEffect, StateField } from '@codemirror/state';
import { EditorView, GutterMarker, gutter } from '@codemirror/view';
export default function CustomGutter(
name: String,
marker: GutterMarker,
callback: (view: EditorView, pos: number) => void
) {
const effect = StateEffect.define<{ pos: number; on: boolean }>({
map: (val, mapping) => ({ pos: mapping.mapPos(val.pos), on: val.on }),
});
const state = StateField.define<RangeSet<GutterMarker>>({
create() {
return RangeSet.empty;
},
update(set, transaction) {
set = set.map(transaction.changes);
for (let e of transaction.effects) {
if (e.is(effect)) {
if (e.value.on) set = set.update({ add: [marker.range(e.value.pos)] });
else set = set.update({ filter: (from) => from != e.value.pos });
}
}
return set;
},
});
let markerPositions = new Set<number>();
let tempMarkerPositions = new Set<number>();
let lastLine: Line;
function toggleGutter(view: EditorView, pos: number) {
let gutters = view.state.field(state);
let hasGutter = false;
gutters.between(pos, pos, () => {
hasGutter = true;
});
view.dispatch({
effects: effect.of({ pos, on: !hasGutter }),
});
}
return {
effect: effect,
state: state,
gutter: [
state,
gutter({
class: `cm-${name}-gutter`,
markers: (v) => v.state.field(state),
initialSpacer: () => marker,
domEventHandlers: {
mousedown(view, line) {
if (callback) {
callback(view, line.from);
} else {
toggleGutter(view, line.from);
}
return true;
},
},
}),
],
};
}