pub fn word_boundary_left(text: &str, char_pos: usize) -> usize {
let chars: Vec<char> = text.chars().collect();
if char_pos == 0 || chars.is_empty() {
return 0;
}
let mut pos = char_pos.min(chars.len());
while pos > 0 && chars[pos - 1].is_whitespace() {
pos -= 1;
}
if pos == 0 {
return 0;
}
let is_word = chars[pos - 1].is_alphanumeric() || chars[pos - 1] == '_';
if is_word {
while pos > 0 && (chars[pos - 1].is_alphanumeric() || chars[pos - 1] == '_') {
pos -= 1;
}
} else {
while pos > 0
&& !chars[pos - 1].is_alphanumeric()
&& chars[pos - 1] != '_'
&& !chars[pos - 1].is_whitespace()
{
pos -= 1;
}
}
pos
}
pub fn word_boundary_right(text: &str, char_pos: usize) -> usize {
let chars: Vec<char> = text.chars().collect();
let len = chars.len();
if char_pos >= len || chars.is_empty() {
return len;
}
let mut pos = char_pos;
let is_word = chars[pos].is_alphanumeric() || chars[pos] == '_';
let is_ws = chars[pos].is_whitespace();
if is_ws {
while pos < len && chars[pos].is_whitespace() {
pos += 1;
}
} else if is_word {
while pos < len && (chars[pos].is_alphanumeric() || chars[pos] == '_') {
pos += 1;
}
} else {
while pos < len
&& !chars[pos].is_alphanumeric()
&& chars[pos] != '_'
&& !chars[pos].is_whitespace()
{
pos += 1;
}
}
while pos < len && chars[pos].is_whitespace() {
pos += 1;
}
pos
}
pub fn word_at_position(text: &str, char_pos: usize) -> (usize, usize) {
let chars: Vec<char> = text.chars().collect();
let len = chars.len();
if len == 0 || char_pos >= len {
return (char_pos, char_pos);
}
let ch = chars[char_pos];
let is_word = ch.is_alphanumeric() || ch == '_';
if ch.is_whitespace() {
let mut start = char_pos;
let mut end = char_pos;
while start > 0 && chars[start - 1].is_whitespace() {
start -= 1;
}
while end < len && chars[end].is_whitespace() {
end += 1;
}
(start, end)
} else if is_word {
let mut start = char_pos;
let mut end = char_pos;
while start > 0 && (chars[start - 1].is_alphanumeric() || chars[start - 1] == '_') {
start -= 1;
}
while end < len && (chars[end].is_alphanumeric() || chars[end] == '_') {
end += 1;
}
(start, end)
} else {
let mut start = char_pos;
let mut end = char_pos;
while start > 0
&& !chars[start - 1].is_alphanumeric()
&& chars[start - 1] != '_'
&& !chars[start - 1].is_whitespace()
{
start -= 1;
}
while end < len
&& !chars[end].is_alphanumeric()
&& chars[end] != '_'
&& !chars[end].is_whitespace()
{
end += 1;
}
(start, end)
}
}
pub fn clipboard_read() -> Option<String> {
arboard::Clipboard::new()
.ok()
.and_then(|mut cb| cb.get_text().ok())
.filter(|t| !t.is_empty())
}
pub fn clipboard_write(text: &str) -> bool {
arboard::Clipboard::new()
.ok()
.and_then(|mut cb| cb.set_text(text.to_string()).ok())
.is_some()
}
pub fn clipboard_read_image() -> Option<(Vec<u8>, u32, u32)> {
let mut cb = arboard::Clipboard::new().ok()?;
let img = cb.get_image().ok()?;
Some((img.bytes.into_owned(), img.width as u32, img.height as u32))
}
pub fn clipboard_write_image(rgba: &[u8], width: u32, height: u32) -> bool {
let img = arboard::ImageData {
width: width as usize,
height: height as usize,
bytes: std::borrow::Cow::Borrowed(rgba),
};
arboard::Clipboard::new()
.ok()
.and_then(|mut cb| cb.set_image(img).ok())
.is_some()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_word_boundary_left() {
assert_eq!(word_boundary_left("hello world", 5), 0);
assert_eq!(word_boundary_left("hello world", 6), 0);
assert_eq!(word_boundary_left("hello world", 11), 6);
assert_eq!(word_boundary_left("fn main() {", 3), 0);
assert_eq!(word_boundary_left("fn main() {", 8), 7); }
#[test]
fn test_word_boundary_right() {
assert_eq!(word_boundary_right("hello world", 0), 6);
assert_eq!(word_boundary_right("hello world", 6), 11);
assert_eq!(word_boundary_right("fn main() {", 0), 3);
}
#[test]
fn test_word_at_position() {
assert_eq!(word_at_position("hello world", 2), (0, 5));
assert_eq!(word_at_position("hello world", 7), (6, 11));
assert_eq!(word_at_position("hello world", 5), (5, 6)); }
}