From 5287edf15b74ad35244c0af6b73f47864dcd81a2 Mon Sep 17 00:00:00 2001 From: JenChieh Date: Wed, 12 Jun 2024 01:08:24 -0700 Subject: [PATCH] feat: Use jumprope for multi-editing --- Cargo.toml | 1 + src/file.rs | 23 ++++++++++++++--------- src/handler/file.rs | 12 ++++++------ src/util.rs | 15 ++++++++++++++- 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 68dfead..d4c073d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ clap = "4.5.4" dunce = "1.0.4" ignore = "0.4.22" java-properties = "2.0.0" +jumprope = "1.1.2" path-slash = "0.2.1" rpassword = "7.3.1" serde = { version = "1.0.203", features = ["derive"] } diff --git a/src/file.rs b/src/file.rs index e1064e0..754b842 100644 --- a/src/file.rs +++ b/src/file.rs @@ -16,13 +16,15 @@ use crate::chat::*; use crate::user::*; use crate::util::*; +use jumprope::{JumpRope, JumpRopeBuf}; use std::collections::HashMap; +use std::io::Write; #[derive(Debug)] pub struct File { - path: String, // absolute path - chat: Chat, // messages in this file - view: Option, // the file view + path: String, // absolute path + chat: Chat, // messages in this file + view: Option, // the file view } impl File { @@ -48,19 +50,20 @@ impl File { if !self.view.is_none() { return; } - self.view = Some(read_to_string(&self.path)); + let content = read_to_string(&self.path); + self.view = Some(JumpRopeBuf::from(content)); } - pub fn update(&mut self, add_or_delete: &String, beg: u64, end: u64, content: &String) { + pub fn update(&mut self, add_or_delete: &String, beg: usize, end: usize, contents: &String) { self.load_file(); // ensure read + let view = self.view.as_mut().unwrap(); match add_or_delete.clone().as_str() { "add" => { - // TODO: .. - //self.view.insert(content, beg); + view.insert(beg, &contents); } "delete" => { - // TODO: .. + view.remove(beg..end); } _ => { unreachable!() @@ -70,6 +73,8 @@ impl File { /// Write the content to file. pub fn save(&self) { - let _ = std::fs::write(&self.path, &self.view.clone().unwrap()); + let view = self.view.clone().unwrap(); + let contents = &view.to_string(); + let _ = std::fs::write(&self.path, contents); } } diff --git a/src/handler/file.rs b/src/handler/file.rs index 2aad2ea..6b94167 100644 --- a/src/handler/file.rs +++ b/src/handler/file.rs @@ -33,9 +33,9 @@ pub mod update { let path = data_str(json, "path").unwrap(); let add_or_delete = data_str(json, "add_or_delete").unwrap(); - let beg = data_u64(json, "beg").unwrap(); - let end = data_u64(json, "end").unwrap(); - let content = data_str(json, "content").unwrap(); + let beg = data_usize(json, "beg").unwrap(); + let end = data_usize(json, "end").unwrap(); + let contents = data_str(json, "contents").unwrap(); let path = to_room_path(&addr, &room, &path); let file = room.get_file_mut(&path); @@ -48,7 +48,7 @@ pub mod update { let file = file.unwrap(); - file.update(&add_or_delete, beg, end, &content); + file.update(&add_or_delete, beg, end, &contents); } } @@ -120,13 +120,13 @@ pub mod sync { return; } - let content = read_to_string(&local_path); + let contents = read_to_string(&local_path); channel .send_json(&serde_json::json!({ "method": METHOD, "file": file_path, // send it back directly - "content": content, + "contents": contents, "status": "success", })) .await; diff --git a/src/util.rs b/src/util.rs index e0225a0..20cd11e 100644 --- a/src/util.rs +++ b/src/util.rs @@ -33,7 +33,7 @@ pub fn data_str(json: &Value, key: &str) -> Option { Some(json[key].as_str().unwrap().to_string()) } -/// Get data as string. +/// Get data as u64. /// /// # Arguments /// @@ -46,6 +46,19 @@ pub fn data_u64(json: &Value, key: &str) -> Option { Some(json[key].as_u64().unwrap()) } +/// Get data as usize. +/// +/// # Arguments +/// +/// * `json` - JSON object. +/// * `key` - Key to the data. +pub fn data_usize(json: &Value, key: &str) -> Option { + if json[key].is_null() { + return None; + } + Some(json[key].to_string().parse::().unwrap()) +} + /// Parse data to u64. /// /// # Arguments