| var common = require('./common'); |
| var _cd = require('./cd'); |
| var path = require('path'); |
| |
| // Pushd/popd/dirs internals |
| var _dirStack = []; |
| |
| function _isStackIndex(index) { |
| return (/^[\-+]\d+$/).test(index); |
| } |
| |
| function _parseStackIndex(index) { |
| if (_isStackIndex(index)) { |
| if (Math.abs(index) < _dirStack.length + 1) { // +1 for pwd |
| return (/^-/).test(index) ? Number(index) - 1 : Number(index); |
| } else { |
| common.error(index + ': directory stack index out of range'); |
| } |
| } else { |
| common.error(index + ': invalid number'); |
| } |
| } |
| |
| function _actualDirStack() { |
| return [process.cwd()].concat(_dirStack); |
| } |
| |
| //@ |
| //@ ### pushd([options,] [dir | '-N' | '+N']) |
| //@ |
| //@ Available options: |
| //@ |
| //@ + `-n`: Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated. |
| //@ |
| //@ Arguments: |
| //@ |
| //@ + `dir`: Makes the current working directory be the top of the stack, and then executes the equivalent of `cd dir`. |
| //@ + `+N`: Brings the Nth directory (counting from the left of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. |
| //@ + `-N`: Brings the Nth directory (counting from the right of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. |
| //@ |
| //@ Examples: |
| //@ |
| //@ ```javascript |
| //@ // process.cwd() === '/usr' |
| //@ pushd('/etc'); // Returns /etc /usr |
| //@ pushd('+1'); // Returns /usr /etc |
| //@ ``` |
| //@ |
| //@ Save the current directory on the top of the directory stack and then cd to `dir`. With no arguments, pushd exchanges the top two directories. Returns an array of paths in the stack. |
| function _pushd(options, dir) { |
| if (_isStackIndex(options)) { |
| dir = options; |
| options = ''; |
| } |
| |
| options = common.parseOptions(options, { |
| 'n' : 'no-cd' |
| }); |
| |
| var dirs = _actualDirStack(); |
| |
| if (dir === '+0') { |
| return dirs; // +0 is a noop |
| } else if (!dir) { |
| if (dirs.length > 1) { |
| dirs = dirs.splice(1, 1).concat(dirs); |
| } else { |
| return common.error('no other directory'); |
| } |
| } else if (_isStackIndex(dir)) { |
| var n = _parseStackIndex(dir); |
| dirs = dirs.slice(n).concat(dirs.slice(0, n)); |
| } else { |
| if (options['no-cd']) { |
| dirs.splice(1, 0, dir); |
| } else { |
| dirs.unshift(dir); |
| } |
| } |
| |
| if (options['no-cd']) { |
| dirs = dirs.slice(1); |
| } else { |
| dir = path.resolve(dirs.shift()); |
| _cd('', dir); |
| } |
| |
| _dirStack = dirs; |
| return _dirs(''); |
| } |
| exports.pushd = _pushd; |
| |
| //@ |
| //@ ### popd([options,] ['-N' | '+N']) |
| //@ |
| //@ Available options: |
| //@ |
| //@ + `-n`: Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated. |
| //@ |
| //@ Arguments: |
| //@ |
| //@ + `+N`: Removes the Nth directory (counting from the left of the list printed by dirs), starting with zero. |
| //@ + `-N`: Removes the Nth directory (counting from the right of the list printed by dirs), starting with zero. |
| //@ |
| //@ Examples: |
| //@ |
| //@ ```javascript |
| //@ echo(process.cwd()); // '/usr' |
| //@ pushd('/etc'); // '/etc /usr' |
| //@ echo(process.cwd()); // '/etc' |
| //@ popd(); // '/usr' |
| //@ echo(process.cwd()); // '/usr' |
| //@ ``` |
| //@ |
| //@ When no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory. The elements are numbered from 0 starting at the first directory listed with dirs; i.e., popd is equivalent to popd +0. Returns an array of paths in the stack. |
| function _popd(options, index) { |
| if (_isStackIndex(options)) { |
| index = options; |
| options = ''; |
| } |
| |
| options = common.parseOptions(options, { |
| 'n' : 'no-cd' |
| }); |
| |
| if (!_dirStack.length) { |
| return common.error('directory stack empty'); |
| } |
| |
| index = _parseStackIndex(index || '+0'); |
| |
| if (options['no-cd'] || index > 0 || _dirStack.length + index === 0) { |
| index = index > 0 ? index - 1 : index; |
| _dirStack.splice(index, 1); |
| } else { |
| var dir = path.resolve(_dirStack.shift()); |
| _cd('', dir); |
| } |
| |
| return _dirs(''); |
| } |
| exports.popd = _popd; |
| |
| //@ |
| //@ ### dirs([options | '+N' | '-N']) |
| //@ |
| //@ Available options: |
| //@ |
| //@ + `-c`: Clears the directory stack by deleting all of the elements. |
| //@ |
| //@ Arguments: |
| //@ |
| //@ + `+N`: Displays the Nth directory (counting from the left of the list printed by dirs when invoked without options), starting with zero. |
| //@ + `-N`: Displays the Nth directory (counting from the right of the list printed by dirs when invoked without options), starting with zero. |
| //@ |
| //@ Display the list of currently remembered directories. Returns an array of paths in the stack, or a single path if +N or -N was specified. |
| //@ |
| //@ See also: pushd, popd |
| function _dirs(options, index) { |
| if (_isStackIndex(options)) { |
| index = options; |
| options = ''; |
| } |
| |
| options = common.parseOptions(options, { |
| 'c' : 'clear' |
| }); |
| |
| if (options['clear']) { |
| _dirStack = []; |
| return _dirStack; |
| } |
| |
| var stack = _actualDirStack(); |
| |
| if (index) { |
| index = _parseStackIndex(index); |
| |
| if (index < 0) { |
| index = stack.length + index; |
| } |
| |
| common.log(stack[index]); |
| return stack[index]; |
| } |
| |
| common.log(stack.join(' ')); |
| |
| return stack; |
| } |
| exports.dirs = _dirs; |