WEBVTT captioned by sachac, checked by sachac NOTE Introduction 00:00:02.120 --> 00:00:07.399 Hello and welcome everyone on EmacsConf 2023. 00:00:07.400 --> 00:00:08.719 I'm Andrew Tropin. 00:00:08.720 --> 00:00:11.919 I work on operating systems and programming languages. 00:00:11.920 --> 00:00:16.639 Today, we discuss Lisps, Schemes, REPLs, 00:00:16.640 --> 00:00:18.139 interactive development, 00:00:18.140 --> 00:00:23.279 and how to make your own cozy development environment. NOTE Interactive development 00:00:23.280 --> 00:00:26.319 Let's start from interactive development. 00:00:26.320 --> 00:00:29.519 Lisps are famous for a nice 00:00:29.520 --> 00:00:32.479 Interactive Development Experience. 00:00:32.480 --> 00:00:33.999 They have REPLs. 00:00:34.000 --> 00:00:40.119 Emacs Lisp has its own Lisp machine, 00:00:40.120 --> 00:00:44.719 and a lot of cool IDE with different functionality 00:00:44.720 --> 00:00:47.879 is already here and providing 00:00:47.880 --> 00:00:51.619 a nice and pleasant experience. 00:00:51.620 --> 00:00:56.839 The question is, is it enough? 00:00:56.840 --> 00:00:59.920 In most cases, yes, but for some languages, 00:00:59.921 --> 00:01:04.839 we have some white spaces, some missing pieces. 00:01:04.840 --> 00:01:08.299 And for example, in Scheme world, 00:01:08.300 --> 00:01:10.879 we already have a few tools. 00:01:10.880 --> 00:01:14.599 We have REPL, we have integration for REPL in Emacs, 00:01:14.600 --> 00:01:16.679 but is it enough? 00:01:16.680 --> 00:01:18.179 Let's see. NOTE REPL: Read Eval Print Loop 00:01:18.180 --> 00:01:22.839 We know that Emacs is very good for Lisps and REPL. 00:01:22.840 --> 00:01:26.039 Lisp and Emacs should be a perfect setup. 00:01:26.040 --> 00:01:30.079 But let's see how REPL basically works. 00:01:30.080 --> 00:01:34.799 It's an event loop which does three things. 00:01:34.800 --> 00:01:37.279 It reads an expression, it evaluates the expression, 00:01:37.280 --> 00:01:40.739 and it prints the result. 00:01:40.740 --> 00:01:47.279 We can take a simple expression, input it into REPL, 00:01:47.280 --> 00:01:48.959 and evaluate it and see the result. 00:01:48.960 --> 00:01:50.819 Very nice, very convenient. 00:01:50.820 --> 00:01:55.339 You can experiment and see immediately what is happening. 00:01:55.340 --> 00:01:57.759 You can even run a long-running process 00:01:57.760 --> 00:01:58.919 which does something. 00:01:58.920 --> 00:02:07.199 You can interrupt it and everything will be okay. 00:02:07.200 --> 00:02:08.639 But the problem appears 00:02:08.640 --> 00:02:11.659 when you start to develop a bigger project. 00:02:11.660 --> 00:02:14.039 And in most cases, you don't do 00:02:14.240 --> 00:02:16.399 your whole development in REPL. 00:02:16.400 --> 00:02:18.460 You do only a small part of it. 00:02:18.461 --> 00:02:20.679 In most cases, you just write 00:02:20.680 --> 00:02:22.919 the source code in text files, 00:02:22.920 --> 00:02:26.399 and after that, you run those snippets of code 00:02:26.400 --> 00:02:30.520 from those text files, or run the whole project. 00:02:30.721 --> 00:02:33.719 It's not very convenient to copy and paste 00:02:33.720 --> 00:02:36.039 every time the snippets of code to the REPL, 00:02:36.040 --> 00:02:38.879 see the result, modify the snippet of code, 00:02:38.880 --> 00:02:41.199 copy it again, and so on. 00:02:41.200 --> 00:02:44.039 So people invented some integration 00:02:44.040 --> 00:02:46.079 between REPL and your text editor. 00:02:46.080 --> 00:02:51.599 So you can evaluate expressions inside your text editor 00:02:51.600 --> 00:02:53.719 and see the result here. NOTE Long-lasting loops 00:02:53.720 --> 00:02:56.679 Works good so far, but what happens 00:02:56.680 --> 00:03:02.299 if we run a long-lasting loop, 00:03:02.300 --> 00:03:04.999 which does a lot of operations. 00:03:05.000 --> 00:03:07.839 As you can see here with a simple example, 00:03:07.840 --> 00:03:13.599 the output of the function, 00:03:13.600 --> 00:03:16.759 stdout of the function is presented here, 00:03:16.760 --> 00:03:18.799 and the resulting value is here. 00:03:18.800 --> 00:03:22.359 If you run a long-running process, 00:03:22.360 --> 00:03:24.639 you don't see anything happening. 00:03:24.640 --> 00:03:29.259 And you see there's a watch instead of my cursor. 00:03:29.260 --> 00:03:33.719 Maybe you don't see it, but nothing actually happens, 00:03:33.720 --> 00:03:36.379 at least from the point of view of the user. 00:03:36.380 --> 00:03:38.399 But if we interrupt the evaluation, 00:03:38.400 --> 00:03:41.439 we will see that some process in the background 00:03:41.440 --> 00:03:44.239 was launched, but we didn't see anything. 00:03:44.240 --> 00:03:51.039 Because the REPL is a single-threaded blocking process, 00:03:51.040 --> 00:03:54.319 which reads stdin and prints stdout, 00:03:54.320 --> 00:03:55.679 make the integration 00:03:55.680 --> 00:03:58.540 between the REPL and your text editor 00:03:58.541 --> 00:04:02.919 is not an easy task. 00:04:02.920 --> 00:04:04.320 And even if you do it, 00:04:04.321 --> 00:04:07.599 you have a lot of downsides, usually. NOTE Not interruptible 00:04:07.600 --> 00:04:13.679 First of all, the process is not interruptible. 00:04:13.680 --> 00:04:18.479 If you have a remote process which listens on the socket 00:04:18.480 --> 00:04:21.939 to which you connect from your development environment, 00:04:21.940 --> 00:04:25.479 and you run some infinite loop, for example, 00:04:25.480 --> 00:04:28.299 you can't interrupt it. 00:04:28.300 --> 00:04:31.239 Because interruption is done via signals, 00:04:31.240 --> 00:04:35.039 and signals to remote processes are not usually 00:04:35.040 --> 00:04:38.759 the thing in such integrations. NOTE Output is not interactive 00:04:38.760 --> 00:04:41.159 Output is also not interactive. 00:04:41.160 --> 00:04:45.319 Usually, for example, here you can see 00:04:45.320 --> 00:04:47.799 when I evaluate the expression, 00:04:47.800 --> 00:04:51.119 the output is captured on the evaluation side, 00:04:51.120 --> 00:04:53.719 and after that, after the whole evaluation 00:04:53.720 --> 00:04:56.179 of the whole expression finished, 00:04:56.180 --> 00:05:06.759 I get the result, all the stdout at once. 00:05:06.760 --> 00:05:09.919 And if I run the process which evaluates for 5 seconds, 00:05:09.920 --> 00:05:13.780 I will see the first signs of the life 00:05:13.781 --> 00:05:17.039 only after 5 seconds of evaluation. 00:05:17.040 --> 00:05:23.159 Okay, what else? NOTE No protocol 00:05:23.160 --> 00:05:26.119 When you do such integrations, you have no protocol, 00:05:26.120 --> 00:05:29.759 you have just stdin and stdout. 00:05:29.760 --> 00:05:32.919 You print to stdin from your text editor. 00:05:32.920 --> 00:05:36.679 You read from stdout of the process. 00:05:36.680 --> 00:05:40.339 It's hard to tell if evaluation is finished, 00:05:40.340 --> 00:05:47.319 if it requires stdin, and how to extend the REPL 00:05:47.320 --> 00:05:51.479 to make it more featureful, and so on. NOTE Not scalable 00:05:51.480 --> 00:05:57.359 And also, such integrations are usually not very scalable. 00:05:57.360 --> 00:06:14.699 For example, if you want to have a completion, 00:06:14.700 --> 00:06:17.460 you type something, you have the completion. Cool. 00:06:17.461 --> 00:06:22.039 But if you run the process and at the same time 00:06:22.040 --> 00:06:24.620 try to have a completion, you don't have it, 00:06:24.621 --> 00:06:29.799 because the evaluation is in progress, 00:06:29.800 --> 00:06:33.279 and you can't calculate the completion candidates 00:06:33.280 --> 00:06:35.519 at the same time. To make it more obvious, 00:06:35.520 --> 00:06:41.019 I will start a completion here. 00:06:41.020 --> 00:06:43.279 You see the completion pop-ups. 00:06:43.280 --> 00:06:46.159 I start the evaluation process, 00:06:46.160 --> 00:06:49.859 and when I try to complete something, 00:06:49.860 --> 00:06:53.119 the evaluation freezes and there is no completion. 00:06:53.120 --> 00:06:55.479 Not very convenient. 00:06:55.480 --> 00:06:58.119 Usually, you have some long-running processes 00:06:58.120 --> 00:07:01.399 and you want them to continue while you have 00:07:01.400 --> 00:07:08.579 your go to definition, completion, and other things. 00:07:08.580 --> 00:07:13.659 Overall, those issues make it quite inconvenient 00:07:13.660 --> 00:07:18.419 to integrate REPL in text editors or development environments, 00:07:18.420 --> 00:07:21.379 so you need something else 00:07:21.380 --> 00:07:25.859 to make the work comfortable. NOTE nREPL 00:07:25.860 --> 00:07:28.979 There is already a solution called nREPL. 00:07:28.980 --> 00:07:31.119 It's a synchronous protocol which allows 00:07:31.120 --> 00:07:34.019 to send operations to the server 00:07:34.020 --> 00:07:37.759 and receive responses in a synchronous manner. 00:07:37.760 --> 00:07:42.159 And here is a simple example of a few operations. 00:07:42.160 --> 00:07:45.079 First one is cloning the existing session, 00:07:45.080 --> 00:07:49.240 and as a response you will get a new session. 00:07:49.241 --> 00:07:52.099 Also you send the evaluation request with code 00:07:52.100 --> 00:07:55.639 that you want to evaluate, and you get two responses. 00:07:55.640 --> 00:08:00.600 First one says that output is captured 00:08:00.601 --> 00:08:02.839 and it's equal to "hi\n", 00:08:02.840 --> 00:08:06.560 and after that, you receive an "Evaluation completed", 00:08:06.561 --> 00:08:12.439 the value of this expression. 00:08:12.440 --> 00:08:14.079 This protocol was developed 00:08:14.080 --> 00:08:15.879 for CIDER development environment. 00:08:15.880 --> 00:08:18.759 It's a Clojure development environment for Emacs. 00:08:18.760 --> 00:08:22.859 It's very cool, featureful, reliable, 00:08:22.860 --> 00:08:26.899 and I would say production-ready. 00:08:26.900 --> 00:08:31.499 A lot of professional Clojure developers use it. 00:08:31.500 --> 00:08:33.239 The nREPL protocol is very simple. 00:08:33.240 --> 00:08:38.219 It has a few operations out of the box, 00:08:38.220 --> 00:08:46.479 and you can extend it with any arbitrary operation you want. 00:08:46.480 --> 00:08:53.819 I work a lot on Guix codebase and other Scheme projects, 00:08:53.820 --> 00:08:57.299 so the experience I had previously with nREPL 00:08:57.300 --> 00:08:59.399 was not satisfying. I decided 00:08:59.400 --> 00:09:01.739 to just implement nREPL protocol. NOTE Arei, Ares, and how to try 00:09:01.740 --> 00:09:05.719 First of all, I implemented nREPL server in Guile. 00:09:05.720 --> 00:09:11.339 I called it `guile-ares-rs`, and used it 00:09:11.340 --> 00:09:13.959 with a generic nREPL client for Emacs. 00:09:13.960 --> 00:09:14.719 It worked. 00:09:14.720 --> 00:09:18.639 It had some rough edges, but overall it was okay. 00:09:18.640 --> 00:09:21.639 And after that, to add more features 00:09:21.640 --> 00:09:25.079 to make the implementation more complete, 00:09:25.080 --> 00:09:33.219 I wrote my own nREPL client for Emacs and called it `arei`. 00:09:33.220 --> 00:09:40.179 And I got almost complete Guile IDE in two months. 00:09:40.180 --> 00:09:45.319 So `ares-rs` is nREPL server implementation. 00:09:45.320 --> 00:09:49.679 `arei` is Emacs client, which uses the same nREPL protocol. 00:09:49.680 --> 00:09:54.439 It utilizes `sesman` package for managing sessions, 00:09:54.440 --> 00:10:00.079 the association of buffers with nREPL connection. 00:10:00.080 --> 00:10:04.379 It has some roots. 00:10:04.380 --> 00:10:06.639 The implementation has some roots 00:10:06.640 --> 00:10:09.979 in Geiser, CIDER, Monroe, and Rail. 00:10:09.980 --> 00:10:15.279 I took small snippets for some parts of functionality. 00:10:15.280 --> 00:10:19.479 I used the CAPF and xref infrastructure 00:10:19.480 --> 00:10:23.079 for completion at point and cross-reference capabilities. 00:10:23.080 --> 00:10:27.679 And by the time of conference, I hope 00:10:27.680 --> 00:10:30.199 that README will be complete enough 00:10:30.200 --> 00:10:34.179 so you will be able to try it yourself. NOTE Demo 00:10:34.180 --> 00:10:42.679 Let's see what is possible with it already. 00:10:42.680 --> 00:10:46.719 Let's connect to nREPL server. 00:10:51.900 --> 00:10:56.280 After that, you can evaluate the expression. 00:10:56.281 --> 00:11:02.319 And you see the stdout and the result. 00:11:02.320 --> 00:11:04.719 Very nice, very convenient. 00:11:04.720 --> 00:11:08.659 You have different expression, you evaluate it, 00:11:08.660 --> 00:11:10.359 you get the value of the evaluation. 00:11:10.360 --> 00:11:12.279 You can run an infinite loop 00:11:12.280 --> 00:11:15.639 which prints to stderr and stdout 00:11:15.640 --> 00:11:18.599 and you see all necessary stuff. 00:11:18.600 --> 00:11:19.299 Very cool. 00:11:19.300 --> 00:11:21.959 But also, you can interrupt the evaluation, 00:11:21.960 --> 00:11:25.159 which is very convenient if you accidentally 00:11:25.160 --> 00:11:27.639 run an infinite loop. NOTE Continuations 00:11:27.640 --> 00:11:32.939 Also, do you remember here we have a few more examples 00:11:32.940 --> 00:11:34.079 that we didn't try yet? 00:11:34.080 --> 00:11:39.159 For example, on usual REPL implementation, 00:11:39.160 --> 00:11:47.599 if I evaluate this expression, I get return value. 00:11:47.600 --> 00:11:50.759 I make a continuation and save it to this variable 00:11:50.760 --> 00:11:52.859 and I try to call this evaluation 00:11:52.860 --> 00:11:55.339 and I get an exception, 00:11:55.340 --> 00:11:58.399 because the environment in which this continuation 00:11:58.400 --> 00:12:03.479 was created was different and it has redefined 00:12:03.480 --> 00:12:06.159 stdout and stderr to capture it. 00:12:06.160 --> 00:12:08.979 But when I run it one more time, 00:12:08.980 --> 00:12:12.199 when I resume the continuation, 00:12:12.200 --> 00:12:15.799 the environment changed and it doesn't work. 00:12:15.800 --> 00:12:17.419 What happens in `arei`? 00:12:17.420 --> 00:12:21.759 I define continuation, I save the continuation 00:12:21.760 --> 00:12:23.479 for the simple expression 00:12:23.480 --> 00:12:27.279 and I resume the continuation with a new argument, 00:12:27.280 --> 00:12:30.139 and you can see at the top of the screen 00:12:30.140 --> 00:12:32.459 that it works perfectly fine. NOTE Reading from stdin 00:12:32.460 --> 00:12:35.559 Also, with a usual REPL implementation, 00:12:35.560 --> 00:12:40.319 let's see what happens when we have a process 00:12:40.320 --> 00:12:41.919 which reads from stdin. 00:12:41.920 --> 00:12:48.099 I evaluate the expression and nothing visible happens. 00:12:48.100 --> 00:12:52.999 I can try to type `C-g`, `C-c`, 00:12:53.000 --> 00:12:56.559 and after some time it will say user interrupt. 00:12:56.560 --> 00:13:00.439 What actually I expect in such a case 00:13:00.440 --> 00:13:04.679 to have a minibuffer which prompts me for the input. 00:13:04.680 --> 00:13:10.019 When I evaluate the same expression in the `arei`, 00:13:10.020 --> 00:13:12.199 you see the prompt at the minibuffer 00:13:12.200 --> 00:13:21.899 and here I can tell, "Hello I'm a message from minibuffer". 00:13:21.900 --> 00:13:26.099 Cool. You will see that this message is printed to stdout, 00:13:26.100 --> 00:13:28.679 and unspecified was returned 00:13:28.680 --> 00:13:33.419 as a result of this expression. NOTE Fancy example with continuations 00:13:33.420 --> 00:13:37.319 Let's make some fancy example with continuations. 00:13:37.320 --> 00:13:45.079 Continuations is a very cool mechanism 00:13:45.080 --> 00:13:47.999 which is not the topic of today's talk, 00:13:48.000 --> 00:13:50.999 but you can find a lot of interesting information 00:13:51.000 --> 00:13:54.439 in Scheme documentation or in related books, 00:13:54.440 --> 00:13:58.339 and I advise you to do it because it's really nice thing 00:13:58.340 --> 00:14:00.119 that is actually applicable 00:14:00.120 --> 00:14:03.519 in many different programming languages. 00:14:03.520 --> 00:14:05.199 Here you can see the infinite loop 00:14:05.200 --> 00:14:09.159 which just prints values increasing one by one. 00:14:09.160 --> 00:14:13.299 And here we save a continuation on each iteration. 00:14:13.300 --> 00:14:18.059 I can call the continuation 00:14:18.060 --> 00:14:21.939 and it will resume from the previous saved step. 00:14:21.940 --> 00:14:27.679 And you can see, it resumed from the same step 00:14:27.680 --> 00:14:31.640 we interrupted earlier, but we provided a new value for it. another value for it. 00:14:31.641 --> 00:14:33.920 We can provide another value 00:14:33.921 --> 00:14:39.199 and it resumed from the same spot it was saved earlier. 00:14:39.200 --> 00:14:42.579 But I also can provide a `read-i` value 00:14:42.580 --> 00:14:45.199 and if I provide `read-i` value, 00:14:45.200 --> 00:14:50.779 the infinite loop will read the input from stdin 00:14:50.780 --> 00:14:53.319 and will continue the evaluation 00:14:53.320 --> 00:14:56.679 with a different `i` provided in this input. 00:14:56.680 --> 00:15:03.039 So let's try to type some arbitrary value 00:15:03.040 --> 00:15:07.519 and you see that the loop continued with this value. 00:15:07.520 --> 00:15:08.039 Very nice. 00:15:08.040 --> 00:15:13.159 And every time we could easily interrupt it. NOTE Guix API 00:15:13.160 --> 00:15:17.319 Okay, what most annoying thing that I had previously 00:15:17.320 --> 00:15:19.339 with the usual REPL implementation 00:15:19.340 --> 00:15:22.759 that I have a quite nice Guix API 00:15:22.760 --> 00:15:27.579 where I can build packages, systems and other stuff. 00:15:27.580 --> 00:15:35.359 But if I evaluate this expression, I will get an error. 00:15:35.360 --> 00:15:38.039 Okay. I will get an error 00:15:38.040 --> 00:15:44.479 because I don't have an appropriate environment. 00:15:44.480 --> 00:15:51.579 But what I can do, I can connect to the remote REPL 00:15:51.580 --> 00:15:55.059 by creating a server with `guix repl --listen` command 00:15:55.060 --> 00:15:58.619 and connecting to it with `geiser-connect` command. 00:15:58.620 --> 00:16:01.819 And now I can evaluate this expression. 00:16:01.820 --> 00:16:03.359 Right? 00:16:03.360 --> 00:16:10.479 Wow. 00:16:10.480 --> 00:16:14.339 Okay. 00:16:14.340 --> 00:16:19.039 It actually doesn't matter for my example. 00:16:19.040 --> 00:16:22.879 I will explain how it doesn't work easily. 00:16:22.880 --> 00:16:26.519 This is a long-running process which prints something 00:16:26.520 --> 00:16:29.579 and it can take up to a few minutes. 00:16:29.580 --> 00:16:33.359 And for the whole few minutes I don't see any results, 00:16:33.360 --> 00:16:38.719 the same as with this infinite loop which prints to stdout 00:16:38.720 --> 00:16:42.199 but I don't see anything interactively. 00:16:42.200 --> 00:16:45.619 With `arei`, I can run 00:16:45.620 --> 00:16:47.920 the evaluation of the same expression, 00:16:51.440 --> 00:16:54.119 and you will see instantly 00:16:54.120 --> 00:17:00.200 that stdout is presented here in slightly yellowish color. 00:17:00.201 --> 00:17:02.920 I can interrupt the evaluation 00:17:02.921 --> 00:17:06.039 if I don't want to wait until it's finished, 00:17:06.040 --> 00:17:15.779 and just after that, I can evaluate another value. 00:17:15.780 --> 00:17:23.359 So that's cool. 00:17:23.360 --> 00:17:25.959 And let's see one more thing. 00:17:25.960 --> 00:17:30.339 We have an infinite loop and we have some completion here. 00:17:30.340 --> 00:17:32.579 And completion still works, 00:17:32.580 --> 00:17:33.659 very nice, 00:17:33.660 --> 00:17:40.259 while the infinite loop is running. 00:17:40.260 --> 00:17:42.059 Okay. NOTE Support 00:17:42.060 --> 00:17:44.919 Actually it took me around two months 00:17:44.920 --> 00:17:48.039 of full-time work funded by my own savings, 00:17:48.040 --> 00:17:51.599 and you can support and help to the project 00:17:51.600 --> 00:17:57.019 using OpenCollective or by contributing on SourceHut. NOTE Future steps - Multiple simultaneous evaluations in different contexts 00:17:57.020 --> 00:17:58.699 The future steps for the project 00:17:58.700 --> 00:18:03.674 include an experimental workflow where you have 00:18:03.675 --> 00:18:07.539 multiple simultaneous evaluation in different contexts. 00:18:07.540 --> 00:18:11.959 For example, you have Fibers, you have Goblins, 00:18:11.960 --> 00:18:16.919 you have some HTTP server or some other thing, 00:18:16.920 --> 00:18:22.119 and you want to run all of them independently 00:18:22.120 --> 00:18:25.319 in slightly isolated sessions, 00:18:25.320 --> 00:18:29.799 and you want to have the ability 00:18:29.800 --> 00:18:30.959 to still interact with them. 00:18:30.960 --> 00:18:33.979 For example, if they require standard input 00:18:33.980 --> 00:18:39.239 or something else, you want to be able to provide it. 00:18:39.240 --> 00:18:42.519 You want to see the stderr and stdout 00:18:42.520 --> 00:18:46.219 of those long-running processes and so on. NOTE Tree-sitter integration 00:18:46.220 --> 00:18:50.239 The second thing is tree-sitter integration 00:18:50.240 --> 00:18:53.399 for better syntax highlighting, code navigation, 00:18:53.400 --> 00:18:56.879 and other features. NOTE Full-fledged debugger 00:18:56.880 --> 00:19:01.399 And after that, probably we will do a full-fledged debugger 00:19:01.400 --> 00:19:06.239 so you can jump expressions one by one 00:19:06.240 --> 00:19:10.779 and see the results and see some intermediate values 00:19:10.780 --> 00:19:13.079 during the evaluation. 00:19:13.080 --> 00:19:14.479 And it's very possible 00:19:14.480 --> 00:19:17.079 because nREPL is a very extensible protocol 00:19:17.080 --> 00:19:18.199 and you can implement 00:19:18.200 --> 00:19:22.759 whatever you want on top of it. NOTE FAQ - Does it support other Scheme implementations? 00:19:22.760 --> 00:19:27.079 I will answer two probably very frequent questions. 00:19:27.080 --> 00:19:30.499 Does it support other Scheme implementations? 00:19:30.500 --> 00:19:32.279 At the moment, it doesn't, 00:19:32.280 --> 00:19:36.519 but the Scheme implementation is not restricted. 00:19:36.520 --> 00:19:40.639 You have a server which is implemented in your language 00:19:40.640 --> 00:19:43.974 and you have a client--in our case, `arei`-- 00:19:43.975 --> 00:19:48.319 which communicates with this protocol. 00:19:48.320 --> 00:19:52.359 So if you implement nREPL server in a different language, 00:19:52.360 --> 00:19:58.379 it should work with already implemented `arei` client. NOTE Is it possible to use it with other text editors? 00:19:58.380 --> 00:20:04.079 And is it possible to use the same functionality 00:20:04.080 --> 00:20:06.999 in other text editors, for example in VS Code, 00:20:07.000 --> 00:20:08.679 Vim, whatever? 00:20:08.680 --> 00:20:13.799 Yes, it's possible and the case is similar here. 00:20:13.800 --> 00:20:16.599 You have already implemented nREPL server 00:20:16.600 --> 00:20:19.359 and you can write your own nREPL client 00:20:19.360 --> 00:20:22.120 in a different text editor and it will work. NOTE Conclusion 00:20:22.121 --> 00:20:26.759 I would like to thank the authors and maintainers 00:20:26.760 --> 00:20:30.439 and contributors of Guile, Geiser, CIDER, Clojure, 00:20:30.440 --> 00:20:33.359 and Emacs, and all other people 00:20:33.360 --> 00:20:38.779 who are somehow related to the work on those projects 00:20:38.780 --> 00:20:42.079 involved in this talk. 00:20:42.080 --> 00:20:45.879 And I hope the Scheme programming will be enjoyable. NOTE Contacts 00:20:45.880 --> 00:20:47.239 If you want to contact me, 00:20:47.240 --> 00:20:49.799 join #tropin IRC channel at libera.chat, 00:20:49.800 --> 00:20:53.039 or drop me a message via email or feediverse 00:20:53.040 --> 00:20:55.879 using `andrew@trop.in` handle. 00:20:55.880 --> 00:21:00.680 I will see you in a bit in Q&A session.