Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | package Psh::Builtins::Cd; |
2 | ||
3 | require Psh::Support::Dirs; | |
4 | require Psh::Completion; | |
5 | require Psh::OS; | |
6 | require Psh::Util; | |
7 | ||
8 | =item * C<cd DIR> | |
9 | ||
10 | Change the working directory to DIR or home if DIR is not specified. | |
11 | The special DIR "-" is interpreted as "return to the previous | |
12 | directory". | |
13 | ||
14 | C<cd %num> will jump to a certain directory in the stack (See also | |
15 | builtin C<dirs>). | |
16 | ||
17 | C<cd +num> and C<cd -num> will go forward/backward in the directory | |
18 | stack. | |
19 | ||
20 | =cut | |
21 | ||
22 | sub bi_cd | |
23 | { | |
24 | my $in_dir = shift || Psh::OS::get_home_dir(); | |
25 | my $explicit=0; | |
26 | unless (@Psh::Support::Dirs::stack) { | |
27 | push @Psh::Support::Dirs::stack, $ENV{PWD}; | |
28 | } | |
29 | ||
30 | if ($in_dir=~/^[+-](\d+)$/) { | |
31 | my $tmp_pos=$Psh::Support::Dirs::stack_pos-int($in_dir); | |
32 | if ($tmp_pos<0) { | |
33 | # TODO: Error handling | |
34 | } elsif ($tmp_pos>$#Psh::Support::Dirs::stack) { | |
35 | # TODO: Error handling | |
36 | } else { | |
37 | $in_dir=$Psh::Support::Dirs::stack[$tmp_pos]; | |
38 | $Psh::Support::Dirs::stack_pos=$tmp_pos; | |
39 | } | |
40 | } elsif ($in_dir eq '-') { | |
41 | if (@Psh::Support::Dirs::stack>1) { | |
42 | if ($Psh::Support::Dirs::stack_pos==0) { | |
43 | $in_dir=$Psh::Support::Dirs::stack[1]; | |
44 | $Psh::Support::Dirs::stack_pos=1; | |
45 | } else { | |
46 | $in_dir=$Psh::Support::Dirs::stack[0]; | |
47 | $Psh::Support::Dirs::stack_pos=0; | |
48 | } | |
49 | } | |
50 | } elsif ($in_dir=~ /^\%(\d+)$/) { | |
51 | my $tmp_pos=$1; | |
52 | if ($tmp_pos>$#Psh::Support::Dirs::stack) { | |
53 | # TODO: Error handling | |
54 | } else { | |
55 | $in_dir=$Psh::Support::Dirs::stack[$tmp_pos]; | |
56 | $Psh::Support::Dirs::stack_pos=$tmp_pos; | |
57 | } | |
58 | } else { | |
59 | $explicit=1 unless $in_dir eq $Psh::Support::Dirs::stack[0]; | |
60 | # Don't push the same value again | |
61 | $Psh::Support::Dirs::stack_pos=0; | |
62 | } | |
63 | my $dirpath='.'; | |
64 | ||
65 | if ($ENV{CDPATH} && !Psh::OS::file_name_is_absolute($in_dir)) { | |
66 | $dirpath.=$ENV{CDPATH}; | |
67 | } | |
68 | ||
69 | foreach my $cdbase (split $Psh::OS::PATH_SEPARATOR,$dirpath) { | |
70 | my $dir= $in_dir; | |
71 | if( $cdbase eq '.') { | |
72 | $dir = Psh::Util::abs_path($dir); | |
73 | } else { | |
74 | $dir = Psh::Util::abs_path(Psh::OS::catdir($cdbase,$dir)); | |
75 | } | |
76 | ||
77 | if ($dir and (-e $dir) and (-d _)) { | |
78 | if (-x _) { | |
79 | $ENV{OLDPWD}= $ENV{PWD}; | |
80 | unshift @Psh::Support::Dirs::stack, $dir if $explicit; | |
81 | CORE::chdir $dir; | |
82 | $ENV{PWD}=$dir; | |
83 | return (1,undef); | |
84 | } else { | |
85 | Psh::Util::print_error_i18n('perm_denied',$in_dir,$Psh::bin); | |
86 | return (0,undef); | |
87 | } | |
88 | } | |
89 | } | |
90 | Psh::Util::print_error_i18n('no_such_dir',$in_dir,$Psh::bin); | |
91 | return (0,undef); | |
92 | } | |
93 | ||
94 | sub cmpl_cd { | |
95 | my( $text, $pre, $start, $line, $startchar) = @_; | |
96 | return 1,Psh::Completion::cmpl_directories($pre.$text); | |
97 | } | |
98 | ||
99 | 1; |