-
Notifications
You must be signed in to change notification settings - Fork 37
/
shell.pl
112 lines (93 loc) · 2.85 KB
/
shell.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use v6;
# A simple shell written in Perl6
# TODO
# BACKPSACE, history, editing ?
my $prompt = '<p6shell>$ ';
my $VERSION = '0.01';
# we should have this list from some internal command
# probably along with the signature of these functions
my @available_commands = <exit print say>;
@available_commands.push( <mkdir rmdir chdir unlink chmod chown> );
@available_commands.push( <pop push> );
# Enable reading character as they ar typed, see Perl5: perldoc -f getc
# It would be better to use Term::ReadKey but it has to be implemented for Perl6
my $BSD_STYLE = 1;
if ($BSD_STYLE) {
run "stty cbreak </dev/tty >/dev/tty 2>&1";
}
else {
run "stty", '-icanon', 'eol', "\x01";
}
my $_loop_ = get_loop();
eval $_loop_;
if ($BSD_STYLE) {
run "stty -cbreak </dev/tty >/dev/tty 2>&1";
}
else {
run "stty", 'icanon', 'eol', '^@'; # ASCII null
}
exit;
#################################################333
sub get_loop {
return '
loop {
my $command = "";
print "\n", $prompt;
loop {
my $char = $*IN.getc;
if ($char eq "\n") {
# TODO: maybe check if _loop_ shows up in the input and disallow that code ?
if (eval "$command;" ~ $_loop_ ) {
exit;
}
else {
print $!;
last;
}
}
if ($char eq "\t") {
# clean the TAB but keep what we had so far
refresh_commandline($command);
my $tail = tab_completition($command);
if (defined $tail) {
$command ~= $tail;
refresh_commandline($command);
}
next;
}
$command ~= $char;
}
}
';
}
# TODO: this should understand the command line typed in so far....
sub tab_completition {
my ($command) = @_;
my @possible_commands = grep { not index($_, $command)}, @available_commands;
# TODO: might really get more than one... and we should let the user step through them using TAB
# or display all possible values, or the user should be able to configure the behivaior
return if not @possible_commands;
return substr(@possible_commands[0], $command.bytes) if 1 == @possible_commands;
# TODO: if there are too many (> $LIMIT) ask if the user really wants to display all
my $WIDTH = 80;
my $out = '';
my $line = '';
for @possible_commands -> $com {
if ($line.bytes + 1 + $com.bytes <= $WIDTH) {
$line ~= " $com";
} else {
$out ~= "$line\n";
$line = $com;
}
}
$out ~= "$line\n";
print "\n$out";
return "";
}
sub refresh_commandline {
my ($command) = @_;
print "\r", $prompt;
print " " x $command.bytes + 1;
print "\r", $prompt;
print $command;
}