2022-11-18 15:04:37 +00:00
|
|
|
// Forked from https://codeberg.org/retronav/ixora
|
|
|
|
// Original author: Pranav Karawale
|
|
|
|
// License: Apache License 2.0.
|
|
|
|
|
2022-12-09 15:09:53 +00:00
|
|
|
import { Decoration, syntaxTree, WidgetType } from "../deps.ts";
|
|
|
|
import { decoratorStateField, isCursorInRange } from "./util.ts";
|
2022-11-18 15:04:37 +00:00
|
|
|
|
|
|
|
const bulletListMarkerRE = /^[-+*]/;
|
|
|
|
|
2022-12-09 15:09:53 +00:00
|
|
|
export function listBulletPlugin() {
|
|
|
|
return decoratorStateField((state) => {
|
2022-11-18 15:04:37 +00:00
|
|
|
const widgets: any[] = [];
|
2022-12-09 15:09:53 +00:00
|
|
|
syntaxTree(state).iterate({
|
2022-11-18 15:04:37 +00:00
|
|
|
enter: ({ type, from, to }) => {
|
2022-12-09 15:09:53 +00:00
|
|
|
if (isCursorInRange(state, [from, to])) return;
|
2022-11-18 15:04:37 +00:00
|
|
|
if (type.name === "ListMark") {
|
2022-12-09 15:09:53 +00:00
|
|
|
const listMark = state.sliceDoc(from, to);
|
2022-11-18 15:04:37 +00:00
|
|
|
if (bulletListMarkerRE.test(listMark)) {
|
|
|
|
const dec = Decoration.replace({
|
|
|
|
widget: new ListBulletWidget(listMark),
|
|
|
|
});
|
|
|
|
widgets.push(dec.range(from, to));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
return Decoration.set(widgets, true);
|
2022-12-09 15:09:53 +00:00
|
|
|
});
|
2022-11-18 15:04:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Widget to render list bullet mark.
|
|
|
|
*/
|
|
|
|
class ListBulletWidget extends WidgetType {
|
|
|
|
constructor(readonly bullet: string) {
|
|
|
|
super();
|
|
|
|
}
|
|
|
|
toDOM(): HTMLElement {
|
|
|
|
const listBullet = document.createElement("span");
|
|
|
|
listBullet.textContent = this.bullet;
|
|
|
|
listBullet.className = "cm-list-bullet";
|
|
|
|
return listBullet;
|
|
|
|
}
|
|
|
|
}
|