You have read the Exercise text first?
Preventing an alias with the same name as a built-in command is easy. All we have to do is change «do-alias»:
File: rash-safe (changes only)
multi sub do-alias ($command)
{
my ($alias, $full) = $command.split(/\s/, 2);
if %commands{$alias}
{
say "Unable to redefine internal command: $alias.";
}
else
{
%aliases{$alias} = $full;
}
}
The complete program:
File: rash-safe
use Linenoise;
constant HIST_FILE = ( $*HOME.add: '.rash-hist' ).Str;
constant HIST_LEN = 25;
constant CONF_FILE = ( $*HOME.add: '.rashrc' ).Str;
linenoiseHistoryLoad(HIST_FILE);
linenoiseHistorySetMaxLen(HIST_LEN);
my %commands; %commands{$_} = True for <alias cd exit help pwd rehash version which6>;
my %programs;
my %aliases;
read-conf;
do-rehash;
linenoiseSetCompletionCallback(-> $line, $c
{
my @all = (|%commands.keys, |%programs.keys, |%aliases.keys);
for @all.grep(/^ $line /).sort -> $cmd
{
linenoiseAddCompletion($c, $cmd);
}
});
say 'rash: Enter «exit» to exit';
signal(SIGINT).tap();
while (my $line = linenoise '> ').defined
{
linenoiseHistoryAdd($line);
my $cmd = $line.words[0];
$line.= subst(/^$cmd/, %aliases{$cmd}) if %aliases{$cmd};
given $line
{
when "alias" { do-alias; }
when /^alias\s+(.*)/ { do-alias $0; }
when /^cd\s+(\S+)/ { do-chdir $0; }
when "exit" { last; }
when "help" { say "Built-in commands: { %commands.keys.sort }" }
when "pwd" { say $*CWD.Str; }
when "rehash" { %programs = (); do-rehash; }
when "version" { say "Version 0.18"; }
when /^which6\s+(\S+)/ { do-which $0; }
default
{
my ($cmd, @args) = $line.words;
%programs{$cmd}
?? do-run %programs{$cmd}, @args
!! say "Unknown command: \"$_\" (use \"help\" for a list of commands)";
}
}
}
linenoiseHistorySave(HIST_FILE);
sub do-run ($cmd, @args)
{
my $res = @args
?? run $cmd, @args
!! run $cmd;
if ! $res.pid
{
say "$cmd: command not found";
}
elsif $res.exitcode
{
say "$cmd: exit with code { $res.exitcode }";
}
}
sub do-chdir ($dir)
{
say "cd: $dir: No such file or directory" unless chdir $dir;
}
sub do-rehash
{
for %*ENV.split(":") -> $dir
{
next unless $dir.IO.d;
%programs{.Str} = "$dir/" ~ .Str for indir($dir, { dir(:x) }).sort
}
}
sub do-which ($command)
{
if %commands{$command}
{
say "$command is a rash built-in command.";
}
else
{
say %programs{$command} if %programs{$command};
}
}
multi sub do-alias ($command)
{
my ($alias, $full) = $command.split(/\s/, 2);
if %commands{$alias}
{
say "Unable to redefine internal command: $alias.";
}
else
{
%aliases{$alias} = $full;
}
}
multi sub do-alias ()
{
say "$_ -> %aliases{$_}" for %aliases.keys.sort;
}
sub read-conf
{
return unless CONF_FILE.IO.r;
for CONF_FILE.IO.lines
{
when /^alias\s+(.*)/ { do-alias $0.Str }
}
}