bcede0abff0c2638c08e5a722f7da31e0bb205ca916dccddf833cd94dff790fc522a2ac677acf4b36414c6a0e80efb7cf18c2b6faa5d2651e4d59691abbd1d 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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 { Position } from './core/position.js';
  6. import { Range } from './core/range.js';
  7. import { Selection } from './core/selection.js';
  8. import { createScopedLineTokens } from './languages/supports.js';
  9. import { CursorColumns } from './core/cursorColumns.js';
  10. import { normalizeIndentation } from './core/indentation.js';
  11. const autoCloseAlways = () => true;
  12. const autoCloseNever = () => false;
  13. const autoCloseBeforeWhitespace = (chr) => (chr === ' ' || chr === '\t');
  14. export class CursorConfiguration {
  15. constructor(languageId, modelOptions, configuration, languageConfigurationService) {
  16. this.languageConfigurationService = languageConfigurationService;
  17. this._cursorMoveConfigurationBrand = undefined;
  18. this._languageId = languageId;
  19. const options = configuration.options;
  20. const layoutInfo = options.get(133 /* EditorOption.layoutInfo */);
  21. this.readOnly = options.get(83 /* EditorOption.readOnly */);
  22. this.tabSize = modelOptions.tabSize;
  23. this.indentSize = modelOptions.indentSize;
  24. this.insertSpaces = modelOptions.insertSpaces;
  25. this.stickyTabStops = options.get(106 /* EditorOption.stickyTabStops */);
  26. this.lineHeight = options.get(61 /* EditorOption.lineHeight */);
  27. this.pageSize = Math.max(1, Math.floor(layoutInfo.height / this.lineHeight) - 2);
  28. this.useTabStops = options.get(118 /* EditorOption.useTabStops */);
  29. this.wordSeparators = options.get(119 /* EditorOption.wordSeparators */);
  30. this.emptySelectionClipboard = options.get(33 /* EditorOption.emptySelectionClipboard */);
  31. this.copyWithSyntaxHighlighting = options.get(21 /* EditorOption.copyWithSyntaxHighlighting */);
  32. this.multiCursorMergeOverlapping = options.get(71 /* EditorOption.multiCursorMergeOverlapping */);
  33. this.multiCursorPaste = options.get(73 /* EditorOption.multiCursorPaste */);
  34. this.autoClosingBrackets = options.get(5 /* EditorOption.autoClosingBrackets */);
  35. this.autoClosingQuotes = options.get(8 /* EditorOption.autoClosingQuotes */);
  36. this.autoClosingDelete = options.get(6 /* EditorOption.autoClosingDelete */);
  37. this.autoClosingOvertype = options.get(7 /* EditorOption.autoClosingOvertype */);
  38. this.autoSurround = options.get(11 /* EditorOption.autoSurround */);
  39. this.autoIndent = options.get(9 /* EditorOption.autoIndent */);
  40. this.surroundingPairs = {};
  41. this._electricChars = null;
  42. this.shouldAutoCloseBefore = {
  43. quote: this._getShouldAutoClose(languageId, this.autoClosingQuotes),
  44. bracket: this._getShouldAutoClose(languageId, this.autoClosingBrackets)
  45. };
  46. this.autoClosingPairs = this.languageConfigurationService.getLanguageConfiguration(languageId).getAutoClosingPairs();
  47. const surroundingPairs = this.languageConfigurationService.getLanguageConfiguration(languageId).getSurroundingPairs();
  48. if (surroundingPairs) {
  49. for (const pair of surroundingPairs) {
  50. this.surroundingPairs[pair.open] = pair.close;
  51. }
  52. }
  53. }
  54. static shouldRecreate(e) {
  55. return (e.hasChanged(133 /* EditorOption.layoutInfo */)
  56. || e.hasChanged(119 /* EditorOption.wordSeparators */)
  57. || e.hasChanged(33 /* EditorOption.emptySelectionClipboard */)
  58. || e.hasChanged(71 /* EditorOption.multiCursorMergeOverlapping */)
  59. || e.hasChanged(73 /* EditorOption.multiCursorPaste */)
  60. || e.hasChanged(5 /* EditorOption.autoClosingBrackets */)
  61. || e.hasChanged(8 /* EditorOption.autoClosingQuotes */)
  62. || e.hasChanged(6 /* EditorOption.autoClosingDelete */)
  63. || e.hasChanged(7 /* EditorOption.autoClosingOvertype */)
  64. || e.hasChanged(11 /* EditorOption.autoSurround */)
  65. || e.hasChanged(118 /* EditorOption.useTabStops */)
  66. || e.hasChanged(61 /* EditorOption.lineHeight */)
  67. || e.hasChanged(83 /* EditorOption.readOnly */));
  68. }
  69. get electricChars() {
  70. var _a;
  71. if (!this._electricChars) {
  72. this._electricChars = {};
  73. const electricChars = (_a = this.languageConfigurationService.getLanguageConfiguration(this._languageId).electricCharacter) === null || _a === void 0 ? void 0 : _a.getElectricCharacters();
  74. if (electricChars) {
  75. for (const char of electricChars) {
  76. this._electricChars[char] = true;
  77. }
  78. }
  79. }
  80. return this._electricChars;
  81. }
  82. /**
  83. * Should return opening bracket type to match indentation with
  84. */
  85. onElectricCharacter(character, context, column) {
  86. const scopedLineTokens = createScopedLineTokens(context, column - 1);
  87. const electricCharacterSupport = this.languageConfigurationService.getLanguageConfiguration(scopedLineTokens.languageId).electricCharacter;
  88. if (!electricCharacterSupport) {
  89. return null;
  90. }
  91. return electricCharacterSupport.onElectricCharacter(character, scopedLineTokens, column - scopedLineTokens.firstCharOffset);
  92. }
  93. normalizeIndentation(str) {
  94. return normalizeIndentation(str, this.indentSize, this.insertSpaces);
  95. }
  96. _getShouldAutoClose(languageId, autoCloseConfig) {
  97. switch (autoCloseConfig) {
  98. case 'beforeWhitespace':
  99. return autoCloseBeforeWhitespace;
  100. case 'languageDefined':
  101. return this._getLanguageDefinedShouldAutoClose(languageId);
  102. case 'always':
  103. return autoCloseAlways;
  104. case 'never':
  105. return autoCloseNever;
  106. }
  107. }
  108. _getLanguageDefinedShouldAutoClose(languageId) {
  109. const autoCloseBeforeSet = this.languageConfigurationService.getLanguageConfiguration(languageId).getAutoCloseBeforeSet();
  110. return c => autoCloseBeforeSet.indexOf(c) !== -1;
  111. }
  112. /**
  113. * Returns a visible column from a column.
  114. * @see {@link CursorColumns}
  115. */
  116. visibleColumnFromColumn(model, position) {
  117. return CursorColumns.visibleColumnFromColumn(model.getLineContent(position.lineNumber), position.column, this.tabSize);
  118. }
  119. /**
  120. * Returns a visible column from a column.
  121. * @see {@link CursorColumns}
  122. */
  123. columnFromVisibleColumn(model, lineNumber, visibleColumn) {
  124. const result = CursorColumns.columnFromVisibleColumn(model.getLineContent(lineNumber), visibleColumn, this.tabSize);
  125. const minColumn = model.getLineMinColumn(lineNumber);
  126. if (result < minColumn) {
  127. return minColumn;
  128. }
  129. const maxColumn = model.getLineMaxColumn(lineNumber);
  130. if (result > maxColumn) {
  131. return maxColumn;
  132. }
  133. return result;
  134. }
  135. }
  136. export class CursorState {
  137. constructor(modelState, viewState) {
  138. this._cursorStateBrand = undefined;
  139. this.modelState = modelState;
  140. this.viewState = viewState;
  141. }
  142. static fromModelState(modelState) {
  143. return new PartialModelCursorState(modelState);
  144. }
  145. static fromViewState(viewState) {
  146. return new PartialViewCursorState(viewState);
  147. }
  148. static fromModelSelection(modelSelection) {
  149. const selection = Selection.liftSelection(modelSelection);
  150. const modelState = new SingleCursorState(Range.fromPositions(selection.getSelectionStart()), 0, selection.getPosition(), 0);
  151. return CursorState.fromModelState(modelState);
  152. }
  153. static fromModelSelections(modelSelections) {
  154. const states = [];
  155. for (let i = 0, len = modelSelections.length; i < len; i++) {
  156. states[i] = this.fromModelSelection(modelSelections[i]);
  157. }
  158. return states;
  159. }
  160. equals(other) {
  161. return (this.viewState.equals(other.viewState) && this.modelState.equals(other.modelState));
  162. }
  163. }
  164. export class PartialModelCursorState {
  165. constructor(modelState) {
  166. this.modelState = modelState;
  167. this.viewState = null;
  168. }
  169. }
  170. export class PartialViewCursorState {
  171. constructor(viewState) {
  172. this.modelState = null;
  173. this.viewState = viewState;
  174. }
  175. }
  176. /**
  177. * Represents the cursor state on either the model or on the view model.
  178. */
  179. export class SingleCursorState {
  180. constructor(selectionStart, selectionStartLeftoverVisibleColumns, position, leftoverVisibleColumns) {
  181. this._singleCursorStateBrand = undefined;
  182. this.selectionStart = selectionStart;
  183. this.selectionStartLeftoverVisibleColumns = selectionStartLeftoverVisibleColumns;
  184. this.position = position;
  185. this.leftoverVisibleColumns = leftoverVisibleColumns;
  186. this.selection = SingleCursorState._computeSelection(this.selectionStart, this.position);
  187. }
  188. equals(other) {
  189. return (this.selectionStartLeftoverVisibleColumns === other.selectionStartLeftoverVisibleColumns
  190. && this.leftoverVisibleColumns === other.leftoverVisibleColumns
  191. && this.position.equals(other.position)
  192. && this.selectionStart.equalsRange(other.selectionStart));
  193. }
  194. hasSelection() {
  195. return (!this.selection.isEmpty() || !this.selectionStart.isEmpty());
  196. }
  197. move(inSelectionMode, lineNumber, column, leftoverVisibleColumns) {
  198. if (inSelectionMode) {
  199. // move just position
  200. return new SingleCursorState(this.selectionStart, this.selectionStartLeftoverVisibleColumns, new Position(lineNumber, column), leftoverVisibleColumns);
  201. }
  202. else {
  203. // move everything
  204. return new SingleCursorState(new Range(lineNumber, column, lineNumber, column), leftoverVisibleColumns, new Position(lineNumber, column), leftoverVisibleColumns);
  205. }
  206. }
  207. static _computeSelection(selectionStart, position) {
  208. if (selectionStart.isEmpty() || !position.isBeforeOrEqual(selectionStart.getStartPosition())) {
  209. return Selection.fromPositions(selectionStart.getStartPosition(), position);
  210. }
  211. else {
  212. return Selection.fromPositions(selectionStart.getEndPosition(), position);
  213. }
  214. }
  215. }
  216. export class EditOperationResult {
  217. constructor(type, commands, opts) {
  218. this._editOperationResultBrand = undefined;
  219. this.type = type;
  220. this.commands = commands;
  221. this.shouldPushStackElementBefore = opts.shouldPushStackElementBefore;
  222. this.shouldPushStackElementAfter = opts.shouldPushStackElementAfter;
  223. }
  224. }
  225. export function isQuote(ch) {
  226. return (ch === '\'' || ch === '"' || ch === '`');
  227. }