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.