Skip to content

Commit

Permalink
fix: Handle quoted alias names
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelarie committed Oct 10, 2024
1 parent b9fedb8 commit cec13ab
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use syntax_tree::find_aliases;
use tree_sitter::Parser;

fn main() {
const TEST_FILE_PATH: &str = "./src/test/examples/bash_aliases";
const TEST_FILE_PATH: &str = "./src/test/examples/special_chars_bash_alias";
let code = fs::read_to_string(TEST_FILE_PATH).expect("Error reading file");

let mut parser = Parser::new();
Expand Down
69 changes: 51 additions & 18 deletions src/syntax_tree/alias.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
// Unquote a string (remove the quotes if it has)
// 'foo' -> foo
// "foo" -> foo
// foo -> foo
// "\'foo\'" -> 'foo'
use crate::syntax_tree::printer;

use super::print_tree;

/// Unquote a string (remove the quotes if it has)
// https://www.gnu.org/software/bash/manual/html_node/Quoting.html
/// Examples:
/// unquote_string("foo") -> foo
/// unquote_string("'foo'") -> foo
/// unquote_string("\"foo\"") -> foo
/// unquote_string("foo'") -> foo'
// TODO: Add tests
fn unquote_string(string: &str) -> String {
if string.len() < 2 {
return string.to_string();
}

let has_single_quotes = string.starts_with('\'') && string.ends_with('\'');
let has_double_quotes = string.starts_with('"') && string.ends_with('"');

Expand All @@ -15,6 +25,7 @@ fn unquote_string(string: &str) -> String {
}
}

/// Represents the possible errors that can occur when extracting an alias
enum AliasError {
MissingCommandName,
MissingAliasName,
Expand All @@ -23,44 +34,64 @@ enum AliasError {
InvalidUtf8Text,
}

// https://www.gnu.org/software/bash/manual/html_node/Quoting.html
// TODO: Handle each error of this function with a enum (AliasError)
// return: -> Result<(String, String), AliasError> {
fn extract_alias(
node: tree_sitter::Node,
source: &[u8],
) -> Result<(String, String), AliasError> {
let mut cursor = node.walk();

// Find the command_name node
if !cursor.goto_first_child() || cursor.node().kind() != "command_name" {
return Err(AliasError::MissingCommandName);
}

// Check if it's an alias command
let command_name = cursor.node().utf8_text(source).unwrap();
if command_name != "alias" {
return Err(AliasError::MissingAliasName);
}

// Go to the argument node
if !cursor.goto_next_sibling() {
return Err(AliasError::MissingArguments);
}

let node = cursor.node();

if node.child_count() != 2 {
if node.child_count() > 3 {
return Err(AliasError::InvalidArgumentCount);
}

cursor.goto_first_child();

let alias_name_node = cursor.node();
let alias_name = alias_name_node
.utf8_text(source)
.unwrap()
.trim_end_matches('=');
let alias_name = match cursor.node().kind() {
"string" => {
if !cursor.goto_first_child() {
return Err(AliasError::MissingAliasName);
}
if !cursor.goto_next_sibling() {
return Err(AliasError::MissingAliasName);
}

let string_node = cursor.node();

cursor.goto_parent();
cursor.goto_next_sibling();

// Attempt to extract the text content from the string node
match string_node.utf8_text(source) {
Ok(alias_content) => Ok(alias_content.to_string()),
Err(_) => Err(AliasError::InvalidUtf8Text),
}
}
"word" => {
// Extract the alias name from the word node and trim '=' at the end
match cursor.node().utf8_text(source) {
Ok(alias_content) => {
Ok(alias_content.trim_end_matches('=').to_string())
}
Err(_) => Err(AliasError::InvalidUtf8Text),
}
}
_ => Err(AliasError::MissingCommandName),
}?;

cursor.goto_next_sibling();

Expand All @@ -71,7 +102,9 @@ fn extract_alias(

let unquoted_alias_content = unquote_string(alias_content);

Ok((alias_name.to_string(), unquoted_alias_content))
// println!("alias_content: {}", alias_content);

Ok((alias_name, unquoted_alias_content))
}

pub fn find_aliases(
Expand Down
3 changes: 2 additions & 1 deletion src/test/examples/bash_aliases
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ shopt -s expand_aliases
# Simple aliases
alias ls='ls --color=auto'
alias ll='ls -l'
alias "abc!"='echo String with special characters'
alias la= 'ls -A' # This alias is invalid and should be ignored
alias gitlog='git log --graph --oneline --decorate --all'

# Cases like this are handled by the parser but it's good to have a test for it
# Cases like this are not handled yet by the Parser
my_function() {
alias greet='echo Hello, World!'
}

0 comments on commit cec13ab

Please sign in to comment.