Skip to content

Commit

Permalink
Command support for specified character encoding, closes #4644 (#4772)
Browse files Browse the repository at this point in the history
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
  • Loading branch information
horochx and lucasfernog committed Jul 27, 2022
1 parent 433dafa commit d8cf9f9
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .changes/shell-encoding-api.md
@@ -0,0 +1,5 @@
---
"api": minor
---

Added the `encoding` option to the `Command` options.
5 changes: 5 additions & 0 deletions .changes/shell-encoding.md
@@ -0,0 +1,5 @@
---
"tauri": minor
---

Add `api::Command::encoding` method to set the stdout/stderr encoding.
1 change: 1 addition & 0 deletions core/tauri/Cargo.toml
Expand Up @@ -93,6 +93,7 @@ serialize-to-javascript = "=0.1.1"
infer = { version = "0.8", optional = true }
png = { version = "0.17", optional = true }
ico = { version = "0.1", optional = true }
encoding_rs = "0.8.31"

[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
gtk = { version = "0.15", features = [ "v3_20" ] }
Expand Down
2 changes: 1 addition & 1 deletion core/tauri/scripts/bundle.js

Large diffs are not rendered by default.

18 changes: 17 additions & 1 deletion core/tauri/src/api/process/command.rs
Expand Up @@ -20,6 +20,7 @@ use std::os::windows::process::CommandExt;
const CREATE_NO_WINDOW: u32 = 0x0800_0000;

use crate::async_runtime::{block_on as block_on_task, channel, Receiver, Sender};
pub use encoding_rs::Encoding;
use os_pipe::{pipe, PipeReader, PipeWriter};
use serde::Serialize;
use shared_child::SharedChild;
Expand Down Expand Up @@ -95,6 +96,7 @@ pub struct Command {
env_clear: bool,
env: HashMap<String, String>,
current_dir: Option<PathBuf>,
encoding: Option<&'static Encoding>,
}

/// Spawned child process.
Expand Down Expand Up @@ -171,6 +173,7 @@ impl Command {
env_clear: false,
env: Default::default(),
current_dir: None,
encoding: None,
}
}

Expand Down Expand Up @@ -216,6 +219,13 @@ impl Command {
self
}

/// Sets the character encoding for stdout/stderr.
#[must_use]
pub fn encoding(mut self, encoding: &'static Encoding) -> Self {
self.encoding.replace(encoding);
self
}

/// Spawns the command.
///
/// # Examples
Expand Down Expand Up @@ -264,12 +274,14 @@ impl Command {
guard.clone(),
stdout_reader,
CommandEvent::Stdout,
self.encoding,
);
spawn_pipe_reader(
tx.clone(),
guard.clone(),
stderr_reader,
CommandEvent::Stderr,
self.encoding,
);

spawn(move || {
Expand Down Expand Up @@ -378,6 +390,7 @@ fn spawn_pipe_reader<F: Fn(String) -> CommandEvent + Send + Copy + 'static>(
guard: Arc<RwLock<()>>,
pipe_reader: PipeReader,
wrapper: F,
character_encoding: Option<&'static Encoding>,
) {
spawn(move || {
let _lock = guard.read().unwrap();
Expand All @@ -392,7 +405,10 @@ fn spawn_pipe_reader<F: Fn(String) -> CommandEvent + Send + Copy + 'static>(
break;
}
let tx_ = tx.clone();
let line = String::from_utf8(buf.clone());
let line = match character_encoding {
Some(encoding) => Ok(encoding.decode_with_bom_removal(&buf).0.into()),
None => String::from_utf8(buf.clone()),
};
block_on_task(async move {
let _ = match line {
Ok(line) => tx_.send(wrapper(line)).await,
Expand Down
10 changes: 10 additions & 0 deletions core/tauri/src/endpoints/shell.rs
Expand Up @@ -54,6 +54,8 @@ pub struct CommandOptions {
// but the env is an `Option` so when it's `None` we clear the env.
#[serde(default = "default_env")]
env: Option<HashMap<String, String>>,
// Character encoding for stdout/stderr
encoding: Option<String>,
}

/// The API descriptor.
Expand Down Expand Up @@ -148,6 +150,13 @@ impl Cmd {
} else {
command = command.env_clear();
}
if let Some(encoding) = options.encoding {
if let Some(encoding) = crate::api::process::Encoding::for_label(encoding.as_bytes()) {
command = command.encoding(encoding);
} else {
return Err(anyhow::anyhow!(format!("unknown encoding {}", encoding)));
}
}
let (mut rx, child) = command.spawn()?;

let pid = child.pid();
Expand Down Expand Up @@ -229,6 +238,7 @@ mod tests {
sidecar: false,
cwd: Option::arbitrary(g),
env: Option::arbitrary(g),
encoding: Option::arbitrary(g),
}
}
}
Expand Down
15 changes: 8 additions & 7 deletions examples/api/src-tauri/Cargo.lock

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

9 changes: 8 additions & 1 deletion examples/api/src/views/Shell.svelte
@@ -1,5 +1,6 @@
<script>
import { Command } from '@tauri-apps/api/shell'
const windows = navigator.userAgent.includes('Windows')
let cmd = windows ? 'cmd' : 'sh'
let args = windows ? ['/C'] : ['-c']
Expand All @@ -9,6 +10,7 @@
let script = 'echo "hello world"'
let cwd = null
let env = 'SOMETHING=value ANOTHER=2'
let encoding = ''
let stdin = ''
let child
Expand All @@ -26,7 +28,8 @@
child = null
const command = new Command(cmd, [...args, script], {
cwd: cwd || null,
env: _getEnv()
env: _getEnv(),
encoding,
})
command.on('close', (data) => {
Expand Down Expand Up @@ -65,6 +68,10 @@
Script:
<input class="grow input" bind:value={script} />
</div>
<div class="flex items-center gap-1">
Encoding:
<input class="grow input" bind:value={encoding} />
</div>
<div class="flex items-center gap-1">
Working directory:
<input
Expand Down
2 changes: 2 additions & 0 deletions tooling/api/src/shell.ts
Expand Up @@ -83,6 +83,8 @@ interface SpawnOptions {
cwd?: string
/** Environment variables. set to `null` to clear the process env. */
env?: { [name: string]: string }
/** Character encoding for stdout/stderr */
encoding?: string
}

/** @ignore */
Expand Down

0 comments on commit d8cf9f9

Please sign in to comment.