UNPKG

how2

Version:

AI for your terminal. Uses Google and Stackoverflow to find how to do things on a Unix command line.

245 lines (204 loc) 5.23 kB
const _ = require('lodash') const blessed = require('blessed') const htmlentities = require('ent') const colors = require('colors') const marked = require('marked') const utils = require('./utils') const updates = require('./updates') let screen let googleList let answersList let logBox function exit () { screen.destroy() const msg = updates.getResult() if (msg) console.error(msg) process.exit(0) } function start () { updates.checkForUpdates() screen = blessed.screen({ smartCSR: true, autoPadding: true }) screen.key(['C-c'], (ch, key) => { exit() }) const logText = `${colors.bgBlue.white.bold(' Enter/Space ')} open link ` + `${colors.bgBlue.white.bold(' b ')} open browser ` + `${colors.bgBlue.white.bold(' p ')} print (for copy-paste) ` + `${colors.bgBlue.white.bold(' Esc ')} close window` logBox = blessed.box({ width: '100%', top: '100%-1', content: logText }) screen.append(logBox) screen.render() } function listStyle () { return { selectedBg: '#b2dfdb', selectedFg: 'black', mouse: true, keys: true, vi: true } } function showGoogling () { const box = blessed.box({ content: 'Googling...' }) screen.append(box) screen.render() } function showGoogleList (searchResults, callback) { const titles = searchResults.map((el) => el.title) const options = { parent: screen, width: '100%', height: '100%-1', top: 'center', left: 'center', padding: 1, title: 'Select Answer:' // mouse: true } _.extend(options, listStyle()) googleList = blessed.list(options) googleList.setItems(titles) googleList.prepend(new blessed.Text({ content: 'Select one code tip:' })) googleList.on('select', function (_) { callback(this.selected) }) googleList.key(['space', 'o'], () => { googleList.enterSelected() screen.render() }) googleList.key(['escape', 'q'], () => { exit() }) googleList.key(['b'], function () { const { link } = searchResults[this.selected] try { require('openurl').open(link) } catch (e) { console.error(e) } }) googleList.select(0) googleList.focus() screen.render() } function makeTitleForAnswer (answer) { const withColors = marked.parse(answer.body_markdown) const lines = withColors.split('\n') let firstLine for (let i = 0; i < lines.length; i++) { firstLine = lines[i] if (firstLine !== '') break } firstLine = htmlentities.decode(firstLine) const score = `(${answer.score}) ` return score + firstLine } function showAnswers (answers, callback) { const listBox = blessed.box({ top: 'center', left: 'center', width: '90%', height: '90%', border: { type: 'line' }, tags: true }) const listOptions = { parent: listBox, border: { type: 'bg' } } _.extend(listOptions, listStyle()) answersList = blessed.list(listOptions) answersList.setItems(answers.map(makeTitleForAnswer)) answersList.on('select', function () { callback(this.selected) }) answersList.key(['space', 'o'], () => { answersList.enterSelected() screen.render() }) answersList.key(['b'], function () { const answer = answers[this.selected] require('openurl').open(answer.link) }) answersList.key(['p'], function () { const answer = answers[this.selected] screen.destroy() printAnswer(answer) }) answersList.key(['escape', 'q'], () => { screen.remove(listBox) googleList.focus() screen.render() }) listBox.append(answersList) answersList.focus() screen.append(listBox) screen.render() } function showAnswer (answer) { const text = utils.toEscapedMarkdown(answer.body_markdown) const answerBox = blessed.box({ top: 'center', left: 'center', width: '80%', height: '80%', border: { type: 'line' }, padding: 1, scrollable: true, alwaysScroll: true, scrollbar: { border: { bg: 'yellow' }, bg: 'yellow' }, keys: true, vi: true // mouse: true }) answerBox.setContent(`${text}\n(${colors.underline.blue(answer.link)})`) answerBox.key(['escape', 'q'], () => { screen.remove(answerBox) if (answersList) { // Focus back on the list of answers answersList.focus() } else { // If we skipped the list of answers because there was only one, // we re-focus on the main googleList googleList.focus() } screen.render() }) answerBox.key(['b'], (event) => require('openurl').open(answer.link)) answerBox.key(['p'], function () { screen.destroy() printAnswer(answer) }) screen.append(answerBox) answerBox.focus() screen.render() } function magicSelect (rows) { screen = blessed.screen({ autoPadding: true }) const list = blessed.list({}) list.setItems(rows) screen.append(list) screen.render() } function printAnswer (answer) { // 'p' button try { const text = utils.toEscapedMarkdown(answer.body_markdown) console.log() console.log(text) } catch (e) { console.error(e) } } module.exports = { start, stop: () => (screen ? screen.destroy() : undefined), showGoogling, showGoogleList, showAnswers, showAnswer, magicSelect }