diff --git a/src/Buffer.test.ts b/src/Buffer.test.ts index 3d39e5ac..93650dab 100644 --- a/src/Buffer.test.ts +++ b/src/Buffer.test.ts @@ -1278,7 +1278,7 @@ describe('Buffer', () => { const s = terminal.buffer.iterator(true).next().content; assert.equal(input, s); for (let i = 10; i < input.length; ++i) { - const bufferIndex = terminal.buffer.stringIndexToBufferIndex(0, i); + const bufferIndex = terminal.buffer.stringIndexToBufferIndex(0, i, true); const j = (i - 0) << 1; assert.deepEqual([(j / terminal.cols) | 0, j % terminal.cols], bufferIndex); } @@ -1290,7 +1290,7 @@ describe('Buffer', () => { const s = terminal.buffer.iterator(true).next().content; assert.equal(input, s); for (let i = 0; i < input.length; ++i) { - const bufferIndex = terminal.buffer.stringIndexToBufferIndex(0, i); + const bufferIndex = terminal.buffer.stringIndexToBufferIndex(0, i, true); assert.equal(input[i], terminal.buffer.lines.get(bufferIndex[0]).loadCell(bufferIndex[1], new CellData()).chars); } }); @@ -1302,7 +1302,7 @@ describe('Buffer', () => { const s = terminal.buffer.iterator(true).next().content; assert.equal(input, s); for (let i = 0; i < input.length; ++i) { - const bufferIndex = terminal.buffer.stringIndexToBufferIndex(0, i); + const bufferIndex = terminal.buffer.stringIndexToBufferIndex(0, i, true); assert.equal( (!(i % 3)) ? input[i] @@ -1312,6 +1312,13 @@ describe('Buffer', () => { terminal.buffer.lines.get(bufferIndex[0]).loadCell(bufferIndex[1], new CellData()).chars); } }); + + it('should handle \t in lines correctly', () => { + const input = '\thttps://google.de'; + terminal.writeSync(input); + const s = terminal.buffer.iterator(true).next().content; + assert.equal(s, Array(terminal.getOption('tabStopWidth') + 1).join(' ') + 'https://google.de'); + }); }); describe('BufferStringIterator', function(): void { it('iterator does not overflow buffer limits', function(): void { diff --git a/src/Buffer.ts b/src/Buffer.ts index e91ee7c0..1555d505 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -489,14 +489,19 @@ export class Buffer implements IBuffer { * @param stringIndex index within the string * @param startCol column offset the string was retrieved from */ - public stringIndexToBufferIndex(lineIndex: number, stringIndex: number): BufferIndex { + public stringIndexToBufferIndex(lineIndex: number, stringIndex: number, trimRight: boolean = false): BufferIndex { while (stringIndex) { const line = this.lines.get(lineIndex); if (!line) { return [-1, -1]; } - for (let i = 0; i < line.length; ++i) { - stringIndex -= line.getString(i).length; + const length = (trimRight) ? line.getTrimmedLength() : line.length; + for (let i = 0; i < length; ++i) { + if (line.get(i)[CHAR_DATA_WIDTH_INDEX]) { + // empty cells report a string length of 0, but get replaced + // with a whitespace in translateToString, thus replace with 1 + stringIndex -= line.get(i)[CHAR_DATA_CHAR_INDEX].length || 1; + } if (stringIndex < 0) { return [lineIndex, i]; } diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index dc9ebbae..d813bc5f 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -443,7 +443,9 @@ declare module 'xterm' { addDisposableListener(type: string, handler: (...args: any[]) => void): IDisposable; /** - * Resizes the terminal. + * Resizes the terminal. It's best practice to debounce calls to resize, + * this will help ensure that the pty can respond to the resize event + * before another one occurs. * @param x The number of columns to resize to. * @param y The number of rows to resize to. */