diff --git a/.changes/cli-fix-overflow-windows.md b/.changes/cli-fix-overflow-windows.md new file mode 100644 index 000000000..e4f7a924a --- /dev/null +++ b/.changes/cli-fix-overflow-windows.md @@ -0,0 +1,6 @@ +--- +"cli.rs": patch +"cli.js": patch +--- + +Fixes text overflow on `tauri dev` on Windows. diff --git a/examples/api/src-tauri/Cargo.lock b/examples/api/src-tauri/Cargo.lock index 35ba43aa0..5206517d0 100644 --- a/examples/api/src-tauri/Cargo.lock +++ b/examples/api/src-tauri/Cargo.lock @@ -3389,7 +3389,7 @@ dependencies = [ [[package]] name = "tauri" -version = "1.0.0-rc.7" +version = "1.0.0-rc.8" dependencies = [ "anyhow", "attohttpc", @@ -3446,7 +3446,7 @@ dependencies = [ [[package]] name = "tauri-build" -version = "1.0.0-rc.6" +version = "1.0.0-rc.7" dependencies = [ "anyhow", "cargo_toml", diff --git a/examples/api/src-tauri/Cargo.toml b/examples/api/src-tauri/Cargo.toml index e4eae7738..eac48f72a 100644 --- a/examples/api/src-tauri/Cargo.toml +++ b/examples/api/src-tauri/Cargo.toml @@ -12,7 +12,7 @@ tauri-build = { path = "../../../core/tauri-build", features = ["isolation"] } [dependencies] serde_json = "1.0" serde = { version = "1.0", features = [ "derive" ] } -tauri = { path = "../../../core/tauri", features = ["api-all", "cli", "http-multipart", "icon-ico", "icon-png", "isolation", "macos-private-api", "reqwest-client", "system-tray", "updater", "global-shortcut"] } +tauri = { path = "../../../core/tauri", features = ["api-all", "cli", "global-shortcut", "http-multipart", "icon-ico", "icon-png", "isolation", "macos-private-api", "reqwest-client", "system-tray", "updater"] } tiny_http = "0.11" [features] diff --git a/tooling/cli/Cargo.lock b/tooling/cli/Cargo.lock index b97ddf3d1..66cb4f37f 100644 --- a/tooling/cli/Cargo.lock +++ b/tooling/cli/Cargo.lock @@ -2740,6 +2740,7 @@ dependencies = [ "ureq", "url", "valico", + "winapi 0.3.9", "zeroize", ] diff --git a/tooling/cli/Cargo.toml b/tooling/cli/Cargo.toml index c72d3e5df..64f7f9657 100644 --- a/tooling/cli/Cargo.toml +++ b/tooling/cli/Cargo.toml @@ -52,7 +52,6 @@ os_info = "3.2" semver = "1.0" regex = "1.5.5" lazy_static = "1" -libc = "0.2" terminal_size = "0.1" unicode-width = "0.1" tempfile = "3" @@ -67,10 +66,14 @@ ctrlc = "3.2" [target."cfg(windows)".dependencies] encode_unicode = "0.3" +winapi = { version = "0.3", features = ["handleapi", "processenv", "winbase", "wincon", "winnt"] } [target."cfg(target_os = \"linux\")".build-dependencies] heck = "0.4" +[target."cfg(unix)".dependencies] +libc = "0.2" + [build-dependencies] tauri-utils = { version = "1.0.0-rc.0", features = [ "schema", "isolation" ], path = "../../core/tauri-utils" } schemars = { version = "0.8", features = [ "url" ] } diff --git a/tooling/cli/src/dev.rs b/tooling/cli/src/dev.rs index 26217c874..3182360dc 100644 --- a/tooling/cli/src/dev.rs +++ b/tooling/cli/src/dev.rs @@ -23,7 +23,7 @@ use std::{ env::set_current_dir, ffi::OsStr, fs::FileType, - io::BufReader, + io::{BufReader, Write}, path::{Path, PathBuf}, process::{exit, Command}, sync::{ @@ -320,7 +320,6 @@ fn lookup(dir: &Path, mut f: F) { default_gitignore.push(".gitignore"); if !default_gitignore.exists() { if let Ok(mut file) = std::fs::File::create(default_gitignore.clone()) { - use std::io::Write; let _ = file.write_all(TAURI_DEV_WATCHER_GITIGNORE); } } @@ -422,7 +421,7 @@ fn kill_before_dev_process() { if !kill_children_script_path.exists() { if let Ok(mut file) = std::fs::File::create(&kill_children_script_path) { - use std::{io::Write, os::unix::fs::PermissionsExt}; + use std::os::unix::fs::PermissionsExt; let _ = file.write_all(KILL_CHILDREN_SCRIPT); let mut permissions = file.metadata().unwrap().permissions(); permissions.set_mode(0o770); @@ -448,9 +447,15 @@ fn start_app( command .env( "CARGO_TERM_PROGRESS_WIDTH", - terminal_size::terminal_size() - .map(|(w, _)| w.0) - .unwrap_or(80) + terminal::stderr_width() + .map(|width| { + if cfg!(windows) { + std::cmp::min(60, width) + } else { + width + } + }) + .unwrap_or(if cfg!(windows) { 60 } else { 80 }) .to_string(), ) .env("CARGO_TERM_PROGRESS_WHEN", "always"); @@ -506,19 +511,18 @@ fn start_app( std::thread::spawn(move || { let mut buf = Vec::new(); let mut lines = stderr_lines_.lock().unwrap(); + let mut io_stderr = std::io::stderr(); loop { buf.clear(); match tauri_utils::io::read_line(&mut stderr, &mut buf) { Ok(s) if s == 0 => break, _ => (), } - let line = String::from_utf8_lossy(&buf).into_owned(); - if line.ends_with('\r') { - eprint!("{}", line); - } else { - eprintln!("{}", line); + let _ = io_stderr.write_all(&buf); + if !buf.ends_with(&[b'\r']) { + let _ = io_stderr.write_all(b"\n"); } - lines.push(line); + lines.push(String::from_utf8_lossy(&buf).into_owned()); } }); @@ -554,3 +558,82 @@ fn start_app( Ok(child_arc) } + +// taken from https://github.com/rust-lang/cargo/blob/78b10d4e611ab0721fc3aeaf0edd5dd8f4fdc372/src/cargo/core/shell.rs#L514 +#[cfg(unix)] +mod terminal { + use std::mem; + + pub fn stderr_width() -> Option { + unsafe { + let mut winsize: libc::winsize = mem::zeroed(); + // The .into() here is needed for FreeBSD which defines TIOCGWINSZ + // as c_uint but ioctl wants c_ulong. + #[allow(clippy::useless_conversion)] + if libc::ioctl(libc::STDERR_FILENO, libc::TIOCGWINSZ.into(), &mut winsize) < 0 { + return None; + } + if winsize.ws_col > 0 { + Some(winsize.ws_col as usize) + } else { + None + } + } + } +} + +// taken from https://github.com/rust-lang/cargo/blob/78b10d4e611ab0721fc3aeaf0edd5dd8f4fdc372/src/cargo/core/shell.rs#L543 +#[cfg(windows)] +mod terminal { + use std::{cmp, mem, ptr}; + use winapi::um::fileapi::*; + use winapi::um::handleapi::*; + use winapi::um::processenv::*; + use winapi::um::winbase::*; + use winapi::um::wincon::*; + use winapi::um::winnt::*; + + pub fn stderr_width() -> Option { + unsafe { + let stdout = GetStdHandle(STD_ERROR_HANDLE); + let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed(); + if GetConsoleScreenBufferInfo(stdout, &mut csbi) != 0 { + return Some((csbi.srWindow.Right - csbi.srWindow.Left) as usize); + } + + // On mintty/msys/cygwin based terminals, the above fails with + // INVALID_HANDLE_VALUE. Use an alternate method which works + // in that case as well. + let h = CreateFileA( + "CONOUT$\0".as_ptr() as *const CHAR, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + ptr::null_mut(), + OPEN_EXISTING, + 0, + ptr::null_mut(), + ); + if h == INVALID_HANDLE_VALUE { + return None; + } + + let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed(); + let rc = GetConsoleScreenBufferInfo(h, &mut csbi); + CloseHandle(h); + if rc != 0 { + let width = (csbi.srWindow.Right - csbi.srWindow.Left) as usize; + // Unfortunately cygwin/mintty does not set the size of the + // backing console to match the actual window size. This + // always reports a size of 80 or 120 (not sure what + // determines that). Use a conservative max of 60 which should + // work in most circumstances. ConEmu does some magic to + // resize the console correctly, but there's no reasonable way + // to detect which kind of terminal we are running in, or if + // GetConsoleScreenBufferInfo returns accurate information. + return Some(cmp::min(60, width)); + } + + None + } + } +}