Skip to content

Commit

Permalink
Remove "terminal::writeline!()" macro
Browse files Browse the repository at this point in the history
In console 0.15.7, read_char() won't break println!() in other threads:
- console-rs/console#165
- console-rs/console#136
"terminal::writeline!()" was a workaround for this problem.
So it's no longer needed.
  • Loading branch information
JasonWei512 committed May 22, 2023
1 parent cc68773 commit 6b93cd3
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 97 deletions.
81 changes: 46 additions & 35 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ reqwest = { version = "0.11.10", features = ["blocking", "json"] }
minimp3 = "0.5.1"
clap = { version = "3.1.18", features = ["derive"] }
indicatif = "0.17.1"
console = "0.15.0"
console = "0.15.7"
colored = "2.0.0"
version-compare = "0.1.0"
inquire = { version = "0.6.1", default-features = false, features = ["console"] }
Expand Down
31 changes: 15 additions & 16 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use model::{CodeRadioMessage, Remote};
use player::Player;
use rodio::Source;
use std::{fmt::Write, sync::Mutex, thread, time::Duration};
use terminal::writeline;
use tokio::{net::TcpStream, time::sleep};
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};

Expand All @@ -36,7 +35,7 @@ async fn main() {
let _terminal_clean_up_helper = terminal::create_clean_up_helper(); // See the comments in "terminal" module

if let Err(e) = start().await {
writeline!();
println!();
terminal::print_error(e);
}
}
Expand Down Expand Up @@ -82,7 +81,7 @@ async fn start_playing(args: Args) -> Result<()> {
}
Err(e) => {
terminal::print_error(e);
writeline!();
println!();
}
}

Expand All @@ -109,17 +108,17 @@ async fn start_playing(args: Args) -> Result<()> {
// Notify user if a new version is available
if update_checking_task.is_finished() {
if let Ok(Ok(Some(new_release))) = update_checking_task.await {
writeline!(
println!(
"{}",
format!("New version available: {}", new_release.version).bright_yellow()
);
writeline!("{}", new_release.url.bright_yellow());
writeline!();
println!("{}", new_release.url.bright_yellow());
println!();
}
}

if let Some(station) = stations.iter().find(|station| station.url == listen_url) {
writeline!("{} {}", "Station:".bright_green(), station.name);
println!("{} {}", "Station:".bright_green(), station.name);
}

if let Some(player) = PLAYER.lock().unwrap().as_ref() {
Expand Down Expand Up @@ -161,11 +160,11 @@ Run {} to get more help.",
);

if !args.no_logo {
writeline!("{}", logo);
writeline!();
println!("{}", logo);
println!();
}
writeline!("{}", description);
writeline!();
println!("{}", description);
println!();
}

async fn get_next_websocket_message(
Expand Down Expand Up @@ -241,10 +240,10 @@ fn update_song_info_on_screen(message: CodeRadioMessage, last_song_id: &mut Stri

*last_song_id = song.id.clone();

writeline!();
writeline!("{} {}", "Song:".bright_green(), song.title);
writeline!("{} {}", "Artist:".bright_green(), song.artist);
writeline!("{} {}", "Album:".bright_green(), song.album);
println!();
println!("{} {}", "Song:".bright_green(), song.title);
println!("{} {}", "Artist:".bright_green(), song.artist);
println!("{} {}", "Album:".bright_green(), song.album);

let progress_bar_len = if total_seconds > 0 {
total_seconds as u64
Expand Down Expand Up @@ -362,7 +361,7 @@ async fn select_station_interactively() -> Result<Remote> {
.unwrap()
.clone();

writeline!();
println!();

Ok(selected_station)
}
Expand Down
60 changes: 15 additions & 45 deletions src/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,70 +3,40 @@ use console::Term;
use once_cell::sync::Lazy;
use std::fmt::Display;

pub static STDOUT: Lazy<Term> = Lazy::new(Term::stdout);
static STDOUT: Lazy<Term> = Lazy::new(Term::stdout);

pub fn enable_color_on_windows() {
#[cfg(windows)]
colored::control::set_virtual_terminal(true).unwrap();
}

/// This program handles keyboard input (adjust volume) by spawning a thread
/// and calling [console](https://github.com/console-rs/console) crate's `console::Term::stdout().read_char()` in a loop.
///
/// This is how `console::Term::stdout().read_char()` works on Unix-like OS:
/// 1. Call the method
/// 2. Your terminal exits "canonical" mode and enters "raw" mode
/// 3. The method blocks until you press a key
/// 4. Terminal exits "raw" mode and returns to "canonical" mode
/// 5. The method returns the key you pressed
///
/// Unfortunately this may cause messy terminal output.
/// See `terminal::writeline!()` and `terminal::create_clean_up_helper()`'s doc.
pub fn read_char() -> std::io::Result<char> {
STDOUT.read_char()
}

pub fn print_error(error: impl Display) {
writeline!("{} {}", "Error:".bright_red(), error);
println!("{} {}", "Error:".bright_red(), error);
}

/// Whenever you want to print something to terminal, use this macro. DO NOT USE Rust's `println!()`.
/// You should create an instance of `CleanUpHelper` by calling this method when the programs starts.
///
/// # The Problem
///
/// On Unix-like OS, when `terminal::read_char()` is blocking in a background thread, your terminal will stay in "raw" mode.
/// If you write something to terminal from another thread, the terminal output will get messy:
///
/// - https://github.com/console-rs/console/issues/36
/// - https://github.com/console-rs/console/issues/136
///
/// See `terminal::read_char()`'s doc.
///
/// # The Workaround
///
/// This macro will move the cursor to the beginning of the line after writing a line, which fixes the bug.
macro_rules! writeline {
() => {
let _ = crate::terminal::STDOUT.write_line("\r");
};
($($arg:tt)+) => {
for line in format!($($arg)+).split("\n") {
let line_r = format!("{}\r", line);
let _ = crate::terminal::STDOUT.write_line(&line_r);
}
};
}

pub(crate) use writeline;

/// You should create an instance of `CleanUpHelper` by calling this method when the programs starts.
/// This program handles keyboard input (adjust volume) by spawning a thread
/// and calling [console](https://github.com/console-rs/console) crate's `console::Term::stdout().read_char()` in a loop.
///
/// # The Problem
/// This is how `console::Term::stdout().read_char()` works on Unix-like OS:
/// 1. Call the method
/// 2. Your terminal exits "canonical" mode and enters "raw" mode
/// 3. The method blocks until you press a key
/// 4. Terminal exits "raw" mode and returns to "canonical" mode
/// 5. The method returns the key you pressed
///
/// On Unix-like OS, if the program exits accidentally when `terminal::read_char()` is blocking,
/// your terminal will stay in "raw" mode and the terminal output will get messy.
/// Unfortunately, on Unix-like OS, if the program exits accidentally when `terminal::read_char()` is blocking,
/// your terminal will stay in "raw" mode and the terminal output will get messy:
///
/// See `terminal::read_char()`'s doc.
/// - https://github.com/console-rs/console/issues/36
/// - https://github.com/console-rs/console/issues/136
///
/// # The Workaround
///
Expand Down

0 comments on commit 6b93cd3

Please sign in to comment.