ScriptFormatter.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * Copyright (C) 2011 Google Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above
  11. * copyright notice, this list of conditions and the following disclaimer
  12. * in the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Google Inc. nor the names of its
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /**
  31. * @interface
  32. */
  33. WebInspector.Formatter = function()
  34. {
  35. }
  36. /**
  37. * @param {WebInspector.ResourceType} contentType
  38. * @return {?WebInspector.Formatter}
  39. */
  40. WebInspector.Formatter.createFormatter = function(contentType)
  41. {
  42. if (contentType === WebInspector.resourceTypes.Script || contentType === WebInspector.resourceTypes.Document)
  43. return new WebInspector.ScriptFormatter();
  44. return new WebInspector.IdentityFormatter();
  45. }
  46. /**
  47. * @param {Array.<number>} lineEndings
  48. * @param {number} lineNumber
  49. * @param {number} columnNumber
  50. * @return {number}
  51. */
  52. WebInspector.Formatter.locationToPosition = function(lineEndings, lineNumber, columnNumber)
  53. {
  54. var position = lineNumber ? lineEndings[lineNumber - 1] + 1 : 0;
  55. return position + columnNumber;
  56. }
  57. /**
  58. * @param {Array.<number>} lineEndings
  59. * @param {number} position
  60. * @return {Array.<number>}
  61. */
  62. WebInspector.Formatter.positionToLocation = function(lineEndings, position)
  63. {
  64. var lineNumber = lineEndings.upperBound(position - 1);
  65. if (!lineNumber)
  66. var columnNumber = position;
  67. else
  68. var columnNumber = position - lineEndings[lineNumber - 1] - 1;
  69. return [lineNumber, columnNumber];
  70. }
  71. WebInspector.Formatter.prototype = {
  72. /**
  73. * @param {string} mimeType
  74. * @param {string} content
  75. * @param {function(string, WebInspector.FormatterSourceMapping)} callback
  76. */
  77. formatContent: function(mimeType, content, callback)
  78. {
  79. }
  80. }
  81. /**
  82. * @constructor
  83. * @implements {WebInspector.Formatter}
  84. */
  85. WebInspector.ScriptFormatter = function()
  86. {
  87. this._tasks = [];
  88. }
  89. WebInspector.ScriptFormatter.prototype = {
  90. /**
  91. * @param {string} mimeType
  92. * @param {string} content
  93. * @param {function(string, WebInspector.FormatterSourceMapping)} callback
  94. */
  95. formatContent: function(mimeType, content, callback)
  96. {
  97. content = content.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, '');
  98. const method = "format";
  99. var parameters = { mimeType: mimeType, content: content, indentString: WebInspector.settings.textEditorIndent.get() };
  100. this._tasks.push({ data: parameters, callback: callback });
  101. this._worker.postMessage({ method: method, params: parameters });
  102. },
  103. _didFormatContent: function(event)
  104. {
  105. var task = this._tasks.shift();
  106. var originalContent = task.data.content;
  107. var formattedContent = event.data.content;
  108. var mapping = event.data["mapping"];
  109. var sourceMapping = new WebInspector.FormatterSourceMappingImpl(originalContent.lineEndings(), formattedContent.lineEndings(), mapping);
  110. task.callback(formattedContent, sourceMapping);
  111. },
  112. /**
  113. * @return {Worker}
  114. */
  115. get _worker()
  116. {
  117. if (!this._cachedWorker) {
  118. this._cachedWorker = new Worker("ScriptFormatterWorker.js");
  119. this._cachedWorker.onmessage = /** @type {function(this:Worker)} */ (this._didFormatContent.bind(this));
  120. }
  121. return this._cachedWorker;
  122. }
  123. }
  124. /**
  125. * @constructor
  126. * @implements {WebInspector.Formatter}
  127. */
  128. WebInspector.IdentityFormatter = function()
  129. {
  130. this._tasks = [];
  131. }
  132. WebInspector.IdentityFormatter.prototype = {
  133. /**
  134. * @param {string} mimeType
  135. * @param {string} content
  136. * @param {function(string, WebInspector.FormatterSourceMapping)} callback
  137. */
  138. formatContent: function(mimeType, content, callback)
  139. {
  140. callback(content, new WebInspector.IdentityFormatterSourceMapping());
  141. }
  142. }
  143. /**
  144. * @constructor
  145. */
  146. WebInspector.FormatterMappingPayload = function()
  147. {
  148. this.original = [];
  149. this.formatted = [];
  150. }
  151. /**
  152. * @interface
  153. */
  154. WebInspector.FormatterSourceMapping = function()
  155. {
  156. }
  157. WebInspector.FormatterSourceMapping.prototype = {
  158. /**
  159. * @param {number} lineNumber
  160. * @param {number=} columnNumber
  161. * @return {Array.<number>}
  162. */
  163. originalToFormatted: function(lineNumber, columnNumber) { },
  164. /**
  165. * @param {number} lineNumber
  166. * @param {number=} columnNumber
  167. * @return {Array.<number>}
  168. */
  169. formattedToOriginal: function(lineNumber, columnNumber) { }
  170. }
  171. /**
  172. * @constructor
  173. * @implements {WebInspector.FormatterSourceMapping}
  174. */
  175. WebInspector.IdentityFormatterSourceMapping = function()
  176. {
  177. }
  178. WebInspector.IdentityFormatterSourceMapping.prototype = {
  179. /**
  180. * @param {number} lineNumber
  181. * @param {number=} columnNumber
  182. * @return {Array.<number>}
  183. */
  184. originalToFormatted: function(lineNumber, columnNumber)
  185. {
  186. return [lineNumber, columnNumber || 0];
  187. },
  188. /**
  189. * @param {number} lineNumber
  190. * @param {number=} columnNumber
  191. * @return {Array.<number>}
  192. */
  193. formattedToOriginal: function(lineNumber, columnNumber)
  194. {
  195. return [lineNumber, columnNumber || 0];
  196. }
  197. }
  198. /**
  199. * @constructor
  200. * @implements {WebInspector.FormatterSourceMapping}
  201. * @param {Array.<number>} originalLineEndings
  202. * @param {Array.<number>} formattedLineEndings
  203. * @param {WebInspector.FormatterMappingPayload} mapping
  204. */
  205. WebInspector.FormatterSourceMappingImpl = function(originalLineEndings, formattedLineEndings, mapping)
  206. {
  207. this._originalLineEndings = originalLineEndings;
  208. this._formattedLineEndings = formattedLineEndings;
  209. this._mapping = mapping;
  210. }
  211. WebInspector.FormatterSourceMappingImpl.prototype = {
  212. /**
  213. * @param {number} lineNumber
  214. * @param {number=} columnNumber
  215. * @return {Array.<number>}
  216. */
  217. originalToFormatted: function(lineNumber, columnNumber)
  218. {
  219. var originalPosition = WebInspector.Formatter.locationToPosition(this._originalLineEndings, lineNumber, columnNumber || 0);
  220. var formattedPosition = this._convertPosition(this._mapping.original, this._mapping.formatted, originalPosition || 0);
  221. return WebInspector.Formatter.positionToLocation(this._formattedLineEndings, formattedPosition);
  222. },
  223. /**
  224. * @param {number} lineNumber
  225. * @param {number=} columnNumber
  226. * @return {Array.<number>}
  227. */
  228. formattedToOriginal: function(lineNumber, columnNumber)
  229. {
  230. var formattedPosition = WebInspector.Formatter.locationToPosition(this._formattedLineEndings, lineNumber, columnNumber || 0);
  231. var originalPosition = this._convertPosition(this._mapping.formatted, this._mapping.original, formattedPosition);
  232. return WebInspector.Formatter.positionToLocation(this._originalLineEndings, originalPosition || 0);
  233. },
  234. /**
  235. * @param {Array.<number>} positions1
  236. * @param {Array.<number>} positions2
  237. * @param {number} position
  238. * @return {number}
  239. */
  240. _convertPosition: function(positions1, positions2, position)
  241. {
  242. var index = positions1.upperBound(position) - 1;
  243. var convertedPosition = positions2[index] + position - positions1[index];
  244. if (index < positions2.length - 1 && convertedPosition > positions2[index + 1])
  245. convertedPosition = positions2[index + 1];
  246. return convertedPosition;
  247. }
  248. }