charProps.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /**
  2. * Indexer constructor (takes index and performs pre-emptive caching)
  3. * @constructor
  4. * @param {String} input Content to index
  5. */
  6. function Indexer(input) {
  7. this.input = input;
  8. // Break up lines by line breaks
  9. var lines = input.split('\n');
  10. // Iterate over the lines until we reach the end or we hit our index
  11. var i = 0,
  12. len = lines.length,
  13. line,
  14. lineStart = 0,
  15. lineEnd,
  16. lineMap = {'length': len};
  17. for (; i < len; i++) {
  18. // Grab the line
  19. line = lines[i];
  20. // Calculate the line end (includes \n we removed)
  21. lineEnd = lineStart + line.length + 1;
  22. // Save the line to its map
  23. lineMap[i] = {'start': lineStart, 'end': lineEnd};
  24. // Overwrite lineStart with lineEnd
  25. lineStart = lineEnd;
  26. }
  27. // Save the lineMap to this
  28. this.lineMap = lineMap;
  29. }
  30. Indexer.prototype = {
  31. /**
  32. * Get the line of the character at a certain index
  33. * @param {Number} index Index of character to retrieve line of
  34. * @param {Object} [options] Options to use for search
  35. * @param {Number} [options.minLine=0] Minimum line for us to search on
  36. * TODO: The following still have to be built/implemented
  37. * @param {Number} [options.maxLine=lines.length] Maximum line for us to search on
  38. * @param {String} [options.guess="average"] Affects searching pattern -- can be "high", "low", or "average" (linear top-down, linear bottom-up, or binary)
  39. * @returns {Number} Line number of character
  40. */
  41. 'lineAt': function (index, options) {
  42. // Fallback options
  43. options = options || {};
  44. // TODO: We can binary search here
  45. // Grab the line map and iterate over it
  46. var lineMap = this.lineMap,
  47. i = options.minLine || 0,
  48. len = lineMap.length,
  49. lineItem;
  50. for (; i < len; i++) {
  51. // TODO: If binary searching, this requires both above and below
  52. // If the index is under end of the lineItem, stop
  53. lineItem = lineMap[i];
  54. if (index < lineItem.end) {
  55. break;
  56. }
  57. }
  58. // Return the line we stopped on
  59. return i;
  60. },
  61. /**
  62. * Get the column of the character at a certain index
  63. * @param {Number} index Index of character to retrieve column of
  64. * @returns {Number} Column number of character
  65. */
  66. 'columnAt': function (index) {
  67. // Start at the index - 1
  68. var input = this.input,
  69. char,
  70. i = index - 1;
  71. // If the index is negative, return now
  72. if (index < 0) {
  73. return 0;
  74. }
  75. // Continue left until index < 0 or we hit a line break
  76. for (; i >= 0; i--) {
  77. char = input.charAt(i);
  78. if (char === '\n') {
  79. break;
  80. }
  81. }
  82. // Return the col of our index - 1 (line break is not in the column count)
  83. var col = index - i - 1;
  84. return col;
  85. },
  86. /**
  87. * Get the index of the character at a line and column
  88. * @param {Object} params Object containing line and column
  89. * @param {Number} params.line Line of character
  90. * @param {Number} params.column Column of character
  91. * @returns {Number} Index of character
  92. */
  93. 'indexAt': function (params) {
  94. // Grab the parameters and lineMap
  95. var line = params.line,
  96. column = params.column,
  97. lineMap = this.lineMap;
  98. // Go to the nth line and get the start
  99. var retLine = lineMap[line],
  100. lineStart = retLine.start;
  101. // Add on the column to the line start and return
  102. var retVal = lineStart + column;
  103. return retVal;
  104. },
  105. /**
  106. * Get the character at a line and column
  107. * @param {Object} params Object containing line and column
  108. * @param {Number} params.line Line of character
  109. * @param {Number} params.column Column of character
  110. * @returns {String} Character at specified location
  111. */
  112. 'charAt': function (params) {
  113. // Get the index of the character, look it up, and return
  114. var index = this.indexAt(params),
  115. input = this.input,
  116. retVal = input.charAt(index);
  117. return retVal;
  118. }
  119. };
  120. function charProps(input) {
  121. // Create and return a new Indexer with the content
  122. var indexer = new Indexer(input);
  123. return indexer;
  124. }
  125. // Expose Indexer to charProps
  126. charProps.Indexer = Indexer;
  127. // Export charProps
  128. module.exports = charProps;