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 std::{cmp::{max, min}, error::Error, io::{stdout, Write}, sync::{atomic::{AtomicUsize, Ordering}, Arc, RwLock}, thread, time::{Duration, SystemTime}};
|
||||||
|
|
||||||
use colored::{Color, Colorize};
|
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 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};
|
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!(
|
let text = format!(
|
||||||
"{}{}\r\n> {}",
|
"{}\r\n> {}",
|
||||||
"\r\n".repeat(context.max_messages - messages.len()),
|
messages[messages.len()-height-1..].into_iter()
|
||||||
messages.join("\r\n"),
|
.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
|
input
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -333,6 +352,13 @@ fn poll_events(ctx: Arc<Context>) -> Result<(), Box<dyn Error>> {
|
|||||||
write!(stdout(), "{}", &data).unwrap();
|
write!(stdout(), "{}", &data).unwrap();
|
||||||
stdout().lock().flush().unwrap();
|
stdout().lock().flush().unwrap();
|
||||||
},
|
},
|
||||||
|
Event::Resize(_, _) => {
|
||||||
|
print_console(
|
||||||
|
ctx.clone(),
|
||||||
|
messages.messages(),
|
||||||
|
&input.read().unwrap()
|
||||||
|
)?;
|
||||||
|
},
|
||||||
Event::Mouse(data) => {
|
Event::Mouse(data) => {
|
||||||
match data.kind {
|
match data.kind {
|
||||||
MouseEventKind::ScrollUp => {
|
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;
|
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 {
|
pub fn sanitize_text(input: &str) -> String {
|
||||||
let ansi_regex = Regex::new(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])").unwrap();
|
let without_ansi = ANSI_REGEX.replace_all(input, "");
|
||||||
let control_chars_regex = Regex::new(r"[\x00-\x1F\x7F]").unwrap();
|
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()
|
cleaned_text.into_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user