viewModelLines.js 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import * as arrays from '../../../base/common/arrays.js';
  6. import { Position } from '../core/position.js';
  7. import { Range } from '../core/range.js';
  8. import { IndentGuide, IndentGuideHorizontalLine } from '../model.js';
  9. import { ModelDecorationOptions } from '../model/textModel.js';
  10. import { LineInjectedText } from '../model/textModelEvents.js';
  11. import * as viewEvents from '../view/viewEvents.js';
  12. import { createModelLineProjection } from './modelLineProjection.js';
  13. import { ConstantTimePrefixSumComputer } from './prefixSumComputer.js';
  14. import { ViewLineData } from './viewModel.js';
  15. export class ViewModelLinesFromProjectedModel {
  16. constructor(editorId, model, domLineBreaksComputerFactory, monospaceLineBreaksComputerFactory, fontInfo, tabSize, wrappingStrategy, wrappingColumn, wrappingIndent) {
  17. this._editorId = editorId;
  18. this.model = model;
  19. this._validModelVersionId = -1;
  20. this._domLineBreaksComputerFactory = domLineBreaksComputerFactory;
  21. this._monospaceLineBreaksComputerFactory = monospaceLineBreaksComputerFactory;
  22. this.fontInfo = fontInfo;
  23. this.tabSize = tabSize;
  24. this.wrappingStrategy = wrappingStrategy;
  25. this.wrappingColumn = wrappingColumn;
  26. this.wrappingIndent = wrappingIndent;
  27. this._constructLines(/*resetHiddenAreas*/ true, null);
  28. }
  29. dispose() {
  30. this.hiddenAreasDecorationIds = this.model.deltaDecorations(this.hiddenAreasDecorationIds, []);
  31. }
  32. createCoordinatesConverter() {
  33. return new CoordinatesConverter(this);
  34. }
  35. _constructLines(resetHiddenAreas, previousLineBreaks) {
  36. this.modelLineProjections = [];
  37. if (resetHiddenAreas) {
  38. this.hiddenAreasDecorationIds = this.model.deltaDecorations(this.hiddenAreasDecorationIds, []);
  39. }
  40. const linesContent = this.model.getLinesContent();
  41. const injectedTextDecorations = this.model.getInjectedTextDecorations(this._editorId);
  42. const lineCount = linesContent.length;
  43. const lineBreaksComputer = this.createLineBreaksComputer();
  44. const injectedTextQueue = new arrays.ArrayQueue(LineInjectedText.fromDecorations(injectedTextDecorations));
  45. for (let i = 0; i < lineCount; i++) {
  46. const lineInjectedText = injectedTextQueue.takeWhile(t => t.lineNumber === i + 1);
  47. lineBreaksComputer.addRequest(linesContent[i], lineInjectedText, previousLineBreaks ? previousLineBreaks[i] : null);
  48. }
  49. const linesBreaks = lineBreaksComputer.finalize();
  50. let values = [];
  51. let hiddenAreas = this.hiddenAreasDecorationIds.map((areaId) => this.model.getDecorationRange(areaId)).sort(Range.compareRangesUsingStarts);
  52. let hiddenAreaStart = 1, hiddenAreaEnd = 0;
  53. let hiddenAreaIdx = -1;
  54. let nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : lineCount + 2;
  55. for (let i = 0; i < lineCount; i++) {
  56. let lineNumber = i + 1;
  57. if (lineNumber === nextLineNumberToUpdateHiddenArea) {
  58. hiddenAreaIdx++;
  59. hiddenAreaStart = hiddenAreas[hiddenAreaIdx].startLineNumber;
  60. hiddenAreaEnd = hiddenAreas[hiddenAreaIdx].endLineNumber;
  61. nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : lineCount + 2;
  62. }
  63. let isInHiddenArea = (lineNumber >= hiddenAreaStart && lineNumber <= hiddenAreaEnd);
  64. let line = createModelLineProjection(linesBreaks[i], !isInHiddenArea);
  65. values[i] = line.getViewLineCount();
  66. this.modelLineProjections[i] = line;
  67. }
  68. this._validModelVersionId = this.model.getVersionId();
  69. this.projectedModelLineLineCounts = new ConstantTimePrefixSumComputer(values);
  70. }
  71. getHiddenAreas() {
  72. return this.hiddenAreasDecorationIds.map((decId) => this.model.getDecorationRange(decId));
  73. }
  74. setHiddenAreas(_ranges) {
  75. const validatedRanges = _ranges.map(r => this.model.validateRange(r));
  76. let newRanges = normalizeLineRanges(validatedRanges);
  77. // TODO@Martin: Please stop calling this method on each model change!
  78. // This checks if there really was a change
  79. let oldRanges = this.hiddenAreasDecorationIds.map((areaId) => this.model.getDecorationRange(areaId)).sort(Range.compareRangesUsingStarts);
  80. if (newRanges.length === oldRanges.length) {
  81. let hasDifference = false;
  82. for (let i = 0; i < newRanges.length; i++) {
  83. if (!newRanges[i].equalsRange(oldRanges[i])) {
  84. hasDifference = true;
  85. break;
  86. }
  87. }
  88. if (!hasDifference) {
  89. return false;
  90. }
  91. }
  92. const newDecorations = newRanges.map((r) => ({
  93. range: r,
  94. options: ModelDecorationOptions.EMPTY,
  95. }));
  96. this.hiddenAreasDecorationIds = this.model.deltaDecorations(this.hiddenAreasDecorationIds, newDecorations);
  97. let hiddenAreas = newRanges;
  98. let hiddenAreaStart = 1, hiddenAreaEnd = 0;
  99. let hiddenAreaIdx = -1;
  100. let nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : this.modelLineProjections.length + 2;
  101. let hasVisibleLine = false;
  102. for (let i = 0; i < this.modelLineProjections.length; i++) {
  103. let lineNumber = i + 1;
  104. if (lineNumber === nextLineNumberToUpdateHiddenArea) {
  105. hiddenAreaIdx++;
  106. hiddenAreaStart = hiddenAreas[hiddenAreaIdx].startLineNumber;
  107. hiddenAreaEnd = hiddenAreas[hiddenAreaIdx].endLineNumber;
  108. nextLineNumberToUpdateHiddenArea = (hiddenAreaIdx + 1 < hiddenAreas.length) ? hiddenAreaEnd + 1 : this.modelLineProjections.length + 2;
  109. }
  110. let lineChanged = false;
  111. if (lineNumber >= hiddenAreaStart && lineNumber <= hiddenAreaEnd) {
  112. // Line should be hidden
  113. if (this.modelLineProjections[i].isVisible()) {
  114. this.modelLineProjections[i] = this.modelLineProjections[i].setVisible(false);
  115. lineChanged = true;
  116. }
  117. }
  118. else {
  119. hasVisibleLine = true;
  120. // Line should be visible
  121. if (!this.modelLineProjections[i].isVisible()) {
  122. this.modelLineProjections[i] = this.modelLineProjections[i].setVisible(true);
  123. lineChanged = true;
  124. }
  125. }
  126. if (lineChanged) {
  127. let newOutputLineCount = this.modelLineProjections[i].getViewLineCount();
  128. this.projectedModelLineLineCounts.setValue(i, newOutputLineCount);
  129. }
  130. }
  131. if (!hasVisibleLine) {
  132. // Cannot have everything be hidden => reveal everything!
  133. this.setHiddenAreas([]);
  134. }
  135. return true;
  136. }
  137. modelPositionIsVisible(modelLineNumber, _modelColumn) {
  138. if (modelLineNumber < 1 || modelLineNumber > this.modelLineProjections.length) {
  139. // invalid arguments
  140. return false;
  141. }
  142. return this.modelLineProjections[modelLineNumber - 1].isVisible();
  143. }
  144. getModelLineViewLineCount(modelLineNumber) {
  145. if (modelLineNumber < 1 || modelLineNumber > this.modelLineProjections.length) {
  146. // invalid arguments
  147. return 1;
  148. }
  149. return this.modelLineProjections[modelLineNumber - 1].getViewLineCount();
  150. }
  151. setTabSize(newTabSize) {
  152. if (this.tabSize === newTabSize) {
  153. return false;
  154. }
  155. this.tabSize = newTabSize;
  156. this._constructLines(/*resetHiddenAreas*/ false, null);
  157. return true;
  158. }
  159. setWrappingSettings(fontInfo, wrappingStrategy, wrappingColumn, wrappingIndent) {
  160. const equalFontInfo = this.fontInfo.equals(fontInfo);
  161. const equalWrappingStrategy = (this.wrappingStrategy === wrappingStrategy);
  162. const equalWrappingColumn = (this.wrappingColumn === wrappingColumn);
  163. const equalWrappingIndent = (this.wrappingIndent === wrappingIndent);
  164. if (equalFontInfo && equalWrappingStrategy && equalWrappingColumn && equalWrappingIndent) {
  165. return false;
  166. }
  167. const onlyWrappingColumnChanged = (equalFontInfo && equalWrappingStrategy && !equalWrappingColumn && equalWrappingIndent);
  168. this.fontInfo = fontInfo;
  169. this.wrappingStrategy = wrappingStrategy;
  170. this.wrappingColumn = wrappingColumn;
  171. this.wrappingIndent = wrappingIndent;
  172. let previousLineBreaks = null;
  173. if (onlyWrappingColumnChanged) {
  174. previousLineBreaks = [];
  175. for (let i = 0, len = this.modelLineProjections.length; i < len; i++) {
  176. previousLineBreaks[i] = this.modelLineProjections[i].getLineBreakData();
  177. }
  178. }
  179. this._constructLines(/*resetHiddenAreas*/ false, previousLineBreaks);
  180. return true;
  181. }
  182. createLineBreaksComputer() {
  183. const lineBreaksComputerFactory = (this.wrappingStrategy === 'advanced'
  184. ? this._domLineBreaksComputerFactory
  185. : this._monospaceLineBreaksComputerFactory);
  186. return lineBreaksComputerFactory.createLineBreaksComputer(this.fontInfo, this.tabSize, this.wrappingColumn, this.wrappingIndent);
  187. }
  188. onModelFlushed() {
  189. this._constructLines(/*resetHiddenAreas*/ true, null);
  190. }
  191. onModelLinesDeleted(versionId, fromLineNumber, toLineNumber) {
  192. if (!versionId || versionId <= this._validModelVersionId) {
  193. // Here we check for versionId in case the lines were reconstructed in the meantime.
  194. // We don't want to apply stale change events on top of a newer read model state.
  195. return null;
  196. }
  197. let outputFromLineNumber = (fromLineNumber === 1 ? 1 : this.projectedModelLineLineCounts.getPrefixSum(fromLineNumber - 1) + 1);
  198. let outputToLineNumber = this.projectedModelLineLineCounts.getPrefixSum(toLineNumber);
  199. this.modelLineProjections.splice(fromLineNumber - 1, toLineNumber - fromLineNumber + 1);
  200. this.projectedModelLineLineCounts.removeValues(fromLineNumber - 1, toLineNumber - fromLineNumber + 1);
  201. return new viewEvents.ViewLinesDeletedEvent(outputFromLineNumber, outputToLineNumber);
  202. }
  203. onModelLinesInserted(versionId, fromLineNumber, _toLineNumber, lineBreaks) {
  204. if (!versionId || versionId <= this._validModelVersionId) {
  205. // Here we check for versionId in case the lines were reconstructed in the meantime.
  206. // We don't want to apply stale change events on top of a newer read model state.
  207. return null;
  208. }
  209. // cannot use this.getHiddenAreas() because those decorations have already seen the effect of this model change
  210. const isInHiddenArea = (fromLineNumber > 2 && !this.modelLineProjections[fromLineNumber - 2].isVisible());
  211. let outputFromLineNumber = (fromLineNumber === 1 ? 1 : this.projectedModelLineLineCounts.getPrefixSum(fromLineNumber - 1) + 1);
  212. let totalOutputLineCount = 0;
  213. let insertLines = [];
  214. let insertPrefixSumValues = [];
  215. for (let i = 0, len = lineBreaks.length; i < len; i++) {
  216. let line = createModelLineProjection(lineBreaks[i], !isInHiddenArea);
  217. insertLines.push(line);
  218. let outputLineCount = line.getViewLineCount();
  219. totalOutputLineCount += outputLineCount;
  220. insertPrefixSumValues[i] = outputLineCount;
  221. }
  222. // TODO@Alex: use arrays.arrayInsert
  223. this.modelLineProjections =
  224. this.modelLineProjections.slice(0, fromLineNumber - 1)
  225. .concat(insertLines)
  226. .concat(this.modelLineProjections.slice(fromLineNumber - 1));
  227. this.projectedModelLineLineCounts.insertValues(fromLineNumber - 1, insertPrefixSumValues);
  228. return new viewEvents.ViewLinesInsertedEvent(outputFromLineNumber, outputFromLineNumber + totalOutputLineCount - 1);
  229. }
  230. onModelLineChanged(versionId, lineNumber, lineBreakData) {
  231. if (versionId !== null && versionId <= this._validModelVersionId) {
  232. // Here we check for versionId in case the lines were reconstructed in the meantime.
  233. // We don't want to apply stale change events on top of a newer read model state.
  234. return [false, null, null, null];
  235. }
  236. let lineIndex = lineNumber - 1;
  237. let oldOutputLineCount = this.modelLineProjections[lineIndex].getViewLineCount();
  238. let isVisible = this.modelLineProjections[lineIndex].isVisible();
  239. let line = createModelLineProjection(lineBreakData, isVisible);
  240. this.modelLineProjections[lineIndex] = line;
  241. let newOutputLineCount = this.modelLineProjections[lineIndex].getViewLineCount();
  242. let lineMappingChanged = false;
  243. let changeFrom = 0;
  244. let changeTo = -1;
  245. let insertFrom = 0;
  246. let insertTo = -1;
  247. let deleteFrom = 0;
  248. let deleteTo = -1;
  249. if (oldOutputLineCount > newOutputLineCount) {
  250. changeFrom = this.projectedModelLineLineCounts.getPrefixSum(lineNumber - 1) + 1;
  251. changeTo = changeFrom + newOutputLineCount - 1;
  252. deleteFrom = changeTo + 1;
  253. deleteTo = deleteFrom + (oldOutputLineCount - newOutputLineCount) - 1;
  254. lineMappingChanged = true;
  255. }
  256. else if (oldOutputLineCount < newOutputLineCount) {
  257. changeFrom = this.projectedModelLineLineCounts.getPrefixSum(lineNumber - 1) + 1;
  258. changeTo = changeFrom + oldOutputLineCount - 1;
  259. insertFrom = changeTo + 1;
  260. insertTo = insertFrom + (newOutputLineCount - oldOutputLineCount) - 1;
  261. lineMappingChanged = true;
  262. }
  263. else {
  264. changeFrom = this.projectedModelLineLineCounts.getPrefixSum(lineNumber - 1) + 1;
  265. changeTo = changeFrom + newOutputLineCount - 1;
  266. }
  267. this.projectedModelLineLineCounts.setValue(lineIndex, newOutputLineCount);
  268. const viewLinesChangedEvent = (changeFrom <= changeTo ? new viewEvents.ViewLinesChangedEvent(changeFrom, changeTo) : null);
  269. const viewLinesInsertedEvent = (insertFrom <= insertTo ? new viewEvents.ViewLinesInsertedEvent(insertFrom, insertTo) : null);
  270. const viewLinesDeletedEvent = (deleteFrom <= deleteTo ? new viewEvents.ViewLinesDeletedEvent(deleteFrom, deleteTo) : null);
  271. return [lineMappingChanged, viewLinesChangedEvent, viewLinesInsertedEvent, viewLinesDeletedEvent];
  272. }
  273. acceptVersionId(versionId) {
  274. this._validModelVersionId = versionId;
  275. if (this.modelLineProjections.length === 1 && !this.modelLineProjections[0].isVisible()) {
  276. // At least one line must be visible => reset hidden areas
  277. this.setHiddenAreas([]);
  278. }
  279. }
  280. getViewLineCount() {
  281. return this.projectedModelLineLineCounts.getTotalSum();
  282. }
  283. _toValidViewLineNumber(viewLineNumber) {
  284. if (viewLineNumber < 1) {
  285. return 1;
  286. }
  287. const viewLineCount = this.getViewLineCount();
  288. if (viewLineNumber > viewLineCount) {
  289. return viewLineCount;
  290. }
  291. return viewLineNumber | 0;
  292. }
  293. getActiveIndentGuide(viewLineNumber, minLineNumber, maxLineNumber) {
  294. viewLineNumber = this._toValidViewLineNumber(viewLineNumber);
  295. minLineNumber = this._toValidViewLineNumber(minLineNumber);
  296. maxLineNumber = this._toValidViewLineNumber(maxLineNumber);
  297. const modelPosition = this.convertViewPositionToModelPosition(viewLineNumber, this.getViewLineMinColumn(viewLineNumber));
  298. const modelMinPosition = this.convertViewPositionToModelPosition(minLineNumber, this.getViewLineMinColumn(minLineNumber));
  299. const modelMaxPosition = this.convertViewPositionToModelPosition(maxLineNumber, this.getViewLineMinColumn(maxLineNumber));
  300. const result = this.model.getActiveIndentGuide(modelPosition.lineNumber, modelMinPosition.lineNumber, modelMaxPosition.lineNumber);
  301. const viewStartPosition = this.convertModelPositionToViewPosition(result.startLineNumber, 1);
  302. const viewEndPosition = this.convertModelPositionToViewPosition(result.endLineNumber, this.model.getLineMaxColumn(result.endLineNumber));
  303. return {
  304. startLineNumber: viewStartPosition.lineNumber,
  305. endLineNumber: viewEndPosition.lineNumber,
  306. indent: result.indent
  307. };
  308. }
  309. // #region ViewLineInfo
  310. getViewLineInfo(viewLineNumber) {
  311. viewLineNumber = this._toValidViewLineNumber(viewLineNumber);
  312. let r = this.projectedModelLineLineCounts.getIndexOf(viewLineNumber - 1);
  313. let lineIndex = r.index;
  314. let remainder = r.remainder;
  315. return new ViewLineInfo(lineIndex + 1, remainder);
  316. }
  317. getMinColumnOfViewLine(viewLineInfo) {
  318. return this.modelLineProjections[viewLineInfo.modelLineNumber - 1].getViewLineMinColumn(this.model, viewLineInfo.modelLineNumber, viewLineInfo.modelLineWrappedLineIdx);
  319. }
  320. getModelStartPositionOfViewLine(viewLineInfo) {
  321. const line = this.modelLineProjections[viewLineInfo.modelLineNumber - 1];
  322. const minViewColumn = line.getViewLineMinColumn(this.model, viewLineInfo.modelLineNumber, viewLineInfo.modelLineWrappedLineIdx);
  323. const column = line.getModelColumnOfViewPosition(viewLineInfo.modelLineWrappedLineIdx, minViewColumn);
  324. return new Position(viewLineInfo.modelLineNumber, column);
  325. }
  326. getModelEndPositionOfViewLine(viewLineInfo) {
  327. const line = this.modelLineProjections[viewLineInfo.modelLineNumber - 1];
  328. const maxViewColumn = line.getViewLineMaxColumn(this.model, viewLineInfo.modelLineNumber, viewLineInfo.modelLineWrappedLineIdx);
  329. const column = line.getModelColumnOfViewPosition(viewLineInfo.modelLineWrappedLineIdx, maxViewColumn);
  330. return new Position(viewLineInfo.modelLineNumber, column);
  331. }
  332. getViewLineInfosGroupedByModelRanges(viewStartLineNumber, viewEndLineNumber) {
  333. const startViewLine = this.getViewLineInfo(viewStartLineNumber);
  334. const endViewLine = this.getViewLineInfo(viewEndLineNumber);
  335. const result = new Array();
  336. let lastVisibleModelPos = this.getModelStartPositionOfViewLine(startViewLine);
  337. let viewLines = new Array();
  338. for (let curModelLine = startViewLine.modelLineNumber; curModelLine <= endViewLine.modelLineNumber; curModelLine++) {
  339. const line = this.modelLineProjections[curModelLine - 1];
  340. if (line.isVisible()) {
  341. let startOffset = curModelLine === startViewLine.modelLineNumber
  342. ? startViewLine.modelLineWrappedLineIdx
  343. : 0;
  344. let endOffset = curModelLine === endViewLine.modelLineNumber
  345. ? endViewLine.modelLineWrappedLineIdx + 1
  346. : line.getViewLineCount();
  347. for (let i = startOffset; i < endOffset; i++) {
  348. viewLines.push(new ViewLineInfo(curModelLine, i));
  349. }
  350. }
  351. if (!line.isVisible() && lastVisibleModelPos) {
  352. const lastVisibleModelPos2 = new Position(curModelLine - 1, this.model.getLineMaxColumn(curModelLine - 1) + 1);
  353. const modelRange = Range.fromPositions(lastVisibleModelPos, lastVisibleModelPos2);
  354. result.push(new ViewLineInfoGroupedByModelRange(modelRange, viewLines));
  355. viewLines = [];
  356. lastVisibleModelPos = null;
  357. }
  358. else if (line.isVisible() && !lastVisibleModelPos) {
  359. lastVisibleModelPos = new Position(curModelLine, 1);
  360. }
  361. }
  362. if (lastVisibleModelPos) {
  363. const modelRange = Range.fromPositions(lastVisibleModelPos, this.getModelEndPositionOfViewLine(endViewLine));
  364. result.push(new ViewLineInfoGroupedByModelRange(modelRange, viewLines));
  365. }
  366. return result;
  367. }
  368. // #endregion
  369. getViewLinesBracketGuides(viewStartLineNumber, viewEndLineNumber, activeViewPosition, options) {
  370. const modelActivePosition = activeViewPosition ? this.convertViewPositionToModelPosition(activeViewPosition.lineNumber, activeViewPosition.column) : null;
  371. const resultPerViewLine = [];
  372. for (const group of this.getViewLineInfosGroupedByModelRanges(viewStartLineNumber, viewEndLineNumber)) {
  373. const modelRangeStartLineNumber = group.modelRange.startLineNumber;
  374. const bracketGuidesPerModelLine = this.model.getLinesBracketGuides(modelRangeStartLineNumber, group.modelRange.endLineNumber, modelActivePosition, options);
  375. for (const viewLineInfo of group.viewLines) {
  376. if (viewLineInfo.isWrappedLineContinuation && this.getMinColumnOfViewLine(viewLineInfo) === 1) {
  377. // Don't add indent guides when the wrapped line continuation has no wrapping-indentation.
  378. resultPerViewLine.push([]);
  379. }
  380. else {
  381. let bracketGuides = bracketGuidesPerModelLine[viewLineInfo.modelLineNumber - modelRangeStartLineNumber];
  382. // visibleColumns stay as they are (this is a bug and needs to be fixed, but it is not a regression)
  383. // model-columns must be converted to view-model columns.
  384. bracketGuides = bracketGuides.map(g => g.horizontalLine ?
  385. new IndentGuide(g.visibleColumn, g.className, new IndentGuideHorizontalLine(g.horizontalLine.top, this.convertModelPositionToViewPosition(viewLineInfo.modelLineNumber, g.horizontalLine.endColumn).column)) : g);
  386. resultPerViewLine.push(bracketGuides);
  387. }
  388. }
  389. }
  390. return resultPerViewLine;
  391. }
  392. getViewLinesIndentGuides(viewStartLineNumber, viewEndLineNumber) {
  393. // TODO: Use the same code as in `getViewLinesBracketGuides`.
  394. // Future TODO: Merge with `getViewLinesBracketGuides`.
  395. // However, this requires more refactoring of indent guides.
  396. viewStartLineNumber = this._toValidViewLineNumber(viewStartLineNumber);
  397. viewEndLineNumber = this._toValidViewLineNumber(viewEndLineNumber);
  398. const modelStart = this.convertViewPositionToModelPosition(viewStartLineNumber, this.getViewLineMinColumn(viewStartLineNumber));
  399. const modelEnd = this.convertViewPositionToModelPosition(viewEndLineNumber, this.getViewLineMaxColumn(viewEndLineNumber));
  400. let result = [];
  401. let resultRepeatCount = [];
  402. let resultRepeatOption = [];
  403. const modelStartLineIndex = modelStart.lineNumber - 1;
  404. const modelEndLineIndex = modelEnd.lineNumber - 1;
  405. let reqStart = null;
  406. for (let modelLineIndex = modelStartLineIndex; modelLineIndex <= modelEndLineIndex; modelLineIndex++) {
  407. const line = this.modelLineProjections[modelLineIndex];
  408. if (line.isVisible()) {
  409. let viewLineStartIndex = line.getViewLineNumberOfModelPosition(0, modelLineIndex === modelStartLineIndex ? modelStart.column : 1);
  410. let viewLineEndIndex = line.getViewLineNumberOfModelPosition(0, this.model.getLineMaxColumn(modelLineIndex + 1));
  411. let count = viewLineEndIndex - viewLineStartIndex + 1;
  412. let option = 0 /* BlockNone */;
  413. if (count > 1 && line.getViewLineMinColumn(this.model, modelLineIndex + 1, viewLineEndIndex) === 1) {
  414. // wrapped lines should block indent guides
  415. option = (viewLineStartIndex === 0 ? 1 /* BlockSubsequent */ : 2 /* BlockAll */);
  416. }
  417. resultRepeatCount.push(count);
  418. resultRepeatOption.push(option);
  419. // merge into previous request
  420. if (reqStart === null) {
  421. reqStart = new Position(modelLineIndex + 1, 0);
  422. }
  423. }
  424. else {
  425. // hit invisible line => flush request
  426. if (reqStart !== null) {
  427. result = result.concat(this.model.getLinesIndentGuides(reqStart.lineNumber, modelLineIndex));
  428. reqStart = null;
  429. }
  430. }
  431. }
  432. if (reqStart !== null) {
  433. result = result.concat(this.model.getLinesIndentGuides(reqStart.lineNumber, modelEnd.lineNumber));
  434. reqStart = null;
  435. }
  436. const viewLineCount = viewEndLineNumber - viewStartLineNumber + 1;
  437. let viewIndents = new Array(viewLineCount);
  438. let currIndex = 0;
  439. for (let i = 0, len = result.length; i < len; i++) {
  440. let value = result[i];
  441. let count = Math.min(viewLineCount - currIndex, resultRepeatCount[i]);
  442. let option = resultRepeatOption[i];
  443. let blockAtIndex;
  444. if (option === 2 /* BlockAll */) {
  445. blockAtIndex = 0;
  446. }
  447. else if (option === 1 /* BlockSubsequent */) {
  448. blockAtIndex = 1;
  449. }
  450. else {
  451. blockAtIndex = count;
  452. }
  453. for (let j = 0; j < count; j++) {
  454. if (j === blockAtIndex) {
  455. value = 0;
  456. }
  457. viewIndents[currIndex++] = value;
  458. }
  459. }
  460. return viewIndents;
  461. }
  462. getViewLineContent(viewLineNumber) {
  463. const info = this.getViewLineInfo(viewLineNumber);
  464. return this.modelLineProjections[info.modelLineNumber - 1].getViewLineContent(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);
  465. }
  466. getViewLineLength(viewLineNumber) {
  467. const info = this.getViewLineInfo(viewLineNumber);
  468. return this.modelLineProjections[info.modelLineNumber - 1].getViewLineLength(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);
  469. }
  470. getViewLineMinColumn(viewLineNumber) {
  471. const info = this.getViewLineInfo(viewLineNumber);
  472. return this.modelLineProjections[info.modelLineNumber - 1].getViewLineMinColumn(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);
  473. }
  474. getViewLineMaxColumn(viewLineNumber) {
  475. const info = this.getViewLineInfo(viewLineNumber);
  476. return this.modelLineProjections[info.modelLineNumber - 1].getViewLineMaxColumn(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);
  477. }
  478. getViewLineData(viewLineNumber) {
  479. const info = this.getViewLineInfo(viewLineNumber);
  480. return this.modelLineProjections[info.modelLineNumber - 1].getViewLineData(this.model, info.modelLineNumber, info.modelLineWrappedLineIdx);
  481. }
  482. getViewLinesData(viewStartLineNumber, viewEndLineNumber, needed) {
  483. viewStartLineNumber = this._toValidViewLineNumber(viewStartLineNumber);
  484. viewEndLineNumber = this._toValidViewLineNumber(viewEndLineNumber);
  485. let start = this.projectedModelLineLineCounts.getIndexOf(viewStartLineNumber - 1);
  486. let viewLineNumber = viewStartLineNumber;
  487. let startModelLineIndex = start.index;
  488. let startRemainder = start.remainder;
  489. let result = [];
  490. for (let modelLineIndex = startModelLineIndex, len = this.model.getLineCount(); modelLineIndex < len; modelLineIndex++) {
  491. let line = this.modelLineProjections[modelLineIndex];
  492. if (!line.isVisible()) {
  493. continue;
  494. }
  495. let fromViewLineIndex = (modelLineIndex === startModelLineIndex ? startRemainder : 0);
  496. let remainingViewLineCount = line.getViewLineCount() - fromViewLineIndex;
  497. let lastLine = false;
  498. if (viewLineNumber + remainingViewLineCount > viewEndLineNumber) {
  499. lastLine = true;
  500. remainingViewLineCount = viewEndLineNumber - viewLineNumber + 1;
  501. }
  502. let toViewLineIndex = fromViewLineIndex + remainingViewLineCount;
  503. line.getViewLinesData(this.model, modelLineIndex + 1, fromViewLineIndex, toViewLineIndex, viewLineNumber - viewStartLineNumber, needed, result);
  504. viewLineNumber += remainingViewLineCount;
  505. if (lastLine) {
  506. break;
  507. }
  508. }
  509. return result;
  510. }
  511. validateViewPosition(viewLineNumber, viewColumn, expectedModelPosition) {
  512. viewLineNumber = this._toValidViewLineNumber(viewLineNumber);
  513. let r = this.projectedModelLineLineCounts.getIndexOf(viewLineNumber - 1);
  514. let lineIndex = r.index;
  515. let remainder = r.remainder;
  516. let line = this.modelLineProjections[lineIndex];
  517. let minColumn = line.getViewLineMinColumn(this.model, lineIndex + 1, remainder);
  518. let maxColumn = line.getViewLineMaxColumn(this.model, lineIndex + 1, remainder);
  519. if (viewColumn < minColumn) {
  520. viewColumn = minColumn;
  521. }
  522. if (viewColumn > maxColumn) {
  523. viewColumn = maxColumn;
  524. }
  525. let computedModelColumn = line.getModelColumnOfViewPosition(remainder, viewColumn);
  526. let computedModelPosition = this.model.validatePosition(new Position(lineIndex + 1, computedModelColumn));
  527. if (computedModelPosition.equals(expectedModelPosition)) {
  528. return new Position(viewLineNumber, viewColumn);
  529. }
  530. return this.convertModelPositionToViewPosition(expectedModelPosition.lineNumber, expectedModelPosition.column);
  531. }
  532. validateViewRange(viewRange, expectedModelRange) {
  533. const validViewStart = this.validateViewPosition(viewRange.startLineNumber, viewRange.startColumn, expectedModelRange.getStartPosition());
  534. const validViewEnd = this.validateViewPosition(viewRange.endLineNumber, viewRange.endColumn, expectedModelRange.getEndPosition());
  535. return new Range(validViewStart.lineNumber, validViewStart.column, validViewEnd.lineNumber, validViewEnd.column);
  536. }
  537. convertViewPositionToModelPosition(viewLineNumber, viewColumn) {
  538. const info = this.getViewLineInfo(viewLineNumber);
  539. let inputColumn = this.modelLineProjections[info.modelLineNumber - 1].getModelColumnOfViewPosition(info.modelLineWrappedLineIdx, viewColumn);
  540. // console.log('out -> in ' + viewLineNumber + ',' + viewColumn + ' ===> ' + (lineIndex+1) + ',' + inputColumn);
  541. return this.model.validatePosition(new Position(info.modelLineNumber, inputColumn));
  542. }
  543. convertViewRangeToModelRange(viewRange) {
  544. const start = this.convertViewPositionToModelPosition(viewRange.startLineNumber, viewRange.startColumn);
  545. const end = this.convertViewPositionToModelPosition(viewRange.endLineNumber, viewRange.endColumn);
  546. return new Range(start.lineNumber, start.column, end.lineNumber, end.column);
  547. }
  548. convertModelPositionToViewPosition(_modelLineNumber, _modelColumn, affinity = 2 /* None */) {
  549. const validPosition = this.model.validatePosition(new Position(_modelLineNumber, _modelColumn));
  550. const inputLineNumber = validPosition.lineNumber;
  551. const inputColumn = validPosition.column;
  552. let lineIndex = inputLineNumber - 1, lineIndexChanged = false;
  553. while (lineIndex > 0 && !this.modelLineProjections[lineIndex].isVisible()) {
  554. lineIndex--;
  555. lineIndexChanged = true;
  556. }
  557. if (lineIndex === 0 && !this.modelLineProjections[lineIndex].isVisible()) {
  558. // Could not reach a real line
  559. // console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + 1 + ',' + 1);
  560. return new Position(1, 1);
  561. }
  562. const deltaLineNumber = 1 + this.projectedModelLineLineCounts.getPrefixSum(lineIndex);
  563. let r;
  564. if (lineIndexChanged) {
  565. r = this.modelLineProjections[lineIndex].getViewPositionOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1), affinity);
  566. }
  567. else {
  568. r = this.modelLineProjections[inputLineNumber - 1].getViewPositionOfModelPosition(deltaLineNumber, inputColumn, affinity);
  569. }
  570. // console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + r.lineNumber + ',' + r);
  571. return r;
  572. }
  573. /**
  574. * @param affinity The affinity in case of an empty range. Has no effect for non-empty ranges.
  575. */
  576. convertModelRangeToViewRange(modelRange, affinity = 0 /* Left */) {
  577. if (modelRange.isEmpty()) {
  578. const start = this.convertModelPositionToViewPosition(modelRange.startLineNumber, modelRange.startColumn, affinity);
  579. return Range.fromPositions(start);
  580. }
  581. else {
  582. const start = this.convertModelPositionToViewPosition(modelRange.startLineNumber, modelRange.startColumn, 1 /* Right */);
  583. const end = this.convertModelPositionToViewPosition(modelRange.endLineNumber, modelRange.endColumn, 0 /* Left */);
  584. return new Range(start.lineNumber, start.column, end.lineNumber, end.column);
  585. }
  586. }
  587. getViewLineNumberOfModelPosition(modelLineNumber, modelColumn) {
  588. let lineIndex = modelLineNumber - 1;
  589. if (this.modelLineProjections[lineIndex].isVisible()) {
  590. // this model line is visible
  591. const deltaLineNumber = 1 + this.projectedModelLineLineCounts.getPrefixSum(lineIndex);
  592. return this.modelLineProjections[lineIndex].getViewLineNumberOfModelPosition(deltaLineNumber, modelColumn);
  593. }
  594. // this model line is not visible
  595. while (lineIndex > 0 && !this.modelLineProjections[lineIndex].isVisible()) {
  596. lineIndex--;
  597. }
  598. if (lineIndex === 0 && !this.modelLineProjections[lineIndex].isVisible()) {
  599. // Could not reach a real line
  600. return 1;
  601. }
  602. const deltaLineNumber = 1 + this.projectedModelLineLineCounts.getPrefixSum(lineIndex);
  603. return this.modelLineProjections[lineIndex].getViewLineNumberOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1));
  604. }
  605. getDecorationsInRange(range, ownerId, filterOutValidation) {
  606. const modelStart = this.convertViewPositionToModelPosition(range.startLineNumber, range.startColumn);
  607. const modelEnd = this.convertViewPositionToModelPosition(range.endLineNumber, range.endColumn);
  608. if (modelEnd.lineNumber - modelStart.lineNumber <= range.endLineNumber - range.startLineNumber) {
  609. // most likely there are no hidden lines => fast path
  610. // fetch decorations from column 1 to cover the case of wrapped lines that have whole line decorations at column 1
  611. return this.model.getDecorationsInRange(new Range(modelStart.lineNumber, 1, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation);
  612. }
  613. let result = [];
  614. const modelStartLineIndex = modelStart.lineNumber - 1;
  615. const modelEndLineIndex = modelEnd.lineNumber - 1;
  616. let reqStart = null;
  617. for (let modelLineIndex = modelStartLineIndex; modelLineIndex <= modelEndLineIndex; modelLineIndex++) {
  618. const line = this.modelLineProjections[modelLineIndex];
  619. if (line.isVisible()) {
  620. // merge into previous request
  621. if (reqStart === null) {
  622. reqStart = new Position(modelLineIndex + 1, modelLineIndex === modelStartLineIndex ? modelStart.column : 1);
  623. }
  624. }
  625. else {
  626. // hit invisible line => flush request
  627. if (reqStart !== null) {
  628. const maxLineColumn = this.model.getLineMaxColumn(modelLineIndex);
  629. result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelLineIndex, maxLineColumn), ownerId, filterOutValidation));
  630. reqStart = null;
  631. }
  632. }
  633. }
  634. if (reqStart !== null) {
  635. result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation));
  636. reqStart = null;
  637. }
  638. result.sort((a, b) => {
  639. const res = Range.compareRangesUsingStarts(a.range, b.range);
  640. if (res === 0) {
  641. if (a.id < b.id) {
  642. return -1;
  643. }
  644. if (a.id > b.id) {
  645. return 1;
  646. }
  647. return 0;
  648. }
  649. return res;
  650. });
  651. // Eliminate duplicate decorations that might have intersected our visible ranges multiple times
  652. let finalResult = [], finalResultLen = 0;
  653. let prevDecId = null;
  654. for (const dec of result) {
  655. const decId = dec.id;
  656. if (prevDecId === decId) {
  657. // skip
  658. continue;
  659. }
  660. prevDecId = decId;
  661. finalResult[finalResultLen++] = dec;
  662. }
  663. return finalResult;
  664. }
  665. getInjectedTextAt(position) {
  666. const info = this.getViewLineInfo(position.lineNumber);
  667. return this.modelLineProjections[info.modelLineNumber - 1].getInjectedTextAt(info.modelLineWrappedLineIdx, position.column);
  668. }
  669. normalizePosition(position, affinity) {
  670. const info = this.getViewLineInfo(position.lineNumber);
  671. return this.modelLineProjections[info.modelLineNumber - 1].normalizePosition(info.modelLineWrappedLineIdx, position, affinity);
  672. }
  673. getLineIndentColumn(lineNumber) {
  674. const info = this.getViewLineInfo(lineNumber);
  675. if (info.modelLineWrappedLineIdx === 0) {
  676. return this.model.getLineIndentColumn(info.modelLineNumber);
  677. }
  678. // wrapped lines have no indentation.
  679. // We deliberately don't handle the case that indentation is wrapped
  680. // to avoid two view lines reporting indentation for the very same model line.
  681. return 0;
  682. }
  683. }
  684. /**
  685. * Overlapping unsorted ranges:
  686. * [ ) [ ) [ )
  687. * [ ) [ )
  688. * ->
  689. * Non overlapping sorted ranges:
  690. * [ ) [ ) [ )
  691. *
  692. * Note: This function only considers line information! Columns are ignored.
  693. */
  694. function normalizeLineRanges(ranges) {
  695. if (ranges.length === 0) {
  696. return [];
  697. }
  698. const sortedRanges = ranges.slice();
  699. sortedRanges.sort(Range.compareRangesUsingStarts);
  700. const result = [];
  701. let currentRangeStart = sortedRanges[0].startLineNumber;
  702. let currentRangeEnd = sortedRanges[0].endLineNumber;
  703. for (let i = 1, len = sortedRanges.length; i < len; i++) {
  704. let range = sortedRanges[i];
  705. if (range.startLineNumber > currentRangeEnd + 1) {
  706. result.push(new Range(currentRangeStart, 1, currentRangeEnd, 1));
  707. currentRangeStart = range.startLineNumber;
  708. currentRangeEnd = range.endLineNumber;
  709. }
  710. else if (range.endLineNumber > currentRangeEnd) {
  711. currentRangeEnd = range.endLineNumber;
  712. }
  713. }
  714. result.push(new Range(currentRangeStart, 1, currentRangeEnd, 1));
  715. return result;
  716. }
  717. /**
  718. * Represents a view line. Can be used to efficiently query more information about it.
  719. */
  720. class ViewLineInfo {
  721. constructor(modelLineNumber, modelLineWrappedLineIdx) {
  722. this.modelLineNumber = modelLineNumber;
  723. this.modelLineWrappedLineIdx = modelLineWrappedLineIdx;
  724. }
  725. get isWrappedLineContinuation() {
  726. return this.modelLineWrappedLineIdx > 0;
  727. }
  728. }
  729. /**
  730. * A list of view lines that have a contiguous span in the model.
  731. */
  732. class ViewLineInfoGroupedByModelRange {
  733. constructor(modelRange, viewLines) {
  734. this.modelRange = modelRange;
  735. this.viewLines = viewLines;
  736. }
  737. }
  738. class CoordinatesConverter {
  739. constructor(lines) {
  740. this._lines = lines;
  741. }
  742. // View -> Model conversion and related methods
  743. convertViewPositionToModelPosition(viewPosition) {
  744. return this._lines.convertViewPositionToModelPosition(viewPosition.lineNumber, viewPosition.column);
  745. }
  746. convertViewRangeToModelRange(viewRange) {
  747. return this._lines.convertViewRangeToModelRange(viewRange);
  748. }
  749. validateViewPosition(viewPosition, expectedModelPosition) {
  750. return this._lines.validateViewPosition(viewPosition.lineNumber, viewPosition.column, expectedModelPosition);
  751. }
  752. validateViewRange(viewRange, expectedModelRange) {
  753. return this._lines.validateViewRange(viewRange, expectedModelRange);
  754. }
  755. // Model -> View conversion and related methods
  756. convertModelPositionToViewPosition(modelPosition, affinity) {
  757. return this._lines.convertModelPositionToViewPosition(modelPosition.lineNumber, modelPosition.column, affinity);
  758. }
  759. convertModelRangeToViewRange(modelRange, affinity) {
  760. return this._lines.convertModelRangeToViewRange(modelRange, affinity);
  761. }
  762. modelPositionIsVisible(modelPosition) {
  763. return this._lines.modelPositionIsVisible(modelPosition.lineNumber, modelPosition.column);
  764. }
  765. getModelLineViewLineCount(modelLineNumber) {
  766. return this._lines.getModelLineViewLineCount(modelLineNumber);
  767. }
  768. getViewLineNumberOfModelPosition(modelLineNumber, modelColumn) {
  769. return this._lines.getViewLineNumberOfModelPosition(modelLineNumber, modelColumn);
  770. }
  771. }
  772. export class ViewModelLinesFromModelAsIs {
  773. constructor(model) {
  774. this.model = model;
  775. }
  776. dispose() {
  777. }
  778. createCoordinatesConverter() {
  779. return new IdentityCoordinatesConverter(this);
  780. }
  781. getHiddenAreas() {
  782. return [];
  783. }
  784. setHiddenAreas(_ranges) {
  785. return false;
  786. }
  787. setTabSize(_newTabSize) {
  788. return false;
  789. }
  790. setWrappingSettings(_fontInfo, _wrappingStrategy, _wrappingColumn, _wrappingIndent) {
  791. return false;
  792. }
  793. createLineBreaksComputer() {
  794. let result = [];
  795. return {
  796. addRequest: (lineText, injectedText, previousLineBreakData) => {
  797. result.push(null);
  798. },
  799. finalize: () => {
  800. return result;
  801. }
  802. };
  803. }
  804. onModelFlushed() {
  805. }
  806. onModelLinesDeleted(_versionId, fromLineNumber, toLineNumber) {
  807. return new viewEvents.ViewLinesDeletedEvent(fromLineNumber, toLineNumber);
  808. }
  809. onModelLinesInserted(_versionId, fromLineNumber, toLineNumber, lineBreaks) {
  810. return new viewEvents.ViewLinesInsertedEvent(fromLineNumber, toLineNumber);
  811. }
  812. onModelLineChanged(_versionId, lineNumber, lineBreakData) {
  813. return [false, new viewEvents.ViewLinesChangedEvent(lineNumber, lineNumber), null, null];
  814. }
  815. acceptVersionId(_versionId) {
  816. }
  817. getViewLineCount() {
  818. return this.model.getLineCount();
  819. }
  820. getActiveIndentGuide(viewLineNumber, _minLineNumber, _maxLineNumber) {
  821. return {
  822. startLineNumber: viewLineNumber,
  823. endLineNumber: viewLineNumber,
  824. indent: 0
  825. };
  826. }
  827. getViewLinesBracketGuides(startLineNumber, endLineNumber, activePosition) {
  828. return new Array(endLineNumber - startLineNumber + 1).fill([]);
  829. }
  830. getViewLinesIndentGuides(viewStartLineNumber, viewEndLineNumber) {
  831. const viewLineCount = viewEndLineNumber - viewStartLineNumber + 1;
  832. let result = new Array(viewLineCount);
  833. for (let i = 0; i < viewLineCount; i++) {
  834. result[i] = 0;
  835. }
  836. return result;
  837. }
  838. getViewLineContent(viewLineNumber) {
  839. return this.model.getLineContent(viewLineNumber);
  840. }
  841. getViewLineLength(viewLineNumber) {
  842. return this.model.getLineLength(viewLineNumber);
  843. }
  844. getViewLineMinColumn(viewLineNumber) {
  845. return this.model.getLineMinColumn(viewLineNumber);
  846. }
  847. getViewLineMaxColumn(viewLineNumber) {
  848. return this.model.getLineMaxColumn(viewLineNumber);
  849. }
  850. getViewLineData(viewLineNumber) {
  851. let lineTokens = this.model.getLineTokens(viewLineNumber);
  852. let lineContent = lineTokens.getLineContent();
  853. return new ViewLineData(lineContent, false, 1, lineContent.length + 1, 0, lineTokens.inflate(), null);
  854. }
  855. getViewLinesData(viewStartLineNumber, viewEndLineNumber, needed) {
  856. const lineCount = this.model.getLineCount();
  857. viewStartLineNumber = Math.min(Math.max(1, viewStartLineNumber), lineCount);
  858. viewEndLineNumber = Math.min(Math.max(1, viewEndLineNumber), lineCount);
  859. let result = [];
  860. for (let lineNumber = viewStartLineNumber; lineNumber <= viewEndLineNumber; lineNumber++) {
  861. let idx = lineNumber - viewStartLineNumber;
  862. if (!needed[idx]) {
  863. result[idx] = null;
  864. }
  865. result[idx] = this.getViewLineData(lineNumber);
  866. }
  867. return result;
  868. }
  869. getDecorationsInRange(range, ownerId, filterOutValidation) {
  870. return this.model.getDecorationsInRange(range, ownerId, filterOutValidation);
  871. }
  872. normalizePosition(position, affinity) {
  873. return this.model.normalizePosition(position, affinity);
  874. }
  875. getLineIndentColumn(lineNumber) {
  876. return this.model.getLineIndentColumn(lineNumber);
  877. }
  878. getInjectedTextAt(position) {
  879. // Identity lines collection does not support injected text.
  880. return null;
  881. }
  882. }
  883. class IdentityCoordinatesConverter {
  884. constructor(lines) {
  885. this._lines = lines;
  886. }
  887. _validPosition(pos) {
  888. return this._lines.model.validatePosition(pos);
  889. }
  890. _validRange(range) {
  891. return this._lines.model.validateRange(range);
  892. }
  893. // View -> Model conversion and related methods
  894. convertViewPositionToModelPosition(viewPosition) {
  895. return this._validPosition(viewPosition);
  896. }
  897. convertViewRangeToModelRange(viewRange) {
  898. return this._validRange(viewRange);
  899. }
  900. validateViewPosition(_viewPosition, expectedModelPosition) {
  901. return this._validPosition(expectedModelPosition);
  902. }
  903. validateViewRange(_viewRange, expectedModelRange) {
  904. return this._validRange(expectedModelRange);
  905. }
  906. // Model -> View conversion and related methods
  907. convertModelPositionToViewPosition(modelPosition) {
  908. return this._validPosition(modelPosition);
  909. }
  910. convertModelRangeToViewRange(modelRange) {
  911. return this._validRange(modelRange);
  912. }
  913. modelPositionIsVisible(modelPosition) {
  914. const lineCount = this._lines.model.getLineCount();
  915. if (modelPosition.lineNumber < 1 || modelPosition.lineNumber > lineCount) {
  916. // invalid arguments
  917. return false;
  918. }
  919. return true;
  920. }
  921. getModelLineViewLineCount(modelLineNumber) {
  922. return 1;
  923. }
  924. getViewLineNumberOfModelPosition(modelLineNumber, modelColumn) {
  925. return modelLineNumber;
  926. }
  927. }