diff --git a/src/gopher.rs b/src/gopher.rs index ac81a24..7cc9507 100644 --- a/src/gopher.rs +++ b/src/gopher.rs @@ -133,18 +133,13 @@ pub fn fetch_url(url: &str) -> Result { // Fetches a gopher URL by its component parts and returns a raw Gopher response. pub fn fetch(host: &str, port: &str, selector: &str) -> Result { - let mut body = String::new(); - let selector = selector.replace('?', "\t"); // search queries - - format!("{}:{}", host, port) - .to_socket_addrs() - .and_then(|mut socks| socks.next().ok_or_else(|| error!("Can't create socket"))) - .and_then(|sock| TcpStream::connect_timeout(&sock, TCP_TIMEOUT_DURATION)) + get(host, port, selector) .and_then(|mut stream| { stream.write(format!("{}\r\n", selector).as_ref()); Ok(stream) }) .and_then(|mut stream| { + let mut body = String::new(); stream.set_read_timeout(Some(TCP_TIMEOUT_DURATION)); stream.read_to_string(&mut body)?; Ok(body) @@ -155,7 +150,6 @@ pub fn fetch(host: &str, port: &str, selector: &str) -> Result { // Returns the path it was saved to and the size in bytes. pub fn download_url(url: &str) -> Result<(String, usize)> { let (_, host, port, sel) = parse_url(url); - let sel = sel.replace('?', "\t"); // search queries let filename = sel .split_terminator('/') .rev() @@ -166,38 +160,42 @@ pub fn download_url(url: &str) -> Result<(String, usize)> { let stdin = termion::async_stdin(); let mut keys = stdin.keys(); + get(host, port, sel).and_then(|mut stream| { + stream.set_read_timeout(Some(TCP_TIMEOUT_DURATION))?; + + let mut file = std::fs::OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .mode(0o770) + .open(path)?; + + let mut buf = [0; 1024]; + let mut bytes = 0; + while let Ok(count) = stream.read(&mut buf) { + if count == 0 { + break; + } + bytes += count; + file.write(&buf[..count]); + if let Some(Ok(termion::event::Key::Ctrl('c'))) = keys.next() { + return Err(error!("Download canceled")); + } + } + Ok((filename.to_string(), bytes)) + }) +} + +pub fn get(host: &str, port: &str, selector: &str) -> Result { + let selector = selector.replace('?', "\t"); // search queries format!("{}:{}", host, port) .to_socket_addrs() .and_then(|mut socks| socks.next().ok_or_else(|| error!("Can't create socket"))) .and_then(|sock| TcpStream::connect_timeout(&sock, TCP_TIMEOUT_DURATION)) .and_then(|mut stream| { - stream.write(format!("{}\r\n", sel).as_ref()); + stream.write(format!("{}\r\n", selector).as_ref()); Ok(stream) }) - .and_then(|mut stream| { - stream.set_read_timeout(Some(TCP_TIMEOUT_DURATION))?; - - let mut file = std::fs::OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .mode(0o770) - .open(path)?; - - let mut buf = [0; 1024]; - let mut bytes = 0; - while let Ok(count) = stream.read(&mut buf) { - if count == 0 { - break; - } - bytes += count; - file.write(&buf[..count]); - if let Some(Ok(termion::event::Key::Ctrl('c'))) = keys.next() { - return Err(error!("Download canceled")); - } - } - Ok((filename.to_string(), bytes)) - }) } // Parses gopher URL into parts. diff --git a/src/menu.rs b/src/menu.rs index ca6dd5d..11aa159 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -88,7 +88,7 @@ impl Menu { if let Some(&pos) = self.links.get(i) { Some(if pos < self.scroll { LinkDir::Above - } else if pos >= self.scroll + self.rows() { + } else if pos > self.scroll + self.rows() { LinkDir::Below } else { LinkDir::Visible @@ -315,7 +315,7 @@ impl Menu { self.link = new_link; // scroll if we are within 5 lines of the top if let Some(&pos) = self.links.get(self.link) { - if pos < self.scroll + 5 { + if self.scroll > 0 && pos < self.scroll + 5 { self.scroll -= 1; } } @@ -353,15 +353,10 @@ impl Menu { T: std::iter::Iterator, { let pattern = pattern.to_ascii_lowercase(); - while let Some(&i) = it.next() { - let name = if let Some(link) = self.link(i) { - link.name.to_ascii_lowercase() - } else { - continue; - }; - - if name.contains(&pattern) { - return Some(i); + for &pos in it { + let line = self.lines.get(pos)?; + if line.name.to_ascii_lowercase().contains(&pattern) { + return Some(line.link); } } None