Skip to content

Alias builtin#44

Open
CraigNewlands wants to merge 1 commit intomainfrom
40-alias-builtin
Open

Alias builtin#44
CraigNewlands wants to merge 1 commit intomainfrom
40-alias-builtin

Conversation

@CraigNewlands
Copy link
Collaborator

No description provided.

@CraigNewlands CraigNewlands linked an issue Jul 25, 2024 that may be closed by this pull request
@CraigNewlands
Copy link
Collaborator Author

works without quotes but will test with quotes and with spaces once we have sported the parser to handle the speech marks
image

@siliconlad
Copy link
Owner

This you might need to revise/force push to fix the merge conflicts too. Other than that (and my other comment) looks good!

Copy link
Owner

@siliconlad siliconlad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rebased this branch so fix the diffs.

@siliconlad siliconlad changed the title 40 alias builtin Alias builtin Jul 29, 2024
@siliconlad
Copy link
Owner

I've merged most of the other PRs so we should be able to revert the temp fix.

@CraigNewlands
Copy link
Collaborator Author

image

Copy link
Owner

@siliconlad siliconlad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, just realized that we probably want to support alias substitution in slightly more complicated scenarios haha 😅

@CraigNewlands
Copy link
Collaborator Author

image

@siliconlad
Copy link
Owner

Should the "Hello world" have double quotes when greet is run?

@CraigNewlands
Copy link
Collaborator Author

Should the "Hello world" have double quotes when greet is run?

It should not hahah, will have a look at that

@CraigNewlands CraigNewlands force-pushed the 40-alias-builtin branch 3 times, most recently from 1efd75c to 31c6bbd Compare September 17, 2024 19:09
@CraigNewlands
Copy link
Collaborator Author

image
After 2 months i think its finally done hahaha

Copy link
Owner

@siliconlad siliconlad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of comments :)

@CraigNewlands CraigNewlands force-pushed the 40-alias-builtin branch 3 times, most recently from f9e5d05 to fe785f4 Compare September 28, 2024 12:14
@CraigNewlands
Copy link
Collaborator Author

Completely changed my approach so now expanding the aliases before they are tokenized. This seems much simpler and means the string is still tokenized properly and we don't need to retokenize in the alias expansion if we did it after the tokenization. Seems to work for all the tests I've done - using piping and recursive aliases etc. What do you think?

@CraigNewlands CraigNewlands force-pushed the 40-alias-builtin branch 2 times, most recently from 363e6f7 to 4c48cc0 Compare September 28, 2024 12:27
@CraigNewlands
Copy link
Collaborator Author

Found a couple more things to fix

@CraigNewlands
Copy link
Collaborator Author

So many edge cases 😂

@siliconlad
Copy link
Owner

I think we should merge #82 so we can add all the edge-cases as tests.

@CraigNewlands
Copy link
Collaborator Author

I think we should merge #82 so we can add all the edge-cases as tests.

Merged, will add some tests now for most of the edge cases I can think of.

@CraigNewlands CraigNewlands force-pushed the 40-alias-builtin branch 2 times, most recently from fcf49f4 to d4a320f Compare September 29, 2024 14:15
@CraigNewlands
Copy link
Collaborator Author

@siliconlad can you think of a way I can get around this problem I'm having...

Currently if we do

> alias greet='echo "Hello, World!"'
> greet
Hello, World!
> alias greet='echo "Hello, World!"' && alias
greet='echo "Hello, World!"'
> alias greet='echo "Hello, World!"' && greet
No such file or directory (os error 2)
> 

the last line doesn't work because expand_aliases is called before we tokenize and then add alias greet='echo "Hello, World!"' to the aliases hashmap, which is done in tokenize.run, so it is not expanded. Can you think of a good way of doing this?

@siliconlad
Copy link
Owner

siliconlad commented Sep 29, 2024

What I might try (in expand_aliases) is the following sequence of steps:

  1. Split string by ;
  2. Split string by &&
  3. Split string by |
  4. Replace the first word of each chunk by an alias if available

Would that work? Maybe you also need to deal with aliases using aliases. Perhaps that's just repeated application of the steps above until you detect no more aliases (might have to detect loops / set maximum alias depth).

@CraigNewlands
Copy link
Collaborator Author

It's not the prettiest code in the world but functionally I think it finally works. Going to try make it a bit nicer to read, especially the expand_aliases function lol

@CraigNewlands CraigNewlands force-pushed the 40-alias-builtin branch 2 times, most recently from 8ffd384 to 4ac43fe Compare October 7, 2024 22:58
@CraigNewlands
Copy link
Collaborator Author

@siliconlad think we're good to go on this PR. Ready for review, hopefully for the final time lol

Copy link
Owner

@siliconlad siliconlad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the main thing is it works.

I left some comments mainly about what bash does and whether we want to behave the same way or not. I think some of it will allow us to cut down on the complexity that alias adds (e.g. in pipe). What do you think?

}
}
} else {
Err("Usage: alias [name[=value] ...]".into())
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the ...?

Comment on lines -129 to +169
fn pipe(&self, stdin: Option<ChildStdout>) -> Result<Option<ChildStdout>, Box<dyn Error>> {
fn pipe(
&self,
stdin: Option<ChildStdout>,
aliases: &mut HashMap<String, String>,
) -> Result<Option<ChildStdout>, Box<dyn Error>> {
let (pipe_out_r, pipe_out_w) = pipe()?;
let (pipe_err_r, pipe_err_w) = pipe()?;
let (alias_r, alias_w) = pipe()?;

match unsafe { fork() }? {
ForkResult::Parent { child: _ } => {
drop(pipe_out_w);
drop(pipe_err_w);
drop(alias_w);

// Read updated aliases from child
let mut alias_reader = unsafe { File::from_raw_fd(alias_r.into_raw_fd()) };
let mut serialized_aliases = String::new();
alias_reader.read_to_string(&mut serialized_aliases)?;
if !serialized_aliases.is_empty() {
*aliases = serde_json::from_str(&serialized_aliases)?;
}

Ok(Some(ChildStdout::from(pipe_out_r)))
}
ForkResult::Child => {
drop(pipe_out_r);
drop(pipe_err_r);
drop(alias_r);

dup2(pipe_out_w.as_raw_fd(), 1)?;
dup2(pipe_err_w.as_raw_fd(), 2)?;
self.run_builtin(stdin)?;
self.run_builtin(stdin, aliases)?;

// Send updated aliases to parent
let serialized_aliases = serde_json::to_string(aliases)?;
let mut alias_writer = unsafe { File::from_raw_fd(alias_w.into_raw_fd()) };
write!(alias_writer, "{}", serialized_aliases)?;

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really cool haha. I'm assuming that this is for this particular scenario:

> alias r='echo' | r Hello
Hello

But this doesn't work in Bash, so we don't necessarily need to support it? Might cut down on the complexity.

Comment on lines +196 to +205
fn handle_alias_definition(temp_aliases: &mut HashMap<String, String>, args: &[String]) {
let full_command = args.join(" ");
if let Some(equals_pos) = full_command.find('=') {
let (alias_name, alias_value) = full_command.split_at(equals_pos);
temp_aliases.insert(
alias_name.to_string(),
alias_value[1..].trim_matches('\'').to_string(),
);
}
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's solving the problem where we have something like alias greet='echo \"Hello, World!\"' && greet because expand tokens gets called before we add greet to the aliases, the second greet after the && doesn't get expanded so this checks if we have an alias on the left of the command and if we do then it expands the right hand side. So basically all handle_alias_definition is doing is getting the alias greet and the expansion of this which is echo "Hello, World!", this is then returned and used in expand_command_aliases to turn the whole command into alias greet='echo \"Hello, World!\"' && alias greet='echo \"Hello, World!\"

Copy link
Collaborator Author

@CraigNewlands CraigNewlands Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could probably be made into one function as we are doing the same thing in the alias buitlin command.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it doesn't hurt to have all these tests, but probably worth having tests that execute aliases (you should be able to use ;).

Comment on lines +211 to +218
while let Some(expansion) = temp_aliases.get(&words[0]) {
let expanded_words: Vec<String> = expansion.split_whitespace().map(String::from).collect();
if expanded_words.is_empty() || expansion_count >= MAX_EXPANSIONS {
break;
}
words.splice(0..1, expanded_words);
expansion_count += 1;
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading the reference manual, they actually don't do recursive expansions.

if parts.len() == 2 {
let alias = parts[0];
let command = parts[1];
aliases.insert(alias.to_string(), command.to_string());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reference manual does not allow special characters in the name. Not sure if we want to enforce that or not :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

alias builtin

2 participants