From 421983636f95be75d113e2b7162351057fe09f8e Mon Sep 17 00:00:00 2001 From: Master-Hash Date: Wed, 26 Nov 2025 00:54:38 +0800 Subject: [PATCH 1/3] Support wasm-wasip1 target Co-authored-by: Cetin Sert Signed-off-by: Master-Hash --- .cargo/config.toml | 6 +++++ .github/workflows/release.yml | 14 ++++++++++++ Cargo.toml | 6 +++-- src/files.rs | 17 +++++++++++++- src/main.rs | 14 ++++++++++-- src/options.rs | 42 +++++++++++++++++++++++++++++------ 6 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000000..529fe26067 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,6 @@ +[target.wasm32-wasip1] +rustflags = [ + "-L/opt/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasi", + "-Clink-arg=-lc++", + "-Clink-arg=-lc++abi" +] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1a7df89522..3a72b7cf07 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,6 +37,8 @@ jobs: # detects that they need cross). - target: x86_64-unknown-linux-musl os: ubuntu-22.04 + - target: wasm32-wasip1 + os: ubuntu-24.04 - target: aarch64-unknown-linux-gnu os: ubuntu-22.04 - target: aarch64-pc-windows-msvc @@ -46,6 +48,13 @@ jobs: runs-on: ${{ matrix.os }} steps: # v4.2.2 + - run: | + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-29/wasi-sdk-29.0-x86_64-linux.deb + sudo apt-get install ./wasi-sdk-29.0-x86_64-linux.deb + rm ./wasi-sdk-29.0-x86_64-linux.deb + rustup override set stable + rustup target add wasm32-wasip1 + if: ${{ matrix.target == 'wasm32-wasip1' }} - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: taiki-e/upload-rust-binary-action@v1 with: @@ -59,6 +68,11 @@ jobs: env: # (required) GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + WASI_SDK_PATH: /opt/wasi-sdk + WASI_SYSROOT: /opt/wasi-sdk/share/wasi-sysroot + CC_wasm32_wasip1: /opt/wasi-sdk/bin/clang + AR_wasm32_wasip1: /opt/wasi-sdk/bin/llvm-ar + CFLAGS_wasm32_wasip1: "--sysroot=/opt/wasi-sdk/share/wasi-sysroot" push_crates_io: runs-on: ubuntu-22.04 diff --git a/Cargo.toml b/Cargo.toml index 4c3f893cee..a86367197c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,6 @@ tree_magic_mini = "3.1.6" bumpalo = "3.16.0" unicode-width = "0.1.9" -crossterm = { version = "0.28.0", features = ["windows"] } glob = "0.3.1" strum = { version = "0.26", features = ["derive"] } hashbrown = "0.14.0" @@ -128,7 +127,10 @@ tree-sitter-xml = "0.7.0" tree-sitter-yaml = "0.7.0" tree-sitter-zig = "1.1.2" -[target.'cfg(not(any(target_env = "msvc", target_os = "illumos", target_os = "freebsd")))'.dependencies] +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +crossterm = { version = "0.28.0", features = ["windows"] } + +[target.'cfg(not(any(target_env = "msvc", target_os = "illumos", target_os = "freebsd", target_arch = "wasm32")))'.dependencies] tikv-jemallocator = "0.6" [dev-dependencies] diff --git a/src/files.rs b/src/files.rs index 9534ab9f8a..5ca5d4bc53 100644 --- a/src/files.rs +++ b/src/files.rs @@ -78,6 +78,7 @@ fn read_file_arg(file_arg: &FileArgument) -> std::io::Result> { } /// Write a human-friendly description of `e` to stderr. +#[cfg(not(target_arch = "wasm32"))] fn eprint_read_error(file_arg: &FileArgument, e: &std::io::Error) { match e.kind() { std::io::ErrorKind::NotFound => { @@ -95,12 +96,26 @@ fn eprint_read_error(file_arg: &FileArgument, e: &std::io::Error) { }; } +#[cfg(target_arch = "wasm32")] +fn eprint_read_error(file_arg: &FileArgument, e: &std::io::Error) { + // For the browser/WASM demo, fail softly so we can keep running. + println!("WASM read error on {} ({:?})", file_arg, e.kind()); +} + pub(crate) fn read_or_die(path: &Path) -> Vec { match fs::read(path) { Ok(src) => src, Err(e) => { eprint_read_error(&FileArgument::NamedPath(path.to_path_buf()), &e); - std::process::exit(EXIT_BAD_ARGUMENTS); + #[cfg(target_arch = "wasm32")] + { + // Return empty content in WASM to avoid aborting the demo. + return Vec::new(); + } + #[cfg(not(target_arch = "wasm32"))] + { + std::process::exit(EXIT_BAD_ARGUMENTS); + } } } } diff --git a/src/main.rs b/src/main.rs index 27bbadb8e0..600206468d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -98,10 +98,20 @@ use crate::parse::syntax; /// /// For reference, Jemalloc uses 10-20% more time (although up to 33% /// more instructions) when testing on sample files. -#[cfg(not(any(target_env = "msvc", target_os = "illumos", target_os = "freebsd")))] +#[cfg(not(any( + target_env = "msvc", + target_os = "illumos", + target_os = "freebsd", + target_arch = "wasm32" +)))] use tikv_jemallocator::Jemalloc; -#[cfg(not(any(target_env = "msvc", target_os = "illumos", target_os = "freebsd")))] +#[cfg(not(any( + target_env = "msvc", + target_os = "illumos", + target_os = "freebsd", + target_arch = "wasm32" +)))] #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; diff --git a/src/options.rs b/src/options.rs index 6231cf9472..52b14821b4 100644 --- a/src/options.rs +++ b/src/options.rs @@ -8,7 +8,6 @@ use std::{ }; use clap::{crate_authors, crate_description, value_parser, Arg, ArgAction, Command}; -use crossterm::tty::IsTty; use owo_colors::OwoColorize as _; use crate::{ @@ -51,6 +50,30 @@ pub(crate) struct DisplayOptions { pub(crate) const DEFAULT_TERMINAL_WIDTH: usize = 80; +#[cfg(not(target_arch = "wasm32"))] +fn stdout_is_tty() -> bool { + use crossterm::tty::IsTty; + std::io::stdout().is_tty() +} + +#[cfg(target_arch = "wasm32")] +fn stdout_is_tty() -> bool { + false +} + +#[cfg(not(target_arch = "wasm32"))] +fn terminal_columns() -> Option { + crossterm::terminal::size() + .ok() + .map(|(cols, _rows)| cols as usize) + .filter(|cols| *cols > 0) +} + +#[cfg(target_arch = "wasm32")] +fn terminal_columns() -> Option { + None +} + impl Default for DisplayOptions { fn default() -> Self { Self { @@ -125,7 +148,7 @@ fn app() -> clap::Command { )); after_help.push_str("\n\nSee the full manual at "); - if std::io::stdout().is_tty() { + if stdout_is_tty() { // Make the link to the manual clickable in terminals that // support OSC 8, the ANSI escape code for hyperlinks. // @@ -596,6 +619,7 @@ fn common_path_suffix(lhs_path: &Path, rhs_path: &Path) -> Option { } /// Does `path` look like "/tmp/git-blob-abcdef/modified_field.txt"? +#[cfg(not(target_arch = "wasm32"))] fn is_git_tmpfile(path: &Path) -> bool { let Ok(rel_path) = path.strip_prefix(std::env::temp_dir()) else { return false; @@ -612,6 +636,12 @@ fn is_git_tmpfile(path: &Path) -> bool { .starts_with("git-blob-") } +#[cfg(target_arch = "wasm32")] +fn is_git_tmpfile(_path: &Path) -> bool { + // WASI environments may not have a writable /tmp; skip special-casing. + false +} + fn build_display_path(lhs_path: &FileArgument, rhs_path: &FileArgument) -> String { match (lhs_path, rhs_path) { (FileArgument::NamedPath(lhs), FileArgument::NamedPath(rhs)) => { @@ -1002,10 +1032,8 @@ pub(crate) fn parse_args() -> Mode { /// Try to work out the width of the terminal we're on, or fall back /// to a sensible default value. fn detect_terminal_width() -> usize { - if let Ok((columns, _rows)) = crossterm::terminal::size() { - if columns > 0 { - return columns.into(); - } + if let Some(columns) = terminal_columns() { + return columns; } // If crossterm couldn't detect the terminal width, use the @@ -1036,7 +1064,7 @@ pub(crate) fn should_use_color(color_output: ColorOutput) -> bool { fn detect_color_support() -> bool { // TODO: consider following the env parsing logic in git_config_bool // in config.c. - std::io::stdout().is_tty() || env::var("GIT_PAGER_IN_USE").is_ok() + stdout_is_tty() || env::var("GIT_PAGER_IN_USE").is_ok() } #[cfg(test)] From 5280af31cfad20695ebe65155e113c74011cee93 Mon Sep 17 00:00:00 2001 From: Master-Hash Date: Wed, 26 Nov 2025 02:45:22 +0800 Subject: [PATCH 2/3] ci: enable test for wasm-wasip1 target Signed-off-by: Master-Hash --- .cargo/config.toml | 1 + .github/workflows/test.yml | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/.cargo/config.toml b/.cargo/config.toml index 529fe26067..4ddecc1c2c 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -4,3 +4,4 @@ rustflags = [ "-Clink-arg=-lc++", "-Clink-arg=-lc++abi" ] +runner = "wasmtime run" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 497926abea..2f82188507 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,6 +16,7 @@ jobs: - { target: aarch64-pc-windows-msvc, os: windows-11-arm } - { target: aarch64-unknown-linux-gnu, os: ubuntu-22.04, use-cross: true } + - { target: wasm32-wasip1, os: ubuntu-24.04 } # mac-14 is an M1 ARM device. - { target: aarch64-apple-darwin, os: macos-14 } @@ -35,6 +36,7 @@ jobs: uses: dtolnay/rust-toolchain@1.76.0 with: targets: ${{ matrix.job.target }} + if: ${{ matrix.job.target != 'wasm32-wasip1' }} - name: Install cross if: matrix.job.use-cross @@ -42,6 +44,14 @@ jobs: with: tool: cross@0.2.5 + - if: ${{ matrix.job.target == 'wasm32-wasip1' }} + run: | + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-29/wasi-sdk-29.0-x86_64-linux.deb + sudo apt-get install ./wasi-sdk-29.0-x86_64-linux.deb + rm ./wasi-sdk-29.0-x86_64-linux.deb + rustup override set stable + rustup target add wasm32-wasip1 + - name: Overwrite build command env variable if: matrix.job.use-cross shell: bash @@ -50,6 +60,12 @@ jobs: - name: Test shell: bash run: $BUILD_CMD $SUBCOMMAND --target ${{ matrix.job.target }} + env: + WASI_SDK_PATH: /opt/wasi-sdk + WASI_SYSROOT: /opt/wasi-sdk/share/wasi-sysroot + CC_wasm32_wasip1: /opt/wasi-sdk/bin/clang + AR_wasm32_wasip1: /opt/wasi-sdk/bin/llvm-ar + CFLAGS_wasm32_wasip1: "--sysroot=/opt/wasi-sdk/share/wasi-sysroot" test_mime_db: name: Test with MIME database From d54b5a0e457bbedca0ba7ac515ec6ff8e32bf9a6 Mon Sep 17 00:00:00 2001 From: Master-Hash Date: Wed, 26 Nov 2025 03:04:06 +0800 Subject: [PATCH 3/3] Revert "ci: enable test for wasm-wasip1 target" This reverts commit 5280af31cfad20695ebe65155e113c74011cee93. --- .cargo/config.toml | 1 - .github/workflows/test.yml | 16 ---------------- 2 files changed, 17 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 4ddecc1c2c..529fe26067 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -4,4 +4,3 @@ rustflags = [ "-Clink-arg=-lc++", "-Clink-arg=-lc++abi" ] -runner = "wasmtime run" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2f82188507..497926abea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,6 @@ jobs: - { target: aarch64-pc-windows-msvc, os: windows-11-arm } - { target: aarch64-unknown-linux-gnu, os: ubuntu-22.04, use-cross: true } - - { target: wasm32-wasip1, os: ubuntu-24.04 } # mac-14 is an M1 ARM device. - { target: aarch64-apple-darwin, os: macos-14 } @@ -36,7 +35,6 @@ jobs: uses: dtolnay/rust-toolchain@1.76.0 with: targets: ${{ matrix.job.target }} - if: ${{ matrix.job.target != 'wasm32-wasip1' }} - name: Install cross if: matrix.job.use-cross @@ -44,14 +42,6 @@ jobs: with: tool: cross@0.2.5 - - if: ${{ matrix.job.target == 'wasm32-wasip1' }} - run: | - wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-29/wasi-sdk-29.0-x86_64-linux.deb - sudo apt-get install ./wasi-sdk-29.0-x86_64-linux.deb - rm ./wasi-sdk-29.0-x86_64-linux.deb - rustup override set stable - rustup target add wasm32-wasip1 - - name: Overwrite build command env variable if: matrix.job.use-cross shell: bash @@ -60,12 +50,6 @@ jobs: - name: Test shell: bash run: $BUILD_CMD $SUBCOMMAND --target ${{ matrix.job.target }} - env: - WASI_SDK_PATH: /opt/wasi-sdk - WASI_SYSROOT: /opt/wasi-sdk/share/wasi-sysroot - CC_wasm32_wasip1: /opt/wasi-sdk/bin/clang - AR_wasm32_wasip1: /opt/wasi-sdk/bin/llvm-ar - CFLAGS_wasm32_wasip1: "--sysroot=/opt/wasi-sdk/share/wasi-sysroot" test_mime_db: name: Test with MIME database