Making an executable take pipelined input in PowerShell

It annoys me when I am working with PowerShell try to pipe the results of a cmdlet into a exe which doesn’t understand pipelined data.  To solve this problem I began aliasing some of the common programs I would like to pipe data to with custom functions.

For example, I have the following function in my profile to alias notepad.exe:

function n($file) {
  if($file -ne $null){
    notepad $file
  } else {
    notepad $input
  }
}

I can use the function named n whenever I want to open a file using notepad. This function will take a file name either through piping or as a regular argument.

So I can open a file in notepad this way:

n someFile.txt

or this way:

ls *.txt | n

You can create similar functions for other programs as well.  Here is the one I use for Emacs:

$emacs = "emacs.exe -nw --no-splash"
function emacs($file){
  if($file -ne $null){
    Invoke-Expression "$emacs $file"
  }
  else {
    Invoke-Expression "$emacs $input"
  }
}

Posted in PowerShell | Leave a comment

FastSharp 2.0

I just released a new version of my FastSharp program.

Download it or View the source code

This release contains some notable enhancements:

  • Support for multiple languages
    • C#
    • Visual Basic
    • F#
  • Persistence of your current code language and snippet. This allows you to close FastSharp and start right back up from where you left off next time you run it.

Posted in C#, F#, FastSharp, Visual Studio Gallery | Leave a comment

A StructureMap Gotcha

I started converting one of the projects I work on to use the StructureMap DI/IOC framework. The previous framework I used was a super simple one that was built in house.   When switching to StructureMap the plethora of options was a concern at first but once I started the conversion I was amazed how easy it went.  However, there was one subtle difference between the behavior of the old framework I used and StructureMap around object lifecycle.

By default, the old framework created a new instance of an object every time it encountered its corresponding interface in a given object graph. I had assumed that was the same behavior StructureMap would use but I was wrong. StructureMap’s default is called PerRequest.

So when you just write this:

For<IThing>().Use<Thing>();

It will create a new instance of Thing only once per object graph.  What that means is if in a given graph with 3 classes that all have IThing in their constructor they will all receive the same instance of the Thing object.

This is an  issue since I have a couple classes that unfortunately have mutable state and do not behave well if the same instance is used. To fix this I just needed to tell StructureMap to always use a unique instance:

For<IThing>().LifecycleIs(new UniquePerRequestLifecycle()).Use<Thing>();

I personally think this should be the default behavior and any instance reuse should be specifically declared instead. At least it was easy enough to change.

Related Links

Posted in Dependency Injection, structuremap | Leave a comment

OpenWithTest released on Visual Studio Gallery

Download

Either download from the extension manager by searching OpenWithTest or go to the project page here.

Summary

Open with Test is a Visual Studio extension which serves one simple task: To always open your test files and implementation files together.

Details

When writing unit tested applications (especially while practicing TDD) you will often open an implementation file (i.e SomeClass.cs) followed by the test file(i.e. SomeClassTests.cs).  This extension makes this a one step process.

It works by detecting when you open a new file and attempting to find via convention the test file. It assumes that you create one test file per class.  So, if you create a class called Car in the file Car.cs then you will have a test file named CarTests.cs which tests the car class.

Currently, only C# (.cs) files are supported but I plan to expand this to other files types soon.

Configuration

Out of the box, this extension will assume a file is a test file if it ends with the suffix Test,Tests, Fact or Facts.  However, this can be configured.  To change these go to Tools -> Options -> Open With Test and you will see this screen:


Feedback

I would love to get feedback about features or suggestion so please feel free to leave a comment on this blog post or start a discussion post on the Visual Studio Gallery page.

Posted in Tools, Visual Studio, Visual Studio Gallery, testing | Leave a comment

Snippet Designer 1.3 Released!

I just released Snippet Designer 1.3.

CodePlex Page: http://snippetdesigner.codeplex.com/

Visual Studio Gallery Page: http://visualstudiogallery.msdn.microsoft.com/en-us/B08B0375-139E-41D7-AF9B-FAEE50F68392

The key features of this release are support for HTML/ASP.NET, JavaScript and SQL snippets and a much improved snippet searching experience.

If you already have it installed for Visual Studio 2010 you will get an update in your extension manager for the new version.

Change log

Changes for Visual Studio 2010

  • Fixed bug where "Export as Snippet" was failing in a website project
  • Changed Snippet Explorer search to use a relevance based algorithm which yields much better results
  • Added support for JavaScript snippets
  • Added support for SQL snippets
  • Added support for HTML/ASP.Net snippets
  • Added support for tag
  • Made the color of the snippet replacement highlighting configurable

Changes for Visual Studio 2008

  • Fixed bug where "Export as Snippet" was failing in a website project
  • Changed Snippet Explorer search to use a relevance based algorithm which yields much better results
Posted in Snippet Designer, Snippets, Visual Studio, Visual Studio Gallery | Leave a comment

DiffPlex 1.1 Released

I released a small update to DiffPlex that helps improve performance for both the release and debug builds.  I now also package the release build in the download zip file instead of the debug.  The release build shows a significant performance improvement over the debug dll’s.


You can download the new version at the DiffPlex home page.

Posted in C#, DiffPlex, Programming | Leave a comment

A Mercurial PowerShell Prompt

Since switching to Mercurial I often use the “hg summary” command.

hg summary [--remote] aliases: sum summarize working directory state This generates a brief summary of the working directory state, including parents, branch, commit status, and available updates. With the –remote option, this will check the default paths for incoming and outgoing changes. This can be time-consuming.

When you execute this command in a directory that is under source control you will see something like this:

parent: 35:008279cba4b4 tip This is the commit message of the last checkin branch: default commit: 1 modified, 1 unknown update: (current)


I am usually most interested in which branch I am currently working in and what is the current status of my working directory.  Since I use PowerShell as my command line I decided to overwrite the default PowerShell prompt (PS >) with some of the data from the “hg summary” command.

To do this I added the following code to my PowerShell profile:

if (test-path function:\prompt)       { 
  $oldPrompt = ls function: | ? {$_.Name -eq "prompt"}
  remove-item -force function:\prompt 
  } 
  
function prompt() {
  $host.ui.rawui.WindowTitle = (get-location).Path
  
  $summary = hg summary 2>&1
  if($summary.Exception -eq $null) {
    $regex = "(?si)(parent:(?<parent>.*?)(\n|\r)+.*?)(branch:(?<branch>.*)\s)(commit:(?<commit>.*)\s)(update:(?<update>.*))";
    $summary = [System.String]::Join([System.Environment]::NewLine,$summary)
    $res = $summary -match $regex
    $format = "hg b:{0} c:{1}" -f $matches["branch"].Trim(), $matches["commit"].Trim()
    write-host ($format) -NoNewLine 
    write-host (">") -NoNewLine 
  }
  else {
    & $oldPrompt
  }
 
  return " "
 
}

With this in place when you are in a directory that is not controlled by Mercurial you will see the normal prompt.  But once you enter a source controlled directory the prompt will look like:

image

This quickly shows me that I am in the default branch and I have 1 file modified and 1 unknown file in my directory.

After committing it will show:

image

Which shows that the current working directory is in a clean state.

Posted in Mercurial, PowerShell | Leave a comment

DiffPlex 1.0 Released!!

The DiffPlex (http://diffplex.codeplex.com) project is now available on Codeplex!

The DiffPlex project is a combination of a .NET Diffing Library with a Silverlight and HTML diff viewer. It is released open source under the MS-PL license.

code

silverlight

websiteInput

websiteOutput

Posted in Codeplex, DiffPlex, Open Source | Leave a comment

Snippet Designer 1.2 Beta Release with Visual Studio 2010 Support

Yesterday I released Snippet Designer 1.2 Beta.


Codeplex Page: http://snippetdesigner.codeplex.com/


Visual Studio Gallery Page: http://visualstudiogallery.msdn.microsoft.com/en-us/B08B0375-139E-41D7-AF9B-FAEE50F68392


This release contains several bug fixes but more importantly it now includes support for Visual Studio 2010.


I am super excited for this since now you can install the Snippet Designer from inside of Visual Studio using the new extension manager. Just open up the extension manager and search for “Snippet Designer”.


image


Then you just need to install it and restart Visual Studio.


image


Enjoy!

Posted in Codeplex, Snippet Designer, Visual Studio, Visual Studio Gallery | Leave a comment

Regex based Lexer with F#

This lexer allows you to define your regular expression based rules in a very declarative way using F# computation expressions.

open Lexer
let definitions =
    lexerDefinitions {
        do! addNextlineDefinition "NEWLINE" @"(\n\r)|\n|\r"
        do! addIgnoreDefinition "WS"        @"\s"
        do! addDefinition "LET"             "let"
        do! addDefinition "ID"              "(?i)[a-z][a-z0-9]*"
        do! addDefinition "FLOAT"           @"[0-9]+\.[0-9]+"
        do! addDefinition "INT"             "[0-9]+"
        do! addDefinition "OPERATOR"      @"[+*=!/&|<>\^\-]+"
    }

With those defined you can execute the lexer with:

open Lexer
let lex input =
    try
        let y = Lexer.tokenize definitions input
        printfn "%A" y
    with e -> printf "%s" e.Message
lex "let a = 5"

Which will result in:

seq [

{name = "LET"; text = "let"; pos = 0; column = 0; line = 0;};

{name = "ID"; text = "a"; pos = 4; column = 4; line = 0;};

{name = "OPERATOR"; text = "="; pos = 6; column = 6; line = 0;};

{name = "INT"; text = "5"; pos = 8; column = 8; line = 0;}]

The lexer’s code is structured in three parts.  The first part is a state monad using the F# computation expressions.  This enables the declarative approach (seen above) to setup your lexer rules.

module StateMonad
type State<'s,'a> = State of ('s -> ('a *'s))
let runState (State f) = f
type StateBuilder() =
    member b.Return(x) = State (fun s -> (x,s))
    member b.Delay(f) = f() : State<'s,'a>
    member b.Zero() = State (fun s -> ((),s))
    member b.Bind(State p,rest) = State (fun s -> let v,s2 = p s in  (runState (rest v)) s2)
    member b.Get () = State (fun s -> (s,s))
    member b.Put s = State (fun _ -> ((),s))

The second part are the combinators that are used to define your lexer rules.  There are three main combinators:  AddDefinition which lets you define a name / regex pair, AddIgnoreDefinition which lets you define characters which the lexer should ignore and AddNextlineDefinition which lets you define what characters determine a new line.

type LexDefinitions =
  {regexes : string list;
   names : string list;
   nextlines : bool list;
   ignores : bool list; }

let buildDefinition name pattern nextLine ignore =
    state {
        let! x = state.Get()
        do! state.Put { regexes = x.regexes @  [sprintf @"(?<%s>%s)" name pattern];
                        names = x.names @ [name];
                        nextlines  = x.nextlines @ [nextLine];
                        ignores = x.ignores @ [ignore]}
    }
let addDefinition name pattern = buildDefinition name pattern false false
let addIgnoreDefinition name pattern = buildDefinition name pattern false true
let addNextlineDefinition name pattern = buildDefinition name pattern true true

And the final part is the code that performs the tokenizing.  It uses the Seq.unfold method to create the list of tokens.  Unfold is a function which takes a single item and generates a list of new items from it.  It is the opposite of Seq.fold which takes a list of items and turns it into a single item.  The tokenize function used Seq.unfold to generate each token while keeping track of the current line number, position in that line and position in the input string.

type Token =
    { name : string;
      text: string;
      pos :int;
      column: int;
      line: int }

let createLexDefs pb =  (runState pb) {regexes = []; names = []; nextlines = []; ignores = []} |> snd
let tokenize lexerBuilder (str:string) =
    let patterns = createLexDefs lexerBuilder
    let combinedRegex =  Regex(List.fold (fun acc reg -> acc + "|" + reg) (List.head patterns.regexes) (List.tail patterns.regexes))
    let nextlineMap = List.zip patterns.names patterns.nextlines |> Map.ofList
    let ignoreMap = List.zip patterns.names patterns.ignores |> Map.ofList
    let tokenizeStep (pos,line,lineStart) =
        if pos >= str.Length then
            None
        else
            let getMatchedGroupName (grps:GroupCollection) names = List.find (fun (name:string) -> grps.[name].Length > 0) names
            match combinedRegex.Match(str, pos) with
                | mt when mt.Success && pos = mt.Index  ->
                    let groupName = getMatchedGroupName mt.Groups patterns.names
                    let column = mt.Index - lineStart
                    let nextPos = pos + mt.Length
                    let (nextLine, nextLineStart) = if nextlineMap.Item groupName then (line + 1, nextPos) else (line,lineStart)
                    let token = if ignoreMap.Item groupName
                                then None
                                else Some {
                                        name = groupName;
                                        text = mt.Value;
                                        pos = pos;
                                        line = line;
                                        column = column; }
                    Some(token, (nextPos, nextLine, nextLineStart))
                | otherwise ->
                    let textAroundError = str.Substring(pos, min (pos + 5) str.Length)
                    raise (ArgumentException (sprintf "Lexing error occured at line:%d and column:%d near the text:%s" line (pos - lineStart) textAroundError))
    Seq.unfold tokenizeStep (0, 0, 0) |> Seq.filter (fun x -> x.IsSome) |> Seq.map (fun x -> x.Value)

Lastly, here are the unit tests written using XUnit.Net:

module LexerFacts
open Xunit
open Lexer
open System.Linq
let simpleDefs =
    state {
        do! addNextlineDefinition "NextLine"           "/"
        do! addIgnoreDefinition "IgnoredSymbol"        "=+"
        do! addDefinition "String"                     "[a-zA-Z]+"
        do! addDefinition "Number"                     "\d+"
        do! addDefinition "Name"                       "Matt"
    }

[<Fact>]
let Will_return_no_tokens_for_empty_string() =
    let tokens = Lexer.tokenize simpleDefs ""
    Assert.Equal(0, tokens.Count())

[<Fact>]
let Will_throw_exception_for_invalid_token() =
    let tokens = Lexer.tokenize simpleDefs "-"
    let ex = Assert.ThrowsDelegateWithReturn(fun () -> upcast tokens.Count()) |> Record.Exception
    Assert.NotNull(ex)
    Assert.True(ex :? System.ArgumentException)

[<Fact>]
let Will_ignore_symbols_defined_as_ignore_symbols() =
    let tokens = Lexer.tokenize simpleDefs "========="
    Assert.Equal(0, tokens.Count())

[<Fact>]
let Will_get_token_with_correct_position_and_type() =
    let tokens = Lexer.tokenize simpleDefs "1one=2=two"
    Assert.Equal("Number",tokens.ElementAt(2).name)
    Assert.Equal("2",tokens.ElementAt(2).text)
    Assert.Equal(5,tokens.ElementAt(2).pos)
    Assert.Equal(5,tokens.ElementAt(2).column)
    Assert.Equal(0,tokens.ElementAt(2).line)

[<Fact>]
let Will_tokenize_string_with_alernating_numbers_and_strings() =
    let tokens = Lexer.tokenize simpleDefs "1one2two"
    Assert.Equal("1",tokens.ElementAt(0).text)
    Assert.Equal("one",tokens.ElementAt(1).text)
    Assert.Equal("2",tokens.ElementAt(2).text)
    Assert.Equal("two",tokens.ElementAt(3).text)

[<Fact>]
let Will_increment_line_with_newline_symbol() =
    let tokens = Lexer.tokenize simpleDefs "1one/2two"
    Assert.Equal("Number",tokens.ElementAt(2).name)
    Assert.Equal("2",tokens.ElementAt(2).text)
    Assert.Equal(5,tokens.ElementAt(2).pos)
    Assert.Equal(0,tokens.ElementAt(2).column)
    Assert.Equal(1,tokens.ElementAt(2).line)

[<Fact>]
let Will_give_priority_to_lexer_definitions_defined_earlier() =
    let tokens = Lexer.tokenize simpleDefs "Matt"
    Assert.Equal("String",tokens.ElementAt(0).name)

I attached a zip containing all the code mentioned above: F# Regex Lexer


Posted in F# | Leave a comment