Saturday, October 30, 2010

Emacs and ReSharper keybindings in Visual Studio

Since committing to Emacs as the text editor to supplement my primary (integrated) development environment, Visual Studio, Emacs has become an indispensable part of my computing life. I run it on any machine I use on a regular basis and sorely miss it when it's not there. It has lived up to its long standing reputation as an extremely powerful text editor that it is more than just a text editor.

I use Visual Studio for C# and .NET coding and Emacs for everything else. Emacs functions as my shell environment (via Eshell with a major assist from Cygwin) when working with file systems local or otherwise. Emacs is where writing and editing Python files, shell scripts, config files, todo lists (with org-mode), notes, and other tasks too trivial to list all take place.

Parsing log files, interacting with source control, and connecting to and running queries on SQL Server have found their way into my Emacs sessions. Also, since editing JavaScript code using Visual Studio 2005 was as mundane and constraining as using Notepad, with no intellisense and no ReSharper magic, Emacs became a more nurturing environment for manipulating JS code. (At least until making the upgrade to Visual Studio 2010 where JavaScript support is vastly improved thereby displacing Emacs in this one activity.)

When using Visual Studio for day-to-day coding sessions in C#, Emacs style keybindings are a must for me. While not as precise as Vim, they do provide me with greater control over the text than the default keybinding most others use in VS or in any other modern, popular IDE or text editor.

ReSharper is what chiefly keeps me relying on Visual Studio to do .NET development. This robust and powerful commercial plug-in for Visual Studio has refactoring and navigation features that are not just superb but they give such control over the code and source files analogous to the power Emacs grants its user with text manipulation.

Initially, adopting Emacs key strokes for Visual Studio was not going to be easy without allowing peaceful co-existence with ReSharper's own extensive list of keyboard shortcuts. Conflicts were inevitable. (These conflicts and how to smoothly resolve them will be covered in more detail.)

Prior to the release of VS2010, the native Emacs keyboard scheme in VS2005 sufficed for coding. To enable it, select on the menu
Tools -> Options -> Environment -> Keyboard -> Apply the following additional keyboard mapping scheme -> Emacs
It provides most of the basic motions and text editing commands found in Emacs ranging from deleting all characters from the cursor to the end of the current line via C-k to moving between words using M-f and M-b. Thus, it gave me the same comforting, familiar experience as coding in Emacs itself.

Unfortunately, upon learning VS2010 would no longer support Emacs keybindings, I needed to find a suitable alternative when upgrading to it from VS2005 (and skipping over Emacs-enabled VS2008). I briefly considered learning VIM either by trying out ViEmu, a commercial VIM emulator for VS, or VsVim, a similar but free extension for VS2010. Fortunately, sanity prevailed and I decided to use XKeymacs, a utility app that applies Emacs style keybindings to any Windows application or program whether it be Word, Outlook, Notepad, Windows Explorer, or cmd.exe. I'd already been using XKeymacs for some time for those other places that I cannot (easily) reach with Emacs itself including composing emails and editing text in web browsers (although I've had some luck with the Firefox add-in, It's All Text!). XKeymacs is far from perfect but works reasonably well.

After using XKeymacs in VS2010 for a bit, I realized that it did a better job than the old native version in VS2005. While XKeymacs has its problems, the built-in Emacs VS keybindings were relatively worse and more aggravating to use in comparison. (Again this will be dissected in more detail.)

Whether you use XKeymacs or the built-in Emacs VS keybindings, I recommend configuring ReSharper to use the "Visual Studio Scheme" and not the "ReSharper 2.x/IDEA scheme" provided in the default install. At first, I did learn and used the (IntelliJ) IDEA scheme when I started with ReSharper mainly because I thought that if I ever were to use the IDEA IDE then the transition would be easier. But, prematurely optimizing for something that might never happen is something to be avoided not just when developing software (if I find myself needing to code in Java I'd probably use Eclipse with Emacs keybindings or Emacs itself).

Choosing the VS scheme over ReSharper's allows for Emacs keybindings to have precedence over the ReSharper keyboard shortcuts whenever possible. The rationale is that Emacs keybindings are far more ubiquitous than ReSharper's. Resharper is limited to Visual Studio (and the aforementioned IntelliJ) while Emacs key shortcuts can be found on a multitude of OS platforms, IDEs, text editors, and shell consoles. It is best to stick with the consistency and prevalence of Emacs style key chords rather than with ones from a niche commercial add-on tool.

Using the Visual Studio scheme for ReSharper does cause problems when working with other team members who use the other ReSharper/IDEA scheme. It's bad enough Emacs keybindings are annoying for someone who sits at my machine and it has not been turned off by the time they type their first character ("Hey, can't I copy? Is Ctrl+C broken? Oh yeah, I forgot, you are using those goofy Emacs keys.").

What's worse (with deeper implications) is when another teammate, knowing a different set of ReSharper shortcuts than I do, attempts to specify a command for me to run. This is likely to occur when pair programming or during code reviews. For example, they might say type Ctrl + n to find the 'Foo' class they recently refactored and it disrupts the flow before we finally figure out that they meant for me to run 'Go to Type' which I know as Ctrl + t. It's like we're speaking to each other in a foreign language. Not good for fostering fluid team collaboration and communication. (This tooling gap occurs with shell commands too since I am fond of using bash on Windows via Cygwin while others are cmd.exe wizards. Typing 'ls' in cmd.exe instead of 'dir' gets odd looks at times.)

Shortly after switching to XKeymacs in VS, a new Emacs Emulation extension for VS2010 was announced that more or less brings back the same old Emacs keyboard scheme from VS2005 (and Visual Studio 2008.) With this new Emacs extension, I was hoping some of the problems that irritated me in the old one which were subsequently magnified when switching to XKeymacs were fixed. But, with the exception of a few things, these annoyances are either still there or behave worse in some cases.

Reasons why I prefer XKeymacs over the VS Emacs keybindings in VS2005 and VS2010:
  • Tabbing and indenting works sanely.
  • Auto formatting works consistently. For example, curly braces line up properly and blocks of code are smartly indented after hitting ENTER. This is not how it behaves in either VS2005 or VS2010 Emacs scheme.
  • DELETE button works by simply pressing it and not requiring to also hit CTRL. Seems blasphemous to care about a key that is not fundamental to Emacs and contradicts my efforts to map the keys faithfully but it's dead simple functionality that should work for any Windows application even if ported from another OS platform. Another nicety of XKeymacs is after selecting text, it supports C-d to delete the entire text not just with the conventional kill command C-w. With VS Emacs, you are limited to just C-w. Granted this is how it also functions in Emacs but it is a nice feature that I would not mind if Emacs supported too out-of-the-box (without requiring adding an Elisp command to remap the key in your .emacs file).
  • Able to overwrite selected text simply by typing and not killing it first (this is the same issue as in the previous item). For example, ReSharper's live templates such as the 'if-statement' code snippet highlights text as contextual placeholders to type custom variable names and values. VS Emacs bindings requires cutting the text via C-w before writing any new text. XKeymacs allows you to just start typing away without that extra step.
  • Copying/yanking text from other applications to VS works as expected (especially from Emacs itself). I never figured out how to get it to work properly in VS2005 Emacs scheme. I suspect the source of the problem was perhaps VS maintaining its own internal kill ring (clipboard) that did not interact well with the Windows clipboard. Sometimes hitting ESC before pasting would help but even that was not reliable. Far worse, VS2010 does not support any copy and paste from external applications (for example, try copying some text from Notepad and then do C-y in VS. You'll see nothing is pasted other than the last yank/kill from within VS)
  • ReSharper's Multiple Entries Clipboard works. It was buggy with the Emacs emulation in VS2005 and in VS2010 it does not work at all.
  • Not limited to just the text editor but able to use XKeymacs everywhere in Visual Studio such as in dialog boxes (e.g. ReSharper's Rename and Find/Replace features), in ReSharper's Navigation and Search features (e.g. in 'Go To Type' and 'View Recent Files'), in other window panes (e.g. the Immediate Window and Solution Explorer) and in textboxes on the menubar (e.g. the extended command-line).
  • Can navigate quickly in Intellisense's dropdown list using C-p and C-n in lieu of the arrows keys (although hitting CTRL for some reason makes the list of values transparent)
  • Does not disable the graphical menu of all open files and window panes when typing CTRL + TAB. It is completely gone from both VS2005 and VS2010 when using VS Emacs scheme.
Despite all of this praise, XKeymacs has a few faults. On occasion it can behave flakey requiring either resetting or closing and then re-running the XKeymacs exe. Another problem is sometimes the ALT key will trigger the file menu instead of (or in addition to) the normal key command.

Regardless, these peculiarities are not enough to keep me from using XKeymacs. However, I use the VS Emacs scheme as fallback whenever XKeymacs acts unbearably goofy. Switching between the two "modes" is fairly quick in my enviroment. XKeymacs has the key command C-q that toggles between disabling and enabling it. In addition, I have created and defined a VS macro that can toggle between the Emacs scheme and the "Default" VS scheme via the key command M-q which I bound to the macro. By combining these two commands, hitting C-q M-q (or M-q C-q) allows me to go back and forth when necessary.

Speaking of macros both XKeymacs and VS Emacs scheme support recording and running macros via the same keys commands used in Emacs proper:
C-x (  recording a macro
    C-x )  stop recording a macro
    C-x e  run the macro
XKeymacs' macro feature works in places you would not expect including applications like Notepad, Outlook, and Word. VS Emacs scheme's macro key chords are hooked into Visual Studio's built-in macro functionality. Discovering both to have support was a surprise to me. I use macros in Emacs quite often. It's great to have this powerful functionality with the same key commands I'm already familiar with.

However, I limit the use of XKeymacs' macros to the simplest of text editing scenarios before turning to alternatives. Sometimes it does behave strangely at which time I might switch over to using VS's macros via Emacs scheme which tends to be a bit more smooth. For more complex editing situations, I'll just open the file in Emacs itself for heavy duty text manipulation.

Configuring Keybindings in Visual Studio

Now follows a list of conflicts and missing keybindings and how best to resolve them. I will include not just how XKeymacs can be configured in VS with ReSharper but also the built-in Emacs VS schemes for both VS2005 and VS2010 (I assume this applies for VS2008 but no guarantees since I've never used it and can not confirm it can be configured the same.)

All key combinations are presented in the traditional Emacs style and format. Specifically, "C-" for "CTRL" and "M-" for "ALT". For example, 'Kill to end of line' is shown as
C-k
instead of
CTRL + k
Also, SHIFT will correspond to the capitalized version of a character such as
C-K
instead of
SHIFT + CTRL + k
To change any key settings in VS go to:
Tools -> Options -> Keyboard 
This is where you'll configure keyboard shortcuts. Generally, you should set the value for 'Use new shortcut in:' to be "Text Editor" (and, if necessary, "HTML Editor") since it overrides any other commands with the same pre-existing key shortcuts that are set to be "Global". If no other commands are using the keybindings (this is evident if any values appear in 'Shortcut currently used by:' dropdown list after pressing the desired keys in 'Press shortcut keys:') then it's safe to just use "Global".

Configuring Keybindings in XKeymacs

When configuring XKeymacs, make certain to select 'devenv.exe' as the specific setting and not the 'Default' value setting. Initially opening XKeymacs' properties always reverts to 'Default' so it is easy to overlook this.

To configure XKeymacs:
In Windows System Tray -> right-click XKeymacs icon (or double-click will automatically open 'Properties) ->
 Properties -> from dropdown list at top of screen, select 'Microsoft Visual Studio .NET (devenv.exe) ->
 select 'Use Specific Setting'
For the 'devenv.exe' setting, I recommend removing all extraneous key commands that serve as duplicates for the basic Emacs commands. These alternate key strokes might include an extra 'SHIFT' (or 'ALT') key press which could override existing non-Emacs VS commands. For example, the command 'forward-char' is typically just C-f but in XKeymacs it can also be called by Shift + Ctrl + f. (In VS, this command is belongs to 'Find All Files' which I use frequently. I'd rather keep it unchanged since I don't need another (more cumbersome) way to move forward one character.

To remove these key commands:
In XKeymacs -> Properties -> change combobox from "Default" to "Microsoft Visual Studio .NET (devenv.exe)" -> Change from 'Use Default Setting' to 'Use Specific Setting' ->
Click 'Advanced' tab -> under 'Category' select "Motion" -> under 'Commands' select "foward-char" -> 
under 'Current keys' select "Ctrl+Shift+B" -> click 'Remove' button
Repeat this for all other commands found under the categories:
  • Search
  • Motion
  • Killing and Deleting
  • Other
Commands that have two or more key bindings associated with them should have their key shortcuts using SHIFT removed. There are a lot of them. Once removed, it should free up some default shortcuts for other VS and ReSharper commands that use the same keys.


Delete Next Character: C-d

XKeymacs Mode:

XKeymacs' command C-d overrides ReSharper's Duplicate Line or Selection command. Instead, set
ReSharper.ReSharper_DuplicateText
to use:
C-D
As mentioned, make sure that XKeymacs is configured to no longer use SHIFT for killing forward characters thus making this available for ReSharper's duplicate text command.

While forward character delete is consistent with Emacs, backward character delete is not only bound to the expected BACKSPACE button as in Emacs, but also bound to C-h. I tend to forget that this exists in XKeymacs since in Emacs proper it is bound to 'Help'. C-h is a better fit for backward delete rather than the infrequently called Help command since it keeps your fingers on home row.

VS Emacs Scheme:

When first hitting C-d and then prompted with 'ReSharper Shortcut Conflict' dialog box, I selected "Use Visual Studio commands" but this does not automatically bind to the 'delete next character' command. The reason is that C-d is reserved for other commands in VS including the family of Debug.* commands. Looking at the documented list of VS Emacs shortcuts, C-Delete is what is expected to be used. This is not consistent with Emacs.

Therefore, manually set the following VS command (using "Text Editor" and not "Global" setting)
Edit.Delete 
to
C-d
Then follow the same steps as XKeymacs mode for reassigning ReSharper's duplicate text command.


Move to the end of the line: C-e

XKeymacs Mode:

Some conflicts with existing ReSharper bindings including 'Insert Live' template, 'Surround With' template, and Code Cleanup. Some of these I use regularly and some I don't. Here are two I do use:

Bind 'Surround With' template command
ReSharper.ReSharper_SurroundWith
to
C-M-j  
The above keybindings is borrowed from the ReSharper 2.x/IDEA scheme.

Bind 'Code Cleanup' command
ReSharper.ReSharper_CleanupCode
to
M-j
The above keybinding is not based on anything other than to be consistent with the previous 'Surround With' command.

VS Emacs Scheme:

When hitting
C-e
you'll be prompted by ReSharper to select which scheme to use whether default VS or ReSharper's (IDEA). Select VS scheme and not ReSharper's. This should be sufficient but make sure that:
Edit.EmacsLineEnd
is bound to
C-e   


Kill region: C-w

XKeymacs Mode:

N/A. Works as expected.

VS Emacs Scheme:

Bind the VS command:
Edit.Cut
to
C-w
Oddly, this standard keybinding of Emacs is not part of the VS Emacs emulation. As an alternative, it recommends using Shift + DELETE. Meanwhile, C-w is bound to Edit.SelectCurrentWord which I thought was ReSharper's similar function but it is actually the native one for VS.

I recommend removing the binding from Edit.SelectCurrentWord and just use ReSharper's equivalent version, 'Extend selection', which already works with C-M-Right Arrow (and conversely 'Shrink Selection' set to C-M-Left Arrow).


Delete (kill) from cursor (point) to end of line: C-k

XKeymacs Mode:

N/A. Works as expected.

VS Emacs Scheme:

Bind the VS command:
Edit.EmacsDeleteToEOL
to
C-k
No (apparent) conflict with ReSharper, but for some reason did not seem bound at all even though according to the list of VS Emacs key shortcuts it should be. Instead, it is by default bound to a whole class of commands such as Edit.CommentSelection.


Tab and Indentation: C-i

XKeymacs Mode:

This works as expected. Hitting ENTER automatically indents the next line to match the previous line.

XKeymacs does not support C-j which inserts newline and indents but it does support C-m which is an alternate to ENTER and only inserts newline. C-m works the same as ENTER in Visual Studio meaning it does smart indenting too and has the advantage that it is easier to hit than ENTER. Regardless, I also bound C-j to Edit.Breakline to use for consistency and convenience.

VS Emacs Scheme:

This is the messy. Tabbing and indenting is one of the weakest and most confusing areas of the VS Emacs scheme. It does not behave how you would expect including interfering with smart indentation.

In both VS2005 and VS2010 Emacs schemes, if you write a line of code and then hit ENTER, the new line will not automatically indent. Instead, ENTER takes the point (cursor) to the first column of the line. You have to hit TAB again to get it to indent. Otherwise, after you start typing some new code, hitting ";" will automatically indent the line to match the preceding one. Both options are not optimal.

Instead, you need to get in the habit of using C-j. This key command is bound to Edit.EmacsBreakLineIndent' which will insert a new line and indent the line correctly.

Hitting TAB on an existing line with text behaves strangely. In VS2010, it toggles tabbing if already tabbed. In VS2005, it does nothing- the line remains unchanged. Once a line is indented, you cannot further indent the line by pressing TAB in either versions of Visual Studio.

To address this issue, I originally bound:
Edit.IncreaseLineIndent 
to
C-M-TAB  
and
Edit.DescreaseLineIndent 
to
Shift-C-M-TAB  
This was really helpful in JS files in VS2005 since no smart indent supported.

However, I then saw this suggested solution to inject additional tabs by using:
C-q TAB
It relies on the Emacs' quoted insert text functionality that VS Emacs scheme also supports via Edit.EmacsQuotedInsert which is bound to C-q.

Unfortunately, C-q conflicts with XKeymacs key command to enable and disable itself which I use fairly heavily. Therefore, I assigned C-Q to Edit.EmacsQuotedInsert and removed the extra keybind from XKeymacs.
XKeymacs -> Under Categories "Other" -> under 'Commands' select "Enable or Disable XKeymacs" -> under 'Current Keys' select Ctrl+ Shift + Q -> click 'Remove'

Finally, for completeness on all-things-tabbing, I thought I could bind
C-i
to
Edit.Indent
but that is reserved by 'Incremental Search' in the default, non-Emacs scheme. I just left it "as is" since it is convenient to have when pair programming with Emacs keybindings turned off.


Delete spaces and tabs around point M-\

XKeymacs Mode:

Bind the VS command:
Edit.DeleteHorizontalWhiteSpace
to
M-\
XKeymacs does not support this command but I use it all the time in Emacs. However, it conflicts with ReSharper's 'Go to File Member'. Therefore I re-mapped
ReSharper.ReSharper_GotoFileMember
to
M-|
VS Emacs Scheme:

Follow the same steps as described for XKeymacs mode.


Expand the word in the buffer before point as a dynamic abbrev: M-/

XKeymacs Mode:

Does not support this command so bind Visual Studio Intellisense/AutoComplete command:
Edit.CompleteWord
to
M-/
VS Emacs Scheme:

N/A. Works as expected.


Running commands by name: M-x

XKeymacs Mode:

XKeymacs supports the keybinding M-x for running external commands in cmd.exe shell, but I never found much use for it since it is awkward to use with no visual feedback of what you just ran.

Therefore, I removed from 'devenv.exe' settings:
In XKeymacs -> under 'Category' select "Other" -> under 'Commands' select 'execute-extended-command' -> under 'Current keys' select "Meta-X" -> click 'Remove' button
Then bind the VS command:
Tools.GoToCommandLine
to
M-x

I use this VS command line feature frequently particularly for TFS source control commands such as
  • File.TfsCompare
  • File.TfsUndoCheckout
  • File.TfsHistory

and to call other commands from the Application Menu such as
  • Tools.Options
  • Tools.AttachProcess
  • File.CopyFullPath (pasting in other applications like emacs itself)
  • bl (alias for Debug.Breakpoints)
  • callstack
  • View.BookmarkWindow (precedes ReSharper 5.0 bookmark)
VS Emacs Scheme:

N/A. Works as expected.


Incremental search forward: C-s

XKeymacs Mode:

Works as expected hooking into VS's
Edit.IncrementalSearch
although not sure how it is automatically bound to it. It is a different command than the traditional 'Find/Replace' command that XKeymacs usually uses in most other Windows application. Regardless, one less thing to bind manually.

VS Emacs Scheme:

N/A. Works as expected.


Incremental search backward: C-r

XKeymacs Mode:

N/A. Works unexpectedly just as incremental search forward.

VS Emacs Scheme:

This is not bound to C-r although C-s is bound to search forward. Instead, the default key shortcut is C-I which is awkward to use when toggling with incremental search forward (C-s). Therefore, mapped the VS command:
Edit.ReverseIncrementalSearch
to
C-r
C-r conflicts with numerous ReSharper refactor mode commands particularly all of the refactoring commands. However, since I tend to use C-R to get list of contextual refactorings and never was in the habit of calling individual refactoring commands, remapping C-r is preferable.


Scroll the selected window so that the current line is the center-most text line: C-l

XKeymacs Mode:

XKeymacs does support this command but it does not work properly in VS. Instead of centering the screen on the current line, it keeps moving the screen one line down.

Therefore, I mapped the following the VS command:
Edit.ScrollLineCenter
to
C-l
and then removed the C-l keybinding from XKeymacs 'devenv.exe' setting by:
XKeymacs -> Advanced -> under 'Category' select "Motion" -> under 'Commands' select "recenter" -> under 'Current keys:' select "Ctrl + L" -> click 'Remove' button
VS Emacs Scheme:

N/A. Works as expected.


Tranpose character: C-t

XKeymacs Mode:

One of the rare circumstances where I chose ReSharper's default key shortcut and ignoring an existing Emacs keybinding. I removed XKeymacs binding of C-t by going into its settings and configuring:
XKeymacs -> Advanced -> under 'Category' select "Killing and Deleting" -> under 'Commands' select "transpose-chars" -> under 'Current keys:' select "Ctrl + T" -> click 'Remove' button
I hardly encounter situations where I need to transpose single characters (although words and lines are more common.) On the other hand, I use Resharper's 'Go to Type' command all the time so I make an exception to keep C-t assigned to it.

Make certain the VS command:
Resharper.Resharper_GoToType
is bound to
C-t
VS Emacs Scheme:

Follow the same steps as described for XKeymacs mode.


Numeric Argument: C--

XKeymacs Mode:

The VS command for navigating backwards is another situation where a VS keybinding wins over an existing Emacs' keybinding:
View.NavigateBackward
is already bound to
C--
However, this conflicts with XKeymacs command 'numeric argument -' for passing negative arguments related to the C-u repetition counts. I never use this and if I do then I would call it via M--. So, kept it unchanged in VS and removed the conflict from XKeymacs 'devenv.exe' settings:
XKeymacs -> Advanced -> under 'Category' select "Other" -> under 'Commands' select "numeric argument -" -> under 'Current keys:' select "Ctrl + -" -> click 'Remove' button
The 'cycle through mark ring' command in Emacs, C-x C-SPC, reminded me of the VS command, View.NavigateBackward. Although not quite the same as VS's feature, it is similar enough for me to also bind these keybindings for consistency.

To do this, find the .xkeymacs config file in the XKeymacs directory.
...\xkeymacs347\etc\English (United States).xkeymacs
Add the line:
(fset 'cycle-mark-ring "\Ctrl+-")
Then configure
XKeymacs Properties -> select 'devenv.exe' -> 'Advanced' tab -> Category 'Original Command' -> 
you should now see the new command, 'cycle-mark-ring', previously added in the config file in the list of commands. To continue:
Under 'Press new shortcut key:' -> check 'Ctrl-X' -> in text field below it, press 'Ctrl-SPACEBAR' -> click 'Assign' -> 'Current keys:' list should now include 'Ctrl-X Ctrl-Space'.
Now in VS, along with C--, C-x C-SPC will also run the navigate backward command when XKeymacs is enabled.

I initially tried to bind to C-u C-SPC but XKeymacs limits prefixing commands with C-x. However, this is for the best since C-x C-SPC is more appropriate because it cycles through all buffers just as the View.NavigateBackward command navigates through all open documents in Visual Studio. That other command only cycles through ones in the current buffer.

I generally stick to using C-- since it is less awkward to type and it is consistent and more fluid to use when switching back and forth with View.NavigateForward which is C-_ (a.k.a. Shift+Ctrl+ -)

VS Emacs Scheme:

Follow same steps as XKeymacs mode.


Undo: C-_

XKeymacs Mode:

The complimentary VS command to previous item 'navigate backward' is of 'navigate forward'
View.NavigateForward
is bound to
C-_

This keybinding conflicts with one of the three existing XKeymacs commands for 'Undo'. Since I always use C-/ for Undo then removed that unnecessary conflicting keybinding:
XKeymacs -> Advanced -> under 'Category' select "Error Recovery" -> under 'Commands' select "undo" -> under 'Current keys:' select "Ctrl + Shift + -" -> click 'Remove' button
VS Emacs Scheme:

A conflict exists since under the VS Emacs scheme
Edit.Undo
is bound to
C-_
Again, since Edit.Undo is also bound to C-/ which is what I only use then remove that binding from the Emacs scheme.


Delete blank lines: C-x C-o

XKeymacs Mode:

This is not supported in XKeymacs but Visual Studio does have this command. It behaves slightly different in VS than in Emacs. In VS, it removes all blanks lines from the cursor and below. Any blank lines above the current blank lines will be ignored. To remove those, you need to call the delete blank lines command again. In Emacs, the equivalent command removes all of the blank lines below and above but leaves the current blank line. To get rid of this line, you need to repeat the same command again.

Now, to use the C-x C-o keybindings requires reconfiguring XKeymacs. First, assign in VS:
Edit.DeleteBlankLines
to
M-o
I would have preferred using C-x C-o but C-x is the common command for Edit.Cut and rather not mess with it to leave it available when pair programming. Therefore, arbitrarily chose M-o as an alternative.

In XKeymacs, you can map key commands to custom ones to use while running XKeymacs.

Find the .xkeymacs config file in the XKeymacs directory. For example, mine is found under Program Files:
C:\Program Files\xkeymacs\xkeymacs347\etc\English (United States).xkeymacs
Add the line:
(fset 'delete-blank-lines "\Alt+o")
Then configure
XKeymacs Properties -> select 'devenv.exe' -> 'Advanced' tab -> Category 'Original Command' -> 
you should now see the new command, 'delete-blank-lines', previously added in the config file in the list of commands. To continue:
Under 'Press new shortcut key:' -> check 'Ctrl-X' -> in text field below it, press 'Ctrl-o' -> click 'Assign'
'Current keys:' list should now include 'Ctrl-X Ctrl-O'. Now in VS, C-x C-o will run delete blank lines command (as well as M-o the original bindings in VS) when XKeymacs is enabled.

VS Emacs Scheme:

N/A. Works as expected.


Split the selected window into two windows, one above the other: C-x 2

XKeymacs Mode:

As with the previous item, XKeymacs does not support this but VS does have this command. However, just like before, I'm unable (or unwilling) to bind to C-x 1 since it interferes with Edit.Cut (C-x) in non-Emacs mode. Therefore, need to map the binding in XKeymacs.

First, in VS make sure:
Window.Split
is bound to
Ctrl + F6
Then in XKeymacs config file, '.xkeymacs':
...\xkeymacs347\etc\English (United States).xkeymacs
add line:
(fset 'split-window-vertically [?\Ctrl+f6])
Then configure XKeymacs
Properties -> select 'devenv.exe' -> 'Advanced' tab -> under Category 'Original Command' -> 
should now see new command, 'split-window-vertically', in the list of commands
Under 'Press new shortcut key:', check 'Ctrl-X' -> in text field below it, press '2' -> click 'Assign' 
'Current keys:' list should now include 'Ctrl-X 2'. Now in VS, C-x 2 will run 'window split' command (as well as Ctrl + F6 the original bindings in VS).

Although I don't use splitting windows that often, it is useful on those rare occasions when I need to view one part of a file while editing another part of that same file.

VS Emacs Scheme:

N/A. Works as expected.


Remove other windows (remove split): C-x 1

XKeymacs Mode:

Continuing from the previous item, we need a way to remove the split window too. In VS, the same command 'Windows.Split' that initially splits the window also removes it. It toggles the two states.

Follow all of the same steps as descibed in the previous item for window split specifically adding the new mapping in .xkeymacs config file.

Now go back into XKeymacs to add an additional keybinding for the same 'window split' command:
XKeymacs Properties -> select 'devenv.exe' -> 'Advanced' tab -> Category 'Original Command' -> 
should now see (new) command, 'split-window-vertically', in the list of commands
under 'Press new shortcut key:, check 'Ctrl-X' -> in text field below it, press '1' -> click 'Assign' -> 
'Current keys:' list should now include 'Ctrl-X 1' along with 'Ctrl-X 2' added previously. Now in VS, C-x 1 will run 'window split' command (as well as Ctrl + F6 the original bindings in VS) to remove the window split.

VS Emacs Scheme:

N/A. Works as expected.


Select another window: C-x o

XKeymacs Mode:

This command is available once a window for a file has been split (see the two previous items). It allows one to move the cursor and focus back and forth between the two views.

In VS, check to see if
Window.NextSplitPane
is assign to
F6
If not, then set it as F6.

Then in XKeymacs config file, '.xkeymacs':
...\xkeymacs347\etc\English (United States).xkeymacs
add line:
(fset 'other-window [f6])

Then configure
XKeymacs Properties -> select 'devenv.exe' -> 'Advanced' tab  -> under Category 'Original Command',
should now see new command, 'other-window', in the list of commands
Under 'Press new shortcut key:', check 'Ctrl-X' -> in text field below it, press 'o' -> click 'Assign'
'Current keys:' list should now include 'Ctrl-X o'. Now in VS with XKeymacs, C-x o will run 'next split pane' command (as well as F6 the original keybinding in VS)

VS Emacs Scheme:

N/A. Works as expected.


Go to line: M-g g

XKeymacs Mode:

In VS, check to see if:
Edit.GoTo
is assign to
C-g
If not, then set it as C-g.

Then in XKeymacs config file, '.xkeymacs':
...\xkeymacs347\etc\English (United States).xkeymacs
add line:
(fset 'goto-line "\Ctrl+g")
Then configure
XKeymacs Properties -> select 'devenv.exe' -> 'Advanced' tab  -> under Category 'Original Command'  ->
should now see new command, 'goto-line', in the list of commands
Under 'Press new shortcut key:' -> in text field below it, press 'Alt + g' -> click 'Assign'
'Current keys:' list should now include 'Meta + G'.

However, sometimes this keybinding does not always work. Therefore, assign an alternate keybinding. Go back to
'Press new shortcut key:'  -> in text field below it, press 'Ctrl+Alt+g' -> click 'Assign'
'Current keys:' list should now include 'Ctrl+Meta+G' along with 'Meta+G' added previously.

In VS, C-g or C-M-g will run 'goto line' command.

VS Emacs Scheme:

N/A. Works as expected.


Delete from beginning of line to point: M-0 C-k

XKeymacs Mode:

N/A. Works as expected.

VS Emacs Scheme:

M-0 C-k kills from point (cursor) to the beginning of the current line. It is the opposite command of C-k which kills from point to the end of line. Unlike XKeymacs, the equivalent VS command, Edit.DeleteToBOL, removes all text to the start of the line which includes the non-blank spaces.

In VS assign:
Edit.DeleteToBOL
to
M-0 C-k


Open line above: C-M-Enter

XKeymacs Mode:

Emacs does not have a single command to insert a newline above the current line. To perform this requires calling multiple commands: C-a C-o. However, VS has a command, Edit.LineOpenAbove, that inserts a newline above regardless of your location on the current line. This behavior is reminiscent of VIM's 'O' command.

In VS assign:
Edit.LineOpenAbove 
to
C-M-Enter
VS also has the command, Edit.LineOpenBelow, that inserts a newline below the current one. It is automatically bound to Shift + Ctrl + Enter. This is similar to Emacs' C-o command but does not drag the rest of the text after the point down to the newline. Instead, this behaves like the 'o' command in VIM. Unfortunately, although a handy shorter command, I rarely use this VS command since I am accustomed to doing C-e C-m to achieve the same functionality.

VS Emacs Scheme:

Follow the same steps as XKeymacs mode.


Swap point and mark: C-x C-x

XKeymacs Mode:

Suprisingly, XKeymacs does not support this command. Therefore, in Visual Studio assign the keybindings to the equivalent 'swap anchor' command:
Edit.SwapAnchor
to
C-k C-a 
Then in XKeymacs config file, '.xkeymacs':
...\xkeymacs347\etc\English (United States).xkeymacs
add line:
(fset 'exchange-point-and-mark "\Ctrl+k\Ctrl+a")
Then configure
XKeymacs Properties -> select 'devenv.exe' -> 'Advanced' tab  -> under Category 'Original Command'  ->
should now see new command, 'exchange-point-and-mark', in the list of commands
Under 'Press new shortcut key:', check 'Ctrl-X' -> in text field below it, press 'C-x' -> click 'Assign'
'Current keys:' list should now include 'Ctrl-X Ctrl-X'.

VS Emacs Scheme:

N/A. Works as expected.


List buffer: C-x C-b

XKeymacs Mode:
The ReSharper command 'View Recent Files' (C-,) reminded me of Emacs' list-buffers command. Therefore, thought I might bind Emacs' key shortcuts to it too.

In XKeymacs config file, '.xkeymacs':
...\xkeymacs347\etc\English (United States).xkeymacs
add line:
(fset 'list-buffers "\Ctrl+,")
Then configure
XKeymacs Properties -> select 'devenv.exe' -> 'Advanced' tab  -> under Category 'Original Command'  ->
should now see new command, 'list-buffers', in the list of commands
Under 'Press new shortcut key:', check 'Ctrl-X' -> in text field below it, press 'C-b' -> click 'Assign'
'Current keys:' list should now include 'Ctrl-X Ctrl-B'.

This is helpful to those who first learned Emacs before using ReSharper. I still generally use C-, since it is more convenient and I've been using that ReSharper command shortcut for a long time. However, nice to have alternatives there for consistency.

VS Emacs Scheme:

Follow same steps as XKeymacs mode.


Back to indentation: M-m

XKeymacs Mode:

Although C-a does a reliable of job of moving from anywhere on the current line to the first indention (i.e. first non-space character on the line), I am in the habit of using M-m to do that in Emacs. For example, I use it frequently when coding in Python using Emacs (indentation being core to the Python language) so mapping the equivalent VS command to M-m provides further consistency for me.

In VS, assign:
Edit.LineStartAfterIndentation
to
M-m
VS Emacs Scheme:

Unlike XKeymacs, C-a does not move the point to the start of the first (non-blank) character in the line but instead moves it to the beginning of the line. Therefore, binding M-m to Edit.LineStartAfterIndentation is extremely useful. So, follow the steps described in XKeymacs mode.


Join Lines: M-^

XKeymacs Mode:

XKeymacs does not have this command nor does Visual Studio. I hadn't really gave much thought about it until answering this question, does Visual Studio 2010 not have a “join lines” keyboard shortcut?, on StackOverflow. Truthfully, I don't find myself needed this when coding in C# with ReSharper but now that I made the effort to create a macro then it will now be included as part of my general keybindings configuration.

Essentially create a macro named something like "JoinLines" and I recommend using the code from my original answer since it behaves more like the Emacs version. The subsequent updated answer for joining lines follows more of the VIM equivalent.

Once the VS macro is created then assign the keybindings:
Tools -> Options -> Environment -> Keyboard -> in text field for 'Show commands containing:', type "JoinLines" and the new macro command should display. 
then assign this command to
M-^ 
This approach opens the door to creating other VS macros for missing commands in VS and are found in Emacs. Currently, join lines is one so I need to keep this mind next time when I need to port over some Emacs function to VS.

VS Emacs Scheme:

Follow same steps as XKeymacs mode.

Tuesday, August 31, 2010

Unit Testing Perils

Adding unit tests to existing code is nowadays applauded for being progressive, almost borderline pedestrian, for most software development shops. This was not the case when I began writing automated unit tests several years ago. It now feels otherworldly to see greater acceptance of unit testing primarily because I'd greatly toned down my advocacy for it. This shift in attitude includes a (substantial) decrease practicing test driven development (TDD). Unit testing can not simply be applied on blind faith hoping to cure all of one's software ills.

Not long ago, I and other developers on a .NET software project were retroactively adding unit tests (no TDD) for recently produced C# code. Part of the process involved removing any cruft specifically code that was not being called by any other code. The motivation was to help increase code coverage by removing any untouched lines of code. We relied on the static analysis features of the Visual Studio plugin, ReSharper, to reveal these isolated areas of code. In ReSharper parlance, Find Usages handles the work of hunting down any dependencies for symbols and functions.

One of those areas ReSharper indicated that no usages found were for a few simple getter/setter properties of a class. This code was then confidently removed. However, it was later discovered that the removed code did indeed serve a purpose and was providing functionality to one of the GUI screens of the WinForms application. More specifically a few of the columns in a 'DataGridView' control that allowed editing no longer did so. They unexpectedly became read-only.

The GUI screens had no tests. The discovery was made via manual end-to-end testing. This 'DataGridView' control was bound to the properties of the class. It inferred from the properties whether they were getters, setters, or both. The 'Set' accessor of the properties were naively removed since the code we wrote did not seem to call it. The grid control however was binding to it and passing values to and from the properties. No setter accessors now meant the associated columns had become effectively non-editable.

Realizing our mistake we rolled back our original edits for that class and cautiously reviewed all other recent refactorings.

Joel Spolsky once stated that manual testing is all you need in developing quality software and that unit testing provides no notable value . Others taking the inevitable opposing view immediately went on the offensive denouncing his claims. Joel's view is more an over reaction to all the TDD zealots who, whether intentional or not, seem to be deemphasizing the value of old fashion manual testing. Meanwhile, the dissenting voices are manifesting as a fear that their do-no-wrong methodology (and possibly their identity) might possibly amount to nothing. Both views are too extreme and leaning one way or the other can cost you in other areas. You need to continually find and maintain a balance in testing and not become complacent with whatever approach you take.

Yes, integration-style tests might have helped in exercising and validating the correct behaviour in the UI but even that might give you a false sense of security. Manual testing does have its virtues. Without it, you might overlook the human elements of UI functionality, design, and usability. Just like it is an incorrect assumption that no compiler errors means your application is fully functional and ready for end-users.

Also, these were CRUD operations. In my experience they tend to be the least risky part of an application, least likely to be buggy, and the quickest to identify and fix. The cost of writing and maintaining these sorts of unit tests do not warrant their benefit. Is it really worth your time and effort chasing after an unrealistic 100% code coverage? You learn your lesson then you move on (part of continually defining the proper testing balance). Regardless, you should confirm that your seemingly harmless refactoring does not produce unwanted side effects. Unit tests help with that but not by themselves.

Putting the merits of unit testing aside for a moment, the inability to easily detect how the .NET framework is referencing and interacting with my code can be somewhat irritating. This datagrid binding issue is another one of those features in .NET where it does something behind the scenes on your behalf (automagically!) but it is not clear (at least not from a coding perspective) what and how it is doing it. I'd experienced this before when trying to implement paging using NHibernate in an ASP.NET GridView control and it was frustrating. Wait until the havoc WebMatrix, LightSwitch, and friends will unleash on the .NET community.

Monday, July 26, 2010

Debugging JavaScript memory leak in IE

I was recently working on one of the most difficult bugs in all of my years of programming. It involved a memory leak in IE8 caused by a couple of ASP.NET pages on a user's machine.

The first indication of the problem was the iexplore.exe process in the Windows Task Manager. Intermittently watching the 'Mem Usage' column on the 'Processes' tab, the memory usage reached over 2 gigabytes thereby significantly slowly down the user's machine. The rate of increase was about 9 MB every 30 seconds.

As with most web app bugs in IE, I checked to see if the problem was reproducible in Firefox. No leak. Next, I used two tools to help further identify the leaks: JavaScript Memory Leak Detector (IEJSLeaksDetector) and sIEve. Surprisingly, neither one indicated any memory leaks. This is when I knew this was not going to be easy troubleshooting much less fixing.

I tried running the app under IE7 compatibility view mode in IE8 but again no leak. Being skeptical of the reliability of this mode, I decided to try a true install of IE7 itself which required removing IE8 from the user's machine. Alas no leak. I also attempted from a different machine to connect to the web server running on that same user's machine to view the app (yes, one of the web app's features is to run as a local instance). Again no leak.

The problem web pages perform Ajax callbacks. Looking at the code, they were set to trigger the calls every 30 seconds. This was consistent with what was observed earlier with the rate of increase of memory usage. Naively, I thought could the ASP.NET Ajax Timer Control be broken?

I kept suspecting Microsoft's Ajax Timer Control which was helping to display a "Processing..." progress image to the user every 30 seconds. My ill-conceived rationale was that perhaps the code was using an old version of the Timer Control since the app was running on ASP.NET 2.0 and the code was originally written around the time when the ASP.NET AJAX framework was originally released.

Unfortunately, I temporarily fell under the spell of believing "Select is broken". This disillusion became painfully clear when I later confirmed that the specific Ajax framework was indeed the latest ASP.NET 3.5 web extensions for 2.0. Just to be sure, I created a standalone dummy web app with the same library that provides the Timer Control. Once again, as has been the pattern thus far: no memory leak.

More detailed information was needed. On the suggestion from another developer on the project, configured Task Manager with:
'Processes' tab -> 'View' -> 'Select Columns'
and added the following columns:
'Handles'
    'Threads'
    'USER Objects'
    'GDI Objects'  
Again, closely monitoring any changes, I noted that the GDI objects counts were increasing by 7~8 units every 30 seconds meaning this leak must somehow be graphics display related. Perhaps some image (or images) was not being removed or repeatedly added on each Ajax server request? (Possibly the aforementioned progress image?)

To further investigate the GDI objects findings, I used a few tools. Neither GDIUsage nor GDIObj provided any useful metrics (It's possible I might not have fully understood how to best use these.) However, GDIView allowed me to do snapshots of the memory usages of the GDI objects.

I manually copied the initial output displayed in GDIView and pasted that data into a text file. I subsequently waited until the data refreshed 30 seconds later and then copied that output into a separate text file. Finally, I performed a diff on the two files and it reconfirmed what was shown in Task Manager. The following text was the diff results:
Handle     Object  Kernel
  Type    Address  Extended Information
---------------------------------------------------------------  
0x86040059 Region 0xe2e68008 
0x3a0508e1 Bitmap 0xe45af558 Width: 1042, Height: 586 , Bits/Pixel: 32
0x29040972 Region 0xe55938d8 
0x3b040bb4 Region 0xe42f9868 
0x9a040bd1 Region 0xe1cd5738 
0xb3010bec DC 0xe3f9e9c8 
0x17300c6a Pen 0xe40dce88 Color: 0x02b0b0b0, Width: 0, Style: 0x00000000
0xe2050fb3 Bitmap 0xe2268840 Width: 1046, Height: 150 , Bits/Pixel: 16
0x133011fb Pen 0xe565c868 Color: 0x02b0b0b0, Width: 0, Style: 0x00000000
0x7004123c Region 0xe5685c18 
0x4e0415eb Region 0xe3031688 
0xc504172b Region 0xe183cdb8 
0x94041733 Region 0xe362f2b8 
0xae05180e Bitmap 0xe2c44840 Width: 1046, Height: 607 , Bits/Pixel: 16
0xfe01198b DC 0xe4c22008 
0x60011b7d DC 0xe28af008 

Clearly some bitmap was indeed being added repeatedly but the questions now were which one and why? The other developer helping out noted that the width of 1042 and height of 150 match the size of the web app within the browser. An important detail.

Recalling the purpose of the Ajax timer control was to display on both web pages a processing progress message and image (specifically a gif file), I decided to delve deeper into that area of the code. A 'progress' element containing the gif image is shown to the user via JavaScript. In that same JS function, an IFrame element is created and added to the 'Content' property of the 'progress' element. I noticed that the width and height of this IFrame was set to the document's height and width:
var progressIFrame = document.createElement("IFRAME");
    // ...
    progressIFrame.style.width = document.body.clientWidth;
    progressIFrame.style.height = document.body.clientHeight;
This was consistent with the results from the previously listed diff of the memory usage since the bitmap's dimensions were about the same size as the browser's viewport. Then, the very next line in the function struck me as strange:
progress.Content = progress.parentNode.insertBefore(progressIFrame, progress);
The return value of 'insertBefore' is a reference to the 'progressIFrame' element which it is then set to the 'progress' element's 'Content' property. Not only does it do this but it also adds it as a node sibling to the very same 'progress' element.

Why add the IFrame element to the DOM in two places? It was far from clear what the intent was for using the 'insertBefore' function if the IFrame element was already being added as part of the progress element itself?

Therefore, I changed it to directly set it and not bother with 'insertBefore':
progress.Content = progressIFrame;
and that stopped the memory leak!

Now, admittedly, I am not comfortably well-versed in JavaScript and this is one of those cases that I do not fully understand why the IE browser behaved the way it did in reaction to how the JavaScript is written.

Sometimes this is the outcome of debugging code (particularly when written by someone else). Although you come away learning some things you did not know before, you also might not know how or why something was broken to begin with or why the fix itself even worked.

Like writing code, debugging code is both a skill and art. However, it is certainly a different mindset.

Sunday, June 27, 2010

Project Euler solution # 1

I had an interest in doing some programming puzzles for the usual reasons: to practise and improve my logic skills, to explore new programming languages, and for simply to have...fun. The Python Challenge seemed appropriate when I started learning Python. I enjoyed doing the first few.

I then took a stab at one of the more popular puzzle websites, Project Euler (pronounced oil-er not you-ler which I incorrectly thought it to be.) This site not only encourages identifying efficient algorithms via your programming language of choice to solve the problems but strongly emphasizes math requiring more and more research as you advance to later problems.

Starting off with problem # 1:

Add all the natural numbers below one thousand that are multiples of 3 or 5.

Here is my first run, brute force attempt at the solution using Python:
divisors = [3, 5]
multiples = []
for i in range(1, 1000):
    del multiples[:]
    for divisor in divisors:
        if i % float(divisor) == 0:
            multiples.append(divisor)
    if multiples:
        print i,' is a multiple of ',', '.join([str(multiple) for multiple in multiples])

The earlier code solved the problem but, shortly after churning it out, I discovered that it did not offer the expected format of the answer. Therefore, re-worked the code to do so:
multiples = []
for i in range(1, 1000):
    if i % 3 == 0 or i % 5 == 0:
        multiples.append(i)

print sum(multiples)           

While this returns the correct value of 233168, the structure of the code could have some pythonic polish added to it. A dab of list comprehensions does the job:
print sum([x for x in range(1, 1000) if x % 3 == 0 or x % 5 ==0])

In the spirit of one reason why I'm doing these puzzles, here is a solution in C:
main()
{
  int sumOfMultiples = 0;
  int i;
  for(i = 1; i < 1000; i++)
    {
      if (i % 3 == 0 || i % 5 == 0){
          sumOfMultiples += i;         
      }
    }
  printf ("%i \n", sumOfMultiples);
}   

Monday, May 31, 2010

Cross-browser compatibility

My first true deep dive into heavy JavaScript programming was working on a project that required adding Firefox support for a web application that only targeted Internet Explorer. The web application was originally written for IE6 and therefore contained some hairy JavaScript.

I experienced firsthand the same rite of passage as millions of web developers around the world. Fortunately, adding support for Firefox also meant that the web app no longer needed to support IE6 (only IE7+) so fixing the JavaScript to be cross-browser compatible became a bit more reasonable and sane.

Now, some snippets collected for these changes in no particular order:

# 1

Replacing all references to the DOM Level 1 function
top.frames['myId']
, which gave Firefox much trouble, with the DOM Level 2 function:
document.getByElementId('myId')


# 2

Replace the function 'removeNode':
if (x)
{
    x.removeNode();
}
with a conditional check that uses the Firefox friendly function 'removeChild' if parentNode is defined (otherwise fallback on 'removeNode'):
if (x)
{                  
    if (x.parentNode) 
        x.parentNode.removeChild(x);  // Firefox                  
    else
        x.removeNode(); // IE
}

# 3

The 'innerText' property does not work in Firefox but it does in IE. Instead, Firefox does recognize 'textContent' serving the same purpose. Again, use another if-else statement checking if the target element exists:
function setText(elem, textValue)
{
    if (elem.textContent || elem.textContent == "")
    {
         elem.textContent = textValue; // Firefox
    }
    else 
    {
         elem.innerText = textValue; // IE
    }
}

# 4

Dot notation for defining functions is another area where JavaScript errors emerge in Firefox:

"...missing ( before formal parameters..."
function window.onDoSomething()
{
 // do some stuff
}
To fix is to swap around the 'function' keyword:
window.onDoSomething = function()
{
 // do some stuff
}

# 5

One of the web pages had a character that used the Webdings (TrueType dingbat) font for an expressive, functional symbol. It rendered incorrectly (and confusingly) in Firefox. Substituting the equivalent Unicode character resolved the discrepancy.


# 6

All AJAX calls involved the following IE6 object:
var xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
As mentioned, with no need for supporting IE6 (something web developers dream of someday being true for all the of internet) every instance of the previous line of code is fully replaced with:
var xmlHttp = new XMLHttpRequest();
Certainly, one of the more satisfying cross-browser changes.


# 7

Firefox does not support referencing global event objects specifically 'window.event' and when encounters JavaScript code that attempts to do so it responds with this error message:

window.event is not defined.

Instead, it is necessary to pass the event object as an argument via a function's parameter:

    function myFunction(e) // <-- add 'e' as a parameter for the global event object
    {
        if(!e) e = window.event // if e is undefined then set e using IE event object
        // other code
    }

    <button onclick="myFunction(event);">test events</button>

# 8

A web page had a file browser functionality to attach a file for upload to the server. The 'onclick' event handler for this element's tag and type
<input type="file" ...
was coded to be programmatically triggered. The reason for this was to allow for the user to type in and edit the free form text of the file path and then the JavaScript would create the 'input' and then fire the event on the user's behalf.

Firefox does not allow this requiring the user to manually click on the tag since the file path text is read-only and can not be edited. It is considered a potential security flaw hence the restriction. The code needed to be rewritten to have the user directly fire the event and open the file browser.


# 9

An html table on a page contained rows with hidden nested rows functioning as a tree-like grid. These top level rows when clicked toggled between the style of
display:none
when hiding its children rows and then used
display:block 
when showing the rows.

In Firefox, the rows do not align properly when made visible with 'block' display style. The premature solution was to replace 'block' with
display:table-row
which worked for both IE8 and Firefox.

However, I later discovered that this type of display was not supported in IE7. Instead, substituted the equivalent of no display style at all using empty string
rowObject.style.display = ''
to show hidden rows. Apparently, each browser knows by default how to appropriately render the rows without the need to be specific in the html.


# 10

Consider a deeply nested event firing and then needing to prevent it from triggering other event handlers further up the DOM hierarchy. In IE,
window.event.cancelbubble
should take care of this. Firefox, of course, does not recognize this command. Instead, one must use the
event.stopPropagation
function to exercise the same control over the scope of an event.

To ensure coverage across the different browsers, do this:
function doSomething(e)
{
 if (!e) var e = window.event;
 e.cancelBubble = true;
 if (e.stopPropagation) e.stopPropagation();
}

# 11

Some JavaScript code was not executing at all. No clear indications why the function was not defined. It turns out that using the term 'jscript' as part of the 'type' attribute in the 'script' tag:
<script language="javascript" type="text/jscript" ...
is , not surprisingly, recognized only in IE and not in Firefox. All instances of 'jscript' were replaced with 'javascript':
<script type="text/javascript" ...
This cross-browser issue caused so much grief for such a simple fix. I spent way too much time figuring it out. When I read:

"...Nevermind, I think I found it. I inherited the code and just noticed that the original programmer had specified JScript rather than Javascript as the script language..."

I glanced over to my aspx page and my eyes immediately saw that exact error. Unbelievable.


# 12

Another function not defined in Firefox but used in IE:
window.attachEvent
In Firefox, use this instead:
window.addEventListener
The cross-browser code might look like this:
eventName = 'load';

if (window.addEventListener) // Firefox
{
  window.addEventListener(eventName, myFunction, false);
} 
else if (window.attachEvent) // IE
{
  window.attachEvent('on' + eventName, myFunction);
}
(Note that IE requires the prefix "on" for the event name while Firefox does not.)

All of the above applies to IE's
window.detachEvent
For Firefox, use
window.removeEventListener


# 13

Some image icons when hovering over with the mouse were expected to show tooltip text. However, no tooltips shown in Firefox with the following:
<input type="image" disabled="disabled" text="Hi there"...
Instead, replaced the 'input' element tag with an 'img' element:
<img text="Hi there" src="disabled.gif"

# 14

An html table needed to be dynamically resized by changing it's style. The original IE-only code:
tableObject.style.left=400
    tableObject.style.top=400
No effect in Firefox (the size remained the same), so needed to explicitly add the unit of measurement "px":
tableObject.style.left=400 + "px"
    tableObject.style.top=400 + "px"
Also applies to 'height' and 'width':
tableObject.style.height="55px"
    tableObject.style.width="33px"


# 15
Dynamically adding some new html into a page relied on 'insertAdjacentHtml':
document.body.insertAdjacentHTML('AfterBegin', '<div>foo</div>')
Worthless in Firefox (at least until HTML5 is supported) so fall back on 'insertBefore':
elementHtml = '<div>foo</div>';

if (document.body.insertAdjacentHTML)
{
     document.body.insertAdjacentHTML('AfterBegin', elementHtml)
}
else
{
    element = document.createElement("div");
    element.innerHTML = elementHtml;
    document.body.parentNode.insertBefore(elem, document.body);    
}
(Orignally, used
document.body.insertBefore(element, document.body.childNodes[0])
but that seemed to cause the event (specifically the 'onload' event of an image) to fire repeatedly in Firefox so changed it to use the one listed above.)


# 16

The mouse's position was necessary to figure out where to render a dynamically injected image. In IE, to determine the X and Y coordinates relative to the web page document:
window.event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft
    window.event.clientY + document.body.scrollTop + document.documentElement.scrollTop
Functions 'client<X|Y>' tell you the "viewport" position of the mouse which is a smaller, overlapping portion of the entire document but not a true subset of it. To obtain the document's actual mouse position, you need to add to these position values the scroll values by using the other functions shown above. Specifically,
document.body.scroll<Left|Top>
are the older (i.e. quirksmode) DOM syntax to retrieve the scroll values while
document.documentElement.scroll<Left|Top>
are the more modern standard approach. Depending on the browser only one of these will have the actual value while the other will equal zero. Therefore, it's safer and relatively harmless to include both.

In stark contrast, Firefox simply uses these:
e.pageX
    e.pageY
For a comprehensive code snippet that works across most major modern browsers:
function doSomething(e) {
 var posx = 0;
 var posy = 0;
 if (!e) var e = window.event;
 if (e.pageX || e.pageY)  {
  posx = e.pageX;
  posy = e.pageY;
 }
 else if (e.clientX || e.clientY)  {
  posx = e.clientX + document.body.scrollLeft
   + document.documentElement.scrollLeft;
  posy = e.clientY + document.body.scrollTop
   + document.documentElement.scrollTop;
 }
 // posx and posy contain the mouse position relative to the document
 // Do something with this information
}


# 17

To cancel an event just for the local scope only but not stop the event from bubbling up to the rest of DOM tree, in IE set
e.returnValue
to false.

For Firefox, use:
e.preventDefault
Cross-browser function:
if(e.preventDefault)
  {
    e.preventDefault();    // Firefox
  } 
  else
  {
    e.returnValue = false;    // IE
  }

One last (thought) snippet

While extremely beneficial being exposed to JavaScript's historical client-side scripting messiness in different browsers, next time when faced with cross-browser quirkiness I'd use a library like jQuery for simplified and easier web development.

Friday, April 30, 2010

Running Mono C# REPL on Windows

Being a big fan of programming language REPLs and command-line consoles, I have awaited one for C# that I can easily install and comfortably use for lightweight validation of C# syntax and for exploring its language features. Originally, Snippet Compiler had filled that role and then replaced with LINQPad but neither one is a REPL.

Fortunately, Mono, the open source project for .NET and C# that offers cross OS platform support especially for Linux and Mac, does have an interactive shell (CsharpRepl) for evaluating C# statements and expressions. Since Mono also runs on Windows, I downloaded and installed the latest Mono release 2.6 on my Windows development machine.

Once installed, to run the C# REPL simply:

  1. Select Start ->; All Programs -> Mono 2.6.1 for Windows -> Mono-2.6.1 Command Prompt
  2. At the command prompt, type "csharp"

The first step just adds Mono's bin directory to your environment PATH for the current shell session. (Alternatively, you can navigate via the command line to the Mono bin directory and directly run the file, csharp.bat.)

The C# REPL works if used within the Windows shell, cmd.exe (a.k.a. "command prompt") but with some caveats. The first immediate one is the command prompt text "csharp >" is not displayed making it a bit disorienting to use. It's difficult to distinguish between the input and the output of your expressions. [Update: This bug was subsequently fixed and it is now available with the version 2.6.7 release.]

Another is no autocomplete functionality but this feature is only available in Mono's GUI command console, 'gsharp'. GSharp requires an additional install of the mono-tools package available on the Windows platform download page under the link named "Gtk# for .NET". Once installed, to launch gsharp:

  1. Start -> All Programs -> Mono 2.6.1 for Windows -> Mono-2.6.1 Command Prompt
  2. c:\> gsharp

To activate autocomplete, type in part of a word and then hit <TAB>. Sometimes auto-completing words is slow in gsharp particularly if it has to search a large set of libraries. For example, typing the text "using Sys" and then <TAB> causes hanging since 'System' is the most top level .NET lib.

I decided to stick with using gsharp (a.k.a. the "C# InteractiveBase Shell"?) over csharp plus cmd.exe combo not only because of the autocomplete feature but because it also does display a "csharp >" prompt.

With those two issues resolved in gsharp, I continued to explore how the csharp REPL performed and behaved. The most striking deficiency I then encountered was when typing a statement containing invalid syntax, it did not show any output results. This was surprising since it goes against what I consider to be one of the hallmarks of a good REPL: immediate feedback not just on command/code that evaluated successfully but on things that failed to evaluate properly. Strange the lack of output...almost as if it was missing the 'Print' in REPL.

With continued use, I noticed in the examples found in the Mono REPL documentation that each expression or statement requires the ";" character at the end of it to produce any visible output. Otherwise, it gets ignored. I was expecting the same behavior found in the Visual Studio's Immediate Window where ";" is not always required. Not sure what the advantage of having to always type ";" (other than as a constant reminder that you are using a C based language in a REPL). Just seems like an extra unneeded keystroke.

However, reading more of the REPL docs, it implies multiple declarations can be made on a single line using ";" as a delimiter:

csharp> var a  = "why so many semi-colons?"; 5; "more stuff!";
"more stuff!"
csharp> a;
"why so many semi-colons?"
csharp>

All three statements get evaluated but only the last one ("more stuff!") is printed to the screen.

The docs also explicitly state the inverse: one declaration ending with ";" can be spread across multiple lines:
"...Statements and expression can take multiple lines, for example, consider this LINQ query that displays all the files modified in the /etc directory in the last week. The prompt changes from "csharp" to " >" to indicate that new input is expected..."
and
"...Multi-line input...If your code does not fit in a single line, you can enter expressions in multiple lines. The shell will not execute the code until a valid expression has been entered or a syntax error is flagged. A special prompt is shown to indicate that ics is waiting for input..."

Although the docs states that multi-line input is supported, it does not seem to be true of my current install on Windows. On Linux, I can do this:

csharp> var list = new int [] {1,2,3};
csharp> var b = from x in list
   >    where x > 1
   >    select x;
csharp> b;

On Windows, however, the special indented continuation prompt "  >" never appears when a new line is returned if the ";" character is not included. This is unfortunately a notable flaw in the REPL tool on the Windows platform.

In addition to the online documentation, another source describing the more common commands is available in the REPL itself. Just type "help;":
"Static methods:
Describe(obj)      - Describes the object's type
LoadPackage (pkg); - Loads the given Package (like -pkg:FILE)
LoadAssembly (ass) - Loads the given assembly (like -r:ASS)
ShowVars ();       - Shows defined local variables.
ShowUsing ();      - Show active using decltions.
Prompt             - The prompt used by the C# shell
ContinuationPrompt - The prompt for partial input
Time(() -> { })    - Times the specified code
quit;
help;
TabAtStartCompletes - Whether tab will complete even on emtpy lines
"
Of course, a couple of these commands exhibit some quirks. If type 'ShowUsing();' it does not display anything in the console although it is expected to do so (it behaves like this on Linux). After trying the command several times, I looked at the original command prompt window from which gsharp launched and saw the results of the command showing in there. The same was true with 'ShowVars()'. Recommend keeping the command prompt console in view while using gsharp to see any output piped outside of it. (The issue appears to been logged at the mono project as a bug.)

Perhaps to truly escape all of these OS specific limitations, I might be better off running Mono's REPL within a Linux VM on Windows. However, this approach negates the benefits of a cross-platform framework that Mono aspires to be.

Despite these minor difficulties, Mono's C# REPL has been a nice addition to my .NET development toolbox. It has proved useful when I needed a deeper understanding of how delegates and lexical closures behave in C# and when figuring out how to do list comprehensions in C# using List<T>.ConvertAll instead of LINQ. It provides a quick, frictionless way of observing and interacting with the functionalities of C# and the .NET libraries.

Tuesday, March 30, 2010

Database schema changes unit tested using TSQLUnit

How does one test the existence of a primary key (PK) constraint belonging to a table in a database? Simple, right? Just write a test that intentionally violates that constraint. One's initial impulse would be to write a test inspecting the data contained within the PK's table. This approach is sensible and can be viewed as the conventional state-based style of testing.

Let's try it. The following test using TSQLUnit attempts to insert in a table a new row with the same value for its primary key as another existing row's PK:
create procedure dbo.ut_SubProduct_PkConstraint
as
begin
    declare @failMessage        varchar(200),
            @err                int,
            @primaryKeyError    int

    set @primaryKeyError = 2627
           
    /* RUN TEST */
-- grab row already in table and try to re-insert it.
    insert into dbo.SubProduct    
        select top 1 sp.*
        from dbo.SubProduct sp
   
    set @err = @@error       

    /* ASSERT TEST */
    if  @err <> @primaryKeyError
        begin
            set @failMessage = 'PK constraint not defined.'
            exec tsu_failure @failMessage
        end
end
The above code will not work as a good test because error messages regarding the failure to insert a row with a duplicate PK will occur that can not be suppressed in TSQLUnit's test runner (as viewed in the 'Results' window in Sql Server Management Studio). (Even with some not-too-in-depth research, I could not find a means to hide or suppress these error messages using TSQL.)

Instead, it can be tested more cleanly using SQL Server's info schema views:
create procedure dbo.ut_Product_PrimaryKey
as
begin
    declare @failMessage        varchar(200),
            @tableName          varchar(40),
            @primaryKeyColumn   varchar(40)

    set @tableName           = 'Product'
    set @primaryKeyColumn    = 'ProductID'
           
    if not exists
    (
        select      c.table_name, c.column_name, c.data_type
        from        information_schema.columns c
            inner join information_schema.key_column_usage kcu
                    on c.table_name = kcu.table_name and c.column_name =
                       kcu.column_name
            inner join information_schema.table_constraints tc
                    on tc.table_name = kcu.table_name and tc.constraint_name =
                       kcu.constraint_name and tc.constraint_type = 'PRIMARY KEY'
        where       c.table_name = @tableName and kcu.column_name = @primaryKeyColumn
    )
    begin
        set @failMessage = 'PK constraint not defined for ''' + @tableName + '.' + @primaryKeyColumn + ''''
        exec tsu_failure @failMessage
    end
end
That's it. You now have a test that handles primary key constraints.

Of course, this is not the last and only time where primary keys will require testing. While the above sproc does a satisfactory job, it is not reusable for any other tables. Let's refactor it into a more generic "Assert" sproc in an xUnit style:
create procedure dbo.tsux_AssertPrimaryKeyExists
/* This is an extension to the TSQLUnit framework. */
(  
    @tableName            varchar(40),
    @keyColumn            varchar(40),   
    @failMessage          varchar(255)=null   
)
as
begin
    if not exists
    (
        select      c.table_name, c.column_name, c.data_type
        from        information_schema.columns c
            inner join information_schema.key_column_usage kcu
                    on c.table_name = kcu.table_name and c.column_name =
                       kcu.column_name
            inner join information_schema.table_constraints tc
                    on tc.table_name = kcu.table_name and tc.constraint_name =
                       kcu.constraint_name and tc.constraint_type = 'PRIMARY KEY'
        where       c.table_name = @tableName and kcu.column_name = @keyColumn
    )
    begin
        if @failMessage is null
            set @failMessage = ' PK constraint not defined for ''' + @tableName + '.' + @keyColumn + ''''
        exec tsu_failure @failMessage
    end
end
Your actual test becomes more compact and easier to understand:
create proc dbo.ut_Product_PrimaryKey
as 
begin
    exec dbo.tsux_AssertPrimaryKeyExists
        @tableName                  = 'Product',
        @primaryKeyColumn           = 'ProductID',
end
Any verification of pure schema changes such as the creation of new tables, columns, constraints, etc. via unit tests is better served using SQL Server's system tables and views to query the necessary meta information. This has proven to be more preferable than performing data centric state based tests (This technique reminds me a little of using reflection in .NET to do testing)

The earlier test for primary keys can be also applied to foreign key constraints as well. However, it requires some additional pieces to validate including the table and column being referenced. After (once again) finding the suitable tsql needed via an online search, here is the test:
create procedure dbo.tsux_AssertForeignKeyExists
/* This is an extension to the TSQLUnit framework. */
(
    @tableName            varchar(40),
    @foreignKeyColumn     varchar(40),
    @referenceTable       varchar(40),
    @referenceColumn      varchar(40),   
    @failMessage          varchar(255)=null   
)
as
begin
    if not exists
    (
        /*
            This is modified version of the tsql query used to retrieve foreign key info
            courtesy of:
                http://www.experts-exchange.com/Microsoft/Development/MS-SQL-Server/Q_22952666.html
        */

        select
            object_name(fkeyid)     as TableName,
            a.name                  as FKColumn,
            object_name(constid)    as FKConstraint,
            object_name(rkeyid)     as ReferenceTable,
            b.name                  as ReferencedColumn
        from sysforeignkeys f
            inner join syscolumns a on a.id = f.fkeyid and a.colid = f.fkey
            inner join syscolumns b on b.id = f.rkeyid and b.colid = f.rkey
        where
            fkeyid                        = object_id( @tableName )
            and a.name                    = @foreignKeyColumn
            and object_name(rkeyid)       = @referenceTable
            and b.name                    = @referenceColumn
    )
        begin
            set @failMessage = 'FOREIGN KEY does not exist for ''' + @tableName + '.' + @foreignKeyColumn  +  ''''
            exec tsu_failure @failMessage
        end
end
Now the new unit test would plainly look like this:
create procedure dbo.ut_Product_ForeignKeys
as
begin
    exec dbo.tsux_AssertForeignKeyExists
        @tableName            ='Product',
        @foreignKeyColumn     ='CategoryID',
        @referenceTable       ='Category',
        @referenceColumn      ='CategoryID'   

end
Database Testing: How to Regression Test a Relational Database, which details areas of any database that should be tested, had been an influence on developing these types of data definition language (DDL) tests. As an example, referential integrity is mentioned as being important area to test. On the surface, it seems a bit overkill to set up tests for PKs and FKs. However, even superfically minor data errors can be costly.

I was once tasked with expanding the size of a core primary key column that had multiple dependencies to other tables (including views and sprocs). As expected, to make the change required temporarily dropping the PK and FK constraints on those other tables and then add them back after applying the change.

Herein lies the risk. What if the "adding back" part was accidentally forgotten and not included in the change script? What if it was temporarily commented out with the intention to uncomment it later but overlooked? Allowing a deficient, regression-inducing script to rollout into a live production environment would be poor software development.

What automated unit tests provide in this situation is the insurance and safety net that the constraints are less likely to be missed or forgotten. They enforce the existence of those key constraints and firmly establish them as requirements for the database. It further instills greater confidence to make these sorts of changes by providing immediate feedback during development (and not much later) if the constraints are not set.

Another situation where unit testing using meta data came in handy was increasing the data type length of a column. Initially, when the size of varchar for a few columns needed to increase, I had some data heavy tests performing row insertions. These tests were fragile since they'd break the TSQLUnit test runner itself if a test inserted data larger than the expected size. Instead, I created a generic assert stored procedure that used the system sproc, 'COL_LENGTH':
create procedure dbo.tsux_AssertColumnLength
/* This is an extension to the TSQLUnit framework. */
(
    @tableName            varchar(40),
    @columnName           varchar(40),
    @expectedLength       smallint,
    @failMessage          varchar(200)=null
)
as
begin
    declare @actualLength        smallint

    select @actualLength = COL_LENGTH(@tableName, @columnName)

    if @expectedLength != @actualLength
        begin           
            set @failMessage = 'Column length for ''' + @tableName + '.' + @columnName  +  ''' does not match expected value.'
            exec tsu_failure @failMessage
            print 'Expected: '    + cast(@expectedLength as varchar(3))
            print 'Actual: '    + cast(@actualLength as varchar(3))
        end
end

Again, reusable and reliable code which avoids relying on sql compiler errors to indicate test failure.

Other examples of generic asserts for columns aside from length:

* tsux_AssertColumnExists
* tsux_AssertColumnDataType

Also, some other areas using test assertions:

* permissions on an object (quite important and often overlooked until too late)
* stored procedure parameter lengths
* existence of tables, views, and other similar database objects
* schemabinding on views

What's more is that these types of tests can be easily code generated. For example, if database changes included adding new columns, then unit tests can be generated by extracting the columns' meta data (e.g. name, datatype, length, etc.) as defined in a sql script (or even from an xml file or spreadsheet). The same can be done with existing data objects and structures requiring DDL changes but the meta data can be pulled from the database's system tables/views. In this situation, you gain some automatic test coverage for your current schema before attacking it with alterations.

Not sure if any of the techniques detailed earlier could be applied to check constraints (e.g. inserted/updated datetime value should not be greater than today's date, etc.). Perhaps, check constratins can be sufficiently managed with simple, direct unit tests using data rather than using meta data. (Although it could be argued that the logic for most check constraints should exist in the application code and not in the database. However, in practise, this is not always the case.) For now, without an immediate need, it will remain speculative.

This is likely my last post on TSQLUnit. In the future, my data access tests will probably be created in and executed from the application code rather than on the SQL Server side. However, if I do find myself in a scenario where database-only unit tests are needed, I'd probably try out T.S.T. the T-SQL Test Tool since it has built-in assert functions.