Skip to content

Commit e188921

Browse files
committed
refactoringを試みた
1 parent c563d15 commit e188921

File tree

2 files changed

+122
-96
lines changed

2 files changed

+122
-96
lines changed

browser/websocket/_codeBlock.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,30 +29,29 @@ export async function applyCommit(
2929
}
3030

3131
/** 新規コードブロックのコミットを作成する */
32-
export async function makeCommitsNewCodeBlock(
32+
export function* makeCommitsNewCodeBlock(
3333
code: CodeFile,
3434
insertLineId: string,
35-
): Promise<InsertCommit[]> {
36-
const userId = await getUserId();
35+
{ userId }: { userId: string },
36+
): Generator<InsertCommit, void, unknown> {
3737
const codeName = code.filename + (code.lang ? `(${code.lang})` : "");
3838
const codeBody = Array.isArray(code.content)
3939
? code.content
4040
: code.content.split("\n");
41-
const commits: InsertCommit[] = [{
41+
yield {
4242
_insert: insertLineId,
4343
lines: {
4444
id: createNewLineId(userId),
4545
text: `code:${codeName}`,
4646
},
47-
}];
47+
};
4848
for (const bodyLine of codeBody) {
49-
commits.push({
49+
yield {
5050
_insert: insertLineId,
5151
lines: {
5252
id: createNewLineId(userId),
5353
text: " " + bodyLine,
5454
},
55-
});
55+
};
5656
}
57-
return commits;
5857
}

browser/websocket/updateCodeFile.ts

Lines changed: 115 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import {
88
} from "../../deps/socket.ts";
99
import { pull } from "./pull.ts";
1010
import { getCodeBlocks, TinyCodeBlock } from "./getCodeBlocks.ts";
11-
import { diffToChanges } from "./diffToChanges.ts";
12-
import { getUserId } from "./id.ts";
11+
import { createNewLineId, getUserId } from "./id.ts";
12+
import { diff, toExtendedChanges } from "../../deps/onp.ts";
1313
import { applyCommit, makeCommitsNewCodeBlock } from "./_codeBlock.ts";
1414

1515
/** コードブロックの上書きに使う情報のinterface */
@@ -35,10 +35,13 @@ export interface UpdateCodeFileOptions {
3535
*/
3636
insertPositionIfNotExist?: "top" | "bottom" | "notInsert";
3737

38+
/** `true`の場合、コードブロック作成時に空行承り太郎(ページ末尾に必ず空行を設ける機能)を有効する(既定は`true`) */
39+
isInsertEmptyLineInTail?: boolean;
40+
3841
/** WebSocketの通信に使うsocket */
3942
socket?: Socket;
4043

41-
/** trueでデバッグ出力ON */
44+
/** `true`でデバッグ出力ON */
4245
debug?: boolean;
4346
}
4447

@@ -63,6 +66,7 @@ export const updateCodeFile = async (
6366
/** optionsの既定値はこの中に入れる */
6467
const defaultOptions: Required<UpdateCodeFileOptions> = {
6568
insertPositionIfNotExist: "notInsert",
69+
isInsertEmptyLineInTail: true,
6670
socket: options?.socket ?? await socketIO(),
6771
debug: false,
6872
};
@@ -77,59 +81,22 @@ export const updateCodeFile = async (
7781
}, {
7882
filename: codeFile.filename,
7983
});
80-
const codeBodies = flatCodeBodies(codeBlocks);
81-
82-
if (codeBlocks.length <= 0) {
83-
// 更新対象のコードブロックが存在していなかった場合は、新しいコードブロックを作成して終了する
84-
if (opt.insertPositionIfNotExist === "notInsert") return;
85-
const insertLineId =
86-
opt.insertPositionIfNotExist === "top" && lines.length >= 1
87-
? lines[1].id
88-
: "_end";
89-
const commits = await makeCommitsNewCodeBlock(
90-
codeFile,
91-
insertLineId,
92-
);
93-
if (codeBodies.length <= 0) {
94-
await applyCommit(commits, head, project, title, opt.socket);
95-
}
96-
return;
97-
} else if (codeBodies.length <= 0) {
98-
// codeBodiesが無かった場合はdiffToChangesが例外を引き起こすので、その対策
99-
const insertLineId = codeBlocks[0].nextLine
100-
? codeBlocks[0].nextLine.id
101-
: "_end";
102-
const commits = await makeCommitsNewCodeBlock(
103-
codeFile,
104-
insertLineId,
105-
);
106-
if (codeBodies.length <= 0) {
107-
await applyCommit(commits.splice(1), head, project, title, opt.socket);
108-
}
109-
return;
110-
}
111-
112-
const changes = [...diffToChanges(
113-
codeBodies,
114-
newCode,
115-
{ userId: await getUserId() },
116-
)];
117-
118-
// insert行のIDと各行のインデントを修正する
119-
const commits = fixCommits(changes, codeBlocks);
84+
const commits = [
85+
...makeCommits(codeBlocks, codeFile, lines, {
86+
...opt,
87+
userId: await getUserId(),
88+
}),
89+
];
12090

12191
if (opt.debug) {
12292
console.log("vvv original code Blocks vvv");
12393
console.log(codeBlocks);
124-
console.log("vvv original code lines vvv");
125-
console.log(codeBodies);
12694
console.log("vvv new codes vvv");
12795
console.log(newCode);
12896
console.log("vvv commits vvv");
12997
console.log(commits);
13098
}
13199

132-
// 差分を送信
133100
await applyCommit(commits, head, project, title, opt.socket);
134101

135102
if (!options?.socket) opt.socket.disconnect();
@@ -148,50 +115,110 @@ function flatCodeBodies(codeBlocks: readonly TinyCodeBlock[]): Line[] {
148115
}).flat();
149116
}
150117

151-
/** insert行のIDと各行のインデントを修正する */
152-
function fixCommits(
153-
commits: (InsertCommit | UpdateCommit | DeleteCommit)[],
118+
/** コードブロックの差分からコミットデータを作成する */
119+
function* makeCommits(
154120
codeBlocks: TinyCodeBlock[],
155-
) {
156-
const idReplacePatterns: {
157-
from: string;
158-
to: string;
159-
}[] = (() => {
160-
const patterns = [];
161-
for (let i = 0; i < codeBlocks.length; i++) {
162-
// コード本体の先頭ID -> 1つ前のコードブロックの真下の行のID
163-
const currentCode = codeBlocks[i];
164-
const nextCode = codeBlocks[i + 1];
165-
if (!currentCode.nextLine) continue;
166-
patterns.push({
167-
from: nextCode?.bodyLines[0].id ?? "_end",
168-
to: currentCode.nextLine.id,
169-
});
121+
codeFile: CodeFile,
122+
lines: Line[],
123+
{ userId, insertPositionIfNotExist, isInsertEmptyLineInTail }: {
124+
userId: string;
125+
insertPositionIfNotExist: Required<
126+
UpdateCodeFileOptions["insertPositionIfNotExist"]
127+
>;
128+
isInsertEmptyLineInTail: Required<
129+
UpdateCodeFileOptions["isInsertEmptyLineInTail"]
130+
>;
131+
},
132+
): Generator<DeleteCommit | InsertCommit | UpdateCommit, void, unknown> {
133+
function makeIndent(codeBlock: TinyCodeBlock): string {
134+
const title = codeBlock.titleLine.text;
135+
const count = title.length - title.trimStart().length + 1;
136+
return " ".repeat(count);
137+
}
138+
139+
const codeBodies = flatCodeBodies(codeBlocks);
140+
if (codeBodies.length <= 0) {
141+
// ページ内にコードブロックが無かった場合は新しく作成して終了する
142+
if (insertPositionIfNotExist === "notInsert") return;
143+
const insertLineId = insertPositionIfNotExist === "top" && lines.length > 1
144+
? lines[1].id
145+
: "_end";
146+
const commits = makeCommitsNewCodeBlock(
147+
codeFile,
148+
insertLineId,
149+
{ userId },
150+
);
151+
let isInsertBottom = false;
152+
for (const commit of commits) {
153+
if (commit._insert == "_end") isInsertBottom = true;
154+
yield commit;
170155
}
171-
return patterns;
172-
})();
173-
for (const commit of commits) {
174-
if ("_delete" in commit) continue;
175-
else if ("_insert" in commit) {
176-
// ID修正
177-
for (const pattern of idReplacePatterns) {
178-
if (commit._insert !== pattern.from) continue;
179-
commit._insert = pattern.to;
180-
break;
181-
}
156+
if (isInsertBottom && isInsertEmptyLineInTail) {
157+
// 空行承り太郎
158+
yield {
159+
_insert: "_end",
160+
lines: {
161+
id: createNewLineId(userId),
162+
text: "",
163+
},
164+
};
182165
}
183-
// インデント挿入
184-
const belongBlock = codeBlocks.find((block) => {
185-
const targetId = "_update" in commit ? commit._update : commit._insert;
186-
if (block.bodyLines.some((e) => e.id === targetId)) return true;
187-
if ("_update" in commit) return false;
188-
if (targetId === block.nextLine?.id) return true;
189-
return false;
190-
});
191-
if (belongBlock === undefined) continue;
192-
const titleText = belongBlock.titleLine.text;
193-
const indent = titleText.length - titleText.trimStart().length + 1;
194-
commit.lines.text = " ".repeat(indent) + commit.lines.text;
166+
return;
167+
}
168+
169+
// 差分を求める
170+
const { buildSES } = diff(
171+
codeBodies.map((e) => e.text),
172+
Array.isArray(codeFile.content)
173+
? codeFile.content
174+
: codeFile.content.split("\n"),
175+
);
176+
let lineNo = 0;
177+
for (const change of toExtendedChanges(buildSES())) {
178+
// 差分からcommitを作成
179+
const { lineId, codeIndex } =
180+
((): { lineId: string; codeIndex: number } => {
181+
if (lineNo >= codeBodies.length) {
182+
const index = codeBlocks.length - 1;
183+
return {
184+
lineId: codeBlocks[index].nextLine?.id ?? "_end",
185+
codeIndex: index,
186+
};
187+
}
188+
return {
189+
lineId: codeBodies[lineNo].id,
190+
codeIndex: codeBlocks.findIndex((e0) =>
191+
e0.bodyLines.some((e1) => e1.id == codeBodies[lineNo].id)
192+
),
193+
};
194+
})();
195+
const codeBlock = codeBlocks[codeIndex];
196+
if (change.type == "added") {
197+
const codeBlockInsert =
198+
lineId == codeBlock.bodyLines[0].id && codeIndex >= 1
199+
? codeBlocks[codeIndex - 1]
200+
: codeBlocks[codeIndex];
201+
yield {
202+
_insert: codeBlockInsert.nextLine?.id ?? "_end",
203+
lines: {
204+
id: createNewLineId(userId),
205+
text: makeIndent(codeBlockInsert) + change.value,
206+
},
207+
};
208+
continue;
209+
} else if (change.type == "deleted") {
210+
yield {
211+
_delete: lineId,
212+
lines: -1,
213+
};
214+
} else if (change.type == "replaced") {
215+
yield {
216+
_update: lineId,
217+
lines: {
218+
text: makeIndent(codeBlock) + change.value,
219+
},
220+
};
221+
}
222+
lineNo++;
195223
}
196-
return commits;
197224
}

0 commit comments

Comments
 (0)