 everybody and welcome to this week's episode action packed episode, I'd say, of writing Visual Studio Extensions with Matt. That's me. And there's something. What is that sound? I can hear myself. Okay. Something is odd. Anyway, let's move on. Today is the second time in a row that we are so lucky to have with us. The excellent producer, Mr. John Gallo. Hello, John. Hello. Let me see. I need to add myself. There I am. Hey, happy Friday. Happy Friday to you too, sir. And happy Friday to everyone out there watching. I think I should start clearing something up because, you know, I was on the Twitter is just a few minutes ago. And, you know, I was tweeting out that we were doing this episode today and inviting people to join. And then the Visual Studio account also tweeted about this episode, but they they tweeted about the wrong episode. They tweeted about an episode that we're not we're not going to do until February 26, which is about writing your very first extension is sort of an introduction to extension writing getting started. And today that's not it. So I don't know what something went went wrong there with with the scheduling for the tweets and all that stuff. So I apologize. So what are we doing this week? Well, today, we are augmenting an existing language. John, you probably you probably had this idea before where you're like, you're seeing something in C sharp or HTML or whatever language you might be in and thought, hey, what if we could add something to it? What if we could enhance it somehow? So not it's not like writing your own language service. Yeah, brand new language that Visual Studio don't understand. But how do we attach to an existing language right and do something there? And this isn't extending the language itself. It's extending the language service, right? That is correct. That's okay. That's a good distinction. Yeah. Which is interesting because I've been keeping an eye on source generators, which is interest is a way of kind of adding on to the language sort of I mean, like you can write in, you can write an attribute that generates some code or stuff like that. But yeah, neat. All right. So this is about so language service that means it's not the language, it's not the compilers. It's none of that stuff. It is how the language visually behaves, let's say in Visual Studio. Okay. All right. So you could imagine you could add, you know, new items in the intelligence list or, you know, such things like that, you know, you can hover over things and you can create like watermarks or a bunch of things. And today we're going to look at one very specific thing. And let me tell you how this came about. It was because we actually had another thing scheduled for today. And a couple of weeks ago, I changed it because someone was saying that they had a problem in Visual Studio. And the problem was when they worked with the JavaScript and they had strings containing HTML that that was not colorized. That was a big problem to them. And also that this was something that there already was an extension for for earlier versions of Visual Studio. So let's take a look at my screen here real quick. There's an extension out there called HTML syntax highlighter for JavaScript strings. And if we kind of look at what it does, I want to zoom in. You can see here, this is JavaScript. What it does is that if you have a string in JavaScript and it's formatted as HTML, it colorizes it as HTML. See that? Yeah. Yeah, you know, this is interesting too. I was playing with this earlier this week, especially now with JavaScript that you can do template literals. Yep. It makes it nicer for adding like this is a little bit ugly for doing, you know, concatenating a bunch of strings. But now like I was just doing this. Actually, that's why that's why I was almost late to the call. I built a SVG image generator thing that we use for these shows that we use for the YouTube. And you know, like the thumbnails to advertise the shows and and so using that I played with a bunch of different things, but I'm doing them using glitch and I ended up just having the SVG in a template literal to avoid cores. So it's actually a bunch of JavaScript files and they're just template literals and it reads in the SVG and does some token replacement. So yeah, show me that one day. That sounds super interesting. Yeah, yeah, it's funny. It's like it's a total hack, but it totally works. So yeah. All right. So so check out this this extension though. There's a problem 2013 that all man, it has not been updated in what seven, eight years, right? And so let's do that. Let's take this extension and just port it to Visual Studio 2019 and there so so and I thought this could be an interesting exercise because you know, there are some extensions out there that are popular where the author has moved on not using Visual Studio anymore, but left it open source and if they're licensed in a good way, then why not fork it and and update some of these extensions to support the latest version of Visual Studio that could be fun and an easy and a kind of interesting way to getting started with writing extensions is to I think that's just kind of a nice kind of slow introduction, right? You think what's the best way to fork works? Like, is there any sort of supported way in the marketplace for doing that? Or do you just kind of because I've seen some people do just like, you know, like the name of the thing and then like 2019 or like new or, you know what I mean? Is there a better way to do that? Well, so there is nothing on the marketplace that helps us do it. Usually the extensions are licensed in a way that you probably have to attribute it. So link back to the original source. Yeah. So we're going to have to remember to do that and you know, even if the license said that we could do whatever, I think it would still be the nice thing to do anyway. Sure. Yeah. So, you know, usually most licenses they state that you can't like, if you ship it, you have to come up with a different name. You can't like just because names are like trademarkable right and copyright and all that sort of stuff. So and I think that's fair. So I think what we're going to do here is that we're going to create a brand new extension, give it a different name and then copy the code files over and massage that into the new world and and then credit the original author basically. Yeah. That's how I would do it. I don't I don't think there's any other smooth way. So another. Okay. So here is there is one other way of doing it. I could just clone down the project from their GitHub page and take that because it was a 2013 project and slowly updated to the latest new good packages and all that sort of stuff. But I feel like that's going to be more work. Yeah. Okay. And and if you look at let's just look at their like if you look at how they structure their repo like this, like they don't have a source folder where the that contains the project and the solution folder is separate and so on. Right. So so that's not how I want the layout of my extension to be anyway. It's a trade off sometimes if there's a lot of code then you'd want to fork and update and that kind of stuff versus in this case, you're like, I want to take the general idea, but you're not going to gain a lot from taking six year old code. Exactly. So, okay, cool. And so I already cloned this project and it's right here. So you can see there. So there's a one to one mapping between what you see in the browser here and what you see in the Explorer. Right. So so that's it. That's wonderful. And you see this MIT license so I can I never understand if it's copy left or whatever it meaning I can kind of do what I'm going to do, but I think MIT is what's called copy left license, which means you can kind of do with it whatever you want as long as you keep a few simple things in mind. Yeah. Okay, so I've cheated and I've actually started my project already because instead of us having to do this every single time where I go into Visual Studio is a file new project and select the Visual Studio extensibility project template and you know, I find an icon to it at my license so on and so forth. I thought I'd just go ahead and do that from the beginning. And so that's right here and the name of the extension is HTML for JavaScript. I don't know what to tell you. I'm not very creative extension names. It's one of my if you look at all my like extensions, you'll notice that they their title of them are always like what they do. Yeah. You know, I think that's a good thing because then people have like a clear expectation SEO friendly. I didn't even think of that. But yeah, of course they're right. So and we don't really have anything here. So we need to attribute the original author and so on and so forth. Okay. Let's head into Visual Studio. Here's what it looks like. My project is over here and let's just look at the problem that the extension is set to solve. Here I have a JavaScript file. You can see here I have a HTML tag inside just a string and it's not colorized as HTML. That would look like this, right? So that's what we're trying to do trying to make this colorized like regular HTML. And you know, if we look at the code that we got from the original author here, we can see there's actually only two C sharp files here that we care about. So let's just grab those and you know, I'm just going to copy them. I like to create folders for things. So I'm going to create a folder and I'm going to call this classify classification classification. I'm going to paste those two files in there. I'll explain the word in a second here what the whole classification means. So but these are the two files. Okay. So classification. Let's take a look at this HTML file right here. You can clearly see that there are differences in color between the different things like HTML element name here and then attribute name and attribute value. And if I had like a string in here, for instance, again, that's colored different from that. So I have an extension installed called extensibility essentials, which you should also install anyone that wants to play around with extensibility. It brings a bunch of functionality. One of them is on the standard toolbar. This button here that's called toggle extensibility margin. I'm going to click it and check out the bottom here. It gives me some information. I'm going to zoom in. We actually wrote this extension in one of the first episodes of this of this show. So go back in time and check that out. But here we have a few interesting things. It shows classification none. Okay. So I'm going to put my cursor on the HTML element name. And so now the classification was actually HTML element name. That is cool. HTML attribute name, HTML attribute value. Okay. And then none. If it's just plain text, there's no reason to classify it. Like the default is just plain text. So now we can see the names of these classifications. Okay. So there's a language service somewhere that figured out that, you know, these four character is an HTML element name and then there's white space in between. Like there's nothing in between no classifications and then an HTML attribute comes up. We have an HTML operator. That's the equal sign. What else do we have? We have HTML tack delimiter. Those are the greater than less than here. Okay. So, so that's how classifications work in Visual Studio. That's how colorization works. Classification is a different way of, well, I guess it's more than just saying colorization. It's kind of what's below. It's an abstraction level lower than color. But you, but you can think of it as the same thing. Like how do you want to colorize your file? Right. So for each classification name, you attach a set of styles, which essentially is just color, but you could actually make things bold and italic and stuff like that too. And so for this, you're not actually setting a color. You're setting a style and that's important because people have different color themes, right? They may have a dark mode or whatever. And they, and so they set, they say this is, if something is an HTML attribute, this is the color. And then it's defined in fonts and colors, right? So you can have your own color theme and all that sort of stuff. But if we go down and we just going to hit H. If we look at HTML, you can see here are the exact same names, right? And you can see how they are colorized and you can change them here. So that's kind of cool. All right. So let's take a look at what we're dealing with. So we need to update some namespaces and stuff. So let's go ahead and just do, well, let's just leave that first. Okay. So this one needs a few things. It needs a component model composition. So let's grab that and system Windows media. Uh, component model and position and Windows media. Oh, because it's that presentation core is I always get these wrong. Let's just try it. Okay. So now we should get composition. Yeah. And media. All right. So far so good. So let's take a look at the provider definition right here. So right off the bat, we notice something and that is that we have an export attribute and when we have an export attribute, we're dealing with meth, the managed extensibility framework. And if we want to do that from our extension, we have to mark our extension as a meth component. So I'm going to go up to the V6 manifest under assets and I'm going to say new going to add a new one and I'm going to add meth component. I'm going to say this is a project in the solution and it's the one project that we've got. So this basically writes if I hit a seven here to go to the code, this basically adds this line that basically tells Visual Studio when we install the extension that hey, this is there's a meth component here too. Okay. So register that otherwise this would do absolutely nothing. Okay. All right. So far so good. So what are we doing here? What the way that meth works in Visual Studio is that you always have this kind of or almost always have this idea of a provider model. So it's a provider that basically just returns an instance of the actual interface implementation that you need. And so what I always do is that I see because there's only one method says get classifier. So the classifier is the one that's important here. So I'm just going to take this because I don't like to have two classes in one phone. So I'm going to move this out. Move this to HTML classifier provider because that's the name of this of that. So now that moved out. Okay, so let's let's just change the namespace now that we're no, let's not do that yet. So that leaves us with just the classifier. So here's the classifier. This is actually quite a long file. It's simple enough, but there's a lot of stuff going on. As you can tell here. So let's just take it nice and easy. So first of all, let's call this something else and let's get rid of the region. Let me try that. I haven't tried this in a long time. Edit comments. Remove. Regents. Boom. It removed the regions. That's another extension. By the way, that's not built into Visual Studio. It's called comment remover. If you're dealing with extensions, you probably need that extension. If you're an extension author, because all this stuff always adds a lot of comments, all the templates for extensions. Okay, but we're going to start here. We're going to start with our provider because that's the very first thing that's going to happen that we're going to need. And you can see here it hooks into two content types. So this is how we make sure that we hook into an existing language that's based on content types. So let's figure out what JavaScript content type is in Visual Studio 2019. And we so we open the JavaScript file and we go down to the bottom. And it's called TypeScript. Okay. TypeScript. Okay. TypeScript. So we don't we can get rid of that. Just do TypeScript. So the reason it's called TypeScript is that because in Visual Studio 2019, maybe even in 2017, but for sure in 2019, it's the same language service that handles both TypeScript and JavaScript. And because all JavaScript is technically also TypeScript. Right. So that makes I guess that makes sense. So the there's it's not like a parent child relationship that, you know, the TypeScript is the parent content type inheriting from JavaScript or anything like that, which is supported by the way by Visual Studio. You can layer content types on each other. What's an example I'm trying to think of a content type that does that layering? Well, I guess they all do. So they all inherit from a code, the content type called code, which inherits from the content type text. Okay. And but it's so it's a way that you can in there might be, I think race or use to do the same thing where it would rely on HTML or something like that. So it's a way of, so if you have anything, any MF export that that lights up on a certain content type and you and in your language, if you inherit from that content type, you get the benefit of that original tooling that came along with it. Right. So it's kind of neat. But I think like nowadays, most of the building stuff probably doesn't maybe some of the C++ actually, you know, I don't know. So also this is pretty verbose. We can we can greatly optimize this. So he basically here he creates, it used to be something that confused me as well, but we don't have to keep a static version of this. We just need to create a new one. But let's just leave this as is because right now our goal is to basically just make this work. So we had a question in the chat, which is how would you specify an inherited content type? Is that I can heriting? Is that class inheritance or is that actually right like right here? So I'm going to show you. So we can we can do that now. So let's just look at the first thing that happened inside our classifier is that so in our provider here, we get like a couple of things. We get a classifier registry and a classifier aggregator. And in that registry right here, we can ask for classification names. Okay. And these are just strings. It's whatever is registered with Visual Studio already. But these ones are actually some that we provide ourselves as MephExports. And they're listed right here. So check this out. Here we can go in and say. Oh, sorry. This is content type. So I wasn't actually going to show you the inheritance. You can only do the inheritance when you do a language service. So we're not doing a language service. We're augmenting an existing language service. But we can do the same for format providers here. So we can say. Based on base definition. And then we can say something else like a CSS string. I don't know if that's a like this, right? So now it inherits all everything from from the base definition plus whatever we define ourselves. And that is defined in so MephExports down here. And see, they're all defined in foreground color blue. You know, they have all these properties. So let's see how can we actually format text? You can see we can do a bunch of things. We can set opacity. We can set background color. And font size. What font size? Yes, you can do font size. You can do bold. You can do italic text decorations such as underlines and overlines and stuff like that. So you can actually do a bunch of stuff that you can't do from the tools options like you don't have. See, this doesn't actually give you all that granular detail that you can do if you do it from an extension. So that's kind of cool. Okay. So here we are. This is all good. Let's see if we can build it. Will it work? Will it work? Okay, it's building. So let's just run it. And I'm going to just copy this into a JavaScript file once. Experimental infant is showing up. There's a question here about regions from fuels. Maybe is there an ad regions as well? No, but that's an idea for an extension. Like you can like maybe you can surround with region. No, there is actually there is right. If I go in here. There's a refactoring. Yeah. It's around with region. Okay. So not in, not in JavaScript. They don't have. Oh yeah. It's just in. Yeah, there it's. Okay. Yes. Here in region. Yeah. Nice. Boom. That's beautiful. All right. So that's open a JavaScript file. So now if it works now we're done. Right. Kind of maybe. Kind of paste it in. Boom. You think that John? Yes. That's amazing. Isn't it? That was quick. That's that's what they call a copy paste magic. Isn't it? Wow. Uh huh. All right. Well, great show this week. All right. See you everybody. Well, okay. I am curious. Like could you let's say you did want to underline or something like that or do some special decorator? Would it be? Is it as simple as just like having some logic to do that? Like when you're pressing it? Wow. Okay. It literally is. It literally is what I just showed before. Here you go in where we define all those classification formats. Somewhere down here. And you see this one. Oh. Classification time attribute name. So if it's an attribute name. Then we just go in and say. You know. Text decorations equals. But new text decorations. Text decoration collection. Oh. And then say add. Okay. So we have to like create that in basically, but. Okay. Wow. Oh. Oh, sweet. So maybe we say text decoration dot add. And there we go. New. Text decoration. I don't think. Okay. Oh my God. What is this even. This complain about. Could you do. Oh, I need to do windows base. Oh. But I made things complicated. I don't want to do that. What I want to do is I want to get rid of all these. I want to, I want to get rid of the entire file here for formats. And John, do you have an idea why I want to get rid of this? Because you're not using them. And it's, I mean, they're already defined in the base, right? Well, yeah. So if we looked at our HTML file, we saw that we have all these. They're already there. So instead of defining my own ones that's going to show up. So now I have two sets of HTML for matters, right? I have the ones that ship in the box. And then I have these new ones that only apply when you're in JavaScript. So that's kind of weird. So what I want to do is I'm just going to open a project that I played around with some of this stuff. So I want to replace these with whatever is built into Visual Studio so that if you change the font colors, let's say, or your theme for regular HTML, well, that should be the same color that we use in our extension here, shouldn't it? And so I cheated and prepared a little something. So what I did was I took the HTML assembly that ships with the Visual Studio that handles the language. And I kind of did an is spy on it. And I figured out to get the list of names. So I'm going to do an old F 12. That's the peak definition. And that shows me these are internals, the internal static. So I can't actually access this. But Visual Studio is kind enough to, like, just do the decomposition and show it to me. So that's very handy. Thank you, Visual Studio. So here they are. That's the list of names. I'm just going to move that over there while I type in. So we can basically just type it in. So what is this one? The limiter. What the hell is the limiter? That must be like operator. Oh, no, it's called tag delimiter. Now I see it. So I can go in here and say HTML tag delimiter. OK. And this one was what HTML element type element type. That must be element name, right? Guessing. Then we have attribute name. That must be like fantastic. Just watching me like kind of type over and over again. Now I miss that. Is there a reason why you can't just add a reference so that you can pull in format names? I totally could, but I don't want to because that assembly, because it's not part of the SDK. It's not part of the Visual Studio officially supported and documented APIs. That means that it is subject to change at any given point in time. It could change between now where we're, you know, Visual Studio 2019 version 16.8 and like 16.9 is coming out soon, right? It could change between those two. And then it's just be broken. Like you will maybe you won't crash Visual Studio, but now you have a reference that's wrong at runtime. And so that's just really bad. OK. Oh, hang on. What is that quote type? I did something wrong. That goes down here. Quote type. What is quote type? I don't have a quote type. I have an operator, HTML operator. Let's use that. That's like an equals. So let's just do that. And then text type. We just had none. I don't know about none. So let's just call it something else string. I don't know if string exists. But now we should be good to go. I don't know if that's true. I don't even know if this compiles. If there's other references. There wasn't. OK, good. Katya is asking if we are from Microsoft. Yes, this is the official Microsoft Visual Studio, YouTube or Twitch channel. So you are watching two guys from the Visual Studio and .NET team. Yep. Yep. And what's cool too Katya is from Portugal. So hello Portugal. Yep. And you know, I've never been I've traveled all over Europe and Portugal is like super high on my list. I just haven't been there yet. I have been to Lisbon and it's awesome or Lisboa and it's it's really cool. I love it. Nice. I recommend it. Yep. OK, so that didn't work at all. So for some reason I couldn't just grab those names. Now what's up with that? That makes me feel sad. I was sure that I could. Why couldn't I do that? Why doesn't your classifier show it should show if it's a classification issue, right? No, it's not. It's a name thing. It classifies them correctly and it gives them this name. But that note. Oh, I wonder if it's because that's a display name and not the hmm, you know, I did something that may help out. I don't know. Classifications types. Let's just try something instead of element name. We have because originally I actually couldn't find this. Let's just try this element name. Originally I couldn't figure out how to I L spy my way in and find those names. So I went in and I looked at the source code in our local Azure DevOps instance, right? Where we keep the Visual Studio source code. But I felt like that was cheating because the viewers out there, they can't do that. I might just have looked in the wrong location in that file. Which you should be able to do. But let's let's try now. Oh, still no go. Well, okay, then we like that. And let's do something crazy. No, that's not too crazy. Okay, let's ever move the region again. Boom. That's nice. Okay, so we were going to do the. The namespace here. So John, do you think I can just rename this and then do the refactoring to apply that to the other files? Oh, no, I can't change namespace. No, I'm weird. It's because there was a dot in it, I believe. There's that dot so I can't use the. Ah, that's interesting. Here we go. What's all this? These are never used to fix violation. Oh, yeah. Let's figure this. This should all be good to go. So let's click that. They don't do it. Fix violation name. We've had this discussion before. John with when James was here. And my take is that I always use. I always use underscores. Yeah. So is that in your editor config then? No, I don't have an editor config for that. Maybe that's why it didn't come up and give me those. Oh, yeah. Yeah. I thought I had an editor config. I do have an editor config. You're right here. So it's got to be in there somewhere. Somewhere. Yeah. Okay. Old school someone says Alex listen up. There's nothing old school. You know what it would be like? It would be like this M underscore. Yeah. Yeah. And maybe all caps just, just because. Yeah. But now I need to go back here and do all these. All this typing I did for no good reason. Makes me feel sad format name. I kind of find that because. Okay. You. Those are the only two I was going to say you should find replace, but those are the only files. So that should be it now. But now something's going on here. Yeah. HTML element type. Oh, no. Oh, sometimes hold down all and then move the mouse. We do that like that. Yeah. There used to be a way I could do this and then say, apply to the whole project. Why, why can't I do that? Where is the whole project? That's total totally uncool. Feel like maybe it's because I don't have that set up right in my what they call editor config. What are we going to do? Should we do something fun with the. The names here. What do you mean by fun? Well, I'm thinking we do something that that looks weird. So we have a code. Can you use Unicode? No, I was thinking more like we make we make it look. So here's like a special. Oh, right, right. Interesting shading or something like that. Yeah. This is an element. HTML element. So what can we do here? We can do the base dot is bold. I mean, that's not something you can do. Right. You can do that from the. We do background color background brush. Now what's the difference between brushing color? Background customizable. Oh, true false. That's sort of background color. Can you do gradients? Wow. Opacity. You've got all kinds of stuff there. Oh, yeah. What kind of let's do. Dodger blue. Is that a thing? Yes. Yeah. That was always my thing when I did CSS, but I always use Dodger blue as my example. Or no, I use corn silk blue. Yes. Corn flower. Corn flower blue. Okay. Let's do that. It really annoys me that I can't reuse HTML that is existing format definition. Can are you able to query? I don't even know if that would have been a thing. Can you query if it's in light mode or dark mode? Yes. Okay. I can. That was that's part of why I don't want to invent my own. So you never want to invent your own. Classifications if you don't have to because then you get the theming for free. Right. So. And there are some like default things. Let's see here. Like comment string. Those are those are default. Those are always in visual studio. Wow. That's that is beautiful. That is definitely going to help me write some good code. Like that. Yes. Let's see. Let's see if this supports something else here. Oh, it doesn't. Because that string. Is that a backflash? No. For multi-line. Do you need a. Yeah. Oh, maybe I can do this. Isn't that multi-line? No. It's multi-line. You do attack. So it's a it's like an apostrophe. Oh, that's for template string. Yeah. Yeah. Oh, you're right though. Okay. So this maybe doesn't work in temperature and temperature. And I can do something like this. All right, but that works. Yeah. But what I can't do new line. Why is that just because this is not. What is this? What is this anyway? Is this a classifier? No. How to. Is this classified as a. As a string, but that was all I needed. It has to do with it only looks at one line at a time and it didn't start tick here. You know, now there's the same thing there. Okay. So now it's. Yeah. So there's something in the syntax of JavaScript here that maybe this needs to be updated to support that latest stuff. You know. Let's see if we can do that. At least templates, but it does a template string though. Right. So it does. So that's accurate. I'm actually surprised at handles. Well, okay. So it's that's just the job. Is that using the JavaScript code? Or is that you? Is that relying on the custom code that you brought in the classifier code? Or is that just the. Okay. That's a great question. Let's take a look. Let's take a look at how this actually works. Just for the sake of remembering to make it look prettier. I'm just going to undo these things that we just did. So the way it works. And I think it's kind of clever the way you did it. Is that check this out. He checks whether or not the classification is of string. So before. So this is called get classification spans. This is basically saying, okay, this returns a collection of. You know, the, the text buffer ranges with what classification name format name they have so they can be colorized. And he checks whether or not are we in something called a string or a script string. Okay. And he doesn't even look at what are you inside like tick marks or single quotes or double quotes. It doesn't matter because the underlying language service classifies all of those things as string. Okay. So we can actually clean up here because he says only 2010 use a string. So we can just do that. We believe we believe he tells the truth. So I don't, I don't actually know. And he excludes the quote. So he just takes whatever the span is and he just minus one and plus one, you know, to get the inner text. That's it. I feel like this is like, look at this is all the same. Yeah. This is a, this could use some, some cleanup, right? And then also some private stuff. I would move this out into zone. Probably. And, but here we go. So this is, this is a very long method scan literal. So he scans through it and he basically does, he figures out what they are. Okay. So he moved, he just moves through and he has new classification spans when he finds something. Here's a closing tag element name or whatever you can see. So it's, it's kind of simple enough. It's, it's all very repeated. And so there's not that many concepts. There's just a lot of it. And so there's a lot of keeping, keeping in mind here. It's interesting. Well, so two thoughts. One is I would want to like do the refactoring with like C sharp eight and nine, do switch statements and all that kind of stuff. The other thing I'm wondering is, can you rely on like there's already some text classifier stuff that's built into like how visual studios already classifying JavaScript and HTML. Is there a way to lean on that as opposed to having to write your own string parsing stuff? Well, yeah, but that's what we're doing here. So we're not writing our own. So because he goes in here, he says, what is the current classification? Oh, it's a string. That's what the underlying JavaScript or TypeScript language service says that this is. So if there's a string, then he, his logic kicks in. Okay. I was just wondering if his custom logic, if there's a way to just tell it like, I guess, I guess not. I was going to say, like, can you use the built in because there's already classifiers for HTML. Right. That's that are being used, but I guess there's not like a way to say like, hey, go run the HTML classifier on this for me. Yeah. There's probably not. There might be some ways you can go about it, but you probably need to do some reflection or something. It's also important to stress the difference here between a classifier and a parse tree, right? Because in order for the HTML that is for instance, I know that pretty intimately because I was the PM at the time when we wrote the new HTML editor. The parse tree, like, looks at the entire text of the document, all the HTML. And it creates a tree just like any other, like, you know, like an AST, right? And then the classifier then uses that tree to figure out, okay, between this position and this position in the text buffer, that's an element name. And between here and here, there's an attribute value, let's say, right? And so if we can get the whole to the tree, then that's the most powerful thing we can do because that means that we know that, hey, this element is actually a child of this other element name and so on. And so we get that full fidelity information. But most of the time, we just have the classifier and then we need to query the classifier like we do here and say, okay, in this span, and a span is usually always a single line. So in this line, get the classification spans. Okay. That's in this line. And this should, of course, be true in lower invariant these days that might not have existed at the time that he wrote originally. So now we get all the whatever classifications that are on that line. And then he just says for each of them, if any of them is a string, then I'm going to run my logic inside to that thing that's classified as a string and provide more granular information. So that's how that works. So you can do that with any language. This is just a core Visual Studio concept. You can do this with BS for Mac as well. It uses the exact same API. So that's kind of neat. All right. Was that really it? Let's commit this to source control. Oh, no, it's not it because we forgot to credit our original, the OG, right? The original gangster here. So let's see. And we also need to put a screenshot. I said to do that screenshot. So the reason is here. So based on the, let's just copy this, based on the, based on this, based on the extension by and who wrote it? Avalbright. Avalbright. Oh, let's do the GitHub name instead. All right. That's probably Avalbright. There we go. Oops. There we go. So now it's based on, but is it based on, or is it like a copy off? What should I write here? I think that legally I'm fine, but I want to give all the credit, you know? Yeah. You could just say an updated version. Oh, yeah. Updated from court or source code, whatever. Or yeah. The updated version that with support for visual studio 2019, right? Boom. And the one other thing is your license file. If, if you have a license, a separate license file, I think you want to put something at the top, like uses or, you know, reference the other one. Is that how it works? I always go on luck. But I don't know how to augment a license file. That seems like something. Oh, that's his license. Where's mine? It's in here. This is just the one I always use. Apache, which is compatible, right? With MIT. Yeah. Yeah. You're not calling out anything separate, like copyright or anything. So I think you're also. Right. Oh, yours actually does. If you look down at the bottom, it says copyright. Oh, it does do that. So I think you also want to say something. Like above that, you just say, you can say above copyright, blah, blah, blah. And then put that person's copy from their license. Oh, from their license. Oh, yeah. And where was that? That was in here. That's a good, good idea. Yeah. So there says copyright 2015. You can just copy that in. Oh, that's fantastic. Good idea. Okay. So now we just need a good screenshot. Yeah. And. This is, this is not it. Let's see here. Hey, what happened? I didn't stop working. What's that about? Oh, no. Should I just like go back and undo controls. I think I just, I think I just closed everything. Go clean up on save. Yeah. Oh, I didn't. I need to install that. Why did that not work? Oh, that's my empty package class. We could probably get rid of that. We're only doing math component. It's not package format. That's all good. What did I do in here? I just, I removed the CS class some some. And then I did what? And of course, because I accidentally closed it, I removed this. And I'm going to do a clean. And then I'm going to do a rebuild. No, it just to build. Yeah. With inspiration from Cisco, Michael Cisco, I believe rainbow colors, Alex says, you can totally do rainbow colors. There's an extension out there that does rainbow curly brackets. So that's that's possible. Absolutely. Okay. Please work. I don't know why you stop working before, but this is problematic. I'll have to like, copy everything in. Oh, few. It still worked. All right. Okay. So that's all good. Let's commit that. So added the classifier commit and push. And then we can go here, take a look at. Oh, what did I click? Go away. Here we go. Let's take our build is passing. Right. Here we go. Will it build? Oh, yeah. I forgot to mention that too. I hooked up the whole CI pipeline as well before we went live here just so that we wouldn't have to look at that again. There is one of the episodes where I show my setup with that there that we're looking at here. My build pipeline. Warning. Oh, yeah. We're never using that. Okay. So now that it builds, it actually publishes it to the V6 gallery. So let's go to the V6 gallery.com. Which is not the marketplace. And we got an HTML for JavaScript. Boom. Amazing. Amazing. We forgot. We forgot our screenshot embarrassing. I guess we could. I don't know about that. Like we could lift it from this extension, but I don't know if that's like, I don't feel good about it. Yeah. Because that's kind of art, right? That's a different. I need to find a good HTML. I can just write the strings, I guess, but it would be cool if I could just find what would that be? HTML string in JavaScript. I just want to get some examples. JavaScript strings. See, so I don't know. So I don't need to do like a multi-line thing. That doesn't have HTML though. Converting this to a little. Not enough. Not enough. Okay. I'm going to have to just do it, I guess. Yeah. And view source on it. So the way he did it was, um, he did something like, um, uh, Like this, right? And then he did. He said plus. And then he went down here and eventually he. So let's do something with some. Let's do a video. But it uses some attributes. So poster. Equals. Um. Uh. And file that PNG. Agile, whatever. And source equals video. MP4. Okay. That that's going to be it. Let's say that's the screen judge. Yeah. Yeah, it looks good enough. I mean, as long as you, you zoom it. I have, oh no, I don't have. I was about to say I have a higher DPI, but I don't think I do in this resolution. I'm just going to grab it here. And I'm going to publish straight into my. Read me. Go away. Go away there. Publish straight into my read me. You know, if you want to make it a few lines longer, you could put in like a picture tag or something. I don't know. You've already taken the screenshot. What do you mean that picture tag? Well, type it out. I just sent you one in the, in the chat for stream yard. If you want to use that or I just, I just searched, um, HTML picture tag. What's nice about that is it's a few, it's a few lines long. Of course, then you'll have to either concatenate or UCM. Oh, or you can. Yeah, exactly. Oh, here I just do control H. Place. Double quote with single quote. And then alt A. Oh, that's not what I want. Not all a, I need to do it in. Selection. Didn't I do a selection? All quote with single quote. There we go. And then we go. Boom. One. That makes no sense. I wouldn't make a better one. I don't know. Yeah. Let's just not do that. This is all good. Did you see what I did there to insert the file? So I take a screenshot, right? I'm just going to take a screenshot. And now in my markdown editor, I just control V for paste. It's easy. There's an image in there and it, you know, suggest that I save it. And when I do, it just inserts it like that. Nice. Pretty sweet. And so I can go in there as an image optimizer, optimize for best compression. Just lowered it by 55% of its weight. Okay. That's it. Added green shot. Save this file too. Okay. That's it. I can now go to the marketplace with this thing. I don't know if it's ready for prime time. What do you think, John? Yeah, I'd say ship it. Should I do it? I mean, yeah. It's updated. It's a works in 2019. Okay. Go to the V6 gallery. There's, we need the newer version. That is, oh, where is it? It's being built right now. There it does come with a money back guarantee, right? Of course. It's there. 105. Let's just download that. And then we can go in here and say new visual studio extension. Let's upload that. And I'm ready to go in my downloads. HTML for JavaScript. Boom. Continue. What are we going to call? We're going to call HTML for JavaScript. That's the, that's what's going to go in the URL. So internal name, isn't that kind of weird? But then you can like customize it a little bit, which is nice. And then we're going to copy in our markdown. Here. I'm just going to take all this, copy it right there. And now we just need to update our paths. And so every time I go ahead, I go in and do this. Okay. To find the path of, let's say this image, I say download. And then I go up here and I copy the full path. And then we can go back and paste that in there and paste that in with the license. There we go. And categories. This is, this is web. I'd say this is web. Right. There's a web somewhere. There it is. And text, TypeScript, JavaScript. I think I have to do one at a time. So first I say TypeScript, then JavaScript. And then HTML. There we go. Free. And what is the URL? Well, the URL to the source code is what I copy here. We're going to allow Q&A. There we go. So now we can see what's going on when you upload an extension is that the marketplace is kind of trying to validate the extension. So the first thing it does is that it runs a tool that's created by the Visual Studio Extensibility Team that checks for any warnings like are you using async package? And if you are using it correctly, it checks for like a few best practice kind of things. And so that's one thing that happened when I uploaded it. Then the marketplace itself also runs some security check. I think it does like a detonator chamber kind of thing. Because a V6 is actually a Visual Studio Extension is a zip file. So you could do zip bombs and stuff like that. And so it tries to validate that it's like benign to the extent that it can. Of course we run in proc. And so it runs in with whatever permission Visual Studio runs under once the extension itself is running. But at least it's like that initial check such that if it's a zip bomb, then just the act of installing it will like crash your machine or something like that. So do you know about zip bombs? I do. They're interesting. We did have a question come in first. I'm trying. I can't think two thoughts at a time. So I'm asking this first. So the question on AppVayer versus GitHub Actions. And I assume it's just because you had AppVayer set up originally, right? Like you already had it in place. That's correct. I would have used GitHub Actions if that was when I first started out. It's just my setup is now so streamlined that when I create a new extension, which it does, which I do like... All the time. Not every Friday, but close to it. Then all I have to do is to copy in an existing AppVayer file. And I have PowerShell scripts and all sorts of things. Already it's open source. It's hosted on GitHub. That's referenced by that AppVayer file. And so it's pretty much the same AppVayer file that I just copy into all my projects and it handles everything. So I haven't had the time to set that same thing up for GitHub Actions, but there's no reason I couldn't do that. You know, that might be an interesting thing for a future stream is actually going through and updating and setting up GitHub Actions for this. I don't know. Because you do a lot of cool stuff in there like packaging and all up and everything. Yeah. So I need to figure out how to run PowerShell from there. And then I need to get the build number from GitHub Actions. And that might be it. And then I need to know what the internal paths are on GitHub because I need to... Or maybe use these relative paths. I don't know. Yeah. You mentioned zip mobs and they are super interesting because the way it basically keeps on unzipping it. So it's a way that a small zip file can unzip into a huge multi-gigabyte file itself. Yes. Yeah. It's recursive. You can also do some really bad stuff even just with regular expressions and stuff. Again, like using recursion and just blow stuff up. And I think even XML bombing is a thing too. Barry Dorans was telling me about that like years ago. Yeah. And it's... There's something about you can format or you can add some characters to an XML file that makes XML parses like loop forever or something like that. Yeah. And so they just create more memory and at some point it dies. Wow. Yeah. So now it's done. Uploading. And you can see here it says that it's not public. It says not public. By default, extensions are not public the first time we upload them. So we have to like go in here and say make public. Are you sure? Yes. So now it's public. Now I can open it up and we can see what it looks like. Marketplace. I feel like it's a little... It looks good. See that screenshot actually came out pretty well. Yeah. But I feel like it's a little less on the description here. So one of the things that people complain about and you should pay attention actually out there if you are writing extensions yourself. I was just reading up on some research the marketplace team has done. And they found out that extension consumers, so not authors, but consumers, they find that often there's not enough description of extensions. So it's super important. Like that was one of their biggest complaints actually. Like that they can't, if you don't have good, if you can't give a very clear expectation to what the extension does and how it helps the user, the user is not going to like it. So the more screenshots you got, animated gives, video, really good description. So they have a super good feel for what it looks like. That's apparently very, very important. I think... I know personally whenever I'm searching for an extension, if I can find somebody that's taking the time to document, describe exactly what it does and all that, I'm more likely to go for that. Yeah. It makes the whole difference, right? It really does. And I did write a... I did write a best practice document for doing extensions. Nice. And it's a gist. It's one of my gists on the Githubs. Can I find it? I don't know. I guess yes. I bet you can. I would encourage everyone to read it. Just to get a good... Discover... Oh, I'm not signed in on this browser. So hang on. So... Oops. And then it has like... It outlines those things and a bunch of other things. It's called the V6 Checklist. V6 Checklist. So here it is. Can I post this? I'll post it in the private comments. Yeah. I don't even know what you can do with that. Well, I can copy it into the chat. Yeah. That's something. I mean, we could AKMS it, I guess. I think I have... Oh man, I don't remember. Anyway, this has a bunch of stuff, including name and description. Right? Good marketplace description, right? Nice. So... Yeah. It even gives you like... If you have a GitHub extension, you can take this and create an issue and paste all this in so that you have a checklist for yourself. That's cool. Isn't that geeky? That's a not well-known enough thing that you can do that. Right? Okay. I think that's it. Wow. That was great. Really? And a pretty useful extension. And it's great that you showed how to... I mean, you covered a few things. One was extending a language service, which was the main topic, but also just looking at the process of finding... There's a lot of extensions that just people don't maintain, don't keep up to date, and updating it and testing it and republishing it was not a big deal. Yeah, right? Absolutely. So I would encourage everyone to take a look at that. There's a comment here I want to just... from Vishal. It's tongue-in-cheek. Oh, what did I click? The wrong one. Microsoft employee doesn't use Edge. This browser right here is Edge that I've been using. Let's see it. The only reason I use Chrome, the only thing I use Chrome for is actually to upload extensions to the marketplace because I use a separate Microsoft account that I don't use for anything else, and I don't want that to pollute my daily driver, which is Edge, so I keep that signed in on the Chrome browser. It's just part of my workflow, man. Yeah, you know what's interesting? I used to do that more, but now I use different browser profiles inside Edge. Yeah, so I have one that I'm signed into that's like my personal Microsoft account email and all that, and then I have another that's my work account. I actually have a third that I use for .NET Foundation because I still have some stuff I do for that. And then I have, and then I also use a whatever, a guest account. So I do that like for .NET Community Standups when I'm sharing my browser because otherwise you get all the personal ads and all kinds of, you know, goofy stuff. That's what I'm doing here too, right? Is it a guest account? Yeah. But we do, I mean, as web developers, it is good to test in multiple browsers. I'm a big fan of Edge, I like it, but I use Chrome regularly too, and I think it's important to test against different browsers as well. Oh yeah, absolutely. Well, good stuff. So John, I hope you have a great weekend. And you too. Like I said last week, this is a great way to get excited for the weekend. This is a nice Friday afternoon thing. I'm actually going to go out to have dinner at a restaurant for the first time almost a year, probably a year. That sounds fun. Outside under like heating lamps is going to be so cold. I'm wearing like, because I'm going to leave right now, I'm wearing long underwear and like ski pants. Like literally I'm wearing ski pants right now. Wow. And three layers of like thermal underwear. Wow. All right. Well, I don't want to hold you up from dinner. Thanks everyone. Yeah. We'll be back next Friday, right? So what are we doing next Friday? Next Friday. What are we doing next Friday? Some cool extension. I'm not writing a new extension. Here I can look at notifications. Okay. That's actually going to be really interesting because how do we notify our users about something? There's many different ways that Visual Studio allows us to do notifications. And we're going to take a look at the various different ones. So we're not going to produce an extension next week. We're just going to look at sort of explore the APIs, if you will. Nice. Okay. All right. Well, I guess we'll wrap up there then. So I am going to search around here and I will play the thanks for watching video. And thank you everybody. Bye.