Fix and apply editorconfig
This commit is contained in:
parent
4150eb2720
commit
ce31969a44
11 changed files with 423 additions and 418 deletions
|
|
@ -11,5 +11,6 @@ indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
tab_width = 4
|
tab_width = 4
|
||||||
|
|
||||||
[*.{yml,yaml}]
|
[*.{yml,yaml,md}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
tab_width = 2
|
||||||
|
|
|
||||||
2
.github/workflows/check.yml
vendored
2
.github/workflows/check.yml
vendored
|
|
@ -22,7 +22,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
node-version: "22.x"
|
node-version: "22.x"
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
|
||||||
- name: Setup Rust toolchain
|
- name: Setup Rust toolchain
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
|
|
|
||||||
|
|
@ -125,37 +125,37 @@ sequenceDiagram
|
||||||
```
|
```
|
||||||
┌─────────┐
|
┌─────────┐
|
||||||
│ Client │
|
│ Client │
|
||||||
└────┬────┘
|
└───┬─-───┘
|
||||||
│ 1. Detect file change
|
│ 1. Detect file change
|
||||||
│
|
│
|
||||||
├─► 2. Read file content
|
├─► 2. Read file content
|
||||||
│
|
│
|
||||||
├─► 3. Create upload message
|
├─► 3. Create upload message
|
||||||
│ {
|
│ {
|
||||||
│ type: "upload_file",
|
│ type: "upload_file",
|
||||||
│ path: "notes/daily.md",
|
│ path: "notes/daily.md",
|
||||||
│ content: "...",
|
│ content: "...",
|
||||||
│ version: 42,
|
│ version: 42,
|
||||||
│ timestamp: "2024-01-01T12:00:00Z"
|
│ timestamp: "2024-01-01T12:00:00Z"
|
||||||
│ }
|
│ }
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌─────────┐
|
┌─────────┐
|
||||||
│ Server │
|
│ Server │
|
||||||
└────┬────┘
|
└───┬────-┘
|
||||||
│ 4. Validate message
|
│ 4. Validate message
|
||||||
│
|
│
|
||||||
├─► 5. Check permissions
|
├─► 5. Check permissions
|
||||||
│
|
│
|
||||||
├─► 6. Apply OT (if conflicts)
|
├─► 6. Apply OT (if conflicts)
|
||||||
│
|
│
|
||||||
├─► 7. Store in database
|
├─► 7. Store in database
|
||||||
│
|
│
|
||||||
├─► 8. Update version
|
├─► 8. Update version
|
||||||
│
|
│
|
||||||
├─► 9. Broadcast to clients
|
├─► 9. Broadcast to clients
|
||||||
│
|
│
|
||||||
└─► 10. Send ACK to uploader
|
└─► 10. Send ACK to uploader
|
||||||
```
|
```
|
||||||
|
|
||||||
### Download
|
### Download
|
||||||
|
|
@ -163,36 +163,36 @@ sequenceDiagram
|
||||||
```
|
```
|
||||||
┌─────────┐
|
┌─────────┐
|
||||||
│ Server │
|
│ Server │
|
||||||
└────┬────┘
|
└───┬─-───┘
|
||||||
│ 1. File updated by another client
|
│ 1. File updated by another client
|
||||||
│
|
│
|
||||||
├─► 2. Broadcast notification
|
├─► 2. Broadcast notification
|
||||||
│ {
|
│ {
|
||||||
│ type: "file_updated",
|
│ type: "file_updated",
|
||||||
│ path: "notes/daily.md",
|
│ path: "notes/daily.md",
|
||||||
│ version: 43
|
│ version: 43
|
||||||
│ }
|
│ }
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌─────────┐
|
┌─────────┐
|
||||||
│ Client │
|
│ Client │
|
||||||
└────┬────┘
|
└───┬─-───┘
|
||||||
│ 3. Receive notification
|
│ 3. Receive notification
|
||||||
│
|
│
|
||||||
├─► 4. Request file download
|
├─► 4. Request file download
|
||||||
│ {
|
│ {
|
||||||
│ type: "download_file",
|
│ type: "download_file",
|
||||||
│ path: "notes/daily.md",
|
│ path: "notes/daily.md",
|
||||||
│ version: 43
|
│ version: 43
|
||||||
│ }
|
│ }
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌─────────┐
|
┌─────────┐
|
||||||
│ Server │
|
│ Server │
|
||||||
└────┬────┘
|
└───┬─=───┘
|
||||||
│ 5. Retrieve from database
|
│ 5. Retrieve from database
|
||||||
│
|
│
|
||||||
└─► 6. Send file content
|
└─► 6. Send file content
|
||||||
{
|
{
|
||||||
type: "file_content",
|
type: "file_content",
|
||||||
path: "notes/daily.md",
|
path: "notes/daily.md",
|
||||||
|
|
@ -201,9 +201,9 @@ sequenceDiagram
|
||||||
}
|
}
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌─────────┐
|
┌─────────┐
|
||||||
│ Client │
|
│ Client │
|
||||||
└────┬────┘
|
└───-─┬───┘
|
||||||
│ 7. Write to filesystem
|
│ 7. Write to filesystem
|
||||||
│
|
│
|
||||||
└─► 8. Update local metadata
|
└─► 8. Update local metadata
|
||||||
|
|
@ -215,30 +215,30 @@ sequenceDiagram
|
||||||
┌─────────┐
|
┌─────────┐
|
||||||
│ Client │
|
│ Client │
|
||||||
└────┬────┘
|
└────┬────┘
|
||||||
│ 1. File deleted locally
|
│ 1. File deleted locally
|
||||||
│
|
│
|
||||||
├─► 2. Send delete message
|
├─► 2. Send delete message
|
||||||
│ {
|
│ {
|
||||||
│ type: "delete_file",
|
│ type: "delete_file",
|
||||||
│ path: "notes/old.md"
|
│ path: "notes/old.md"
|
||||||
│ }
|
│ }
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌─────────┐
|
┌─────────┐
|
||||||
│ Server │
|
│ Server │
|
||||||
└────┬────┘
|
└────┬────┘
|
||||||
│ 3. Mark as deleted in DB
|
│ 3. Mark as deleted in DB
|
||||||
│ (soft delete for history)
|
│ (soft delete for history)
|
||||||
│
|
│
|
||||||
├─► 4. Broadcast deletion
|
├─► 4. Broadcast deletion
|
||||||
│
|
│
|
||||||
└─► 5. ACK to sender
|
└─► 5. ACK to sender
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌─────────┐
|
┌─────────┐
|
||||||
│ Other │
|
│ Other │
|
||||||
│ Clients │
|
│ Clients │
|
||||||
└────┬────┘
|
└────┬────┘
|
||||||
│ 6. Delete local file
|
│ 6. Delete local file
|
||||||
│
|
│
|
||||||
└─► 7. Update metadata
|
└─► 7. Update metadata
|
||||||
|
|
@ -252,32 +252,32 @@ sequenceDiagram
|
||||||
Time →
|
Time →
|
||||||
|
|
||||||
Client A Server Client B
|
Client A Server Client B
|
||||||
│ │ │
|
│ │ │
|
||||||
│ Edit file v10 │ │
|
│ Edit file v10 │ │
|
||||||
│ "Add line A" │ │ Edit file v10
|
│ "Add line A" │ │ Edit file v10
|
||||||
│ │ │ "Add line B"
|
│ │ │ "Add line B"
|
||||||
│ │ │
|
│ │ │
|
||||||
├─── Upload @ t1 ─────────►│ │
|
├─── Upload @ t1 ─────────►│ │
|
||||||
│ │◄────── Upload @ t2 ────────┤
|
│ │◄────── Upload @ t2 ────────┤
|
||||||
│ │ │
|
│ │ │
|
||||||
│ │ 1. Receive both edits │
|
│ │ 1. Receive both edits │
|
||||||
│ │ (based on v10) │
|
│ │ (based on v10) │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ │ 2. Apply first edit │
|
│ │ 2. Apply first edit │
|
||||||
│ │ → v11 (line A added) │
|
│ │ → v11 (line A added) │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ │ 3. Transform second edit │
|
│ │ 3. Transform second edit │
|
||||||
│ │ against first │
|
│ │ against first │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ │ 4. Apply transformed edit │
|
│ │ 4. Apply transformed edit │
|
||||||
│ │ → v12 (both lines) │
|
│ │ → v12 (both lines) │
|
||||||
│ │ │
|
│ │ │
|
||||||
│◄──── v12 content ────────┤ │
|
│◄──── v12 content ────────┤ │
|
||||||
│ ├───── v12 content ─────────►│
|
│ ├───── v12 content ─────────►│
|
||||||
│ │ │
|
│ │ │
|
||||||
│ Apply v12 │ │ Apply v12
|
│ Apply v12 │ │ Apply v12
|
||||||
│ (has both lines) │ │ (has both lines)
|
│ (has both lines) │ │ (has both lines)
|
||||||
│ │ │
|
│ │ │
|
||||||
```
|
```
|
||||||
|
|
||||||
### Conflict Resolution Steps
|
### Conflict Resolution Steps
|
||||||
|
|
@ -361,11 +361,11 @@ VALUES (?, ?, ?);
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "upload_file",
|
"type": "upload_file",
|
||||||
"path": "notes/example.md",
|
"path": "notes/example.md",
|
||||||
"content": "File content here...",
|
"content": "File content here...",
|
||||||
"base_version": 10,
|
"base_version": 10,
|
||||||
"timestamp": "2024-01-01T12:00:00Z"
|
"timestamp": "2024-01-01T12:00:00Z"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -373,8 +373,8 @@ VALUES (?, ?, ?);
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "download_file",
|
"type": "download_file",
|
||||||
"path": "notes/example.md"
|
"path": "notes/example.md"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -382,8 +382,8 @@ VALUES (?, ?, ?);
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "delete_file",
|
"type": "delete_file",
|
||||||
"path": "notes/old.md"
|
"path": "notes/old.md"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -391,8 +391,8 @@ VALUES (?, ?, ?);
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "list_files",
|
"type": "list_files",
|
||||||
"since_version": 0
|
"since_version": 0
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -402,11 +402,11 @@ VALUES (?, ?, ?);
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "file_updated",
|
"type": "file_updated",
|
||||||
"path": "notes/example.md",
|
"path": "notes/example.md",
|
||||||
"version": 11,
|
"version": 11,
|
||||||
"size": 1024,
|
"size": 1024,
|
||||||
"hash": "abc123..."
|
"hash": "abc123..."
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -414,10 +414,10 @@ VALUES (?, ?, ?);
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "file_content",
|
"type": "file_content",
|
||||||
"path": "notes/example.md",
|
"path": "notes/example.md",
|
||||||
"content": "Updated content...",
|
"content": "Updated content...",
|
||||||
"version": 11
|
"version": 11
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -425,9 +425,9 @@ VALUES (?, ?, ?);
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "file_deleted",
|
"type": "file_deleted",
|
||||||
"path": "notes/old.md",
|
"path": "notes/old.md",
|
||||||
"version": 12
|
"version": 12
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -435,9 +435,9 @@ VALUES (?, ?, ?);
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "sync_complete",
|
"type": "sync_complete",
|
||||||
"total_files": 150,
|
"total_files": 150,
|
||||||
"current_version": 200
|
"current_version": 200
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -445,9 +445,9 @@ VALUES (?, ?, ?);
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "error",
|
"type": "error",
|
||||||
"message": "File too large",
|
"message": "File too large",
|
||||||
"code": "FILE_TOO_LARGE"
|
"code": "FILE_TOO_LARGE"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@ Central sync server with multiple clients. High-level architecture and design de
|
||||||
│ Obsidian Plugin │ Obsidian Plugin │ CLI Client │
|
│ Obsidian Plugin │ Obsidian Plugin │ CLI Client │
|
||||||
│ (User A - Device1) │ (User A - Device2│ (Server/Backup) │
|
│ (User A - Device1) │ (User A - Device2│ (Server/Backup) │
|
||||||
└──────────┬──────────┴─────────┬─────────┴──────────┬────────┘
|
└──────────┬──────────┴─────────┬─────────┴──────────┬────────┘
|
||||||
│ │ │
|
│ │ │
|
||||||
│ WebSocket │ WebSocket │ WebSocket
|
│ WebSocket │ WebSocket │ WebSocket
|
||||||
│ │ │
|
│ │ │
|
||||||
└────────────────────┼────────────────────┘
|
└────────────────────┼────────────────────┘
|
||||||
│
|
│
|
||||||
┌───────────▼───────────┐
|
┌───────────▼───────────┐
|
||||||
│ Sync Server │
|
│ Sync Server │
|
||||||
|
|
|
||||||
|
|
@ -243,9 +243,9 @@ users:
|
||||||
2. Client sends authentication message:
|
2. Client sends authentication message:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "auth",
|
"type": "auth",
|
||||||
"token": "user-token",
|
"token": "user-token",
|
||||||
"vault": "vault-name"
|
"vault": "vault-name"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
3. Server validates:
|
3. Server validates:
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"lib": [
|
"lib": [
|
||||||
"DOM", // to get `fetch` & `WebSocket`
|
"DOM", // to get `fetch` & `WebSocket`
|
||||||
"ES2024"
|
"ES2024"
|
||||||
],
|
],
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"rootDir": "./src",
|
"rootDir": "./src",
|
||||||
|
|
@ -18,5 +18,7 @@
|
||||||
"declarationMap": true,
|
"declarationMap": true,
|
||||||
"sourceMap": true
|
"sourceMap": true
|
||||||
},
|
},
|
||||||
"exclude": ["dist"]
|
"exclude": [
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,32 +2,32 @@ const path = require("path");
|
||||||
const webpack = require("webpack");
|
const webpack = require("webpack");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
cli: "./src/cli.ts",
|
cli: "./src/cli.ts",
|
||||||
healthcheck: "./src/healthcheck.ts"
|
healthcheck: "./src/healthcheck.ts"
|
||||||
},
|
},
|
||||||
target: "node",
|
target: "node",
|
||||||
mode: "production",
|
mode: "production",
|
||||||
optimization: {
|
optimization: {
|
||||||
minimize: false
|
minimize: false
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.ts$/,
|
test: /\.ts$/,
|
||||||
use: "ts-loader"
|
use: "ts-loader"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [".ts", ".js"]
|
extensions: [".ts", ".js"]
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
globalObject: "this",
|
globalObject: "this",
|
||||||
filename: "[name].js",
|
filename: "[name].js",
|
||||||
path: path.resolve(__dirname, "dist")
|
path: path.resolve(__dirname, "dist")
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.BannerPlugin({ banner: "#!/usr/bin/env node", raw: true })
|
new webpack.BannerPlugin({ banner: "#!/usr/bin/env node", raw: true })
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import type {
|
import type {
|
||||||
MarkdownView,
|
MarkdownView,
|
||||||
Editor,
|
Editor,
|
||||||
MarkdownFileInfo,
|
MarkdownFileInfo,
|
||||||
TAbstractFile,
|
TAbstractFile,
|
||||||
WorkspaceLeaf
|
WorkspaceLeaf
|
||||||
} from "obsidian";
|
} from "obsidian";
|
||||||
import { Notice, Platform, Plugin, TFile } from "obsidian";
|
import { Notice, Platform, Plugin, TFile } from "obsidian";
|
||||||
import "../manifest.json";
|
import "../manifest.json";
|
||||||
|
|
@ -12,19 +12,19 @@ import { StatusBar } from "./views/status-bar/status-bar";
|
||||||
import { LogsView } from "./views/logs/logs-view";
|
import { LogsView } from "./views/logs/logs-view";
|
||||||
import { StatusDescription } from "./views/status-description/status-description";
|
import { StatusDescription } from "./views/status-description/status-description";
|
||||||
import {
|
import {
|
||||||
SyncClient,
|
SyncClient,
|
||||||
rateLimit,
|
rateLimit,
|
||||||
DEFAULT_SETTINGS,
|
DEFAULT_SETTINGS,
|
||||||
Logger,
|
Logger,
|
||||||
debugging
|
debugging
|
||||||
} from "sync-client";
|
} from "sync-client";
|
||||||
import { ObsidianFileSystemOperations } from "./obsidian-file-system";
|
import { ObsidianFileSystemOperations } from "./obsidian-file-system";
|
||||||
import { SyncSettingsTab } from "./views/settings/settings-tab";
|
import { SyncSettingsTab } from "./views/settings/settings-tab";
|
||||||
import { EditorStatusDisplayManager } from "./views/editor-status-display-manager/editor-status-display-manager";
|
import { EditorStatusDisplayManager } from "./views/editor-status-display-manager/editor-status-display-manager";
|
||||||
import { remoteCursorsTheme } from "./views/cursors/remote-cursor-theme";
|
import { remoteCursorsTheme } from "./views/cursors/remote-cursor-theme";
|
||||||
import {
|
import {
|
||||||
remoteCursorsPlugin,
|
remoteCursorsPlugin,
|
||||||
RemoteCursorsPluginValue
|
RemoteCursorsPluginValue
|
||||||
} from "./views/cursors/remote-cursors-plugin";
|
} from "./views/cursors/remote-cursors-plugin";
|
||||||
import { LocalCursorUpdateListener } from "./views/cursors/local-cursor-update-listener";
|
import { LocalCursorUpdateListener } from "./views/cursors/local-cursor-update-listener";
|
||||||
import { renderCursorsInFileExplorer } from "./views/cursors/file-explorer";
|
import { renderCursorsInFileExplorer } from "./views/cursors/file-explorer";
|
||||||
|
|
@ -33,252 +33,252 @@ const MIN_WAIT_BETWEEN_UPDATES_IN_MS = 250;
|
||||||
const IS_DEBUG_BUILD = process.env.NODE_ENV === "development";
|
const IS_DEBUG_BUILD = process.env.NODE_ENV === "development";
|
||||||
|
|
||||||
export default class VaultLinkPlugin extends Plugin {
|
export default class VaultLinkPlugin extends Plugin {
|
||||||
private readonly rateLimitedUpdatesPerFile = new Map<
|
private readonly rateLimitedUpdatesPerFile = new Map<
|
||||||
string,
|
string,
|
||||||
() => Promise<unknown>
|
() => Promise<unknown>
|
||||||
>();
|
>();
|
||||||
|
|
||||||
private readonly syncClient: SyncClient | undefined;
|
private readonly syncClient: SyncClient | undefined;
|
||||||
private settingsTab: SyncSettingsTab | undefined;
|
private settingsTab: SyncSettingsTab | undefined;
|
||||||
|
|
||||||
public async onload(): Promise<void> {
|
public async onload(): Promise<void> {
|
||||||
this.app.workspace.onLayoutReady(async () => {
|
this.app.workspace.onLayoutReady(async () => {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
if ((globalThis as any).VAULT_LINK_RUNNING_INSTANCE) {
|
if ((globalThis as any).VAULT_LINK_RUNNING_INSTANCE) {
|
||||||
new Notice(
|
new Notice(
|
||||||
"Another instance of VaultLink is already running. Please disable the duplicate instance."
|
"Another instance of VaultLink is already running. Please disable the duplicate instance."
|
||||||
);
|
);
|
||||||
throw new Error("VaultLink instance already running");
|
throw new Error("VaultLink instance already running");
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
(globalThis as any).VAULT_LINK_RUNNING_INSTANCE = this;
|
(globalThis as any).VAULT_LINK_RUNNING_INSTANCE = this;
|
||||||
|
|
||||||
const client = await this.createSyncClient();
|
const client = await this.createSyncClient();
|
||||||
|
|
||||||
this.registerObsidianExtensions(client);
|
this.registerObsidianExtensions(client);
|
||||||
|
|
||||||
this.registerEditorEvents(client);
|
this.registerEditorEvents(client);
|
||||||
|
|
||||||
this.register(async () => {
|
this.register(async () => {
|
||||||
await client.waitUntilFinished();
|
await client.waitUntilFinished();
|
||||||
await client.destroy();
|
await client.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.start();
|
await client.start();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public onUserEnable(): void {
|
public onUserEnable(): void {
|
||||||
new Notice(
|
new Notice(
|
||||||
"VaultLink has been enabled, check out the docs for tips on getting started!"
|
"VaultLink has been enabled, check out the docs for tips on getting started!"
|
||||||
);
|
);
|
||||||
void this.activateView(HistoryView.TYPE).catch((e: unknown) => {
|
void this.activateView(HistoryView.TYPE).catch((e: unknown) => {
|
||||||
this.syncClient?.logger.error(
|
this.syncClient?.logger.error(
|
||||||
`Failed to open history view on enable: ${e}`
|
`Failed to open history view on enable: ${e}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
void this.activateView(LogsView.TYPE).catch((e: unknown) => {
|
void this.activateView(LogsView.TYPE).catch((e: unknown) => {
|
||||||
this.syncClient?.logger.error(
|
this.syncClient?.logger.error(
|
||||||
`Failed to open logs view on enable: ${e}`
|
`Failed to open logs view on enable: ${e}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
this.openSettings();
|
this.openSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
public openSettings(): void {
|
public openSettings(): void {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
(this.app as any).setting.open(); // this is undocumented
|
(this.app as any).setting.open(); // this is undocumented
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
(this.app as any).setting.openTab(this.settingsTab); // this is undocumented
|
(this.app as any).setting.openTab(this.settingsTab); // this is undocumented
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeSettings(): void {
|
public closeSettings(): void {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
(this.app as any).setting.close(); // this is undocumented
|
(this.app as any).setting.close(); // this is undocumented
|
||||||
}
|
}
|
||||||
|
|
||||||
public async activateView(type: string): Promise<void> {
|
public async activateView(type: string): Promise<void> {
|
||||||
const { workspace } = this.app;
|
const { workspace } = this.app;
|
||||||
|
|
||||||
let leaf: WorkspaceLeaf | null = null;
|
let leaf: WorkspaceLeaf | null = null;
|
||||||
const leaves = workspace.getLeavesOfType(type);
|
const leaves = workspace.getLeavesOfType(type);
|
||||||
|
|
||||||
if (leaves.length > 0) {
|
if (leaves.length > 0) {
|
||||||
[leaf] = leaves;
|
[leaf] = leaves;
|
||||||
} else {
|
} else {
|
||||||
leaf = workspace.getRightLeaf(false);
|
leaf = workspace.getRightLeaf(false);
|
||||||
await leaf?.setViewState({ type: type, active: true });
|
await leaf?.setViewState({ type: type, active: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leaf) {
|
if (leaf) {
|
||||||
await workspace.revealLeaf(leaf);
|
await workspace.revealLeaf(leaf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createSyncClient(): Promise<SyncClient> {
|
private async createSyncClient(): Promise<SyncClient> {
|
||||||
DEFAULT_SETTINGS.ignorePatterns.push(
|
DEFAULT_SETTINGS.ignorePatterns.push(
|
||||||
".obsidian/**",
|
".obsidian/**",
|
||||||
".git/**",
|
".git/**",
|
||||||
".trash/**",
|
".trash/**",
|
||||||
"**/.DS_Store"
|
"**/.DS_Store"
|
||||||
);
|
);
|
||||||
|
|
||||||
const client = await SyncClient.create({
|
const client = await SyncClient.create({
|
||||||
fs: new ObsidianFileSystemOperations(
|
fs: new ObsidianFileSystemOperations(
|
||||||
this.app.vault,
|
this.app.vault,
|
||||||
this.app.workspace
|
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)
|
||||||
},
|
},
|
||||||
nativeLineEndings: Platform.isWin ? "\r\n" : "\n",
|
nativeLineEndings: Platform.isWin ? "\r\n" : "\n",
|
||||||
...(IS_DEBUG_BUILD
|
...(IS_DEBUG_BUILD
|
||||||
? {
|
? {
|
||||||
fetch: debugging.slowFetchFactory(1),
|
fetch: debugging.slowFetchFactory(1),
|
||||||
webSocket: debugging.slowWebSocketFactory(
|
webSocket: debugging.slowWebSocketFactory(
|
||||||
1,
|
1,
|
||||||
new Logger()
|
new Logger()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
: {})
|
: {})
|
||||||
});
|
});
|
||||||
|
|
||||||
if (IS_DEBUG_BUILD) {
|
if (IS_DEBUG_BUILD) {
|
||||||
debugging.logToConsole(client);
|
debugging.logToConsole(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerObsidianExtensions(client: SyncClient): void {
|
private registerObsidianExtensions(client: SyncClient): void {
|
||||||
const statusDescription = new StatusDescription(client);
|
const statusDescription = new StatusDescription(client);
|
||||||
|
|
||||||
this.settingsTab = new SyncSettingsTab({
|
this.settingsTab = new SyncSettingsTab({
|
||||||
app: this.app,
|
app: this.app,
|
||||||
plugin: this,
|
plugin: this,
|
||||||
syncClient: client,
|
syncClient: client,
|
||||||
statusDescription
|
statusDescription
|
||||||
});
|
});
|
||||||
this.addSettingTab(this.settingsTab);
|
this.addSettingTab(this.settingsTab);
|
||||||
|
|
||||||
new StatusBar(this, client);
|
new StatusBar(this, client);
|
||||||
|
|
||||||
this.registerView(HistoryView.TYPE, (leaf) => {
|
this.registerView(HistoryView.TYPE, (leaf) => {
|
||||||
const view = new HistoryView(client, leaf);
|
const view = new HistoryView(client, leaf);
|
||||||
this.register(async () => view.onClose());
|
this.register(async () => view.onClose());
|
||||||
return view;
|
return view;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.registerView(LogsView.TYPE, (leaf) => new LogsView(client, leaf));
|
this.registerView(LogsView.TYPE, (leaf) => new LogsView(client, leaf));
|
||||||
|
|
||||||
this.registerEditorExtension([remoteCursorsTheme, remoteCursorsPlugin]);
|
this.registerEditorExtension([remoteCursorsTheme, remoteCursorsPlugin]);
|
||||||
|
|
||||||
client.addRemoteCursorsUpdateListener((cursors) => {
|
client.addRemoteCursorsUpdateListener((cursors) => {
|
||||||
RemoteCursorsPluginValue.setCursors(cursors, this.app);
|
RemoteCursorsPluginValue.setCursors(cursors, this.app);
|
||||||
renderCursorsInFileExplorer(cursors, this.app);
|
renderCursorsInFileExplorer(cursors, this.app);
|
||||||
});
|
});
|
||||||
|
|
||||||
const cursorListener = new LocalCursorUpdateListener(
|
const cursorListener = new LocalCursorUpdateListener(
|
||||||
client,
|
client,
|
||||||
this.app.workspace
|
this.app.workspace
|
||||||
);
|
);
|
||||||
this.register(() => {
|
this.register(() => {
|
||||||
cursorListener.dispose();
|
cursorListener.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.app.workspace.updateOptions();
|
this.app.workspace.updateOptions();
|
||||||
|
|
||||||
this.addRibbonIcons();
|
this.addRibbonIcons();
|
||||||
|
|
||||||
const editorStatusDisplayManager = new EditorStatusDisplayManager(
|
const editorStatusDisplayManager = new EditorStatusDisplayManager(
|
||||||
this,
|
this,
|
||||||
this.app.workspace,
|
this.app.workspace,
|
||||||
client
|
client
|
||||||
);
|
);
|
||||||
this.register(() => {
|
this.register(() => {
|
||||||
editorStatusDisplayManager.dispose();
|
editorStatusDisplayManager.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.register(() => {
|
this.register(() => {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
(globalThis as any).VAULT_LINK_RUNNING_INSTANCE = null;
|
(globalThis as any).VAULT_LINK_RUNNING_INSTANCE = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private addRibbonIcons(): void {
|
private addRibbonIcons(): void {
|
||||||
this.addRibbonIcon(
|
this.addRibbonIcon(
|
||||||
HistoryView.ICON,
|
HistoryView.ICON,
|
||||||
"Open VaultLink events",
|
"Open VaultLink events",
|
||||||
async (_: MouseEvent) => this.activateView(HistoryView.TYPE)
|
async (_: MouseEvent) => this.activateView(HistoryView.TYPE)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.addRibbonIcon(
|
this.addRibbonIcon(
|
||||||
LogsView.ICON,
|
LogsView.ICON,
|
||||||
"Open VaultLink logs",
|
"Open VaultLink logs",
|
||||||
async (_: MouseEvent) => this.activateView(LogsView.TYPE)
|
async (_: MouseEvent) => this.activateView(LogsView.TYPE)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerEditorEvents(client: SyncClient): void {
|
private registerEditorEvents(client: SyncClient): void {
|
||||||
[
|
[
|
||||||
this.app.workspace.on(
|
this.app.workspace.on(
|
||||||
"editor-change",
|
"editor-change",
|
||||||
async (
|
async (
|
||||||
_editor: Editor,
|
_editor: Editor,
|
||||||
info: MarkdownView | MarkdownFileInfo
|
info: MarkdownView | MarkdownFileInfo
|
||||||
) => {
|
) => {
|
||||||
const { file } = info;
|
const { file } = info;
|
||||||
if (file) {
|
if (file) {
|
||||||
await this.rateLimitedUpdate(file.path, client);
|
await this.rateLimitedUpdate(file.path, client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
this.app.vault.on("create", async (file: TAbstractFile) => {
|
this.app.vault.on("create", async (file: TAbstractFile) => {
|
||||||
if (file instanceof TFile) {
|
if (file instanceof TFile) {
|
||||||
await client.syncLocallyCreatedFile(file.path);
|
await client.syncLocallyCreatedFile(file.path);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
this.app.vault.on("modify", async (file: TAbstractFile) => {
|
this.app.vault.on("modify", async (file: TAbstractFile) => {
|
||||||
if (file instanceof TFile) {
|
if (file instanceof TFile) {
|
||||||
await this.rateLimitedUpdate(file.path, client);
|
await this.rateLimitedUpdate(file.path, client);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
this.app.vault.on("delete", async (file: TAbstractFile) => {
|
this.app.vault.on("delete", async (file: TAbstractFile) => {
|
||||||
await client.syncLocallyDeletedFile(file.path);
|
await client.syncLocallyDeletedFile(file.path);
|
||||||
}),
|
}),
|
||||||
this.app.vault.on(
|
this.app.vault.on(
|
||||||
"rename",
|
"rename",
|
||||||
async (file: TAbstractFile, oldPath: string) => {
|
async (file: TAbstractFile, oldPath: string) => {
|
||||||
if (file instanceof TFile) {
|
if (file instanceof TFile) {
|
||||||
await client.syncLocallyUpdatedFile({
|
await client.syncLocallyUpdatedFile({
|
||||||
oldPath,
|
oldPath,
|
||||||
relativePath: file.path
|
relativePath: file.path
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
].forEach((event) => {
|
].forEach((event) => {
|
||||||
this.registerEvent(event);
|
this.registerEvent(event);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async rateLimitedUpdate(
|
private async rateLimitedUpdate(
|
||||||
path: string,
|
path: string,
|
||||||
client: SyncClient
|
client: SyncClient
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!this.rateLimitedUpdatesPerFile.has(path)) {
|
if (!this.rateLimitedUpdatesPerFile.has(path)) {
|
||||||
this.rateLimitedUpdatesPerFile.set(
|
this.rateLimitedUpdatesPerFile.set(
|
||||||
path,
|
path,
|
||||||
rateLimit(
|
rateLimit(
|
||||||
async () =>
|
async () =>
|
||||||
client.syncLocallyUpdatedFile({
|
client.syncLocallyUpdatedFile({
|
||||||
relativePath: path
|
relativePath: path
|
||||||
}),
|
}),
|
||||||
MIN_WAIT_BETWEEN_UPDATES_IN_MS
|
MIN_WAIT_BETWEEN_UPDATES_IN_MS
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
await this.rateLimitedUpdatesPerFile.get(path)?.();
|
await this.rateLimitedUpdatesPerFile.get(path)?.();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"target": "ES2023",
|
"target": "ES2023",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"lib": [
|
"lib": [
|
||||||
"DOM",
|
"DOM",
|
||||||
"ES2024"
|
"ES2024"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"./dist"
|
"./dist"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Parse arguments
|
|
||||||
FIX_MODE=false
|
FIX_MODE=false
|
||||||
if [[ "$1" == "--fix" ]]; then
|
if [[ "$1" == "--fix" ]]; then
|
||||||
FIX_MODE=true
|
FIX_MODE=true
|
||||||
|
|
@ -33,12 +32,16 @@ else
|
||||||
npm ci
|
npm ci
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Checking .editorconfig compliance"
|
cd ..
|
||||||
|
|
||||||
|
# Use git ls-files to only check tracked files, respecting .gitignore
|
||||||
if [[ "$FIX_MODE" == true ]]; then
|
if [[ "$FIX_MODE" == true ]]; then
|
||||||
npx eclint fix '../**/*' '!../node_modules/**' '!../frontend/node_modules/**' '!../sync-server/target/**' '!../frontend/dist/**' '!../.git/**'
|
git ls-files | xargs npx eclint fix
|
||||||
else
|
else
|
||||||
npx eclint check '../**/*' '!../node_modules/**' '!../frontend/node_modules/**' '!../sync-server/target/**' '!../frontend/dist/**' '!../.git/**'
|
git ls-files | xargs npx eclint check
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
cd frontend
|
||||||
npm run build
|
npm run build
|
||||||
npm run test
|
npm run test
|
||||||
npm run lint
|
npm run lint
|
||||||
|
|
|
||||||
|
|
@ -109,4 +109,3 @@ while true; do
|
||||||
|
|
||||||
sleep 0.2
|
sleep 0.2
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue