Skip to content

Commit 96175a8

Browse files
authored
Update ClockExtension sample (#3872)
* update ClockExtension sample and docs
1 parent b53a9fb commit 96175a8

File tree

4 files changed

+232
-101
lines changed

4 files changed

+232
-101
lines changed

Diff for: docs/extending-dotnet-interactive.md

+54-43
Original file line numberDiff line numberDiff line change
@@ -35,64 +35,75 @@ Give the [sample notebook](../samples/extensions/ClockExtension.ipynb) a try to
3535

3636
Here are some of the more common things you might want to do when extending .NET Interactive.
3737

38-
## Add magic commands
38+
### Add magic commands
3939

40-
You can add to the set of magic commands available in your notebooks. A magic command is defined using [System.CommandLine](https://learn.microsoft.com/en-us/dotnet/standard/commandline/) to parse the user's input as well as provide help and completions. A `System.CommandLine.Command` is used to define a magic command. The handler you define for the command will be invoked when the user runs the magic command.
40+
You can create you own magic commands and add them to the available commands in your notebooks either by writing an extension or by defining them directly in the notebook code. Magic commands are defined using the APIs under the `Microsoft.DotNet.Interactive.Directives` namespace to parse the user's input and define the associated actions performed by the magic command, as well as provide hover help and completions.
4141

42-
Here's an example from the `ClockExtension` sample, showing how to define the `#!clock` magic command:
42+
We'll use the example found in the [`ClockExtension` sample](https://github.com/dotnet/interactive/blob/main/samples/extensions/ClockExtension) to go over the high-level usage of this API. This sample creates a magic command called `#!clock` that can be used to display an SVG rendering of a clock showing the specified time.
43+
44+
<img src="https://github.com/user-attachments/assets/4d5a10c8-daac-444a-9c99-699e526307b9" />
45+
46+
Let's start by looking at the code used to define the magic command itself. This code creates a magic command (`#!clock`) with three parameters (`--hour`, `--minute`, and `--second`), which can be called as in the screen shot above. We'll go through the code step by step to explain how the API is used.
4347

4448
```csharp
45-
public class ClockKernelExtension : IKernelExtension
49+
var hourParameter = new KernelDirectiveParameter("--hour", "The position of the hour hand");
50+
var minuteParameter = new KernelDirectiveParameter("--minute", "The position of the minute hand");
51+
var secondParameter = new KernelDirectiveParameter("--second", "The position of the second hand");
52+
53+
var clockDirective = new KernelActionDirective("#!clock")
4654
{
47-
public async Task OnLoadAsync(Kernel kernel)
48-
{
49-
// ...
50-
51-
var hourOption = new Option<int>(new[] { "-o", "--hour" },
52-
"The position of the hour hand");
53-
var minuteOption = new Option<int>(new[] { "-m", "--minute" },
54-
"The position of the minute hand");
55-
var secondOption = new Option<int>(new[] { "-s", "--second" },
56-
"The position of the second hand");
57-
58-
var clockCommand = new Command("#!clock", "Displays a clock showing the current or specified time.")
59-
{
60-
hourOption,
61-
minuteOption,
62-
secondOption
63-
};
64-
65-
//...
66-
67-
kernel.AddDirective(clockCommand);
68-
69-
// ...
70-
}
71-
}
55+
Description = "Displays a clock showing the current or specified time.",
56+
Parameters =
57+
[
58+
hourParameter,
59+
minuteParameter,
60+
secondParameter
61+
]
62+
};
7263
```
7364

74-
Once the `Command` has been added using `Kernel.AddDirective`, it's available in the kernel and ready to be used.
65+
A `KernelActionDirective` is used to define a magic command and give it a name (`#!clock`), which is the text used in code to invoke it. The `KernelDirectiveParameter` class is used to define the parameters that the magic command accepts.
7566

76-
System.CommandLine allows users to get help for a magic command just like they can get help on in a command line app. For example, to get help for the `#!clock` magic command, you can run `#!clock -h`. That produces the following output:
67+
The names and descriptions for these objects are used to provide hover help and standard completions such as parameter names.
7768

78-
```console
79-
Description:
80-
Displays a clock showing the current or specified time.
69+
<img src="https://github.com/user-attachments/assets/85adc71a-cf7c-418e-b8b5-a3832576d0a9" />
8170

82-
Usage:
83-
#!clock [options]
71+
<img src="https://github.com/user-attachments/assets/78654d82-68c8-49b5-a779-83624565ad4f" />
8472

85-
Options:
86-
-o, --hour <hour> The position of the hour hand
87-
-m, --minute <minute> The position of the minute hand
88-
-s, --second <second> The position of the second hand
89-
-?, -h, --help Show help and usage information
73+
The next step is to add the `KernelActionDirective` to the kernel where it will be in scope.
74+
75+
```csharp
76+
kernel.AddDirective<DisplayClock>(clockDirective, (displayClock, context) =>
77+
{
78+
context.Display(
79+
SvgClock.DrawSvgClock(
80+
displayClock.Hour,
81+
displayClock.Minute,
82+
displayClock.Second));
83+
return Task.CompletedTask;
84+
});
9085
```
9186

92-
By calling the `#!clock` magic command, you can draw a lovely purple clock using SVG with the hands at the positions specified:
87+
Several things are happening in the above code.
88+
89+
* `kernel.AddDirective` adds the the directive (`clockDirective`) to the kernel.
90+
* The generic parameter (`DisplayClock`) defines the type of the associated `KernelCommand` that will be instantiated and sent to the kernel when the magic command is invoked.
91+
* The delegate defines the code that will run to handle the `DisplayClock` command.
92+
93+
Here's the definition of `DisplayClock`:
94+
95+
```csharp
96+
public class DisplayClock : KernelDirectiveCommand
97+
{
98+
public int Hour { get; set; }
99+
public int Minute { get; set; }
100+
public int Second { get; set; }
101+
}
102+
```
93103

94-
<img width="513" alt="image" src="https://user-images.githubusercontent.com/547415/213597279-a5bf64b4-f6de-4f78-a29c-af3c6052677c.png">
104+
Note that `KernelDirectiveCommand` inherits `KernelCommand`, so you can send the `DisplayClock` command directly using the `Kernel.SendAsync` method, just like any other `KernelCommand`.
95105

106+
### Customize formatting
96107

97108
The extension also changes the default formatting for the `System.DateTime` type. This feature is the basis for creating custom visualizations for any .NET type. Before installing the extension, the default output just used the `DateTime.ToString` method:
98109

0 commit comments

Comments
 (0)