diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 7be2ea09..3dacb5c8 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3778,6 +3778,10 @@ pub fn insert_char(cx: &mut Context, c: char) { doc.apply(&t, view.id); } + // -- TudbuT mod begin + helix_view::tt__update_manpage(doc, view.id); + // -- TudbuT mod end + helix_event::dispatch(PostInsertChar { c, cx }); } diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 23b597a3..5b4fdc4d 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1144,6 +1144,9 @@ pub fn set_selection(&mut self, view_id: ViewId, selection: Selection) { // TODO: use a transaction? self.selections .insert(view_id, selection.ensure_invariants(self.text().slice(..))); + // -- TudbuT mod begin + crate::tt__update_manpage(self, view_id); + // -- TudbuT mod end helix_event::dispatch(SelectionDidChange { doc: self, view: view_id, @@ -1225,6 +1228,9 @@ fn apply_impl( view_id, selection.clone().ensure_invariants(self.text.slice(..)), ); + // -- TudbuT mod begin + crate::tt__update_manpage(self, view_id); + // -- TudbuT mod end helix_event::dispatch(SelectionDidChange { doc: self, view: view_id, diff --git a/helix-view/src/lib.rs b/helix-view/src/lib.rs index 14b6e1ce..79541244 100644 --- a/helix-view/src/lib.rs +++ b/helix-view/src/lib.rs @@ -75,3 +75,148 @@ pub fn align_view(doc: &Document, view: &mut View, align: Align) { use helix_core::char_idx_at_visual_offset; pub use theme::Theme; pub use view::View; + +// -- TudbuT mod begin + +/// communicates with the outside world +#[allow(non_camel_case_types)] +struct TT__Server { + tcp_listener: std::net::TcpListener, + tcp_streams: Vec, + last_word: String, +} + +impl TT__Server { + fn new() -> Self { + // god damn + #[derive(Clone)] + struct AddrIter + Clone> { + inner: T, + } + impl + Clone> AddrIter { + pub fn new(inner: T) -> Self { + Self { inner } + } + } + impl + Clone> Iterator for AddrIter { + type Item = std::net::SocketAddr; + + fn next(&mut self) -> Option { + Some(std::net::SocketAddr::V4(std::net::SocketAddrV4::new( + std::net::Ipv4Addr::new(127, 0, 0, 1), + self.inner.next()?, + ))) + } + } + impl + Clone> std::net::ToSocketAddrs for AddrIter { + type Iter = Self; + + fn to_socket_addrs(&self) -> std::io::Result { + Ok(self.clone()) + } + } + + let me = Self { + tcp_listener: std::net::TcpListener::bind(AddrIter::new(7400..)).expect("DO NOT REPORT THIS TO HELIX!!! This is a TudbuT mod error: unable to start TT__Server"), + tcp_streams: Vec::new(), + last_word: String::default(), + }; + + me.tcp_listener.set_nonblocking(true).expect( + "DO NOT REPORT THIS TO HELIX!!! This is a TudbuT mod error: unable to set nonblocking", + ); + + me + } + + fn update(&mut self, mut new_word: String) { + use std::io::{ErrorKind, Read, Write}; + + if let Ok((x, _)) = self.tcp_listener.accept() { + if x.set_nonblocking(true).is_ok() { + self.tcp_streams.push(x); + } + } + new_word += "\n"; + if self.last_word != new_word { + let b = new_word.as_bytes().len(); + let mut buf = [0u8; 1024]; + let mut to_remove = Vec::new(); + for (i, stream) in self.tcp_streams.iter_mut().enumerate() { + match stream.read(&mut buf) { + Ok(_n @ 1..) => (), + Err(e) if e.kind() == ErrorKind::WouldBlock => (), + _ => { + to_remove.push(i); + continue; + } + } + match stream.write(new_word.as_bytes()) { + Ok(n) if n == b => (), + _ => to_remove.push(i), + } + } + for i in to_remove { + let stream = self.tcp_streams.remove(i); + let _ = stream.shutdown(std::net::Shutdown::Both); + } + + self.last_word = new_word; + } + } +} + +#[allow(non_upper_case_globals)] +static TT__SERVER: std::sync::Mutex> = std::sync::Mutex::new(None); + +#[allow(non_snake_case)] +pub fn tt__update_manpage(doc: &Document, view_id: ViewId) { + let c = helix_core::syntax::FileType::Extension("c".to_owned()); + + fn get_word(text: &str, idx: usize) -> &str { + let mut start = idx; + let mut end = idx; + + const WORD_END: &str = " {}()[],#+-/*;<>&!\"'%$?~^|'\n\r"; + + while start != 0 && !WORD_END.contains(&&text[start - 1..start]) { + start = match start.checked_sub(1) { + Some(n) => n, + None => break, + } + } + + while end != text.len() && !WORD_END.contains(&&text[end..=end]) { + end += 1; + } + + &text[start..end] + } + + if doc + .language + .as_ref() + .is_some_and(|x| x.file_types.contains(&c)) + { + let idx = doc.selection(view_id).primary().to() - 1; + let lidx = doc.text().char_to_line(idx); + let line_idx = doc.text().line_to_char(lidx); + let next_line_idx = doc.text().line_to_char(lidx + 1); + let idx_in_line = idx - line_idx; + + let text_in_line = doc.text().slice(line_idx..next_line_idx).to_string(); + + let word = get_word(&text_in_line, idx_in_line); + + let mut server = TT__SERVER + .lock() + .expect("DO NOT REPORT THIS TO HELIX (mod error)"); + if let Some(ref mut server) = *server { + server.update(word.to_owned()); + } else { + *server = Some(TT__Server::new()); + } + } +} + +// -- TudbuT mod end