mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2025-12-21 13:41:29 +00:00
## 0.24.31
### Fixed - The description of `Enable Developers' Debug Tools.` has been refined. - Automatic conflict checking and resolution has been improved. - Resolving conflicts dialogue will not be shown for the multiple files at once.
This commit is contained in:
@@ -13,6 +13,7 @@ import { ConflictResolveModal } from "./InteractiveConflictResolving/ConflictRes
|
||||
import { AbstractObsidianModule, type IObsidianModule } from "../AbstractObsidianModule.ts";
|
||||
import { displayRev, getPath, getPathWithoutPrefix } from "../../common/utils.ts";
|
||||
import { fireAndForget } from "octagonal-wheels/promises";
|
||||
import { serialized } from "../../lib/src/concurrency/lock.ts";
|
||||
|
||||
export class ModuleInteractiveConflictResolver extends AbstractObsidianModule implements IObsidianModule {
|
||||
$everyOnloadStart(): Promise<boolean> {
|
||||
@@ -34,67 +35,71 @@ export class ModuleInteractiveConflictResolver extends AbstractObsidianModule im
|
||||
}
|
||||
|
||||
async $anyResolveConflictByUI(filename: FilePathWithPrefix, conflictCheckResult: diff_result): Promise<boolean> {
|
||||
this._log("Merge:open conflict dialog", LOG_LEVEL_VERBOSE);
|
||||
const dialog = new ConflictResolveModal(this.app, filename, conflictCheckResult);
|
||||
dialog.open();
|
||||
const selected = await dialog.waitForResult();
|
||||
if (selected === CANCELLED) {
|
||||
// Cancelled by UI, or another conflict.
|
||||
this._log(`Merge: Cancelled ${filename}`, LOG_LEVEL_INFO);
|
||||
return false;
|
||||
}
|
||||
const testDoc = await this.localDatabase.getDBEntry(filename, { conflicts: true }, false, true, true);
|
||||
if (testDoc === false) {
|
||||
this._log(`Merge: Could not read ${filename} from the local database`, LOG_LEVEL_VERBOSE);
|
||||
return false;
|
||||
}
|
||||
if (!testDoc._conflicts) {
|
||||
this._log(`Merge: Nothing to do ${filename}`, LOG_LEVEL_VERBOSE);
|
||||
return false;
|
||||
}
|
||||
const toDelete = selected;
|
||||
// const toKeep = conflictCheckResult.left.rev != toDelete ? conflictCheckResult.left.rev : conflictCheckResult.right.rev;
|
||||
if (toDelete === LEAVE_TO_SUBSEQUENT) {
|
||||
// Concatenate both conflicted revisions.
|
||||
// Create a new file by concatenating both conflicted revisions.
|
||||
const p = conflictCheckResult.diff.map((e) => e[1]).join("");
|
||||
const delRev = testDoc._conflicts[0];
|
||||
if (!(await this.core.databaseFileAccess.storeContent(filename, p))) {
|
||||
this._log(`Concatenated content cannot be stored:${filename}`, LOG_LEVEL_NOTICE);
|
||||
// UI for resolving conflicts should one-by-one.
|
||||
return await serialized(`conflict-resolve-ui`, async () => {
|
||||
this._log("Merge:open conflict dialog", LOG_LEVEL_VERBOSE);
|
||||
const dialog = new ConflictResolveModal(this.app, filename, conflictCheckResult);
|
||||
dialog.open();
|
||||
const selected = await dialog.waitForResult();
|
||||
if (selected === CANCELLED) {
|
||||
// Cancelled by UI, or another conflict.
|
||||
this._log(`Merge: Cancelled ${filename}`, LOG_LEVEL_INFO);
|
||||
return false;
|
||||
}
|
||||
// 2. As usual, delete the conflicted revision and if there are no conflicts, write the resolved content to the storage.
|
||||
if (
|
||||
(await this.core.$$resolveConflictByDeletingRev(filename, delRev, "UI Concatenated")) ==
|
||||
MISSING_OR_ERROR
|
||||
) {
|
||||
this._log(
|
||||
`Concatenated saved, but cannot delete conflicted revisions: ${filename}, (${displayRev(delRev)})`,
|
||||
LOG_LEVEL_NOTICE
|
||||
);
|
||||
const testDoc = await this.localDatabase.getDBEntry(filename, { conflicts: true }, false, true, true);
|
||||
if (testDoc === false) {
|
||||
this._log(`Merge: Could not read ${filename} from the local database`, LOG_LEVEL_VERBOSE);
|
||||
return false;
|
||||
}
|
||||
} else if (typeof toDelete === "string") {
|
||||
// Select one of the conflicted revision to delete.
|
||||
if (
|
||||
(await this.core.$$resolveConflictByDeletingRev(filename, toDelete, "UI Selected")) == MISSING_OR_ERROR
|
||||
) {
|
||||
if (!testDoc._conflicts) {
|
||||
this._log(`Merge: Nothing to do ${filename}`, LOG_LEVEL_VERBOSE);
|
||||
return false;
|
||||
}
|
||||
const toDelete = selected;
|
||||
// const toKeep = conflictCheckResult.left.rev != toDelete ? conflictCheckResult.left.rev : conflictCheckResult.right.rev;
|
||||
if (toDelete === LEAVE_TO_SUBSEQUENT) {
|
||||
// Concatenate both conflicted revisions.
|
||||
// Create a new file by concatenating both conflicted revisions.
|
||||
const p = conflictCheckResult.diff.map((e) => e[1]).join("");
|
||||
const delRev = testDoc._conflicts[0];
|
||||
if (!(await this.core.databaseFileAccess.storeContent(filename, p))) {
|
||||
this._log(`Concatenated content cannot be stored:${filename}`, LOG_LEVEL_NOTICE);
|
||||
return false;
|
||||
}
|
||||
// 2. As usual, delete the conflicted revision and if there are no conflicts, write the resolved content to the storage.
|
||||
if (
|
||||
(await this.core.$$resolveConflictByDeletingRev(filename, delRev, "UI Concatenated")) ==
|
||||
MISSING_OR_ERROR
|
||||
) {
|
||||
this._log(
|
||||
`Concatenated saved, but cannot delete conflicted revisions: ${filename}, (${displayRev(delRev)})`,
|
||||
LOG_LEVEL_NOTICE
|
||||
);
|
||||
return false;
|
||||
}
|
||||
} else if (typeof toDelete === "string") {
|
||||
// Select one of the conflicted revision to delete.
|
||||
if (
|
||||
(await this.core.$$resolveConflictByDeletingRev(filename, toDelete, "UI Selected")) ==
|
||||
MISSING_OR_ERROR
|
||||
) {
|
||||
this._log(`Merge: Something went wrong: ${filename}, (${toDelete})`, LOG_LEVEL_NOTICE);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
this._log(`Merge: Something went wrong: ${filename}, (${toDelete})`, LOG_LEVEL_NOTICE);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
this._log(`Merge: Something went wrong: ${filename}, (${toDelete})`, LOG_LEVEL_NOTICE);
|
||||
// In here, some merge has been processed.
|
||||
// So we have to run replication if configured.
|
||||
// TODO: Make this is as a event request
|
||||
if (this.settings.syncAfterMerge && !this.core.$$isSuspended()) {
|
||||
await this.core.$$replicateByEvent();
|
||||
}
|
||||
// And, check it again.
|
||||
await this.core.$$queueConflictCheck(filename);
|
||||
return false;
|
||||
}
|
||||
// In here, some merge has been processed.
|
||||
// So we have to run replication if configured.
|
||||
// TODO: Make this is as a event request
|
||||
if (this.settings.syncAfterMerge && !this.core.$$isSuspended()) {
|
||||
await this.core.$$replicateByEvent();
|
||||
}
|
||||
// And, check it again.
|
||||
await this.core.$$queueConflictCheck(filename);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
async allConflictCheck() {
|
||||
while (await this.pickFileForResolve());
|
||||
|
||||
Reference in New Issue
Block a user