Skip to content

Commit d8cf9f9

Browse files
horochxlucasfernog
andauthored
Command support for specified character encoding, closes #4644 (#4772)
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
1 parent 433dafa commit d8cf9f9

File tree

9 files changed

+57
-10
lines changed

9 files changed

+57
-10
lines changed

.changes/shell-encoding-api.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"api": minor
3+
---
4+
5+
Added the `encoding` option to the `Command` options.

.changes/shell-encoding.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": minor
3+
---
4+
5+
Add `api::Command::encoding` method to set the stdout/stderr encoding.

core/tauri/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ serialize-to-javascript = "=0.1.1"
9393
infer = { version = "0.8", optional = true }
9494
png = { version = "0.17", optional = true }
9595
ico = { version = "0.1", optional = true }
96+
encoding_rs = "0.8.31"
9697

9798
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
9899
gtk = { version = "0.15", features = [ "v3_20" ] }

core/tauri/scripts/bundle.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/tauri/src/api/process/command.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use std::os::windows::process::CommandExt;
2020
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
2121

2222
use crate::async_runtime::{block_on as block_on_task, channel, Receiver, Sender};
23+
pub use encoding_rs::Encoding;
2324
use os_pipe::{pipe, PipeReader, PipeWriter};
2425
use serde::Serialize;
2526
use shared_child::SharedChild;
@@ -95,6 +96,7 @@ pub struct Command {
9596
env_clear: bool,
9697
env: HashMap<String, String>,
9798
current_dir: Option<PathBuf>,
99+
encoding: Option<&'static Encoding>,
98100
}
99101

100102
/// Spawned child process.
@@ -171,6 +173,7 @@ impl Command {
171173
env_clear: false,
172174
env: Default::default(),
173175
current_dir: None,
176+
encoding: None,
174177
}
175178
}
176179

@@ -216,6 +219,13 @@ impl Command {
216219
self
217220
}
218221

222+
/// Sets the character encoding for stdout/stderr.
223+
#[must_use]
224+
pub fn encoding(mut self, encoding: &'static Encoding) -> Self {
225+
self.encoding.replace(encoding);
226+
self
227+
}
228+
219229
/// Spawns the command.
220230
///
221231
/// # Examples
@@ -264,12 +274,14 @@ impl Command {
264274
guard.clone(),
265275
stdout_reader,
266276
CommandEvent::Stdout,
277+
self.encoding,
267278
);
268279
spawn_pipe_reader(
269280
tx.clone(),
270281
guard.clone(),
271282
stderr_reader,
272283
CommandEvent::Stderr,
284+
self.encoding,
273285
);
274286

275287
spawn(move || {
@@ -378,6 +390,7 @@ fn spawn_pipe_reader<F: Fn(String) -> CommandEvent + Send + Copy + 'static>(
378390
guard: Arc<RwLock<()>>,
379391
pipe_reader: PipeReader,
380392
wrapper: F,
393+
character_encoding: Option<&'static Encoding>,
381394
) {
382395
spawn(move || {
383396
let _lock = guard.read().unwrap();
@@ -392,7 +405,10 @@ fn spawn_pipe_reader<F: Fn(String) -> CommandEvent + Send + Copy + 'static>(
392405
break;
393406
}
394407
let tx_ = tx.clone();
395-
let line = String::from_utf8(buf.clone());
408+
let line = match character_encoding {
409+
Some(encoding) => Ok(encoding.decode_with_bom_removal(&buf).0.into()),
410+
None => String::from_utf8(buf.clone()),
411+
};
396412
block_on_task(async move {
397413
let _ = match line {
398414
Ok(line) => tx_.send(wrapper(line)).await,

core/tauri/src/endpoints/shell.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ pub struct CommandOptions {
5454
// but the env is an `Option` so when it's `None` we clear the env.
5555
#[serde(default = "default_env")]
5656
env: Option<HashMap<String, String>>,
57+
// Character encoding for stdout/stderr
58+
encoding: Option<String>,
5759
}
5860

5961
/// The API descriptor.
@@ -148,6 +150,13 @@ impl Cmd {
148150
} else {
149151
command = command.env_clear();
150152
}
153+
if let Some(encoding) = options.encoding {
154+
if let Some(encoding) = crate::api::process::Encoding::for_label(encoding.as_bytes()) {
155+
command = command.encoding(encoding);
156+
} else {
157+
return Err(anyhow::anyhow!(format!("unknown encoding {}", encoding)));
158+
}
159+
}
151160
let (mut rx, child) = command.spawn()?;
152161

153162
let pid = child.pid();
@@ -229,6 +238,7 @@ mod tests {
229238
sidecar: false,
230239
cwd: Option::arbitrary(g),
231240
env: Option::arbitrary(g),
241+
encoding: Option::arbitrary(g),
232242
}
233243
}
234244
}

examples/api/src-tauri/Cargo.lock

Lines changed: 8 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/api/src/views/Shell.svelte

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script>
22
import { Command } from '@tauri-apps/api/shell'
3+
34
const windows = navigator.userAgent.includes('Windows')
45
let cmd = windows ? 'cmd' : 'sh'
56
let args = windows ? ['/C'] : ['-c']
@@ -9,6 +10,7 @@
910
let script = 'echo "hello world"'
1011
let cwd = null
1112
let env = 'SOMETHING=value ANOTHER=2'
13+
let encoding = ''
1214
let stdin = ''
1315
let child
1416
@@ -26,7 +28,8 @@
2628
child = null
2729
const command = new Command(cmd, [...args, script], {
2830
cwd: cwd || null,
29-
env: _getEnv()
31+
env: _getEnv(),
32+
encoding,
3033
})
3134
3235
command.on('close', (data) => {
@@ -65,6 +68,10 @@
6568
Script:
6669
<input class="grow input" bind:value={script} />
6770
</div>
71+
<div class="flex items-center gap-1">
72+
Encoding:
73+
<input class="grow input" bind:value={encoding} />
74+
</div>
6875
<div class="flex items-center gap-1">
6976
Working directory:
7077
<input

tooling/api/src/shell.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ interface SpawnOptions {
8383
cwd?: string
8484
/** Environment variables. set to `null` to clear the process env. */
8585
env?: { [name: string]: string }
86+
/** Character encoding for stdout/stderr */
87+
encoding?: string
8688
}
8789

8890
/** @ignore */

0 commit comments

Comments
 (0)