Vim, Tagbar, and PowerShell

I discovered a plugin named Tagbar that provides a sort of outline view of the elements in your script or source code file. For example, here is how C# is displayed:
tagbarCS

With a ctags.cnf file set up as described in a previous post, you need to add some information to your _vimrc to allow Tagbar to recognize tags for PowerShell.
In _vimrc:
let g:tagbar_type_ps1 = {
\ 'ctagstype' : 'powershell',
\ 'kinds' : [
\ 'f:function',
\ 'i:filter',
\ 'a:alias'
\ ]
\ }
(Note that the ‘f’, ‘i’, and ‘a’ match up with the end of the regex in ctags.cnf.)
Tell Tagbar where to find the Exuberant CTags executable, if it is not on your path:
let g:tagbar_ctags_bin='C:\ProgramData\chocolatey\bin\ctags.exe'

The result:
tagbarPS1

You can find Tagbar here: Tagbar

Vim, Ctags, and PowerShell

Since I have been working with some PowerShell modules that consist of several .ps1 files (in addition to the .psm1 file), I was curious as to whether ctags could work with PowerShell.

This post was a pretty good start. 

There were two problems, easily fixed.

The first was in the command line to add PowerShell to ctags:
–regex-powershell=”/^function[\t ]*([a-zA-Z0-9_]+)/\1/d,definition/”
The regex doesn’t include ‘-‘, so it won’t recognize a whole lot of functions….

The other problem was in the .cnf file:

--langdef=powershell
--langmap=powershell:.ps1
--langmap=powershell:.psm1

That did not work; the .ps1 files were not recognized, as though the .psm1 line was overwriting the previous assignment.
Looking at the ctags documentation, I learned that this is a way to do it:

--langmap=powershell:.ps1.psm1

Perfect.

My complete ctags.cnf (stored in $env:USERPROFILE):

--langdef=powershell
--langmap=powershell:.ps1.psm1
--regex-powershell=/^[Ff]unction[\t ]*([a-zA-Z0-9_-]+)/\1/f,function/
--regex-powershell=/^[Ff]ilter[\t ]*([a-zA-Z0-9_-]+)/\1/i,filter/
--regex-powershell=/^[sS]et-[Aa]lias[\t ]*([a-zA-Z0-9_-]+)/\1/a,alias/

(Unfortunately, aliases are not recognized yet.)

To use, open a console and navigate to a directory with some PowerShell files.
Here’s the command I use:

> ctags.exe –append=yes –verbose=yes -o p:\tags –tag-relative=yes *

(Run “ctags –help” for all command line switches.)

In using this at work I discovered that ctags (and maybe gvim) doesn’t work well with UNC paths.  I wanted to put my tags file in “\\corp\hdq\data2\ZZZ CMM\2 WPDB\2.03 Application Material\Ziggy_Danger_2014\Support\PowerShell”, but that didn’t work, so I mapped P: to that path and it worked as expected.

In gvim:
:set tags=P:\tags
… and Bob’s your uncle.

Some useful basic commands for using tags:
– With the cursor in a function name, press Control-].
– To pop back to where you came from, press Control-o (oh, not zero).

– From the command line, regex search for tags, can be partial names: :ts /Edit-
This will bring up a list of matching tags, cool.

Very handy for navigating within the .psm1/.ps1 components of a PowerShell module.

Exuberant CTags: http://ctags.sourceforge.net/

If you have Chocolatey installed (you don’t?  Are you nuts?):

> choco install ctags

Get Git status in PowerShell

A script that queries every subdirectory of the current directory, checking for untracked or modified files, as well as updates in a remote source.

For example, running it in the bundles dir (home to a number of Vim addins):

> . gitStat.ps1
—————————————
Checking for local changes
—————————————
AutoComplPop
    No modified files
iceberg.vim
    C:\Users\vim\vimfiles\bundle\iceberg.vim has modified files

neomru.vim
    C:\Users\vim\vimfiles\bundle\neomru.vim has untracked files

nerdcommenter
    No modified files
snipmate.vim
    C:\Users\vim\vimfiles\bundle\snipmate.vim has untracked files

—————————————
Checking for remote changes
—————————————

unite-outline

unite.vim
    C:\Users\vim\vimfiles\bundle\unite.vim has updates available

vim-airline
    C:\Users\vim\vimfiles\bundle\vim-airline has updates available

vim-twilight

Built with and run in PowerShell v4.0; not tested in previous versions.

gitstat

(I’d be interested in any improvements anyone comes up with…)

Build VisStudio projects from PowerShell Console

I like being able to build projects and solutions from the command line.  That is easy enough to do from a “Developer Command Prompt”, as that sets up all the necessary environment variables (via vsvars32.bat).

However, I have long preferred TakeCommand/TCC to cmd.exe, so I created a .bat file for TakeCommand that called vsvars32 (if necessary), then launched MSBuild with the appropriate command line.  The .bat allowed certain parameters – Config and Target – to be set.  Unfortunately, if you set one, you had to set them all.

I wanted the same functionality in PowerShell, and thought I would have to translate vsvars32.bat to a .ps1 file.  Naturally, someone has already done that.  Even better, someone created a way to run a .bat file, extract the resulting environment vars to a temp file, and set those environment vars in the PowerShell session.  Much better – no having to keep a .ps1 in sync with a .bat!

With the power of PowerShell named params and default values, it is easy to create flexible functions that don’t rely on the position of a parameter for its meaning.

Here is the basic help:
C:\Users\Charles\SkyDrive\PowerShell
[master +1 ~0 -1 !] > get-help Build-Solution

NAME
Build-Solution

SYNTAX
Build-Solution [-Proj] <string> [[-Config] <string>] [[-Target] <string>]
[<CommonParameters>]

ALIASES
bld12

REMARKS
None

The Config var defaults to “Debug”, and the Target var defaults to “Build”.

Example:
> bld12 gloogle.sln

> bld12 flankle.sln –Target REBUILD

msbld12 depends on Invoke-CmdScript.  Download the attached files and rename to *.ps1.

msbld12 Invoke-CmdScript

Sharing configuration files

A number of years ago I started a new job at a software company.  A colleague walked me through the email system, network layout, and other infrastructure.  He explained how Brief was the standard editor, and was set up so everyone had a local config file that pointed to the common config file on the network.  The common config set up the necessary drive mappings, file shares, etc.  No matter what computer you logged in to, Brief was set up correctly based on your user id.

I thought of that as I find myself using SkyDrive more and more to share my own config files, script files, utilities, and other junk I want available on various computers.   It is very nice having _vimrc and my PowerShell profile always synchronized across computers, while being able to easily add computer-specific changes.
My local PowerShell profile can be identical on all computers that have a _skydrive environment variable pointing to the local SkyDrive dir:

#
# Load the common profile, shared via SkyDrive
. $env:_skydrive\PowerShell\cb_common.ps1
. $env:_skydrive\PowerShell\colorDir.ps1
# Machine-specific pieces here…

# Load posh-git example profile
. $env:_skydrive\posh-git\profile.example.ps1

Visual Studio 2013 is doing this, now, too.  Not only does VS2013 save information in the user’s profile, but VSCommands 12 saves a whole bunch of options.

vsCommandsSync

Save to a local dir sync’d with SkyDrive, DropBox, or any one of similar services, and your VS2013 experience can be consistent across computers.

PowerShell in VS2013

The Package Manager Console is an instance of PowerShell in a tool window.

You can get your full PowerShell environment by  manually running your startup script:
> cd $env:Home\Documents\WindowsPowerShell  # you may need to use $env:USERPROFILE
> . Microsoft.PowerShell_profile.ps1
(Of course, use the name of your startup script…)

I use posh-git with PowrShell, and now I have that in VS2013:
pkgMgrConsole

(I suspect this would work in VS2012, but I haven’t tried it.)

UPDATE:  To load your startup script automatically, you need to find the script that the Package Manager Console first loads.  I found a file named “Profile.ps1” in “C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\t15jiici.0ox\Modules\NuGet”.

In Profile.ps1, I added:
. C:\Users\Charles\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

Document AutoSave for Visual Studio

For many years I used CodeWright, and then SlickEdit, for all my editing. Both of those had a very useful feature:  Save Files on loss of focus.

As Visual Studio improved, I started using it more and more, and missed that autosave feature.  So, a few years ago, I wrote an AddIn for VisualStudio 2010 that saved all changed documents when VS lost focus.

I kept that AddIn up-to-date for VS2012 and VS2013, but read recently that AddIn support would be going away, and VSPackages was the way to enhance and extend VS.

Converting the AddIn to a VSPackage was pretty straightforward, except for one problem:  the autosave functionality didn’t work initially.  I found that this appears to be a difference in AddIn load behavior vs. VSPackage load behavior.  AddIns are initialized on load, while VSPackages are only initialized when certain conditions exist.  (This is done to minimize VS startup time by preventing all the extensions from trying to load at once.)

The load behavior is controlled by attributes decorating the class that extends Package.  I added the attributes for UIContext_EmptySolution and UIContext_SolutionExists, and the extension works as desired.  See this post for details in installing the extension.

(Note that you can get the same behavior in vim by adding this to your _vimrc:
‘ Save all files when gvim loses focus
au FocusLost * wa
“au” is the abbreviation for autocmd, and FocusLost is the name of the event to trigger it.

Similarly, setting autowrite saves changes when you switch buffers (:bn, for example).)