PowerShell: Writing code snippets in the ISE

This is my scratchpad for a simple talk I’ll be doing on creating code snippets for use in the ISE.

Code

PsPresentation01

Code

PsPresentation02.PNG

code

PsPresentation05.PNG

Example with intentional error to show the contrast:

PsPresentation04.PNG

Advertisements

VSCode: richer snippets

Summary: I want to be able to use or define a constructor snippet in Visual Studio Code for C#. However it achieves it, that means when I press a reserved (by me, if I’m defining it) set of keystrokes, then it has to determine the class name, which at that point is only in memory? And therefore needs to be reflected over? In fact the last question is supposition and pointless.. but it’s staying there. 🙂 Regardless, I feel a bit frustrated that I have burned 3 hours and got nowhere. Diddums.

Like the ones in fullfat Visual Studio, that’s what I need. e.g. ctor. Means nothing in VSCode evidently.
This is the ctor snippet in VS-speak:

 

snippetvs01

I thought I read that VSCode supported a richer syntax, so time to put that to the test.

Firstly there is this link:

snippetvs02

Not a lot right now then. And what is there just uses the lean syntax I have used before. So no use.

Then we have the tutorial here, which contains this promising thang…

So first try

npm install -g yo

Which in my case gives me:

Your npm version is outdated.

Upgrade to the latest version by running:
npm install -g npm

OK…Getting annoyed now:

snippetvs04

Maybe it was my own fault for doing it through PowerShell – now trying cmd/Node:

snippetvs05

snippetvs06

Seems better:

snippetvs07

Now try
npm install -g generator-code

snippetvs08

Now

yo code

snippetvs09

snippetvs10

Do a find for folders with .tmSnippet…

snippetvs11

C:\Users\Dennis\AppData\Roaming\npm\node_modules\generator-code\test\fixtures\tmsnippets

Plug that in:

snippetvs12

snippetvs13

snippetvs14

Really unhelpful. Exactly where have you installed it? Can’t find it using Windows Search, so let’s try PowerShell:

gci -Recurse -Path . -Filter “vsc-extension-quickstart.md” -ErrorAction SilentlyContinue

snippetvs15

snippetvs16

snippetvs17
# Welcome to your VS Code Extension

## What’s in the folder
* This folder contains all of the files necessary for your extension
* `package.json` – this is the manifest file that defines the location of the snippet file
and specifies the language of the snippets
* `snippets/snippets.json` – the file containing all snippets

## Get up and running straight away
* press `F5` to open a new window with your extension loaded
* create a new file with a file name suffix matching your language
* verify that your snippets are proposed on intellisense

## Make changes
* you can relaunch the extension from the debug toolbar after making changes to the files listed above
* you can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes

## Install your extension
* To start using your extension with Visual Studio Code copy it into the /.vscode/extensions folder and restart Code.
* To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension.

https://code.visualstudio.com/docs/tools/yocode

https://code.visualstudio.com/docs/tools/samples

 

https://code.visualstudio.com/docs/editor/extension-gallery

Let’s try this route for an example:

snippetvs18

 

snippetvs19

So the C# XML docs extension clearly works… I just have to work out how now, and then I can use that for ctor. Another night:

snippetvs21

In fact as is often the way, now I am out of time, I’ve found possibly the most useful entries:

https://code.visualstudio.com/docs/customization/userdefinedsnippets

https://code.visualstudio.com/docs/editor/editingevolved

 

 

 

Visual Studio… Code Snippets: no snippets manager?

.., no problem:

Keeping things simple, this is a basic snippet, that can act as a template. It has no parameters:

BasicSnippet01

You will see that the Title and the ShortCut, and the filename, are all [MyTestMethodEmpty]. That helps with cataloguing and maintenance, I find.

So that is sitting on the file system in some scratch location, and we want to use it in Visual Studio.

These are the steps:

In Visual Studio, import the snippet you created earlier using any-old text editor (note that even though I intend to use this in C#, I have left the language at the default of Basic):

BasicSnippet02

Browse to the location where you created/saved your snippet, and click [Open] ([Open] not shown in the screenshot):

BasicSnippet03

The next dialog carries forward the named snippet, and suggests a location: this might be a default, or it might just be remembering my previous choice. I don’t care how it decided, this is fine for my purposes:

BasicSnippet04

We then click [Finish]/[OK] (not shown here), and we return to the IDE.

There are 2 things to check: a) Does Visual Studio find the snippet, and b) where has it stored it?

a) Does Visual Studio find the snippet

In the IDE, I start to type [myt], and it finds the shortcut:

BasicSnippet05

I then press tab twice… and it brings up the boilerplate that is clearly from the snippet I created (the squiggles are because I did the editing in a non-Test class). So this is clearly working:

BasicSnippet06

b) where has it stored it?

I just don’t trust Windows Search (and that continues into Windows 10), so I use PowerShell to look for the wild card. Although it’s not efficient, on an SSD it goes pretty quickly. And this screenshot confirms on the file system what we asked for in the IDE, in that we created the file c:\temp, and Visual Studio must have followed the instruction to put in the [My Code Snippets folder].

BasicSnippet07

gci -Path c:\ -Filter *empty*.snippet -Recurse -File -ErrorAction SilentlyContinue

Backup

As this are all pretty small, it is valid to take the whole content of the Code Snippets parent folder, and back that up – 25 files looks a bit suspiciously small, so maybe validate that before putting faith in the backup, but you get my point regarding size:

BasicSnippet08

Blue below represents the things you would change in a template without parameters:

<?xml version=”1.0″ encoding=”utf-8″?>
<CodeSnippets xmlns=”http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet”&gt;
<CodeSnippet Format=”1.0.0″>
<Header>
<Title>MyTestMethodEmpty</Title>
<Author>Dennis</Author>
<Description>MyTestMethodEmpty</Description>
<HelpUrl></HelpUrl>
<SnippetTypes />
<Keywords />
<Shortcut>MyTestMethodEmpty</Shortcut>
</Header>
<Snippet>
<References />
<Imports />
<Declarations />
<Code Language=”csharp” Kind=”” Delimiter=”$”><![CDATA[[TestMethod]
public void TestMethod() {
Assert.Fail();
}]]></Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>

Visual Studio: code snippets

As at work we might stop using ReSharper, I’ll assume that and come back to how you do Code Snippets, Visual Studio-style.

There’s this from MSDN which shows you how to create one.

This is how you can use it of course: you start to type letters and after some pre-defined pause it assumes you want to see the snippet library, in this case for all snippets starting with [p]:

VSSnippets01

Where has this come from?

VSSnippets02

VSSnippets03

Now interesting here is that e.g. the [propa] and [propdp] snippets are not in that list, so presumably it at least aggregates from a few different sources under the [C:\Program Files (x86)\Microsoft Visual Studio 14.0] area. So if I do try to find e.g. propdp,

VSSnippets05

, which expands to this promising code:VSSnippets04

I need to know the location and extension of a snippet, so from the Manager, I can get the location, giving this:

VSSnippets06

Notice that [Snippets] is below [VC#], rather than the other way round, which seems a bit mad to me. Regardless,I now know where to look for the propdp snippet:

C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC#\Snippets\1033\NetFX30

VSSnippets09

VSSnippets08

So that too is under the VC# umbrella, so maybe it is just grouping the C# bits together.

More MSDN [List of common C# snippets (.e.g. for properties)] [Create a New Snippet with Replacements] [Distribute Code Snippets]

Now my pet rant on C# code snippets vs ReSharper was the fact that you can’t do any on-the-fly substitution (see my YouTube elsewhere on what I mean by that) on macro variables. Fine, with a few extra keystrokes, you can achieve the necessary with the standard snippet [propfull]:

PropFull01 PropFull02

and in simple uses, this is probably enough (propg):

Propg01

Might be helpful to show what underpins the fuller one, propfull:

snippett01

Code

Snippets: C# console app

If I want to play with some ideas in C# that don’t involve a GUI but where you want some console output, then that’s obviously a use-case for the Console Application template in Visual Studio… but it’s not quite as I like. THIS is as I like:

ConsoleApp01

Pastebin

That then gives me a clear place in the RunTheTest method to new up stuff, and a ready-made prompt so the console doesn’t just run away after execution.

While I’m on it, this will save me a few keystrokes * 1000, as it’s easier to remove stuff doing this crude form of debugging than it is to add it. I always like to surround arguments in those square brackets for easy visual delimitation, better too many than too few:

ConsoleSnip01

Of course I should anyway go back to my Resharper Template notes here, and the related YouTube video here.

Editors: Visual Studio Code

One day, without recalling I had installed it, I saw I had Visual Studio Code on my box. It strikes me as a bit like Brackets, mentioned elsewhere in this blog.

VSCode01

and they also support Emmet:

VSCode02

My interest right now is in JavaScript, and while I’m at it snippets/templates to avoid typing more than I need to.

Some docs around this here, here and here.

Actually on snippets, it starts to get quite interesting – in Code, if you go File/Preferences/User Snippets, and then select HTML as the language, you get this:

UserSnippets01

So fairly self-documented. If I now remove the comments…

UserSnippets02

If in a piece of HTML, I now do ctrl-space to bring up the suggestions, this is what I see…

UserSnippets03

, and if I hit return I see this…

UserSnippets04

Hm, but in fact that is obviously JavaScript, so that is not a fat lot of help. But in fact it turns out that ALL the template files (e.g. for Docker as well, just as a random punt) have the same starting content.

So those templates anyway give us the principle, so let’s have a punt at that. I’ve hacked up this, which is the simplest possible HTML, but with a few variables thrown in, which get replaced at the point you use them (using ctrl-space to bring up the set):

UserSnippets05

If we now start out with a blank html page, thus…

UserSnippets06

, then do ctrl-space to get this…

UserSnippets07

, hit return to get this, with the cursor resting on ‘Title goes here’,

UserSnippets08

, start typing to replace that text, then hit tab to get to the next replacement (based on the $ variable you put in template), then you end up with this (but bear in mind because Emmet seems to be on by default, you can’t just press tab willy nilly)

UserSnippets08

These are the edits I used:

UserSnippets10

In Chrome with F12, you see this…

UserSnippets09

, which is fine in that a) the files don’t exist, but b) it has replaced the title with what I wanted. Also note that I have AutoSave on in Code, so upsides and downsides I guess, but it suits me.

And maybe finally, it is easy enough to escape double quotes:

UserSnippets11

PowerShell: The basic template in ISE

The basic Ctrl-J template in the PowerShell ISE is a bit noisier than I need. This is all I want:

PSTemplate01

<#
.Synopsis
Drop set of databases
.Example
Drop-Database -DatabasePrefix “TestSet”
#>
function Drop-Database
{
[CmdletBinding(SupportsShouldProcess=$true)]
Param (
[Parameter(Mandatory=$true)]
$DatabasePrefix
)
Begin {
}
Process {
}
End {
}
}

Beyond that, you can use the New-IseSnippet function to make it part of the ISE, and use Ctrl-J to invoke it. Straight from msdn…

$m = @'
Param
(
  [parameter(Mandatory=$true)]
  [String[]]
  $<ParameterName>
)
'@

PS C:\>New-ISESnippet -Text $m -Title Mandatory -Description "Adds a mandatory function parameter." -Author "Kim Akers, Fabrikam Corp." -Force

So applying that principle to our very basic snippet at the top, we get..


$m = @'
<# .Synopsis Drop set of databases .Example Drop-Database -DatabasePrefix "TestSet" #>
function Drop-Database {
[CmdletBinding(SupportsShouldProcess)]
Param (
[Parameter(Mandatory)]
$DatabasePrefix
)
Begin {
}
Process {
}
End {
}
}
'@

New-ISESnippet -Text $m -Title DropDatabases -Description “A snippet to drop databases.” -Author “Dennis Wells, The Things I Do” -Force

Not so fast… So this was OK to execute…

PowerShellSnippetISE01

 

But then…

PowerShellSnippetISE02

Exception calling “Load” with “1” argument(s): “Unable to find or access the file C:\Users\denni\Documents\WindowsPowerShell\Snippets\DropDatabases.snippets.ps1xml”
At C:\Windows\system32\WindowsPowerShell\v1.0\Modules\ISE\ISE.psm1:102 char:9
+ $psise.CurrentPowerShellTab.Snippets.Load($params[“FilePath”] …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : InvalidOperationException

Looking at the file location, the offending file is clearly there…

PowerShellSnippetISE03

, with this content:

PowerShellSnippetISE04

Executing the command line a second time also gives the error.

Hang on…

I recently rebuilt this machine.

If we try this…

New-Item -ItemType File -Path $profile -Force

PowerShellSnippetISE05

And from then on just refer to my old post here

PowerShellSnippetISE07

PowerShellSnippetISE08

PowerShellSnippetISE09

, and as admin..

PowerShellSnippetISE10

Now we shall try again…

PowerShellSnippetISE11

That means I expect to find a snippet with a title of [Mandatory] when I press Ctrl-J in the ISE.

PowerShellSnippetISE12

Hm, so that all works, but it doesn’t seem keen on the carats in the $<parametername>. Fine, don’t care.

I won’t bother with the evidence, but following that little trial, I then ran the DropDatabases snippet through the New-ISESnippet command, and it also appears in the selection list, and can be invoked.

No matter how irritating it is to get these automation-related things working, they SO pay you back for the effort.