Skip to content

Commit

Permalink
更改:添加 slice 接口,为 BreakLine 事件提供准备
Browse files Browse the repository at this point in the history
  • Loading branch information
SuiltaPico committed Nov 19, 2024
1 parent 03ee4bf commit a75d0ca
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 19 deletions.
9 changes: 7 additions & 2 deletions src/common/signal.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { Accessor, Setter, Signal, createSignal as solid_createSignal } from "solid-js";
import {
Accessor,
Setter,
Signal,
createSignal as solid_createSignal,
} from "solid-js";

export class WrappedSignal<T> {
get: Accessor<T>;
Expand Down Expand Up @@ -31,4 +36,4 @@ export class EmitterSignal {

export function createEmitterSignal() {
return new EmitterSignal();
}
}
4 changes: 3 additions & 1 deletion src/components/base/mix_editor/Area.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { BlockSavedData, InlineSavedData, InlineTagSavedData } from "./save";
import { WrappedSignal } from "@/common/signal";

export interface BaseArea {
/** 切割当前区域。 */
slice(from: number, to: number): MaybePromise<this>;
/** 生成保存数据。 */
save: () => MaybePromise<any>;
save(): MaybePromise<any>;

/** 获取子区域数量。 */
children_count(): number;
Expand Down
45 changes: 40 additions & 5 deletions src/components/base/mix_editor/event/BreakLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ import { MaybePromise } from "@/common/async";
import { Area } from "../Area";
import { BaseEvent } from "../event";
import { Selection } from "../selection";
import { find_index_in_parent_area } from "../utils/area";

export type BreakLineEventCommand =
| {
type: "break";
/** 输入的结束位置。 */
to: number;
}
| {
type: "no_break";
Expand All @@ -17,17 +16,53 @@ export const BreakLineEventCommand = {
/** 不接受断行。 */
no_break: { type: "no_break" } satisfies BreakLineEventCommand,
/** 接受断行,并把光标移动到指定位置。 */
break: (to: number) => ({ type: "break", to } satisfies BreakLineEventCommand),
break: { type: "break" } satisfies BreakLineEventCommand,
};

/** 输入事件。 */
export interface BreakLineEvent extends BaseEvent {
event_type: "break_line";
/** 输入的位置。 */
/** 要断行的位置。 */
to: number;
/** 是否从子节点进入。 */
from_child: boolean;
}

export type BreakLineEventPair = {
event: BreakLineEvent;
result: MaybePromise<BreakLineEventCommand>;
};
};

export async function handle_break_line_event_command(
selection: Selection,
curr_area: Area,
command: BreakLineEventCommand | void,
to: number
) {
let break_points: [Area, number][] = [[curr_area, to]];
while (true) {
command ??= BreakLineEventCommand.no_break;

if (command.type === "no_break") {
// 1. 自顶向下,切割每个区域的后半区域(不含要被切割的区域)
// 2. 自底向上,将自身补到上级的开头
// 3. 自顶向下,递归删除被切割的区域
} else if (command.type === "break") {
// 让父节点处理
const context = selection.editor.get_context(curr_area);
if (!context?.parent) return;

const index_in_parent = find_index_in_parent_area(
curr_area,
context.parent
);

curr_area = context.parent;
command = await curr_area.handle_event?.<BreakLineEventPair>({
event_type: "break_line",
to: index_in_parent,
from_child: true,
});
}
}
}
10 changes: 10 additions & 0 deletions src/components/base/mix_editor/plugins/paragraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,16 @@ export class ParagraphBlock<TInline extends Inline<any, any>>
{
area_type = "block" as const;
type = "paragraph" as const;
slice(from: number, to: number): this {
return new ParagraphBlock(
{
inlines: createSignal(this.data.inlines.get().slice(from, to), {
equals: false,
}),
},
this.editor
) as this;
}
async save() {
return create_BlockSaveData(this.type, {
inlines: await save_inlines(this.data.inlines.get()),
Expand Down
6 changes: 6 additions & 0 deletions src/components/base/mix_editor/plugins/text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ export class TextInline
area_type = "inline" as const;
type = "text" as const;
data: { value: WrappedSignal<string>; tags: WrappedSignal<InlineTag[]> };
slice(from: number, to: number) {
return new TextInline(
{ value: this.data.value.get().slice(from, to) },
this.editor
) as this;
}
async save() {
return create_InlineSaveData(
this.type,
Expand Down
3 changes: 3 additions & 0 deletions src/components/base/mix_editor/root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ export class RootArea implements Block<"root", {}> {
area_type = "block" as const;
type = "root" as const;
data = {};
slice(from: number, to: number): this {
throw new Error("根区域的切割未实现。");
}
save() {
return {
type: "root",
Expand Down
6 changes: 6 additions & 0 deletions src/components/base/mix_editor/save.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ export class LoadingErrorBlock
{
area_type = "block" as const;
type = "loading_error" as const;
slice(from: number, to: number) {
return new LoadingErrorBlock(this.data) as this;
}
save() {
return this.data.original;
}
Expand Down Expand Up @@ -129,6 +132,9 @@ export class LoadingErrorInline
{
area_type = "inline" as const;
type = "loading_error" as const;
slice(from: number, to: number) {
return new LoadingErrorInline(this.data) as this;
}
save() {
return this.data.original;
}
Expand Down
11 changes: 0 additions & 11 deletions src/components/base/mix_editor/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ import {
CaretMoveEnterEventPair,
handle_caret_move_enter_event_command
} from "./event/CaretMoveEnter";
import { CombineEventPair } from "./event/Combine";
import {
DeleteEventPair,
handle_delete_event_command
} from "./event/Delete";
import { EnterEventPair, handle_enter_result } from "./event/Enter";
import { MixEditor } from "./MixEditor";

export type SelectedAreaInfo = {
Expand Down Expand Up @@ -59,15 +57,6 @@ export class Selection {
return this.selected.get();
}

async enter(area: Area, to: number) {
const result = await area.handle_event?.<EnterEventPair>({
event_type: "enter",
to,
});

return await handle_enter_result(this, result, area, to);
}

private async move(direction: "backward" | "forward") {
const selected = this.selected.get();
if (!selected) return;
Expand Down

0 comments on commit a75d0ca

Please sign in to comment.