Sync while typing not just on save
This commit is contained in:
parent
60ed4e5109
commit
e5a0c5830a
4 changed files with 72 additions and 93 deletions
|
|
@ -1,58 +0,0 @@
|
||||||
import type { SyncClient } from "sync-client";
|
|
||||||
import type { TAbstractFile } from "obsidian";
|
|
||||||
import { TFile } from "obsidian";
|
|
||||||
|
|
||||||
export class ObsidianFileEventHandler {
|
|
||||||
public constructor(private readonly client: SyncClient) {}
|
|
||||||
|
|
||||||
public async onCreate(file: TAbstractFile): Promise<void> {
|
|
||||||
if (file instanceof TFile) {
|
|
||||||
this.client.logger.info(`File created: ${file.path}`);
|
|
||||||
|
|
||||||
await this.client.syncLocallyCreatedFile(file.path);
|
|
||||||
} else {
|
|
||||||
this.client.logger.debug(`Folder created: ${file.path}, ignored`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async onDelete(file: TAbstractFile): Promise<void> {
|
|
||||||
if (file instanceof TFile) {
|
|
||||||
this.client.logger.info(`File deleted: ${file.path}`);
|
|
||||||
|
|
||||||
await this.client.syncLocallyDeletedFile(file.path);
|
|
||||||
} else {
|
|
||||||
this.client.logger.debug(`Folder deleted: ${file.path}, ignored`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async onRename(file: TAbstractFile, oldPath: string): Promise<void> {
|
|
||||||
if (file instanceof TFile) {
|
|
||||||
this.client.logger.info(`File renamed: ${oldPath} -> ${file.path}`);
|
|
||||||
|
|
||||||
await this.client.syncLocallyUpdatedFile({
|
|
||||||
oldPath,
|
|
||||||
relativePath: file.path
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.client.logger.debug(
|
|
||||||
`Folder renamed: ${oldPath} -> ${file.path}, ignored`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async onModify(file: TAbstractFile): Promise<void> {
|
|
||||||
if (file instanceof TFile) {
|
|
||||||
if (file.basename.startsWith("console-log.iPhone")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.client.logger.info(`File modified: ${file.path}`);
|
|
||||||
|
|
||||||
await this.client.syncLocallyUpdatedFile({
|
|
||||||
relativePath: file.path
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.client.logger.debug(`Folder modified: ${file.path}, ignored`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +1,23 @@
|
||||||
import type { Stat, Vault } from "obsidian";
|
import type { Stat, Vault, Workspace } from "obsidian";
|
||||||
import { normalizePath } from "obsidian";
|
import { MarkdownView, normalizePath } from "obsidian";
|
||||||
import type { FileSystemOperations, RelativePath } from "sync-client";
|
import type { FileSystemOperations, RelativePath } from "sync-client";
|
||||||
|
|
||||||
export class ObsidianFileSystemOperations implements FileSystemOperations {
|
export class ObsidianFileSystemOperations implements FileSystemOperations {
|
||||||
public constructor(private readonly vault: Vault) {}
|
public constructor(
|
||||||
|
private readonly vault: Vault,
|
||||||
|
private readonly workspace: Workspace
|
||||||
|
) {}
|
||||||
|
|
||||||
public async listAllFiles(): Promise<RelativePath[]> {
|
public async listAllFiles(): Promise<RelativePath[]> {
|
||||||
return this.vault.getFiles().map((file) => file.path);
|
return this.vault.getFiles().map((file) => file.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async read(path: RelativePath): Promise<Uint8Array> {
|
public async read(path: RelativePath): Promise<Uint8Array> {
|
||||||
|
const view = this.workspace.getActiveViewOfType(MarkdownView);
|
||||||
|
if (view?.file?.path === path) {
|
||||||
|
return new TextEncoder().encode(view.editor.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
return new Uint8Array(
|
return new Uint8Array(
|
||||||
await this.vault.adapter.readBinary(normalizePath(path))
|
await this.vault.adapter.readBinary(normalizePath(path))
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
import type { WorkspaceLeaf } from "obsidian";
|
import type {
|
||||||
import { Platform, Plugin } from "obsidian";
|
Editor,
|
||||||
|
MarkdownFileInfo,
|
||||||
|
MarkdownView,
|
||||||
|
TAbstractFile,
|
||||||
|
WorkspaceLeaf
|
||||||
|
} from "obsidian";
|
||||||
|
import { Platform, Plugin, TFile } from "obsidian";
|
||||||
import "./styles.scss";
|
import "./styles.scss";
|
||||||
import "../manifest.json";
|
import "../manifest.json";
|
||||||
import { SyncSettingsTab } from "./views/settings-tab";
|
import { SyncSettingsTab } from "./views/settings-tab";
|
||||||
import { HistoryView } from "./views/history-view";
|
import { HistoryView } from "./views/history-view";
|
||||||
import { ObsidianFileEventHandler } from "./obisidan-event-handler";
|
|
||||||
import { StatusBar } from "./views/status-bar";
|
import { StatusBar } from "./views/status-bar";
|
||||||
import { LogsView } from "./views/logs-view";
|
import { LogsView } from "./views/logs-view";
|
||||||
import { StatusDescription } from "./views/status-description";
|
import { StatusDescription } from "./views/status-description";
|
||||||
|
|
@ -15,6 +20,7 @@ import { ObsidianFileSystemOperations } from "./obsidian-file-system";
|
||||||
export default class VaultLinkPlugin extends Plugin {
|
export default class VaultLinkPlugin extends Plugin {
|
||||||
private settingsTab: SyncSettingsTab | undefined;
|
private settingsTab: SyncSettingsTab | undefined;
|
||||||
private client!: SyncClient;
|
private client!: SyncClient;
|
||||||
|
|
||||||
private static registerConsoleForLogging(client: SyncClient): void {
|
private static registerConsoleForLogging(client: SyncClient): void {
|
||||||
client.logger.addOnMessageListener((logLine: LogLine) => {
|
client.logger.addOnMessageListener((logLine: LogLine) => {
|
||||||
const formatted = `${logLine.timestamp.toISOString()} ${logLine.level} ${logLine.message}`;
|
const formatted = `${logLine.timestamp.toISOString()} ${logLine.level} ${logLine.message}`;
|
||||||
|
|
@ -38,7 +44,10 @@ export default class VaultLinkPlugin extends Plugin {
|
||||||
|
|
||||||
public async onload(): Promise<void> {
|
public async onload(): Promise<void> {
|
||||||
this.client = await SyncClient.create({
|
this.client = await SyncClient.create({
|
||||||
fs: new ObsidianFileSystemOperations(this.app.vault),
|
fs: new ObsidianFileSystemOperations(
|
||||||
|
this.app.vault,
|
||||||
|
this.app.workspace
|
||||||
|
),
|
||||||
persistence: {
|
persistence: {
|
||||||
load: this.loadData.bind(this),
|
load: this.loadData.bind(this),
|
||||||
save: this.saveData.bind(this)
|
save: this.saveData.bind(this)
|
||||||
|
|
@ -80,35 +89,9 @@ export default class VaultLinkPlugin extends Plugin {
|
||||||
async (_: MouseEvent) => this.activateView(LogsView.TYPE)
|
async (_: MouseEvent) => this.activateView(LogsView.TYPE)
|
||||||
);
|
);
|
||||||
|
|
||||||
const eventHandler = new ObsidianFileEventHandler(this.client);
|
|
||||||
|
|
||||||
this.app.workspace.onLayoutReady(async () => {
|
this.app.workspace.onLayoutReady(async () => {
|
||||||
this.client.logger.info("Initialising sync handlers");
|
this.registerEditorEvents();
|
||||||
|
|
||||||
[
|
|
||||||
this.app.vault.on(
|
|
||||||
"create",
|
|
||||||
eventHandler.onCreate.bind(eventHandler)
|
|
||||||
),
|
|
||||||
this.app.vault.on(
|
|
||||||
"modify",
|
|
||||||
eventHandler.onModify.bind(eventHandler)
|
|
||||||
),
|
|
||||||
this.app.vault.on(
|
|
||||||
"delete",
|
|
||||||
eventHandler.onDelete.bind(eventHandler)
|
|
||||||
),
|
|
||||||
this.app.vault.on(
|
|
||||||
"rename",
|
|
||||||
eventHandler.onRename.bind(eventHandler)
|
|
||||||
)
|
|
||||||
].forEach((event) => {
|
|
||||||
this.registerEvent(event);
|
|
||||||
});
|
|
||||||
|
|
||||||
void this.client.start();
|
void this.client.start();
|
||||||
|
|
||||||
this.client.logger.info("Sync handlers initialised");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,4 +128,51 @@ export default class VaultLinkPlugin extends Plugin {
|
||||||
await workspace.revealLeaf(leaf);
|
await workspace.revealLeaf(leaf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private registerEditorEvents() {
|
||||||
|
[
|
||||||
|
this.app.workspace.on(
|
||||||
|
"editor-change",
|
||||||
|
async (
|
||||||
|
_editor: Editor,
|
||||||
|
info: MarkdownView | MarkdownFileInfo
|
||||||
|
) => {
|
||||||
|
const file = info.file;
|
||||||
|
if (file) {
|
||||||
|
await this.client.syncLocallyUpdatedFile({
|
||||||
|
relativePath: file.path
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
this.app.vault.on("create", async (file: TAbstractFile) => {
|
||||||
|
if (file instanceof TFile) {
|
||||||
|
await this.client.syncLocallyCreatedFile(file.path);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
this.app.vault.on("modify", async (file: TAbstractFile) => {
|
||||||
|
if (file instanceof TFile) {
|
||||||
|
await this.client.syncLocallyUpdatedFile({
|
||||||
|
relativePath: file.path
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
this.app.vault.on("delete", async (file: TAbstractFile) => {
|
||||||
|
await this.client.syncLocallyDeletedFile(file.path);
|
||||||
|
}),
|
||||||
|
this.app.vault.on(
|
||||||
|
"rename",
|
||||||
|
async (file: TAbstractFile, oldPath: string) => {
|
||||||
|
if (file instanceof TFile) {
|
||||||
|
await this.client.syncLocallyUpdatedFile({
|
||||||
|
oldPath,
|
||||||
|
relativePath: file.path
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
].forEach((event) => {
|
||||||
|
this.registerEvent(event);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import type { IconName, WorkspaceLeaf } from "obsidian";
|
import type { IconName, WorkspaceLeaf } from "obsidian";
|
||||||
import { ItemView, setIcon } from "obsidian";
|
import { ItemView, setIcon } from "obsidian";
|
||||||
|
|
||||||
import { intlFormatDistance } from "date-fns";
|
import { intlFormatDistance } from "date-fns";
|
||||||
import type { HistoryEntry, SyncClient } from "sync-client";
|
import type { HistoryEntry, SyncClient } from "sync-client";
|
||||||
import { SyncType } from "sync-client";
|
import { SyncType } from "sync-client";
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue