mirror of
https://github.com/MeexReay/bRAC.git
synced 2025-05-06 13:38:04 +03:00
scrollbar
This commit is contained in:
parent
6868f0b3eb
commit
4518896f45
38
src/chat.rs
38
src/chat.rs
@ -1,10 +1,10 @@
|
||||
use std::{cmp::{max, min}, error::Error, io::{stdout, Write}, sync::{atomic::{AtomicUsize, Ordering}, Arc, RwLock}, thread, time::{Duration, SystemTime}};
|
||||
|
||||
use colored::{Color, Colorize};
|
||||
use crossterm::{cursor::{MoveLeft, MoveRight}, event::{self, Event, KeyCode, KeyModifiers, MouseEventKind}, terminal::{disable_raw_mode, enable_raw_mode}};
|
||||
use crossterm::{cursor::{MoveLeft, MoveRight}, event::{self, Event, KeyCode, KeyModifiers, MouseEventKind}, terminal::{self, disable_raw_mode, enable_raw_mode}};
|
||||
use rand::random;
|
||||
|
||||
use crate::IP_REGEX;
|
||||
use crate::{util::string_chunks, IP_REGEX};
|
||||
|
||||
use super::{proto::read_messages, util::sanitize_text, COLORED_USERNAMES, DATE_REGEX, config::Context, proto::send_message};
|
||||
|
||||
@ -88,11 +88,30 @@ Press enter to close")?;
|
||||
}
|
||||
|
||||
|
||||
pub fn print_console(context: Arc<Context>, messages: Vec<String>, input: &str) -> Result<(), Box<dyn Error>> {
|
||||
pub fn print_console(ctx: Arc<Context>, messages: Vec<String>, input: &str) -> Result<(), Box<dyn Error>> {
|
||||
let (width, height) = terminal::size()?;
|
||||
let (width, height) = (width as usize, height as usize);
|
||||
|
||||
let scroll = ctx.scroll.load(Ordering::SeqCst);
|
||||
let scroll = (1f64 - scroll as f64 / messages.len() as f64) * (height - 1) as f64;
|
||||
let scroll = scroll as usize;
|
||||
|
||||
let text = format!(
|
||||
"{}{}\r\n> {}",
|
||||
"\r\n".repeat(context.max_messages - messages.len()),
|
||||
messages.join("\r\n"),
|
||||
"{}\r\n> {}",
|
||||
messages[messages.len()-height-1..].into_iter()
|
||||
.flat_map(|o| string_chunks(&o, width as usize - 1))
|
||||
.enumerate()
|
||||
.map(|(i, (s, l))| {
|
||||
format!("{}{}{}",
|
||||
s,
|
||||
" ".repeat(width - 1 - l),
|
||||
if i == scroll {
|
||||
"#"
|
||||
} else {
|
||||
"|"
|
||||
}
|
||||
)
|
||||
}).collect::<Vec<String>>().join("\r\n"),
|
||||
input
|
||||
);
|
||||
|
||||
@ -333,6 +352,13 @@ fn poll_events(ctx: Arc<Context>) -> Result<(), Box<dyn Error>> {
|
||||
write!(stdout(), "{}", &data).unwrap();
|
||||
stdout().lock().flush().unwrap();
|
||||
},
|
||||
Event::Resize(_, _) => {
|
||||
print_console(
|
||||
ctx.clone(),
|
||||
messages.messages(),
|
||||
&input.read().unwrap()
|
||||
)?;
|
||||
},
|
||||
Event::Mouse(data) => {
|
||||
match data.kind {
|
||||
MouseEventKind::ScrollUp => {
|
||||
|
59
src/util.rs
59
src/util.rs
@ -1,13 +1,62 @@
|
||||
use std::io::{stdin, stdout, BufRead, Write};
|
||||
use std::{collections::HashSet, io::{stdin, stdout, BufRead, Write}, ops::Range};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
|
||||
lazy_static! {
|
||||
static ref ANSI_REGEX: Regex = Regex::new(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])").unwrap();
|
||||
static ref CONTROL_CHARS_REGEX: Regex = Regex::new(r"[\x00-\x1F\x7F]").unwrap();
|
||||
}
|
||||
|
||||
fn get_matches(regex: &Regex, text: &str) -> Vec<Range<usize>> {
|
||||
regex.find_iter(text).map(|mat| mat.range()).collect()
|
||||
}
|
||||
|
||||
pub fn string_chunks(text: &str, width: usize) -> Vec<(String, usize)> {
|
||||
let mut norm: Vec<bool> = vec![true; text.chars().count()];
|
||||
|
||||
for range in get_matches(&ANSI_REGEX, text) {
|
||||
for i in range {
|
||||
if let Some(index) = text.char_indices().position(|x| x.0 == i) {
|
||||
norm[index] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
for range in get_matches(&CONTROL_CHARS_REGEX, text) {
|
||||
for i in range {
|
||||
if let Some(index) = text.char_indices().position(|x| x.0 == i) {
|
||||
norm[index] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut now_chunk = String::new();
|
||||
let mut chunks = Vec::new();
|
||||
let mut length = 0;
|
||||
|
||||
for (i, b) in norm.iter().enumerate() {
|
||||
if *b {
|
||||
length += 1;
|
||||
}
|
||||
|
||||
now_chunk.push(text.chars().skip(i).next().unwrap());
|
||||
|
||||
if length == width {
|
||||
chunks.push((now_chunk.clone(), length));
|
||||
now_chunk.clear();
|
||||
length = 0;
|
||||
}
|
||||
}
|
||||
if !now_chunk.is_empty() {
|
||||
chunks.push((now_chunk.clone(), length));
|
||||
}
|
||||
|
||||
chunks
|
||||
}
|
||||
|
||||
pub fn sanitize_text(input: &str) -> String {
|
||||
let ansi_regex = Regex::new(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])").unwrap();
|
||||
let control_chars_regex = Regex::new(r"[\x00-\x1F\x7F]").unwrap();
|
||||
let without_ansi = ansi_regex.replace_all(input, "");
|
||||
let cleaned_text = control_chars_regex.replace_all(&without_ansi, "");
|
||||
let without_ansi = ANSI_REGEX.replace_all(input, "");
|
||||
let cleaned_text = CONTROL_CHARS_REGEX.replace_all(&without_ansi, "");
|
||||
cleaned_text.into_owned()
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user