| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import * as strings from '../../../base/common/strings.js';
- /**
- * A column in a position is the gap between two adjacent characters. The methods here
- * work with a concept called "visible column". A visible column is a very rough approximation
- * of the horizontal screen position of a column. For example, using a tab size of 4:
- * ```txt
- * |<TAB>|<TAB>|T|ext
- * | | | \---- column = 4, visible column = 9
- * | | \------ column = 3, visible column = 8
- * | \------------ column = 2, visible column = 4
- * \------------------ column = 1, visible column = 0
- * ```
- *
- * **NOTE**: Visual columns do not work well for RTL text or variable-width fonts or characters.
- *
- * **NOTE**: These methods work and make sense both on the model and on the view model.
- */
- export class CursorColumns {
- static _nextVisibleColumn(codePoint, visibleColumn, tabSize) {
- if (codePoint === 9 /* CharCode.Tab */) {
- return CursorColumns.nextRenderTabStop(visibleColumn, tabSize);
- }
- if (strings.isFullWidthCharacter(codePoint) || strings.isEmojiImprecise(codePoint)) {
- return visibleColumn + 2;
- }
- return visibleColumn + 1;
- }
- /**
- * Returns a visible column from a column.
- * @see {@link CursorColumns}
- */
- static visibleColumnFromColumn(lineContent, column, tabSize) {
- const textLen = Math.min(column - 1, lineContent.length);
- const text = lineContent.substring(0, textLen);
- const iterator = new strings.GraphemeIterator(text);
- let result = 0;
- while (!iterator.eol()) {
- const codePoint = strings.getNextCodePoint(text, textLen, iterator.offset);
- iterator.nextGraphemeLength();
- result = this._nextVisibleColumn(codePoint, result, tabSize);
- }
- return result;
- }
- /**
- * Returns a column from a visible column.
- * @see {@link CursorColumns}
- */
- static columnFromVisibleColumn(lineContent, visibleColumn, tabSize) {
- if (visibleColumn <= 0) {
- return 1;
- }
- const lineContentLength = lineContent.length;
- const iterator = new strings.GraphemeIterator(lineContent);
- let beforeVisibleColumn = 0;
- let beforeColumn = 1;
- while (!iterator.eol()) {
- const codePoint = strings.getNextCodePoint(lineContent, lineContentLength, iterator.offset);
- iterator.nextGraphemeLength();
- const afterVisibleColumn = this._nextVisibleColumn(codePoint, beforeVisibleColumn, tabSize);
- const afterColumn = iterator.offset + 1;
- if (afterVisibleColumn >= visibleColumn) {
- const beforeDelta = visibleColumn - beforeVisibleColumn;
- const afterDelta = afterVisibleColumn - visibleColumn;
- if (afterDelta < beforeDelta) {
- return afterColumn;
- }
- else {
- return beforeColumn;
- }
- }
- beforeVisibleColumn = afterVisibleColumn;
- beforeColumn = afterColumn;
- }
- // walked the entire string
- return lineContentLength + 1;
- }
- /**
- * ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns)
- * @see {@link CursorColumns}
- */
- static nextRenderTabStop(visibleColumn, tabSize) {
- return visibleColumn + tabSize - visibleColumn % tabSize;
- }
- /**
- * ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns)
- * @see {@link CursorColumns}
- */
- static nextIndentTabStop(visibleColumn, indentSize) {
- return visibleColumn + indentSize - visibleColumn % indentSize;
- }
- /**
- * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)
- * @see {@link CursorColumns}
- */
- static prevRenderTabStop(column, tabSize) {
- return Math.max(0, column - 1 - (column - 1) % tabSize);
- }
- /**
- * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)
- * @see {@link CursorColumns}
- */
- static prevIndentTabStop(column, indentSize) {
- return Math.max(0, column - 1 - (column - 1) % indentSize);
- }
- }
|