mirror of
https://github.com/tiennm99/ccstatusline.git
synced 2026-10-14 02:15:32 +00:00
Gracefully handle unknown widgets in the settings.json in both the TUI and statusline rendering
This commit is contained in:
1 parent
077dc0f5eb
commit
9767fc6399
5 files changed
+52
-65
No files matched your search
@@ -43,13 +43,9 @@ export const ColorMenu: React.FC<ColorMenuProps> = ({ widgets, lineIndex, settin
|
||||
return showSeparators;
|
||||
}
|
||||
// Use the widget's supportsColors method
|
||||
try {
|
||||
const widgetInstance = getWidget(widget.type);
|
||||
return widgetInstance.supportsColors(widget);
|
||||
} catch {
|
||||
// If widget type is not found, exclude it
|
||||
return false;
|
||||
}
|
||||
const widgetInstance = getWidget(widget.type);
|
||||
// Include unknown widgets (they might support colors, we just don't know)
|
||||
return widgetInstance ? widgetInstance.supportsColors(widget) : true;
|
||||
});
|
||||
const [highlightedItemId, setHighlightedItemId] = useState<string | null>(colorableWidgets[0]?.id ?? null);
|
||||
const [editingBackground, setEditingBackground] = useState(false);
|
||||
@@ -259,7 +255,9 @@ export const ColorMenu: React.FC<ColorMenuProps> = ({ widgets, lineIndex, settin
|
||||
let defaultColor = 'white';
|
||||
if (widget.type !== 'separator' && widget.type !== 'flex-separator') {
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
defaultColor = widgetImpl.getDefaultColor();
|
||||
if (widgetImpl) {
|
||||
defaultColor = widgetImpl.getDefaultColor();
|
||||
}
|
||||
}
|
||||
let currentColor = widget.color ?? defaultColor;
|
||||
// If color is 'dim', treat as if no color was set
|
||||
@@ -313,7 +311,7 @@ export const ColorMenu: React.FC<ColorMenuProps> = ({ widgets, lineIndex, settin
|
||||
}
|
||||
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
return widgetImpl.getDisplayName();
|
||||
return widgetImpl ? widgetImpl.getDisplayName() : `Unknown: ${widget.type}`;
|
||||
};
|
||||
|
||||
// Color list for cycling
|
||||
@@ -333,7 +331,9 @@ export const ColorMenu: React.FC<ColorMenuProps> = ({ widgets, lineIndex, settin
|
||||
let defaultColor = 'white';
|
||||
if (widget.type !== 'separator' && widget.type !== 'flex-separator') {
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
defaultColor = widgetImpl.getDefaultColor();
|
||||
if (widgetImpl) {
|
||||
defaultColor = widgetImpl.getDefaultColor();
|
||||
}
|
||||
}
|
||||
const styledLabel = applyColors(label, widget.color ?? defaultColor, widget.backgroundColor, widget.bold, level);
|
||||
return {
|
||||
@@ -363,7 +363,7 @@ export const ColorMenu: React.FC<ColorMenuProps> = ({ widgets, lineIndex, settin
|
||||
: (selectedWidget ? (selectedWidget.color ?? (() => {
|
||||
if (selectedWidget.type !== 'separator' && selectedWidget.type !== 'flex-separator') {
|
||||
const widgetImpl = getWidget(selectedWidget.type);
|
||||
return widgetImpl.getDefaultColor();
|
||||
return widgetImpl ? widgetImpl.getDefaultColor() : 'white';
|
||||
}
|
||||
return 'white';
|
||||
})()) : 'white');
|
||||
|
||||
@@ -263,8 +263,8 @@ export const ItemsEditor: React.FC<ItemsEditorProps> = ({ widgets, onUpdate, onB
|
||||
// Check for custom widget keybinds
|
||||
const currentWidget = widgets[selectedIndex];
|
||||
if (currentWidget && currentWidget.type !== 'separator' && currentWidget.type !== 'flex-separator') {
|
||||
try {
|
||||
const widgetImpl = getWidget(currentWidget.type);
|
||||
const widgetImpl = getWidget(currentWidget.type);
|
||||
if (widgetImpl) {
|
||||
if (widgetImpl.getCustomKeybinds) {
|
||||
const customKeybinds = widgetImpl.getCustomKeybinds();
|
||||
const matchedKeybind = customKeybinds.find(kb => kb.key === input);
|
||||
@@ -288,8 +288,6 @@ export const ItemsEditor: React.FC<ItemsEditorProps> = ({ widgets, onUpdate, onB
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Widget not found or doesn't support custom keybinds
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -309,10 +307,13 @@ export const ItemsEditor: React.FC<ItemsEditorProps> = ({ widgets, onUpdate, onB
|
||||
|
||||
// Handle regular widgets - delegate to widget for display
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
const { displayText, modifierText } = widgetImpl.getEditorDisplay(widget);
|
||||
|
||||
// Return plain text without colors
|
||||
return displayText + (modifierText ? ` ${modifierText}` : '');
|
||||
if (widgetImpl) {
|
||||
const { displayText, modifierText } = widgetImpl.getEditorDisplay(widget);
|
||||
// Return plain text without colors
|
||||
return displayText + (modifierText ? ` ${modifierText}` : '');
|
||||
}
|
||||
// Unknown widget type
|
||||
return `Unknown: ${widget.type}`;
|
||||
};
|
||||
|
||||
const hasFlexSeparator = widgets.some(widget => widget.type === 'flex-separator');
|
||||
@@ -327,14 +328,14 @@ export const ItemsEditor: React.FC<ItemsEditorProps> = ({ widgets, onUpdate, onB
|
||||
let canToggleRaw = false;
|
||||
let customKeybinds: { key: string; label: string; action: string }[] = [];
|
||||
if (currentWidget && !isSeparator && !isFlexSeparator) {
|
||||
try {
|
||||
const widgetImpl = getWidget(currentWidget.type);
|
||||
const widgetImpl = getWidget(currentWidget.type);
|
||||
if (widgetImpl) {
|
||||
canToggleRaw = widgetImpl.supportsRawValue();
|
||||
// Get custom keybinds from the widget
|
||||
if (widgetImpl.getCustomKeybinds) {
|
||||
customKeybinds = widgetImpl.getCustomKeybinds();
|
||||
}
|
||||
} catch {
|
||||
} else {
|
||||
canToggleRaw = false;
|
||||
}
|
||||
}
|
||||
@@ -448,12 +449,8 @@ export const ItemsEditor: React.FC<ItemsEditorProps> = ({ widgets, onUpdate, onB
|
||||
} else if (currentWidget.type === 'flex-separator') {
|
||||
return 'Expands to fill available terminal width';
|
||||
} else {
|
||||
try {
|
||||
const widgetImpl = getWidget(currentWidget.type);
|
||||
return widgetImpl.getDescription();
|
||||
} catch {
|
||||
return 'Widget description not available';
|
||||
}
|
||||
const widgetImpl = getWidget(currentWidget.type);
|
||||
return widgetImpl ? widgetImpl.getDescription() : 'Unknown widget type';
|
||||
}
|
||||
})()}
|
||||
</Text>
|
||||
|
||||
@@ -60,7 +60,9 @@ export const TerminalOptionsMenu: React.FC<TerminalOptionsMenuProps> = ({ settin
|
||||
if (widget.color?.startsWith('hex:')) {
|
||||
if (widget.type !== 'separator' && widget.type !== 'flex-separator') {
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
newWidget.color = widgetImpl.getDefaultColor();
|
||||
if (widgetImpl) {
|
||||
newWidget.color = widgetImpl.getDefaultColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (widget.backgroundColor?.startsWith('hex:')) {
|
||||
@@ -71,7 +73,9 @@ export const TerminalOptionsMenu: React.FC<TerminalOptionsMenuProps> = ({ settin
|
||||
if (widget.color?.startsWith('ansi256:')) {
|
||||
if (widget.type !== 'separator' && widget.type !== 'flex-separator') {
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
newWidget.color = widgetImpl.getDefaultColor();
|
||||
if (widgetImpl) {
|
||||
newWidget.color = widgetImpl.getDefaultColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (widget.backgroundColor?.startsWith('ansi256:')) {
|
||||
@@ -82,7 +86,9 @@ export const TerminalOptionsMenu: React.FC<TerminalOptionsMenuProps> = ({ settin
|
||||
if (widget.color?.startsWith('ansi256:') || widget.color?.startsWith('hex:')) {
|
||||
if (widget.type !== 'separator' && widget.type !== 'flex-separator') {
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
newWidget.color = widgetImpl.getDefaultColor();
|
||||
if (widgetImpl) {
|
||||
newWidget.color = widgetImpl.getDefaultColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (widget.backgroundColor?.startsWith('ansi256:') || widget.backgroundColor?.startsWith('hex:')) {
|
||||
@@ -118,7 +124,9 @@ export const TerminalOptionsMenu: React.FC<TerminalOptionsMenuProps> = ({ settin
|
||||
if (widget.color?.startsWith('ansi256:') || widget.color?.startsWith('hex:')) {
|
||||
if (widget.type !== 'separator' && widget.type !== 'flex-separator') {
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
newWidget.color = widgetImpl.getDefaultColor();
|
||||
if (widgetImpl) {
|
||||
newWidget.color = widgetImpl.getDefaultColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (widget.backgroundColor?.startsWith('ansi256:') || widget.backgroundColor?.startsWith('hex:')) {
|
||||
|
||||
+12
-26
@@ -134,11 +134,9 @@ function renderPowerlineStatusLine(
|
||||
if (preRendered?.content) {
|
||||
widgetText = preRendered.content;
|
||||
// Get default color from widget impl for consistency
|
||||
try {
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
if (widgetImpl) {
|
||||
defaultColor = widgetImpl.getDefaultColor();
|
||||
} catch {
|
||||
// Keep default
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,20 +479,14 @@ export function preRenderAllWidgets(
|
||||
continue;
|
||||
}
|
||||
|
||||
let widgetText = '';
|
||||
try {
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
widgetText = widgetImpl.render(widget, context, settings) ?? '';
|
||||
} catch {
|
||||
// Unknown widget type - store empty content
|
||||
preRenderedLine.push({
|
||||
content: '',
|
||||
plainLength: 0,
|
||||
widget
|
||||
});
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
if (!widgetImpl) {
|
||||
// Unknown widget type - skip it entirely
|
||||
continue;
|
||||
}
|
||||
|
||||
const widgetText = widgetImpl.render(widget, context, settings) ?? '';
|
||||
|
||||
// Store the rendered content without padding (padding is applied later)
|
||||
const plainLength = widgetText.replace(ANSI_REGEX, '').length;
|
||||
preRenderedLine.push({
|
||||
@@ -664,12 +656,8 @@ export function renderStatusLine(
|
||||
// Get the previous widget's colors
|
||||
let widgetColor = prevWidget.color;
|
||||
if (!widgetColor) {
|
||||
try {
|
||||
const widgetImpl = getWidget(prevWidget.type);
|
||||
widgetColor = widgetImpl.getDefaultColor();
|
||||
} catch {
|
||||
widgetColor = 'white';
|
||||
}
|
||||
const widgetImpl = getWidget(prevWidget.type);
|
||||
widgetColor = widgetImpl ? widgetImpl.getDefaultColor() : 'white';
|
||||
}
|
||||
separatorColor = widgetColor;
|
||||
separatorBg = prevWidget.backgroundColor;
|
||||
@@ -697,11 +685,9 @@ export function renderStatusLine(
|
||||
if (preRendered?.content) {
|
||||
widgetText = preRendered.content;
|
||||
// Get default color from widget impl for consistency
|
||||
try {
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
const widgetImpl = getWidget(widget.type);
|
||||
if (widgetImpl) {
|
||||
defaultColor = widgetImpl.getDefaultColor();
|
||||
} catch {
|
||||
// Keep default
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,7 +776,7 @@ export function renderStatusLine(
|
||||
let widgetColor = prevElem.widget.color;
|
||||
if (!widgetColor && prevElem.widget.type !== 'separator' && prevElem.widget.type !== 'flex-separator') {
|
||||
const widgetImpl = getWidget(prevElem.widget.type);
|
||||
widgetColor = widgetImpl.getDefaultColor();
|
||||
widgetColor = widgetImpl ? widgetImpl.getDefaultColor() : 'white';
|
||||
}
|
||||
const coloredSep = applyColorsWithOverride(defaultSep, widgetColor, prevElem.widget.backgroundColor, prevElem.widget.bold);
|
||||
finalElements.push(coloredSep);
|
||||
|
||||
@@ -28,12 +28,8 @@ const widgetRegistry = new Map<WidgetItemType, Widget>([
|
||||
['custom-command', new widgets.CustomCommandWidget()]
|
||||
]);
|
||||
|
||||
export function getWidget(type: WidgetItemType): Widget {
|
||||
const widget = widgetRegistry.get(type);
|
||||
if (!widget) {
|
||||
throw new Error(`Unknown widget type: ${type}`);
|
||||
}
|
||||
return widget;
|
||||
export function getWidget(type: WidgetItemType): Widget | null {
|
||||
return widgetRegistry.get(type) ?? null;
|
||||
}
|
||||
|
||||
export function getAllWidgetTypes(settings: Settings): WidgetItemType[] {
|
||||
@@ -50,7 +46,7 @@ export function getAllWidgetTypes(settings: Settings): WidgetItemType[] {
|
||||
return allTypes;
|
||||
}
|
||||
|
||||
export function isWidgetType(type: string): boolean {
|
||||
export function isKnownWidgetType(type: string): boolean {
|
||||
return widgetRegistry.has(type)
|
||||
|| type === 'separator'
|
||||
|| type === 'flex-separator';
|
||||
|
||||
Reference in new issue
Block a user