Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
3 changes: 3 additions & 0 deletions docs/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ Some widgets support "raw value" mode which displays just the value without a la
- Normal: `Block: 3hr 45m` → Raw: `3hr 45m`
- Normal: `Ctx: 18.6k` → Raw: `18.6k`

To keep a label but change it, select the widget and press `b` (`la(b)el…`) instead. The label is replaced verbatim, so include any trailing space or colon yourself (e.g. `M ` renders `M Claude 3.5 Sonnet`); an empty label drops it, and Tab in the editor resets it to the default. Widgets whose label changes with their mode (e.g. `Ctx Used:`/`Ctx Left:`, or `Block:` vs `Block ` before a progress bar) use the one custom label in every mode, even one that matches the current mode's default. The editor row shows `(label: "M ")` while a custom label is set; `b` is hidden while raw value is on, since the label isn't rendered then.

## Number Formatting

Numeric widgets support three display styles without changing their underlying values:
Expand All @@ -249,6 +251,7 @@ Common controls in the line editor:
- `c` clear the current line
- `Space` cycle a manual separator character
- `r` toggle raw value (supported widgets)
- `b` edit the label shown before the value when raw value is off (labeled widgets)
- `.` cycle precise/compact/whole number formatting (supported widgets)
- `m` cycle merge mode (`off` → `merge` → `merge no padding`)
- `x` exclude the selected widget and the rest of its line from shared Powerline column widths (shown only when Powerline auto-alignment is enabled)
Expand Down
36 changes: 35 additions & 1 deletion src/tui/components/ItemsEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,16 @@ import {
getHideKeybind,
getHideModifierText
} from '../../widgets/shared/hideable';
import {
EDIT_LABEL_ACTION,
clearLabel,
getLabelKeybind,
getLabelModifierText
} from '../../widgets/shared/raw-or-labeled';

import { ConfirmDialog } from './ConfirmDialog';
import { HideStatesEditor } from './HideStatesEditor';
import { LabelEditor } from './LabelEditor';
import {
handleMoveInputMode,
handleNormalInputMode,
Expand Down Expand Up @@ -132,6 +139,12 @@ export const ItemsEditor: React.FC<ItemsEditorProps> = ({ widgets, onUpdate, onB
keybinds.push(getHideKeybind());
}

// The label only shows when raw value is off, so the editor is offered
// only then. Like 'h', widgets must leave this key unbound.
if (widgetImpl.getLabelPrefix && !widget.rawValue) {
keybinds.push(getLabelKeybind());
}

return keybinds;
};

Expand Down Expand Up @@ -162,7 +175,10 @@ export const ItemsEditor: React.FC<ItemsEditorProps> = ({ widgets, onUpdate, onB
const currentWidget = widgets[selectedIndex];
if (currentWidget) {
const newWidgets = [...widgets];
newWidgets[selectedIndex] = { ...currentWidget, type: selectedType };
// Other metadata carries over, but a label names the old widget's value
newWidgets[selectedIndex] = currentWidget.type === selectedType
? currentWidget
: { ...clearLabel(currentWidget), type: selectedType };
onUpdate(newWidgets);
}
} else {
Expand Down Expand Up @@ -350,6 +366,17 @@ export const ItemsEditor: React.FC<ItemsEditorProps> = ({ widgets, onUpdate, onB
);
}

if (customEditorWidget?.action === EDIT_LABEL_ACTION && customEditorWidget.impl.getLabelPrefix) {
return (
<LabelEditor
widget={customEditorWidget.widget}
defaultLabel={customEditorWidget.impl.getLabelPrefix(customEditorWidget.widget)}
onComplete={handleEditorComplete}
onCancel={handleEditorCancel}
/>
);
}

// If custom editor is active, render it instead of the normal UI
if (customEditorWidget?.impl.renderEditor) {
return customEditorWidget.impl.renderEditor({
Expand Down Expand Up @@ -582,6 +609,7 @@ export const ItemsEditor: React.FC<ItemsEditorProps> = ({ widgets, onUpdate, onB
? getNumberFormatModifierText(widget)
: undefined;
const hideModifierText = widgetImpl ? getHideModifierText(widget, widgetImpl.getHideableStates?.() ?? []) : undefined;
const labelModifierText = widgetImpl?.getLabelPrefix && !widget.rawValue ? getLabelModifierText(widget) : undefined;

return (
<Box key={widget.id} flexDirection='row' flexWrap='nowrap'>
Expand Down Expand Up @@ -611,6 +639,12 @@ export const ItemsEditor: React.FC<ItemsEditorProps> = ({ widgets, onUpdate, onB
{hideModifierText}
</Text>
)}
{labelModifierText && (
<Text dimColor>
{' '}
{labelModifierText}
</Text>
)}
{supportsRawValue && widget.rawValue && <Text dimColor> (raw value)</Text>}
{widget.merge === true && <Text dimColor> (merged→)</Text>}
{widget.merge === 'no-padding' && <Text dimColor> (merged-no-pad→)</Text>}
Expand Down
53 changes: 53 additions & 0 deletions src/tui/components/LabelEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {
Box,
Text,
useInput
} from 'ink';
import React from 'react';

import type { WidgetItem } from '../../types/Widget';
import {
clearLabel,
getLabel,
setLabel
} from '../../widgets/shared/raw-or-labeled';
import { useTextCursor } from '../../widgets/shared/text-cursor';

export interface LabelEditorProps {
widget: WidgetItem;
defaultLabel: string;
onComplete: (updatedWidget: WidgetItem) => void;
onCancel: () => void;
}

export const LabelEditor: React.FC<LabelEditorProps> = ({ widget, defaultLabel, onComplete, onCancel }) => {
const { getText, display, handleInput } = useTextCursor(getLabel(widget, defaultLabel));

useInput((input, key) => {
if (key.return) {
onComplete(setLabel(widget, getText()));
} else if (key.escape) {
onCancel();
} else if (key.tab) {
onComplete(clearLabel(widget));
} else {
handleInput(input, key);
}
});

// Quoted so trailing spaces, which usually separate the label from the
// value, stay visible. One Text, because Ink measures a toned or joined
// emoji as several columns and a sibling Text would overwrite its end.
return (
<Box flexDirection='column'>
<Text bold>Label</Text>
<Text dimColor>←→ move cursor, Ctrl+←→ jump to start/end, Tab reset to default, Enter save, ESC cancel</Text>
<Box marginTop={1}>
<Text>
{`"${display}"`}
<Text dimColor>{` (default: ${JSON.stringify(defaultLabel)})`}</Text>
</Text>
</Box>
</Box>
);
};
Loading
Loading