mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-24 05:41:40 +00:00
fix(tui): word-wrap composer input (#17651)
* fix(tui): word-wrap composer input Wrap composer input at word boundaries and anchor the good-vibes heart to the full composer row. * test(tui): cover composer word wrap edge Add regression coverage for moving the next word instead of splitting it at the composer edge.
This commit is contained in:
parent
5e6e8b6af3
commit
98f5be13fa
4 changed files with 170 additions and 96 deletions
|
|
@ -3,7 +3,7 @@ import { describe, expect, it } from 'vitest'
|
|||
import { offsetFromPosition } from '../components/textInput.js'
|
||||
import { composerPromptWidth, cursorLayout, inputVisualHeight, stableComposerColumns } from '../lib/inputMetrics.js'
|
||||
|
||||
describe('cursorLayout — char-wrap parity with wrap-ansi', () => {
|
||||
describe('cursorLayout — word-wrap parity with wrap-ansi', () => {
|
||||
it('places cursor mid-line at its column', () => {
|
||||
expect(cursorLayout('hello world', 6, 40)).toEqual({ column: 6, line: 0 })
|
||||
})
|
||||
|
|
@ -18,12 +18,20 @@ describe('cursorLayout — char-wrap parity with wrap-ansi', () => {
|
|||
expect(cursorLayout('abcdefgh', 8, 8)).toEqual({ column: 0, line: 1 })
|
||||
})
|
||||
|
||||
it('tracks a word across a char-wrap boundary without jumping', () => {
|
||||
// With wordWrap:false, "hello world" at cols=8 is "hello wo\nrld" —
|
||||
// typing incremental letters doesn't reshuffle the word across lines.
|
||||
it('moves words across wrap boundaries instead of splitting them', () => {
|
||||
// With wordWrap:true, "hello wor" at cols=8 is "hello \nwor" rather
|
||||
// than "hello wo\nr".
|
||||
expect(cursorLayout('hello wo', 8, 8)).toEqual({ column: 0, line: 1 })
|
||||
expect(cursorLayout('hello wor', 9, 8)).toEqual({ column: 1, line: 1 })
|
||||
expect(cursorLayout('hello worl', 10, 8)).toEqual({ column: 2, line: 1 })
|
||||
expect(cursorLayout('hello wor', 9, 8)).toEqual({ column: 3, line: 1 })
|
||||
expect(cursorLayout('hello worl', 10, 8)).toEqual({ column: 4, line: 1 })
|
||||
expect(cursorLayout('hello world', 11, 8)).toEqual({ column: 5, line: 1 })
|
||||
})
|
||||
|
||||
it('wraps the next word instead of splitting it at the right edge', () => {
|
||||
const text = 'hello world baby chickens are so cool its really rainy outside but wish'
|
||||
|
||||
expect(cursorLayout(text, text.length, 70)).toEqual({ column: 4, line: 1 })
|
||||
expect(inputVisualHeight(text, 70)).toBe(2)
|
||||
})
|
||||
|
||||
it('honours explicit newlines', () => {
|
||||
|
|
@ -56,7 +64,7 @@ describe('input metrics helpers', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('offsetFromPosition — char-wrap inverse of cursorLayout', () => {
|
||||
describe('offsetFromPosition — word-wrap inverse of cursorLayout', () => {
|
||||
it('returns 0 for empty input', () => {
|
||||
expect(offsetFromPosition('', 0, 0, 10)).toBe(0)
|
||||
})
|
||||
|
|
@ -70,11 +78,23 @@ describe('offsetFromPosition — char-wrap inverse of cursorLayout', () => {
|
|||
})
|
||||
|
||||
it('maps clicks on a wrapped second row at cols boundary', () => {
|
||||
// "abcdefghij" at cols=8 wraps to "abcdefgh\nij" — click at row 1 col 0
|
||||
// should land on 'i' (offset 8).
|
||||
// Long words still hard-wrap when there is no word boundary.
|
||||
expect(offsetFromPosition('abcdefghij', 1, 0, 8)).toBe(8)
|
||||
})
|
||||
|
||||
it('maps clicks on a word-wrapped second row', () => {
|
||||
// "hello world" at cols=8 wraps to "hello \nworld".
|
||||
expect(offsetFromPosition('hello world', 1, 0, 8)).toBe(6)
|
||||
expect(offsetFromPosition('hello world', 1, 3, 8)).toBe(9)
|
||||
})
|
||||
|
||||
it('maps clicks on the moved final word', () => {
|
||||
const text = 'hello world baby chickens are so cool its really rainy outside but wish'
|
||||
|
||||
expect(offsetFromPosition(text, 1, 0, 70)).toBe(text.indexOf('wish'))
|
||||
expect(offsetFromPosition(text, 1, 3, 70)).toBe(text.indexOf('wish') + 3)
|
||||
})
|
||||
|
||||
it('maps clicks past a \\n into the target line', () => {
|
||||
expect(offsetFromPosition('one\ntwo', 1, 2, 40)).toBe(6)
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue