Welcome to the first chapter of our journey into building a smart Command Line Interface (CLI)!
We are going to start with a feature that makes your tool feel intelligent: the Plugin Hint System.
Imagine you are in a kitchen trying to open a can of soup, but you are holding a spoon. A helpful assistant taps you on the shoulder and says: "I see you are trying to open a can. Would you like me to hand you the Can Opener tool?"
This is exactly what the Plugin Hint System does for your code.
When a user runs a command (like sourceCommand) but lacks the specific tool to handle it perfectly, this system steps in. It presents a menu suggesting a specific extension (Plugin) from a marketplace that can do the job.
To make this work, we need three main ingredients:
The core of this system is a React component called PluginHintMenu. It handles the display and the user's choice.
Here is a high-level look at how we use it in our application code.
We pass the details of what we are recommending.
<PluginHintMenu
pluginName="Data Viewer"
marketplaceName="Official Store"
sourceCommand="view-data"
onResponse={(choice) => handleUserChoice(choice)}
/>
When this code runs, the user sees a neat dialog box in their terminal:
Plugin Recommendation
The view-data command suggests installing a plugin.
Plugin: Data Viewer
Marketplace: Official Store
>
Would you like to install it?
[>] Yes, install Data Viewer
[ ] No
[ ] No, and don't show plugin installation hints again
Let's look under the hood of PluginHintMenu.tsx. We will break it down into small, easy-to-understand pieces.
First, we define what information the menu needs to function.
// We define what data we need from the parent
type Props = {
pluginName: string; // The name of the tool to install
marketplaceName: string; // Where it comes from
sourceCommand: string; // What the user typed to trigger this
// The function to call when the user picks an option
onResponse: (response: 'yes' | 'no' | 'disable') => void;
};
Explanation: These Props act like the configuration settings for our menu. The onResponse is crucialβit's how the menu talks back to the main application.
We need to define what choices the user can make.
const options = [{
label: <Text>Yes, install <Text bold>{pluginName}</Text></Text>,
value: 'yes'
}, {
label: 'No',
value: 'no'
}, {
label: "No, and don't show plugin installation hints again",
value: 'disable'
}];
Explanation: We create an array of options. Notice that for the "Yes" option, we use <Text> components to make the plugin name bold. This formatting relies on Ink UI Components.
When the user picks an option, we need to process it.
function onSelect(value: string): void {
switch (value) {
case 'yes':
onResponse('yes');
break;
case 'disable':
onResponse('disable');
break;
default:
onResponse('no');
}
}
Explanation: This function acts as a middleman. It takes the raw value selected by the user and ensures the correct onResponse callback is fired.
Finally, we put it all together inside a dialog wrapper.
return (
<PermissionDialog title="Plugin Recommendation">
<Box flexDirection="column" paddingX={2}>
<Text>
The <Text bold>{sourceCommand}</Text> suggests a plugin.
</Text>
{/* ... details regarding plugin name ... */}
<Select
options={options}
onChange={onSelect}
/>
</Box>
</PermissionDialog>
);
Explanation:
PermissionDialog to give it a nice border and title (see Permission Dialog Wrapper).Box and Text to layout the description.Select component to let the user choose an answer (see Custom Selection Input).How does the data flow when this hint appears? Let's visualize the process.
You might have noticed in the diagram above that if the user does nothing, the menu disappears.
The PluginHintMenu includes a built-in timer. If the user doesn't interact within 30 seconds (AUTO_DISMISS_MS), the menu automatically selects "No" to keep the terminal clean.
React.useEffect(() => {
// Set a timer to auto-dismiss after 30 seconds
const timeoutId = setTimeout(
ref => ref.current('no'),
AUTO_DISMISS_MS,
onResponseRef
);
// Clean up the timer if the user answers manually
return () => clearTimeout(timeoutId);
}, []);
Explanation: This uses React's useEffect to start a countdown the moment the menu appears. We will cover the specific mechanics of this timer logic in detail in Time-Limited Interactions.
You have now learned how to create a Plugin Hint System! This component is a friendly way to bridge the gap between what a user wants to do and the tools they need to do it.
Key takeaways:
sourceCommand).To make this menu look good, we relied heavily on basic building blocks. In the next chapter, we will learn exactly how those blocks work.
Next Chapter: Ink UI Components
Generated by Code IQ