Skip to content

Commit e93a3bb

Browse files
Mike Morganclaude
andcommitted
fix: System font fallback and status bar improvements
Font Changes: - Use system fonts FIRST (SF Mono, Menlo, DejaVu Sans Mono) to avoid "Unable to load font" errors on fresh macOS/Linux installs - JetBrains Mono and Fira Code moved to END of fallback chain - Rust default: Menlo (macOS), DejaVu Sans Mono (Linux), Consolas (Windows) Status Bar (cx.lua): - Added Git branch indicator with dirty status (yellow dot) - Added "AI Ready" indicator in CX teal - Added current working directory on left - Added Ctrl+Space hint Key Bindings (cx.lua): - Ctrl+Space: AI panel (command palette) - Ctrl+Shift+F: Fix last error (sends "cx fix-last-error") - Ctrl+Shift+E: Explain output (sends "cx explain") - Cmd+D: Split horizontal, Cmd+Shift+D: Split vertical - Cmd+1-9: Switch tabs - Session persistence via unix domains Fixes the font error from: ERROR mux::connui > Configuration Error: Unable to load a font... Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 667d4d0 commit e93a3bb

4 files changed

Lines changed: 164 additions & 50 deletions

File tree

config/src/font.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -431,8 +431,16 @@ impl FontAttributes {
431431
impl Default for FontAttributes {
432432
fn default() -> Self {
433433
Self {
434-
// CX Terminal: Default to JetBrains Mono (bundled)
435-
family: "JetBrains Mono".into(),
434+
// CX Terminal: Default to system font (Menlo on macOS, DejaVu on Linux)
435+
// This ensures the terminal works without custom font installation
436+
#[cfg(target_os = "macos")]
437+
family: "Menlo".into(),
438+
#[cfg(target_os = "linux")]
439+
family: "DejaVu Sans Mono".into(),
440+
#[cfg(target_os = "windows")]
441+
family: "Consolas".into(),
442+
#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
443+
family: "monospace".into(),
436444
weight: FontWeight::default(),
437445
stretch: FontStretch::default(),
438446
style: FontStyle::Normal,

examples/cx-full.lua

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ local config = cx.config_builder()
77

88
-------------------------------------------------------------------------------
99
-- FONTS
10+
-- System fonts FIRST to avoid "Unable to load font" errors on fresh installs
1011
-------------------------------------------------------------------------------
1112
config.font = cx.font_with_fallback({
12-
"JetBrains Mono",
13+
"SF Mono", -- macOS system font (always present)
14+
"Menlo", -- macOS fallback (always present)
15+
"DejaVu Sans Mono", -- Linux fallback
16+
"JetBrains Mono", -- If installed (recommended)
1317
"Noto Color Emoji",
1418
"Symbols Nerd Font",
1519
})

examples/cx-themes.lua

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -303,31 +303,24 @@ config.window_background_opacity = 0.95
303303

304304
-------------------------------------------------------------------------------
305305
-- FONT STYLING
306-
-- CX Terminal default: Fira Code for terminal, Inter for UI
306+
-- System fonts FIRST to avoid "Unable to load font" errors
307+
-- Optional fonts (Fira Code, JetBrains Mono) at end for ligature support
307308
-------------------------------------------------------------------------------
308309
config.font = cx.font_with_fallback({
309-
"Fira Code", -- Primary: excellent ligatures and readability
310-
"JetBrains Mono", -- Fallback: widely available
311-
"Cascadia Code", -- Fallback: Windows default
312-
"Menlo", -- Fallback: macOS default
310+
"SF Mono", -- macOS system font (always present)
311+
"Menlo", -- macOS fallback (always present)
312+
"Monaco", -- macOS classic (always present)
313+
"DejaVu Sans Mono", -- Linux fallback
314+
"Consolas", -- Windows fallback
315+
"JetBrains Mono", -- If installed (recommended for ligatures)
316+
"Fira Code", -- If installed (excellent ligatures)
313317
})
314318
config.font_size = 14.0
315319

316-
-- Enable Fira Code stylistic sets for better symbols
317-
-- ss01: r with serifs, ss02: <= and >= with horizontal bar
318-
-- ss03: & ampersand, ss04: $ with broken bar
319-
-- ss05: @ with larger inner circle, ss06: thin backslash
320-
-- ss07: ~= and != with large tilde/equals
321-
-- ss08: == and === with large ligature
320+
-- Enable ligatures if using a font that supports them (JetBrains Mono, Fira Code)
322321
config.harfbuzz_features = {
323322
"calt=1", -- Contextual alternates (ligatures)
324-
"clig=1", -- Ligatures
325323
"liga=1", -- Standard ligatures
326-
"ss01=1", -- Fira Code stylistic set 1
327-
"ss02=1", -- Fira Code stylistic set 2
328-
"ss03=1", -- Fira Code stylistic set 3
329-
"ss07=1", -- Fira Code stylistic set 7
330-
"zero=1", -- Slashed zero
331324
}
332325

333326
-- Disable ligatures if you prefer

examples/cx.lua

Lines changed: 139 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,29 @@ local config = cx.config_builder()
1717
-- Use "CX Light" for a light theme
1818
config.color_scheme = "CX Dark"
1919

20-
-- Font settings - Fira Code with full ligatures
20+
-- Font settings - System fonts FIRST to avoid "Unable to load font" errors
21+
-- macOS: SF Mono and Menlo are always available
22+
-- Linux: DejaVu Sans Mono is typically available
23+
-- Then fall back to optional fonts if installed
2124
config.font = cx.font_with_fallback({
22-
"Fira Code",
23-
"JetBrains Mono",
24-
"Cascadia Code",
25-
"Menlo",
25+
"SF Mono", -- macOS system font (always present)
26+
"Menlo", -- macOS fallback (always present)
27+
"Monaco", -- macOS classic (always present)
28+
"DejaVu Sans Mono", -- Linux fallback
29+
"Consolas", -- Windows fallback
30+
"JetBrains Mono", -- If installed (recommended)
31+
"Fira Code", -- If installed
2632
})
2733
config.font_size = 14.0
2834

29-
-- Enable Fira Code ligatures and stylistic sets
35+
-- Enable ligatures if using a font that supports them
3036
config.harfbuzz_features = {
3137
"calt=1", -- Contextual alternates
3238
"liga=1", -- Standard ligatures
33-
"ss01=1", -- r with serifs
34-
"ss02=1", -- <= >= with horizontal bar
35-
"ss07=1", -- ~= != with proper glyphs
36-
"zero=1", -- Slashed zero
3739
}
3840

3941
-- Window appearance
40-
config.window_background_opacity = 0.98
42+
config.window_background_opacity = 0.95
4143
config.window_decorations = "RESIZE"
4244
config.window_padding = {
4345
left = 12,
@@ -47,14 +49,90 @@ config.window_padding = {
4749
}
4850

4951
-- Tab bar
50-
config.hide_tab_bar_if_only_one_tab = true
52+
config.hide_tab_bar_if_only_one_tab = false
5153
config.tab_bar_at_bottom = false
5254
config.use_fancy_tab_bar = true
5355

5456
-- Cursor
5557
config.default_cursor_style = "SteadyBlock"
5658
config.cursor_blink_rate = 500
5759

60+
-------------------------------------------------------------------------------
61+
-- STATUS BAR - Git Branch + AI Ready Indicator
62+
-------------------------------------------------------------------------------
63+
64+
config.status_update_interval = 1000
65+
66+
cx.on('update-status', function(window, pane)
67+
local cells = {}
68+
69+
-- Left status: Current working directory
70+
local cwd_uri = pane:get_current_working_dir()
71+
if cwd_uri then
72+
local cwd = cwd_uri.file_path or ""
73+
-- Shorten home directory
74+
local home = os.getenv("HOME") or ""
75+
if home ~= "" and cwd:sub(1, #home) == home then
76+
cwd = "~" .. cwd:sub(#home + 1)
77+
end
78+
table.insert(cells, { Foreground = { Color = "#6272A4" } })
79+
table.insert(cells, { Text = " " .. cwd .. " " })
80+
end
81+
82+
window:set_left_status(cx.format(cells))
83+
84+
-- Right status
85+
local right_cells = {}
86+
87+
-- Git branch indicator
88+
if cwd_uri then
89+
local success, stdout = pcall(function()
90+
local handle = io.popen('git -C "' .. (cwd_uri.file_path or ".") .. '" branch --show-current 2>/dev/null')
91+
if handle then
92+
local result = handle:read("*l")
93+
handle:close()
94+
return result
95+
end
96+
return nil
97+
end)
98+
99+
if success and stdout and stdout ~= "" then
100+
-- Check if dirty
101+
local dirty_handle = io.popen('git -C "' .. (cwd_uri.file_path or ".") .. '" status --porcelain 2>/dev/null | head -1')
102+
local is_dirty = false
103+
if dirty_handle then
104+
local dirty_result = dirty_handle:read("*l")
105+
dirty_handle:close()
106+
is_dirty = dirty_result and dirty_result ~= ""
107+
end
108+
109+
table.insert(right_cells, { Foreground = { Color = "#00FF88" } })
110+
table.insert(right_cells, { Text = "" .. stdout })
111+
if is_dirty then
112+
table.insert(right_cells, { Foreground = { Color = "#FFCC00" } })
113+
table.insert(right_cells, { Text = "" })
114+
end
115+
table.insert(right_cells, { Text = " " })
116+
end
117+
end
118+
119+
-- Separator
120+
table.insert(right_cells, { Foreground = { Color = "#44475A" } })
121+
table.insert(right_cells, { Text = "" })
122+
123+
-- AI Status indicator
124+
table.insert(right_cells, { Foreground = { Color = "#00D9FF" } })
125+
table.insert(right_cells, { Text = " ⚡ AI Ready " })
126+
127+
-- Hint for AI shortcut
128+
table.insert(right_cells, { Foreground = { Color = "#44475A" } })
129+
table.insert(right_cells, { Text = "" })
130+
table.insert(right_cells, { Foreground = { Color = "#6272A4" } })
131+
table.insert(right_cells, { Text = " ^Space " })
132+
133+
window:set_right_status(cx.format(right_cells))
134+
end)
135+
58136
-------------------------------------------------------------------------------
59137
-- TERMINAL BEHAVIOR
60138
-------------------------------------------------------------------------------
@@ -79,39 +157,70 @@ config.selection_word_boundary = " \t\n{}[]()\"'`,;:"
79157
-------------------------------------------------------------------------------
80158

81159
config.keys = {
160+
-- AI Integration
161+
{ key = "Space", mods = "CTRL", action = cx.action.ShowLauncherArgs { flags = "COMMANDS" } },
162+
{ key = "f", mods = "CTRL|SHIFT", action = cx.action.SendString("cx fix-last-error\n") },
163+
{ key = "e", mods = "CTRL|SHIFT", action = cx.action.SendString("cx explain\n") },
164+
82165
-- Pane management
83-
{ key = "d", mods = "CTRL|SHIFT", action = cx.action.SplitHorizontal { domain = "CurrentPaneDomain" } },
84-
{ key = "e", mods = "CTRL|SHIFT", action = cx.action.SplitVertical { domain = "CurrentPaneDomain" } },
85-
{ key = "w", mods = "CTRL|SHIFT", action = cx.action.CloseCurrentPane { confirm = true } },
166+
{ key = "d", mods = "CMD", action = cx.action.SplitHorizontal { domain = "CurrentPaneDomain" } },
167+
{ key = "d", mods = "CMD|SHIFT", action = cx.action.SplitVertical { domain = "CurrentPaneDomain" } },
168+
{ key = "w", mods = "CMD|SHIFT", action = cx.action.CloseCurrentPane { confirm = true } },
86169

87170
-- Pane navigation
88-
{ key = "LeftArrow", mods = "CTRL|SHIFT", action = cx.action.ActivatePaneDirection "Left" },
89-
{ key = "RightArrow", mods = "CTRL|SHIFT", action = cx.action.ActivatePaneDirection "Right" },
90-
{ key = "UpArrow", mods = "CTRL|SHIFT", action = cx.action.ActivatePaneDirection "Up" },
91-
{ key = "DownArrow", mods = "CTRL|SHIFT", action = cx.action.ActivatePaneDirection "Down" },
171+
{ key = "LeftArrow", mods = "CMD|ALT", action = cx.action.ActivatePaneDirection "Left" },
172+
{ key = "RightArrow", mods = "CMD|ALT", action = cx.action.ActivatePaneDirection "Right" },
173+
{ key = "UpArrow", mods = "CMD|ALT", action = cx.action.ActivatePaneDirection "Up" },
174+
{ key = "DownArrow", mods = "CMD|ALT", action = cx.action.ActivatePaneDirection "Down" },
175+
{ key = "h", mods = "CMD|ALT", action = cx.action.ActivatePaneDirection "Left" },
176+
{ key = "l", mods = "CMD|ALT", action = cx.action.ActivatePaneDirection "Right" },
177+
{ key = "k", mods = "CMD|ALT", action = cx.action.ActivatePaneDirection "Up" },
178+
{ key = "j", mods = "CMD|ALT", action = cx.action.ActivatePaneDirection "Down" },
92179

93180
-- Tab management
94-
{ key = "t", mods = "CTRL|SHIFT", action = cx.action.SpawnTab "CurrentPaneDomain" },
95-
{ key = "Tab", mods = "CTRL", action = cx.action.ActivateTabRelative(1) },
96-
{ key = "Tab", mods = "CTRL|SHIFT", action = cx.action.ActivateTabRelative(-1) },
181+
{ key = "t", mods = "CMD", action = cx.action.SpawnTab "CurrentPaneDomain" },
182+
{ key = "w", mods = "CMD", action = cx.action.CloseCurrentTab { confirm = true } },
183+
{ key = "[", mods = "CMD|SHIFT", action = cx.action.ActivateTabRelative(-1) },
184+
{ key = "]", mods = "CMD|SHIFT", action = cx.action.ActivateTabRelative(1) },
185+
{ key = "1", mods = "CMD", action = cx.action.ActivateTab(0) },
186+
{ key = "2", mods = "CMD", action = cx.action.ActivateTab(1) },
187+
{ key = "3", mods = "CMD", action = cx.action.ActivateTab(2) },
188+
{ key = "4", mods = "CMD", action = cx.action.ActivateTab(3) },
189+
{ key = "5", mods = "CMD", action = cx.action.ActivateTab(4) },
190+
{ key = "6", mods = "CMD", action = cx.action.ActivateTab(5) },
191+
{ key = "7", mods = "CMD", action = cx.action.ActivateTab(6) },
192+
{ key = "8", mods = "CMD", action = cx.action.ActivateTab(7) },
193+
{ key = "9", mods = "CMD", action = cx.action.ActivateTab(8) },
97194

98195
-- Font size
99-
{ key = "+", mods = "CTRL", action = cx.action.IncreaseFontSize },
100-
{ key = "-", mods = "CTRL", action = cx.action.DecreaseFontSize },
101-
{ key = "0", mods = "CTRL", action = cx.action.ResetFontSize },
196+
{ key = "=", mods = "CMD", action = cx.action.IncreaseFontSize },
197+
{ key = "-", mods = "CMD", action = cx.action.DecreaseFontSize },
198+
{ key = "0", mods = "CMD", action = cx.action.ResetFontSize },
199+
200+
-- Utilities
201+
{ key = "p", mods = "CMD|SHIFT", action = cx.action.ActivateCommandPalette },
202+
{ key = "f", mods = "CMD", action = cx.action.Search "CurrentSelectionOrEmptyString" },
203+
{ key = "k", mods = "CMD", action = cx.action.ClearScrollback "ScrollbackAndViewport" },
204+
{ key = "Enter", mods = "CMD", action = cx.action.ToggleFullScreen },
205+
{ key = "r", mods = "CMD|SHIFT", action = cx.action.ReloadConfiguration },
206+
}
207+
208+
-------------------------------------------------------------------------------
209+
-- SESSION PERSISTENCE
210+
-------------------------------------------------------------------------------
102211

103-
-- Command palette
104-
{ key = "p", mods = "CTRL|SHIFT", action = cx.action.ActivateCommandPalette },
212+
config.unix_domains = {
213+
{ name = "cx-session" },
105214
}
106215

107216
-------------------------------------------------------------------------------
108217
-- AI INTEGRATION
109218
-- Requires: ANTHROPIC_API_KEY or OLLAMA_HOST environment variable
110219
-------------------------------------------------------------------------------
111220

112-
-- AI panel toggle: Ctrl+Space (default)
113-
-- Explain selection: Ctrl+Shift+E
114-
-- Suggest commands: Ctrl+Shift+S
221+
-- AI panel toggle: Ctrl+Space
222+
-- Fix last error: Ctrl+Shift+F
223+
-- Explain output: Ctrl+Shift+E
115224

116225
-- For Claude API:
117226
-- export ANTHROPIC_API_KEY="your-api-key"

0 commit comments

Comments
 (0)