filemanager.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /**
  2. * filemanager.js - file manager element for blessed
  3. * Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
  4. * https://github.com/chjj/blessed
  5. */
  6. /**
  7. * Modules
  8. */
  9. var path = require('path')
  10. , fs = require('fs');
  11. var helpers = require('../helpers');
  12. var Node = require('./node');
  13. var List = require('./list');
  14. /**
  15. * FileManager
  16. */
  17. function FileManager(options) {
  18. var self = this;
  19. if (!(this instanceof Node)) {
  20. return new FileManager(options);
  21. }
  22. options = options || {};
  23. options.parseTags = true;
  24. // options.label = ' {blue-fg}%path{/blue-fg} ';
  25. List.call(this, options);
  26. this.cwd = options.cwd || process.cwd();
  27. this.file = this.cwd;
  28. this.value = this.cwd;
  29. if (options.label && ~options.label.indexOf('%path')) {
  30. this._label.setContent(options.label.replace('%path', this.cwd));
  31. }
  32. this.on('select', function(item) {
  33. var value = item.content.replace(/\{[^{}]+\}/g, '').replace(/@$/, '')
  34. , file = path.resolve(self.cwd, value);
  35. return fs.stat(file, function(err, stat) {
  36. if (err) {
  37. return self.emit('error', err, file);
  38. }
  39. self.file = file;
  40. self.value = file;
  41. if (stat.isDirectory()) {
  42. self.emit('cd', file, self.cwd);
  43. self.cwd = file;
  44. if (options.label && ~options.label.indexOf('%path')) {
  45. self._label.setContent(options.label.replace('%path', file));
  46. }
  47. self.refresh();
  48. } else {
  49. self.emit('file', file);
  50. }
  51. });
  52. });
  53. }
  54. FileManager.prototype.__proto__ = List.prototype;
  55. FileManager.prototype.type = 'file-manager';
  56. FileManager.prototype.refresh = function(cwd, callback) {
  57. if (!callback) {
  58. callback = cwd;
  59. cwd = null;
  60. }
  61. var self = this;
  62. if (cwd) this.cwd = cwd;
  63. else cwd = this.cwd;
  64. return fs.readdir(cwd, function(err, list) {
  65. if (err && err.code === 'ENOENT') {
  66. self.cwd = cwd !== process.env.HOME
  67. ? process.env.HOME
  68. : '/';
  69. return self.refresh(callback);
  70. }
  71. if (err) {
  72. if (callback) return callback(err);
  73. return self.emit('error', err, cwd);
  74. }
  75. var dirs = []
  76. , files = [];
  77. list.unshift('..');
  78. list.forEach(function(name) {
  79. var f = path.resolve(cwd, name)
  80. , stat;
  81. try {
  82. stat = fs.lstatSync(f);
  83. } catch (e) {
  84. ;
  85. }
  86. if ((stat && stat.isDirectory()) || name === '..') {
  87. dirs.push({
  88. name: name,
  89. text: '{light-blue-fg}' + name + '{/light-blue-fg}/',
  90. dir: true
  91. });
  92. } else if (stat && stat.isSymbolicLink()) {
  93. files.push({
  94. name: name,
  95. text: '{light-cyan-fg}' + name + '{/light-cyan-fg}@',
  96. dir: false
  97. });
  98. } else {
  99. files.push({
  100. name: name,
  101. text: name,
  102. dir: false
  103. });
  104. }
  105. });
  106. dirs = helpers.asort(dirs);
  107. files = helpers.asort(files);
  108. list = dirs.concat(files).map(function(data) {
  109. return data.text;
  110. });
  111. self.setItems(list);
  112. self.select(0);
  113. self.screen.render();
  114. self.emit('refresh');
  115. if (callback) callback();
  116. });
  117. };
  118. FileManager.prototype.pick = function(cwd, callback) {
  119. if (!callback) {
  120. callback = cwd;
  121. cwd = null;
  122. }
  123. var self = this
  124. , focused = this.screen.focused === this
  125. , hidden = this.hidden
  126. , onfile
  127. , oncancel;
  128. function resume() {
  129. self.removeListener('file', onfile);
  130. self.removeListener('cancel', oncancel);
  131. if (hidden) {
  132. self.hide();
  133. }
  134. if (!focused) {
  135. self.screen.restoreFocus();
  136. }
  137. self.screen.render();
  138. }
  139. this.on('file', onfile = function(file) {
  140. resume();
  141. return callback(null, file);
  142. });
  143. this.on('cancel', oncancel = function() {
  144. resume();
  145. return callback();
  146. });
  147. this.refresh(cwd, function(err) {
  148. if (err) return callback(err);
  149. if (hidden) {
  150. self.show();
  151. }
  152. if (!focused) {
  153. self.screen.saveFocus();
  154. self.focus();
  155. }
  156. self.screen.render();
  157. });
  158. };
  159. FileManager.prototype.reset = function(cwd, callback) {
  160. if (!callback) {
  161. callback = cwd;
  162. cwd = null;
  163. }
  164. this.cwd = cwd || this.options.cwd;
  165. this.refresh(callback);
  166. };
  167. /**
  168. * Expose
  169. */
  170. module.exports = FileManager;