Skip to content

Commit

Permalink
try: walk dir - read content
Browse files Browse the repository at this point in the history
  • Loading branch information
danloh committed Apr 10, 2023
1 parent 3712013 commit d7f9c65
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 31 deletions.
24 changes: 18 additions & 6 deletions src-tauri/src/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ pub fn check_hidden(file_path: &str) -> bool {
basename.starts_with(".")
}

#[inline]
pub fn check_md(file_path: &str) -> bool {
let extension = Path::new(file_path).extension().and_then(|ext|ext.to_str());
match extension {
Some(et) => {
let ext = et.to_lowercase();
ext == "md" || ext == "markdown" || ext == "text" || ext == "txt"
},
None => false
}
}

// Get file_name or dir_name of the path given: (name, is_file)
#[tauri::command]
pub fn get_basename(file_path: &str) -> (String, bool) {
Expand Down Expand Up @@ -267,8 +279,8 @@ pub async fn get_file_meta(file_path: &str) -> Result<FileMetaData, String> {
}
};

// TODO, get text if md file
let file_text = if meta_data.is_file {
// get text if md file
let file_text = if meta_data.is_file && check_md(file_path) {
match fs::read_to_string(file_path) {
Ok(text) => text,
Err(e) => {
Expand Down Expand Up @@ -397,7 +409,7 @@ pub async fn read_directory(dir: &str) -> Result<FolderData, String> {

// Get array of files of a directory
#[tauri::command]
pub async fn list_directory(dir: &str) -> Result<Vec<SimpleFileMeta>, String> {
pub async fn list_directory(dir: &str) -> Result<Vec<FileMetaData>, String> {
// let paths = match fs::read_dir(dir) {
// Ok(res) => res,
// Err(e) => {
Expand Down Expand Up @@ -441,11 +453,11 @@ pub async fn list_directory(dir: &str) -> Result<Vec<SimpleFileMeta>, String> {
// filemetas.push(simple_meta);
// }

let tree = Tree::init(dir);
let tree = Tree::init(dir, Some(1), false);
// println!(">> dir tree: {:?}", tree);
let nodes = tree.map(|t|t.children_vec()).unwrap_or_default();
let metas: Vec<SimpleFileMeta> =
nodes.iter().filter_map(|n|from_node(n)).collect();
let metas: Vec<FileMetaData> =
nodes.iter().filter_map(|n| from_node(n)).collect();

Ok(metas)
}
Expand Down
22 changes: 13 additions & 9 deletions src-tauri/src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,24 @@ impl Tree {
}

/// Initiates file-system traversal and [Tree construction].
pub fn init(dir: &str) -> TreeResult<Self> {
let (inner, root) = Self::traverse(dir)?;
pub fn init(dir: &str, depth: Option<usize>, read_ctn: bool) -> TreeResult<Self> {
let (inner, root) = Self::traverse(dir, depth, read_ctn)?;

Ok(Self::new(inner, root))
}

/// Grabs a reference to `inner`.
fn inner(&self) -> &Arena<Node> {
&self.inner
&self.inner
}

/// Parallel traversal of the directory
fn traverse(dir: &str) -> TreeResult<(Arena<Node>, NodeId)> {
let walker = new_walker(PathBuf::from(dir))?;
fn traverse(
dir: &str,
depth: Option<usize>,
read_ctn: bool,
) -> TreeResult<(Arena<Node>, NodeId)> {
let walker = new_walker(PathBuf::from(dir), depth)?;
let (tx, rx) = channel::unbounded::<TraversalState>();

thread::scope(|s| {
Expand Down Expand Up @@ -90,7 +94,7 @@ impl Tree {
Ok::<(Arena<Node>, NodeId), String>((tree, root))
});

let mut visitor_builder = BranchVisitorBuilder::new(Sender::clone(&tx));
let mut visitor_builder = BranchVisitorBuilder::new(Sender::clone(&tx), read_ctn);

walker.visit(&mut visitor_builder);

Expand Down Expand Up @@ -145,15 +149,15 @@ impl Tree {
}

/// Build a new Parallel walker
fn new_walker(dir: PathBuf) -> Result<WalkParallel, String> {
fn new_walker(dir: PathBuf, depth: Option<usize>) -> Result<WalkParallel, String> {
let root = fs::canonicalize(dir).map_err(|e| (format!("{e}")))?;

fs::metadata(&root)
.map_err(|e| (format!("{}: {e}", root.display())))?;
.map_err(|e| (format!("Not Found {}: {e}", root.display())))?;

Ok(
WalkBuilder::new(root)
.max_depth(Some(1))
.max_depth(depth)
.follow_links(false)
.git_ignore(false)
.hidden(true)
Expand Down
36 changes: 28 additions & 8 deletions src-tauri/src/tree/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ use std::{
borrow::Cow,
convert::{From, Into},
ffi::{OsStr, OsString},
fs::{FileType, Metadata},
fs::{self, FileType, Metadata},
path::{Path, PathBuf},
time::SystemTime,
};
use crate::{paths::PathExt, files::check_hidden};
use crate::files::SimpleFileMeta;
use crate::{paths::PathExt, files::{check_hidden, FileMetaData, check_md}};

#[derive(Debug, Clone)]
pub struct Node {
pub depth: usize,
file_name: OsString,
file_type: Option<FileType>,
pub file_meta: Option<Metadata>,
pub file_text: Option<String>,
path: PathBuf,
}

Expand All @@ -27,13 +27,15 @@ impl Node {
file_name: OsString,
file_type: Option<FileType>,
file_meta: Option<Metadata>,
file_text: Option<String>,
path: PathBuf,
) -> Self {
Self {
depth,
file_name,
file_type,
file_meta,
file_text,
path,
}
}
Expand Down Expand Up @@ -67,8 +69,8 @@ impl Node {
}
}

impl From<&DirEntry> for Node {
fn from(dir_entry: &DirEntry) -> Self {
impl From<(&DirEntry, bool)> for Node {
fn from((dir_entry, ctn): (&DirEntry, bool)) -> Self {

let depth = dir_entry.depth();

Expand All @@ -82,12 +84,30 @@ impl From<&DirEntry> for Node {
);

let metadata = dir_entry.metadata().ok();
let text = if ctn {
match metadata.clone() {
Some(meta) => {
if meta.is_file() && check_md(&path.display().to_string()) {
match fs::read_to_string(path) {
Ok(text) => Some(text),
Err(_e) => None,
}
} else {
None
}
},
_ => None,
}
} else {
None
};

Self::new(
depth,
file_name,
file_type,
metadata,
text,
path.into()
)
}
Expand All @@ -100,7 +120,7 @@ impl From<(NodeId, &mut Arena<Self>)> for &Node {
}


pub fn from_node(node: &Node) -> Option<SimpleFileMeta> {
pub fn from_node(node: &Node) -> Option<FileMetaData> {
let metadata = match node.file_meta.clone() {
Some(meta) => meta,
None => return None,
Expand All @@ -117,10 +137,10 @@ pub fn from_node(node: &Node) -> Option<SimpleFileMeta> {
};
let is_hidden = check_hidden(&normalized_path);

let data = SimpleFileMeta {
let data = FileMetaData {
file_path: normalized_path,
file_name: node.file_name_lossy().to_string(),
// file_type,
file_text: node.file_text.clone().unwrap_or_default(),
created,
last_modified,
last_accessed,
Expand Down
14 changes: 8 additions & 6 deletions src-tauri/src/tree/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,23 @@ pub enum TraversalState {

pub struct BranchVisitor {
tx: Sender<TraversalState>,
ctn: bool,
}

pub struct BranchVisitorBuilder {
tx: Sender<TraversalState>,
ctn: bool,
}

impl BranchVisitorBuilder {
pub fn new(tx: Sender<TraversalState>) -> Self {
Self { tx }
pub fn new(tx: Sender<TraversalState>, ctn: bool,) -> Self {
Self { tx, ctn }
}
}

impl BranchVisitor {
pub fn new(tx: Sender<TraversalState>) -> Self {
Self { tx }
pub fn new(tx: Sender<TraversalState>, ctn: bool,) -> Self {
Self { tx, ctn }
}
}

Expand All @@ -38,7 +40,7 @@ impl From<Node> for TraversalState {
impl ParallelVisitor for BranchVisitor {
fn visit(&mut self, entry: Result<DirEntry, IgnoreError>) -> WalkState {
entry
.map(|e| TraversalState::from(Node::from(&e)))
.map(|e| TraversalState::from(Node::from((&e, self.ctn))))
.map(|n| self.tx.send(n).unwrap())
.map(|_| WalkState::Continue)
.unwrap_or(WalkState::Skip)
Expand All @@ -47,7 +49,7 @@ impl ParallelVisitor for BranchVisitor {

impl<'s> ParallelVisitorBuilder<'s> for BranchVisitorBuilder {
fn build(&mut self) -> Box<dyn ParallelVisitor + 's> {
let visitor = BranchVisitor::new(self.tx.clone());
let visitor = BranchVisitor::new(self.tx.clone(), self.ctn);
Box::new(visitor)
}
}
55 changes: 53 additions & 2 deletions src/editor/hooks/useOnNoteLinkClick.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { useCallback } from 'react';
import { useCurrentViewContext } from 'context/useCurrentView';
import { openFilePath } from 'file/open';
//import { openFilePath } from 'file/open';
import FileAPI from 'file/files';
import { checkFileIsMd, rmFileNameExt } from 'file/process';
import { regDateStr } from 'utils/helper';
import { defaultNote } from 'types/model';
import { Notes, store } from 'lib/store';

export default function useOnNoteLinkClick() {
const currentView = useCurrentViewContext();
Expand All @@ -9,7 +14,7 @@ export default function useOnNoteLinkClick() {
const onClick = useCallback(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async (toId: string, highlightedPath?: any) => {
const note = await openFilePath(toId, true);
const note = await openFile(toId, true);
if (!note) return;
const noteId = note.id;
const hash = highlightedPath ? `0-${highlightedPath}` : ''; // TODO
Expand All @@ -21,3 +26,49 @@ export default function useOnNoteLinkClick() {

return { onClick };
}

/**
* Open and process md file
* @param filePath
* @returns Promise<Note | undefined>
*/
export async function openFile(filePath: string, setCurrent: boolean) {
const fileInfo = new FileAPI(filePath);
if (await fileInfo.exists()) {
const file = await fileInfo.getMetadata();
if (file.is_file) {
const fileName = file.file_name;

if (!fileName || !file.is_file) {
return;
}
const fileContent = file.file_text;
const filePath = file.file_path;

const checkMd = checkFileIsMd(fileName);
// new note from file
const newNoteTitle = checkMd ? rmFileNameExt(fileName) : fileName;
const lastModDate = new Date(file.last_modified.secs_since_epoch * 1000).toISOString();
const createdDate = new Date(file.created.secs_since_epoch * 1000).toISOString();
const isDaily = checkMd ? regDateStr.test(newNoteTitle) : false;
const newNoteObj = {
id: filePath,
title: newNoteTitle,
content: fileContent,
created_at: createdDate,
updated_at: lastModDate,
is_daily: isDaily,
file_path: filePath,
};
const note = {...defaultNote, ...newNoteObj};
if (setCurrent) {
const cNote: Notes = {};
cNote[note.id] = note;
store.getState().setCurrentNote(cNote);
}
return note;
}
} else {
return;
}
}

0 comments on commit d7f9c65

Please sign in to comment.