From 2927b538c6294c4f4403909e84944513df4a5764 Mon Sep 17 00:00:00 2001
From: prsabahrami
Date: Sun, 8 Sep 2024 11:44:31 -0400
Subject: [PATCH 1/6] Inital implementation for Tilde expansion
---
crates/deno_task_shell/src/grammar.pest | 23 +++++++-
crates/deno_task_shell/src/parser.rs | 63 ++++++++++++++++++++-
crates/deno_task_shell/src/shell/execute.rs | 4 ++
scripts/tilde_expansion.sh | 7 +++
4 files changed, 92 insertions(+), 5 deletions(-)
create mode 100644 scripts/tilde_expansion.sh
diff --git a/crates/deno_task_shell/src/grammar.pest b/crates/deno_task_shell/src/grammar.pest
index 0b270ee..a3d710b 100644
--- a/crates/deno_task_shell/src/grammar.pest
+++ b/crates/deno_task_shell/src/grammar.pest
@@ -7,17 +7,28 @@ COMMENT = _{ "#" ~ (!NEWLINE ~ ANY)* }
// Basic tokens
QUOTED_WORD = { DOUBLE_QUOTED | SINGLE_QUOTED }
-UNQUOTED_PENDING_WORD = ${ !OPERATOR ~
- (!(WHITESPACE | NEWLINE) ~ (
+UNQUOTED_PENDING_WORD = ${
+ (!(OPERATOR | WHITESPACE | NEWLINE) ~ (
EXIT_STATUS |
UNQUOTED_ESCAPE_CHAR |
SUB_COMMAND |
("$" ~ "{" ~ VARIABLE ~ "}" | "$" ~ VARIABLE) |
+ TILDE_PREFIX |
UNQUOTED_CHAR |
QUOTED_WORD
)
)+ }
+TILDE_PREFIX = ${
+ "~" ~ (!(OPERATOR | WHITESPACE | NEWLINE | "/") ~ (
+ QUOTED_CHAR
+ ))*
+}
+
+ASSIGNMENT_TILDE_PREFIX = ${
+ "~" ~ (!(OPERATOR | WHITESPACE | NEWLINE | "/" | ":") ~ ANY)*
+}
+
FILE_NAME_PENDING_WORD = ${ (!(WHITESPACE | OPERATOR | NEWLINE) ~ (UNQUOTED_ESCAPE_CHAR | ("$" ~ VARIABLE) | UNQUOTED_CHAR | QUOTED_WORD))+ }
QUOTED_PENDING_WORD = ${ (
@@ -41,7 +52,12 @@ DOUBLE_QUOTED = @{ "\"" ~ QUOTED_PENDING_WORD ~ "\"" }
SINGLE_QUOTED = @{ "'" ~ (!"'" ~ ANY)* ~ "'" }
NAME = ${ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
-ASSIGNMENT_WORD = { NAME ~ "=" ~ UNQUOTED_PENDING_WORD? }
+ASSIGNMENT_WORD = { NAME ~ "=" ~ ASSIGNMENT_VALUE? }
+ASSIGNMENT_VALUE = ${
+ ASSIGNMENT_TILDE_PREFIX ~
+ ((":" ~ ASSIGNMENT_TILDE_PREFIX) | (!":" ~ UNQUOTED_PENDING_WORD))* |
+ UNQUOTED_PENDING_WORD
+}
IO_NUMBER = @{ ASCII_DIGIT+ }
// Special tokens
@@ -59,6 +75,7 @@ DLESSDASH = { "<<-" }
CLOBBER = { ">|" }
AMPERSAND = { "&" }
EXIT_STATUS = ${ "$?" }
+TILDE = ${ "~" }
// Operators
diff --git a/crates/deno_task_shell/src/parser.rs b/crates/deno_task_shell/src/parser.rs
index 61bd0a6..a2a9899 100644
--- a/crates/deno_task_shell/src/parser.rs
+++ b/crates/deno_task_shell/src/parser.rs
@@ -1,6 +1,6 @@
// Copyright 2018-2024 the Deno authors. MIT license.
-use anyhow::{anyhow, Result};
+use anyhow::{anyhow, Result, Context};
use pest::iterators::Pair;
use pest::Parser;
use pest_derive::Parser;
@@ -214,6 +214,23 @@ impl EnvVar {
}
}
+#[cfg_attr(feature = "serialization", derive(serde::Serialize))]
+#[cfg_attr(feature = "serialization", serde(rename_all = "camelCase"))]
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct TildePrefix {
+ pub user: Option,
+}
+
+impl TildePrefix {
+ pub fn only_tilde(self) -> bool {
+ self.user.is_none()
+ }
+
+ pub fn new(user: Option) -> Self {
+ TildePrefix { user }
+ }
+}
+
#[cfg_attr(feature = "serialization", derive(serde::Serialize))]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Word(Vec);
@@ -261,6 +278,8 @@ pub enum WordPart {
Command(SequentialList),
/// Quoted string (ex. `"hello"` or `'test'`)
Quoted(Vec),
+ /// Tilde prefix (ex. `~user/path`)
+ Tilde(TildePrefix),
}
#[cfg_attr(feature = "serialization", derive(serde::Serialize))]
@@ -730,6 +749,10 @@ fn parse_word(pair: Pair) -> Result {
let quoted = parse_quoted_word(part)?;
parts.push(quoted);
}
+ Rule::TILDE_PREFIX => {
+ let tilde_prefix = parse_tilde_prefix(part)?;
+ parts.push(tilde_prefix);
+ }
_ => {
return Err(anyhow::anyhow!(
"Unexpected rule in UNQUOTED_PENDING_WORD: {:?}",
@@ -795,6 +818,17 @@ fn parse_word(pair: Pair) -> Result {
}
}
+fn parse_tilde_prefix(pair: Pair) -> Result {
+ let tilde_prefix_str = pair.as_str();
+ let user = if tilde_prefix_str.len() > 1 {
+ Some(tilde_prefix_str[1..].to_string())
+ } else {
+ None
+ };
+ let tilde_prefix = TildePrefix::new(user);
+ Ok(WordPart::Tilde(tilde_prefix))
+}
+
fn parse_quoted_word(pair: Pair) -> Result {
let mut parts = Vec::new();
let inner = pair.into_inner().next().unwrap();
@@ -863,7 +897,7 @@ fn parse_env_var(pair: Pair) -> Result {
// Get the value of the environment variable
let word_value = if let Some(value) = parts.next() {
- parse_word(value)?
+ parse_assignment_value(value).context("Failed to parse assignment value")?
} else {
Word::new_empty()
};
@@ -874,6 +908,31 @@ fn parse_env_var(pair: Pair) -> Result {
})
}
+fn parse_assignment_value(pair: Pair) -> Result {
+ let mut parts = Vec::new();
+
+ for part in pair.into_inner() {
+ match part.as_rule() {
+ Rule::ASSIGNMENT_TILDE_PREFIX => {
+ let tilde_prefix = parse_tilde_prefix(part).context("Failed to parse tilde prefix")?;
+ parts.push(tilde_prefix);
+ }
+ Rule::UNQUOTED_PENDING_WORD => {
+ let word_parts = parse_word(part)?;
+ parts.extend(word_parts.into_parts());
+ }
+ _ => {
+ return Err(anyhow::anyhow!(
+ "Unexpected rule in assignment value: {:?}",
+ part.as_rule()
+ ))
+ }
+ }
+ }
+
+ Ok(Word::new(parts))
+}
+
fn parse_io_redirect(pair: Pair) -> Result {
let mut inner = pair.into_inner();
diff --git a/crates/deno_task_shell/src/shell/execute.rs b/crates/deno_task_shell/src/shell/execute.rs
index cd988ef..45e148e 100644
--- a/crates/deno_task_shell/src/shell/execute.rs
+++ b/crates/deno_task_shell/src/shell/execute.rs
@@ -895,6 +895,10 @@ fn evaluate_word_parts(
current_text.push(TextPart::Quoted(text));
continue;
+ },
+ WordPart::Tilde(tilde_prefix) => {
+ current_text.push(TextPart::Text(tilde_prefix));
+ continue;
}
};
diff --git a/scripts/tilde_expansion.sh b/scripts/tilde_expansion.sh
new file mode 100644
index 0000000..155cb69
--- /dev/null
+++ b/scripts/tilde_expansion.sh
@@ -0,0 +1,7 @@
+ls ~/Desktop
+
+echo ~$var
+
+echo ~\/bin
+
+echo ~parsabahraminejad/Desktop
From 9224afbc2d118e15ee5a9a81c8b9436d53651d55 Mon Sep 17 00:00:00 2001
From: prsabahrami
Date: Sun, 8 Sep 2024 11:52:13 -0400
Subject: [PATCH 2/6] Added support for single ~
---
crates/deno_task_shell/src/shell/execute.rs | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/crates/deno_task_shell/src/shell/execute.rs b/crates/deno_task_shell/src/shell/execute.rs
index 45e148e..9dbf952 100644
--- a/crates/deno_task_shell/src/shell/execute.rs
+++ b/crates/deno_task_shell/src/shell/execute.rs
@@ -4,6 +4,7 @@ use std::collections::HashMap;
use std::path::Path;
use std::rc::Rc;
+use anyhow::Context;
use futures::future;
use futures::future::LocalBoxFuture;
use futures::FutureExt;
@@ -729,6 +730,8 @@ pub enum EvaluateWordTextError {
},
#[error("glob: no matches found '{}'", pattern)]
NoFilesMatched { pattern: String },
+ #[error("Failed to get home directory")]
+ FailedToGetHomeDirectory(anyhow::Error),
}
impl EvaluateWordTextError {
@@ -738,6 +741,12 @@ impl EvaluateWordTextError {
}
}
+impl From for EvaluateWordTextError {
+ fn from(err: anyhow::Error) -> Self {
+ Self::FailedToGetHomeDirectory(err)
+ }
+}
+
fn evaluate_word_parts(
parts: Vec,
state: &ShellState,
@@ -897,7 +906,12 @@ fn evaluate_word_parts(
continue;
},
WordPart::Tilde(tilde_prefix) => {
- current_text.push(TextPart::Text(tilde_prefix));
+ if tilde_prefix.only_tilde() {
+ let home_str = dirs::home_dir().context("Failed to get home directory")?.display().to_string();
+ current_text.push(TextPart::Text(home_str));
+ } else {
+ todo!("tilde expansion with user name is not supported");
+ }
continue;
}
};
From 6fc25ab4ad92db23d8f96ac689f723d269e9d73d Mon Sep 17 00:00:00 2001
From: prsabahrami
Date: Sun, 8 Sep 2024 11:52:41 -0400
Subject: [PATCH 3/6] run fmt
---
crates/deno_task_shell/src/parser.rs | 43 +++++++++++----------
crates/deno_task_shell/src/shell/execute.rs | 7 +++-
2 files changed, 27 insertions(+), 23 deletions(-)
diff --git a/crates/deno_task_shell/src/parser.rs b/crates/deno_task_shell/src/parser.rs
index a2a9899..3d1922b 100644
--- a/crates/deno_task_shell/src/parser.rs
+++ b/crates/deno_task_shell/src/parser.rs
@@ -1,6 +1,6 @@
// Copyright 2018-2024 the Deno authors. MIT license.
-use anyhow::{anyhow, Result, Context};
+use anyhow::{anyhow, Context, Result};
use pest::iterators::Pair;
use pest::Parser;
use pest_derive::Parser;
@@ -909,28 +909,29 @@ fn parse_env_var(pair: Pair) -> Result {
}
fn parse_assignment_value(pair: Pair) -> Result {
- let mut parts = Vec::new();
-
- for part in pair.into_inner() {
- match part.as_rule() {
- Rule::ASSIGNMENT_TILDE_PREFIX => {
- let tilde_prefix = parse_tilde_prefix(part).context("Failed to parse tilde prefix")?;
- parts.push(tilde_prefix);
- }
- Rule::UNQUOTED_PENDING_WORD => {
- let word_parts = parse_word(part)?;
- parts.extend(word_parts.into_parts());
- }
- _ => {
- return Err(anyhow::anyhow!(
- "Unexpected rule in assignment value: {:?}",
- part.as_rule()
- ))
- }
- }
+ let mut parts = Vec::new();
+
+ for part in pair.into_inner() {
+ match part.as_rule() {
+ Rule::ASSIGNMENT_TILDE_PREFIX => {
+ let tilde_prefix =
+ parse_tilde_prefix(part).context("Failed to parse tilde prefix")?;
+ parts.push(tilde_prefix);
+ }
+ Rule::UNQUOTED_PENDING_WORD => {
+ let word_parts = parse_word(part)?;
+ parts.extend(word_parts.into_parts());
+ }
+ _ => {
+ return Err(anyhow::anyhow!(
+ "Unexpected rule in assignment value: {:?}",
+ part.as_rule()
+ ))
+ }
}
+ }
- Ok(Word::new(parts))
+ Ok(Word::new(parts))
}
fn parse_io_redirect(pair: Pair) -> Result {
diff --git a/crates/deno_task_shell/src/shell/execute.rs b/crates/deno_task_shell/src/shell/execute.rs
index 9dbf952..62daa5d 100644
--- a/crates/deno_task_shell/src/shell/execute.rs
+++ b/crates/deno_task_shell/src/shell/execute.rs
@@ -904,10 +904,13 @@ fn evaluate_word_parts(
current_text.push(TextPart::Quoted(text));
continue;
- },
+ }
WordPart::Tilde(tilde_prefix) => {
if tilde_prefix.only_tilde() {
- let home_str = dirs::home_dir().context("Failed to get home directory")?.display().to_string();
+ let home_str = dirs::home_dir()
+ .context("Failed to get home directory")?
+ .display()
+ .to_string();
current_text.push(TextPart::Text(home_str));
} else {
todo!("tilde expansion with user name is not supported");
From c20d2e393039ac767c4e414ec52b0a7717a854ba Mon Sep 17 00:00:00 2001
From: prsabahrami
Date: Sun, 8 Sep 2024 12:04:37 -0400
Subject: [PATCH 4/6] small fix
---
crates/deno_task_shell/src/grammar.pest | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/crates/deno_task_shell/src/grammar.pest b/crates/deno_task_shell/src/grammar.pest
index a3d710b..ae4f95a 100644
--- a/crates/deno_task_shell/src/grammar.pest
+++ b/crates/deno_task_shell/src/grammar.pest
@@ -21,12 +21,14 @@ UNQUOTED_PENDING_WORD = ${
TILDE_PREFIX = ${
"~" ~ (!(OPERATOR | WHITESPACE | NEWLINE | "/") ~ (
- QUOTED_CHAR
+ (!("\"" | "'" | "$" | "\\" | "/") ~ ANY)
))*
}
ASSIGNMENT_TILDE_PREFIX = ${
- "~" ~ (!(OPERATOR | WHITESPACE | NEWLINE | "/" | ":") ~ ANY)*
+ "~" ~ (!(OPERATOR | WHITESPACE | NEWLINE | "/" | ":") ~
+ (!("\"" | "'" | "$" | "\\" | "/") ~ ANY)
+ )*
}
FILE_NAME_PENDING_WORD = ${ (!(WHITESPACE | OPERATOR | NEWLINE) ~ (UNQUOTED_ESCAPE_CHAR | ("$" ~ VARIABLE) | UNQUOTED_CHAR | QUOTED_WORD))+ }
From 8c28dd9125c527dfca6807ee1b9524d4792dbff1 Mon Sep 17 00:00:00 2001
From: prsabahrami
Date: Sun, 8 Sep 2024 12:10:02 -0400
Subject: [PATCH 5/6] Fixed parsing issue on echo a~b
---
crates/deno_task_shell/src/grammar.pest | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/crates/deno_task_shell/src/grammar.pest b/crates/deno_task_shell/src/grammar.pest
index ae4f95a..8909557 100644
--- a/crates/deno_task_shell/src/grammar.pest
+++ b/crates/deno_task_shell/src/grammar.pest
@@ -8,16 +8,24 @@ COMMENT = _{ "#" ~ (!NEWLINE ~ ANY)* }
QUOTED_WORD = { DOUBLE_QUOTED | SINGLE_QUOTED }
UNQUOTED_PENDING_WORD = ${
+ (TILDE_PREFIX ~ (!(OPERATOR | WHITESPACE | NEWLINE) ~ (
+ EXIT_STATUS |
+ UNQUOTED_ESCAPE_CHAR |
+ SUB_COMMAND |
+ ("$" ~ "{" ~ VARIABLE ~ "}" | "$" ~ VARIABLE) |
+ UNQUOTED_CHAR |
+ QUOTED_WORD
+ ))*)
+ |
(!(OPERATOR | WHITESPACE | NEWLINE) ~ (
EXIT_STATUS |
UNQUOTED_ESCAPE_CHAR |
SUB_COMMAND |
("$" ~ "{" ~ VARIABLE ~ "}" | "$" ~ VARIABLE) |
- TILDE_PREFIX |
UNQUOTED_CHAR |
QUOTED_WORD
- )
-)+ }
+ ))+
+}
TILDE_PREFIX = ${
"~" ~ (!(OPERATOR | WHITESPACE | NEWLINE | "/") ~ (
From 18c11a636c63017a1596e97df350045e3483326d Mon Sep 17 00:00:00 2001
From: Parsa Bahraminejad
Date: Sun, 8 Sep 2024 12:26:53 -0400
Subject: [PATCH 6/6] Update parser.rs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Ondřej Čertík
---
crates/deno_task_shell/src/parser.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crates/deno_task_shell/src/parser.rs b/crates/deno_task_shell/src/parser.rs
index 3d1922b..9032f53 100644
--- a/crates/deno_task_shell/src/parser.rs
+++ b/crates/deno_task_shell/src/parser.rs
@@ -278,7 +278,7 @@ pub enum WordPart {
Command(SequentialList),
/// Quoted string (ex. `"hello"` or `'test'`)
Quoted(Vec),
- /// Tilde prefix (ex. `~user/path`)
+ /// Tilde prefix (ex. `~user/path` or `~/bin`)
Tilde(TildePrefix),
}