Skip to content

Commit

Permalink
feat: add shellExec and shellSpawn for running shell commands (#160)
Browse files Browse the repository at this point in the history
  • Loading branch information
lars-berger authored Jan 27, 2025
1 parent bad20ce commit df23221
Show file tree
Hide file tree
Showing 33 changed files with 2,553 additions and 818 deletions.
1,831 changes: 1,045 additions & 786 deletions Cargo.lock

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
[workspace]
resolver = "2"
members = ["packages/desktop"]
members = ["packages/desktop", "crates/*"]

[workspace.dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["raw_value"] }
tokio = { version = "1", features = ["full"] }
tracing = "0.1"
thiserror = "2"
18 changes: 18 additions & 0 deletions crates/shell-util/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "shell-util"
version = "0.0.0"
authors = ["you"]
license = ""
repository = ""
edition = "2021"

[dependencies]
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
thiserror = { workspace = true }
shared_child = "1"
regex = "1"
encoding_rs = "0.8"
os_pipe = "1"
62 changes: 62 additions & 0 deletions crates/shell-util/src/encoding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use serde::{Deserialize, Serialize};

use crate::shell::Buffer;

#[derive(Debug, Clone, Deserialize, Eq, PartialEq, Serialize)]
pub enum Encoding {
#[serde(rename = "raw")]
Raw,
#[serde(rename = "utf-8")]
Utf8,
#[serde(rename = "utf-16")]
Utf16,
#[serde(rename = "gbk")]
Gbk,
#[serde(rename = "gb18030")]
Gb18030,
#[serde(rename = "big5")]
Big5,
#[serde(rename = "euc-jp")]
EucJp,
#[serde(rename = "euc-kr")]
EucKr,
#[serde(rename = "iso-2022-jp")]
Iso2022Jp,
#[serde(rename = "shift-jis")]
ShiftJis,
}

impl Encoding {
pub fn decode(&self, line: Vec<u8>) -> Buffer {
match <&Encoding as TryInto<&'static encoding_rs::Encoding>>::try_into(
self,
) {
Ok(encoding) => {
let encoding = encoding.decode_with_bom_removal(&line).0;
Buffer::Text(encoding.into())
}
Err(_) => Buffer::Raw(line),
}
}
}

impl TryInto<&'static encoding_rs::Encoding> for &Encoding {
type Error = ();

fn try_into(
self,
) -> Result<&'static encoding_rs::Encoding, Self::Error> {
match self {
Encoding::Raw => Err(()),
Encoding::Utf8 => Ok(encoding_rs::UTF_8),
Encoding::Gbk => Ok(encoding_rs::GBK),
Encoding::Gb18030 => Ok(encoding_rs::GB18030),
Encoding::Big5 => Ok(encoding_rs::BIG5),
Encoding::EucJp => Ok(encoding_rs::EUC_JP),
Encoding::Iso2022Jp => Ok(encoding_rs::ISO_2022_JP),
Encoding::ShiftJis => Ok(encoding_rs::SHIFT_JIS),
Encoding::EucKr => Ok(encoding_rs::EUC_KR),
Encoding::Utf16 => Ok(encoding_rs::UTF_16LE),
}
}
}
22 changes: 22 additions & 0 deletions crates/shell-util/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use serde::{Serialize, Serializer};

#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
Io(#[from] std::io::Error),

#[error("Invalid buffer")]
InvalidBuffer,
}

impl Serialize for Error {
fn serialize<S>(
&self,
serializer: S,
) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
15 changes: 15 additions & 0 deletions crates/shell-util/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#![feature(slice_internals)]

mod encoding;
mod error;
mod options;
mod shell;
mod stdout_reader;

pub use encoding::*;
pub use error::*;
pub use options::*;
pub use shell::*;
pub(crate) use stdout_reader::*;

pub type Result<T> = std::result::Result<T, Error>;
30 changes: 30 additions & 0 deletions crates/shell-util/src/options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use std::{collections::HashMap, path::PathBuf};

use serde::{Deserialize, Serialize};

use crate::encoding::Encoding;

#[derive(Debug, Clone, Deserialize, Eq, PartialEq, Serialize)]
#[serde(default, rename_all = "camelCase")]
pub struct CommandOptions {
pub cwd: Option<PathBuf>,

pub env: HashMap<String, String>,

/// Clear the environment variables of the spawned process.
pub clear_env: bool,

/// Character encoding for stdout/stderr.
pub encoding: Encoding,
}

impl Default for CommandOptions {
fn default() -> Self {
Self {
cwd: None,
env: HashMap::default(),
clear_env: false,
encoding: Encoding::Utf8,
}
}
}
Loading

0 comments on commit df23221

Please sign in to comment.