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; |