Skip to content

Commit ddd977a

Browse files
authored
Merge branch 'main' into fix/hyperlink-click-pipeline
2 parents c83d0d9 + 924e9a7 commit ddd977a

File tree

12 files changed

+124
-5
lines changed

12 files changed

+124
-5
lines changed

docs/docs/config.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@ When configured, Rio will automatically switch between the specified light and d
4747

4848
![Adaptive theme](/assets/features/adaptive-theme.gif)
4949

50+
## force-theme
51+
52+
When using adaptive themes, you can override the system theme by forcing Rio to use a specific theme regardless of the system appearance.
53+
54+
```toml
55+
force-theme = "dark"
56+
```
57+
58+
Accepted values: `"dark"` or `"light"`. When not set, Rio follows the system theme.
59+
60+
You can also toggle the appearance theme at runtime using the `ToggleAppearanceTheme` key binding action or through the command palette.
61+
5062
## colors
5163

5264
Defining colors in the configuration file will not have any effect if you're using a theme.

docs/docs/key-bindings.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Execute a predefined action in Rio terminal.
7373
| CreateWindow | Create a Rio window instance |
7474
| Quit | Exit Rio |
7575
| ToggleFullscreen | Toggle fullscreen |
76+
| ToggleAppearanceTheme | Toggle between dark and light appearance theme |
7677

7778
### [Split Actions](#split-actions)
7879

docs/src/pages/changelog.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ language: 'en'
2626
- **Native Vulkan Support** (Linux/Windows): Hardware-accelerated rendering with Vulkan
2727
- **New GPU-Rendered Navigation**: Faster, smoother tab interface
2828
- **Command Palette**: Quick access to terminal functions
29+
- **Toggle Appearance Theme**: Switch between dark and light themes at runtime via key binding (`ToggleAppearanceTheme`) or command palette (only available when adaptive theme is configured)
30+
- **Force Theme**: New `force-theme` configuration property to override the system theme when using adaptive themes
2931
- **Quake Window Mode**: Drop-down terminal from top of screen
3032
- **macOS Traffic Light Positioning**: Customize position of window control buttons
3133
- Configure via `macos-traffic-light-position-x` and `macos-traffic-light-position-y`

frontends/rioterm/src/application.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ impl ApplicationHandler<EventPayload> for Application<'_> {
162162
return;
163163
}
164164

165-
update_colors_based_on_theme(&mut self.config, event_loop.system_theme());
165+
let theme = self.config.force_theme.map(|t| t.to_window_theme()).or(event_loop.system_theme());
166+
update_colors_based_on_theme(&mut self.config, theme);
166167

167168
self.router.create_window(
168169
event_loop,
@@ -385,7 +386,8 @@ impl ApplicationHandler<EventPayload> for Application<'_> {
385386
// Apply system theme to ensure colors are consistent
386387
if !has_checked_adaptive_colors {
387388
let system_theme = route.window.winit_window.theme();
388-
update_colors_based_on_theme(&mut self.config, system_theme);
389+
let theme = self.config.force_theme.map(|t| t.to_window_theme()).or(system_theme);
390+
update_colors_based_on_theme(&mut self.config, theme);
389391
has_checked_adaptive_colors = true;
390392
}
391393

@@ -790,6 +792,34 @@ impl ApplicationHandler<EventPayload> for Application<'_> {
790792
}
791793
}
792794
}
795+
RioEventType::Rio(RioEvent::ToggleAppearanceTheme) => {
796+
if let Some(route) = self.router.routes.get_mut(&window_id) {
797+
use rio_backend::config::theme::AppearanceTheme;
798+
let current = self
799+
.config
800+
.force_theme
801+
.or_else(|| {
802+
route
803+
.window
804+
.winit_window
805+
.theme()
806+
.map(AppearanceTheme::from_window_theme)
807+
})
808+
.unwrap_or(AppearanceTheme::Dark);
809+
let toggled = current.toggled();
810+
self.config.force_theme = Some(toggled);
811+
update_colors_based_on_theme(
812+
&mut self.config,
813+
Some(toggled.to_window_theme()),
814+
);
815+
route.window.screen.update_config(
816+
&self.config,
817+
&self.router.font_library,
818+
false,
819+
);
820+
route.window.configure_window(&self.config);
821+
}
822+
}
793823
RioEventType::Rio(RioEvent::ColorChange(route_id, index, color)) => {
794824
if let Some(route) = self.router.routes.get_mut(&window_id) {
795825
let screen = &mut route.window.screen;
@@ -1569,6 +1599,9 @@ impl ApplicationHandler<EventPayload> for Application<'_> {
15691599
}
15701600

15711601
WindowEvent::ThemeChanged(new_theme) => {
1602+
if self.config.force_theme.is_some() {
1603+
return;
1604+
}
15721605
update_colors_based_on_theme(&mut self.config, Some(new_theme));
15731606
route.window.screen.update_config(
15741607
&self.config,

frontends/rioterm/src/bindings/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ impl From<String> for Action {
263263
"movedividerleft" => Some(Action::MoveDividerLeft),
264264
"movedividerright" => Some(Action::MoveDividerRight),
265265
"togglevimode" => Some(Action::ToggleViMode),
266+
"toggleappearancetheme" => Some(Action::ToggleAppearanceTheme),
266267
"togglefullscreen" => Some(Action::ToggleFullscreen),
267268
"none" => Some(Action::None),
268269
_ => None,
@@ -456,6 +457,9 @@ pub enum Action {
456457
/// Toggle vi mode.
457458
ToggleViMode,
458459

460+
/// Toggle appearance theme (dark/light).
461+
ToggleAppearanceTheme,
462+
459463
// Tab selections
460464
SelectTab(usize),
461465
SelectLastTab,

frontends/rioterm/src/context/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,12 @@ impl<T: EventListener + Clone + std::marker::Send + 'static> ContextManager<T> {
647647
.send_event(RioEvent::ToggleFullScreen, self.window_id);
648648
}
649649

650+
#[inline]
651+
pub fn toggle_appearance_theme(&mut self) {
652+
self.event_proxy
653+
.send_event(RioEvent::ToggleAppearanceTheme, self.window_id);
654+
}
655+
650656
#[inline]
651657
pub fn minimize(&mut self) {
652658
self.event_proxy

frontends/rioterm/src/renderer/command_palette.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub enum PaletteAction {
6262
ResetFontSize,
6363
ToggleViMode,
6464
ToggleFullscreen,
65+
ToggleAppearanceTheme,
6566
Copy,
6667
Paste,
6768
SearchForward,
@@ -163,6 +164,11 @@ const COMMANDS: &[Command] = &[
163164
shortcut: "",
164165
action: PaletteAction::ToggleFullscreen,
165166
},
167+
Command {
168+
title: "Toggle Appearance Theme",
169+
shortcut: "",
170+
action: PaletteAction::ToggleAppearanceTheme,
171+
},
166172
Command {
167173
title: "Copy",
168174
shortcut: "Cmd+C",
@@ -248,6 +254,7 @@ pub struct CommandPalette {
248254
pub query: String,
249255
pub selected_index: usize,
250256
scroll_offset: usize,
257+
pub has_adaptive_theme: bool,
251258
/// Pre-allocated rich text ID for input (lazily initialized)
252259
input_text_id: Option<usize>,
253260
/// Pre-allocated rich text IDs for result rows (lazily initialized, fixed pool)
@@ -265,6 +272,7 @@ impl Default for CommandPalette {
265272
query: String::new(),
266273
selected_index: 0,
267274
scroll_offset: 0,
275+
has_adaptive_theme: false,
268276
input_text_id: None,
269277
result_text_ids: Vec::new(),
270278
shortcut_text_ids: Vec::new(),
@@ -330,8 +338,15 @@ impl CommandPalette {
330338
}
331339

332340
fn filtered_commands(&self) -> Vec<(i32, &Command)> {
341+
let has_adaptive = self.has_adaptive_theme;
333342
let mut results: Vec<(i32, &Command)> = COMMANDS
334343
.iter()
344+
.filter(|cmd| {
345+
if cmd.action == PaletteAction::ToggleAppearanceTheme {
346+
return has_adaptive;
347+
}
348+
true
349+
})
335350
.filter_map(|cmd| {
336351
let score = fuzzy_score(&self.query, cmd.title)?;
337352
Some((score, cmd))
@@ -702,7 +717,8 @@ mod tests {
702717
fn test_filtered_commands_empty_query() {
703718
let palette = CommandPalette::new();
704719
let filtered = palette.filtered_commands();
705-
assert_eq!(filtered.len(), COMMANDS.len());
720+
// ToggleAppearanceTheme is hidden when has_adaptive_theme is false
721+
assert_eq!(filtered.len(), COMMANDS.len() - 1);
706722
}
707723

708724
#[test]

frontends/rioterm/src/renderer/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,11 @@ impl Renderer {
127127
navigation: config.navigation.clone(),
128128
margin: config.margin,
129129
island,
130-
command_palette: command_palette::CommandPalette::new(),
130+
command_palette: {
131+
let mut palette = command_palette::CommandPalette::new();
132+
palette.has_adaptive_theme = config.adaptive_colors.is_some();
133+
palette
134+
},
131135
named_colors,
132136
dynamic_background,
133137
search: search::SearchOverlay::default(),

frontends/rioterm/src/screen/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,9 @@ impl Screen<'_> {
11381138
self.render();
11391139
}
11401140
Act::ToggleFullscreen => self.context_manager.toggle_full_screen(),
1141+
Act::ToggleAppearanceTheme => {
1142+
self.context_manager.toggle_appearance_theme();
1143+
}
11411144
Act::Minimize => {
11421145
self.context_manager.minimize();
11431146
}
@@ -3187,6 +3190,9 @@ impl Screen<'_> {
31873190
PaletteAction::ToggleFullscreen => {
31883191
self.context_manager.toggle_full_screen();
31893192
}
3193+
PaletteAction::ToggleAppearanceTheme => {
3194+
self.context_manager.toggle_appearance_theme();
3195+
}
31903196
PaletteAction::Copy => {
31913197
self.copy_selection(ClipboardType::Clipboard);
31923198
}

rio-backend/src/config/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use std::io::Write;
3030
use std::path::PathBuf;
3131
use std::{default::Default, fs::File};
3232
use sugarloaf::font::fonts::SugarloafFonts;
33-
use theme::{AdaptiveColors, AdaptiveTheme, Theme};
33+
use theme::{AdaptiveColors, AdaptiveTheme, AppearanceTheme, Theme};
3434
use tracing::warn;
3535

3636
#[derive(Clone, Debug)]
@@ -130,6 +130,8 @@ pub struct Config {
130130
pub colors: Colors,
131131
#[serde(default = "Option::default", skip_serializing)]
132132
pub adaptive_colors: Option<AdaptiveColors>,
133+
#[serde(default = "Option::default", rename = "force-theme")]
134+
pub force_theme: Option<AppearanceTheme>,
133135
#[serde(default = "Developer::default")]
134136
pub developer: Developer,
135137
#[serde(default = "Bindings::default")]
@@ -612,6 +614,7 @@ impl Default for Config {
612614
editor: default_editor(),
613615
adaptive_theme: None,
614616
adaptive_colors: None,
617+
force_theme: None,
615618
bindings: Bindings::default(),
616619
colors: Colors::default(),
617620
scroll: Scroll::default(),

0 commit comments

Comments
 (0)