134 lines
3.0 KiB
TypeScript
134 lines
3.0 KiB
TypeScript
/**
|
|
* 删除行功能
|
|
* 处理代码块边界
|
|
*/
|
|
|
|
import { EditorSelection, SelectionRange } from "@codemirror/state";
|
|
import { EditorView } from "@codemirror/view";
|
|
import { getNoteBlockFromPos } from "./state";
|
|
|
|
interface LineBlock {
|
|
from: number;
|
|
to: number;
|
|
ranges: SelectionRange[];
|
|
}
|
|
|
|
/**
|
|
* 更新选择范围
|
|
*/
|
|
function updateSel(sel: EditorSelection, by: (range: SelectionRange) => SelectionRange): EditorSelection {
|
|
return EditorSelection.create(sel.ranges.map(by), sel.mainIndex);
|
|
}
|
|
|
|
/**
|
|
* 获取选中的行块
|
|
*/
|
|
function selectedLineBlocks(state: any): LineBlock[] {
|
|
let blocks: LineBlock[] = [];
|
|
let upto = -1;
|
|
|
|
for (let range of state.selection.ranges) {
|
|
let startLine = state.doc.lineAt(range.from);
|
|
let endLine = state.doc.lineAt(range.to);
|
|
|
|
if (!range.empty && range.to == endLine.from) {
|
|
endLine = state.doc.lineAt(range.to - 1);
|
|
}
|
|
|
|
if (upto >= startLine.number) {
|
|
let prev = blocks[blocks.length - 1];
|
|
prev.to = endLine.to;
|
|
prev.ranges.push(range);
|
|
} else {
|
|
blocks.push({
|
|
from: startLine.from,
|
|
to: endLine.to,
|
|
ranges: [range]
|
|
});
|
|
}
|
|
upto = endLine.number + 1;
|
|
}
|
|
|
|
return blocks;
|
|
}
|
|
|
|
/**
|
|
* 删除行命令
|
|
*/
|
|
export const deleteLine = (view: EditorView): boolean => {
|
|
if (view.state.readOnly) {
|
|
return false;
|
|
}
|
|
|
|
const { state } = view;
|
|
const selectedLines = selectedLineBlocks(state);
|
|
|
|
const changes = state.changes(selectedLines.map(({ from, to }) => {
|
|
const block = getNoteBlockFromPos(state, from);
|
|
|
|
// 如果不是删除整个代码块,需要调整删除范围
|
|
if (block && (from !== block.content.from || to !== block.content.to)) {
|
|
if (from > 0) {
|
|
from--;
|
|
} else if (to < state.doc.length) {
|
|
to++;
|
|
}
|
|
}
|
|
|
|
return { from, to };
|
|
}));
|
|
|
|
const selection = updateSel(
|
|
state.selection,
|
|
range => view.moveVertically(range, true)
|
|
).map(changes);
|
|
|
|
view.dispatch({
|
|
changes,
|
|
selection,
|
|
scrollIntoView: true,
|
|
userEvent: "delete.line"
|
|
});
|
|
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* 删除行命令函数,用于键盘映射
|
|
*/
|
|
export const deleteLineCommand = ({ state, dispatch }: { state: any; dispatch: any }) => {
|
|
if (state.readOnly) {
|
|
return false;
|
|
}
|
|
|
|
const selectedLines = selectedLineBlocks(state);
|
|
|
|
const changes = state.changes(selectedLines.map(({ from, to }: LineBlock) => {
|
|
const block = getNoteBlockFromPos(state, from);
|
|
|
|
// 如果不是删除整个代码块,需要调整删除范围
|
|
if (block && (from !== block.content.from || to !== block.content.to)) {
|
|
if (from > 0) {
|
|
from--;
|
|
} else if (to < state.doc.length) {
|
|
to++;
|
|
}
|
|
}
|
|
|
|
return { from, to };
|
|
}));
|
|
|
|
const selection = updateSel(
|
|
state.selection,
|
|
range => EditorSelection.cursor(range.from)
|
|
).map(changes);
|
|
|
|
dispatch(state.update({
|
|
changes,
|
|
selection,
|
|
scrollIntoView: true,
|
|
userEvent: "delete.line"
|
|
}));
|
|
|
|
return true;
|
|
};
|