Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions THEME_COMMAND_INFO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Qwen Code Theme Command

## Overview

The `/theme` command in Qwen Code opens a dialog that allows users to change the visual theme of the CLI. This command provides an interactive interface for selecting from built-in themes and custom themes defined in settings. The implementation has been optimized for performance, memory efficiency, and responsiveness.

## How It Works

### 1. Command Invocation

- Typing `/theme` in the Qwen Code CLI triggers the theme dialog
- The command is handled by `themeCommand` which returns a dialog action with type 'theme'

### 2. Dialog Interface

The ThemeDialog component provides:

- A left panel with theme selection (radio button list)
- A right panel with live theme preview showing code and diff examples
- Tab navigation between theme selection and scope configuration
- Scope selector to choose where to save the theme setting (user/workspace/system)
- **Optimized rendering**: Uses React.memo and useMemo to prevent unnecessary re-renders and calculations

### 3. Available Themes

Built-in themes include:

- **Dark Themes**: AyuDark, AtomOneDark, Dracula, GitHubDark, DefaultDark, QwenDark, ShadesOfPurple
- **Light Themes**: AyuLight, GitHubLight, GoogleCode, DefaultLight, QwenLight, XCode
- **ANSI Themes**: ANSI, ANSILight

### 4. Custom Themes

- Users can define custom themes in their settings.json file
- Custom themes can be added via `customThemes` object in the settings
- Theme files can also be loaded directly from JSON files (only from within the home directory for security)
- **Optimized loading**: Implements caching for faster theme retrieval and reduced processing

### 5. Theme Preview

- The dialog shows a live preview of the selected theme
- Includes Python code highlighting and a diff example
- This helps users see how the theme will look before applying it
- **Performance optimized**: Layout calculations are memoized to avoid redundant computations

### 6. Theme Application

- When a theme is selected, it's applied immediately to the preview
- When confirmed, the theme is saved to the selected scope (user/workspace/system)
- The theme persists across sessions
- **Efficient theme switching**: Uses optimized lookup mechanisms in the theme manager

### 7. Security Note

- For security, theme files can only be loaded from within the user's home directory
- This prevents loading potentially malicious theme files from untrusted sources
- **Memory safety**: Implements proper cache clearing to prevent memory leaks

## Performance Optimizations

- **Theme Manager**: Implements O(1) theme lookup using name-based cache
- **File Loading**: Caches loaded theme files separately to avoid re-reading from disk
- **UI Rendering**: Uses React hooks (useMemo, useCallback) for efficient re-rendering
- **Memory Management**: Provides methods for clearing theme caches to prevent memory bloat
- **Custom Theme Processing**: Optimized validation and loading of custom themes

## Usage Steps

1. Type `/theme` in Qwen Code CLI
2. Browse themes using arrow keys (with live preview)
3. Press Enter to select a theme or Tab to switch to scope configuration
4. If switching to scope configuration, select the scope where you want to save the theme
5. The selected theme will be applied and saved to your settings

## Configuration

Themes can also be set directly in settings.json:

```json
{
"ui": {
"theme": "QwenDark",
"customThemes": {
"MyCustomTheme": {
"name": "MyCustomTheme",
"type": "dark",
"Foreground": "#ffffff",
"Background": "#000000"
// ... other color definitions
}
}
}
}
```
40 changes: 40 additions & 0 deletions docs/performance-optimizations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Performance Optimizations

This document outlines the performance optimizations implemented in the Qwen Code project to improve startup time, memory usage, and UI responsiveness.

## Implemented Optimizations

### 1. Memory Management Optimization

- **Caching**: Memory values are now cached to avoid recalculating on every function call
- **Implementation**: The `getMemoryValues()` function caches the total memory and current heap size, preventing repeated calls to `os.totalmem()` and `v8.getHeapStatistics()`

### 2. DNS Resolution Optimization

- **Caching**: DNS resolution order validation is now cached to avoid repeated validation
- **Implementation**: The `cachedDnsResolutionOrder` variable prevents repeated validation of the DNS resolution order setting

### 3. UI Performance Optimizations

- **Memoization**: Several expensive calculations in `AppContainer.tsx` are now memoized:
- Terminal width/height calculations
- Shell execution configuration
- Console message filtering
- Context file names computation

## Benefits

These optimizations provide the following benefits:

1. **Faster startup times**: Reduced redundant calculations during application initialization
2. **Lower memory usage**: Fewer temporary objects created through caching and memoization
3. **Better UI responsiveness**: Efficient rendering through proper memoization of expensive calculations
4. **Scalability**: Improved performance under various load conditions

## Development Considerations

When making changes to the optimized code:

1. Be mindful of memoization dependencies - make sure all relevant variables are included in dependency arrays
2. Remember to update cache invalidation logic if needed when adding new functionality
3. Consider performance implications when modifying cached/memoized functions
96 changes: 51 additions & 45 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 37 additions & 5 deletions packages/cli/src/gemini.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,29 +58,61 @@ import {
} from './utils/relaunch.js';
import { validateNonInteractiveAuth } from './validateNonInterActiveAuth.js';

// Cache the DNS resolution order to avoid repeated validation for the same value
let cachedDnsInput: string | undefined = undefined;
let cachedDnsOutput: DnsResolutionOrder | null = null;

export function validateDnsResolutionOrder(
order: string | undefined,
): DnsResolutionOrder {
// If we've already computed the result for this input, return it
if (cachedDnsInput === order && cachedDnsOutput !== null) {
return cachedDnsOutput;
}

const defaultValue: DnsResolutionOrder = 'ipv4first';
if (order === undefined) {
cachedDnsInput = order;
cachedDnsOutput = defaultValue;
return defaultValue;
}
if (order === 'ipv4first' || order === 'verbatim') {
cachedDnsInput = order;
cachedDnsOutput = order;
return order;
}
// We don't want to throw here, just warn and use the default.
console.warn(
`Invalid value for dnsResolutionOrder in settings: "${order}". Using default "${defaultValue}".`,
);
cachedDnsInput = order;
cachedDnsOutput = defaultValue;
return defaultValue;
}

// Cache memory values to avoid recalculating on each call
let cachedMemoryValues: {
totalMemoryMB: number;
currentMaxOldSpaceSizeMb: number;
} | null = null;

function getMemoryValues(): {
totalMemoryMB: number;
currentMaxOldSpaceSizeMb: number;
} {
if (!cachedMemoryValues) {
const totalMemoryMB = os.totalmem() / (1024 * 1024);
const heapStats = v8.getHeapStatistics();
const currentMaxOldSpaceSizeMb = Math.floor(
heapStats.heap_size_limit / 1024 / 1024,
);
cachedMemoryValues = { totalMemoryMB, currentMaxOldSpaceSizeMb };
}
return cachedMemoryValues;
}

function getNodeMemoryArgs(isDebugMode: boolean): string[] {
const totalMemoryMB = os.totalmem() / (1024 * 1024);
const heapStats = v8.getHeapStatistics();
const currentMaxOldSpaceSizeMb = Math.floor(
heapStats.heap_size_limit / 1024 / 1024,
);
const { totalMemoryMB, currentMaxOldSpaceSizeMb } = getMemoryValues();

// Set target to 50% of total memory
const targetMaxOldSpaceSizeInMB = Math.floor(totalMemoryMB * 0.5);
Expand Down
Loading