mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Mostly emoji selection
Selection is not aware of characters that have a size greater than 1. When the emoji is at the start of the selection it still doesn't work. Fixes #1015
This commit is contained in:
+30
-8
@@ -208,9 +208,19 @@ export class Buffer implements IBuffer {
|
||||
public translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol: number = 0, endCol: number = null): string {
|
||||
// Get full line
|
||||
let lineString = '';
|
||||
let widthAdjustedStartCol = startCol;
|
||||
let widthAdjustedEndCol = endCol;
|
||||
const line = this.lines.get(lineIndex);
|
||||
if (!line) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Initialize column and index values. Column values represent the actual
|
||||
// cell column, indexes represent the index in the string. Indexes are
|
||||
// needed here because some chars are 0 characters long (eg. after wide
|
||||
// chars) and some chars are longer than 1 characters long (eg. emojis).
|
||||
let startIndex = startCol;
|
||||
endCol = endCol || line.length;
|
||||
let endIndex = endCol;
|
||||
|
||||
for (let i = 0; i < line.length; i++) {
|
||||
const char = line[i];
|
||||
lineString += char[CHAR_DATA_CHAR_INDEX];
|
||||
@@ -218,29 +228,41 @@ export class Buffer implements IBuffer {
|
||||
// column indexes
|
||||
if (char[CHAR_DATA_WIDTH_INDEX] === 0) {
|
||||
if (startCol >= i) {
|
||||
widthAdjustedStartCol--;
|
||||
startIndex -= char[CHAR_DATA_CHAR_INDEX].length;
|
||||
}
|
||||
if (endCol >= i) {
|
||||
widthAdjustedEndCol--;
|
||||
endIndex -= char[CHAR_DATA_CHAR_INDEX].length;
|
||||
}
|
||||
} else {
|
||||
// Adjust the columns to take glyphs that are represented by multiple
|
||||
// code points into account.
|
||||
if (char[CHAR_DATA_CHAR_INDEX].length > 1) {
|
||||
if (startCol >= i) {
|
||||
startIndex += char[CHAR_DATA_CHAR_INDEX].length - 1;
|
||||
}
|
||||
if (endCol >= i) {
|
||||
endIndex += char[CHAR_DATA_CHAR_INDEX].length - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: startCol needs to be emoji-aware, currently each emoji code point is
|
||||
// consuming addition space in the selection text
|
||||
}
|
||||
|
||||
// Calculate the final end col by trimming whitespace on the right of the
|
||||
// line if needed.
|
||||
let finalEndCol = widthAdjustedEndCol || line.length;
|
||||
if (trimRight) {
|
||||
const rightWhitespaceIndex = lineString.search(/\s+$/);
|
||||
if (rightWhitespaceIndex !== -1) {
|
||||
finalEndCol = Math.min(finalEndCol, rightWhitespaceIndex);
|
||||
endIndex = Math.min(endIndex, rightWhitespaceIndex);
|
||||
}
|
||||
// Return the empty string if only trimmed whitespace is selected
|
||||
if (finalEndCol <= widthAdjustedStartCol) {
|
||||
if (endIndex <= startIndex) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return lineString.substring(widthAdjustedStartCol, finalEndCol);
|
||||
return lineString.substring(startIndex, endIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+42
-5
@@ -11,7 +11,7 @@ import { EventEmitter } from './EventEmitter';
|
||||
import { ITerminal, ICircularList, ISelectionManager, IBuffer } from './Interfaces';
|
||||
import { SelectionModel } from './SelectionModel';
|
||||
import { LineData } from './Types';
|
||||
import { CHAR_DATA_WIDTH_INDEX } from './Buffer';
|
||||
import { CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX } from './Buffer';
|
||||
|
||||
/**
|
||||
* The number of pixels the mouse needs to be above or below the viewport in
|
||||
@@ -281,6 +281,9 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
|
||||
// Convert to 0-based
|
||||
coords[0]--;
|
||||
coords[1]--;
|
||||
|
||||
console.log('coords', coords);
|
||||
|
||||
// Convert viewport coords to buffer coords
|
||||
coords[1] += this._terminal.buffer.ydisp;
|
||||
return coords;
|
||||
@@ -545,9 +548,16 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
|
||||
for (let i = 0; coords[0] >= i; i++) {
|
||||
const char = bufferLine[i];
|
||||
if (char[CHAR_DATA_WIDTH_INDEX] === 0) {
|
||||
// Wide characters aren't included in the line string so decrement the index
|
||||
charIndex--;
|
||||
// }
|
||||
} else if (char[CHAR_DATA_CHAR_INDEX].length > 1) {
|
||||
console.log('char length > 1', char[CHAR_DATA_CHAR_INDEX], char[CHAR_DATA_CHAR_INDEX].length);
|
||||
// Emojis take up multiple characters, so adjust accordingly
|
||||
charIndex += char[CHAR_DATA_CHAR_INDEX].length - 1;
|
||||
}
|
||||
}
|
||||
console.log('character index: ', charIndex);
|
||||
return charIndex;
|
||||
}
|
||||
|
||||
@@ -606,20 +616,47 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
|
||||
endCol++;
|
||||
}
|
||||
// Expand the string in both directions until a space is hit
|
||||
while (startIndex > 0 && !this._isCharWordSeparator(line.charAt(startIndex - 1))) {
|
||||
if (bufferLine[startCol - 1][CHAR_DATA_WIDTH_INDEX] === 0) {
|
||||
let nextCharData = startIndex > 0 ? bufferLine[startCol - 1] : null;
|
||||
|
||||
|
||||
|
||||
// TODO: Need to make sure that characters whose strings are longer than 1 get compensated for
|
||||
// Double click words should expand to the spaces.
|
||||
|
||||
|
||||
// while (startIndex > 0 && !this._isCharWordSeparator(line.charAt(startIndex - 1))) {
|
||||
console.log('start char: ' + bufferLine[startCol]);
|
||||
console.log('scan backwards');
|
||||
console.log(' startIndex:',startIndex);
|
||||
while (startIndex > 0 && !this._isCharWordSeparator(bufferLine[startCol - 1][CHAR_DATA_CHAR_INDEX])) {
|
||||
const char = bufferLine[startCol - 1];
|
||||
console.log(' char: ' + char);
|
||||
if (char[CHAR_DATA_WIDTH_INDEX] === 0) {
|
||||
// If the next character is a wide char, record it and skip the column
|
||||
leftWideCharCount++;
|
||||
startCol--;
|
||||
} else if (char[CHAR_DATA_CHAR_INDEX].length > 1) {
|
||||
startIndex -= char[CHAR_DATA_CHAR_INDEX].length - 1;
|
||||
console.log('x', char[CHAR_DATA_CHAR_INDEX], char[CHAR_DATA_CHAR_INDEX].length);
|
||||
}
|
||||
startIndex--;
|
||||
startCol--;
|
||||
}
|
||||
while (endIndex + 1 < line.length && !this._isCharWordSeparator(line.charAt(endIndex + 1))) {
|
||||
if (bufferLine[endCol + 1][CHAR_DATA_WIDTH_INDEX] === 2) {
|
||||
console.log('scan forwards');
|
||||
// while (endIndex + 1 < line.length && !this._isCharWordSeparator(line.charAt(endIndex + 1))) {
|
||||
console.log(' first checking: ',bufferLine[endCol + 1]);
|
||||
console.log(' endIndex:',endIndex);
|
||||
console.log(' line:',line);
|
||||
console.log(' line.length:',line.length);
|
||||
while (endIndex + 1 < line.length && !this._isCharWordSeparator(bufferLine[endCol + 1][CHAR_DATA_CHAR_INDEX])) {
|
||||
const char = bufferLine[endCol + 1];
|
||||
console.log(' char: ' + char);
|
||||
if (char[CHAR_DATA_WIDTH_INDEX] === 2) {
|
||||
// If the next character is a wide char, record it and skip the column
|
||||
rightWideCharCount++;
|
||||
endCol++;
|
||||
} else if (char[CHAR_DATA_CHAR_INDEX].length > 1) {
|
||||
startIndex += char[CHAR_DATA_CHAR_INDEX].length - 1;
|
||||
}
|
||||
endIndex++;
|
||||
endCol++;
|
||||
|
||||
Reference in New Issue
Block a user