Files
voidraft/frontend/src/views/editor/extensions/codeblock/deleteLine.ts
2025-06-18 21:19:19 +08:00

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;
};