Search DuckDuckGo from the command-line

search-pane2 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #!/usr/bin/env node
  2. var blessed = require('blessed'),
  3. PythonShell = require('python-shell'),
  4. screen = blessed.screen({
  5. smartCSR: true,
  6. autoPadding: true
  7. }),
  8. searchResults;
  9. screen._listenedMouse = true; // HACK HACK HACK
  10. var cleanExit = function () {
  11. // program.clear();
  12. // program.disableMouse();
  13. // program.showCursor();
  14. // program.normalBuffer();
  15. process.exit(0);
  16. };
  17. var form = blessed.form({
  18. parent: screen,
  19. keys: true,
  20. top: 'center',
  21. left: 'center',
  22. padding: {
  23. left: 1,
  24. right: 1,
  25. top: 1,
  26. bottom: 1
  27. },
  28. border: {
  29. type: 'line',
  30. fg: 'white',
  31. },
  32. width: '95%',
  33. height: 7,
  34. content: 'Search: '
  35. });
  36. var input = blessed.textbox({
  37. parent: form,
  38. name: 'input',
  39. keys: true,
  40. inputOnFocus: true,
  41. height: 1,
  42. padding: {
  43. left: 1,
  44. right: 1
  45. },
  46. top: 0,
  47. left: 10,
  48. right: 2
  49. });
  50. var submit = blessed.button({
  51. parent: form,
  52. keys: true,
  53. shrink: true,
  54. padding: {
  55. left: 1,
  56. right: 1
  57. },
  58. right: 12,
  59. top: 2,
  60. name: 'submit',
  61. content: 'submit',
  62. style: {
  63. bg: 'blue',
  64. focus: {
  65. bg: 'white',
  66. fg: 'blue'
  67. },
  68. hover: {
  69. bg: 'white',
  70. fg: 'blue'
  71. }
  72. }
  73. });
  74. var cancel = blessed.button({
  75. parent: form,
  76. keys: true,
  77. shrink: true,
  78. padding: {
  79. left: 1,
  80. right: 1
  81. },
  82. right: 2,
  83. top: 2,
  84. name: 'cancel',
  85. content: 'cancel',
  86. style: {
  87. bg: 'red',
  88. focus: {
  89. bg: 'white',
  90. fg: 'red'
  91. },
  92. hover: {
  93. bg: 'white',
  94. fg: 'red'
  95. }
  96. }
  97. });
  98. var loading = blessed.loading({
  99. parent: screen,
  100. visible: false,
  101. hidden: true,
  102. top: 'center',
  103. left: 'center',
  104. padding: {
  105. left: 1,
  106. right: 1,
  107. top: 1,
  108. bottom: 1
  109. },
  110. border: {
  111. type: 'line',
  112. fg: 'white'
  113. },
  114. width: 32,
  115. height: 7,
  116. });
  117. var resultsForm = blessed.form({
  118. parent: screen,
  119. hidden: true,
  120. input: false,
  121. keys: true,
  122. tags: true
  123. });
  124. var resultsSet = blessed.radioset({
  125. parent: resultsForm,
  126. input: false,
  127. keys: true,
  128. tags: true,
  129. top: 0,
  130. left: 0,
  131. border: {
  132. type: 'line',
  133. fg: 'white'
  134. },
  135. selectedBg: 'darkred',
  136. selectedFg: 'yellow',
  137. scollbar: true,
  138. });
  139. submit.on('press', function() {
  140. form.submit();
  141. });
  142. cancel.on('press', function() {
  143. form.reset();
  144. });
  145. input.on('submit', function(data) {
  146. form.submit();
  147. });
  148. form.on('submit', function(data) {
  149. form.hide();
  150. PythonShell.run('results.py', {args: [data.input], mode: 'json',
  151. scriptPath: __dirname,
  152. pythonPath: '/usr/bin/python3'},
  153. function (err, results) {
  154. loading.stop();
  155. if (err) throw err;
  156. searchResults = results[0];
  157. resultsForm.show();
  158. searchResults.forEach(function(r, i) {
  159. var result = blessed.radiobutton({
  160. tags: true,
  161. top: i * 4,
  162. height: 4,
  163. padding: {
  164. bottom: 1
  165. },
  166. text: '{bold}' + (i + 1) + '. ' + r.title + '{/}\n\t{blue-fg}' + r.link.slice(0, 100) + '{/}\n\t' + r.desc
  167. });
  168. result.set('index', i);
  169. resultsSet.append(result);
  170. result.key('left', backToSearch);
  171. result.on('check', function() {
  172. resultsForm.hide();
  173. screen.leave();
  174. var browser = screen.spawn('w3m', [searchResults[this.get('index')].link]);
  175. var self = this;
  176. browser.on('exit', function() {
  177. screen.program.hideCursor();
  178. resultsForm.show();
  179. self.focus();
  180. screen.render();
  181. });
  182. })
  183. result.key('j', listNext);
  184. result.key('k', listPrev);
  185. result.key('up', listNext);
  186. result.key('down', listPrev);
  187. result.on('keypress', numberPress);
  188. })
  189. resultsSet.children[0].focus(); // first result
  190. screen.render();
  191. });
  192. loading.load('Searching...');
  193. // loading._.icon.style = {bg: 'grey'}; // Hacky, loading icon doesn't support styling via options
  194. });
  195. form.on('reset', function(data) {
  196. form.setContent('Canceled.');
  197. cleanExit();
  198. });
  199. var backToSearch = function() {
  200. screen.saveFocus();
  201. resultsForm.hide();
  202. form.show();
  203. input.focus();
  204. screen.render();
  205. }
  206. var forwardToList = function() {
  207. if (searchResults) {
  208. form.hide();
  209. resultsForm.show();
  210. screen.restoreFocus();
  211. screen.render();
  212. }
  213. }
  214. var numberPress = function(key) {
  215. numbers = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
  216. if (numbers.indexOf(key) > -1) {
  217. resultsSet.children[parseInt(key, 10) - 1].focus();
  218. resultsSet.children[parseInt(key, 10) - 1].check();
  219. }
  220. }
  221. var listNext = function() {
  222. resultsForm.focusNext();
  223. }
  224. var listPrev = function() {
  225. resultsForm.focusPrevious();
  226. }
  227. // resultsSet.key('left', backToSearch);
  228. // resultsForm.key('left', backToSearch);
  229. // resultsSet.on('keypress', numberPress);
  230. // resultsForm.on('keypress', numberPress);
  231. form.key('right', forwardToList);
  232. input.key('right', forwardToList);
  233. submit.key('right', forwardToList);
  234. cancel.key('right', forwardToList);
  235. screen.key('q', function() {
  236. cleanExit();
  237. });
  238. screen.key('escape', function() {
  239. cleanExit();
  240. });
  241. screen.render();
  242. input.focus();