WEBVTT

00:00.000 --> 00:10.000
My next speaker in the section of today, which is called using Go.

00:10.000 --> 00:16.000
And using Go to write a shell and programming language, looks so interesting.

00:16.000 --> 00:22.000
I could not reject these proposals to come talk about how to build a language in a programming language.

00:22.000 --> 00:24.000
Which ran to our class.

00:29.000 --> 00:31.000
Hello.

00:31.000 --> 00:33.000
I guess you can hear me.

00:33.000 --> 00:35.000
How is everybody doing?

00:35.000 --> 00:38.000
I'm obviously, let's all try to stay awake.

00:38.000 --> 00:39.000
All right.

00:39.000 --> 00:43.000
So I'm going to talk about developing a modern shell and programming language with Go.

00:43.000 --> 00:45.000
My name is Qi.

00:45.000 --> 00:47.000
As introduced.

00:47.000 --> 00:48.000
Right.

00:48.000 --> 00:50.000
This thing is called Elvish.

00:50.000 --> 00:52.000
The website has a domain name.

00:52.000 --> 00:54.000
I'm very proud of.

00:54.000 --> 00:56.000
So first thing first.

00:56.000 --> 01:00.000
So I think a lot of people don't know how to show different from a terminal.

01:00.000 --> 01:02.000
Because a lot of the time you kind of use them together.

01:02.000 --> 01:04.000
They kind of blend together in a lot of people's minds.

01:04.000 --> 01:09.000
So the way I think about this is that like the shell is just a program that runs in the terminal.

01:09.000 --> 01:11.000
It's usually the first program.

01:11.000 --> 01:16.000
So you can think of it as kind of back when people still set home pages in the browser.

01:16.000 --> 01:18.000
It's kind of like the homepage browser.

01:18.000 --> 01:20.000
It's like just another web page.

01:20.000 --> 01:22.000
But just you go to it first.

01:22.000 --> 01:26.000
So shell is a program that runs your terminal by you.

01:26.000 --> 01:27.000
You tend to start it first.

01:27.000 --> 01:28.000
Actually don't have to.

01:28.000 --> 01:32.000
You can say you're terminated to start them or anything like that.

01:32.000 --> 01:33.000
Right.

01:33.000 --> 01:34.000
So Elvish is a shell.

01:34.000 --> 01:38.000
That means it's kind of like bash, zesh, and fish and other things.

01:38.000 --> 01:40.000
So there's a bit more modern.

01:40.000 --> 01:42.000
And by modern I mean two things.

01:42.000 --> 01:45.000
One is that it has more powerful interactive features.

01:45.000 --> 01:47.000
There also has a full-fledged programming language.

01:47.000 --> 01:49.000
And we'll talk a bit about both aspects a bit.

01:49.000 --> 01:51.000
And there are other modern shells.

01:51.000 --> 01:53.000
Here are just three.

01:53.000 --> 01:55.000
And there are more if you look up.

01:55.000 --> 01:57.000
So why make a shell?

01:57.000 --> 02:02.000
So the way I think about this is that like in our profession as programmers.

02:02.000 --> 02:06.000
We're actually very similar to like back blacksmiths back in the olden days.

02:06.000 --> 02:10.000
In that we are uniquely qualified to make our own tools.

02:10.000 --> 02:13.000
That's something a lot of other professors don't have.

02:13.000 --> 02:17.000
I think shell is a way to make your own tool.

02:17.000 --> 02:19.000
Something that you can use.

02:19.000 --> 02:25.000
And it is something that shells then can be also used to make other tools in the form of shell scripts of course.

02:25.000 --> 02:33.000
So I think of like the rationale for making a shell in this two kind of recursive aspects.

02:33.000 --> 02:34.000
Right.

02:34.000 --> 02:39.000
Let's talk a bit about what does the full-fledged programming language look like.

02:39.000 --> 02:44.000
I think a lot of people think that advanced programming features and shell script are kind of incompatible.

02:44.000 --> 02:45.000
I don't think that is true.

02:45.000 --> 02:50.000
And here's like a very contrived example to try to convince you in a minute.

02:50.000 --> 02:54.000
So so this is kind of it's not.

02:54.000 --> 02:57.000
It's a very real workflow to have to do all the time in that.

02:57.000 --> 02:59.000
I have two different servers.

02:59.000 --> 03:03.000
Unfortunately one of them runs and dead in another runs.

03:04.000 --> 03:07.000
And I want to like update them.

03:07.000 --> 03:13.000
And I want to do this in parallel because updating ones that we shouldn't need to wait upon the other server.

03:13.000 --> 03:16.000
In a traditional shell language this can be awkward.

03:16.000 --> 03:19.000
But in Elvish like you can model this in a pretty natural way.

03:19.000 --> 03:22.000
So for instance, Elvish has nested a data structure.

03:22.000 --> 03:28.000
So you can write a list of maps and each map describes a server and a server has a name and has a command.

03:28.000 --> 03:32.000
And then Elvish has this peach command means parallel each.

03:32.000 --> 03:35.000
It takes this list and it takes a lambda.

03:35.000 --> 03:40.000
And the lambda says what you need to do with each element of the list.

03:40.000 --> 03:43.000
So that kind of comes very naturally in Elvish.

03:43.000 --> 03:48.000
And I think you would it would be a little bit awkward to write it in like many other languages.

03:48.000 --> 03:50.000
Like if you write in a traditional shell.

03:50.000 --> 03:53.000
It's a bit awkward because they don't have like nested data structure.

03:53.000 --> 03:55.000
So you have to kind of mix data and logic.

03:55.000 --> 04:00.000
But if you write it in like another program language like Python or even go.

04:00.000 --> 04:03.000
It doesn't allow you to like just say SSH.

04:03.000 --> 04:06.000
You have to say something like exact command SSH something like that.

04:06.000 --> 04:09.000
But in the shell this is all very natural.

04:09.000 --> 04:14.000
And Elvish also still has all the familiar shell features.

04:14.000 --> 04:16.000
So you can just run commands.

04:16.000 --> 04:18.000
That's what you do in the shell at the time.

04:18.000 --> 04:20.000
And it has like things like wildcards.

04:20.000 --> 04:23.000
So for instance you can count number of lines in your go files.

04:23.000 --> 04:26.000
This is something actually actually to quite often.

04:26.000 --> 04:29.000
So you can do.

04:29.000 --> 04:36.000
But Elvish also extends this pattern in that it has recursive wildcards.

04:36.000 --> 04:41.000
So you can count all the go files not just directly in the directory.

04:41.000 --> 04:43.000
So this is also something I do a lot of time.

04:43.000 --> 04:49.000
And unfortunately Elvish has more than 70,000 lines of code now.

04:49.000 --> 04:54.000
And you can also use Elvish as a wild write scripts obviously.

04:54.000 --> 04:58.000
And I think in many ways it's kind of complimentary to go.

04:58.000 --> 05:04.000
And one example I always like to give is that Elvish has a continuous deployment pipeline,

05:04.000 --> 05:06.000
which doesn't use any existing solution.

05:06.000 --> 05:07.000
It's just some.

05:07.000 --> 05:11.000
It's a go program and a JavaScript that I just put together.

05:11.000 --> 05:15.000
So I think that like go is very good to write a web server with like all the build thing.

05:15.000 --> 05:16.000
It should be module and stuff.

05:16.000 --> 05:20.000
So if you want something simple, you don't need anything besides the standard module.

05:20.000 --> 05:23.000
But when it comes to actually building things like invoking a lot of commands,

05:23.000 --> 05:25.000
you'll get a little bit unwieldly.

05:25.000 --> 05:31.000
And I compliment that by just writing the meat of the CD logic in an Elvish script.

05:31.000 --> 05:34.000
It's actually in the Elvish report.

05:34.000 --> 05:36.000
Like part of it is in the Elvish report.

05:36.000 --> 05:40.000
But another part of it is in the different report called Elvish up.

05:40.000 --> 05:42.000
Let me show that.

05:42.000 --> 05:44.000
Okay, so it's for how to find files.

05:44.000 --> 05:46.000
Give up.

05:46.000 --> 05:50.000
So I think like I think this is a very nice pattern.

05:50.000 --> 05:54.000
Like you have a slightly more low level language to handle things like speed serving

05:54.000 --> 05:59.000
and have a more high level language to define your actual CRCD workflow.

05:59.000 --> 06:02.000
Much better than I am.

06:02.000 --> 06:04.000
Right, interactive features.

06:04.000 --> 06:07.000
So let's just do some demo.

06:07.000 --> 06:10.000
You have things like Elvish has it's in that highlighting.

06:10.000 --> 06:15.000
And with more than like a highlight things like strings, comments,

06:15.000 --> 06:17.000
has completion.

06:17.000 --> 06:20.000
Like pretty standard stuff.

06:20.000 --> 06:23.000
And it also has a directory history.

06:23.000 --> 06:26.000
I have shown that a little bit if you press Ctrl L.

06:26.000 --> 06:29.000
It gives you a list of all the directories of being through.

06:29.000 --> 06:32.000
So most of the time you don't, you shouldn't need CD.

06:32.000 --> 06:35.000
Like, this is where my slides are.

06:35.000 --> 06:38.000
I just start typing SLI and I see.

06:38.000 --> 06:41.000
Okay, I'm not currently in the slides directory.

06:41.000 --> 06:42.000
So it doesn't work.

06:42.000 --> 06:44.000
If I just type SL, I can see slides.

06:44.000 --> 06:46.000
I go to slides.

06:46.000 --> 06:49.000
And then it has command history with Ctrl R.

06:49.000 --> 06:52.000
So this is kind of the same binding as in Bash or Zesh.

06:52.000 --> 06:54.000
But instead of like looking at one command at the time,

06:54.000 --> 06:56.000
it gives you a list of all the commands.

06:56.000 --> 06:59.000
And you can do searching like, like, this is FF,

06:59.000 --> 07:00.000
and pay command.

07:00.000 --> 07:02.000
I wouldn't ever know how to be a phone scratch.

07:02.000 --> 07:04.000
But it's in my command history.

07:04.000 --> 07:06.000
So nice.

07:06.000 --> 07:07.000
Right.

07:07.000 --> 07:10.000
And it also has a built-in file system navigator.

07:10.000 --> 07:12.000
It's press Ctrl L and M for navigation.

07:12.000 --> 07:15.000
And this allows you to like, preview files and like,

07:15.000 --> 07:18.000
change directories and that kind of stuff.

07:20.000 --> 07:21.000
Right.

07:21.000 --> 07:22.000
I wrote this soon.

07:22.000 --> 07:25.000
The entire UI will be programmed over the new toy framework.

07:25.000 --> 07:26.000
And that's a bit ambitious.

07:26.000 --> 07:27.000
It hasn't happened yet.

07:27.000 --> 07:29.000
Oh, I skipped this part.

07:29.000 --> 07:32.000
So I think the good thing with having introductory features

07:32.000 --> 07:35.000
and a good programming language is that I think they

07:35.000 --> 07:37.000
should have very good synergy together.

07:37.000 --> 07:41.000
So one thing when it comes to like customizing prompts,

07:41.000 --> 07:45.000
I guess people nowadays use like pre-pagged things like

07:45.000 --> 07:48.000
Starship and stuff, but in traditional like in Bash,

07:48.000 --> 07:51.000
after to learn this little language that has like

07:51.000 --> 07:52.000
percent of the H is hostname.

07:52.000 --> 07:55.000
percent you is using it that kind of stuff.

07:55.000 --> 07:56.000
In average, there's none of that.

07:56.000 --> 08:00.000
Instead, the prompt is just a lambda that you can assign to.

08:00.000 --> 08:03.000
And you can just output stuff in your prompt.

08:03.000 --> 08:07.000
So this is something you can do to get something similar,

08:07.000 --> 08:10.000
but not exactly the same as the default prompt.

08:10.000 --> 08:13.000
It's more similar to the Bash's default prompt,

08:13.000 --> 08:14.000
I think.

08:14.000 --> 08:16.000
And I hope this works.

08:16.000 --> 08:17.000
Please work.

08:17.000 --> 08:18.000
I think, oh, okay.

08:18.000 --> 08:21.000
I haven't actually installed Starfish, but if you install

08:21.000 --> 08:23.000
Starfish, the way you switch to Starfish is just,

08:23.000 --> 08:25.000
it's just called Starfish in your prompt.

08:25.000 --> 08:28.000
A Starship, sorry, not Starfish.

08:29.000 --> 08:33.000
Well, that would be a nice name for a project.

08:33.000 --> 08:35.000
All right.

08:35.000 --> 08:39.000
It's a go talk, so let's also talk a bit about my experience building

08:39.000 --> 08:41.000
I'll wish with go.

08:41.000 --> 08:44.000
So one thing I kind of showed a little bit earlier is

08:44.000 --> 08:46.000
which is data type support.

08:46.000 --> 08:48.000
I showed lists and maps, but they're also like pretty

08:48.000 --> 08:51.000
center things like Boolean strings, which are just

08:51.000 --> 08:53.000
those Boolean, like this is what you get.

08:53.000 --> 08:55.000
If you implement a language using another language,

08:55.000 --> 08:58.000
you kind of steal the whole language's data type.

08:58.000 --> 09:03.000
So you can do things like this is true.

09:03.000 --> 09:05.000
This is false.

09:05.000 --> 09:07.000
This is a string.

09:07.000 --> 09:10.000
This is just go through false and strings.

09:10.000 --> 09:12.000
And you can do.

09:12.000 --> 09:17.000
And also I still go syntax for strings, that kind of stuff.

09:17.000 --> 09:19.000
And you also have numbers.

09:19.000 --> 09:22.000
So you have goes primitive number types.

09:22.000 --> 09:25.000
Interflow 64.

09:25.000 --> 09:28.000
And go standard library also has those big numbers.

09:28.000 --> 09:30.000
In L, which is kind of a blend together.

09:30.000 --> 09:34.000
So they're like numbers auto promote to the appropriate numbers type.

09:34.000 --> 09:40.000
So you can compute 40 factorial just by doing this.

09:40.000 --> 09:42.000
And it works.

09:42.000 --> 09:45.000
And if you write something with slashes, it becomes a rational number.

09:45.000 --> 09:47.000
It becomes a big rat.

09:47.000 --> 09:51.000
I don't want to say that, but you can do something like this.

09:52.000 --> 09:55.000
And then the list and mapping limitations are kind of special.

09:55.000 --> 09:57.000
In that they're actually modeled after closure.

09:57.000 --> 09:59.000
They're actually mutable.

09:59.000 --> 10:02.000
But we don't have time to get too much into that.

10:02.000 --> 10:03.000
It's quite interesting.

10:03.000 --> 10:06.000
If you even know closure, then good for you.

10:06.000 --> 10:09.000
If you don't know closure, you should look it up.

10:09.000 --> 10:11.000
And standard library.

10:11.000 --> 10:12.000
That's another thing.

10:12.000 --> 10:15.000
I still from go, like I still a lot of goes standard library.

10:15.000 --> 10:17.000
So you can use the math module.

10:18.000 --> 10:20.000
Like, basically, it goes math module.

10:20.000 --> 10:23.000
So it has most stuff in here.

10:23.000 --> 10:27.000
I don't think it has everything, but it has probably most things you will need.

10:27.000 --> 10:30.000
Let's try this.

10:30.000 --> 10:32.000
It has pi.

10:32.000 --> 10:36.000
So, right, it should be zero, but it's a very small number.

10:36.000 --> 10:41.000
And strings.

10:41.000 --> 10:46.000
So one of the biggest gripes I have with traditional shelves is that.

10:46.000 --> 10:49.000
The string manipulations are so painful.

10:49.000 --> 10:53.000
There's an operator for trimming the prefix and the operative for trimming the suffix.

10:53.000 --> 10:54.000
And one of them is percent.

10:54.000 --> 10:55.000
Another is hash.

10:55.000 --> 10:57.000
And then remember which is which.

10:57.000 --> 11:01.000
So in LVs, I just still go standard string library.

11:01.000 --> 11:04.000
So you can do has prefix.

11:04.000 --> 11:09.000
You can do train prefix.

11:09.000 --> 11:12.000
And everything's fine.

11:12.000 --> 11:15.000
And regular expressions as well.

11:16.000 --> 11:29.000
Just to prove that it doesn't always return true.

11:29.000 --> 11:30.000
All right.

11:30.000 --> 11:34.000
Okay, that's actually just another colour for showing more of a lavish.

11:34.000 --> 11:38.000
But let's also talk a little bit about, kind of, to a slight deep dive.

11:38.000 --> 11:41.000
I guess a shallow dive into the implementation.

11:41.000 --> 11:45.000
I think the most interesting, like semantic part about shelves is.

11:45.000 --> 11:47.000
It's a pipeline semantics.

11:47.000 --> 11:50.000
So it's a thing that doesn't really exist in many other languages.

11:50.000 --> 11:52.000
But if you look at this.

11:52.000 --> 11:53.000
I mean, this is a trivial example.

11:53.000 --> 11:55.000
So I'm echoing the PIDM.

11:55.000 --> 11:57.000
Accounting how many characters they are in the PID,

11:57.000 --> 11:58.000
which is not very useful.

11:58.000 --> 12:03.000
But you can imagine, like, like, this being a much more complex command.

12:03.000 --> 12:06.000
Like, the thing with the pipeline is that they always run in parallel.

12:06.000 --> 12:11.000
So if this is a very complex amount that probably needs to make natural requests and stuff,

12:11.000 --> 12:13.000
the WC command will run in parallel.

12:14.000 --> 12:19.000
So, but, and this turned out to be, I think, that's actually very suited for, and go to implement.

12:19.000 --> 12:22.000
So let's kind of speedrun through the interpreter implementation.

12:22.000 --> 12:27.000
So this start with stuff on the string, and it gets parsed, those are standard stuff.

12:27.000 --> 12:29.000
And then, Elvich has these kind of compilation step,

12:29.000 --> 12:32.000
but there's no way too much about those.

12:32.000 --> 12:37.000
But let's just keep in mind that this gets compared to a pipeline of, like, up-for operation,

12:37.000 --> 12:41.000
which has two phonops from kind of roughly means command.

12:41.000 --> 12:48.000
And one thing you realize is that, like, in shell, those commands really, like, have different standard input and standard output.

12:48.000 --> 12:50.000
So you have to represent that.

12:50.000 --> 12:54.000
So, obviously, you represent that using just a structure that has this thing.

12:54.000 --> 12:58.000
This is not a real definition, but good enough for this purpose.

12:58.000 --> 13:02.000
And this pipeline all, you can execute it with the, within the context,

13:02.000 --> 13:05.000
and the phonob, you can also execute it with the context.

13:05.000 --> 13:09.000
So that's kind of the setup of the pipeline semantics.

13:10.000 --> 13:12.000
So, implementing the pipeline semantics.

13:12.000 --> 13:15.000
I kind of, this is, really, this is, this is, again, more real code,

13:15.000 --> 13:17.000
by it's kind of the meat of the real code.

13:17.000 --> 13:22.000
And you can see, we actually use a lot of kind of, those booting stuff in here.

13:22.000 --> 13:26.000
So, for instance, like, this is a, let's assume for simplicity that there,

13:26.000 --> 13:28.000
we just, like, consider two forms,

13:28.000 --> 13:31.000
because if you can do two, you can probably do three and four and five.

13:31.000 --> 13:36.000
So we have two of them, and those two commands,

13:36.000 --> 13:40.000
there, the, the output of the first command is connected to the input of the second command.

13:40.000 --> 13:45.000
So, go give you just, you just, OS, OS, or pipe, and you get, like, two parts.

13:45.000 --> 13:49.000
And then, Elvish also has this idea where you can actually pass go values through

13:49.000 --> 13:51.000
to different commands.

13:51.000 --> 13:54.000
So, that's an Elvish specific thing, but that's just a go channel.

13:54.000 --> 13:58.000
And then, you can create the context for the first command,

13:58.000 --> 14:02.000
which I didn't show the inclination of this, but you can probably guess how your works.

14:02.000 --> 14:08.000
So, you just replace, it's a center output with the, the writing end of the pipe and the channel.

14:08.000 --> 14:13.000
And for the second form, you replace this center input with the reading end of the pipe and the channel.

14:13.000 --> 14:15.000
And you can now execute them parallel.

14:15.000 --> 14:19.000
Again, this uses, like, kind of, pretty center go, and idioms.

14:19.000 --> 14:22.000
You use, you, like, a spin-up, a wake-roop.

14:22.000 --> 14:25.000
You add two, and then you spin-up two and go routines.

14:25.000 --> 14:29.000
One of them is executing the first command, and then wake-roop down.

14:29.000 --> 14:31.000
You can look at the real code.

14:31.000 --> 14:37.000
It's, I mean, it's more complex than this, but by necessity, but, like, the meat idea is kind of like that.

14:37.000 --> 14:43.000
You can see those kind of, this is a go, here's a WG though down.

14:43.000 --> 14:50.000
Because it needs to handle, like, end command, things stuff, two commands, right?

14:50.000 --> 14:56.000
So, go is actually a pretty decent language to write a showing.

14:56.000 --> 14:58.000
This is a recap of the current section.

14:58.000 --> 15:01.000
So, like, you get a lot of data types, and the standard library for free.

15:01.000 --> 15:05.000
And it also has very good primitives for pipeline semantics.

15:05.000 --> 15:09.000
And another thing people don't always appreciate is that, because go is a garbage collector language.

15:09.000 --> 15:13.000
You might think, oh, this means your language must have proper formats.

15:13.000 --> 15:16.000
But, actually, it gives your language garbage collection for free as well.

15:16.000 --> 15:19.000
So, like, if you want to implement a language, like, in Rust,

15:19.000 --> 15:23.000
and your language is garbage collector, you have to write a garbage collector from scratch.

15:23.000 --> 15:25.000
But, go already has a garbage collector.

15:25.000 --> 15:28.000
So, if it just makes sure that language values are go values,

15:28.000 --> 15:34.000
and the language values are unreachable when go, like, when their go values are also unreachable,

15:34.000 --> 15:38.000
like, you can kind of pick it back on the, on the go garbage collector.

15:38.000 --> 15:40.000
So, that's quite nice.

15:40.000 --> 15:44.000
All right, let's also talk a bit about testing strategy, which I think is,

15:44.000 --> 15:48.000
if you are, like, into testing stuff, it's very interesting.

15:48.000 --> 15:52.000
If I'm not into testing stuff, hopefully I can convince you a little bit more.

15:52.000 --> 15:59.000
So, I think testing is very important, because give us a confidence about the correctness of the code.

15:59.000 --> 16:02.000
Like, if you never test your code, like, what did you write it?

16:02.000 --> 16:04.000
And, how do you know this correct?

16:04.000 --> 16:07.000
And, but, also, especially when you're changing your code.

16:07.000 --> 16:11.000
Like, when you're first write a code, I mean, like, the running ones, I think, is fine.

16:11.000 --> 16:14.000
But, you come back three months later, you have no idea what your code is doing.

16:14.000 --> 16:19.000
And, you have no idea if, like, changing a piece of code, we'll change another part, like.

16:20.000 --> 16:28.000
Right. So, I think the most important thing about the testing strategy is that you should make it very, very easy to create and maintain test,

16:28.000 --> 16:33.000
because there are already lazy. So, if you want to write more test, there must be very easy to write.

16:33.000 --> 16:37.000
So, easy to write test leads to more test leads to higher test coverage.

16:37.000 --> 16:43.000
So, I always has 92% test coverage. I don't think it's high enough, but it's probably higher than most projects.

16:44.000 --> 16:53.000
And, now, let's talk about the interpreter's API, like, because most of one non-most, like, about half of the average is probably rated through the interpreter.

16:53.000 --> 16:59.000
So, interpreter is actually one of the easiest things to test. So, because the, this API is very simple.

16:59.000 --> 17:06.000
So, it's input is just code, and this output is some text, and in the case of average, also output is some values.

17:06.000 --> 17:12.000
So, if you, like, this is your code, echo, hollow world, and this output is hollow world.

17:12.000 --> 17:22.000
And in average case, you can also output values, but it has a special command called a put. So, you can put hollow world for bar and in outputs to values.

17:22.000 --> 17:26.000
Right. So, this is how most of the average test used to be written.

17:26.000 --> 17:33.000
Like, this is a pretty standard in go community, I think, table driven tests. So, we just analyzed the API of the interpreter.

17:33.000 --> 17:37.000
So, you kind of encode that using a struct, right, and then you'll be the table of those structs.

17:37.000 --> 17:44.000
So, in the average case, the struct looks like this, this is code, and then you want some values, and then you want some text.

17:44.000 --> 17:58.000
And then you start writing these kind of things, and then you test function, you iterate through this slice, and then you, like, assume that this encapsulates the entirety of the interpreter, and then you just compare things.

17:58.000 --> 18:03.000
So, this is, this was fine for a while, but then you realize it's actually quite repetitive.

18:03.000 --> 18:08.000
So, every time you need to add a new test case, so what do you do? Let's look at that.

18:08.000 --> 18:14.000
So, step one is that you must have implemented something to new, otherwise, why you're writing tests, or maybe you're writing tests for existing stuff.

18:14.000 --> 18:22.000
Anyway, and then the second step, usually what I do is that, because the average is a shell, and we just test manually in a terminal.

18:22.000 --> 18:27.000
So, let's assume that I'm going to need to join the string drawing, which you must be familiar with, like, those strings are drawing.

18:27.000 --> 18:35.000
And then I would just do this in the terminal, and I say, oh, this is good, and then I manually convert the interaction into a test case.

18:35.000 --> 18:44.000
So, let's look at step three, like, I already did step two, I already tested it actually, I just tested it manually, not writing a real test.

18:44.000 --> 18:52.000
So, but shouldn't the computer be able to derive this test case from a manual testing session, like, and computers are really good at repetitive tasks.

18:52.000 --> 19:12.000
So, that's what I did. So, instead of defining strikes for inputs and outputs, let's just, let's just, like, copy-paste the terminal transcription into the test, and let's, and this thing just gets passed into the struct we have seen earlier, and then everything else is the same.

19:13.000 --> 19:26.000
So, then again, let's, so, let's kind of demonstrate that. So, let's assume this is how we do today, as to our drawing, A, B, right?

19:26.000 --> 19:36.000
Then, okay, I'm not using the default prompt. So, anyway, the kind of the, the test is kind of assumed that using the default prompt.

19:36.000 --> 19:54.000
So, let's paste that here, and then let's, let's actually run the test, and it passes, just to show, sure that it doesn't always pass, like, this introduced a manual type on here, and it tells you, okay, it didn't pass.

19:54.000 --> 20:09.000
And this was fine for a while, until I realized that I don't even want to do the copy-paste thing. So, what should we do instead, and we can just, like, if I need to do this in the terminal, then I have to copy-paste.

20:09.000 --> 20:21.000
If I don't want to copy-paste, I have to do this in the editor. So, what I did was I wrote an editor extension, and in this case, the as code. So, in the editor, so, this is how this works now.

20:21.000 --> 20:39.000
So, in the editor, I pretend I'm actually using L, which is not nice, but it's not too bad, and then there's a key, I can press, in my case, out, enter, and then it just, like, runs L, which for me, and shows the output.

20:39.000 --> 20:47.000
And then I press save, and this is my test case. There's no copy-paste thing involved. I just type, I kind of, this is also my manual testing session.

20:47.000 --> 21:01.000
So, my manual testing session results in an automatic testing written. So, I think this is a very good kind of property in that, we can eliminate test writing as a separate step to a development.

21:01.000 --> 21:15.000
So, because you will always do some sort of manual testing. If you can combine your manual testing with automatic testing, and then, probably you're kind of, kind of, offset for adding more test cases.

21:15.000 --> 21:29.000
All right, so the interpreter was very easy to test, because that's very simple API. Now, let's consider something slightly more complex. So, so, L, which is also a terminal application, as I've shown you before, like, it has all those, like, fancy bells and whistles.

21:29.000 --> 21:39.000
So, so, I also want the terminal application to be tested. So, and just to give you kind of, like, this is a very rough approximation of how it works under the hood.

21:39.000 --> 21:53.000
It's made up of a bunch of widgets, and there's a widget called text area. And for instance, one test case who may want to write is, if I press X and Y, it inserts X and Y, right? If I press left, it moves the cursor to the left.

21:53.000 --> 22:08.000
And if I press backspace at this point, it leads X instead of Y. So, this is one possible test case I want to write. So, this API is now much more complex than the simple interpreter API. It's no longer like, text in text and some values out anymore.

22:08.000 --> 22:14.000
It's kind of taking turns. Like, I do something, I want to see something, I want to see something.

22:14.000 --> 22:21.000
All right, and the solution to that is, we already have this framework of running testing the editor, why don't we just, like, make use of that.

22:21.000 --> 22:28.000
So, which I just create, I wish bindings for each of those widgets, and this binding comes in in the form of two commands.

22:28.000 --> 22:33.000
There's a send command, and there's a render command. The send command emulates some keyboard events.

22:33.000 --> 22:38.000
The render commands just don't set up the terminal. Again, another demo.

22:38.000 --> 22:46.000
I'm so okay. I chose the Sally different, has got it. So, in this case, that's right, ECO.

22:46.000 --> 22:58.000
And then I also just pressed Alt back enter as I did it before. So, and then I press left.

22:59.000 --> 23:06.000
Oh, it didn't work.

23:06.000 --> 23:13.000
No.

23:13.000 --> 23:23.000
Okay. I think it's the test feature.

23:24.000 --> 23:31.000
Anyway, this is more complicated than I try to make it look so, and that's probably why.

23:31.000 --> 23:38.000
Let me look at my test. I think, oh, text area, text demo fixer. Okay, sure.

23:38.000 --> 23:45.000
Right, because the way is implemented, by default, the left command actually doesn't do anything.

23:45.000 --> 23:48.000
I need to inject a specific kind of handler to it.

23:48.000 --> 23:53.000
Okay, this a little bit added a little bit more stuff in here.

23:53.000 --> 24:00.000
Ah, it still didn't work.

24:00.000 --> 24:06.000
Anyway, let's not worry too much about that. Let's choose a Sally simpler test case.

24:06.000 --> 24:12.000
So, let's know left keys anymore. We don't support that.

24:12.000 --> 24:16.000
Let's just do this thing where, like, I'm emulating kind of this.

24:16.000 --> 24:22.000
Like, when I'm taking type in the echo command, I start by having ECA H, right.

24:22.000 --> 24:26.000
And it's red because the command doesn't exist. And as a type, oh, it becomes green.

24:26.000 --> 24:30.000
So, a type ECA H and it's red and that type, oh, it's green.

24:30.000 --> 24:36.000
So, you may have noticed that there's kind of this single, and there's this kind of a DSL thing here,

24:36.000 --> 24:42.000
in that, like, the first line. Again, let me turn off syntax highlighting.

24:42.000 --> 24:47.000
Just to, because it's a bit distracting now, plain text.

24:47.000 --> 24:50.000
So, okay, this doesn't fix it.

24:50.000 --> 25:00.000
And let me look at this file in the terminal.

25:00.000 --> 25:04.000
Okay, so this is how it actually looks like, kind of, in pure text form.

25:04.000 --> 25:10.000
So, this is kind of a DSL in that the first line just represents the content of the file.

25:10.000 --> 25:14.000
And the second line represents the style of each character above it.

25:14.000 --> 25:21.000
So, by inventing this DSL, I'm able to encode the terminal state within pure text.

25:21.000 --> 25:24.000
Like, R says it's red and G says it's green, right.

25:24.000 --> 25:28.000
And then there's also this little thing that represents the cursor.

25:28.000 --> 25:31.000
It's too bad that I cannot show, like, it goes to the left,

25:31.000 --> 25:37.000
but it actually can go to the left, and it will overlap with those RNG characters.

25:37.000 --> 25:42.000
Because it's actually done using Unicode, kind of, direct critics.

25:42.000 --> 25:45.000
And it looks like a barrel.

25:49.000 --> 25:55.000
Anyway, I don't know if you've got this from, like, my box demo, but that's kind of the idea.

25:55.000 --> 26:01.000
So, right, so if you want to make testing, your test code, you need to make testing easy.

26:01.000 --> 26:04.000
And you should embrace DSLs, embrace text.

26:04.000 --> 26:08.000
And if DSLs don't solve your problem, that means you're not using enough of it.

26:08.000 --> 26:13.000
And this kind of similar idea of, like, just testing input outputs.

26:13.000 --> 26:15.000
Actually, it has a lot of presidents.

26:15.000 --> 26:18.000
I think the earliest example is materials tests.

26:18.000 --> 26:20.000
They actually write shell scripts.

26:20.000 --> 26:25.000
Elvis just set up his slide even more complicated.

26:25.000 --> 26:28.000
Like, this is an actual material test.

26:28.000 --> 26:31.000
Like, this is a shell session.

26:34.000 --> 26:38.000
All right, so I talked a lot about what Elvis can currently do.

26:38.000 --> 26:42.000
But I can also talk a bit about, kind of, my vision for, like, for the future of the shell.

26:42.000 --> 26:45.000
That kind of goes back to why I want to write a shell.

26:45.000 --> 26:49.000
Like, I don't think Elvis in this current form is, like, all I want it to be.

26:49.000 --> 26:51.000
I want it to be, like, a little more.

26:51.000 --> 26:54.000
Because I think shell languages are really, like, the language.

26:54.000 --> 26:57.000
If you think about it for, like, real personal computing.

26:57.000 --> 27:02.000
Like, today we are just using apps, like, packages that are developed by the companies,

27:02.000 --> 27:04.000
which I don't think is really ideal.

27:04.000 --> 27:06.000
I really want people to kind of build their own tools.

27:06.000 --> 27:10.000
And Elvis is kind of, like, my, my means to that.

27:10.000 --> 27:16.000
And, like, in my vision, we should be using, like, shells to manage your personal service.

27:16.000 --> 27:20.000
And to build simple CRCD pipelines, which I did instead of YAMO.

27:20.000 --> 27:24.000
And using shell, like, using shell to build, like, later UIs,

27:24.000 --> 27:27.000
that I tailor to you need instead of, like,

27:27.000 --> 27:33.000
I don't know, like, paying $200 to buy boutique and macOS apps.

27:33.000 --> 27:37.000
And I think shell should break free from the terminal at some point,

27:37.000 --> 27:41.000
but it's not happened yet.

27:41.000 --> 27:45.000
And if you want to learn more, if you want to learn more about interpreters,

27:45.000 --> 27:47.000
if that's kind of an interesting thing.

27:47.000 --> 27:51.000
There's a pretty, like, I think it's pretty standard these days to recommend an incredibly

27:51.000 --> 27:54.000
interpreters, but just in case you haven't heard it.

27:54.000 --> 27:58.000
And if you want to use a learn elvish, go to this website, and you can get elvish.

27:58.000 --> 28:06.000
And it has a one-line installation script that doesn't involve curl into bash.

28:06.000 --> 28:09.000
Because elvish is one binary thanks to go.

28:09.000 --> 28:12.000
So it's curl into tar instead of bash.

28:12.000 --> 28:14.000
So.

28:16.000 --> 28:21.000
Right. And it goes back to what I mentioned before, like, a shell is really just another program you

28:21.000 --> 28:25.000
don't need to think of, like, if I want to try elvish, you have to give up bash or zesh.

28:25.000 --> 28:29.000
It's just another program. So if you want to try it, you don't have to do, like,

28:29.000 --> 28:33.000
or nothing, you can just download it and then use it as another program.

28:33.000 --> 28:35.000
Every now and then see if you like it, if you really like it.

28:35.000 --> 28:39.000
And there is some guys on, like, how to use elvish as a default shell.

28:39.000 --> 28:42.000
You can also try it in the browser.

28:42.000 --> 28:46.000
Okay, I'm surprised every time this is still up, it hasn't been detoxed yet.

28:46.000 --> 28:52.000
So. But you can go here and there's an elvish session directly in the browser.

28:52.000 --> 28:55.000
You can do things.

28:55.000 --> 28:58.000
And if you want to hack an elvish, if I'm get up.

28:58.000 --> 29:03.000
And there are developer docs, which I hope is pretty good.

29:03.000 --> 29:07.000
There's architectural interview, process of contributing and that kind of stuff.

29:07.000 --> 29:12.000
Also testing changes covers some of the stuff I talk about in testing strategy.

29:12.000 --> 29:15.000
Do I still have time for questions?

29:15.000 --> 29:19.000
Sadly not. However, we've got a great hallway track over there.

29:19.000 --> 29:23.000
We even have a bar right next to our devroom. I just discovered this.

29:23.000 --> 29:26.000
I mean, I'm being locked since 9 a.m. So I just discovered that.

29:26.000 --> 29:31.000
So if you want to go grab a drink and talk about an amazing shell language,

29:31.000 --> 29:33.000
this is the guy.

