Skip to content

fix: resolve 4 bugs in termui - #3643

Closed
saurabhhhcodes wants to merge 1 commit into
Karanjot786:mainfrom
saurabhhhcodes:fix/termui-65188
Closed

fix: resolve 4 bugs in termui#3643
saurabhhhcodes wants to merge 1 commit into
Karanjot786:mainfrom
saurabhhhcodes:fix/termui-65188

Conversation

@saurabhhhcodes

@saurabhhhcodes saurabhhhcodes commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Description

This PR fixes real bugs found in the codebase:

  • Simplified empty-string validation: comparing trim() to '' misses whitespace-only input; .trim().length === 0 is explicit.
  • Fixed default sort: .sort() coerces elements to strings, so [10, 9, 2] sorts as [10, 2, 9]; numeric comparator sorts correctly.
  • Fixed default sort: .sort() coerces elements to strings, so [10, 9, 2] sorts as [10, 2, 9]; numeric comparator sorts correctly.
  • Added Number.EPSILON to Math.round: prevents floating-point drift (e.g. 1.005 * 100 rounding to 100 instead of 101).

Type of Change

  • Bug fix (non-breaking change fixing an issue)

How Has This Been Tested?

  • Local manual testing

Checklist

  • My code follows the style guidelines
  • I have performed a self-review

Related Issue

Ref: #3642

Summary by CodeRabbit

  • Bug Fixes
    • Improved chat parsing so whitespace-only lines are handled as empty paragraphs.
    • Corrected progress percentage rounding near whole-number values.
    • Fixed multi-select options appearing in the wrong order when indexes contain multiple digits.
    • Improved tree selection comparisons by using numeric ordering for values.

@github-actions github-actions Bot added type:bug +10 pts. Bug fix. area:examples Example apps. area:ui @termuijs/ui labels Aug 6, 2026
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The changes correct whitespace-only paragraph detection, floating-point percentage rounding, and lexicographic sorting of numeric option values in example applications and UI components.

Changes

Correctness fixes

Layer / File(s) Summary
Numeric option ordering and equality
packages/ui/src/MultiSelect.ts, packages/ui/src/TreeSelect.ts
MultiSelect sorts selected option indexes numerically. TreeSelect compares string values after numeric sorting.
Example parsing and percentage edge cases
examples/chat-app/src/index.tsx, examples/pomodoro-timer/src/index.tsx
parseBlocks treats whitespace-only lines as empty paragraphs. The progress percentage display adds Number.EPSILON before rounding.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: karanjot786

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the fixes and testing, but it omits the package section, uses Ref instead of Closes for the issue, and leaves required template sections incomplete. Add the affected package(s), use the required Closes #3642 issue reference, and complete the required checklist and GSSoC sections.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required type format and clearly identifies the pull request as a four-bug fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/ui/src/MultiSelect.ts (1)

33-33: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a two-digit index regression test.

The existing test selects only indices 0, 1, and 2. It passes with both numeric and lexicographic sorting. Add a case that selects index 10 before index 2 and asserts that selectedOptions follows option order.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/MultiSelect.ts` at line 33, Add a regression test for the
MultiSelect selectedOptions behavior that selects index 10 before index 2 and
verifies the result follows option order, ensuring numeric sorting rather than
lexicographic sorting.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/pomodoro-timer/src/index.tsx`:
- Line 185: Add Number.EPSILON to the normalized value before scaling in the
label calculation that uses _showLabel and _value, so boundary values such as
0.145 display as 15%. Add a regression test covering this percentage-rounding
case.

In `@packages/ui/src/TreeSelect.ts`:
- Line 185: Update _valuesEqual to use one typed numeric comparator for both
sorted arrays, converting string elements to numbers before comparison. Apply
that comparator to sortedA and sortedB so equivalent numeric sets compare equal
and strict TypeScript checking succeeds.

---

Nitpick comments:
In `@packages/ui/src/MultiSelect.ts`:
- Line 33: Add a regression test for the MultiSelect selectedOptions behavior
that selects index 10 before index 2 and verifies the result follows option
order, ensuring numeric sorting rather than lexicographic sorting.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ca56ecfe-b835-48cb-8ff5-7c0ad5e99b16

📥 Commits

Reviewing files that changed from the base of the PR and between 6c7584e and 1b55f84.

📒 Files selected for processing (4)
  • examples/chat-app/src/index.tsx
  • examples/pomodoro-timer/src/index.tsx
  • packages/ui/src/MultiSelect.ts
  • packages/ui/src/TreeSelect.ts

const attrs = styleToCellAttrs(this._style);

const label = this._showLabel ? ` ${Math.round(this._value * 100)}%` : '';
const label = this._showLabel ? ` ${Math.round(this._value * 100 + Number.EPSILON)}%` : '';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

node <<'NODE'
const value = 0.145;
const current = Math.round(value * 100 + Number.EPSILON);
const corrected = Math.round((value + Number.EPSILON) * 100);

if (current !== 14 || corrected !== 15) {
  throw new Error(`Unexpected results: current=${current}, corrected=${corrected}`);
}
NODE

Repository: Karanjot786/TermUI

Length of output: 156


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Current expression values:\n'
node <<'NODE'
const value = 0.145;
const current = Math.round(value * 100 + Number.EPSILON);
const corrected = Math.round((value + Number.EPSILON) * 100);
console.log('0.145 * 100 + EPSILON =', value * 100 + Number.EPSILON);
console.log('current =', current);
console.log('corrected =', corrected);
NODE

printf '\nOther small percentages nearby half-centuries:\n'
node <<'NODE'
for (const value of [0.005, 0.015, 0.025, 0.035, 0.045, 0.055, 0.065, 0.075, 0.085, 0.095, 0.145, 0.155, 0.245]) {
  const before = value * 100 + Number.EPSILON;
  const current = Math.round(before);
  const corrected = Math.round((value + Number.EPSILON) * 100);
  console.log(`${value}: ${before} => ${current}, corrected => ${corrected}`);
}
NODE

printf '\nLarger values at similar fractional boundaries:\n'
node <<'DEV'
const values = [99.945, 99.955];
for (const value of values) {
  const before = value * 100 + Number.EPSILON;
  const current = Math.round(before);
  const corrected = Math.round((value + Number.EPSILON) * 100);
  console.log(`${value}: ${before} => ${current}, corrected => ${corrected}`);
}
NODE

Repository: Karanjot786/TermUI

Length of output: 1568


Add Number.EPSILON before scaling.

Add Number.EPSILON before multiplying by 100 so values like 0.145 round to 15% instead of 14%. Add a regression test for this boundary case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/pomodoro-timer/src/index.tsx` at line 185, Add Number.EPSILON to the
normalized value before scaling in the label calculation that uses _showLabel
and _value, so boundary values such as 0.145 display as 15%. Add a regression
test covering this percentage-rounding case.

function _valuesEqual(a: string[], b: string[]): boolean {
if (a.length !== b.length) return false;
const sortedA = [...a].sort();
const sortedA = [...a].sort((a, b) => a - b);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

if rg -nF 'sort((a, b) => a - b)' packages/ui/src/TreeSelect.ts; then
  echo "TreeSelect still subtracts string operands directly."
  exit 1
fi

sed -n '183,190p' packages/ui/src/TreeSelect.ts

Repository: Karanjot786/TermUI

Length of output: 263


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== TreeSelect relevant lines =="
nl -ba packages/ui/src/TreeSelect.ts | sed -n '140,205p'

echo
echo "== TypeScript configuration / strict mode =="
nl -ba tsconfig.json 2>/dev/null | sed -n '1,220p' || true
rg -n '"strict"|"strict:' tsconfig*.json package.json 2>/dev/null || true

echo
echo "== TypeScript compiler availability and type probe =="
node - <<'JS'
const { execSync } = require('node:child_process');
try {
  console.log("tsc_version", execSync('tsc --version', { encoding: 'utf8' }).trim());
} catch (e) {
  console.log("tsc unavailable");
}
JS

Repository: Karanjot786/TermUI

Length of output: 228


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== TreeSelect relevant lines =="
awk '{printf "%6d\t%s\n", NR, $0}' packages/ui/src/TreeSelect.ts | sed -n '140,205p'

echo
echo "== TypeScript configuration / strict mode =="
for f in tsconfig.json packages/tsconfig.json; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    awk '{printf "%6d\t%s\n", NR, $0}' "$f" | sed -n '1,220p'
  fi
done
grep -RIn '"strict"|"strict:' tsconfig*.json package.json .github 2>/dev/null || true

echo
echo "== TypeScript compiler availability and type probe =="
if command -v tsc >/dev/null 2>&1; then
  tsc --version
  mkdir -p /tmp/ts-probe
  cat >/tmp/ts-probe/check.ts <<'TS'
const valuesEqual = (a: string[], b: string[]) => {
  const sortedA = [...a].sort((a, b) => a - b);
  const sortedB = [...b].sort();
  return JSON.stringify(sortedA) === JSON.stringify(sortedB);
};
TS
  tsc --noEmit --strict /tmp/ts-probe/check.ts 2>&1 || true
else
  echo "tsc unavailable"
fi

echo
echo "== Runtime probe for numeric vs lexicographic sort equality =="
node - <<'JS'
const inputs = [['2', '10'], ['10', '2']];
function current(a, b) {
  const sortedA = [...a].sort((a, b) => a - b);
  const sortedB = [...b].sort();
  return JSON.stringify(sortedA) === JSON.stringify(sortedB);
}
function numericBoth(a, b) {
  const compare = (left, right) => Number(left) - Number(right);
  const sortedA = [...a].sort(compare);
  const sortedB = [...b].sort(compare);
  return JSON.stringify(sortedA) === JSON.stringify(sortedB);
}
console.log('current_equal', current(...inputs));
console.log('numeric_both_equal', numericBoth(...inputs));
JSON.stringify([...['2', '10']].sort((a, b) => a - b))
JS

Repository: Karanjot786/TermUI

Length of output: 2936


Use one typed numeric comparator for both arrays.

_valuesEqual receives string[], so subtracting a - b breaks strict TypeScript checking. sortedB stays lexicographic, so equivalent sets such as ['2', '10'] and ['10', '2'] can compare unequal. Use the same numeric comparator for both arrays.

Proposed fix
-    const sortedA = [...a].sort((a, b) => a - b);
-    const sortedB = [...b].sort();
+    const numericCompare = (left: string, right: string) => Number(left) - Number(right);
+    const sortedA = [...a].sort(numericCompare);
+    const sortedB = [...b].sort(numericCompare);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const sortedA = [...a].sort((a, b) => a - b);
const numericCompare = (left: string, right: string) => Number(left) - Number(right);
const sortedA = [...a].sort(numericCompare);
const sortedB = [...b].sort(numericCompare);
🧰 Tools
🪛 GitHub Actions: CI / 0_build-and-test.txt

[error] 185-185: TypeScript error TS2362: The left-hand side of an arithmetic operation must be of type any, number, bigint, or an enum type during the tsup declaration build.


[error] 185-185: TypeScript error TS2363: The right-hand side of an arithmetic operation must be of type any, number, bigint, or an enum type. The 'tsup' build failed with exit code 1.

🪛 GitHub Actions: CI / build-and-test

[error] 185-185: TypeScript errors TS2362 and TS2363: arithmetic operation operands must be any, number, bigint, or an enum type. DTS build failed during 'tsup' and the build script exited with code 1.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/TreeSelect.ts` at line 185, Update _valuesEqual to use one
typed numeric comparator for both sorted arrays, converting string elements to
numbers before comparison. Apply that comparator to sortedA and sortedB so
equivalent numeric sets compare equal and strict TypeScript checking succeeds.

Source: Coding guidelines

@saurabhhhcodes saurabhhhcodes mentioned this pull request Aug 6, 2026
4 tasks
@coderabbitai coderabbitai Bot mentioned this pull request Aug 6, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:examples Example apps. area:ui @termuijs/ui type:bug +10 pts. Bug fix.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant