load project files when it opens

This commit is contained in:
Nikita Galaiko 2023-02-03 15:20:55 +01:00
parent 1e26d05e69
commit 163155c319
No known key found for this signature in database
GPG Key ID: EBAB54E845BA519D
5 changed files with 90 additions and 23 deletions

View File

@ -1,13 +1,44 @@
use std::fs::read_to_string;
use std::{fs, path::Path};
use tauri::InvokeError;
use tauri_plugin_log::{
fern::colors::{Color, ColoredLevelConfig},
LogTarget,
};
// return a list of files in directory recursively
fn list_files(path: &Path) -> Vec<String> {
let mut files = Vec::new();
if path.is_dir() {
for entry in fs::read_dir(path).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
if path.is_dir() {
files.append(&mut list_files(&path));
} else {
files.push(path.to_str().unwrap().to_string());
}
}
}
files.sort();
files
}
// returns a list of files in directory recursively
#[tauri::command]
fn read_dir(path: &str) -> Result<Vec<String>, InvokeError> {
let path = Path::new(path);
if path.is_dir() {
let files = list_files(path);
return Ok(files);
} else {
return Err("Path is not a directory".into());
}
}
// reads file contents and returns it
#[tauri::command]
fn read_file(file_path: &str) -> Result<String, InvokeError> {
let contents = read_to_string(file_path);
let contents = fs::read_to_string(file_path);
if contents.is_ok() {
return Ok(contents.unwrap());
} else {
@ -33,7 +64,7 @@ fn main() {
.targets([LogTarget::LogDir, LogTarget::Stdout, LogTarget::Webview])
.build(),
)
.invoke_handler(tauri::generate_handler![read_file])
.invoke_handler(tauri::generate_handler![read_file, read_dir])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

View File

@ -55,7 +55,7 @@ export class TextDocument {
if (content !== undefined && history.length > 0) {
throw new Error("only one of content and history can be set");
} else if (content !== undefined) {
this.update(content);
this.doc.getText().insert(0, content);
} else if (history.length > 0) {
this.doc
.getText()

View File

@ -1,6 +1,12 @@
export {
debug,
info,
error,
attachConsole as setup,
} from "tauri-plugin-log-api";
export { attachConsole as setup } from "tauri-plugin-log-api";
import * as log from "tauri-plugin-log-api";
export const debug = (...args: any[]) =>
log.debug(args.map((argument) => JSON.stringify(argument)).join(" "));
export const info = (...args: any[]) =>
log.info(args.map((argument) => JSON.stringify(argument)).join(" "));
export const error = (...args: any[]) =>
log.error(args.map((argument) => JSON.stringify(argument)).join(" "));

View File

@ -1,4 +1,5 @@
import { invoke } from "@tauri-apps/api";
import { log } from "$lib";
export class NoSuchFileOrDirectoryError extends Error {
constructor(message: string) {
@ -6,11 +7,24 @@ export class NoSuchFileOrDirectoryError extends Error {
}
}
export const readFile = (filePath: string) =>
invoke<string>("read_file", { filePath }).catch((err) => {
export const readFile = async (filePath: string) => {
log.info("readFile", { path: filePath });
return invoke<string>("read_file", { filePath }).catch((err) => {
if (err.message === "No such file or directory (os error 2)") {
throw new NoSuchFileOrDirectoryError(err.message);
} else {
throw err;
}
});
};
export const readDir = async (path: string) => {
log.info("readDir", { path });
return invoke<string[]>("read_dir", { path }).catch((err) => {
if (err.message === "No such file or directory (os error 2)") {
throw new NoSuchFileOrDirectoryError(err.message);
} else {
throw err;
}
});
};

View File

@ -2,12 +2,15 @@
import { derived, writable } from "svelte/store";
import { EventType, watch, type Event } from "$lib/watch";
import { TextDocument } from "$lib/crdt";
import { NoSuchFileOrDirectoryError, readFile } from "$lib/tauri";
import { NoSuchFileOrDirectoryError, readFile, readDir } from "$lib/tauri";
import type { PageData } from "./$types";
import { Timeline } from "$lib/components";
import { onMount } from "svelte";
export let data: PageData;
const project = data.project;
const docs = writable<Record<string, TextDocument>>({});
const deleteDocs = (...filepaths: string[]) => {
@ -18,8 +21,16 @@
);
};
const upsertDoc = (filepath: string) =>
readFile(filepath)
// TODO
const shouldIgnore = (filepath: string) => {
if (filepath.includes(".git")) return true;
if (filepath.includes("node_modules")) return true;
return false;
};
const upsertDoc = async (filepath: string) => {
if (shouldIgnore(filepath)) return;
return readFile(filepath)
.then((content) => {
if (filepath in $docs) {
$docs[filepath].update(content);
@ -35,26 +46,31 @@
throw err;
}
});
};
const onEvent = (event: Event) => {
const onEvent = async (event: Event) => {
const isFileCreate =
EventType.isCreate(event.type) && event.type.create.kind === "file";
const isFileUpdate =
EventType.isModify(event.type) && event.type.modify.kind === "data";
const isFileRemove = EventType.isRemove(event.type);
if (isFileCreate) {
event.paths.forEach(upsertDoc);
} else if (isFileUpdate) {
event.paths.forEach(upsertDoc);
if (isFileCreate || isFileUpdate) {
for (const path of event.paths) {
await upsertDoc(path);
}
} else if (isFileRemove) {
deleteDocs(...event.paths);
}
};
$: data.project?.subscribe(async (project) => {
if (project === undefined) return;
return await watch(project.path, onEvent);
onMount(async () => {
if ($project === undefined) return;
const filepaths = await readDir($project.path);
for (const filepath of filepaths) {
await upsertDoc(filepath);
}
return watch($project.path, onEvent);
});
const timestamps = derived(docs, (docs) =>