[
  {
    "path": ".gitignore",
    "content": "node_modules\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\n\nlanguage: node_js\n\nnode_js:\n  - \"9\"\n  - \"8\"\n  - \"6\"\n\nos:\n  - linux\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2017 Mathias Buus\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# diffy\n\nA tiny framework for building diff based interactive command line tools.\n\n```\nnpm install diffy\n```\n\n[![Build Status](https://travis-ci.org/mafintosh/diffy.svg?branch=master)](https://travis-ci.org/mafintosh/diffy)\n\nBasically React, but in the terminal powered by [ansi-diff](https://github.com/mafintosh/ansi-diff) and [neat-input](https://github.com/mafintosh/neat-input).\n\n## Usage\n\n``` js\nvar diffy = require('diffy')()\nvar trim = require('diffy/trim')\n\ndiffy.render(function () {\n  return trim(`\n    Hello user. The time is:\n      ${new Date()}\n    That is all for now\n  `)\n})\n\n// re-render every 1s\nsetInterval(() => diffy.render(), 1000)\n```\n\nYou can also use `diffy` to query input from a user\n\n``` js\nvar diffy = require('diffy')()\nvar trim = require('diffy/trim')\nvar input = require('diffy/input')({style: style})\nvar names = []\n\ninput.on('update', () => diffy.render())\ninput.on('enter', (line) => names.push(line))\n\ndiffy.render(function () {\n  return trim(`\n    Enter your name: ${input.line()}\n    List of names: ${names.join(', ')}\n  `)\n})\n\nfunction style (start, cursor, end) {\n  return start + '[' + (cursor || ' ') + ']' + end\n}\n```\n\nSee the examples folder for more.\n\n## API\n\n#### `var diffy = require('diffy')([options])`\n\nMake a new diffy instance. Writes to stdout.\n\nOptions include:\n\n``` js\n{\n  fullscreen: true // overtake the terminal like vim/less does\n}\n```\n\nNote that if you use `fullscreen: true`, the terminal will be restored\non exit, even if your program crashes.\n\n#### `diffy.render([function])`\n\nTrigger a render and/or update the default render\nfunction. A render function should simply return a string\ncontaining the output you wish to display and then `diffy` will make sure to only print the diff.\n\n#### `diffy.width`\n\nProperty containing the width of the terminal.\n\n#### `diffy.height`\n\nProperty containing the height of the terminal.\n\n#### `diffy.on('resize')`\n\nEmitted when the terminal is resized. Triggers a render as well.\n\n#### `diffy.on('render')`\n\nEmitted just before a render happens.\n\n#### `var input = require('diffy/input')()`\n\nGet a [neat-input](https://github.com/mafintosh/neat-input) instance. Use this if you want to accept interactive input.\n\n#### `var trim = require('diffy/trim')`\n\nHelper function that trims and removes the indentation of a multiline string. Useful if you have a render function that returns an indented string like in the above example.\n\n#### `var trim = require('diffy/trim+newline')`\n\nHelper function that trims but adds a newline at the end\n\n## Components\n\nWith diffy, components are just strings you compose together to form your application.\nA bunch of modules already exists for this pattern, providing useful features.\n\n* [watson/menu-string](https://github.com/watson/menu-string) - Generate a menu with selectable menu items as a string.\n* [watson/progress-string](https://github.com/watson/progress-string) - Generate a CLI progress bar as a string that you can then output in any way you like.\n* [mafintosh/scrollable-string](https://github.com/mafintosh/scrollable-string) - Generate a diff friendly string that is bounded by a configurable scroll box.\n\n## Credits\n\nThank you to [@Fouad](https://github.com/Fouad) for donating the module name.\n\n## License\n\nMIT\n"
  },
  {
    "path": "examples/date.js",
    "content": "var diffy = require('../')()\nvar trim = require('../trim')\n\ndiffy.render(function () {\n  return trim(`\n    Hello user. The time is:\n      ${new Date()}\n    That is all for now\n  `)\n})\n\n// re-render every 1s\nsetInterval(() => diffy.render(), 1000)\n"
  },
  {
    "path": "examples/enter-name.js",
    "content": "var diffy = require('../')()\nvar input = require('../input')({style: style})\nvar trim = require('../trim')\n\nvar names = []\n\ninput.on('update', () => diffy.render())\ninput.on('enter', (line) => names.push(line))\n\ndiffy.render(function () {\n  return trim(`\n    Enter your name: ${input.line()}\n    List of names: ${names.join(', ')}\n  `)\n})\n\nfunction style (start, cursor, end) {\n  return start + '[' + (cursor || ' ') + ']' + end\n}\n"
  },
  {
    "path": "examples/exit.js",
    "content": "var diffy = require('../')()\nvar trim = require('../trim')\n\nvar text = 'lowercase'\n\nprocess.once('SIGINT', function () {\n  text = 'UPPERCASE'\n  diffy.render(render)\n  process.nextTick(process.exit)\n})\n\ndiffy.render(render)\n\n// re-render every 1s\nsetInterval(() => diffy.render(), 1000)\n\nfunction render () {\n  return trim(`\n    Hello world.\n    Error should happen on last line:\n    ${text}\n  `)\n}\n"
  },
  {
    "path": "examples/fullscreen.js",
    "content": "var diffy = require('../')({fullscreen: true})\nvar input = require('../input')()\nvar fs = require('fs')\n\nvar src = fs.readFileSync(__filename, 'utf-8')\nvar tmp = src\nvar upper = false\n\ndiffy.render(function () {\n  return tmp\n})\n\ninput.on('enter', function () {\n  upper = !upper\n  tmp = upper ? src.toUpperCase() : src\n  diffy.render()\n})\n"
  },
  {
    "path": "examples/nested.js",
    "content": "var diffy = require('../')()\nvar trim = require('../trim')\n\ndiffy.render(function () {\n  return trim(`\n    Hello user. The time is:\n      ${nestedDate()}\n    THERE SHOULD BE NO SPACE ABOVE THIS LINE\n    That is all for now\n  `)\n})\n\n// re-render every 1s\nsetInterval(() => diffy.render(), 1000)\n\nfunction nestedDate () {\n  return trim(`\n    ${new Date()}\n  `)\n}\n"
  },
  {
    "path": "examples/slider.js",
    "content": "var diffy = require('../')()\nvar input = require('../input')()\n\nvar pos = 0\nvar ch = '>'\n\ninput.on('left', function () {\n  pos--\n  ch = '<'\n  diffy.render()\n})\n\ninput.on('right', function () {\n  pos++\n  ch = '>'\n  diffy.render()\n})\n\ndiffy.render(render)\n\nfunction render () {\n  if (pos < 1) pos = 1\n  var widLen = diffy.width.toString().length\n  var wid = Math.max(diffy.width - 2 * widLen - 1 - 6, 10)\n  if (pos >= wid - 1) pos = wid - 2\n  var i = 1\n  var s = 'Move the cursor <left> or <right>\\n['\n  for (; i < pos; i++) s += ' '\n  s += ch\n  i++\n  for (; i < wid - 1; i++) s += ' '\n  s += '] ' + (pos - 1) + '/' + (wid - 3) + '\\n'\n  if (ch === '>') s += 'You are moving <right>'\n  else s += 'You are moving <left>'\n  return s\n}\n"
  },
  {
    "path": "index.js",
    "content": "var differ = require('ansi-diff')\nvar events = require('events')\nvar util = require('util')\n\nvar SMCUP = Buffer.from([0x1b, 0x5b, 0x3f, 0x31, 0x30, 0x34, 0x39, 0x68])\nvar RMCUP = Buffer.from([0x1b, 0x5b, 0x3f, 0x31, 0x30, 0x34, 0x39, 0x6c])\nvar CLEAR = Buffer.from([0x1b, 0x5b, 0x33, 0x4a, 0x1b, 0x5b, 0x48, 0x1b, 0x5b, 0x32, 0x4a])\n\nmodule.exports = Diffy\n\nfunction Diffy (opts) {\n  if (!(this instanceof Diffy)) return new Diffy(opts)\n  if (!opts) opts = {}\n  if (typeof opts === 'function') opts = {render: opts}\n\n  events.EventEmitter.call(this)\n\n  this.destroyed = false\n  this.fullscreen = !!opts.fullscreen\n  this.out = process.stdout\n  this.out.on('resize', this._onresize.bind(this))\n  this.differ = differ(this._dimension())\n\n  this._destroy = this.destroy.bind(this)\n  this._isFullscreen = false\n\n  process.on('SIGWINCH', noop)\n  process.on('exit', this._destroy)\n\n  if (opts.render) this.render(opts.render)\n}\n\nutil.inherits(Diffy, events.EventEmitter)\n\nObject.defineProperty(Diffy.prototype, 'height', {\n  enumerable: true,\n  get: function () {\n    return this.differ.height\n  }\n})\n\nObject.defineProperty(Diffy.prototype, 'width', {\n  enumerable: true,\n  get: function () {\n    return this.differ.width\n  }\n})\n\nDiffy.prototype.render = function (fn) {\n  if (this.fullscreen && !this._isFullscreen) {\n    this._isFullscreen = true\n    this.out.write(SMCUP)\n    this.out.write(CLEAR)\n  }\n  if (fn) this._render = fn\n  this.emit('render')\n  this.out.write(this.differ.update(this._render()))\n}\n\nDiffy.prototype.destroy = function () {\n  if (this.destroyed) return\n  this.destroyed = true\n  process.removeListener('SIGWINCH', noop)\n  process.removeListener('exit', this._destroy)\n  if (this._isFullscreen) this.out.write(RMCUP)\n  this.emit('destroy')\n}\n\nDiffy.prototype._onresize = function () {\n  this.differ.resize(this._dimension())\n  this.emit('resize')\n  this.render()\n}\n\nDiffy.prototype._dimension = function () {\n  return {\n    width: this.out.columns,\n    height: this.out.rows\n  }\n}\n\nfunction noop () {\n  return ''\n}\n"
  },
  {
    "path": "input.js",
    "content": "module.exports = require('neat-input')\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"diffy\",\n  \"version\": \"2.1.0\",\n  \"description\": \"A tiny framework for building diff based interactive command line tools.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"ansi-diff\": \"^1.0.10\",\n    \"neat-input\": \"^1.9.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/mafintosh/diffy.git\"\n  },\n  \"scripts\": {\n    \"test\": \"standard\"\n  },\n  \"author\": \"Mathias Buus (@mafintosh)\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/mafintosh/diffy/issues\"\n  },\n  \"homepage\": \"https://github.com/mafintosh/diffy\",\n  \"devDependencies\": {\n    \"standard\": \"^10.0.3\"\n  }\n}\n"
  },
  {
    "path": "trim+newline.js",
    "content": "var trim = require('./trim')\nvar os = require('os')\n\nmodule.exports = trimAndNewline\n\nfunction trimAndNewline (s) {\n  return trim(s) + os.EOL\n}\n"
  },
  {
    "path": "trim.js",
    "content": "\nmodule.exports = trim\n\nfunction trim (s) {\n  if (!/^\\r?\\n/.test(s)) return s\n  return deindent(s).trim()\n}\n\nfunction deindent (s) {\n  if (!/^\\r?\\n/.test(s)) return s\n  var indent = (s.match(/\\n([ ]+)/m) || [])[1] || ''\n  s = indent + s\n  return s.split('\\n')\n    .map(l => replace(indent, l))\n    .join('\\n')\n}\n\nfunction replace (prefix, line) {\n  return line.slice(0, prefix.length) === prefix ? line.slice(prefix.length) : line\n}\n"
  }
]