mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-25 20:44:46 -07:00
perf(ui): optimize text buffer and highlighting for large inputs (#16782)
Co-authored-by: Jacob Richman <jacob314@gmail.com>
This commit is contained in:
@@ -8,6 +8,8 @@ import stripAnsi from 'strip-ansi';
|
||||
import ansiRegex from 'ansi-regex';
|
||||
import { stripVTControlCharacters } from 'node:util';
|
||||
import stringWidth from 'string-width';
|
||||
import { LruCache } from '@google/gemini-cli-core';
|
||||
import { LRU_BUFFER_PERF_CACHE_LIMIT } from '../constants.js';
|
||||
|
||||
/**
|
||||
* Calculates the maximum width of a multi-line ASCII art string.
|
||||
@@ -28,9 +30,11 @@ export const getAsciiArtWidth = (asciiArt: string): number => {
|
||||
* code units so that surrogate‑pair emoji count as one "column".)
|
||||
* ---------------------------------------------------------------------- */
|
||||
|
||||
// Cache for code points to reduce GC pressure
|
||||
const codePointsCache = new Map<string, string[]>();
|
||||
// Cache for code points
|
||||
const MAX_STRING_LENGTH_TO_CACHE = 1000;
|
||||
const codePointsCache = new LruCache<string, string[]>(
|
||||
LRU_BUFFER_PERF_CACHE_LIMIT,
|
||||
);
|
||||
|
||||
export function toCodePoints(str: string): string[] {
|
||||
// ASCII fast path - check if all chars are ASCII (0-127)
|
||||
@@ -48,14 +52,14 @@ export function toCodePoints(str: string): string[] {
|
||||
// Cache short strings
|
||||
if (str.length <= MAX_STRING_LENGTH_TO_CACHE) {
|
||||
const cached = codePointsCache.get(str);
|
||||
if (cached) {
|
||||
if (cached !== undefined) {
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
|
||||
const result = Array.from(str);
|
||||
|
||||
// Cache result (unlimited like Ink)
|
||||
// Cache result
|
||||
if (str.length <= MAX_STRING_LENGTH_TO_CACHE) {
|
||||
codePointsCache.set(str, result);
|
||||
}
|
||||
@@ -119,21 +123,26 @@ export function stripUnsafeCharacters(str: string): string {
|
||||
.join('');
|
||||
}
|
||||
|
||||
// String width caching for performance optimization
|
||||
const stringWidthCache = new Map<string, number>();
|
||||
const stringWidthCache = new LruCache<string, number>(
|
||||
LRU_BUFFER_PERF_CACHE_LIMIT,
|
||||
);
|
||||
|
||||
/**
|
||||
* Cached version of stringWidth function for better performance
|
||||
* Follows Ink's approach with unlimited cache (no eviction)
|
||||
*/
|
||||
export const getCachedStringWidth = (str: string): number => {
|
||||
// ASCII printable chars have width 1
|
||||
if (/^[\x20-\x7E]*$/.test(str)) {
|
||||
return str.length;
|
||||
// ASCII printable chars (32-126) have width 1.
|
||||
// This is a very frequent path, so we use a fast numeric check.
|
||||
if (str.length === 1) {
|
||||
const code = str.charCodeAt(0);
|
||||
if (code >= 0x20 && code <= 0x7e) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (stringWidthCache.has(str)) {
|
||||
return stringWidthCache.get(str)!;
|
||||
const cached = stringWidthCache.get(str);
|
||||
if (cached !== undefined) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
let width: number;
|
||||
|
||||
Reference in New Issue
Block a user