Make your CLI program interactive
In this chapter, you'll get hands-on practice with Dart syntax. You'll learn how to read user input, print usage information, and create a basic command-line interaction.
Prerequisites
#Before you begin this chapter, ensure you have:
- Completed Chapter 1 and have a working Dart development environment.
- Familiarity with basic programming concepts (variables, data types, control flow).
Tasks
#Add some basic functionality to your Dartpedia command-line application and then explore the Dart syntax for it.
Task 1: Implement version and help commands
#Implement the
version
command incli/bin/cli.dart
: Add logic to handle aversion
command, which prints the current version of the CLI. Use anif
statement to check if the first argument provided isversion
. You'll also need aversion
constant.First, above your
main
function, declare aconst
variable for the version. The value of aconst
variable can never be changed after it's been set:dartconst version = '0.0.1'; // Add this line
Next, modify your
main
function to check for theversion
argument:dartvoid main(List<String> arguments) { if (arguments.isEmpty) { print('Hello, Dart!'); } else if (arguments.first == 'version') { print('Dartpedia CLI version $version'); } }
Test the
version
command: Run your application with the version argument:bashdart bin/cli.dart version
You should now see:
bashDartpedia CLI version 0.0.1
If you run your app without arguments, you'll still see "Hello, Dart!".
Add a
printUsage
function: To make the output more user-friendly, create a separate function to display usage information. Place this function outside and below yourmain
function.dartvoid printUsage() { // Add this new function print( "The following commands are valid: 'help', 'version', 'search <ARTICLE-TITLE>'" ); }
search
is the command that will eventually search from Wikipedia.Implement the
help
command and refinemain
: Now, integrate thehelp
command using anelse if
statement, and clean up the default behavior to call theprintUsage
function.Modify your
main
function to look like this:dartvoid main(List<String> arguments) { if (arguments.isEmpty || arguments.first == 'help') { printUsage(); // Change this from 'Hello, Dart!' } else if (arguments.first == 'version') { print('Dartpedia CLI version $version'); } else { printUsage(); // Catch all for any unrecognized command. } }
Understand the
if/else
structure and variables: Now that you've implemented control flow in themain
function, review the code that was added for it.arguments.isNotEmpty
checks if any command-line arguments were provided.arguments.first
accesses the very first argument, which you're using as our command.version
is declared as aconst
. This means its value is known at compile time and you can't change it during runtime.arguments
is a regular (non-constant) variable because its content can change during runtime based on user input.
Run your application with the help argument. You should see the usage information printed:
bashdart bin/cli.dart help
Also, try running it without any arguments:
bashdart bin/cli.dart
Notice that it continues to display usage information. At this point, any command you haven't defined will also print usage information. This is expected behavior for now.
Task 2: Implement the search command
#Next, implement a basic search
command that takes an article title as input. As you build this functionality, you'll work with List
manipulation, null checks, and string interpolation.
Integrate the
search
command intomain
: First, modify themain
function incli/bin/cli.dart
to include anelse if
branch that handles thesearch
command. For now, just print a placeholder message.dartvoid main(List<String> arguments) { if (arguments.isEmpty || arguments.first == 'help') { printUsage(); } else if (arguments.first == 'version') { print('Dartpedia CLI version $version'); } else if (arguments.first == 'search') { // Add this new block: print('Search command recognized!'); } else { printUsage(); } }
Test the new command: Run your application with the
search
command:bashdart bin/cli.dart search
You should see:
bashSearch command recognized!
Define the
searchWikipedia
function: Thesearch
command will eventually run the core logic of your application by calling a function calledsearchWikipedia
. For now, havesearchWikipedia
print the arguments passed into it with thesearch
command. Place this new function belowmain
.dart// ... (your existing main function) void searchWikipedia(List<String>? arguments) { // Add this new function and add ? to arguments type print('searchWikipedia received arguments: $arguments'); } // ... (your existing printUsage() function)
Highlights from the preceding code:
List<String>? arguments
means that thearguments
list itself can benull
.
Call the
searchWikipedia
function from themain
function: Now, modify thesearch
command block inmain
to callsearchWikipedia
and pass it any arguments that come after thesearch
command itself. Usearguments.sublist(1)
to get all arguments starting from the second one. If no arguments are provided aftersearch
, passnull
tosearchWikipedia
.dartvoid main(List<String> arguments) { if (arguments.isEmpty || arguments.first == 'help') { printUsage(); } else if (arguments.first == 'version') { print('Dartpedia CLI version $version'); } else if (arguments.first == 'search') { // Add this new block: final inputArgs = arguments.length > 1 ? arguments.sublist(1) : null; searchWikipedia(inputArgs); } else { printUsage(); } }
Highlights from the preceding code:
arguments.sublist(1)
creates a new list containing all elements of thearguments
list after the first element (which wassearch
).arguments.length > 1 ? ... : null;
is a conditional (ternary) operator. It ensures that if no arguments are provided after thesearch
command,inputArgs
becomesnull
, matching the sample code's behavior forsearchWikipedia
'sarguments
parameter ofList<String>?
.
Test
searchWikipedia
with arguments: Using the command line, run the application with a test article title:bashdart bin/cli.dart search Dart Programming
You should see:
bashsearchWikipedia received arguments: [Dart, Programming]
Next, run the same command without the extra arguments:
bashdart bin/cli.dart search
You should see:
bashsearchWikipedia received arguments: null
Handle the missing article title and user input with the
stdin
command: It's more user-friendly to prompt the user if they don't provide an article title on the command line. Usestdin.readLineSync()
for this.First, add the necessary import at the top of your
cli/bin/cli.dart
file:dartimport 'dart:io'; // Add this line at the top
dart:io
is core library in the Dart SDK, and provides APIs to deal with files, directories, sockets, and HTTP clients and servers, and more.Now, update your
searchWikipedia
function.dartvoid searchWikipedia(List<String>? arguments) { late String articleTitle; // If the user didn't pass in arguments, request an article title. if (arguments == null || arguments.isEmpty) { print('Please provide an article title.'); articleTitle = stdin.readLineSync(); // Await input from the user } else { // Otherwise, join the arguments into the CLI into a single string articleTitle = arguments.join(' '); } print('Current article title: $articleTitle'); }
This preceding code block introduces a few key concepts:
- It declares a
late String? articleTitle
variable which will hold the full search query, whether it comes from the command line or user input.late
is a keyword that tells the analyzer that you, the programmer, promise that this variable won't be null by the time it's used. - An
if/else
statement then checks if command-line arguments for the search were provided. - If arguments are missing, it prompts the user, reads input using
stdin.readLineSync()
, and performs null and empty checks. - If arguments are present, it uses
arguments.join(' ')
to combine them into a single search string.
Highlights from the preceding code:
stdin.readLineSync()
reads a line of text typed by the user into the console. Its return type isString?
.if (inputFromStdin == null || inputFromStdin.isEmpty)
performs a null check and an empty string check. If either is true, the program prints a message andreturn
s, exiting the function.arguments.join(' ')
: concatenates all elements of thearguments
list into a single string, using a space as the separator. For example,['Dart', 'Programming']
becomes"Dart Programming"
. This is crucial for treating multi-word command-line inputs as a single search phrase.
- It declares a
Finish
searchWikipedia
to print mock search results: UpdatesearchWikipedia
to display messages that look like our program found something. This helps us see what our finished program will do without actually building everything right now. You'll only see these messages if you include a search query when you run the program.For example:
dart bin/cli.dart search Dart Programming
.dartvoid searchWikipedia(List<String>? arguments) { late String? articleTitle; if (arguments == null || arguments.isEmpty) { print('Please provide an article title.'); articleTitle = stdin.readLineSync(); return; // Exits here if input is from stdin } else { articleTitle = arguments.join(' '); } print('Looking up articles about "$articleTitle". Please wait.'); print('Here ya go!'); print('(Pretend this is an article about "$articleTitle")'); }
Final Test Run with both scenarios:
Now that the article simulation is set up, test the
searchWikipedia
function in a few different ways:bashdart bin/cli.dart search Dart Programming
You should see:
bashLooking up articles about "Dart Programming". Please wait. Here ya go! (Pretend this is an article about "Dart Programming")
Run without arguments (type "Flutter Framework" when prompted):
bashdart bin/cli.dart search
bashPlease provide an article title. Flutter Framework
You have now successfully built the basic
search
command with user input handling, correctly treating multi-word command-line inputs as a single search phrase in the output.
Review
#In this chapter, you learned:
- Control flow: Using
if/else
statements to control the execution flow of your program. - Variables and Constants: Declaring variables with
var
,const
, andlate String?
. - Lists: Creating and manipulating lists using
.isNotEmpty
,.first
,.sublist
, and.join()
. - Null Safety: Understanding nullability (
?
) and using null checks. - Functions: Defining and calling functions.
- String interpolation: Embedding variables in strings using
$
. - Input/Output: Reading user input from the console using
stdin.readLineSync()
.
Quiz
#Question 1: Which keyword is used to declare a constant variable in Dart whose value is known at compile time?
- A)
var
- B)
final
- C)
const
- D)
static
Question 2: What is the primary purpose of stdin.readLineSync()
in a CLI application?
- A) To print output to the console.
- B) To read a single line of text input from the user.
- C) To execute a command.
- D) To check if a file exists.
Next lesson
#In the next chapter, you'll dive into asynchronous programming and learn how to fetch data from the Wikipedia API using the http
package. This will allow your application to retrieve real data and display it to the user.
Unless stated otherwise, the documentation on this site reflects Dart 3.8.1. Page last updated on 2025-06-13. View source or report an issue.