LineCountStream.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. 'use strict'
  2. const util = require('util')
  3. const stream = require('stream')
  4. const PassThrough = stream.PassThrough
  5. // Expose
  6. module.exports = LineCountStream
  7. /*
  8. * This is a PassThrough stream that keep track of how many lines have been logged.
  9. *
  10. * TODO: Account for terminal size changes/wrapping
  11. */
  12. function LineCountStream(outStream) {
  13. // Checks if the outStream is already a LineCountStream. If so, return it
  14. if (outStream instanceof LineCountStream)
  15. return outStream
  16. // Make sure this is a new instance
  17. if (!(this instanceof LineCountStream))
  18. return new LineCountStream(outStream)
  19. // Call super constructor
  20. PassThrough.call(this)
  21. // Save outStream
  22. this._outStream = outStream
  23. // Initialize line and logs (line starts as 1)
  24. this._line = 1
  25. this._logs = 0
  26. // Flag indicating a change is being made not with current cursor
  27. this._editing = false
  28. // Pipe this data to output stream
  29. outStream && this.pipe(outStream)
  30. }
  31. // Inherits from PassThrough
  32. util.inherits(LineCountStream, PassThrough)
  33. /*
  34. * Get current line
  35. */
  36. LineCountStream.prototype.line = function line() {
  37. return this._line
  38. }
  39. /*
  40. * Get log count
  41. */
  42. LineCountStream.prototype.logs = function logs() {
  43. return this._logs
  44. }
  45. /*
  46. * On write, increment lines and logs
  47. *
  48. * Benchmark: http://jsperf.com/count-the-number-of-characters-in-a-string
  49. */
  50. LineCountStream.prototype.write = function write(data) {
  51. if (! this._editing) {
  52. this.countLines(data)
  53. }
  54. this.push(data)
  55. }
  56. /*
  57. * Binds a inputStream to this, in order to account for extra lines
  58. * typed in the Terminal.
  59. * This method will bind event 'data' into the stream, and call
  60. * countLines(data) with the data. It will not account for '_editing',
  61. * because there can be user input while editing.
  62. */
  63. LineCountStream.prototype.addLineListener = function addLineListener(inStream) {
  64. // Binds to 'data' event
  65. inStream.on('data', this.countLines.bind(this))
  66. }
  67. /*
  68. * Counts lines on the data and increment counters.
  69. * Compensation for `_editing` mode should be done
  70. * outside this method. Keep this as clean as possible
  71. */
  72. LineCountStream.prototype.countLines = function countLines(data) {
  73. var dataLines = (data.toString().split('\n').length - 1)
  74. this._logs++
  75. this._line += dataLines || 0
  76. }
  77. /*
  78. * Call this to stop line counts (during some change of data in previous records)
  79. */
  80. LineCountStream.prototype.stopLineCount = function stopLineCount() {
  81. this._editing = true
  82. }
  83. /*
  84. * Call this to resume line counts
  85. */
  86. LineCountStream.prototype.resumeLineCount = function resumeLineCount() {
  87. this._editing = false
  88. }
  89. /*
  90. * Proxy rows from the stream
  91. */
  92. LineCountStream.prototype.rows = function rows() {
  93. return this._outStream.rows
  94. }
  95. /*
  96. * Proxy columns from the stream
  97. */
  98. LineCountStream.prototype.columns = function columns() {
  99. return this._outStream.columns
  100. }