chore: renamed TextChange and Event fields

Co-authored-by: alemi <me@alemi.dev>
This commit is contained in:
zaaarf 2024-10-16 03:11:40 +02:00
parent 3326217058
commit 4b5ed06bb7
No known key found for this signature in database
GPG key ID: 102E445F4C3F829B
11 changed files with 124 additions and 134 deletions

View file

@ -18,13 +18,13 @@ public class TextChange {
* The starting position of the change. * The starting position of the change.
* If negative, it is clamped to 0. * If negative, it is clamped to 0.
*/ */
public final long start; public final long startIdx;
/** /**
* The ending position of the change. * The ending position of the change.
* If negative, it is clamped to 0. * If negative, it is clamped to 0.
*/ */
public final long end; public final long endIdx;
/** /**
* The content of the change. * The content of the change.
@ -39,7 +39,7 @@ public class TextChange {
* @return true if this change represents a deletion * @return true if this change represents a deletion
*/ */
public boolean isDelete() { public boolean isDelete() {
return this.start < this.end; return this.startIdx < this.endIdx;
} }
/** /**
@ -66,14 +66,14 @@ public class TextChange {
* @return the mutated string * @return the mutated string
*/ */
public String apply(String input) { public String apply(String input) {
long preIndex = Math.min(this.start, input.length()); long preIndex = Math.min(this.startIdx, input.length());
String pre = ""; String pre = "";
try { try {
pre = input.substring(0, (int) preIndex); pre = input.substring(0, (int) preIndex);
} catch(IndexOutOfBoundsException ignored) {} } catch(IndexOutOfBoundsException ignored) {}
String post = ""; String post = "";
try { try {
post = input.substring((int) this.end); post = input.substring((int) this.endIdx);
} catch(IndexOutOfBoundsException ignored) {} } catch(IndexOutOfBoundsException ignored) {}
return pre + this.content + post; return pre + this.content + post;
} }

View file

@ -361,8 +361,8 @@ local BufferController = {}
---@class TextChange ---@class TextChange
---@field content string text content of change ---@field content string text content of change
---@field start integer start index of change ---@field start_idx integer start index of change
---@field finish integer end index of change ---@field end_idx integer end index of change
local TextChange = {} local TextChange = {}
---@class (exact) BufferUpdate ---@class (exact) BufferUpdate

View file

@ -39,25 +39,25 @@ class Promise[T]:
It can either be used directly or you can wrap it inside a future python side. It can either be used directly or you can wrap it inside a future python side.
""" """
def wait(self) -> T: ... def wait(self) -> T: ...
def is_done(self) -> bool: ... def is_done(self) -> bool: ...
class Client: class Client:
""" """
Handle to the actual client that manages the session. It manages the connection Handle to the actual client that manages the session. It manages the connection
to a server and joining/creating new workspaces to a server and joining/creating new workspaces
""" """
def attach_workspace(self, workspace: str) -> Promise[Workspace]: ... def attach_workspace(self, workspace: str) -> Promise[Workspace]: ...
def create_workspace(self, workspace: str) -> Promise[None]: ... def create_workspace(self, workspace: str) -> Promise[None]: ...
def delete_workspace(self, workspace: str) -> Promise[None]: ... def delete_workspace(self, workspace: str) -> Promise[None]: ...
def invite_to_workspace(self, workspace: str, username: str) -> Promise[None]: ... def invite_to_workspace(self, workspace: str, username: str) -> Promise[None]: ...
def fetch_owned_workspaces(self) -> Promise[list[str]]: ... def fetch_owned_workspaces(self) -> Promise[list[str]]: ...
def fetch_joined_workspaces(self) -> Promise[list[str]]: ... def fetch_joined_workspaces(self) -> Promise[list[str]]: ...
def leave_workspace(self, workspace: str) -> bool: ... def leave_workspace(self, workspace: str) -> bool: ...
def get_workspace(self, id: str) -> Workspace: ... def get_workspace(self, id: str) -> Workspace: ...
def active_workspaces(self) -> list[str]: ... def active_workspaces(self) -> list[str]: ...
def current_user(self) -> User: ... def current_user(self) -> User: ...
def refresh(self) -> Promise[None]: ... def refresh(self) -> Promise[None]: ...
class Event: class Event:
pass pass
@ -67,23 +67,23 @@ class Workspace:
Handle to a workspace inside codemp. It manages buffers. Handle to a workspace inside codemp. It manages buffers.
A cursor is tied to the single workspace. A cursor is tied to the single workspace.
""" """
def create_buffer(self, path: str) -> Promise[None]: ... def create_buffer(self, path: str) -> Promise[None]: ...
def attach_buffer(self, path: str) -> Promise[BufferController]: ... def attach_buffer(self, path: str) -> Promise[BufferController]: ...
def detach_buffer(self, path: str) -> bool: ... def detach_buffer(self, path: str) -> bool: ...
def fetch_buffers(self) -> Promise[list[str]]: ... def fetch_buffers(self) -> Promise[list[str]]: ...
def fetch_users(self) -> Promise[list[User]]: ... def fetch_users(self) -> Promise[list[User]]: ...
def fetch_buffer_users(self, path: str) -> Promise[list[User]]: ... def fetch_buffer_users(self, path: str) -> Promise[list[User]]: ...
def delete_buffer(self, path: str) -> Promise[None]: ... def delete_buffer(self, path: str) -> Promise[None]: ...
def id(self) -> str: ... def id(self) -> str: ...
def cursor(self) -> CursorController: ... def cursor(self) -> CursorController: ...
def get_buffer(self, path: str) -> Optional[BufferController]: ... def get_buffer(self, path: str) -> Optional[BufferController]: ...
def user_list(self) -> list[User]: ... def user_list(self) -> list[User]: ...
def active_buffers(self) -> list[str]: ... def active_buffers(self) -> list[str]: ...
def search_buffers(self, filter: Optional[str]) -> list[str]: ... def search_buffers(self, filter: Optional[str]) -> list[str]: ...
def recv(self) -> Promise[Event]: ... def recv(self) -> Promise[Event]: ...
def try_recv(self) -> Promise[Optional[Event]]: ... def try_recv(self) -> Promise[Optional[Event]]: ...
def poll(self) -> Promise[None]: ... def poll(self) -> Promise[None]: ...
def clear_callback(self) -> None: ... def clear_callback(self) -> None: ...
def callback(self, cb: Callable[[Workspace], None]) -> None: ... def callback(self, cb: Callable[[Workspace], None]) -> None: ...
class TextChange: class TextChange:
@ -95,10 +95,10 @@ class TextChange:
end: int end: int
content: str content: str
def is_delete(self) -> bool: ... def is_delete(self) -> bool: ...
def is_insert(self) -> bool: ... def is_insert(self) -> bool: ...
def is_empty(self) -> bool: ... def is_empty(self) -> bool: ...
def apply(self, txt: str) -> str: ... def apply(self, txt: str) -> str: ...
class BufferUpdate: class BufferUpdate:
""" """
@ -114,19 +114,16 @@ class BufferController:
Handle to the controller for a specific buffer, which manages the back and forth Handle to the controller for a specific buffer, which manages the back and forth
of operations to and from other peers. of operations to and from other peers.
""" """
def path(self) -> str: ... def path(self) -> str: ...
def content(self) -> Promise[str]: ... def content(self) -> Promise[str]: ...
def ack(self, v: list[int]) -> None: ... def ack(self, v: list[int]) -> None: ...
def send(self, def send(self, op: TextChange) -> None: ...
start: int, def try_recv(self) -> Promise[Optional[TextChange]]: ...
end: int, def recv(self) -> Promise[TextChange]: ...
txt: str) -> Promise[None]: ... def poll(self) -> Promise[None]: ...
def try_recv(self) -> Promise[Optional[TextChange]]: ...
def recv(self) -> Promise[TextChange]: ...
def poll(self) -> Promise[None]: ...
def callback(self, def callback(self,
cb: Callable[[BufferController], None]) -> None: ... cb: Callable[[BufferController], None]) -> None: ...
def clear_callback(self) -> None: ... def clear_callback(self) -> None: ...
@ -151,14 +148,11 @@ class CursorController:
Handle to the controller for a workspace, which manages the back and forth of Handle to the controller for a workspace, which manages the back and forth of
cursor movements to and from other peers cursor movements to and from other peers
""" """
def send(self, def send(self, pos: Selection) -> None: ...
path: str, def try_recv(self) -> Promise[Optional[Cursor]]: ...
start: Tuple[int, int], def recv(self) -> Promise[Cursor]: ...
end: Tuple[int, int]) -> Promise[None]: ... def poll(self) -> Promise[None]: ...
def try_recv(self) -> Promise[Optional[Cursor]]: ...
def recv(self) -> Promise[Cursor]: ...
def poll(self) -> Promise[None]: ...
def callback(self, def callback(self,
cb: Callable[[CursorController], None]) -> None: ... cb: Callable[[CursorController], None]) -> None: ...
def clear_callback(self) -> None: ... def clear_callback(self) -> None: ...

View file

@ -55,10 +55,9 @@ pub struct BufferUpdate {
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub struct TextChange { pub struct TextChange {
/// Range start of text change, as char indexes in buffer previous state. /// Range start of text change, as char indexes in buffer previous state.
pub start: u32, pub start_idx: u32,
/// Range end of text change, as char indexes in buffer previous state. /// Range end of text change, as char indexes in buffer previous state.
#[cfg_attr(feature = "serialize", serde(alias = "finish"))] // Lua uses `end` as keyword pub end_idx: u32,
pub end: u32,
/// New content of text inside span. /// New content of text inside span.
pub content: String, pub content: String,
} }
@ -66,7 +65,7 @@ pub struct TextChange {
impl TextChange { impl TextChange {
/// Returns the [`std::ops::Range`] representing this change's span. /// Returns the [`std::ops::Range`] representing this change's span.
pub fn span(&self) -> std::ops::Range<usize> { pub fn span(&self) -> std::ops::Range<usize> {
self.start as usize..self.end as usize self.start_idx as usize..self.end_idx as usize
} }
} }
@ -76,7 +75,7 @@ impl TextChange {
/// ///
/// Note that this is is **not** mutually exclusive with [TextChange::is_insert]. /// Note that this is is **not** mutually exclusive with [TextChange::is_insert].
pub fn is_delete(&self) -> bool { pub fn is_delete(&self) -> bool {
self.start < self.end self.start_idx < self.end_idx
} }
/// Returns true if this [`TextChange`] adds new text. /// Returns true if this [`TextChange`] adds new text.
@ -93,9 +92,9 @@ impl TextChange {
/// Applies this text change to given text, returning a new string. /// Applies this text change to given text, returning a new string.
pub fn apply(&self, txt: &str) -> String { pub fn apply(&self, txt: &str) -> String {
let pre_index = std::cmp::min(self.start as usize, txt.len()); let pre_index = std::cmp::min(self.start_idx as usize, txt.len());
let pre = txt.get(..pre_index).unwrap_or("").to_string(); let pre = txt.get(..pre_index).unwrap_or("").to_string();
let post = txt.get(self.end as usize..).unwrap_or("").to_string(); let post = txt.get(self.end_idx as usize..).unwrap_or("").to_string();
format!("{}{}{}", pre, self.content, post) format!("{}{}{}", pre, self.content, post)
} }
} }
@ -105,8 +104,8 @@ mod tests {
#[test] #[test]
fn textchange_apply_works_for_insertions() { fn textchange_apply_works_for_insertions() {
let change = super::TextChange { let change = super::TextChange {
start: 5, start_idx: 5,
end: 5, end_idx: 5,
content: " cruel".to_string(), content: " cruel".to_string(),
}; };
let result = change.apply("hello world!"); let result = change.apply("hello world!");
@ -116,8 +115,8 @@ mod tests {
#[test] #[test]
fn textchange_apply_works_for_deletions() { fn textchange_apply_works_for_deletions() {
let change = super::TextChange { let change = super::TextChange {
start: 5, start_idx: 5,
end: 11, end_idx: 11,
content: "".to_string(), content: "".to_string(),
}; };
let result = change.apply("hello cruel world!"); let result = change.apply("hello cruel world!");
@ -127,8 +126,8 @@ mod tests {
#[test] #[test]
fn textchange_apply_works_for_replacements() { fn textchange_apply_works_for_replacements() {
let change = super::TextChange { let change = super::TextChange {
start: 5, start_idx: 5,
end: 11, end_idx: 11,
content: " not very pleasant".to_string(), content: " not very pleasant".to_string(),
}; };
let result = change.apply("hello cruel world!"); let result = change.apply("hello cruel world!");
@ -138,8 +137,8 @@ mod tests {
#[test] #[test]
fn textchange_apply_never_panics() { fn textchange_apply_never_panics() {
let change = super::TextChange { let change = super::TextChange {
start: 100, start_idx: 100,
end: 110, end_idx: 110,
content: "a very long string \n which totally matters".to_string(), content: "a very long string \n which totally matters".to_string(),
}; };
let result = change.apply("a short text"); let result = change.apply("a short text");
@ -152,8 +151,8 @@ mod tests {
#[test] #[test]
fn empty_textchange_doesnt_alter_buffer() { fn empty_textchange_doesnt_alter_buffer() {
let change = super::TextChange { let change = super::TextChange {
start: 42, start_idx: 42,
end: 42, end_idx: 42,
content: "".to_string(), content: "".to_string(),
}; };
let result = change.apply("some important text"); let result = change.apply("some important text");

View file

@ -1,5 +1,7 @@
//! # Event //! # Event
//! Real time notification of changes in a workspace, to either users or buffers. //! Real time notification of changes in a workspace, to either users or buffers.
#![allow(non_upper_case_globals, non_camel_case_types)] // pyo3 fix your shit
use codemp_proto::workspace::workspace_event::Event as WorkspaceEventInner; use codemp_proto::workspace::workspace_event::Event as WorkspaceEventInner;
/// Event in a [crate::Workspace]. /// Event in a [crate::Workspace].
@ -10,21 +12,21 @@ use codemp_proto::workspace::workspace_event::Event as WorkspaceEventInner;
pub enum Event { pub enum Event {
/// Fired when the file tree changes. /// Fired when the file tree changes.
/// Contains the modified buffer path (deleted, created or renamed). /// Contains the modified buffer path (deleted, created or renamed).
FileTreeUpdated(String), FileTreeUpdated { path: String },
/// Fired when an user joins the current workspace. /// Fired when an user joins the current workspace.
UserJoin(String), UserJoin { name: String },
/// Fired when an user leaves the current workspace. /// Fired when an user leaves the current workspace.
UserLeave(String), UserLeave { name: String },
} }
impl From<WorkspaceEventInner> for Event { impl From<WorkspaceEventInner> for Event {
fn from(event: WorkspaceEventInner) -> Self { fn from(event: WorkspaceEventInner) -> Self {
match event { match event {
WorkspaceEventInner::Join(e) => Self::UserJoin(e.user.name), WorkspaceEventInner::Join(e) => Self::UserJoin { name: e.user.name },
WorkspaceEventInner::Leave(e) => Self::UserLeave(e.user.name), WorkspaceEventInner::Leave(e) => Self::UserLeave { name: e.user.name },
WorkspaceEventInner::Create(e) => Self::FileTreeUpdated(e.path), WorkspaceEventInner::Create(e) => Self::FileTreeUpdated { path: e.path },
WorkspaceEventInner::Delete(e) => Self::FileTreeUpdated(e.path), WorkspaceEventInner::Delete(e) => Self::FileTreeUpdated { path: e.path },
WorkspaceEventInner::Rename(e) => Self::FileTreeUpdated(e.after), WorkspaceEventInner::Rename(e) => Self::FileTreeUpdated { path: e.after },
} }
} }
} }

View file

@ -160,8 +160,8 @@ impl BufferWorker {
async fn handle_editor_change(&mut self, change: TextChange, tx: &mpsc::Sender<Operation>) { async fn handle_editor_change(&mut self, change: TextChange, tx: &mpsc::Sender<Operation>) {
let last_ver = self.oplog.local_version(); let last_ver = self.oplog.local_version();
// clip to buffer extents // clip to buffer extents
let clip_start = change.start as usize; let clip_start = change.start_idx as usize;
let mut clip_end = change.end as usize; let mut clip_end = change.end_idx as usize;
let b_len = self.branch.len(); let b_len = self.branch.len();
if clip_end > b_len { if clip_end > b_len {
tracing::warn!("clipping TextChange end span from {clip_end} to {b_len}"); tracing::warn!("clipping TextChange end span from {clip_end} to {b_len}");
@ -262,8 +262,8 @@ impl BufferWorker {
.map(|x| i64::from_ne_bytes(x.to_ne_bytes())) .map(|x| i64::from_ne_bytes(x.to_ne_bytes()))
.collect(), // TODO this is wasteful .collect(), // TODO this is wasteful
change: crate::api::TextChange { change: crate::api::TextChange {
start: dtop.start() as u32, start_idx: dtop.start() as u32,
end: dtop.start() as u32, end_idx: dtop.start() as u32,
content: dtop.content_as_str().unwrap_or_default().to_string(), content: dtop.content_as_str().unwrap_or_default().to_string(),
}, },
} }
@ -276,8 +276,8 @@ impl BufferWorker {
.map(|x| i64::from_ne_bytes(x.to_ne_bytes())) .map(|x| i64::from_ne_bytes(x.to_ne_bytes()))
.collect(), // TODO this is wasteful .collect(), // TODO this is wasteful
change: crate::api::TextChange { change: crate::api::TextChange {
start: dtop.start() as u32, start_idx: dtop.start() as u32,
end: dtop.end() as u32, end_idx: dtop.end() as u32,
content: dtop.content_as_str().unwrap_or_default().to_string(), content: dtop.content_as_str().unwrap_or_default().to_string(),
}, },
}, },

View file

@ -170,9 +170,9 @@ impl<'j> jni_toolbox::IntoJavaObject<'j> for crate::api::Event {
env: &mut jni::JNIEnv<'j>, env: &mut jni::JNIEnv<'j>,
) -> Result<jni::objects::JObject<'j>, jni::errors::Error> { ) -> Result<jni::objects::JObject<'j>, jni::errors::Error> {
let (ordinal, arg) = match self { let (ordinal, arg) = match self {
crate::api::Event::UserJoin(arg) => (0, env.new_string(arg)?), crate::api::Event::UserJoin { name: arg } => (0, env.new_string(arg)?),
crate::api::Event::UserLeave(arg) => (1, env.new_string(arg)?), crate::api::Event::UserLeave { name: arg } => (1, env.new_string(arg)?),
crate::api::Event::FileTreeUpdated(arg) => (2, env.new_string(arg)?), crate::api::Event::FileTreeUpdated { path: arg } => (2, env.new_string(arg)?),
}; };
let type_class = env.find_class("mp/code/Workspace$Event$Type")?; let type_class = env.find_class("mp/code/Workspace$Event$Type")?;
@ -242,8 +242,8 @@ impl<'j> jni_toolbox::IntoJavaObject<'j> for crate::api::TextChange {
class, class,
"(JJLjava/lang/String;)V", "(JJLjava/lang/String;)V",
&[ &[
jni::objects::JValueGen::Long(self.start.into()), jni::objects::JValueGen::Long(self.start_idx.into()),
jni::objects::JValueGen::Long(self.end.into()), jni::objects::JValueGen::Long(self.end_idx.into()),
jni::objects::JValueGen::Object(&content), jni::objects::JValueGen::Object(&content),
], ],
) )
@ -438,11 +438,11 @@ impl<'j> jni_toolbox::FromJava<'j> for crate::api::TextChange {
change: Self::From, change: Self::From,
) -> Result<Self, jni::errors::Error> { ) -> Result<Self, jni::errors::Error> {
let start = env let start = env
.get_field(&change, "start", "J")? .get_field(&change, "startIdx", "J")?
.j()? .j()?
.clamp(0, u32::MAX.into()) as u32; .clamp(0, u32::MAX.into()) as u32;
let end = env let end = env
.get_field(&change, "end", "J")? .get_field(&change, "endIdx", "J")?
.j()? .j()?
.clamp(0, u32::MAX.into()) as u32; .clamp(0, u32::MAX.into()) as u32;
@ -457,8 +457,8 @@ impl<'j> jni_toolbox::FromJava<'j> for crate::api::TextChange {
}; };
Ok(Self { Ok(Self {
start, start_idx: start,
end, end_idx: end,
content, content,
}) })
} }

View file

@ -19,15 +19,15 @@ pub struct JsEvent {
impl From<crate::api::Event> for JsEvent { impl From<crate::api::Event> for JsEvent {
fn from(value: crate::api::Event) -> Self { fn from(value: crate::api::Event) -> Self {
match value { match value {
crate::api::Event::FileTreeUpdated(value) => Self { crate::api::Event::FileTreeUpdated { path: value } => Self {
r#type: "filetree".into(), r#type: "filetree".into(),
value, value,
}, },
crate::api::Event::UserJoin(value) => Self { crate::api::Event::UserJoin { name: value } => Self {
r#type: "join".into(), r#type: "join".into(),
value, value,
}, },
crate::api::Event::UserLeave(value) => Self { crate::api::Event::UserLeave { name: value } => Self {
r#type: "leave".into(), r#type: "leave".into(),
value, value,
}, },

View file

@ -21,7 +21,7 @@
//! //!
//! // write `hello!` at the beginning of this buffer //! // write `hello!` at the beginning of this buffer
//! buffer.send(codemp::api::TextChange { //! buffer.send(codemp::api::TextChange {
//! start: 0, end: 0, //! start_idx: 0, end_idx: 0,
//! content: "hello!".to_string(), //! content: "hello!".to_string(),
//! })?; //! })?;
//! //!
@ -58,7 +58,7 @@
//! //!
//! // write `hello!` at the beginning of this buffer //! // write `hello!` at the beginning of this buffer
//! await buffer.send({ //! await buffer.send({
//! start: 0, end: 0, //! start_idx: 0, end_idx: 0,
//! content: "hello!", //! content: "hello!",
//! }); //! });
//! //!
@ -94,7 +94,7 @@
//! //!
//! # write `hello!` at the beginning of this buffer //! # write `hello!` at the beginning of this buffer
//! buffer.send(codemp.TextChange( //! buffer.send(codemp.TextChange(
//! start=0, end=0, //! start_idx=0, end_idx=0,
//! content="hello!" //! content="hello!"
//! )).wait() //! )).wait()
//! //!
@ -141,7 +141,7 @@
//! //!
//! -- write `hello!` at the beginning of this buffer //! -- write `hello!` at the beginning of this buffer
//! buffer:send({ //! buffer:send({
//! start = 0, finish = 0, //! start_idx = 0, end_idx = 0,
//! content = "hello!" //! content = "hello!"
//! }):await() //! }):await()
//! //!

View file

@ -13,22 +13,8 @@ use super::Promise;
#[pymethods] #[pymethods]
impl CursorController { impl CursorController {
#[pyo3(name = "send")] #[pyo3(name = "send")]
fn pysend( fn pysend(&self, _py: Python, pos: Selection) -> PyResult<()> {
&self, self.send(pos)?;
_py: Python,
path: String,
start: (i32, i32),
end: (i32, i32),
) -> PyResult<()> {
let pos = Selection {
start_row: start.0,
start_col: start.1,
end_row: end.0,
end_col: end.1,
buffer: path,
};
let this = self.clone();
this.send(pos)?;
Ok(()) Ok(())
} }
@ -86,12 +72,7 @@ impl BufferController {
} }
#[pyo3(name = "send")] #[pyo3(name = "send")]
fn pysend(&self, _py: Python, start: u32, end: u32, txt: String) -> PyResult<()> { fn pysend(&self, _py: Python, op: TextChange) -> PyResult<()> {
let op = TextChange {
start,
end,
content: txt,
};
let this = self.clone(); let this = self.clone();
this.send(op)?; this.send(op)?;
Ok(()) Ok(())

View file

@ -10,8 +10,8 @@ use crate::{
}; };
use pyo3::{ use pyo3::{
prelude::*,
exceptions::{PyConnectionError, PyRuntimeError, PySystemError}, exceptions::{PyConnectionError, PyRuntimeError, PySystemError},
prelude::*,
types::PyDict, types::PyDict,
}; };
@ -162,7 +162,11 @@ impl User {
#[setter] #[setter]
fn set_id(&mut self, value: String) -> pyo3::PyResult<()> { fn set_id(&mut self, value: String) -> pyo3::PyResult<()> {
self.id = value.parse().map_err(|x: <uuid::Uuid as std::str::FromStr>::Err| pyo3::exceptions::PyRuntimeError::new_err(x.to_string()))?; self.id = value
.parse()
.map_err(|x: <uuid::Uuid as std::str::FromStr>::Err| {
pyo3::exceptions::PyRuntimeError::new_err(x.to_string())
})?;
Ok(()) Ok(())
} }
@ -245,7 +249,13 @@ impl Selection {
String::default() String::default()
}; };
Ok(Self { start_row, start_col, end_row, end_col, buffer }) Ok(Self {
start_row,
start_col,
end_row,
end_col,
buffer,
})
} else { } else {
Ok(Self::default()) Ok(Self::default())
} }
@ -269,13 +279,13 @@ impl TextChange {
#[pyo3(signature = (**kwds))] #[pyo3(signature = (**kwds))]
pub fn py_new(kwds: Option<&Bound<'_, PyDict>>) -> PyResult<Self> { pub fn py_new(kwds: Option<&Bound<'_, PyDict>>) -> PyResult<Self> {
if let Some(kwds) = kwds { if let Some(kwds) = kwds {
let start = if let Some(e) = kwds.get_item("start")? { let start_idx = if let Some(e) = kwds.get_item("start")? {
e.extract()? e.extract()?
} else { } else {
0 0
}; };
let end = if let Some(e) = kwds.get_item("end")? { let end_idx = if let Some(e) = kwds.get_item("end")? {
e.extract()? e.extract()?
} else { } else {
0 0
@ -287,7 +297,11 @@ impl TextChange {
String::default() String::default()
}; };
Ok(Self { start, end, content }) Ok(Self {
start_idx,
end_idx,
content,
})
} else { } else {
Ok(Self::default()) Ok(Self::default())
} }