[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs     diff=csharp\n*.sln    merge=union\n*.csproj merge=union\n*.vbproj merge=union\n*.fsproj merge=union\n*.dbproj merge=union\n\n# Standard to msysgit\n*.doc\t diff=astextplain\n*.DOC\t diff=astextplain\n*.docx diff=astextplain\n*.DOCX diff=astextplain\n*.dot  diff=astextplain\n*.DOT  diff=astextplain\n*.pdf  diff=astextplain\n*.PDF\t diff=astextplain\n*.rtf\t diff=astextplain\n*.RTF\t diff=astextplain\n\n*.sh text eol=lf\n*.fs text eol=lf\nMakefile.orig text eol=lf\nconfigure.sh text eol=lf\n"
  },
  {
    "path": ".gitignore",
    "content": "# F#\n[Bb]in/\n[Oo]bj/\n.fake/\nrepository/*\n*.suo\n*.pidb\n*.userprefs\n*.GhostDoc.xml\n*.user\n*.dll\n*.pdb\n*.cache\n*.swp\n*.swo\n*.swn\n*.pyc\n*.orig\n=======\n*~\npack/*\n\n.DS_Store\n\n/packages\nXSVim/any\n\n.paket/paket.exe\n"
  },
  {
    "path": ".travis.yml",
    "content": "﻿language: csharp\nos: osx\nmono: latest\nsolution: XSVim.sln\ninstall:\n- nuget restore XSVim.sln\n- wget https://download.visualstudio.microsoft.com/download/pr/29ca6bca-9226-4904-93f8-3678cb24c2ca/596a772e2d2a7d28cbfd570933817a70/visualstudioformac-8.4.8.2.dmg\nscript:\n- msbuild /p:Configuration=Release\n#- mono64 \"/Volumes/Visual Studio/Visual Studio.app/Contents/Resources/lib/monodevelop/bin/vstool.exe\"\n#  run-md-tests XSVim.Tests/bin/Release/XSVim.Tests.dll -labels\n- mono64 \"/Volumes/Visual Studio/Visual Studio.app/Contents/Resources/lib/monodevelop/bin/vstool.exe\"\n  setup pack XSVim/bin/Release/XSVim.dll\ndeploy:\n  provider: releases\n  api_key:\n    secure: GMgK73gqQxvaMXXtgZTVypt2nTmmY/uNOFc3f6pHqe31nvLtDgdwRgaqGC4uFHK/YspWujMXkmdo0OplyWZarZcGTSPJYcJ9/k9bEY4uXDVbLAGve2n7qIyhngprd1Mk9g+3zPEoi+xu7Ugc1y0GEFLy9Z3CXgr9A1AcEM49LsqpV2rqtjP8AjstmpVUgLXv5+6w5MlcJyoi0PulVE3B4N0I9EJoD8zfaTCNyq0YaydekR173bu5iuZsVuYkyqLsrKbWDJb67MiDG5pwW5vvcPIziPXf5TMXHRbnWZHdXmx5jlbV8k0DoaeChWh1gpMtr6gg1IuBCsFV65ackHqeZyyn6iKl/SwIUGBYkTadY4Hob5ns5LC/vRB2Rb32U7MRyP8eN8PpmHpVZL28DQq3PlqvehG3vjYe8AOZrRWY7e/2iu0lrpWxbYwf9X5CjTRhTPOUvMV0u7SgLMYdcf39iZoMwQuJTG3gv79ScZBlimisybEDl88T++XsfTI7LZOE4w91RnzjvhoHAUu2+R8Tpcj2wm0df/eOcFzIZqCTGgT+WefBB4yAo2Art3Ckk8MH/uLIEzRjsVeEYUFTN5xZ6N7YRhQB6JgyEEaP8NT7wZFX6xms+AwgITQEiTf29veyPKPFL0htvAaIlu7XFse7f4JZBtXNGfOja+T0b7nvlEI=\n  file_glob: true\n  file: XSVim*.mpack\n  skip_cleanup: true\n  on:\n    tags: true\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2016 Jason Imison\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# XSVim [![Gitter](https://badges.gitter.im/XSVim/Lobby.svg)](https://gitter.im/XSVim/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/nosami/XSVim.svg?branch=7.4)](https://travis-ci.org/nosami/XSVim)\n\n# This addin is obsolete\n\nThis extension only works for the older editor. For VSMac 8.4, you should install VsVim instead ![VsVim installation from the Gallery](https://user-images.githubusercontent.com/667194/71757513-71efdc00-2e8e-11ea-898d-167d5d40cb17.png) as VsVim works on the new editor.\n\nSome file types (e.g. F#) are still currently using the old editor in VSMac. This addin will still work for those file types while the transition is made to the new editor.\n\n# Installation\n\nInteract with Visual Studio for Mac as follows:\n\n```\nVisual Studio -> Extensions -> Gallery -> IDE Extensions -> \"VIM\" -> Install\n```\n\nThen close the current document that you are working on and open a new document to activate the plugin.\n\n## 8.1 New Editor\n\nUnfortunately, this addin does not work with the new editor that was made default in 8.1. To use this addin, make sure that the old editor is in use.\n\n![image](https://user-images.githubusercontent.com/667194/59626372-9de68280-9133-11e9-9fbe-035553d7042e.png)\n\nAlternatively, I have been working on making VsVim work for the new editor. If you want to try this out, please follow the instructions [here](https://github.com/VsVim/VsVim/pull/2733#issuecomment-538998555)\n\n# What works?\n\nMost Vim commands should work. If you see something that doesn't work, please file an issue. There's a good chance that I just don't know about it.\n\n# What doesn't work\n\n- Vim split windows. XSVim uses VS for Mac's side by side mode to emulate this, but it's only possible to have 2 vertical split windows. `<C-w>s` and `<C-w>v` both switch to side by side mode.\n- Visual block mode works for most tasks, but there are some differences in the way that VS handles virtual spacing at the end of lines.\n- Selecting text with the mouse or using cmd+arrow keys doesn't switch to Visual mode\n- No leader key support or configurable key bindings.\n\n# Why don't the control keys work?\n\nSome Vim keybindings (such as Ctrl-F, Ctrl-D etc) conflict with VS's own built in keybindings. However, there is a keybinding scheme included that you may apply if you want (Visual Studio + Vim)\n\n![image](https://user-images.githubusercontent.com/667194/37340194-39775566-26b5-11e8-9119-58d171aa9a01.png)\n\n# Extras\n\n- `gd` - Goto declaration\n- `gu` - Find usages\n- `gb` - Go to base symbol\n- `gh` - Show tooltip at current caret location (`G`o `H`over)\n- `hjkl` support on the Solution Explorer pad and Test Explorer pad. Pressing `<esc>` on these will switch focus back to the last editor window. `jk` support on the Search Results pad.\n- Goto Pad shortcuts start with `gp`\n  - `gps` - Go to solution explorer \n  - `gpc` - Go to class pad\n  - `gpe` - Go to error list pad\n  - `gpt` - Go to Task List pad\n  - `gpp` - Go to Property pad\n  - `gpo` - Go to document outline pad\n  - `gpb` - Go to breakpoint pad\n  - `gpl` - Go to locals pad\n  - `gpw` - Go to watch pad\n  - `gpi` - Go to immediate pad\n  - `gpn` - Go to F# Interactive pad\n  - `gpf` - When there is only one search results pad, go to it\n  - `gpf1` - When there is more than one search results pad, go to the 1st\n  - `gpf2` - When there is more than one search results pad, go to the 2nd....etc.\n  - `gpdt` - Go to debugger threads pad\n  - `gpds` - Go to debugger stack trace pad\n  - `gput` - Go to unit test pad\n  - `gpur` - Go to unit test results pad\n- Insert mode escape binding. See example screenshot to see how to configure `jj` to escape when in insert mode.\n\n![Insert mode escape screenshot](screenshots/InsertModeMapping.png)\n# Looking for the latest release?\n\nCheck the [release page](https://github.com/nosami/XSVim/releases) as there is usually a more recent version of the addin here than on the Visual Studio for Mac feed. Grab the .mpack file and install it via Visual Studio -> Extensions -> Install from file\n\n# Support & Contributions\n\nJump in our [Gitter channel](https://gitter.im/XSVim/Lobby) and introduce yourself. \n\n# With thanks to\n\n- @shirshov\n- @mdizzy\n- @tdfacer\n\n"
  },
  {
    "path": "XSVim/Addin.fs",
    "content": "﻿namespace XSVim\n\nopen System\nopen System.Collections.Generic\nopen MonoDevelop.Components.Commands\nopen MonoDevelop.Core\nopen MonoDevelop.Ide\nopen MonoDevelop.Ide.Editor\nopen MonoDevelop.Ide.Editor.Extension\nopen MonoDevelop.Ide.FindInFiles\nopen Reflection\n\nmodule Subscriptions =\n    let textChanged (editor:TextEditor) (changes: Text.TextChangeEventArgs) =\n        for change in changes.TextChanges do\n            if change.RemovalLength > 0 then\n                let state = Vim.editorStates.[editor.FileName]\n                let actions =\n                    [ yield! state.lastAction\n                      for _i in 1..change.RemovalLength do\n                          yield (typeChar VimKey.Backspace) ]\n\n                let newState = { state with lastAction = actions }\n                Vim.editorStates.[editor.FileName] <- newState\n\n            if change.Offset + change.InsertionLength = editor.CaretOffset then\n                let state = Vim.editorStates.[editor.FileName]\n                let typedChars =\n                    [ for c in change.InsertedText.Text do\n                        yield typeChar (Key c) ]\n                let vimState = \n                   { state with lastAction = state.lastAction @ typedChars }\n                Vim.editorStates.[editor.FileName] <- vimState\n\ntype XSVim() as this =\n    inherit TextEditorExtension()\n\n    let mutable disposables : IDisposable list = []\n    let mutable processingKey = false\n    let mutable config = Config.Default\n    static let searchPads = HashSet<string>() \n    let initConfig() =\n        let keyboardMapping =  match SettingsPanel.KeyboardLayout() with\n                                         | \"Colemak\" -> Colemak\n                                         | \"Dvorak\" -> Dvorak\n                                         | _ -> Qwerty\n        let mapping = SettingsPanel.InsertModeEscapeMapping()\n        if mapping.Length = 2 then\n            config <- { insertModeEscapeKey =\n                            {\n                                insertModeEscapeKey1 = string mapping.[0]\n                                insertModeEscapeKey2 = string mapping.[1]\n                                insertModeEscapeTimeout = SettingsPanel.InsertModeEscapeMappingTimeout()\n                            } |> Some\n                        keyboardLayout = keyboardMapping }\n        else\n            config <- { Config.Default with keyboardLayout = keyboardMapping }\n\n\n    let initializeSearchResultsPads() =\n        IdeApp.Workbench\n        |> Option.ofObj\n        |> Option.iter(fun workbench ->\n            workbench.Pads\n            |> Seq.iter(fun pad ->\n                try\n                    // fetching pad.Content can throw when there is an exception\n                    // when initializing the pad\n                    tryUnbox<SearchResultPad> pad.Content\n                    |> Option.iter(fun pad ->\n                        let padId = pad.Window.Id\n                        if not (searchPads.Contains padId) then\n                            searchPads.Add padId |> ignore\n                            let tree = pad.Control?nativeWidget?treeviewSearchResults\n                            padTreeViews.initialize tree)\n                with\n                | _ -> ()))\n\n    let ctrl c =\n        KeyDescriptor.FromGtk(Enum.Parse(typeof<Gdk.Key>, c) :?> Gdk.Key, char c, Gdk.ModifierType.ControlMask)\n        |> this.KeyPress\n\n    let mutable fileName = FilePath.Empty\n\n    member x.State\n        with get() = Vim.editorStates.[fileName]\n        and set(value) = Vim.editorStates.[fileName] <- value\n\n\n    override x.IsValidInContext documentContext =\n        documentContext.Name <> \"__FSI__.fs\" && documentContext.Name <> \"__FSI__.fsx\"\n\n    override x.Initialize() =\n        treeViewPads.initialize()\n        x.Editor.FocusLost.Add(fun _ -> initializeSearchResultsPads())\n        fileName <- x.Editor.FileName.FullPath\n        LoggingService.LogDebug(\"XSVim initializing - \" + string fileName)\n        initConfig()\n        let editor = x.Editor\n\n        let state =\n            match Vim.getCaretMode editor with\n            | Insert -> { VimState.Default with mode = InsertMode }\n            | Block -> VimState.Default\n\n        let initialState = Vim.switchToNormalMode editor state\n\n        if not (Vim.editorStates.ContainsKey fileName) then\n\n            Vim.editorStates.Add(fileName, initialState)\n            editor.GrabFocus()\n            let caretChanged =\n                editor.CaretPositionChanged.Subscribe\n                    (fun _e ->\n                        if not processingKey then // only interested in mouse clicks\n                            let line = editor.GetLine editor.CaretLine\n                            if line.Length > 0 && editor.CaretColumn >= line.LengthIncludingDelimiter then\n                                editor.CaretOffset <- editor.CaretOffset - 1)\n\n            let documentClosed =\n                IdeApp.Workbench |> Option.ofObj\n                |> Option.map(fun workbench ->\n                    workbench.DocumentClosed.Subscribe\n                        (fun e -> let documentName = e.Document.FileName\n                                  if Vim.editorStates.ContainsKey documentName then\n                                      Vim.editorStates.Remove documentName |> ignore))\n\n            let textChanged = editor.TextChanged.Subscribe(fun changes -> Subscriptions.textChanged editor changes)\n\n            let propertyChanged =\n                PropertyService.PropertyChanged.Subscribe (fun _ -> initConfig())\n\n            let focusLost =\n                editor.FocusLost.Subscribe\n                    (fun _ ->\n                        match x.State.mode with\n                        | ExMode _ ->\n                            x.State <- Vim.switchToNormalMode x.Editor x.State\n                            IdeApp.Workbench.StatusBar.ShowReady()\n                        | _ -> ())\n\n            disposables <- [ yield caretChanged\n                             if documentClosed.IsSome then\n                                yield documentClosed.Value\n                             yield propertyChanged\n                             yield textChanged\n                             yield focusLost ]\n\n    override x.KeyPress descriptor =\n        match descriptor.ModifierKeys with\n        | ModifierKeys.Control\n        | ModifierKeys.Command when descriptor.KeyChar = 'z' ->\n            // cmd-z uses the vim undo group\n            x.State.undoGroup |> Option.iter(fun d -> d.Dispose())\n            EditActions.Undo x.Editor\n            x.Editor.ClearSelection()\n            false\n        | ModifierKeys.Command when descriptor.KeyChar <> 'z' && descriptor.KeyChar <> 'r' -> false\n        | _ ->\n            let oldState = x.State\n\n            processingKey <- true\n            let newState, handledKeyPress = Vim.handleKeyPress x.State descriptor x.Editor config\n            processingKey <- false\n\n            match newState.statusMessage, newState.macro with\n            | Some m, None -> IdeApp.Workbench.StatusBar.ShowMessage m\n            | Some m, Some _ -> IdeApp.Workbench.StatusBar.ShowMessage (m + \"recording\")\n            | None, Some _ -> IdeApp.Workbench.StatusBar.ShowMessage \"recording\"\n            | _ -> IdeApp.Workbench.StatusBar.ShowReady()\n\n            x.State <- newState\n            match oldState.mode, newState.mode, config.insertModeEscapeKey with\n            | InsertMode, InsertMode, _ when descriptor.ModifierKeys = ModifierKeys.Control && descriptor.KeyChar = 'n' ->\n                false // Hack: Ctrl-N seems to be hardwired inside VS somehow to Emacs' line down\n            | InsertMode, InsertMode, None ->\n                base.KeyPress descriptor\n            | InsertMode, InsertMode, Some escapeCombo when descriptor.KeyChar.ToString() <> escapeCombo.insertModeEscapeKey1 ->\n                base.KeyPress descriptor\n            | VisualMode, _, _ -> false\n            | _ -> not handledKeyPress\n\n    [<CommandUpdateHandler (\"MonoDevelop.Ide.Commands.EditCommands.Undo\")>]\n    // We handle cmd-z ourselves to use the vim undo stack\n    member x.CanUndo(ci:CommandInfo) = ci.Enabled <- false\n\n    [<CommandUpdateHandler (\"MonoDevelop.Ide.Commands.EditCommands.Rename\")>]\n    member x.Rename(ci:CommandInfo) =\n        ci.Enabled <- true\n        // dirty hack - use the command update handler to switch to insert mode\n        // before the inline rename kicks in\n        if x.State.mode <> InsertMode then\n            x.State <- Vim.switchToInsertMode x.Editor x.State false\n\n    // Command handlers for all keys that possibly conflict with\n    // out of the box key binding schemes.\n    [<CommandHandler (\"XSVim.HalfPageDown\")>]\n    member x.HalfPageDown() = ctrl \"d\"\n\n    [<CommandHandler (\"XSVim.PageDown\")>]\n    member x.PageDown() = ctrl \"f\"\n\n    [<CommandHandler (\"XSVim.PageUp\")>]\n    member x.PageUp() = ctrl \"b\"\n\n    [<CommandHandler (\"XSVim.FindFile\")>]\n    member x.FindFile() = ctrl \"p\"\n\n    [<CommandHandler (\"XSVim.DynamicAbbrev\")>]\n    member x.DynamicAbbrev() = ctrl \"n\"\n\n    [<CommandHandler (\"XSVim.NavigateBackwards\")>]\n    member x.NavigateBackwards() = ctrl \"o\"\n\n    [<CommandHandler (\"XSVim.NavigateForwards\")>]\n    member x.NavigateForwards() = ctrl \"i\"\n\n    [<CommandHandler (\"XSVim.IncrementNumber\")>]\n    member x.IncrementNumber() = ctrl \"x\"\n\n    [<CommandHandler (\"XSVim.DecrementNumber\")>]\n    member x.DecrementNumber() = ctrl \"a\"\n\n    [<CommandHandler (\"XSVim.Escape\")>]\n    member x.Escape() = ctrl \"c\"\n\n    override x.Dispose() =\n        Vim.editorStates.Remove(fileName) |> ignore;\n        base.Dispose()\n        disposables |> List.iter(fun d -> d.Dispose())\n"
  },
  {
    "path": "XSVim/Classes.fs",
    "content": "﻿namespace XSVim\nopen MonoDevelop.Core\nopen MonoDevelop.Core.Text\nopen MonoDevelop.Ide\nopen MonoDevelop.Ide.Editor\nopen MonoDevelop.Ide.Editor.Extension\n\ntype Marker(editor:TextEditor, name:string) =\n    let segment = TextSegment(editor.CaretOffset, 1)\n    // Create an invisible \"find usages\" marker. This is the only way to construct a TextSegmentMarker\n    // without reflection hacks. VS checks that the marker is a TextSegmentMarker\n    // https://github.com/mono/monodevelop/blob/61459958511d7ad4ea8debf4a59a77b1e98793fc/main/src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/SourceEditorView.cs#L2744\n    let marker = TextMarkerFactory.CreateUsageMarker(editor, Usage(segment, FindInFiles.ReferenceUsageType.Unknown))\n    do\n        marker.IsVisible <- false\n        editor.AddMarker marker\n    member x.Name = name\n    member x.FileName = string editor.FileName.FullPath\n    member x.Offset = marker.Offset\n    member x.TextSegmentMarker = marker\n    member x.Remove() =\n        try\n            editor.RemoveMarker marker |> ignore\n        with\n        | ex -> LoggingService.LogError (string ex)\n"
  },
  {
    "path": "XSVim/ExMode.fs",
    "content": "﻿namespace XSVim\nopen System\nopen System.Text.RegularExpressions\nopen Reflection\nopen MonoDevelop.Ide\nopen MonoDevelop.Ide.Commands\nopen MonoDevelop.Ide.Editor.Extension\n\nmodule exMode =\n    let getFirstCharAndRest (s:string) = s.[0], s.[1..]\n\n    let processCommand command =\n        let firstChar, rest = getFirstCharAndRest command\n        match firstChar, rest with\n        | '/', _ -> [ runOnce (IncrementalSearch rest) Nothing ]\n        | '?', _ -> [ runOnce (IncrementalSearchBackwards rest) Nothing ]\n        | _ -> wait\n\n    let save() = IdeApp.Workbench.ActiveDocument.Save() |> Async.AwaitTask\n\n    let (|DeleteBetweenMarks|_|) input =\n        let matches = Regex.Matches(input, \"'([a-z]),'([a-z])d\", RegexOptions.Compiled)\n        if matches.Count = 1 then \n            let m = matches.[0]\n            Some (m.Groups.[1].Value, m.Groups.[2].Value)\n        else\n            None\n\n    let (|DeleteLines|_|) input =\n        let matches = Regex.Matches(input, \"([\\d]+),([\\d]+)d\", RegexOptions.Compiled)\n        if matches.Count = 1 then \n            let m = matches.[0]\n            Some (int m.Groups.[1].Value, int m.Groups.[2].Value)\n        else\n            None\n\n    let (|Substitute|_|) input =\n        let matches = Regex.Matches(input, \"(.*)s/(.*)/(.*)\", RegexOptions.Compiled)\n        if matches.Count = 1 then \n            let m = matches.[0]\n            match m.Groups.[1].Value with\n            | \"%\" -> Some { find = m.Groups.[2].Value; replace = m.Groups.[3].Value; scope = Document }\n            | \"'<,'>\" -> Some { find = m.Groups.[2].Value; replace = m.Groups.[3].Value; scope = Selection }\n            | _ -> None\n        else\n            None\n\n\n    let processKey (state:VimState) (key:KeyDescriptor) =\n        let setMessage message = { state with statusMessage = message }\n        let normalMode = { state with statusMessage = None; mode = NormalMode }\n        match key.SpecialKey with\n        | SpecialKey.BackSpace ->\n            let message =\n                match state.statusMessage with\n                | Some msg ->\n                    let len = msg.Length\n                    msg.[0..len-2]\n                | None -> \"\"\n            if message.Length > 0 then\n                setMessage (Some message), processCommand message\n            else\n                normalMode, resetKeys\n        | SpecialKey.Return ->\n            match state.statusMessage with\n            | Some message ->\n                let firstChar, rest = getFirstCharAndRest message\n                let getSearchAction() = match state.searchAction with | Some action -> action | _ -> Move\n                let restIsNumeric, number = Int32.TryParse rest\n                // really bad parser. TODO: try and use https://github.com/jaredpar/VsVim/blob/447d980da9aa6c761238e39df9d2b64424643de1/Src/VimCore/Interpreter_Parser.fs\n                match firstChar with\n                | '/' ->\n                    { state with statusMessage = None; mode = NormalMode; lastSearch = Some (Jump (ToSearch rest)) }\n                    , [ runOnce (getSearchAction()) (Jump (ToSearch rest))]\n                | '?' ->\n                    { state with statusMessage = None; mode = NormalMode; lastSearch = Some (Jump (ToSearchBackwards rest)) }\n                    , [ runOnce (getSearchAction()) (Jump (ToSearchBackwards rest))]\n                | ':' when restIsNumeric ->\n                    { state with statusMessage = None; mode = NormalMode; }\n                    , [ runOnce Move (Jump (StartOfLineNumber number)) ]\n                | ':'  ->\n                    match rest with\n                    | \"q\" ->\n                        Window.closeTab()\n                        normalMode, resetKeys\n                    | \"q!\"  ->\n                        Window.forceCloseTab()\n                        normalMode, resetKeys\n                    | \"w\"\n                    | \"w!\"  ->\n                        async {\n                            do! save()\n                        } |> Async.StartImmediate\n                        normalMode, resetKeys\n                    | \"wa\"\n                    | \"wa!\"  ->\n                        async {\n                            dispatchCommand FileCommands.SaveAll\n                        } |> Async.StartImmediate\n                        normalMode, resetKeys\n                    | \"qa\"  ->\n                        async {\n                            dispatchCommand FileCommands.CloseAllFiles\n                        } |> Async.StartImmediate\n                        normalMode, resetKeys\n                    | \"qa!\"  ->\n                        IdeApp.Workbench.Documents\n                        |> Seq.iter(fun doc ->\n                            async {\n                                do! doc.Close true |> Async.AwaitTask |> Async.Ignore\n                            } |> Async.StartImmediate)\n                        normalMode, resetKeys\n                    | \"wq\"  ->\n                        async {\n                            do! save()\n                            dispatchCommand FileCommands.CloseFile\n                        } |> Async.StartImmediate\n                        normalMode, resetKeys\n                    | \"wq!\"  ->\n                        async {\n                            do! save()\n                            Window.forceCloseTab()\n                        } |> Async.StartImmediate\n                        normalMode, resetKeys\n                    | \"vs\"\n                    | \"vsp\"\n                    | \"vsplit\"\n                    | \"sp\"\n                    | \"split\" ->\n                        let notebooks = Window.getNotebooks()\n                        if notebooks.Length < 2 then\n                            dispatchCommand \"MonoDevelop.Ide.Commands.ViewCommands.SideBySideMode\"\n                        normalMode, resetKeys\n                    | DeleteBetweenMarks (startMarker, endMarker) ->\n                        let actions =\n                            [ runOnce Move (Jump (ToMark (startMarker, MarkerJumpType.StartOfLine)))\n                              runOnce DeleteWholeLines (Jump (ToMark (endMarker, MarkerJumpType.StartOfLine))) ]\n                        normalMode, actions\n                    | DeleteLines (startLine, endLine) ->\n                        let actions =\n                            [ runOnce Move (Jump (StartOfLineNumber startLine))\n                              runOnce DeleteWholeLines (Jump (StartOfLineNumber endLine)) ]\n                        normalMode, actions\n                    | Substitute substition ->\n                        match Substitute.substitute substition with\n                        | true -> normalMode, resetKeys\n                        | false -> state, resetKeys\n                    | _  ->\n                        { state with statusMessage = sprintf \"Could not parse :%s\" rest |> Some; mode = NormalMode; }\n                        , resetKeys\n                | _ -> normalMode, resetKeys\n            | _ -> normalMode, resetKeys\n        | _ ->\n            let message =\n                match state.statusMessage with\n                | Some msg -> sprintf \"%s%c\" msg key.KeyChar\n                | None -> string key.KeyChar\n\n            setMessage (Some message), processCommand message\n"
  },
  {
    "path": "XSVim/KeyBindingSchemeVim.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<scheme version=\"1.0\">\n    <!-- Vim keybinding scheme containing all the keys that\n         conflict with keybindings in the Visual Studio keybinding scheme-->\n    <binding command=\"MonoDevelop.Ide.Commands.TextEditorCommands.DeleteRightChar\" shortcut=\"\" />\n    <binding command=\"XSVim.HalfPageDown\" shortcut=\"Control+D\" />\n    <binding command=\"MonoDevelop.Ide.Commands.TextEditorCommands.LineUp\" shortcut=\"\" />\n    <binding command=\"XSVim.FindFile\" shortcut=\"Control+P\" />\n    <binding command=\"MonoDevelop.Ide.Commands.TextEditorCommands.CharRight\" shortcut=\"\" />\n    <binding command=\"XSVim.PageDown\" shortcut=\"Control+F\" />\n    <binding command=\"MonoDevelop.Ide.Commands.TextEditorCommands.CharLeft\" shortcut=\"\" />\n    <binding command=\"XSVim.PageUp\" shortcut=\"Control+B\" />\n    <binding command=\"MonoDevelop.Ide.Commands.TextEditorCommands.LineDown\" shortcut=\"\" />\n    <binding command=\"XSVim.DynamicAbbrev\" shortcut=\"Control+N\" />\n    <binding command=\"MonoDevelop.Ide.Commands.TextEditorCommands.InsertNewLinePreserveCaretPosition\" shortcut=\"\" />\n    <binding command=\"XSVim.NavigateBackwards\" shortcut=\"Control+O\" />\n    <binding command=\"MonoDevelop.Ide.CodeFormatting.CodeFormattingCommands.FormatBuffer\" shortcut=\"\" />\n    <binding command=\"XSVim.NavigateForwards\" shortcut=\"Control+I\" />\n    <binding command=\"MonoDevelop.Ide.Commands.TextEditorCommands.LineStart\" shortcut = \"Meta+Left\"/> <!-- removed ctrl-a -->\n    <binding command=\"XSVim.DecrementNumber\" shortcut=\"Control+A\" />\n    <binding command=\"XSVim.IncrementNumber\" shortcut=\"Control+X\" />\n    <binding command=\"XSVim.Escape\" shortcut=\"Escape Control+C Control+[\" />\n</scheme>"
  },
  {
    "path": "XSVim/Mapping.fs",
    "content": "﻿namespace XSVim\n\n[<AutoOpen>]\nmodule mapping =\n    let colemakToQwerty = function\n        | \"f\" -> \"e\"\n        | \"p\" -> \"r\"\n        | \"g\" -> \"t\"\n        | \"j\" -> \"y\"\n        | \"l\" -> \"u\"\n        | \"u\" -> \"i\"\n        | \"y\" -> \"o\"\n        | \";\" -> \"p\"\n        | \"r\" -> \"s\"\n        | \"s\" -> \"d\"\n        | \"t\" -> \"f\"\n        | \"d\" -> \"g\"\n        | \"n\" -> \"j\"\n        | \"e\" -> \"k\"\n        | \"i\" -> \"l\"\n        | \"o\" -> \";\"\n        | \"k\" -> \"n\"\n        | \"F\" -> \"E\"\n        | \"P\" -> \"R\"\n        | \"G\" -> \"T\"\n        | \"J\" -> \"Y\"\n        | \"L\" -> \"U\"\n        | \"U\" -> \"I\"\n        | \"Y\" -> \"O\"\n        | \":\" -> \"P\"\n        | \"R\" -> \"S\"\n        | \"S\" -> \"D\"\n        | \"T\" -> \"F\"\n        | \"D\" -> \"G\"\n        | \"N\" -> \"J\"\n        | \"E\" -> \"K\"\n        | \"I\" -> \"L\"\n        | \"O\" -> \":\"\n        | \"K\" -> \"N\"\n        | c -> c\n\n    let dvorakToQwerty = function\n        | \"[\" -> \"-\"\n        | \"]\" -> \"=\"\n        | \"'\" -> \"q\"\n        | \",\" -> \"w\"\n        | \".\" -> \"e\"\n        | \"p\" -> \"r\"\n        | \"y\" -> \"t\"\n        | \"f\" -> \"y\"\n        | \"g\" -> \"u\"\n        | \"c\" -> \"i\"\n        | \"r\" -> \"o\"\n        | \"l\" -> \"p\"\n        | \"/\" -> \"[\"\n        | \"=\" -> \"]\"\n        | \"o\" -> \"s\"\n        | \"e\" -> \"d\"\n        | \"u\" -> \"f\"\n        | \"i\" -> \"g\"\n        | \"d\" -> \"h\"\n        | \"h\" -> \"j\"\n        | \"t\" -> \"k\"\n        | \"n\" -> \"l\"\n        | \"s\" -> \";\"\n        | \"-\" -> \"'\"\n        | \";\" -> \"z\"\n        | \"q\" -> \"x\"\n        | \"j\" -> \"c\"\n        | \"k\" -> \"v\"\n        | \"x\" -> \"b\"\n        | \"b\" -> \"n\"\n        | \"w\" -> \",\"\n        | \"v\" -> \".\"\n        | \"z\" -> \"/\"\n        | \"{\" -> \"_\"\n        | \"}\" -> \"+\"\n        | \"\\\"\" -> \"Q\"\n        | \"<\" -> \"W\"\n        | \">\" -> \"E\"\n        | \"P\" -> \"R\"\n        | \"Y\" -> \"T\"\n        | \"F\" -> \"Y\"\n        | \"G\" -> \"U\"\n        | \"C\" -> \"I\"\n        | \"R\" -> \"O\"\n        | \"L\" -> \"P\"\n        | \"?\" -> \"{\"\n        | \"+\" -> \"}\"\n        | \"O\" -> \"S\"\n        | \"E\" -> \"D\"\n        | \"U\" -> \"F\"\n        | \"I\" -> \"G\"\n        | \"D\" -> \"H\"\n        | \"H\" -> \"J\"\n        | \"T\" -> \"K\"\n        | \"N\" -> \"L\"\n        | \"S\" -> \":\"\n        | \"_\" -> \"\\\"\"\n        | \":\" -> \"Z\"\n        | \"Q\" -> \"X\"\n        | \"J\" -> \"C\"\n        | \"K\" -> \"V\"\n        | \"X\" -> \"B\"\n        | \"B\" -> \"N\"\n        | \"M\" -> \"M\"\n        | \"W\" -> \"<\"\n        | \"V\" -> \">\"\n        | \"Z\" -> \"?\"\n        | c -> c\n\n    let remap layout key =\n        match layout with\n        | Colemak -> colemakToQwerty key\n        | Dvorak -> dvorakToQwerty key\n        | _ -> key\n"
  },
  {
    "path": "XSVim/PadTreeViews.fs",
    "content": "﻿namespace XSVim\n\nopen Gtk\nopen MonoDevelop.Ide.Gui.Components\n\nmodule padTreeViews =\n    let select (tree:TreeView) path =\n        let column = tree.Columns.[0]\n        tree.Selection.SelectPath path\n        tree.SetCursor(path, column, false)\n\n    let getSelectedPath (tree:TreeView) =\n        tree.Selection.GetSelectedRows().[0]\n\n    let moveDown tree =\n        let path = getSelectedPath tree\n        path.Next()\n        select tree path\n\n    let moveUp tree =\n        let path = getSelectedPath tree\n        path.Prev() |> ignore\n        select tree path\n\n    let initialize (tree:PadTreeView) =\n        let processKey (key:KeyPressEventArgs) =\n            match key.Event.Key with\n            | Gdk.Key.Escape ->\n                dispatchCommand \"MonoDevelop.Ide.Commands.ViewCommands.FocusCurrentDocument\"\n                key.RetVal <- false\n            | Gdk.Key.j ->\n                moveDown tree\n                key.RetVal <- true\n            | Gdk.Key.k ->\n                moveUp tree\n                key.RetVal <- true\n            | _ -> ()\n\n        tree.KeyPressEvent.Add processKey\n"
  },
  {
    "path": "XSVim/Properties/AddinInfo.fs",
    "content": "﻿namespace XSVim\n\nopen Mono.Addins\nopen MonoDevelop\n[<assembly:Addin (\n  \"XSVim\",\n  Namespace = \"XSVim\",\n  Version = version\n)>]\n\n[<assembly:AddinName (\"Vim\")>]\n[<assembly:AddinCategory (\"IDE extensions\")>]\n[<assembly:AddinDescription (\"Vim emulation layer for Xamarin Studio / Visual Studio for Mac.\")>]\n[<assembly:AddinUrl (\"https://github.com/nosami/XSVim\")>]\n[<assembly:AddinAuthor (\"jason\")>]\n[<assembly:AddinDependency (\"::MonoDevelop.Core\", \"8.1\")>]\n[<assembly:AddinDependency (\"::MonoDevelop.Ide\", \"8.1\")>]\n[<assembly:AddinDependency (\"::MonoDevelop.SourceEditor2\", \"8.1\")>]\n()\n"
  },
  {
    "path": "XSVim/Properties/AssemblyInfo.fs",
    "content": "﻿namespace XSVim\nopen System.Reflection\nopen System.Runtime.CompilerServices\n\n[<AutoOpen>]\nmodule AddinVersion =\n    [<Literal>]\n    let version = \"0.65.12.81\"\n\n[<assembly: AssemblyTitle(\"XSVim\")>]\n\n\n[<assembly: AssemblyVersion(version)>]\n\n//[<assembly: AssemblyDelaySign(false)>]\n//[<assembly: AssemblyKeyFile(\"\")>]\n\n()\n"
  },
  {
    "path": "XSVim/Properties/Manifest.addin.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ExtensionModel>\n    <Runtime>\n    </Runtime>\n    <Extension path=\"/MonoDevelop/Ide/TextEditorExtensions\">\n        <Class class=\"XSVim.XSVim\" />\n    </Extension>\n    <Extension path = \"/MonoDevelop/Ide/Commands\">\n        <Category _name = \"Vim\" id = \"Vim\" >\n            <!-- Override undo to use the vim undo stack -->\n            <Command id = \"MonoDevelop.Ide.Commands.EditCommands.Undo\"\n                _label = \"_Undo\"\n                icon = \"gtk-undo\"\n                _description = \"Undo (vim)\"\n                shortcut = \"Control|Z\"\n                macShortcut = \"Meta|Z\" />\n            <!-- Commands that may conflict with built in keybinding schemes -->\n            <Command id=\"XSVim.HalfPageDown\" _label=\"Half page down\" _description=\"Move half a page down\" shortcut=\"Control|D\" />\n            <Command id=\"XSVim.FindFile\" _label=\"Find file\" shortcut=\"Control|P\" />\n            <Command id=\"XSVim.PageDown\" _label=\"Page down\" shortcut=\"Control|F\" />\n            <Command id=\"XSVim.PageUp\" _label=\"Page up\" shortcut=\"Control|B\" />\n            <Command id=\"XSVim.DynamicAbbrev\" _label=\"Complete from file\" shortcut=\"Control|N\" />\n            <Command id=\"XSVim.NavigateBackwards\" _label=\"Navigate Backwards\" shortcut=\"Control|O\" />\n            <Command id=\"XSVim.NavigateForwards\" _label=\"Navigate Forwards\" shortcut=\"Control|I\" />\n            <Command id=\"XSVim.NavigateForwards\" _label=\"Navigate Forwards\" shortcut=\"Control|I\" />\n            <Command id=\"XSVim.IncrementNumber\" _label=\"Increment Number\" shortcut=\"Control|X\" />\n            <Command id=\"XSVim.DecrementNumber\" _label=\"Decrement Number\" shortcut=\"Control|A\" />\n            <Command id=\"XSVim.Escape\" _label=\"Return to normal mode\" shortcut=\"Escape Control|C Control|[\" />\n        </Category>\n    </Extension>\n    <Extension path=\"/MonoDevelop/Ide/GlobalOptionsDialog/Other\">\n        <Section id=\"VimSettings\" _label=\"Vim Settings\" class = \"XSVim.SettingsPanel\" icon=\"md-prefs-source\" />\n    </Extension>\n    <Extension path = \"/MonoDevelop/Ide/KeyBindingSchemes\">\n        <Scheme id=\"XSVim\" _name = \"Visual Studio + Vim\" resource=\"KeyBindingSchemeVim.xml\" forMac=\"true\" />\n    </Extension>\n</ExtensionModel>\n"
  },
  {
    "path": "XSVim/Reflection.fs",
    "content": "﻿namespace XSVim\nopen System\nopen System.Reflection\nopen Microsoft.FSharp.Reflection\n\nmodule Reflection =\n    // Various flags that specify what members can be called\n    // NOTE: Remove 'BindingFlags.NonPublic' if you want a version\n    // that can call only public methods of classes\n    let staticFlags = BindingFlags.NonPublic ||| BindingFlags.Public ||| BindingFlags.Static\n    let instanceFlags = BindingFlags.NonPublic ||| BindingFlags.Public ||| BindingFlags.Instance\n    let private ctorFlags = instanceFlags\n    let inline asMethodBase(a:#MethodBase) = a :> MethodBase\n\n    // The operator takes just instance and a name. Depending on how it is used\n    // it either calls method (when 'R is function) or accesses a property\n    let (?) (o:obj) name : 'R =\n      // The return type is a function, which means that we want to invoke a method\n      if FSharpType.IsFunction(typeof<'R>) then\n\n        // Get arguments (from a tuple) and their types\n        let argType, _resType = FSharpType.GetFunctionElements(typeof<'R>)\n        // Construct an F# function as the result (and cast it to the\n        // expected function type specified by 'R)\n        FSharpValue.MakeFunction(typeof<'R>, fun args ->\n\n          // We treat elements of a tuple passed as argument as a list of arguments\n          // When the 'o' object is 'System.Type', we call static methods\n          let methods, instance, args =\n            let args =\n              // If argument is unit, we treat it as no arguments,\n              // if it is not a tuple, we create singleton array,\n              // otherwise we get all elements of the tuple\n              if argType = typeof<unit> then [| |]\n              elif not(FSharpType.IsTuple(argType)) then [| args |]\n              else FSharpValue.GetTupleFields(args)\n\n            // Static member call (on value of type System.Type)?\n            if (typeof<System.Type>).IsAssignableFrom(o.GetType()) then\n                let methods = (unbox<Type> o).GetMethods(staticFlags) |> Array.map asMethodBase\n                let ctors = (unbox<Type> o).GetConstructors(ctorFlags) |> Array.map asMethodBase\n                Array.concat [ methods; ctors ], null, args\n            else\n              o.GetType().GetMethods(instanceFlags) |> Array.map asMethodBase, o, args\n\n          // A simple overload resolution based on the name and the number of parameters only\n          // TODO: This doesn't correctly handle multiple overloads with same parameter count\n          let methods =\n            [ for m in methods do\n                if m.Name = name && m.GetParameters().Length = args.Length then yield m ]\n\n          // If we find suitable method or constructor to call, do it!\n          match methods with\n          | [] -> failwithf \"No method '%s' with %d arguments found\" name args.Length\n          | _::_::_ -> failwithf \"Multiple methods '%s' with %d arguments found\" name args.Length\n          | [:? ConstructorInfo as c] -> c.Invoke(args)\n          | [ m ] -> m.Invoke(instance, args) ) |> unbox<'R>\n\n      else\n        // The result type is not an F# function, so we're getting a property\n        // When the 'o' object is 'System.Type', we access static properties\n        let typ, flags, instance =\n            if (typeof<System.Type>).IsAssignableFrom(o.GetType())\n                then unbox o, staticFlags, null\n            else o.GetType(), instanceFlags, o\n\n        // Find a property that we can call and get the value\n        let prop = typ.GetProperty(name, flags)\n        if prop = null && instance = null then\n          // The syntax can be also used to access nested types of a type\n          let nested = typ.Assembly.GetType(typ.FullName + \"+\" + name)\n          // Return nested type if we found one\n          if nested = null then\n              failwithf \"Property nested type '%s' not found in '%s'.\" name typ.Name\n          elif not ((typeof<'R>).IsAssignableFrom(typeof<System.Type>)) then\n              let rname = (typeof<'R>.Name)\n              failwithf \"Cannot return nested type '%s' as a type '%s'.\" nested.Name rname\n          else nested |> box |> unbox<'R>\n        else\n            if prop = null then\n                // if we didn't find a nested type then search for a field\n                let field = typ.GetField(name, flags)\n                if not (isNull field) then\n                    field.GetValue(o) |> unbox<'R>\n                else\n                    failwithf \"Property '%s' found, but doesn't have 'get' method.\" name\n            else\n                // Call property and return result if we found some\n                let meth = prop.GetGetMethod(true)\n                try meth.Invoke(instance, [| |]) |> unbox<'R>\n                with _ -> failwithf \"Failed to get value of '%s' property (of type '%s')\" name typ.Name\n\n    let (?<-) (this:obj) (property:string) (value:'Value) =\n      this.GetType().GetProperty(property).SetValue(this, value, null)\n"
  },
  {
    "path": "XSVim/SettingsPanel.fs",
    "content": "﻿namespace XSVim\nopen Gtk\nopen MonoDevelop.Components\nopen MonoDevelop.Core\nopen MonoDevelop.Ide.Gui.Dialogs\n\ntype SettingsWidget() as this =\n    inherit Gtk.Box()\n\n    let labelMapping =\n        new Label(\"Insert mode escape binding\",\n                  TooltipText = \"2 character combination to escape from insert mode (jj / hh / jk etc)\")\n\n    let escapeMappingEntry = new Entry(2)\n    let hbox = new HBox(false, 6)\n\n    let vbox = new VBox(true, 6)\n    let labelMappingTimeout =\n        new Label(\"Insert mode mapping timeout (ms)\",\n                  TooltipText = \"Timeout (in milliseconds) before key is registered as an insert mode key press\")\n\n    let escapeMappingEntryTimeout = new Entry(\"1000\")\n    let checkDisableAutoCompleteNormalMode =\n        new CheckButton(\"Disable intellisense in Normal mode. Use only if you are having issues with the intellisense drop down.\",\n                  TooltipText = \"Enabling this switches the setting Intellisense on keystroke globally when in Normal mode.\")\n\n    let labelKeyboardLayout =\n        new Label(\"Keyboard Layout\",\n                  TooltipText = \"Select an keyboard layout for when not in insert mode\")\n    let dropDownKeyboardLayout =\n        new ComboBox([| \"Qwerty\"; \"Colemak\"; \"Dvorak\" |]);\n\n    do\n        hbox.PackStart labelMapping\n        hbox.PackStart escapeMappingEntry\n\n        let hboxTimeout = new HBox(false, 6)\n        hboxTimeout.PackStart labelMappingTimeout\n        hboxTimeout.PackStart escapeMappingEntryTimeout\n\n        let hboxKeyboardLayout = new HBox(false, 6)\n        hboxKeyboardLayout.PackStart labelKeyboardLayout\n        hboxKeyboardLayout.PackStart dropDownKeyboardLayout\n\n        vbox.PackStart hbox\n        vbox.PackStart hboxTimeout\n        vbox.PackStart hboxKeyboardLayout\n        vbox.Add hbox\n        vbox.Add checkDisableAutoCompleteNormalMode\n        this.Add vbox\n        this.ShowAll()\n\n    member this.EscapeMappingEntry = escapeMappingEntry\n    member this.EscapeMappingEntryTimeout = escapeMappingEntryTimeout\n    member this.DisableAutoCompleteNormalMode = checkDisableAutoCompleteNormalMode\n    member this.KeyboardLayout = dropDownKeyboardLayout\n\ntype SettingsPanel() =\n    inherit OptionsPanel()\n    let widget = new SettingsWidget()\n    static let escapeMappingKey = \"VimEscapeMapping\"\n    static let escapeMappingKeyTimeout = \"VimEscapeMappingTimeout\"\n    static let disableAutoComplete = \"VimDisableAutoComplete\"\n    static let keyboardLayout = \"VimAlternateMapping\"\n\n    static member InsertModeEscapeMapping() =\n        PropertyService.Get(escapeMappingKey, \"\")\n\n    static member InsertModeEscapeMappingTimeout() =\n        PropertyService.Get(escapeMappingKeyTimeout, 1000)\n\n    static member AutoCompleteInNormalModeIsDisabled() =\n        PropertyService.Get(disableAutoComplete, false)\n\n    static member KeyboardLayout() =\n        PropertyService.Get(keyboardLayout, \"Qwerty\")\n\n    override x.Dispose() = widget.Dispose()\n\n    override x.CreatePanelWidget() =\n        widget.EscapeMappingEntry.Text <- SettingsPanel.InsertModeEscapeMapping()\n        widget.EscapeMappingEntryTimeout.Text <- SettingsPanel.InsertModeEscapeMappingTimeout() |> string\n        widget.DisableAutoCompleteNormalMode.Active <- SettingsPanel.AutoCompleteInNormalModeIsDisabled()\n        widget.KeyboardLayout.Active <- match SettingsPanel.KeyboardLayout() with\n                                                | \"Colemak\" -> 1\n                                                | \"Dvorak\" -> 2\n                                                | _ -> 0\n        widget.Show()\n        Control.op_Implicit widget\n\n    override x.ApplyChanges() =\n        match widget.EscapeMappingEntry.Text.Length with\n        | 2 | 0 ->\n            PropertyService.Set(escapeMappingKey, widget.EscapeMappingEntry.Text)\n        | _ ->\n            let md = new MessageDialog (null, DialogFlags.Modal ||| DialogFlags.DestroyWithParent, MessageType.Error, ButtonsType.Ok, \"Mapping must be empty (not used) or 2 characters.\")\n            md.Show()\n        PropertyService.Set(escapeMappingKeyTimeout, int widget.EscapeMappingEntryTimeout.Text)\n        PropertyService.Set(disableAutoComplete, widget.DisableAutoCompleteNormalMode.Active)\n        PropertyService.Set(keyboardLayout, widget.KeyboardLayout.ActiveText)\n"
  },
  {
    "path": "XSVim/SubstituteCommand.fs",
    "content": "﻿namespace XSVim\nopen System\nopen MonoDevelop.Core\nopen MonoDevelop.Core.ProgressMonitoring\nopen MonoDevelop.Ide\nopen MonoDevelop.Ide.FindInFiles\n\ntype SubstituteScope = Selection | Document\n\ntype Substitution = { find: string; replace: string; scope: SubstituteScope } \n\nmodule Substitute =\n  let substitute substitution =\n    let find = FindInFiles.FindReplace()\n    let options = FindInFiles.FilterOptions()\n    options.RegexSearch <- true\n    if not(find.ValidatePattern(options, substitution.find)) then\n        MessageService.ShowError (GettextCatalog.GetString (\"Search pattern is invalid\"));\n        false\n    elif not(find.ValidatePattern(options, substitution.replace)) then\n        MessageService.ShowError (GettextCatalog.GetString (\"Replace pattern is invalid\"));\n        false\n    else\n        use monitor =\n            match IdeApp.Workbench with\n            | null -> new ConsoleProgressMonitor() :> ProgressMonitor\n            | workbench -> \n                let monitor = workbench.ProgressMonitors.GetSearchProgressMonitor (true)\n                monitor.PathMode <- PathMode.Hidden\n                monitor :> ProgressMonitor\n        let scope =\n            match substitution.scope with\n            | Document -> DocumentScope() :> Scope\n            | Selection -> SelectionScope() :> Scope\n\n        find.FindAll(scope, monitor, substitution.find, substitution.replace, options, Threading.CancellationToken.None)\n        |> Seq.iter(fun res ->\n            match monitor with\n            | :? SearchProgressMonitor as mon ->\n                mon.ReportResult res\n            | _ -> printfn \"%A\" res)\n\n        true"
  },
  {
    "path": "XSVim/TreeViewPads.fs",
    "content": "﻿namespace XSVim\nopen System\nopen Gtk\nopen MonoDevelop.Ide\nopen MonoDevelop.Ide.Gui.Components\nopen MonoDevelop.Ide.Gui.Pads\nopen Reflection\n\n/// Set up TreeViewPads to accept hjkl keys\nmodule treeViewPads =\n    let getTreeViewPads() =\n        match IdeApp.Workbench |> Option.ofObj with\n        | Some workbench ->\n            workbench.Pads\n            |> List.ofSeq\n            |> List.choose(fun pad ->\n                try\n                    // fetching pad.Content can throw when there is an exception\n                    // when initializing the pad\n                    match pad.Content with\n                    | :? TreeViewPad as pad -> Some pad\n                    | _ -> None\n                with\n                | _ -> None)\n        | None -> List.empty\n\n    let select (tree:TreeView) path =\n        if tree.Selection.GetSelectedRows().Length > 0 then\n            tree.Selection.UnselectAll()\n        let column = tree.Columns.[0]\n        tree.Selection.SelectPath path\n        tree.SetCursor(path, column, false)\n\n    let getSelectedNode (pad:TreeViewPad) =\n        let (node:ITreeNavigator) = pad.TreeView?GetSelectedNode()\n        node\n\n    let getPath (tree:TreeView) =\n        tree.Selection.GetSelectedRows().[0]\n\n    let pathExists (store:TreeStore) path =\n        let iter : TreeIter ref = ref Unchecked.defaultof<_>\n        store.GetIter (iter, path)\n\n    let moveDown (tree:TreeView) (store:TreeStore) pad =\n        let selected = tree.Selection.GetSelectedRows()\n        let pathExists = pathExists store\n        if selected.Length > 0 then\n            let path = selected.[0]\n            path.Down()\n            let node = getSelectedNode pad\n            let res = pathExists path\n            if res && node.Expanded then\n                select tree path\n            else\n                let path = getPath tree\n                path.Next()\n                let res = pathExists path\n                if res then\n                    select tree path\n                else\n                    // parent, then sibling\n                    let path = getPath tree\n                    let _res = path.Up()\n                    let res = pathExists path\n                    if res then\n                        path.Next()\n                        let res = pathExists path\n                        if res then\n                            select tree path\n\n    let moveUp (tree:TreeView) (store:TreeStore) pad =\n        let selected = tree.Selection.GetSelectedRows()\n        let pathExists = pathExists store\n        if selected.Length > 0 then\n            let path = selected.[0]\n            let prev = path.Prev()\n            let res = pathExists path\n            if prev && res then\n                select tree path\n                let node = getSelectedNode pad\n                if node.Expanded then\n                    // move to last child\n                    let path = getPath tree\n                    path.Down()\n                    let rec moveNext lastPath =\n                        path.Next()\n                        let res = pathExists path\n                        if res then\n                            moveNext (path.Copy())\n                        else\n                            select tree lastPath\n\n                    moveNext (path.Copy())\n            else\n                let path = getPath tree\n                if path.Depth > 1 then\n                    let up = path.Up()\n                    let res = pathExists path\n                    if res && up then\n                        select tree path\n\n    let mutable initialized = false\n\n    /// Set up TreeViewPads to accept hjkl keys\n    let initialize() =\n        if not initialized then\n            initialized <- true\n            let errorPad = IdeApp.Workbench.Pads.ErrorsPad.Content\n            let errorPadTree = errorPad?view\n\n            if errorPadTree <> null then\n                padTreeViews.initialize errorPadTree\n\n            for pad in getTreeViewPads() do\n                let (tree:TreeView) = pad.TreeView?Tree\n                let (store:TreeStore) = pad.TreeView?Store\n\n                let processKey (key:KeyPressEventArgs) =\n                    match key.Event.Key with\n                    | Gdk.Key.Escape ->\n                        dispatchCommand \"MonoDevelop.Ide.Commands.ViewCommands.FocusCurrentDocument\"\n                        key.RetVal <- false\n                    | Gdk.Key.l ->\n                        pad.TreeView?ExpandCurrentItem()\n                        key.RetVal <- true\n                    | Gdk.Key.h ->\n                        pad.TreeView?CollapseCurrentItem()\n                        key.RetVal <- true\n                    | Gdk.Key.j ->\n                        moveDown tree store pad\n                        key.RetVal <- true\n                    | Gdk.Key.k ->\n                        moveUp tree store pad\n                        key.RetVal <- true\n                    | _ -> ()\n\n                tree.KeyPressEvent.Add processKey\n"
  },
  {
    "path": "XSVim/Types.fs",
    "content": "namespace XSVim\nopen System\nopen System.Threading\nopen System.Threading.Tasks\nopen MonoDevelop.Ide\nopen MonoDevelop.Ide.Editor\n\ntype BeforeOrAfter = Before | After | OverSelection\n\ntype CaretMode = Insert | Block\n\ntype Selection = {\n    linewise : bool\n    content: string\n}\n\ntype InsertModeEscapeKeyCombo = {\n    insertModeEscapeKey1: string\n    insertModeEscapeKey2: string\n    insertModeEscapeTimeout: int\n}\n\ntype KeyboardLayout = \n    | Qwerty\n    | Colemak\n    | Dvorak\n\ntype Config = {\n    insertModeEscapeKey: InsertModeEscapeKeyCombo option\n    keyboardLayout: KeyboardLayout\n} with\n    static member Default = { insertModeEscapeKey = None; keyboardLayout = Qwerty }\n\ntype Register =\n    | Register of char\n    | EmptyRegister\n\ntype VimMode =\n    | NormalMode\n    | VisualMode\n    | VisualBlockMode\n    | VisualLineMode\n    | InsertMode\n    | ReplaceMode\n    | ExMode of string // initial char typed to get to command line\n\n\ntype MoveRightBehaviour = StopAtEndOfLine | MoveToNextLineAtEnd | IncludeDelimiter\n\ntype MarkerJumpType = Offset | StartOfLine\n\ntype Jump =\n    | StartOfLineNumber of int\n    | StartOfDocument\n    | ToMark of string * MarkerJumpType\n    | ToSearch of string\n    | ToSearchBackwards of string\n    | SearchAgain\n    | SearchAgainBackwards\n    | HalfPageUp\n    | HalfPageDown\n    | PageUp\n    | PageDown\n    | LastLine\n    | FirstVisibleLine\n    | MiddleVisibleLine\n    | LastVisibleLine\n    | ParagraphForwards\n    | ParagraphBackwards\n\ntype VimKey =\n    | Esc\n    | Ret\n    | Left\n    | Down\n    | Up\n    | Right\n    | Backspace\n    | Delete\n    | Control of char\n    | Super of char\n    | Key of char\n    | EscapeKey of char // The key is part of an insert escape mapping\n\n    override x.ToString() =\n        match x with\n        | Esc -> \"<esc>\"\n        | Backspace -> \"<bs>\"\n        | Ret -> \"<ret>\"\n        | Delete -> \"<del>\"\n        | Control k -> sprintf \"<C-%c>\" k\n        | Super k -> sprintf \"<D-%c>\" k\n        | Down -> \"<down>\"\n        | Up -> \"<up>\"\n        | Left -> \"<left>\"\n        | Right -> \"<right>\"\n        | EscapeKey c -> string c\n        | Key c -> string c\n\ntype Repeat = int\ntype Offset = int\n\ntype TextObject =\n    | Jump of Jump\n    | Character of Repeat\n    | AWord\n    | InnerWord\n    | AWORD\n    | InnerWORD\n    | ASentence\n    | InnerSentence\n    | AParagraph\n    | InnerParagraph\n    | ABlock of string * string\n    | InnerBlock of string * string\n    | AQuotedBlock of char\n    | InnerQuotedBlock of char\n    | WholeLine\n    | WholeLineIncludingDelimiter\n    | ATag\n    | InnerTag\n    // motions\n    | Up\n    | Down\n    | Left\n    | Right of MoveRightBehaviour\n    | FirstNonWhitespace\n    | StartOfLine\n    | EndOfLine\n    | EndOfLineIncludingDelimiter\n    | ToCharInclusive of string\n    | ToCharInclusiveBackwards of string\n    | ToCharExclusive of string\n    | ToCharExclusiveBackwards of string\n    | WordForwards\n    | WORDForwards\n    | WordBackwards\n    | WORDBackwards\n    | ForwardToEndOfWord\n    | ForwardToEndOfWORD\n    | BackwardToEndOfWord\n    | BackwardToEndOfWORD\n    | Nothing\n    | CurrentLocation\n    | SelectedText\n    | SelectionStart\n    | MatchingBrace\n    | PrevUnmatchedBrace\n    | NextUnmatchedBrace\n    | PrevUnmatchedParen\n    | NextUnmatchedParen\n    | Offset of Offset\n    | Range of Offset * Offset\n\ntype CommandType =\n    | Move\n    | Visual\n    | Yank of Register\n    | Put of BeforeOrAfter\n    | Delete\n    | Substitute\n    | DeleteWholeLines\n    | DeleteLeft\n    | BlockInsert of BeforeOrAfter\n    | Change\n    | SwitchMode of VimMode\n    | Undo\n    | Redo\n    | JoinLines\n    | Dispatch of obj\n    | InsertLine of BeforeOrAfter\n    | ReplaceChar of string\n    | ResetKeys\n    | DoNothing\n    | Star of BeforeOrAfter\n    | ToggleCase\n    | InsertChar of VimKey\n    | IncrementNumber\n    | DecrementNumber\n    | SetMark of string\n    | IncrementalSearch of string\n    | IncrementalSearchBackwards of string\n    | SetSearchAction of CommandType\n    | MacroStart of char\n    | MacroEnd\n    | ReplayMacro of char\n    | NextTab\n    | PreviousTab\n    | Func of (unit -> unit)\n    | EditorFunc of (TextEditor -> unit)\n    | GotoPad of string\n    | DelayedFunc of (TextEditor -> unit) * int\n    | CancelFunc\n    | ChangeState of VimState\n    | Indent\n    | UnIndent\n    | EqualIndent\n    | SelectionOtherEnd\n\nand VimAction = {\n    repeat: int option\n    commandType: CommandType\n    textObject: TextObject\n}\n\nand Macro = Macro of char\n\nand VimSelection = { start: int; finish: int; mode: VimMode }\n\nand VimState = {\n    keys: VimKey list\n    mode: VimMode\n    visualStartOffset: int\n    lastSelection: VimSelection option\n    findCharCommand: VimAction option // f,F,t or T command to be repeated with ;\n    lastAction: VimAction list // used by . command to repeat the last action\n    desiredColumn: int option\n    undoGroup: IDisposable option\n    statusMessage: string option\n    searchAction: CommandType option // Delete, Change, Visual, Yank or Move when / or ? is pressed\n    lastSearch: TextObject option // Last term searched for with / or ?\n    macro: Macro option\n    insertModeCancellationTokenSource: CancellationTokenSource option\n} with\n    static member Default =\n        { keys=[]\n          mode=NormalMode\n          visualStartOffset=0\n          lastSelection=None\n          findCharCommand=None\n          lastAction=[]\n          desiredColumn=None\n          undoGroup=None\n          statusMessage=None\n          lastSearch=None\n          searchAction=None\n          macro=None\n          insertModeCancellationTokenSource=None }\n\n// shim for the build server which runs Mono 4.6.1\nmodule Option =\n    let inline defaultValue value =\n        function\n        | Some v -> v\n        | None -> value\n\n[<AutoOpen>]\nmodule commandHelpers =\n    let getCommand repeat commandType textObject =\n        { repeat=repeat; commandType=commandType; textObject=textObject }\n\n    let runOnce = getCommand (Some 1)\n    let typeChar c = runOnce (InsertChar c) Nothing\n    let wait = [ getCommand None DoNothing Nothing ]\n    let switchMode mode = runOnce (SwitchMode mode) Nothing\n    let dispatch command = runOnce (Dispatch command) Nothing\n    let resetKeys = [ runOnce ResetKeys Nothing ]\n    let func f = runOnce (Func f) Nothing\n    let delayedFunc f ms = runOnce (DelayedFunc (f, ms)) Nothing\n    let dispatchCommand command = IdeApp.CommandService.DispatchCommand command |> ignore\n    let gotoPad padId = runOnce (GotoPad padId) Nothing"
  },
  {
    "path": "XSVim/WindowManagement.fs",
    "content": "﻿namespace XSVim\nopen MonoDevelop.Core\nopen MonoDevelop.Ide\nopen MonoDevelop.Ide.Commands\nopen Reflection\n\nmodule Window =\n    type Notebook = {\n        isActive: bool\n        activeTab: int\n        tabs: string list\n    }\n\n    let dispatch command = IdeApp.CommandService.DispatchCommand command |> ignore\n\n    let openDocument fileName =\n        let (project:MonoDevelop.Projects.Project) = Unchecked.defaultof<_>\n        IdeApp.Workbench.OpenDocument(fileName |> FilePath, project).Wait(System.Threading.CancellationToken.None)\n\n    let switchToNotebook notebook =\n        openDocument notebook.tabs.[notebook.activeTab]\n\n    let forceClose() = IdeApp.Workbench.ActiveDocument.Close true |> Async.AwaitTask |> Async.Ignore\n\n    let getNotebooks() =\n        let (dockNotebookContainer: obj seq) = IdeApp.Workbench?RootWindow?TabControl?Container?GetNotebooks()\n        let getFiles notebook =\n            let tabs = notebook?Tabs\n            let tabs' = tabs :> seq<obj>\n            tabs' |> Seq.map(fun tab -> tab?Tooltip) |> List.ofSeq\n\n        dockNotebookContainer\n        |> Seq.map(fun notebook ->\n                       let firstChild = notebook?Children |> Array.tryHead\n                       let isActive =\n                           firstChild\n                           |> Option.map(fun tabstrip -> tabstrip?IsActiveNotebook)\n                           |> Option.defaultValue false\n                       { isActive=isActive; activeTab=notebook?CurrentTabIndex; tabs=getFiles notebook } )\n        |> List.ofSeq\n\n    let tryFindActiveNoteBook() =\n        getNotebooks()\n        |> List.tryFind(fun notebook -> notebook.isActive)\n\n    let tryActiveInactiveNoteBooks() =\n        let notebooks = getNotebooks()\n        notebooks |> List.tryFind(fun notebook -> notebook.isActive),\n        notebooks |> List.tryFind(fun notebook -> not notebook.isActive)\n\n    let nextTab() =\n        tryFindActiveNoteBook() |> Option.iter(fun notebook ->\n            let tabCount = notebook.tabs.Length\n            let currentTabIndex = notebook.activeTab\n            let index =\n                if currentTabIndex < (tabCount-1) then\n                    currentTabIndex + 1\n                else\n                    0\n            openDocument notebook.tabs.[index])\n\n    let previousTab() =\n        tryFindActiveNoteBook() |> Option.iter(fun notebook ->\n            let tabCount = notebook.tabs.Length\n            let currentTabIndex = notebook.activeTab\n            let index =\n                if currentTabIndex > 0 then\n                    currentTabIndex - 1\n                else\n                    tabCount - 1\n            openDocument notebook.tabs.[index])\n\n    let switchWindow() =\n        let notebook =\n            getNotebooks()\n            |> List.tryFind(fun notebook -> not notebook.isActive)\n        notebook |> Option.iter switchToNotebook\n\n    let leftWindow() =\n        let notebooks = getNotebooks()\n        if notebooks.Length = 2 && notebooks.[1].isActive then\n            switchToNotebook notebooks.[0]\n\n    let rightWindow() =\n        let notebooks = getNotebooks()\n        if notebooks.Length = 2 && notebooks.[0].isActive then\n            switchToNotebook notebooks.[1]\n\n    let private closeTabWithForce force  =\n        let closeFunc() =\n            match force with\n            | true -> forceClose() |> Async.RunSynchronously\n            | false -> dispatch FileCommands.CloseFile\n\n        match tryActiveInactiveNoteBooks() with\n        | Some active, Some inactive when active.tabs.Length = 1 ->\n            closeFunc()\n            switchToNotebook inactive\n        | Some active, _ when active.activeTab > 0 ->\n            closeFunc()\n            openDocument active.tabs.[active.activeTab-1]\n        | Some active, _ when active.activeTab = 0 && active.tabs.Length > 1 ->\n            closeFunc()\n            openDocument active.tabs.[1]\n        | _ -> closeFunc()\n\n    let closeTab() = closeTabWithForce false\n    let forceCloseTab() = closeTabWithForce true\n\n    let gotoPad padId =\n        IdeApp.Workbench.Pads\n        |> Seq.tryFind(fun p -> p.Id = padId)\n        |> Option.iter(fun pad -> pad.BringToFront(true))\n"
  },
  {
    "path": "XSVim/XSVim.fs",
    "content": "﻿namespace XSVim\n\nopen System\nopen System.Collections.Generic\nopen System.Text.RegularExpressions\nopen System.Threading\nopen MonoDevelop.Core\nopen MonoDevelop.Core.Text\nopen MonoDevelop.Ide\nopen MonoDevelop.Ide.Commands\nopen MonoDevelop.Ide.Editor\nopen MonoDevelop.Ide.Editor.Extension\nopen Reflection\n\n[<AutoOpen>]\nmodule VimHelpers =\n    let commandManager = IdeApp.CommandService |> Option.ofObj\n       \n    let dispatchCommand command =\n        commandManager\n        |> Option.iter(fun c -> c.DispatchCommand command |> ignore)\n\n    let closingBraces = [')'; '}'; ']'] |> set\n    let openingbraces = ['('; '{'; '[' ] |> set\n\n    let markDict = Dictionary<string, Marker>()\n\n    let findNextBraceForwardsOnLine (editor:TextEditor) (line:IDocumentLine) =\n        if closingBraces.Contains(editor.[editor.CaretOffset]) then\n            Some editor.CaretOffset\n        else\n            seq { editor.CaretOffset .. line.EndOffset }\n            |> Seq.tryFind(fun index -> openingbraces.Contains(editor.[index]))\n\n    let findCharForwardsOnLine (editor:TextEditor) (line:IDocumentLine) startOffset character =\n        let ch = char character\n        seq { startOffset+1 .. line.EndOffset }\n        |> Seq.tryFind(fun index -> editor.[index] = ch)\n\n    let findCharBackwardsOnLine startOffset (editor:TextEditor) (line:IDocumentLine) matcher =\n        seq { startOffset .. -1 .. line.Offset }\n        |> Seq.tryFind (fun i -> matcher editor.[i])\n\n    let findCharBackwardsOnLineExclusive (editor:TextEditor) startOffset = findCharBackwardsOnLine (startOffset-1) editor\n    let findCharBackwardsOnLineInclusive (editor:TextEditor) = findCharBackwardsOnLine editor.CaretOffset editor\n\n    let findStringCharBackwardsOnLine (editor:TextEditor) (line:IDocumentLine) startOffset character =\n        let ch = char character\n        let f = findCharBackwardsOnLineExclusive editor startOffset\n        f line ((=) ch)\n\n    let findCharForwards (editor:TextEditor) character =\n        let ch = char character\n        seq { editor.CaretOffset+1 .. editor.Length-1 }\n        |> Seq.tryFind(fun index -> editor.[index] = ch)\n\n    let findCharBackwards (editor:TextEditor) character =\n        let ch = char character\n        seq { editor.CaretOffset .. -1 .. 0 }\n        |> Seq.tryFind(fun index -> editor.[index] = ch)\n\n    let findUnmatchedBlockDelimiter(editor:TextEditor) pos blockStartDelimiter blockEndDelimiter op =\n        let blockStartShift = (blockStartDelimiter |> String.length) - 1\n        let blockEndShift = (blockEndDelimiter |> String.length) - 1\n\n        let text = editor.Text\n\n        let rec findRec startCount endCount at =\n            if (text.Length <= at || at < 0) then None else\n\n            let next = op at 1\n            let st = try text.[at..(at+blockStartShift)] with | _ -> \"\"\n            let en = try text.[at..(at+blockEndShift)] with | _ -> \"\"\n\n            match st, en with\n            | _, e when e = blockEndDelimiter && startCount < (endCount+1) -> Some at\n            | _, e when e = blockEndDelimiter -> findRec startCount (endCount+1) next\n            | s, _ when s = blockStartDelimiter -> findRec (startCount+1) endCount next\n            | _,_ -> findRec startCount endCount next\n\n        findRec 0 0 pos\n\n    let rec findUnmatchedBlockStartDelimiter(editor:TextEditor) pos blockStartDelimiter blockEndDelimiter =\n        findUnmatchedBlockDelimiter editor pos blockEndDelimiter blockStartDelimiter (-)\n\n    let findUnmatchedBlockEndDelimiter(editor:TextEditor) pos blockStartDelimiter blockEndDelimiter =\n        findUnmatchedBlockDelimiter editor pos blockStartDelimiter blockEndDelimiter (+)\n\n    let isWordChar c = Char.IsLetterOrDigit c || c = '-' || c = '_'\n    let isWORDChar c = not (Char.IsWhiteSpace c)\n    let isNonBlankButNotWordChar c = isWORDChar c && not (isWordChar c)\n    let isEOLChar c = c = '\\r' || c = '\\n'\n    let isSpaceOrTab c = c = ' ' || c = '\\t'\n\n    let (|WhiteSpace|_|) c =\n        if Char.IsWhiteSpace c then Some WhiteSpace else None\n\n    let (|IsWordChar|_|) c =\n        if isWordChar c then Some IsWordChar else None\n\n    let (|EOLChar|_|) c =\n        if isEOLChar c then Some EOLChar else None\n\n    let findWordForwards (editor:TextEditor) commandType fWordChar =\n        let findFromNonLetterChar index =\n            match editor.[index], commandType with\n            | EOLChar, Delete -> Some index\n            | WhiteSpace, Move\n            | WhiteSpace, Delete ->\n                seq { index+1 .. editor.Length-1 }\n                |> Seq.tryFind(fun index -> not (isSpaceOrTab editor.[index]))\n                |> Option.bind(fun newIndex ->\n\n                    let findFirstWordOnLine startOffset =\n                        match editor.[startOffset] with\n                        | WhiteSpace ->\n                            seq { startOffset .. editor.Length-1 }\n                            |> Seq.tryFind(fun index -> let c = editor.[index]\n                                                        fWordChar c || c = '\\n')\n                        | _ -> Some newIndex\n\n                    match editor.[newIndex] with\n                    | '\\r' -> findFirstWordOnLine (newIndex + 2)\n                    | '\\n' -> findFirstWordOnLine (newIndex + 1)\n                    | _ -> Some newIndex)\n            | _ -> Some index\n\n        if not (fWordChar editor.[editor.CaretOffset]) && fWordChar editor.[editor.CaretOffset + 1] then\n            editor.CaretOffset + 1 |> Some\n        else\n            seq { editor.CaretOffset+1 .. editor.Length-1 }\n            |> Seq.tryFind(fun index -> index = editor.Length || not (fWordChar editor.[index]))\n            |> Option.bind findFromNonLetterChar\n\n    let findWordBackwards (editor:TextEditor) commandType fWordChar =\n        let findFromNonLetterChar index =\n            match editor.[index], commandType with\n            | WhiteSpace, Move ->\n                seq { index .. -1 .. 0 }\n                |> Seq.tryFind(fun index -> not (Char.IsWhiteSpace editor.[index]))\n            | _ -> Some index\n\n        if not (fWordChar editor.[editor.CaretOffset]) && fWordChar editor.[editor.CaretOffset - 1] then\n            editor.CaretOffset - 1 |> Some\n        else\n            seq { editor.CaretOffset .. -1 .. 0 }\n            |> Seq.tryFind(fun index -> index = editor.Length+1 || not (fWordChar editor.[index]))\n            |> Option.bind findFromNonLetterChar\n\n    let findPrevWord (editor:TextEditor) fWordChar =\n        let result = Math.Max(editor.CaretOffset - 1, 0)\n        let previous = fWordChar editor.[result]\n        let rec findStartBackwards index previous isInIdentifier =\n            let ch = editor.[index]\n            let current = fWordChar ch\n\n            match previous with\n            | _ when index = 0 -> 0\n            | false when isInIdentifier -> index + 2\n            | _ -> findStartBackwards (index - 1) current previous\n        findStartBackwards result previous previous\n\n    let findCurrentWordEnd (editor:TextEditor) fWordChar =\n        seq { editor.CaretOffset .. editor.Length - 2 }\n        |> Seq.tryFind(fun index -> not (fWordChar editor.[index+1]))\n        |> Option.defaultValue (editor.Length-1)\n\n    let findWordEnd (editor:TextEditor) fWordChar =\n        let currentWordEnd = findCurrentWordEnd editor fWordChar\n        if editor.CaretOffset = currentWordEnd then\n            let nextWordOffset = findWordForwards editor Move fWordChar\n            match nextWordOffset with\n            | Some offset ->\n                let f =\n                    if fWordChar editor.[offset] then fWordChar else isNonBlankButNotWordChar\n                editor.CaretOffset <- offset\n                findCurrentWordEnd editor f\n            | None -> editor.Length\n        else\n            currentWordEnd\n\n    let findCurrentWordStart (editor:TextEditor) fWordChar =\n        seq { editor.CaretOffset .. -1 .. 1 }\n        |> Seq.tryFind(fun index -> not (fWordChar editor.[index-1]))\n        |> Option.defaultValue 0\n\n    let paragraphBackwards (editor:TextEditor) =\n        seq { editor.CaretLine-1 .. -1 .. 1 }\n        |> Seq.tryFind(fun lineNr -> let line = editor.GetLineText lineNr\n                                     String.IsNullOrWhiteSpace line)\n        |> Option.bind(fun lineNr -> Some (editor.GetLine lineNr).Offset)\n\n    let paragraphForwards (editor:TextEditor) =\n        seq { editor.CaretLine+1 .. editor.LineCount }\n        |> Seq.tryFind(fun lineNr -> let line = editor.GetLineText lineNr\n                                     String.IsNullOrWhiteSpace line)\n        |> Option.bind(fun lineNr -> Some (editor.GetLine lineNr).Offset)\n\n    let getVisibleLines editor =\n        let (lines:IDocumentLine seq) = editor?VisibleLines\n        lines\n\n    let getSortedVisibleLines editor =\n        getVisibleLines editor |> Seq.sortBy(fun l -> l.LineNumber) /// the lines come back in random order\n\n    let getVisibleLineCount editor =\n        getVisibleLines editor |> Seq.length\n\n    let getComparisonType (search:string) =\n        match search with\n        | s when s.ToLower() = s -> StringComparison.CurrentCultureIgnoreCase\n        | _ -> StringComparison.CurrentCulture\n\n    let findNextSearchOffset (editor:TextEditor) (search:string) (startOffset:int) =\n        let comparison = getComparisonType search\n        let index = editor.Text.IndexOf(search, startOffset, comparison)\n        if index > -1 then\n            Some index\n        else\n            let index = editor.Text.IndexOf(search, comparison)\n            if index > -1 then Some index else None\n\n    let findNextSearchOffsetBackwards (editor:TextEditor) (search:string) (startOffset:int) =\n        let comparison = getComparisonType search\n        let index = editor.Text.LastIndexOf(search, startOffset, comparison)\n        if index > -1 then\n            Some index\n        else\n            let index = editor.Text.LastIndexOf(search, editor.Length, comparison)\n            if index > -1 then Some index else None\n\n    let wordAtCaret (editor:TextEditor) =\n        if isWordChar (editor.[editor.CaretOffset]) then\n            let start = findCurrentWordStart editor isWordChar\n            let finish = (findCurrentWordEnd editor isWordChar)\n            let word = editor.GetTextAt(start, finish - start + 1)\n            Some word\n        else\n            None\n\n    let eofOnLine (line: IDocumentLine) = line.DelimiterLength = 0\n\n    let findQuoteTriplet (editor:TextEditor) line quoteChar =\n        let firstBackwards = findCharBackwardsOnLine editor.CaretOffset editor line ((=) quoteChar)\n        let firstForwards = findCharForwardsOnLine editor line editor.CaretOffset (string quoteChar)\n        let secondForwards =\n            match firstForwards with\n            | Some offset when offset + 1 < editor.Length ->\n                findCharForwardsOnLine editor line offset (string quoteChar)\n            | _ -> None\n        firstBackwards, firstForwards, secondForwards\n\n    let inferDelimiter (editor:TextEditor) =\n        editor.GetLines()\n        |> Seq.tryFind(fun line -> line.DelimiterLength > 0)\n        |> Option.map(fun line -> match line.UnicodeNewline with\n                                  | UnicodeNewline.LF -> \"\\n\"\n                                  | UnicodeNewline.CRLF -> \"\\r\\n\"\n                                  | UnicodeNewline.CR -> \"\\r\"\n                                  | _ -> editor.Options.DefaultEolMarker)\n        |> Option.defaultValue editor.Options.DefaultEolMarker\n\n    /// Get the range of the trailing or leading whitespace\n    /// around a word when aw or aW is used\n    let getAroundWordRange (editor:TextEditor) wordStart wordEnd =\n        let hasLeadingWhiteSpace =\n            wordStart > 1 && Char.IsWhiteSpace editor.[wordStart-1]\n\n        let hasTrailingWhiteSpace =\n            wordEnd < editor.Length && Char.IsWhiteSpace editor.[wordEnd]\n\n        let line = editor.GetLine editor.CaretLine\n        match hasTrailingWhiteSpace, hasLeadingWhiteSpace with\n        | true, _ ->\n            let finish =\n                seq { wordEnd .. line.EndOffset - 2 }\n                |> Seq.tryFind(fun index -> not (Char.IsWhiteSpace editor.[index+1]))\n                |> Option.defaultValue (line.EndOffset-1)\n            wordStart, finish + 1\n        | false, true ->\n            let start =\n                seq { wordStart .. -1 .. line.Offset }\n                |> Seq.tryFind(fun index -> not (Char.IsWhiteSpace editor.[index-1]))\n                |> Option.defaultValue line.Offset\n            start, wordEnd\n        | _ -> wordStart, wordEnd\n\n    let getWordRange (editor:TextEditor) fWordChar =\n        let wordStart = findCurrentWordStart editor fWordChar\n        let wordEnd = findCurrentWordEnd editor fWordChar\n        wordStart, wordEnd + 1\n\n    let getWhitespaceRange (editor:TextEditor) fWordChar =\n        let prevWordEnd = findWordBackwards editor Move fWordChar |> Option.defaultValue editor.CaretOffset\n        let nextWordEnd = findWordEnd editor fWordChar\n        prevWordEnd + 1, nextWordEnd + 1\n\n    let rec findEnclosingTag(editor:TextEditor) pos =\n        let search = seq { pos .. -1 .. 0 } |> Seq.tryFind(fun index -> editor.[index] = '<')\n        match search with\n        | Some startTagStart -> \n            let m = Regex.Match(editor.GetTextBetween(startTagStart, editor.Length), \"<([\\w|:|\\.]+).*?>\", RegexOptions.Singleline)\n            if m.Success then \n                let tagName = m.Groups.[1].Value;\n                let endTag = \"</\" + tagName + \">\"\n                let startTagEnd = startTagStart + m.Length - 1\n                match findUnmatchedBlockEndDelimiter editor startTagEnd (\"<\" + tagName) endTag with \n                | Some endTagStart -> Some (startTagStart, startTagEnd, endTagStart, endTagStart + endTag.Length)\n                | None -> findEnclosingTag editor (startTagStart - 1)\n            else \n                None\n        | None -> None\n\n    let rec getRange (config:Config) (vimState:VimState) (editor:TextEditor) (command:VimAction) =\n        let line = editor.GetLine editor.CaretLine\n        let noOp = (editor.CaretOffset, editor.CaretOffset)\n        match command.textObject with\n        | Right behaviour ->\n            let line = editor.GetLine editor.CaretLine\n            let endOffset =\n                match behaviour with\n                | StopAtEndOfLine when editor.CaretColumn >= line.Length -> editor.CaretOffset\n                | MoveToNextLineAtEnd when editor.[editor.CaretOffset+1] = '\\r' -> editor.CaretOffset + 3\n                | MoveToNextLineAtEnd when editor.[editor.CaretOffset+1] = '\\n' -> editor.CaretOffset + 2\n                | IncludeDelimiter ->\n                    let line = editor.GetLine editor.CaretLine\n                    if line.Length > 0 && editor.CaretColumn <= line.LengthIncludingDelimiter then\n                        editor.CaretOffset + 1\n                    else\n                        editor.CaretOffset\n                | _ -> editor.CaretOffset + 1\n            editor.CaretOffset, endOffset\n        | Left ->\n           editor.CaretOffset,\n           if editor.CaretColumn > DocumentLocation.MinColumn && editor.[editor.CaretOffset-1] <> '\\n' then\n               editor.CaretOffset - 1\n           else\n               editor.CaretOffset\n        | Up ->\n            editor.CaretOffset,\n            if editor.CaretLine > DocumentLocation.MinLine then\n                let column =\n                    let line = editor.GetLine (editor.CaretLine - 1)\n                    let desiredColumn = vimState.desiredColumn |> Option.defaultValue editor.CaretColumn\n                    if desiredColumn <= line.Length then\n                        desiredColumn\n                    else\n                        line.Length\n\n                editor.LocationToOffset (new DocumentLocation(editor.CaretLine - 1, column))\n            else\n                editor.CaretOffset\n        | Down ->\n            editor.CaretOffset,\n            if editor.CaretLine < editor.LineCount then\n                let column =\n                    let line = editor.GetLine (editor.CaretLine + 1)\n                    let desiredColumn = vimState.desiredColumn |> Option.defaultValue editor.CaretColumn\n                    if desiredColumn <= line.Length then\n                        desiredColumn\n                    else\n                        line.Length\n\n                editor.LocationToOffset (new DocumentLocation(editor.CaretLine + 1, column))\n            else\n                editor.CaretOffset\n        | EndOfLine -> editor.CaretOffset, line.EndOffset-1\n        | Character repeat ->\n            let line = editor.GetLine editor.CaretLine\n            let endOffset = min line.EndOffset (editor.CaretOffset + repeat)\n            editor.CaretOffset, endOffset\n        | EndOfLineIncludingDelimiter ->\n            editor.CaretOffset,\n            if eofOnLine line then\n                line.EndOffsetIncludingDelimiter\n            else\n                line.EndOffsetIncludingDelimiter-1\n        | StartOfLine -> editor.CaretOffset, line.Offset\n        | Jump (StartOfLineNumber lineNumber) ->\n            let line = editor.GetLine lineNumber\n            editor.CaretOffset, line.Offset + editor.GetLineIndent(lineNumber).Length\n        | Jump StartOfDocument -> editor.CaretOffset, 0\n        | FirstNonWhitespace -> editor.CaretOffset, line.Offset + editor.GetLineIndent(editor.CaretLine).Length\n        | WholeLine ->\n            line.Offset, line.EndOffset\n        | WholeLineIncludingDelimiter ->\n            if eofOnLine line && line.LineNumber <> 1 then\n                let delimiter = inferDelimiter editor\n                line.Offset-delimiter.Length, line.EndOffsetIncludingDelimiter\n            else\n                line.Offset, line.EndOffsetIncludingDelimiter\n        | Jump LastLine ->\n            let lastLine = editor.GetLine editor.LineCount\n            editor.CaretOffset, lastLine.Offset\n        | Jump FirstVisibleLine ->\n            let firstLine = getSortedVisibleLines editor |> Seq.head\n            editor.CaretOffset, firstLine.Offset\n        | Jump MiddleVisibleLine ->\n            let firstLine = getSortedVisibleLines editor |> Seq.head\n            let lastLine = getSortedVisibleLines editor |> Seq.last\n            let middleLineNumber = (lastLine.LineNumber - firstLine.LineNumber) / 2 + firstLine.LineNumber\n            let middleLine = editor.GetLine middleLineNumber\n            editor.CaretOffset, middleLine.Offset\n        | Jump LastVisibleLine ->\n            let lastLine = getSortedVisibleLines editor |> Seq.last\n            editor.CaretOffset, lastLine.Offset\n        | ToCharInclusiveBackwards c ->\n            match findStringCharBackwardsOnLine editor line (editor.CaretOffset-1) c with\n            | Some index -> editor.CaretOffset, index\n            | None -> editor.CaretOffset, editor.CaretOffset\n        | ToCharExclusiveBackwards c ->\n            let startOffset =\n                match config.keyboardLayout, vimState.keys with\n                | Qwerty, Key ';' :: _ when c = editor.[editor.CaretOffset-1].ToString() ->\n                    editor.CaretOffset-1\n                | Colemak, Key 'o' :: _ when c = editor.[editor.CaretOffset-1].ToString() ->\n                    editor.CaretOffset-1\n                | Dvorak, Key 's' :: _ when c = editor.[editor.CaretOffset-1].ToString() ->\n                    editor.CaretOffset-1\n                | _, _ -> editor.CaretOffset\n            match findStringCharBackwardsOnLine editor line startOffset c with\n            | Some index -> editor.CaretOffset, index+1\n            | None -> editor.CaretOffset, editor.CaretOffset\n        | ToCharInclusive c ->\n            match findCharForwardsOnLine editor line editor.CaretOffset c with\n            | Some index -> editor.CaretOffset, index\n            | None -> editor.CaretOffset, editor.CaretOffset\n        | ToCharExclusive c ->\n            let startOffset =\n                match config.keyboardLayout, vimState.keys with\n                | Qwerty, Key ';' :: _ when c = editor.[editor.CaretOffset+1].ToString() ->\n                    editor.CaretOffset+1\n                | Colemak, Key 'o' :: _ when c = editor.[editor.CaretOffset+1].ToString() ->\n                    editor.CaretOffset+1\n                | Dvorak, Key 's' :: _ when c = editor.[editor.CaretOffset+1].ToString() ->\n                    editor.CaretOffset+1\n                | _, _ -> editor.CaretOffset\n            match findCharForwardsOnLine editor line startOffset c with\n            | Some index -> editor.CaretOffset, index-1\n            | None -> editor.CaretOffset, editor.CaretOffset\n        | InnerBlock (startChar, endChar) ->\n            let opening = findUnmatchedBlockStartDelimiter editor editor.CaretOffset startChar endChar\n            let closing = findUnmatchedBlockEndDelimiter editor editor.CaretOffset startChar endChar\n            match opening, closing with\n            | Some start, Some finish -> start+1, finish\n            | _, _ -> editor.CaretOffset, editor.CaretOffset\n        | ABlock (startChar, endChar) ->\n            let opening = findUnmatchedBlockStartDelimiter editor editor.CaretOffset startChar endChar\n            let closing = findUnmatchedBlockEndDelimiter editor editor.CaretOffset startChar endChar\n            match opening, closing with\n            | Some start, Some finish when finish < editor.Length -> start, finish+1\n            | _, _ -> editor.CaretOffset, editor.CaretOffset\n        | InnerQuotedBlock c ->\n            match findQuoteTriplet editor line c with\n            | Some start, Some finish, _ -> start + 1, finish // we're inside quotes\n            | None, Some start, Some finish -> start + 1, finish // there's quoted text to the right\n            | _, _,_ -> editor.CaretOffset, editor.CaretOffset\n        | AQuotedBlock c ->\n            match findQuoteTriplet editor line c with\n            | Some start, Some finish, _ -> start, finish + 1 // we're inside quotes\n            | None, Some start, Some finish -> start, finish + 1 // there's quoted text to the right\n            | _, _,_ -> editor.CaretOffset, editor.CaretOffset\n        | WordForwards ->\n            match findWordForwards editor command.commandType isWordChar with\n            | Some index -> editor.CaretOffset, index\n            | None -> editor.CaretOffset, editor.Length\n        | WORDForwards ->\n            match findWordForwards editor command.commandType isWORDChar with\n            | Some index -> editor.CaretOffset, index\n            | None -> editor.CaretOffset, editor.CaretOffset\n        | WordBackwards -> editor.CaretOffset, findPrevWord editor isWordChar\n        | WORDBackwards -> editor.CaretOffset, findPrevWord editor isWORDChar\n        | BackwardToEndOfWord ->\n            match findWordBackwards editor command.commandType isWordChar with\n            | Some index -> editor.CaretOffset, index\n            | None -> editor.CaretOffset, 0\n        | BackwardToEndOfWORD ->\n            match findWordBackwards editor command.commandType isWORDChar with\n            | Some index -> editor.CaretOffset, index\n            | None -> editor.CaretOffset, 0\n        | Jump ParagraphBackwards ->\n            match paragraphBackwards editor with\n            | Some index -> editor.CaretOffset, index\n            | None -> editor.CaretOffset, 0\n        | Jump ParagraphForwards ->\n            match paragraphForwards editor with\n            | Some index -> editor.CaretOffset, index\n            | None -> editor.CaretOffset, editor.CaretOffset\n        | InnerWord ->\n            let getWordCharFunc = function\n                | IsWordChar -> isWordChar\n                | _ -> isNonBlankButNotWordChar\n\n            match editor.[editor.CaretOffset] with\n            | WhiteSpace ->\n                let matchFunc c = Char.IsWhiteSpace c && (not (isEOLChar c))\n                getWordRange editor matchFunc\n            | _ ->\n                let fWordChar = getWordCharFunc editor.[editor.CaretOffset]\n                getWordRange editor fWordChar\n        | InnerWORD ->\n            match editor.[editor.CaretOffset] with\n            | WhiteSpace ->\n                let matchFunc c = Char.IsWhiteSpace c && (not (isEOLChar c))\n                getWordRange editor matchFunc\n            | _ ->\n                getWordRange editor isWORDChar\n        | AWord ->\n            let getWordCharFunc = function\n                | IsWordChar -> isWordChar\n                | _ -> isNonBlankButNotWordChar\n\n            match editor.[editor.CaretOffset] with\n            | WhiteSpace -> getWhitespaceRange editor isWordChar\n            | _ ->\n                let fWordChar = getWordCharFunc editor.[editor.CaretOffset]\n                let wordStart, wordEnd = getWordRange editor fWordChar\n                getAroundWordRange editor wordStart wordEnd\n        | AWORD ->\n            match editor.[editor.CaretOffset] with\n            | WhiteSpace -> getWhitespaceRange editor isWORDChar\n            | _ ->\n                let wordStart, wordEnd = getWordRange editor isWORDChar\n                getAroundWordRange editor wordStart wordEnd\n        | ForwardToEndOfWord ->\n            let isWordCharAtOffset offset = isWordChar (editor.[offset])\n\n            match command.commandType, isWordCharAtOffset editor.CaretOffset, Char.IsWhiteSpace (editor.[editor.CaretOffset+1]) with\n            | Change, true, true\n            | Delete, true, true ->\n                 editor.CaretOffset, editor.CaretOffset\n            | _ -> editor.CaretOffset, findWordEnd editor isWordChar\n        | ForwardToEndOfWORD -> editor.CaretOffset, findWordEnd editor isWORDChar\n        | ATag -> \n            match findEnclosingTag editor editor.CaretOffset with\n            | Some (startTagStart, _, _, endTagEnd) -> startTagStart, endTagEnd\n            | None -> noOp\n        | InnerTag -> \n            match findEnclosingTag editor editor.CaretOffset with\n            | Some (_, startTagEnd, endTagStart, _) -> startTagEnd + 1, endTagStart\n            | None -> noOp\n        | Jump HalfPageUp ->\n            let visibleLineCount = getVisibleLineCount editor\n            let halfwayUp = max 1 (editor.CaretLine - visibleLineCount / 2)\n            editor.CaretOffset, editor.GetLine(halfwayUp).Offset\n        | Jump HalfPageDown ->\n            let visibleLineCount = getVisibleLineCount editor\n            let halfwayDown = min editor.LineCount (editor.CaretLine + visibleLineCount / 2)\n            editor.CaretOffset, editor.GetLine(halfwayDown).Offset\n        | Jump PageUp ->\n            let visibleLineCount = getVisibleLineCount editor\n            let pageUp = max 1 (editor.CaretLine - visibleLineCount)\n            editor.CaretOffset, editor.GetLine(pageUp).Offset\n        | Jump PageDown ->\n            let visibleLineCount = getVisibleLineCount editor\n            let pageDown = min editor.LineCount (editor.CaretLine + visibleLineCount)\n            editor.CaretOffset, editor.GetLine(pageDown).Offset\n        | CurrentLocation -> editor.CaretOffset, editor.CaretOffset+1\n        | SelectedText ->\n            let selection = editor.Selections |> Seq.head\n            let lead = editor.LocationToOffset selection.Lead\n            let anchor = editor.LocationToOffset selection.Anchor\n            min lead anchor, max lead anchor\n        | SelectionStart -> editor.CaretOffset, vimState.visualStartOffset\n        | MatchingBrace ->\n            match findNextBraceForwardsOnLine editor line with\n            | Some offset ->\n                let startOffset = editor.CaretOffset\n                editor.CaretOffset <- offset\n                EditActions.GotoMatchingBrace editor\n                startOffset, editor.CaretOffset\n            | _ -> editor.CaretOffset, editor.CaretOffset\n        | PrevUnmatchedBrace -> \n            match findUnmatchedBlockStartDelimiter editor editor.CaretOffset \"{\" \"}\" with\n            | Some jumpPos -> editor.CaretOffset, jumpPos\n            | None -> noOp\n        | NextUnmatchedBrace -> \n            match findUnmatchedBlockEndDelimiter editor editor.CaretOffset \"{\" \"}\" with\n            | Some jumpPos -> editor.CaretOffset, jumpPos\n            | None -> noOp\n        | PrevUnmatchedParen -> \n            match findUnmatchedBlockStartDelimiter editor editor.CaretOffset \"(\" \")\" with\n            | Some jumpPos -> editor.CaretOffset, jumpPos\n            | None -> noOp\n        | NextUnmatchedParen -> \n            match findUnmatchedBlockEndDelimiter editor editor.CaretOffset \"(\" \")\" with\n            | Some jumpPos -> editor.CaretOffset, jumpPos\n            | None -> noOp\n        | Jump (ToMark (c, jumpType)) ->\n            match markDict.TryGetValue c with\n            | true, mark ->\n                let offset =\n                    match jumpType with\n                    | MarkerJumpType.Offset -> mark.Offset\n                    | MarkerJumpType.StartOfLine ->\n                        let line = editor.GetLineByOffset mark.Offset\n                        line.Offset + editor.GetLineIndent(line).Length\n\n                if editor.FileName.FullPath.ToString() = mark.FileName then\n                    editor.CaretOffset, offset\n                else\n                    let document = IdeApp.Workbench.GetDocument(FilePath mark.FileName)\n                    let fileInfo = new MonoDevelop.Ide.Gui.FileOpenInformation (document.FileName)\n                    IdeApp.Workbench.OpenDocument(fileInfo) |> ignore\n                    editor.CaretOffset, offset\n            | _ -> editor.CaretOffset, editor.CaretOffset\n        | Offset offset -> editor.CaretOffset, offset\n        | Range (startOffset, endOffset) -> startOffset, endOffset\n        | Jump (ToSearch search) ->\n            let startOffset =\n                match config.keyboardLayout, vimState.keys with\n                | Qwerty, [Key 'n'] \n                | Qwerty, [Key 'N']\n                | Colemak, [Key 'k'] \n                | Colemak, [Key 'K']\n                | Dvorak, [Key 'b'] \n                | Dvorak, [Key 'B'] -> editor.CaretOffset + 1\n                | _ -> editor.CaretOffset\n            let offset = findNextSearchOffset editor search startOffset |> Option.defaultValue editor.CaretOffset\n            editor.CaretOffset, offset\n        | Jump (ToSearchBackwards search) ->\n            let offset = findNextSearchOffsetBackwards editor search editor.CaretOffset |> Option.defaultValue editor.CaretOffset\n            editor.CaretOffset, offset\n        | Jump SearchAgain ->\n            match vimState.lastSearch with\n            | Some search -> getRange config vimState editor { command with textObject = search }\n            | None -> editor.CaretOffset, editor.CaretOffset\n        | Jump SearchAgainBackwards ->\n            match vimState.lastSearch with\n            | Some search ->\n                let reverseSearch =\n                    match search with\n                    | Jump (ToSearch s) -> Jump (ToSearchBackwards s)\n                    | Jump (ToSearchBackwards s) -> Jump (ToSearch s)\n                    | _ -> failwith \"Invalid search\"\n                getRange config vimState editor { command with textObject = reverseSearch }\n            | None -> editor.CaretOffset, editor.CaretOffset\n        | _ -> editor.CaretOffset, editor.CaretOffset\n\nmodule Vim =\n    LoggingService.LogInfo (\"XSVim \" + version)\n\n    let registers = Dictionary<Register, XSVim.Selection>()\n    let editorStates = Dictionary<FilePath, VimState>()\n\n    registers.[EmptyRegister] <- { linewise=false; content=\"\" }\n\n    let macros = Dictionary<char, VimAction list>()\n\n    let (|VisualModes|_|) = function\n        | VisualMode | VisualLineMode | VisualBlockMode -> Some VisualModes\n        | _ -> None\n\n    let (|NotInsertMode|_|) = function\n        | InsertMode | ReplaceMode | ExMode _ -> None\n        | _ -> Some NotInsertMode\n\n    let setSelection vimState (editor:TextEditor) (command:VimAction) (start:int) finish =\n        match vimState.mode, command.commandType with\n        | VisualMode, Move | VisualMode, SwitchMode _ ->\n            let start, finish =\n                if finish < vimState.visualStartOffset then\n                    finish, vimState.visualStartOffset + 1\n                else\n                    vimState.visualStartOffset, finish + if command.textObject = EndOfLine then 0 else 1\n\n            editor.SetSelection(start, min finish editor.Length)\n            if editor.SelectionMode = SelectionMode.Block then EditActions.ToggleBlockSelectionMode editor\n        | VisualBlockMode, Move | VisualBlockMode, SwitchMode _ ->\n            let selectionStartLocation = editor.OffsetToLocation vimState.visualStartOffset\n            let leftColumn, rightColumn =\n                if editor.CaretColumn < selectionStartLocation.Column then\n                    editor.CaretColumn, selectionStartLocation.Column+1\n                else\n                    selectionStartLocation.Column, editor.CaretColumn+1\n            let topLine = min selectionStartLocation.Line editor.CaretLine\n            let bottomLine = max selectionStartLocation.Line editor.CaretLine\n            editor.SetSelection(DocumentLocation (topLine, leftColumn), DocumentLocation (bottomLine, rightColumn))\n            if editor.SelectionMode = SelectionMode.Normal then EditActions.ToggleBlockSelectionMode editor\n        | VisualLineMode, Move | VisualLineMode, SwitchMode _ ->\n            let startPos = min finish vimState.visualStartOffset\n            let endPos = max finish vimState.visualStartOffset\n            let startLine = editor.GetLineByOffset startPos\n            let endLine = editor.GetLineByOffset endPos\n            editor.SetSelection(startLine.Offset, endLine.EndOffsetIncludingDelimiter)\n            if editor.SelectionMode = SelectionMode.Block then EditActions.ToggleBlockSelectionMode editor\n        | _ -> editor.SetSelection(start, min finish editor.Length)\n\n    let (|MoveUpOrDown|_|) = function\n        | { commandType=Move; textObject=Up }\n        | { commandType=Move; textObject=Down } -> Some MoveUpOrDown\n        | _ -> None\n\n    let (|LineWise|_|) = function\n        | Up | Down\n        | WholeLine\n        | WholeLineIncludingDelimiter\n        | Jump (ToMark (_, MarkerJumpType.StartOfLine))\n        | Jump LastLine -> Some LineWise\n        | _ -> None\n\n    let (|StartsWithDelimiter|_|) (s:string) =\n        if s.StartsWith \"\\r\\n\" then Some \"\\r\\n\"\n        elif s.StartsWith \"\\n\" then Some \"\\n\"\n        else None\n\n    let (|EndsWithDelimiter|_|) (s:string) =\n        if s.EndsWith \"\\r\\n\" then Some \"\\r\\n\"\n        elif s.EndsWith \"\\n\" then Some \"\\n\"\n        else None\n\n    let isLineWise vimState command =\n        match vimState.mode with\n        | VisualLineMode -> true\n        | _ ->\n            match command.textObject with\n            | LineWise -> true\n            | _ -> false\n\n    let getSelectedText vimState (editor: TextEditor) command =\n        let linewise = isLineWise vimState command\n        { linewise=linewise; content=editor.SelectedText }\n\n    let getCaretMode (editor:TextEditor) =\n        let caret = editor.Carets.[0]\n        let caretMode:bool = caret?IsInInsertMode\n        match caretMode with\n        | true -> Insert\n        | false -> Block\n\n    let setCaretMode (editor:TextEditor) caretMode =\n        let currentMode = getCaretMode editor\n        match currentMode, caretMode with\n        | Block, Insert -> EditActions.SwitchCaretMode editor\n        | Insert, Block -> EditActions.SwitchCaretMode editor\n        | _ -> ()\n\n    let setAutoCompleteOnKeystroke value =\n        if SettingsPanel.AutoCompleteInNormalModeIsDisabled() then\n            IdeApp.Preferences.EnableAutoCodeCompletion.Set value |> ignore\n\n    let switchToInsertMode (editor:TextEditor) state isInitial =\n        let group =\n            if isInitial\n                then editor.OpenUndoGroup() |> Some\n            else\n                state.undoGroup\n\n        setAutoCompleteOnKeystroke true\n        setCaretMode editor Insert\n        { state with mode = InsertMode; statusMessage = \"-- INSERT --\" |> Some; keys = []; undoGroup = group }\n\n    let switchToNormalMode (editor:TextEditor) vimState =\n        let lastSelection =\n            match vimState.mode with\n            | VisualModes ->\n                Some { start = vimState.visualStartOffset; finish = editor.CaretOffset; mode = vimState.mode }\n            | _ -> vimState.lastSelection\n        editor.ClearSelection()\n        setAutoCompleteOnKeystroke false\n        setCaretMode editor Block\n        // stupid hack to prevent intellisense in normal mode\n        // https://github.com/mono/monodevelop/blob/fdbfbe89529bd9076e1906e7b70fdb51a9ae6b99/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/CompletionTextEditorExtension.cs#L153\n        if editor.SelectionMode = SelectionMode.Normal then EditActions.ToggleBlockSelectionMode editor\n        vimState.undoGroup |> Option.iter(fun d -> d.Dispose())\n        if vimState.mode = InsertMode && editor.CaretColumn > 1 then\n            EditActions.MoveCaretLeft editor\n        { vimState with mode = NormalMode; lastSelection = lastSelection; undoGroup = None; statusMessage = None }\n\n    let processVimKey (editor:TextEditor) =\n        function\n        | Key k -> editor.InsertAtCaret (string k)\n        | VimKey.Delete -> EditActions.Delete editor\n        | VimKey.Backspace -> EditActions.Backspace editor\n        | VimKey.Left -> EditActions.MoveCaretLeft editor\n        | VimKey.Right -> EditActions.MoveCaretRight editor\n        | VimKey.Up -> EditActions.MoveCaretUp editor\n        | VimKey.Down -> EditActions.MoveCaretDown editor\n        | Ret -> EditActions.InsertNewLine editor\n        | Super _\n        | Esc\n        | EscapeKey _\n        | Control _ -> ()\n\n    let runCommand config vimState editor command =\n        let delete state start finish =\n            let finish =\n                match command.textObject with\n                | ForwardToEndOfWord\n                | ForwardToEndOfWORD\n                | EndOfLine\n                | MatchingBrace\n                | PrevUnmatchedBrace\n                | NextUnmatchedBrace\n                | PrevUnmatchedParen\n                | NextUnmatchedParen\n                | ToCharInclusive _\n                | ToCharExclusive _ -> finish + 1\n                | _ -> finish\n\n            if start <> finish then\n                if command.textObject <> SelectedText then\n                    setSelection state editor command start finish\n                registers.[EmptyRegister] <- getSelectedText state editor command\n                EditActions.ClipboardCut editor\n            state\n\n        let setMark c =\n            if markDict.ContainsKey c then\n                let marker = markDict.[c]\n                markDict.Remove c |> ignore\n                marker.Remove()\n            let marker = Marker(editor, c)\n            markDict.Add (c, marker) |> ignore\n\n        let toggleCase state start finish =\n            if command.textObject <> SelectedText then\n                setSelection state editor command start finish\n\n            let toggleChar = function\n                | c when Char.IsUpper c -> Char.ToLower c\n                | c when Char.IsLower c -> Char.ToUpper c\n                | c -> c\n\n            match state.mode with\n            | VisualBlockMode ->\n                let selectionStartLocation = editor.OffsetToLocation vimState.visualStartOffset\n                let topLine = Math.Min(selectionStartLocation.Line, editor.CaretLine)\n                let bottomLine = Math.Max(selectionStartLocation.Line, editor.CaretLine)\n                editor.CaretColumn <- Math.Min(editor.CaretColumn, selectionStartLocation.Column)\n                let offsets = [ topLine .. bottomLine ] |> List.map (fun c -> editor.LocationToOffset(c, editor.CaretColumn))\n                for i in offsets do\n                    let currentLetter = editor.[i]\n                    let isLetter = Char.IsLetter editor.[i]\n                    if isLetter then\n                        let c = toggleChar currentLetter\n                        editor.SetSelection(i, i+1)\n                        EditActions.Delete editor\n                        editor.InsertAtCaret (string c)\n                        EditActions.MoveCaretLeft editor\n            | _ ->\n                let swappedChars = editor.SelectedText |> Seq.map toggleChar |> Array.ofSeq\n                EditActions.Delete editor\n                editor.InsertAtCaret (swappedChars |> String)\n            if command.textObject = SelectedText then\n                editor.CaretOffset <- state.visualStartOffset\n            state\n\n        let modifyNumber f =\n            let line = editor.GetLine editor.CaretLine\n            let startOffset =\n                let f = findCharBackwardsOnLineInclusive editor\n                f line (fun c -> (c < '0' || c > '9') && c <> '-')\n            let offset =\n                match startOffset with\n                | Some i -> i+1\n                | None -> editor.CaretOffset\n            let lineToEnd = editor.Text.[offset .. line.EndOffset-1]\n            let matches = Regex.Matches(lineToEnd, \"-?[0-9]+\", RegexOptions.Compiled) |> Seq.cast<Match>\n\n            match matches |> Seq.tryHead with\n            | Some m ->\n                let i = Convert.ToInt32 (lineToEnd.[m.Index .. m.Index+m.Length-1])\n                let replacement = (f i) |> string\n                editor.ReplaceText(line.Offset+m.Index+(line.Length-lineToEnd.Length), m.Length, replacement)\n                let line = editor.GetLine editor.CaretLine\n                editor.CaretOffset <- line.Offset + m.Index+(line.Length-lineToEnd.Length)+m.Length-1\n                vimState\n            | None -> vimState\n\n        let rec processCommands config count vimState command isInitial =\n            let blockInsert fColumnSelect =\n                let selectionStartLocation = editor.OffsetToLocation vimState.visualStartOffset\n                let topLine = min selectionStartLocation.Line editor.CaretLine\n                let bottomLine = max selectionStartLocation.Line editor.CaretLine\n                editor.CaretColumn <- fColumnSelect editor.CaretColumn selectionStartLocation.Column\n                editor.SetSelection(DocumentLocation (topLine, editor.CaretColumn), DocumentLocation (bottomLine, editor.CaretColumn))\n                if editor.SelectionMode = SelectionMode.Normal then EditActions.ToggleBlockSelectionMode editor\n                switchToInsertMode editor vimState isInitial\n\n            let start, finish =\n                if editor.Length > 0 then\n                    VimHelpers.getRange config vimState editor command\n                else\n                    // editor can have zero length when a tab containing it has just been closed\n                    0, 0\n\n            let newState =\n                match command.commandType with\n                | Move ->\n                    match vimState.mode with\n                    | VisualModes ->\n                        editor.CaretOffset <- finish\n                        let finish =\n                            match command.textObject with\n                            | EndOfLine -> finish + 1\n                            | _ -> finish\n\n                        setSelection vimState editor command start finish\n                    | _ -> ()\n\n                    match command.textObject with\n                    | Jump _ ->\n                        setMark \"\\'\"\n                        setMark \"`\"\n                    | _ -> ()\n                    let newState =\n                        match command, vimState.desiredColumn with\n                        // don't change desired column if we already started moving up or down\n                        | MoveUpOrDown, Some _c ->\n                            editor.CaretOffset <- finish\n                            vimState\n                        | MoveUpOrDown, None ->\n                            let res = { vimState with desiredColumn = Some editor.CaretColumn }\n                            editor.CaretOffset <- finish\n                            res\n                        | _ ->\n                            editor.CaretOffset <- finish\n                            { vimState with desiredColumn = Some editor.CaretColumn }\n                    newState\n                | Delete ->\n                    let linewise = isLineWise vimState command\n                    let start, finish =\n                        match linewise with\n                        | true ->\n\n                            let min = min start finish\n                            let maxOffset = max start finish\n                            let line = editor.GetLineByOffset min\n                            let finish = editor.GetLineByOffset(maxOffset).EndOffsetIncludingDelimiter\n                            if eofOnLine line && line.LineNumber <> 1 then\n                                let delimiter = inferDelimiter editor\n                                line.Offset-delimiter.Length, finish\n                            else\n                                line.Offset, finish\n                        | false -> start, finish\n\n                    let newState = delete vimState start finish\n                    let offsetBeforeDelimiter =\n                        match linewise with\n                        | true ->\n                            let line = editor.GetLineByOffset(editor.CaretOffset)\n                            let line =\n                                if editor.CaretOffset = editor.Length && editor.Length > 0 && editor.[editor.Length-1] = '\\n' && line.PreviousLine <> null then\n                                    line.PreviousLine\n                                else\n                                    line\n                            line.Offset + editor.GetLineIndent(line.LineNumber).Length\n                        | false when editor.CaretOffset < editor.Length && editor.CaretOffset > 0 ->\n                            let charAtCaret = editor.[editor.CaretOffset]\n                            let previous = editor.[editor.CaretOffset - 1]\n\n                            if isEOLChar charAtCaret && not (isEOLChar previous) then\n                                editor.CaretOffset - 1\n                            else\n                                editor.CaretOffset\n                        | _ -> editor.CaretOffset\n                    editor.CaretOffset <- max offsetBeforeDelimiter 0\n                    newState\n                | Indent ->\n                    let line = editor.GetLineByOffset(finish)\n                    setSelection vimState editor command start line.EndOffset\n                    EditActions.IndentSelection editor\n                    editor.ClearSelection()\n                    vimState\n                | UnIndent ->\n                    let line = editor.GetLineByOffset(finish)\n                    setSelection vimState editor command start line.EndOffset\n                    EditActions.UnIndentSelection editor\n                    editor.ClearSelection()\n                    vimState\n                | EqualIndent ->\n                    // Always work top to bottom\n                    setSelection vimState editor command start finish\n                    dispatchCommand CodeFormatting.CodeFormattingCommands.FormatBuffer\n                    editor.ClearSelection()\n                    processCommands config 1 vimState (runOnce Move FirstNonWhitespace) false\n                | Substitute ->\n                    let newState = delete vimState start finish\n                    switchToInsertMode editor newState isInitial\n                | ToggleCase ->\n                    toggleCase vimState start finish\n                | DeleteWholeLines ->\n                    let min = min start finish\n                    let max = max start finish\n                    let start = editor.GetLineByOffset(min).Offset\n                    let finish = editor.GetLineByOffset(max).EndOffsetIncludingDelimiter\n                    delete vimState start finish\n                | DeleteLeft -> if editor.CaretColumn > 1 then delete vimState (editor.CaretOffset - 1) editor.CaretOffset else vimState\n                | Change ->\n                    let finish =\n                        if count <> 1 && editor.[finish] = ' ' then\n                            finish + 1\n                        else\n                            finish\n                    let state = delete vimState start finish\n                    switchToInsertMode editor state isInitial\n                | Yank register ->\n                    let finish =\n                        match command.textObject with\n                        | ForwardToEndOfWord\n                        | ForwardToEndOfWORD\n                        | EndOfLine\n                        | ToCharInclusive _\n                        | ToCharExclusive _ -> finish + 1\n                        | _ -> finish\n                    if command.textObject <> SelectedText then\n                        setSelection vimState editor command start finish\n                    registers.[register] <- getSelectedText vimState editor command\n                    if register = EmptyRegister then\n                        EditActions.ClipboardCopy editor\n                    editor.ClearSelection()\n                    match vimState.mode with\n                    | VisualModes -> editor.CaretOffset <- vimState.visualStartOffset\n                    | _ -> ()\n                    processCommands config 1 vimState (runOnce (SwitchMode NormalMode) Nothing) false\n                | Put Before ->\n                    if registers.[EmptyRegister].linewise then\n                        editor.CaretOffset <- editor.GetLine(editor.CaretLine).Offset\n                        EditActions.ClipboardPaste editor\n                        EditActions.MoveCaretUp editor\n                        EditActions.MoveCaretToLineStart editor\n                    else\n                        EditActions.ClipboardPaste editor\n                    vimState\n                | Put After ->\n                    if registers.[EmptyRegister].linewise then\n                        if editor.CaretLine = editor.LineCount then\n                            let line = editor.GetLine(editor.CaretLine)\n                            let delimiter = inferDelimiter editor\n                            match registers.[EmptyRegister].content with\n                            | StartsWithDelimiter _delimiter -> ()\n                            | _ -> editor.InsertText(editor.Length, delimiter)\n                            editor.CaretOffset <- editor.Length\n                            EditActions.ClipboardPaste editor\n                            if eofOnLine line then\n                                match registers.[EmptyRegister].content with\n                                | EndsWithDelimiter clipboardDelimiter ->\n                                    editor.RemoveText(editor.Length-clipboardDelimiter.Length, clipboardDelimiter.Length)\n                                | _ -> ()\n                            editor.CaretOffset <- line.Offset\n                            EditActions.MoveCaretDown editor\n                            EditActions.MoveCaretToLineStart editor\n                        else\n                            let line = editor.GetLine(editor.CaretLine)\n                            editor.CaretOffset <- line.EndOffsetIncludingDelimiter\n                            EditActions.ClipboardPaste editor\n                            editor.CaretOffset <- line.Offset\n                            EditActions.MoveCaretDown editor\n                            EditActions.MoveCaretToLineStart editor\n                    else\n                        EditActions.MoveCaretRight editor\n                        EditActions.ClipboardPaste editor\n                        EditActions.MoveCaretLeft editor\n                    vimState\n                | Put OverSelection ->\n                    EditActions.ClipboardPaste editor\n                    { vimState with mode = NormalMode }\n                | SelectionOtherEnd ->\n                    let offset = editor.CaretOffset\n                    editor.CaretOffset <- vimState.visualStartOffset\n                    let start, finish =\n                        if offset > vimState.visualStartOffset then\n                            vimState.visualStartOffset, offset + 1\n                        else\n                            offset, vimState.visualStartOffset + 1\n                    editor.SetSelection(start, finish)\n                    { vimState with visualStartOffset = offset }\n                | Visual ->\n                    editor.SetSelection(start, finish); vimState\n                | Undo -> EditActions.Undo editor; editor.ClearSelection(); vimState\n                | Redo -> EditActions.Redo editor; vimState\n                | JoinLines ->\n                    let lastColumn = editor.GetLine(editor.CaretLine).Length\n                    EditActions.JoinLines editor\n                    editor.CaretColumn <- lastColumn + 1\n                    vimState\n                | ReplaceChar c ->\n                    if editor.CaretOffset < editor.Length  && not (isEOLChar editor.[editor.CaretOffset]) then\n                        editor.SetSelection(editor.CaretOffset, editor.CaretOffset+1)\n                        EditActions.Delete editor\n                    match c with\n                    | StartsWithDelimiter _ ->\n                        EditActions.InsertNewLine editor\n                    | _ ->\n                        editor.InsertAtCaret c\n                        EditActions.MoveCaretLeft editor\n                    vimState\n                | SetMark c ->\n                    setMark c\n                    vimState\n                | InsertLine Before ->\n                    EditActions.InsertNewLineAtEnd editor\n                    vimState\n                | InsertLine After ->\n                    if editor.CaretLine = 1 then\n                        EditActions.MoveCaretToLineStart editor\n                        EditActions.InsertNewLine editor\n                        EditActions.MoveCaretUp editor\n                        vimState\n                    else\n                        EditActions.MoveCaretUp editor\n                        EditActions.InsertNewLineAtEnd editor\n                        vimState\n                | Dispatch command -> dispatchCommand command ; vimState\n                | ResetKeys -> { vimState with keys = [] }\n                | BlockInsert Before -> blockInsert min\n                | BlockInsert After -> blockInsert (fun s f -> (max s f) + 1)\n                | SwitchMode mode ->\n                    match mode with\n                    | NormalMode ->\n                        let state = switchToNormalMode editor vimState\n                        if vimState.mode = InsertMode then\n                            MonoDevelop.Ide.CodeCompletion.CompletionWindowManager.HideWindow ()\n                            processCommands config 1 state (runOnce (SetMark \".\") Nothing) false\n                        else\n                            state\n                    | VisualMode | VisualLineMode | VisualBlockMode ->\n                        setCaretMode editor Block\n                        let start, finish = VimHelpers.getRange config vimState editor command\n                        let statusMessage =\n                            match mode with\n                            | VisualMode -> Some \"-- VISUAL --\"\n                            | VisualLineMode -> Some \"-- VISUAL LINE --\"\n                            | VisualBlockMode -> Some \"-- VISUAL BLOCK --\"\n                            | _ -> None\n                        let newState = { vimState with mode = mode; visualStartOffset = editor.CaretOffset; statusMessage = statusMessage }\n                        setAutoCompleteOnKeystroke false\n                        setSelection newState editor command start finish\n                        match mode, editor.SelectionMode with\n                        | VisualBlockMode, SelectionMode.Normal -> EditActions.ToggleBlockSelectionMode editor\n                        | _, SelectionMode.Block -> EditActions.ToggleBlockSelectionMode editor\n                        | _ -> ()\n                        newState\n                    | InsertMode ->\n                        switchToInsertMode editor vimState isInitial\n                    | ReplaceMode ->\n                        let undoGroup =\n                            if isInitial\n                                then editor.OpenUndoGroup() |> Some\n                            else\n                                vimState.undoGroup\n\n                        { vimState with mode = ReplaceMode; statusMessage = \"-- REPLACE --\"|> Some; undoGroup = undoGroup }\n                    | ExMode c ->\n                        { vimState with mode = (ExMode c); statusMessage = string c |> Some }\n                | Star After ->\n                    match wordAtCaret editor with\n                    | Some word ->\n                        let matches = Regex.Matches(editor.Text, sprintf @\"\\b%s\\b\" word)\n                                      |> Seq.cast<Match>\n\n                        let m =\n                            matches\n                            |> Seq.tryFind(fun m -> m.Index > editor.CaretOffset)\n\n                        let offset =\n                            match m with\n                            | Some m -> m.Index\n                            | None ->\n                                let m = matches |> Seq.head\n                                m.Index\n                        editor.CaretOffset <- offset\n                        { vimState with lastSearch = Some (Jump (ToSearch word)) }\n                    | None ->\n                        processCommands config 1 vimState (runOnce Move WordForwards) isInitial\n                | Star Before ->\n                    match wordAtCaret editor with\n                    | Some word ->\n                        let matches = Regex.Matches(editor.Text, sprintf @\"\\b%s\\b\" word)\n                                      |> Seq.cast<Match>\n\n                        let start = findCurrentWordStart editor isWordChar\n\n                        let m =\n                            matches\n                            |> Seq.tryFindBack(fun m -> m.Index < start)\n\n                        let offset =\n                            match m with\n                            | Some m -> m.Index\n                            | None ->\n                                let m = matches |> Seq.last\n                                m.Index\n                        editor.CaretOffset <- offset\n                        { vimState with lastSearch = Some (Jump (ToSearchBackwards word)) }\n                    | None -> vimState\n                | InsertChar c ->\n                    match vimState.mode with\n                    | InsertMode ->\n                        processVimKey editor c\n                        vimState\n                    | _ -> vimState\n                | IncrementNumber -> modifyNumber (fun i -> i + 1)\n                | DecrementNumber -> modifyNumber (fun i -> i - 1)\n                | IncrementalSearch search ->\n                    findNextSearchOffset editor search editor.CaretOffset\n                    |> Option.iter(fun index ->\n                                       editor.SetSelection(index, index + search.Length)\n                                       editor.ScrollTo(index))\n                    vimState\n                | IncrementalSearchBackwards search ->\n                    findNextSearchOffsetBackwards editor search editor.CaretOffset\n                    |> Option.iter(fun index ->\n                                       editor.SetSelection(index, index + search.Length)\n                                       editor.ScrollTo(index))\n                    vimState\n                | SetSearchAction command -> { vimState with searchAction = Some command }\n                | MacroStart c ->\n                    macros.[c] <- []\n                    { vimState with macro = Macro (char c) |> Some }\n                | MacroEnd ->\n                    { vimState with macro = None }\n                | ReplayMacro c ->\n                    let getCount repeat = repeat |> Option.defaultValue 1\n\n                    let rec runMacro state actions =\n                        match actions with\n                        | [ only ] ->\n                            processCommands config (getCount only.repeat) state only false\n                        | h :: t ->\n                            let newState = processCommands config (getCount h.repeat) state h false\n                            runMacro newState t\n                        | [] -> state\n                    runMacro vimState macros.[c]\n                | NextTab ->\n                    Window.nextTab()\n                    vimState\n                | PreviousTab ->\n                    Window.previousTab()\n                    vimState\n                | Func f ->\n                    f()\n                    vimState\n                | EditorFunc f ->\n                    f editor\n                    vimState\n                | GotoPad padId ->\n                    Window.gotoPad padId\n                    vimState\n                | ChangeState s -> s\n                | DelayedFunc (f, ms) ->\n                    let token = new CancellationTokenSource()\n                    let work =\n                        async {\n                            do! Async.Sleep ms\n                            if (not token.IsCancellationRequested) then\n                                Runtime.RunInMainThread(fun _ -> f editor) |> ignore\n                        }\n                    Async.Start(work, token.Token)\n                    { vimState with insertModeCancellationTokenSource = Some token }\n                | CancelFunc ->\n                    vimState.insertModeCancellationTokenSource\n                    |> Option.iter(fun token -> token.Cancel())\n                    { vimState with insertModeCancellationTokenSource = None }\n                | _ -> vimState\n\n            match count with\n            | 1 -> newState\n            | _ -> processCommands config (count-1) newState command false\n        let count = command.repeat |> Option.defaultValue 1\n\n        processCommands config count vimState command true\n\n    let (|Digit|_|) character =\n        if character >= \"0\" && character <= \"9\" then\n            Some (Convert.ToInt32 character)\n        else\n            None\n\n    let (|OneToNine|_|) character =\n        if character >= \"1\" && character <= \"9\" then\n            Some (Convert.ToInt32 character)\n        else\n            None\n\n    let (|RegisterMatch|_|) = function\n        | c -> Some (Register (Char.Parse c))\n\n    let (|BlockDelimiter|_|) layout character =\n        let pairs =\n            [\n                \"[\", (\"[\", \"]\")\n                \"]\", (\"[\", \"]\")\n                \"(\", (\"(\", \")\")\n                \")\", (\"(\", \")\")\n                \"b\", (\"(\", \")\")\n                \"{\", (\"{\", \"}\")\n                \"}\", (\"{\", \"}\")\n                \"B\", (\"{\", \"}\")\n                \"<\", (\"<\", \">\")\n                \">\", (\"<\", \">\")\n            ] |> dict\n        let mappedChar = remap layout character\n        if pairs.ContainsKey mappedChar then\n            Some pairs.[mappedChar]\n        else\n            None\n\n    let (|QuoteDelimiter|_|) layout character =\n        let mappedChar = remap layout character\n        if Array.contains mappedChar [| \"\\\"\"; \"'\"; \"`\"|] then\n            Some mappedChar\n        else\n            None\n\n    let (|Movement|_|) layout keys =\n        let remappedKeys = keys |> List.map (fun k -> remap layout k)\n        match remappedKeys with\n        | [\"<left>\"]\n        | [\"h\"] -> Some Left\n        | [\"<down>\"]\n        | [\"j\"] -> Some Down\n        | [\"<up>\"]\n        | [\"k\"] -> Some Up\n        | [\"<right>\"]\n        | [\"l\"] -> Some (Right StopAtEndOfLine)\n        | [\" \"] -> Some (Right MoveToNextLineAtEnd)\n        | [\"$\"] -> Some EndOfLine\n        | [\"^\"] -> Some FirstNonWhitespace\n        | [\"0\"] -> Some StartOfLine\n        | [\"_\"] -> Some FirstNonWhitespace\n        | [\"w\"] -> Some WordForwards\n        | [\"W\"] -> Some WORDForwards\n        | [\"b\"] -> Some WordBackwards\n        | [\"B\"] -> Some WORDBackwards\n        | [\"e\"] -> Some ForwardToEndOfWord\n        | [\"E\"] -> Some ForwardToEndOfWORD\n        | [\"g\"; \"e\"] -> Some BackwardToEndOfWord\n        | [\"g\"; \"E\"] -> Some BackwardToEndOfWORD\n        | [\"{\"] -> Some (Jump ParagraphBackwards)\n        | [\"}\"] -> Some (Jump ParagraphForwards)\n        | [\"%\"] -> Some MatchingBrace\n        | [\"[\"; \"{\"] -> Some PrevUnmatchedBrace\n        | [\"]\"; \"}\"] -> Some NextUnmatchedBrace\n        | [\"[\"; \"(\"] -> Some PrevUnmatchedParen\n        | [\"]\"; \")\"] -> Some NextUnmatchedParen\n        | [\"G\"] -> Some (Jump LastLine)\n        | [\"H\"] -> Some (Jump FirstVisibleLine)\n        | [\"M\"] -> Some (Jump MiddleVisibleLine)\n        | [\"L\"] -> Some (Jump LastVisibleLine)\n        | [\"<C-d>\"] -> Some (Jump HalfPageDown)\n        | [\"<C-u>\"] -> Some (Jump HalfPageUp)\n        | [\"<C-f>\"] -> Some (Jump PageDown)\n        | [\"<C-b>\"] -> Some (Jump PageUp)\n        | [\"n\"] -> Some (Jump SearchAgain)\n        | [\"N\"] -> Some (Jump SearchAgainBackwards)\n        | [\"'\"; c] -> Some (Jump (ToMark (c, MarkerJumpType.StartOfLine)))\n        | [\"`\"; c] -> Some (Jump (ToMark (c, MarkerJumpType.Offset)))\n        | _ -> None\n\n    let unfinishedMovements = [ \"g\"; \"[\"; \"]\"; \"@\"; \"m\"; \"`\"; \"'\" ] |> set\n\n    let (|UnfinishedMovement|_|) layout character =\n        let remappedCharacter = remap layout character\n        if unfinishedMovements.Contains remappedCharacter then\n            Some UnfinishedMovement\n        else\n            None\n\n    let (|IndentChar|_|) layout key =\n        match remap layout key with\n        | \">\" -> Some Indent\n        | \"<\" -> Some UnIndent\n        | \"=\" -> Some EqualIndent\n        | _ -> None\n\n    let (|FindChar|_|) layout key =\n        match remap layout key with\n        | \"f\" -> Some ToCharInclusive\n        | \"F\" -> Some ToCharInclusiveBackwards\n        | \"t\" -> Some ToCharExclusive\n        | \"T\" -> Some ToCharExclusiveBackwards\n        | _ -> None\n\n    let (|SearchChar|_|) layout key =\n        match remap layout key with\n        | \"/\" -> Some (SearchChar '/')\n        | \"?\" -> Some (SearchChar '?')\n        | _ -> None\n\n    let (|Action|_|) layout key =\n        match remap layout key with\n        | \"d\" -> Some Delete\n        | \"c\" -> Some Change\n        | \"v\" -> Some Visual\n        | \"y\" -> Some (Yank EmptyRegister)\n        | \">\" -> Some Indent\n        | \"<\" -> Some UnIndent\n        | _ -> None\n\n    let (|ModeChange|_|) layout key =\n        match remap layout key with\n        | \"i\" -> Some InsertMode\n        | \"v\" -> Some VisualMode\n        | \"<C-v>\" -> Some VisualBlockMode\n        | \"<C-q>\" -> Some VisualBlockMode\n        | \"V\" -> Some VisualLineMode\n        | \"R\" -> Some ReplaceMode\n        | _ -> None\n\n    let (|Escape|_|) = function\n        | \"<esc>\" | \"<C-c>\" | \"<C-[>\" -> Some Escape\n        | _ -> None\n\n    let (|RemappedMatches|_|) layout matchList unmappedList = \n        let mappedList = unmappedList |> List.map (fun x -> remap layout x)\n        if mappedList = matchList then \n          Some matchList\n        else \n          None\n\n    let (|RemappedMatchesChar|_|) layout matchChar unmappedChar = //\n        let mappedChar = remap layout unmappedChar\n        if mappedChar = matchChar then \n          Some matchChar\n        else \n          None\n                \n    let getInsertModeEscapeCombo config =\n        match config.insertModeEscapeKey with\n        | Some combo ->\n            combo.insertModeEscapeKey1, combo.insertModeEscapeKey2, combo.insertModeEscapeTimeout\n        | None -> \"\", \"\", 0\n\n    let parseKeys (state:VimState) (config: Config) =\n        let layout = config.keyboardLayout;\n        let keyList = state.keys |> List.map string\n        let numericArgument, keyList =\n            match keyList, state.mode with\n            | \"r\" :: _, _\n            | [ _ ], ReplaceMode\n            | FindChar layout _ :: _, _ -> None, keyList\n            // 2dw -> 2, dw\n            | OneToNine d1 :: Digit d2 :: Digit d3 :: Digit d4 :: t, _ ->\n                Some (d1 * 1000 + d2 * 100 + d3 * 10 + d4), t\n            | OneToNine d1 :: Digit d2 :: Digit d3 :: t, _ ->\n                Some (d1 * 100 + d2 * 10 + d3), t\n            | OneToNine d1 :: Digit d2 :: t, _ ->\n                Some (d1 * 10 + d2), t\n            | OneToNine d :: t, _ -> Some (d), t\n            // d2w -> 2, dw\n            | c :: OneToNine d1 :: Digit d2 :: Digit d3 :: Digit d4 :: t, _ ->\n                Some (d1 * 1000 + d2 * 100 + d3 * 10 + d4), c::t\n            | c :: OneToNine d1 :: Digit d2 :: Digit d3 :: t, _ ->\n                Some (d1 * 100 + d2 * 10 + d3), c::t\n            | c :: OneToNine d1 :: Digit d2 :: t, _ ->\n                Some (d1 * 10 + d2), c::t\n            | c :: OneToNine d :: t, _ ->\n                Some d, c::t\n            | _ -> None, keyList\n\n        let run = getCommand numericArgument\n\n        let runInVisualMode actions = [ yield switchMode VisualMode; yield! actions; yield switchMode NormalMode ]\n        let runInVisualLineMode actions = [ yield switchMode VisualLineMode; yield! actions; yield switchMode NormalMode ]\n\n        LoggingService.LogDebug (sprintf \"%A %A\" state.mode keyList)\n        let newState =\n            match keyList with\n            | [ FindChar layout m; c ] -> { state with findCharCommand = run Move ( m c ) |> Some }\n            | _ -> state\n\n        let insertModeEscapeFirstChar, insertModeEscapeSecondChar, insertModeTimeout =\n            getInsertModeEscapeCombo config\n\n        let action =\n            match state.mode, keyList with\n            | VisualBlockMode, [ Escape ] -> [ switchMode NormalMode; run Move SelectionStart ]\n            | NormalMode, [ Escape ] -> [ yield! resetKeys; yield dispatch \"MonoDevelop.Ide.Commands.ViewCommands.FocusCurrentDocument\" ]\n            | _, [ Escape ] -> [ switchMode NormalMode ]\n            | InsertMode, [ c ] when c = insertModeEscapeFirstChar ->\n                delayedFunc (fun editor ->\n                                 editor.InsertAtCaret insertModeEscapeFirstChar\n                                 let oldState = editorStates.[editor.FileName]\n                                 editorStates.[editor.FileName] <- { oldState with keys = [] }  ) insertModeTimeout :: wait\n            | InsertMode, [ c1; c2 ] when c1 = insertModeEscapeFirstChar && c2 = insertModeEscapeSecondChar ->\n                [ run CancelFunc Nothing; switchMode NormalMode ]\n            | InsertMode, [ c; _ ] when c = insertModeEscapeFirstChar ->\n                [ run CancelFunc Nothing\n                  run (ChangeState { state with keys = [] }) Nothing\n                  typeChar (Key (char insertModeEscapeFirstChar)) ]\n            | NotInsertMode, RemappedMatches layout [ \"G\" ] _ ->\n                match numericArgument with\n                | Some lineNumber -> [ runOnce Move (Jump (StartOfLineNumber lineNumber)) ]\n                | None -> [ runOnce Move (Jump LastLine) ]\n            | NormalMode, [ IndentChar layout _ ] -> wait\n            | NormalMode, [ IndentChar layout _ ; RemappedMatchesChar layout \"g\" _ ] -> wait\n            | NormalMode, [ IndentChar layout indent; RemappedMatchesChar layout \"G\" _ ] ->\n                match numericArgument with\n                | Some lineNumber -> [ runOnce Indent (Jump (StartOfLineNumber lineNumber)) ]\n                | None -> [ runOnce indent (Jump LastLine) ]\n            | NormalMode, [ IndentChar layout indent; RemappedMatchesChar layout \"g\" _; RemappedMatchesChar layout \"g\" _ ] ->\n                let lineNumber = match numericArgument with Some n -> n | None -> 1\n                [ runOnce indent (Jump (StartOfLineNumber lineNumber)) ]\n            | NormalMode, RemappedMatches layout [ \">\"; \">\" ] _ -> [ run Indent WholeLine ]\n            | NormalMode, RemappedMatches layout [ \"<\"; \"<\" ] _ -> [ run UnIndent WholeLine ]\n            | NormalMode, RemappedMatches layout [ \"=\"; \"=\" ] _ -> [ run EqualIndent WholeLine ]\n            | NormalMode, RemappedMatches layout [ \"V\" ] _ ->\n                match numericArgument with\n                | Some lines -> [ switchMode VisualLineMode; getCommand (lines-1 |> Some) Move Down ]\n                | None -> [ switchMode VisualLineMode ]\n            | NormalMode, RemappedMatches layout [ \"v\" ] _ ->\n                match numericArgument with\n                | Some chars -> [ switchMode VisualMode; getCommand (chars-1 |> Some) Move (Right StopAtEndOfLine) ]\n                | None -> [ switchMode VisualMode ]\n            | NormalMode, RemappedMatches layout [ \"d\"; \"G\" ] _ -> [ runOnce DeleteWholeLines (Jump LastLine)]\n            | NormalMode, RemappedMatches layout [ \"d\"; \"j\" ] _ ->\n                let numberOfLines =\n                    match numericArgument with\n                    | Some lines -> lines\n                    | None -> 1\n                runInVisualLineMode [ getCommand (numberOfLines |> Some) Move Down; runOnce Delete SelectedText ]\n            | NormalMode, RemappedMatches layout [ \"d\"; \"k\" ] _ ->\n                let numberOfLines =\n                    match numericArgument with\n                    | Some lines -> lines\n                    | None -> 1\n                runInVisualLineMode [ getCommand (numberOfLines |> Some) Move Up; runOnce Delete SelectedText; ]\n            | NotInsertMode, [ (Action layout _) ; UnfinishedMovement layout _] -> wait\n            | NotInsertMode, [ UnfinishedMovement layout _ ] -> wait\n            | NormalMode, RemappedMatches layout [ \"d\"; \"g\"; \"g\" ] _ -> [ runOnce DeleteWholeLines (Jump StartOfDocument)]\n            | ReplaceMode, [ c ] -> [ run (ReplaceChar c) Nothing; run Move (Right IncludeDelimiter) ]\n            | NotInsertMode, Movement layout m -> [ run Move m ]\n            | NotInsertMode, [ FindChar layout m; c ] -> [ run Move (m c) ]\n            | NormalMode, IndentChar layout indent :: Movement layout m ->\n                match numericArgument with\n                | None -> [ run indent m ]\n                | Some lines ->\n                    runInVisualMode [ getCommand (lines-1 |> Some) Move Down; runOnce indent SelectedText ]\n            | NormalMode, Action layout action :: Movement layout m when numericArgument = None -> [ run action m ]\n            | NormalMode, Action layout action :: Movement layout m ->\n                match action, m with\n                | Delete, _\n                | Yank _, _ ->\n                    match m with\n                    | WordForwards -> runInVisualMode [ run Move ForwardToEndOfWord; runOnce Move (Right StopAtEndOfLine); runOnce action SelectedText; ]\n                    | WORDForwards -> runInVisualMode [ run Move ForwardToEndOfWORD; runOnce Move (Right StopAtEndOfLine); runOnce action SelectedText; ]\n                    | WordBackwards -> runInVisualMode [ runOnce Move Left; run Move ForwardToEndOfWord; runOnce action SelectedText; ]\n                    | WORDBackwards -> runInVisualMode [ runOnce Move Left; run Move ForwardToEndOfWORD; runOnce action SelectedText; ]\n                    | _ -> runInVisualMode [ run Move m; runOnce action SelectedText; ]\n                | _ -> [ run action m ]\n            | NormalMode, RemappedMatches layout [ \"u\" ] _ -> [ run Undo Nothing ]\n            | NormalMode, [ \"<C-r>\" ] -> [ run Redo Nothing ]\n            | NormalMode, RemappedMatches layout [ \"d\"; \"d\" ] _ ->\n                match numericArgument with\n                | None -> [ run Delete WholeLine ]\n                | Some lines ->\n                    [ switchMode VisualLineMode\n                      getCommand (lines-1 |> Some) Move Down\n                      runOnce Delete SelectedText\n                      switchMode NormalMode\n                      runOnce Move FirstNonWhitespace ]\n            | NormalMode, RemappedMatches layout [ \"c\"; \"c\" ] _ -> [ run Change WholeLine ]\n            | NormalMode, RemappedMatches layout [\"\\\"\"] _ -> wait\n            | NormalMode, [RemappedMatchesChar layout \"\\\"\" _; _ ] -> wait\n            | NormalMode, [RemappedMatchesChar layout \"\\\"\" _; _; RemappedMatchesChar layout \"y\" _ ] -> wait\n            | NormalMode, RemappedMatchesChar layout \"\\\"\" _ :: (RegisterMatch r) :: RemappedMatchesChar layout \"y\" _ :: (Movement layout m) -> [ run (Yank r) m]\n            | NormalMode, RemappedMatches layout [ \"y\"; \"y\" ] _\n            | NormalMode, RemappedMatches layout [ \"Y\" ] _ ->\n                match numericArgument with\n                | Some lines -> runInVisualLineMode [ getCommand (lines-1 |> Some) Move Down; runOnce (Yank EmptyRegister) SelectedText ]\n                | None -> [ runOnce (Yank EmptyRegister) WholeLineIncludingDelimiter ]\n            | NormalMode, RemappedMatches layout [ \"C\" ] _ -> [ run Change EndOfLine ]\n            | NormalMode, RemappedMatches layout [ \"D\" ] _ -> [ run Delete EndOfLine ]\n            | NormalMode, RemappedMatches layout [ \"x\" ] _ -> [ runOnce Delete (Character (numericArgument |> Option.defaultValue 1)) ]\n            | NormalMode, RemappedMatches layout [ \"X\" ] _ -> [ run DeleteLeft Nothing ]\n            | NormalMode, RemappedMatches layout [ \"s\" ] _ -> [ run Substitute CurrentLocation]\n            | NormalMode, RemappedMatches layout [ \"S\" ] _ -> [ run Delete WholeLine; runOnce (InsertLine After) Nothing; switchMode InsertMode ]\n            | NormalMode, RemappedMatches layout [ \"p\" ] _ -> [ run (Put After) Nothing ]\n            | NormalMode, RemappedMatches layout [ \"P\" ] _ -> [ run (Put Before) Nothing ]\n            | VisualModes, RemappedMatches layout [ \"p\" ] _ -> [ run (Put OverSelection) Nothing ]\n            | VisualModes, RemappedMatches layout [ \"P\" ] _ -> [ run (Put OverSelection) Nothing ]\n            | NormalMode, RemappedMatches layout [ \"J\" ] _ -> [ run JoinLines Nothing ]\n            | NotInsertMode, RemappedMatches layout [ \"*\" ] _ -> [ run (Star After) Nothing ]\n            | NotInsertMode, RemappedMatches layout [ \"#\" ] _ -> [ run (Star Before) Nothing ]\n            | NotInsertMode, RemappedMatches layout [ \"£\" ] _ -> [ run (Star Before) Nothing ]\n            | NotInsertMode, [ SearchChar layout c ] -> [ switchMode (ExMode (string c)); runOnce (SetSearchAction Move) Nothing ]\n            | VisualModes, RemappedMatches layout [ \":\" ] _ -> [ switchMode (ExMode \":'<,'>\") ]\n            | NotInsertMode, RemappedMatches layout [ \":\" ] _ -> [ switchMode (ExMode \":\") ]\n            | NotInsertMode, [ Action layout action; SearchChar layout c ] -> [ switchMode (ExMode (string c)); runOnce (SetSearchAction action) Nothing ]\n            | NormalMode, RemappedMatches layout [ \"z\"; \"z\" ] _ -> [ dispatch ViewCommands.CenterAndFocusCurrentDocument ]\n            | NormalMode, RemappedMatches layout [ \"z\"; ] _ -> wait\n            | NormalMode, [ \"<C-y>\" ] -> [ dispatch TextEditorCommands.ScrollLineUp ]\n            | NormalMode, [ \"<C-e>\" ] -> [ dispatch TextEditorCommands.ScrollLineDown ]\n            | NormalMode, [ \"<C-o>\" ] -> [ dispatch NavigationCommands.NavigateBack ]\n            | NormalMode, [ \"<C-i>\" ] -> [ dispatch NavigationCommands.NavigateForward ]\n            | NormalMode, RemappedMatches layout [ \"r\" ] _ -> wait\n            | NormalMode, [ RemappedMatchesChar layout \"r\" _; \"<ret>\" ] -> [ run (ReplaceChar \"\\n\" ) Nothing ]\n            | NormalMode, [ RemappedMatchesChar layout \"r\" _; c ] -> [ run (ReplaceChar c) Nothing ]\n            | NormalMode, [ RemappedMatchesChar layout \"m\" _; c ] -> [ run (SetMark c) Nothing ]\n            | NotInsertMode, [ Action layout action; FindChar layout m; c ] -> [ run action (m c) ]\n            | NotInsertMode, [ Action layout action; RemappedMatchesChar layout \"i\" _; BlockDelimiter layout c ] -> [ run action (InnerBlock c) ]\n            | NotInsertMode, [ Action layout action; RemappedMatchesChar layout \"a\" _; BlockDelimiter layout c ] -> [ run action (ABlock c) ]\n            | NotInsertMode, [ Action layout action; RemappedMatchesChar layout \"i\" _; QuoteDelimiter layout c ] -> [ run action (InnerQuotedBlock (char c)) ]\n            | NotInsertMode, [ Action layout action; RemappedMatchesChar layout \"a\" _; QuoteDelimiter layout c ] -> [ run action (AQuotedBlock (char c)) ]\n            | NotInsertMode, [ Action layout action; RemappedMatchesChar layout \"i\" _; RemappedMatchesChar layout \"w\" _ ] -> [ run action InnerWord ]\n            | NotInsertMode, [ Action layout action; RemappedMatchesChar layout \"a\" _; RemappedMatchesChar layout \"w\" _ ] -> [ run action AWord ]\n            | NotInsertMode, [ Action layout action; RemappedMatchesChar layout \"i\" _; RemappedMatchesChar layout \"W\" _ ] -> [ run action InnerWORD ]\n            | NotInsertMode, [ Action layout action; RemappedMatchesChar layout \"a\" _; RemappedMatchesChar layout \"W\" _ ] -> [ run action AWORD ]\n            | NotInsertMode, [ Action layout action; RemappedMatchesChar layout \"a\" _; RemappedMatchesChar layout \"t\" _ ] -> [ run action ATag ]\n            | NotInsertMode, [ Action layout action; RemappedMatchesChar layout \"i\" _; RemappedMatchesChar layout \"t\" _ ] -> [ run action InnerTag ]\n            | VisualMode, RemappedMatches layout [ \"i\"; \"w\" ] _ -> [ run Visual InnerWord ]\n            | VisualMode, RemappedMatches layout [ \"a\"; \"w\" ] _ -> [ run Visual AWord ]\n            | VisualMode, RemappedMatches layout [ \"i\"; \"W\" ] _ -> [ run Visual InnerWORD ]\n            | VisualMode, RemappedMatches layout [ \"a\"; \"W\" ] _ -> [ run Visual AWORD ]\n            | VisualMode, RemappedMatches layout [ \"a\"; \"t\" ] _ -> [ run Visual ATag ]\n            | VisualMode, RemappedMatches layout [ \"i\"; \"t\" ] _ -> [ run Visual InnerTag ]\n            | VisualMode, RemappedMatches layout [ \"u\"] _ -> [ dispatch EditCommands.LowercaseSelection ]\n            | VisualMode, RemappedMatches layout [ \"U\"] _ -> [ dispatch EditCommands.UppercaseSelection ]\n            | NormalMode, [ ModeChange layout mode ] -> [ switchMode mode ]\n            | NormalMode, RemappedMatches layout [ \"a\" ] _ -> [ run Move (Right IncludeDelimiter); switchMode InsertMode ]\n            | NormalMode, RemappedMatches layout [ \"A\" ] _ -> [ run Move EndOfLineIncludingDelimiter; switchMode InsertMode ]\n            | NormalMode, RemappedMatches layout [ \"O\" ] _ -> [ run (InsertLine After) Nothing; switchMode InsertMode ]\n            | NormalMode, RemappedMatches layout [ \"o\" ] _ -> [ run (InsertLine Before) Nothing; switchMode InsertMode ]\n            | NormalMode, RemappedMatches layout [ \"I\" ] _ -> [ run Move FirstNonWhitespace; switchMode InsertMode ]\n            | NormalMode, [ Action layout _ ] -> wait\n            | NotInsertMode, [ Action layout _; RemappedMatchesChar layout \"i\" _ ] -> wait\n            | NotInsertMode, [ Action layout _; \"a\" ] -> wait\n            | VisualMode, RemappedMatches layout [ \"i\" ] _ | VisualMode, [ \"a\" ] -> wait\n            | NotInsertMode, [ FindChar layout _; ] -> wait\n            | NotInsertMode, [ Action layout _; FindChar layout _; ] -> wait | NotInsertMode, [ \"<ret>\" ] -> [ run Move Down; run Move FirstNonWhitespace ]\n            | NotInsertMode, RemappedMatches layout [ \"q\" ] _ when state.macro.IsNone -> wait\n            | NotInsertMode, [ RemappedMatchesChar layout \"q\" _; c ] -> [ run (MacroStart (char c)) Nothing ]\n            | NotInsertMode, RemappedMatches layout [ \"q\" ] _ -> [ run MacroEnd Nothing ]\n            | NotInsertMode, [ \"@\"; c ] -> [ run (ReplayMacro (char c)) Nothing ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"g\" ] _ ->\n                let lineNumber = match numericArgument with Some n -> n | None -> 1\n                [ runOnce Move (Jump (StartOfLineNumber lineNumber)) ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"d\" ] _ -> [ dispatch \"MonoDevelop.Refactoring.RefactoryCommands.GotoDeclaration\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"u\" ] _ -> [ dispatch \"MonoDevelop.Refactoring.RefactoryCommands.FindReferences\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"b\" ] _ -> [ dispatch \"MonoDevelop.RefactoryCommands.NavigationCommands.FindBaseSymbols\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"t\" ] _ -> [ func Window.nextTab ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"T\" ] _ -> [ func Window.previousTab ]\n            | NotInsertMode, RemappedMatches layout [ \"z\"; \"z\" ] _ -> [ dispatch TextEditorCommands.RecenterEditor ]\n            | NotInsertMode, RemappedMatches layout [ \"z\"; \"a\" ] _ -> [ dispatch EditCommands.ToggleAllFoldings ]\n            | NotInsertMode, RemappedMatches layout [ \"z\"; \"o\" ] _ -> [ dispatch EditCommands.ToggleFolding ]\n            | NotInsertMode, RemappedMatches layout [ \"z\"; \"c\" ] _ -> [ dispatch EditCommands.ToggleFolding ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"h\" ] _ -> [ dispatch TextEditorCommands.ShowQuickInfo ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"v\" ] _ ->\n                match state.lastSelection with\n                | Some selection -> [ run Move (Offset selection.start)\n                                      switchMode selection.mode\n                                      run Move (Offset selection.finish) ]\n                | None -> resetKeys\n            | NotInsertMode, RemappedMatches layout [ \".\" ] _ -> state.lastAction @ [ switchMode NormalMode ]\n            | NotInsertMode, RemappedMatches layout [ \";\" ] _ -> match state.findCharCommand with Some command -> [ command ] | None -> []\n            | NotInsertMode, RemappedMatches layout [ \",\" ] _ ->\n                match state.findCharCommand with\n                | Some command ->\n                    let findCommand =\n                        match command.textObject with\n                        | ToCharInclusive c -> ToCharInclusiveBackwards c\n                        | ToCharInclusiveBackwards c -> ToCharInclusive c\n                        | ToCharExclusive c -> ToCharExclusiveBackwards c\n                        | ToCharExclusiveBackwards c -> ToCharExclusive c\n                        | _ -> failwith \"Invalid find command\"\n                    [ { command with textObject=findCommand } ]\n                | None -> []\n            | VisualModes, Movement layout m -> [ run Move m ]\n            | VisualBlockMode, RemappedMatches layout [ \"I\" ] _ -> [ run (BlockInsert Before) Nothing ]\n            | VisualBlockMode, [ \"A\" ] -> [ run (BlockInsert After) Nothing ]\n            | VisualModes, [ RemappedMatchesChar layout \"i\" _; BlockDelimiter layout c ] -> [ run Visual (InnerBlock c) ]\n            | VisualModes, [ \"a\"; BlockDelimiter layout c ] -> [ run Visual (ABlock c) ]\n            | VisualModes, [ RemappedMatchesChar layout \"i\" _; QuoteDelimiter layout c ] -> [ run Visual (InnerQuotedBlock (char c)) ]\n            | VisualModes, [ \"a\"; QuoteDelimiter layout c ] -> [ run Visual (AQuotedBlock (char c)) ]\n            | VisualModes, RemappedMatches layout [ \"x\" ] _ -> [ run Delete SelectedText; switchMode NormalMode ]\n            | VisualModes, RemappedMatches layout [ \"d\" ] _ -> [ run Delete SelectedText; switchMode NormalMode ]\n            | VisualModes, RemappedMatches layout [ \"D\" ] _ -> [ run Delete EndOfLine; switchMode NormalMode ]\n            | VisualModes, RemappedMatches layout [ \"c\" ] _\n            | VisualModes, RemappedMatches layout [ \"s\" ] _ -> [ run Change SelectedText ]\n            | VisualModes, RemappedMatches layout [ \"o\" ] _ -> [ run SelectionOtherEnd Nothing ]\n            | NormalMode, [ \"~\" ] -> [ run ToggleCase CurrentLocation ]\n            | VisualModes, [ \"~\" ] -> [ run ToggleCase SelectedText; switchMode NormalMode ]\n            | VisualModes, RemappedMatches layout [ \"y\" ] _ -> [ run (Yank EmptyRegister) SelectedText; switchMode NormalMode ]\n            | VisualModes, RemappedMatches layout [ \"Y\" ] _ -> [ run (Yank EmptyRegister) WholeLine; switchMode NormalMode ]\n            | VisualModes, RemappedMatches layout [ \">\" ] _ -> [ run (EditorFunc EditActions.IndentSelection) Nothing; switchMode NormalMode ]\n            | VisualModes, RemappedMatches layout [ \"<\" ] _ -> [ run (EditorFunc EditActions.UnIndentSelection) Nothing; switchMode NormalMode ]\n            | VisualModes, RemappedMatches layout [ \"=\" ] _ -> [ run EqualIndent SelectedText; switchMode NormalMode ]\n            | NotInsertMode, RemappedMatches layout [ \"Z\" ] _ -> wait\n            | NotInsertMode, RemappedMatches layout  [\"Z\"; \"Z\" ] _ -> [ func Window.closeTab ]\n            | NotInsertMode, [ \"<C-p>\" ] -> [ dispatch SearchCommands.GotoFile ]\n            | NotInsertMode, [ \"<C-w>\" ] -> wait\n            | NotInsertMode, [ \"<C-w>\"; \"w\" ]\n            | NotInsertMode, [ \"<C-w>\"; \"<C-w>\" ] -> [ func Window.switchWindow ]\n            | NotInsertMode, [ \"<C-w>\"; \"h\" ] -> [ func Window.leftWindow ]\n            | NotInsertMode, [ \"<C-w>\"; \"l\" ] -> [ func Window.rightWindow ]\n            // These commands don't work the same way as vim yet, but better than nothing\n            | NotInsertMode, [ \"<C-w>\"; \"o\" ] -> [ dispatch FileTabCommands.CloseAllButThis ]\n            | NotInsertMode, [ \"<C-w>\"; \"c\" ] -> [ func Window.closeTab ]\n            | NotInsertMode, [ \"<C-w>\"; \"v\" ]\n            | NotInsertMode, [ \"<C-w>\"; \"s\" ]\n            | NotInsertMode, [ \"<C-w>\"; \"<C-v>\" ]\n            | NotInsertMode, [ \"<C-w>\"; \"<C-s>\" ] ->\n                let notebooks = Window.getNotebooks()\n                if notebooks.Length < 2 then\n                    [ dispatch \"MonoDevelop.Ide.Commands.ViewCommands.SideBySideMode\" ]\n                else\n                    resetKeys\n            | InsertMode, [ \"<C-n>\" ] -> [ dispatch TextEditorCommands.DynamicAbbrev ]\n            | NotInsertMode, [ \"<C-a>\" ] -> [ run IncrementNumber Nothing; switchMode NormalMode ]\n            | NotInsertMode, [ \"<C-x>\" ] -> [ run DecrementNumber Nothing; switchMode NormalMode ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\" ] _ -> wait\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"s\" ] _ -> [ gotoPad \"ProjectPad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"c\" ] _ -> [ gotoPad \"ClassPad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"e\" ] _ -> [ gotoPad \"MonoDevelop.Ide.Gui.Pads.ErrorListPad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"t\" ] _ -> [ gotoPad \"MonoDevelop.Ide.Gui.Pads.TaskListPad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"p\" ] _ -> [ gotoPad \"MonoDevelop.DesignerSupport.PropertyPad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"o\" ] _ -> [ gotoPad \"MonoDevelop.DesignerSupport.DocumentOutlinePad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"b\" ] _ -> [ gotoPad \"MonoDevelop.Debugger.BreakpointPad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"l\" ] _ -> [ gotoPad \"MonoDevelop.Debugger.LocalsPad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"w\" ] _ -> [ gotoPad \"MonoDevelop.Debugger.WatchPad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"i\" ] _ -> [ gotoPad \"MonoDevelop.Debugger.ImmediatePad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"n\" ] _ -> [ gotoPad \"MonoDevelop.FSharp.FSharpInteractivePad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"f\" ] _ ->\n                let searchResultPads = IdeApp.Workbench.Pads |> Seq.filter(fun p -> p.Content :? MonoDevelop.Ide.FindInFiles.SearchResultPad)\n                match searchResultPads |> Seq.length with\n                | 0 -> resetKeys\n                | 1 -> [ gotoPad \"SearchPad - Search Results - 0\" ]\n                | _ -> wait\n            | NotInsertMode, [ RemappedMatchesChar layout \"g\" _; RemappedMatchesChar layout \"p\" _; RemappedMatchesChar layout \"f\" _; OneToNine d ] ->\n                [ gotoPad (sprintf \"SearchPad - Search Results - %d\" (d-1)) ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"d\" ] _ -> wait\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"d\"; \"t\" ] _ -> [ gotoPad \"MonoDevelop.Debugger.ThreadsPad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"d\"; \"s\" ] _ -> [ gotoPad \"MonoDevelop.Debugger.StackTracePad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"d\"; \"c\" ] _ -> [ gotoPad \"MonoDevelop.Debugger.StackTracePad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"u\" ] _ -> wait\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"u\"; \"t\" ] _ -> [ gotoPad \"MonoDevelop.UnitTesting.TestPad\" ]\n            | NotInsertMode, RemappedMatches layout [ \"g\"; \"p\"; \"u\"; \"r\" ] _-> [ gotoPad \"MonoDevelop.UnitTesting.TestResultsPad\" ]\n            | _, [] when numericArgument.IsSome  -> wait\n            | _ -> resetKeys\n        action, newState\n\n    let keyPressToVimKey (keyPress:KeyDescriptor) =\n        match keyPress.KeyChar with\n        | c when keyPress.ModifierKeys = ModifierKeys.Control ->\n            Control c\n        | c when keyPress.ModifierKeys = ModifierKeys.Command ->\n            Super c\n        | 'z' when keyPress.ModifierKeys = ModifierKeys.Command ->\n            Key 'u'\n        | c when keyPress.KeyChar <> '\\000' ->\n            Key c\n        | _ ->\n            match keyPress.SpecialKey with\n            | SpecialKey.Escape -> Esc\n            | SpecialKey.Return -> Ret\n            | SpecialKey.Left -> VimKey.Left\n            | SpecialKey.Down -> VimKey.Down\n            | SpecialKey.Up -> VimKey.Up\n            | SpecialKey.Right -> VimKey.Right\n            | SpecialKey.BackSpace -> Backspace\n            | SpecialKey.Delete -> VimKey.Delete\n            | _ -> Key keyPress.KeyChar\n\n    let handleKeyPress state (keyPress:KeyDescriptor) (editor:TextEditor) config =\n        let fileName = editor.FileName\n        let vimKey =\n            match state.mode, keyPress.KeyChar, config.insertModeEscapeKey with\n            | InsertMode, c, Some combo when (string c) = combo.insertModeEscapeKey1 ->\n                EscapeKey c\n            | InsertMode, c, Some combo when state.keys |> List.tryHead = Some (Key (char combo.insertModeEscapeKey1)) ->\n                EscapeKey c\n            | _ -> keyPressToVimKey keyPress\n\n        let newState = { state with keys = state.keys @ [ vimKey ] }\n        let action, newState = parseKeys newState config\n        let newState =\n            match state.statusMessage, state.mode, newState.mode with\n            | Some _, NormalMode, NormalMode -> { newState with statusMessage = None }\n            | _ -> newState\n\n        LoggingService.LogDebug (sprintf \"%A\" action)\n\n        let rec performActions config actions' state handled =\n            match actions' with\n            | [] -> state, handled\n            | [ only ] ->\n                match only.commandType with\n                | DoNothing -> state, true\n                | _ ->\n                    let newState = runCommand config state editor only\n                    { newState with keys = [] }, true\n            | h::t ->\n                let newState = runCommand config state editor h\n                performActions config t newState true\n\n        let newState, handled =\n            let processKey() =\n                use group = editor.OpenUndoGroup()\n                state.macro\n                |> Option.iter(fun (Macro c) -> macros.[c] <- macros.[c] @ action)\n                performActions config action newState false\n\n            match state.mode, newState.keys |> List.map string with\n            | ExMode _, [ Escape ] -> processKey()\n            | ExMode _, _ ->\n                let state, actions = exMode.processKey state keyPress\n                performActions config actions state true\n            | _ -> processKey()\n\n        let firstAction = action |> List.head\n\n        let newState =\n            match config.keyboardLayout, state.mode, vimKey, firstAction.commandType with\n            | _, InsertMode, _, _ ->\n                newState.macro |> Option.iter(fun (Macro m) ->\n                    macros.[m] <- macros.[m] @ [ typeChar vimKey ])\n                //{ newState with lastAction = newState.lastAction @ [ typeChar vimKey ]}\n                newState\n            | _, NotInsertMode, _, SwitchMode VisualModes\n            | _, NotInsertMode, _, Delete\n            | _, NotInsertMode, _, Change\n            | _, NotInsertMode, _, Indent\n            | _, NotInsertMode, _, UnIndent\n            | _, NotInsertMode, _, Put _\n            | _, NotInsertMode, _, ReplaceChar _\n            | Qwerty, NotInsertMode, Key 'a', _\n            | Qwerty, NotInsertMode, Key 'i', _\n            | Qwerty, NotInsertMode, Key 'I', _\n            | Qwerty, NotInsertMode, Key 'o', _\n            | Qwerty, NotInsertMode, Key 'O', _\n            | Qwerty, NotInsertMode, Key 'A', _\n            | Colemak, NotInsertMode, Key 'a', _\n            | Colemak, NotInsertMode, Key 'u', _\n            | Colemak, NotInsertMode, Key 'U', _\n            | Colemak, NotInsertMode, Key 'y', _\n            | Colemak, NotInsertMode, Key 'Y', _\n            | Colemak, NotInsertMode, Key 'A', _\n            | Dvorak, NotInsertMode, Key 'a', _\n            | Dvorak, NotInsertMode, Key 'c', _\n            | Dvorak, NotInsertMode, Key 'C', _\n            | Dvorak, NotInsertMode, Key 'r', _\n            | Dvorak, NotInsertMode, Key 'R', _\n            | Dvorak, NotInsertMode, Key 'A', _-> { newState with lastAction = action }\n            | _ -> newState\n\n        editorStates.[fileName] <- newState\n        newState, handled\n"
  },
  {
    "path": "XSVim/XSVim.fsproj",
    "content": "﻿<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{9DB313D4-4CD1-455F-846F-42CD234DE626}</ProjectGuid>\n    <OutputType>Library</OutputType>\n    <RootNamespace>XSVim</RootNamespace>\n    <AssemblyName>XSVim</AssemblyName>\n    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>\n    <UseMSBuildEngine>false</UseMSBuildEngine>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>portable</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug</OutputPath>\n    <DefineConstants>DEBUG</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <PlatformTarget></PlatformTarget>\n    <StartAction>Program</StartAction>\n    <OtherFlags>--warnon:1182</OtherFlags>\n    <StartAction>Program</StartAction>\n    <StartProgram>/Applications/Visual Studio.app/Contents/Resources/lib/monodevelop/bin/VisualStudio.exe</StartProgram>\n    <StartWorkingDirectory>/Applications/Visual Studio.app/Contents/Resources/lib/monodevelop/bin</StartWorkingDirectory>\n    <Commandlineparameters>-no-redirect</Commandlineparameters>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>portable</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release</OutputPath>\n    <DefineConstants></DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <GenerateTailCalls>true</GenerateTailCalls>\n    <PlatformTarget></PlatformTarget>\n  </PropertyGroup>\n  <PropertyGroup>\n    <FSharpTargetsPath>$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\FSharp\\Microsoft.FSharp.Targets</FSharpTargetsPath>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"MonoDevelop.SourceEditor\">\n      <HintPath>..\\lib\\MonoDevelop.SourceEditor.dll</HintPath>\n      <Private>False</Private>\n    </Reference>\n    <Reference Include=\"MonoDevelop.Core\">\n      <HintPath>..\\lib\\MonoDevelop.Core.dll</HintPath>\n      <Private>False</Private>\n    </Reference>\n    <Reference Include=\"MonoDevelop.Ide\">\n      <HintPath>..\\lib\\MonoDevelop.Ide.dll</HintPath>\n      <Private>False</Private>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f\" />\n    <Reference Include=\"Mono.Addins\">\n      <HintPath>..\\lib\\Mono.Addins.dll</HintPath>\n      <Private>False</Private>\n    </Reference>\n    <Reference Include=\"glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f\" />\n    <Reference Include=\"gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f\" />\n    <Reference Include=\"System.Collections.Immutable\">\n      <HintPath>..\\lib\\System.Collections.Immutable.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Xamarin.Mac\">\n      <HintPath>..\\lib\\Xamarin.Mac.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Xwt\">\n      <HintPath>..\\lib\\Xwt.dll</HintPath>\n    </Reference>\n    <Reference Include=\"atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f\" />\n    <Reference Include=\"pango-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f\" />\n    <Reference Include=\"Mono.Cairo\" />\n    <Reference Include=\"FSharp.Core\">\n      <HintPath>..\\packages\\FSharp.Core.4.5.4\\lib\\net45\\FSharp.Core.dll</HintPath>\n    </Reference>\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"Properties\\AssemblyInfo.fs\" />\n    <Compile Include=\"Properties\\AddinInfo.fs\" />\n    <EmbeddedResource Include=\"Properties\\Manifest.addin.xml\" />\n    <Compile Include=\"SettingsPanel.fs\" />\n    <Compile Include=\"Reflection.fs\" />\n    <Compile Include=\"Classes.fs\" />\n    <Compile Include=\"Types.fs\" />\n    <Compile Include=\"WindowManagement.fs\" />\n    <Compile Include=\"SubstituteCommand.fs\" />\n    <Compile Include=\"ExMode.fs\" />\n    <Compile Include=\"PadTreeViews.fs\" />\n    <Compile Include=\"TreeViewPads.fs\" />\n    <Compile Include=\"Mapping.fs\" />\n    <Compile Include=\"XSVim.fs\" />\n    <Compile Include=\"Addin.fs\" />\n    <EmbeddedResource Include=\"KeyBindingSchemeVim.xml\" />\n    <None Include=\"packages.config\" />\n  </ItemGroup>\n  <Import Project=\"$(FSharpTargetsPath)\" />\n</Project>"
  },
  {
    "path": "XSVim/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"FSharp.Core\" version=\"4.5.4\" targetFramework=\"net472\" />\n</packages>"
  },
  {
    "path": "XSVim.Tests/ChangeTests.fs",
    "content": "﻿namespace XSVim.Tests\nopen NUnit.Framework\nopen System.Runtime.CompilerServices\nopen System.Threading.Tasks\n\n[<TestFixture>]\nmodule ``Change tests`` =\n    [<SetUp;AsyncStateMachine(typeof<Task>)>]\n    let ``run before tests``() =\n        FixtureSetup.initialiseMonoDevelop()\n\n    [<Test>]\n    let ``cc non empty line``() =\n        assertText \"abc\\nd$ef\\nghi\" \"cc\" \"abc\\n|\\nghi\"\n\n    [<Test>]\n    let ``cw changes word``() =\n        assertText \"a$bc    def\" \"cw\" \"|    def\"\n\n    [<Test>]\n    let ``C changes last character``() =\n        assertText \"abc$\" \"C\" \"ab|\"\n\n    [<Test>]\n    let ``cw changes space``() =\n        assertText \"abc $def\" \"cw\" \"abc|def\"\n\n    [<Test>]\n    let ``c2w changes two words``() =\n        assertText \"a$bc def ghi\" \"c2w\" \"| ghi\"\n\n    [<Test>]\n    let ``undo works after cw``() =\n        assertText \"a$bc def ghi\" \"cw<esc>u\" \"a$bc def ghi\"\n\n    [<Test>]\n    let ``undo works after c2w``() =\n        assertText \"a$bc def ghi\" \"c2w<esc>u\" \"a$bc def ghi\"\n\n    [<Test>]\n    let ``ce changes word``() =\n        assertText \"a$bc def\" \"ce\" \"| def\"\n\n    [<Test>]\n    let ``ce changes last character``() =\n        assertText \"a$ bcd\" \"ce\" \"| bcd\"\n\n    [<Test>]\n    let ``c% changes to matching parens``() =\n        assertText \"abc($def)ghi\" \"c%\" \"abc|ghi\"\n\n    [<Test>]\n    let ``Change to end of word does not include dot``() =\n        assertText \"open Mon$o.Addins\" \"ce\" \"open Mo|.Addins\"\n\n    [<Test>]\n    let ``Change to end of word includes dot``() =\n        assertText \"open Mono$.Addins\" \"ce\" \"open Mon|Addins\"\n\n    [<Test>]\n    let ``cc empty line``() =\n        assertText \"abc\\n\\n$def\" \"cc\" \"abc\\n|\\ndef\"\n\n    [<Test>]\n    let ``ci backtick``() =\n        assertText \"``some t$ext``\" \"ci`\" \"``|``\"\n\n    [<Test>]\n    let ``S changes entire line``() =\n        assertText \" line1 \\n line2$ \\n line3 \" \"S\" \" line1 \\n |\\n line3 \"\n\n    [<Test>]\n    let ``2S changes two lines``() =\n        assertText \" line1 \\n line2$ \\n line3 \\n line4 \" \"2S\" \" line1 \\n |\\n line4 \"\n\n    [<Test>]\n    let ``s before the end of line``() =\n        assertText \"a$b\" \"s\" \"|b\"\n\n    [<Test>]\n    let ``s at the end of line``() =\n        assertText \"ab$\\n\" \"s\" \"a|\\n\"\n"
  },
  {
    "path": "XSVim.Tests/DeleteTests.fs",
    "content": "﻿namespace XSVim.Tests\nopen NUnit.Framework\nopen System.Runtime.CompilerServices\nopen System.Threading.Tasks\n\n[<TestFixture>]\nmodule ``Delete tests`` =\n    [<SetUp;AsyncStateMachine(typeof<Task>)>]\n    let ``run before tests``() =\n        FixtureSetup.initialiseMonoDevelop()\n\n    [<Test>]\n    let ``Vjd test``() =\n        let source =\n            @\"aaaaaa\n              bb$bbbb\n              cccccc\n              dddddd\n              eeeeee\";\n\n        let expected =\n            @\"aaaaaa\n              d$ddddd\n              eeeeee\";\n        assertText source \"Vjd\" expected\n\n    [<Test>]\n    let ``Delete line and line below``() =\n        let source =\n            @\"aaaaaa\n              bb$bbbb\n              cccccc\n              dddddd\n              eeeeee\";\n\n        let expected =\n            @\"aaaaaa\n              d$ddddd\n              eeeeee\";\n        assertText source \"dj\" expected\n\n    [<Test>]\n    let ``Delete line and next two lines``() =\n        let source =\n            @\"aaaaaa\n              bb$bbbb\n              cccccc\n              dddddd\n              eeeeee\";\n\n        let expected =\n            @\"aaaaaa\n              e$eeeee\";\n        assertText source \"d2j\" expected\n\n    [<Test>]\n    let ``dd first line``() =\n        assertText \"ab$c\\n  def\" \"dd\" \"  d$ef\"\n\n    [<Test>]\n    let ``dd next line is blank``() =\n        assertText\n\n            \"\"\"\n{\n    fo$o\n\n    bar\n}\n            \"\"\"\n\n            \"dd\"\n// $ is over \\n here\n            \"\"\"\n{\n\n$    bar\n}\n            \"\"\"\n\n    [<Test>]\n    let ``2dd deletes 2 lines``() =\n        assertText \"ab$c\\ndef\\nghi\" \"2dd\" \"g$hi\"\n\n    [<Test>]\n    let ``2ddp puts 2 lines back``() =\n        assertText \"abc\\nde$f\\nghi\" \"2ddp\" \"abc\\nd$ef\\nghi\"\n\n    [<Test>]\n    let ``dd last line at EOF``() =\n        assertText \"abc\\ndef\\ngh$i\" \"dd\" \"abc\\nd$ef\"\n\n    [<Test>]\n    let ``dd only line``() =\n        assertText \"a$bc\" \"dd\" \"$\"\n\n    [<Test>]\n    let ``Delete char under caret``() =\n        assertText \"abc$def\" \"x\" \"abd$ef\"\n\n    [<Test>]\n    let ``Delete char at EOL``() =\n        assertText \"abcdef$\\n\" \"xx\" \"abcd$\\n\"\n\n    [<Test>]\n    let ``x with multiplier stops at EOL (caret at EOL)``() =\n        assertText \"abcdef$\\n\" \"4x\" \"abcde$\\n\"\n\n    [<Test>]\n    let ``x with multiplier stops at EOL``() =\n        assertText \"ab$cdef\\n\" \"100x\" \"a$\\n\"\n\n    [<Test>]\n    let ``Delete char to left of caret``() =\n        assertText \"abc$def\" \"X\" \"ac$def\"\n\n    [<Test>]\n    let ``Delete to end of line``() =\n        assertText \"abc$ def\\nghi\" \"d$\" \"ab$\\nghi\"\n\n    [<Test>]\n    let ``Delete to end of document``() =\n        assertText \"abc\\nde$f\\nghi\" \"dG\" \"abc\\n$\"\n\n    [<Test>]\n    let ``Delete to start of document``() =\n        assertText \"abc\\nde$f\\nghi\" \"dgg\" \"g$hi\"\n\n    [<Test>]\n    let ``Delete to end of line using D``() =\n        assertText \"abc$ def\\nghi\" \"D\" \"ab$\\nghi\"\n\n    [<Test>]\n    let ``Delete to end of line from start keeps caret on current line``() =\n        assertText \"abc\\nd$ef\\nghi\" \"D\" \"abc\\n\\n$ghi\"\n\n    [<Test>]\n    let ``Deletes word``() =\n        assertText \"a$bc     def\" \"dw\" \"d$ef\"\n\n    [<Test>]\n    let ``Delete to end of word``() =\n        assertText \"ab$c def\" \"de\" \"a $def\"\n\n    [<Test>]\n    let ``Delete to end of word does not include dot``() =\n        assertText \"open Mon$o.Addins\" \"de\" \"open Mo.$Addins\"\n\n    [<Test>]\n    let ``Delete to end of word includes dot``() =\n        assertText \"open Mono$.Addins\" \"de\" \"open MonA$ddins\"\n\n    [<Test>]\n    let ``Delete word does not include dot``() =\n        assertText \"open Mo$no.Addins\" \"dw\" \"open M.$Addins\"\n\n    [<Test>]\n    let ``Delete to end of WORD``() =\n        assertText \"ab$c.def ghi\" \"dE\" \"a $ghi\"\n\n    [<Test>]\n    let ``Deleting last word doesn't delete delimiter'``() =\n        assertText \"abc d$ef  \\nghi\" \"dw\" \"abc $\\nghi\"\n\n    [<Test>]\n    let ``Deleting last word touching EOL doesn't delete delimiter'``() =\n        assertText \"abc d$ef\\nghi\" \"dw\" \"abc $\\nghi\"\n\n    [<Test>]\n    let ``Delete char to left doesn't delete past start of line``() =\n        assertText \"abcdef\\nab$cdef\" \"XXX\" \"abcdef\\nb$cdef\"\n\n    [<Test>]\n    let ``dw last word at EOF``() =\n        assertText \"a$bc\" \"dw\" \"$\"\n\n    [<Test>]\n    let ``dw to brace #167``() =\n        assertText \"abc\\n $  {\" \"dw\" \"abc\\n{$\"\n\n    [<Test>]\n    let ``d]) deletes to next unmatched )``() =\n        assertText \"if (a$ == (b)c)\" \"d])\" \"if ($\"\n    [<Test>]\n    let ``dib deletes nested brackets``() =\n        assertText \"(fo$o (bar (foo) )  )\" \"dib\" \"()$\"\n\n    [<Test>]\n    let ``dib deletes nested brackets backwards``() =\n        assertText \"(foo (bar (foo) ) $ )\" \"dib\" \"()$\"\n\n    [<Test>]\n    let ``dib outside brackets does nothing``() =\n        assertText \"don't crash$ me\" \"dib\" \"don't crash$ me\""
  },
  {
    "path": "XSVim.Tests/ExModeTests.fs",
    "content": "﻿namespace XSVim.Tests\nopen NUnit.Framework\nopen XSVim\nopen System.Runtime.CompilerServices\nopen System.Threading.Tasks\n\n[<TestFixture>]\nmodule ``Ex mode tests`` =\n    [<SetUp;AsyncStateMachine(typeof<Task>)>]\n    let ``run before tests``() =\n        FixtureSetup.initialiseMonoDevelop()\n\n    [<Test>]\n    let ``/ searches for word``() =\n        assertText \"ab$c abc\" \"/abc<ret>\" \"abc a$bc\"\n\n    [<Test>]\n    let ``/ is case insensitive``() =\n        assertText \"ab$c ABC\" \"/abc<ret>\" \"abc A$BC\"\n\n    [<Test>]\n    let ``/ is case sensitive``() =\n        assertText \"ab$c ABC Abc\" \"/Abc<ret>\" \"abc ABC A$bc\"\n\n    [<Test>]\n    let ``deletes to search term``() =\n        assertText \"ab$c ABC Abc 123\" \"d/123<ret>\" \"a1$23\"\n\n    [<Test>]\n    let ``n searches for next word``() =\n        assertText \"ab$c abc abc\" \"/abc<ret>n\" \"abc abc a$bc\"\n\n    [<Test>]\n    let ``n wraps to start``() =\n        assertText \"ab$c abc abc\" \"/abc<ret>nn\" \"a$bc abc abc\"\n\n    [<Test>]\n    let ``N searches for previous word``() =\n        assertText \"ab$c abc abc\" \"/abc<ret>N\" \"a$bc abc abc\"\n\n    [<Test>]\n    let ``n searches for previous word after ?``() =\n        assertText \"abc abc a$bc\" \"?abc<ret>n\" \"a$bc abc abc\"\n\n    [<Test>]\n    let ``? searches for word backwards``() =\n        assertText \"abc abc a$bc\" \"?abc<ret>\" \"abc a$bc abc\"\n\n    [<Test>]\n    let ``:2 jumps to line 2``() =\n        assertText \"l$ine1\\nline2\" \":2<ret>\" \"line1\\nl$ine2\"\n\n    [<Test>]\n    let ``Backspacing ex mode returns to normal mode``() =\n        let _, state, _ = test \"abc abc a$bc\" \"/a<bs><bs>\"\n        state.mode |> should equal NormalMode\n\n    [<Test>]\n    let ``<esc> returns to normal mode``() =\n        let _, state, _ = test \"abc abc a$bc\" \"/<esc>\"\n        state.mode |> should equal NormalMode\n\n    [<Test>]\n    let ``<C-c> returns to normal mode``() =\n        let _, state, _ = test \"abc abc a$bc\" \"/<C-c>\"\n        state.mode |> should equal NormalMode\n\n    [<Test>]\n    let ``<C-[> returns to normal mode``() =\n        let _, state, _ = test \"abc abc a$bc\" \"/<C-[>\"\n        state.mode |> should equal NormalMode\n\n    [<Test>]\n    let ``Displays could not parse message``() =\n        let _, state, _ = test \"a$bc\" \":garbage<ret>\"\n        state.statusMessage.Value |> should equal \"Could not parse :garbage\"\n\n    [<Test>]\n    let ``Could not parse message is reset``() =\n        let _, state, _ = test \"a$bc\" \":garbage<ret>l\"\n        state.statusMessage |> should equal None\n\n    [<Test>]\n    let ``Deletes lines 2 to 4``() =\n        assertText\n            \"\"\"11111\n22222\n33333\n44444\n55555$\"\"\"\n\n            \":2,4d<ret>\"\n\n            \"\"\"11111\n5$5555\"\"\"\n\n    [<Test>]\n    let ``Switching to substitute command mode with a selection``() =\n        let _, state, _ = test \"a$bc\" \"v:\"\n        state.statusMessage |> should equal (Some \":'<,'>\")\n"
  },
  {
    "path": "XSVim.Tests/IndentationTests.fs",
    "content": "﻿namespace XSVim.Tests\nopen NUnit.Framework\nopen XSVim\nopen System.Runtime.CompilerServices\nopen System.Threading.Tasks\n\n[<TestFixture>]\nmodule ``Indentation tests`` =\n    [<SetUp;AsyncStateMachine(typeof<Task>)>]\n    let ``run before tests``() =\n        FixtureSetup.initialiseMonoDevelop()\n\n    [<Test>]\n    let ``>> indents right in normal mode``() =\n        assertText \"a$bc\" \">>\" \"    a$bc\"\n\n    [<Test>]\n    let ``indent is repeatable``() =\n        assertText \"a$bc\" \">>.\" \"        a$bc\"\n\n    [<Test>]\n    let ``V> indents line right``() =\n        let text, state, _ = test \"a$bc\\ndef\" \"V>\"\n        text |> should equal \"    a$bc\\ndef\"\n        state.mode |> should equal NormalMode\n\n    [<Test>]\n    let ``V2> indents line right twice``() =\n        assertText \"a$bc\\ndef\" \"V2>\" \"        a$bc\\ndef\"\n\n    [<Test>]\n    let ``>j indents current line and line below``() =\n        assertText \"a$bc\\ndef\" \">j\" \"    a$bc\\n    def\"\n\n    [<Test>]\n    let ``<j unindents current line and line below``() =\n        assertText \"    a$bc\\n    def\" \"<j\" \"a$bc\\ndef\"\n\n    [<Test;Ignore(\"Doesn't place caret at correct location\")>]\n    let ``>2j indents current line and two lines below``() =\n        assertText \"a$bc\\ndef\\nghi\" \">2j\" \"    a$bc\\n    def\\n    ghi\"\n\n    [<Test>]\n    let ``>gg indents to top of file``() =\n        assertText \"abc\\ndef\\ngh$i\" \">gg\" \"    abc\\n    def\\n    gh$i\"\n\n    [<Test>]\n    let ``V> indents line``() =\n        assertText \"abc\\ndef\\ngh$i\" \">gg\" \"    abc\\n    def\\n    gh$i\"\n\n    [<Test>]\n    let ``>2gg indents to line 2``() =\n        assertText \"abc\\ndef\\ngh$i\" \">2gg\" \"abc\\n    def\\n    gh$i\"\n\n    [<Test>]\n    let ``>2G indents to line 2``() =\n        assertText \"abc\\ndef\\ngh$i\" \">2G\" \"abc\\n    def\\n    gh$i\"\n\n    [<Test>]\n    let ``== autoindents line``() =\n        assertText \"abc\\n    def\\ngh$i\" \"==\" \"abc\\n    def\\n    g$hi\"\n\n    [<Test>]\n    let ``= autoindents selection``() =\n        assertText \"abc\\n    def\\ngh$i\" \"V=\" \"abc\\n    def\\n    g$hi\"\n\n    [<Test>]\n    let ``= autoindents multiple line selection``() =\n            assertText \"abc\\n    de$f\\n   ghi\\n   jkl\" \"Vj=\" \"abc\\nd$ef\\nghi\\n   jkl\"\n\n    [<Test>]\n    let ``=gg indents to top of file``() =\n        assertText \"abc\\n  def\\n  gh$i\" \"=gg\" \"a$bc\\ndef\\nghi\"\n"
  },
  {
    "path": "XSVim.Tests/InsertionTests.fs",
    "content": "﻿namespace XSVim.Tests\nopen NUnit.Framework\nopen XSVim\nopen System.Runtime.CompilerServices\nopen System.Threading.Tasks\n\n[<TestFixture>]\nmodule ``Insertion tests`` =\n    [<SetUp;AsyncStateMachine(typeof<Task>)>]\n    let ``run before tests``() =\n        FixtureSetup.initialiseMonoDevelop()\n\n    [<Test>]\n    let ``'O' should insert line above``() =\n        //TODO: 'O' is broken on the top line\n        assertText \" \\n a$bcdef\" \"O\" \" \\n |\\n abcdef\"\n\n    [<Test>]\n    let ``'O' inserts line above``() =\n        assertText \"abc$def\\n\" \"O\" \"|\\nabcdef\\n\"\n"
  },
  {
    "path": "XSVim.Tests/KeyParsing.fs",
    "content": "﻿namespace XSVim.Tests\nopen XSVim\nopen NUnit.Framework\n\n[<TestFixture>]\nmodule ``Key parsing tests`` =\n    let test keys =\n        let keys = [for c in keys -> Key c]\n        let state = { VimState.Default with keys=keys }\n        let config = Config.Default\n        let action, _state = Vim.parseKeys state config\n        let first = action.Head\n\n        first.repeat, first.commandType, first.textObject\n\n    [<Test>]\n    let ``10j``() =\n        test \"10j\" |> should equal (Some 10, Move, Down)\n\n    [<Test>]\n    let ``11G``() =\n        test \"11G\" |> should equal (Some 1, Move, Jump (StartOfLineNumber 11))\n"
  },
  {
    "path": "XSVim.Tests/KeyboardMap.fs",
    "content": "﻿namespace XSVim.Tests\n\nopen XSVim\nmodule mapFromQwerty =\n    let qwertyToColemak = function\n        | 'e' -> 'f'\n        | 'r' -> 'p'\n        | 't' -> 'g'\n        | 'y' -> 'j'\n        | 'u' -> 'l'\n        | 'i' -> 'u'\n        | 'o' -> 'y'\n        | 'p' -> ';'\n        | 's' -> 'r'\n        | 'd' -> 's'\n        | 'f' -> 't'\n        | 'g' -> 'd'\n        | 'j' -> 'n'\n        | 'k' -> 'e'\n        | 'l' -> 'i'\n        | ';' -> 'o'\n        | 'n' -> 'k'\n        | 'E' -> 'F'\n        | 'R' -> 'P'\n        | 'T' -> 'G'\n        | 'Y' -> 'J'\n        | 'U' -> 'L'\n        | 'I' -> 'U'\n        | 'O' -> 'Y'\n        | 'P' -> ':'\n        | 'S' -> 'R'\n        | 'D' -> 'S'\n        | 'F' -> 'T'\n        | 'G' -> 'D'\n        | 'J' -> 'N'\n        | 'K' -> 'E'\n        | 'L' -> 'I'\n        | ':' -> 'O'\n        | 'N' -> 'K'\n        | c -> c\n\n    let qwertyToDvorak = function\n        | '-' -> '['\n        | '=' -> ']'\n        | 'q' -> '''\n        | 'w' -> ','\n        | 'e' -> '.'\n        | 'r' -> 'p'\n        | 't' -> 'y'\n        | 'y' -> 'f'\n        | 'u' -> 'g'\n        | 'i' -> 'c'\n        | 'o' -> 'r'\n        | 'p' -> 'l'\n        | '[' -> '/'\n        | ']' -> '='\n        | 's' -> 'o'\n        | 'd' -> 'e'\n        | 'f' -> 'u'\n        | 'g' -> 'i'\n        | 'h' -> 'd'\n        | 'j' -> 'h'\n        | 'k' -> 't'\n        | 'l' -> 'n'\n        | ';' -> 's'\n        | ''' -> '-'\n        | 'z' -> ';'\n        | 'x' -> 'q'\n        | 'c' -> 'j'\n        | 'v' -> 'k'\n        | 'b' -> 'x'\n        | 'n' -> 'b'\n        | ',' -> 'w'\n        | '.' -> 'v'\n        | '/' -> 'z'\n        | '_' -> '{'\n        | '+' -> '}'\n        | 'Q' -> '\\''\n        | 'W' -> '<'\n        | 'E' -> '>'\n        | 'R' -> 'P'\n        | 'T' -> 'Y'\n        | 'Y' -> 'F'\n        | 'U' -> 'G'\n        | 'I' -> 'C'\n        | 'O' -> 'R'\n        | 'P' -> 'L'\n        | '{' -> '?'\n        | '}' -> '+'\n        | 'S' -> 'O'\n        | 'D' -> 'E'\n        | 'F' -> 'U'\n        | 'G' -> 'I'\n        | 'H' -> 'D'\n        | 'J' -> 'H'\n        | 'K' -> 'T'\n        | 'L' -> 'N'\n        | ':' -> 'S'\n        | '\"' -> '_'\n        | 'Z' -> ':'\n        | 'X' -> 'Q'\n        | 'C' -> 'J'\n        | 'V' -> 'K'\n        | 'B' -> 'X'\n        | 'N' -> 'B'\n        | 'M' -> 'M'\n        | '<' -> 'W'\n        | '>' -> 'V'\n        | '?' -> 'Z'\n        | c -> c\n\n    let remap layout key =\n        match layout with\n        | Colemak -> qwertyToColemak key\n        | Dvorak -> qwertyToDvorak key\n        | _ -> key"
  },
  {
    "path": "XSVim.Tests/MacrosTests.fs",
    "content": "﻿namespace XSVim.Tests\nopen NUnit.Framework\nopen XSVim\nopen System.Runtime.CompilerServices\nopen System.Threading.Tasks\n\n[<TestFixture>]\nmodule ``Macro tests`` =\n    [<SetUp;AsyncStateMachine(typeof<Task>)>]\n    let ``run before tests``() =\n        FixtureSetup.initialiseMonoDevelop()\n\n    [<Test>]\n    let ``Start recording macro q``() =\n        let _, state, _ = test \" $\" \"qq\"\n        state.macro |> should equal (Some (Macro 'q'))\n\n    [<Test>]\n    let ``Stop recording macro q``() =\n        let _, state, _ = test \" $\" \"qqq\"\n        state.macro |> should equal None\n\n    [<Test>]\n    let ``Replay macro q``() =\n        assertText \"a$bc abc\" \"qqfcad<esc>q@q\" \"abcd abcd$\"\n\n    [<Test>]\n    let ``Macros are repeatable``() =\n        assertText \"a$bc abc abc abc\" \"qqfcad<esc>q3@q\" \"abcd abcd abcd abcd$\"\n\n    [<Test>]\n    let ``Macros containing repeats are repeatable``() =\n        assertText \" $aa aa aa aa\" \"qq2faab<esc>q3@q\" \" aab aab aab aab$\"\n"
  },
  {
    "path": "XSVim.Tests/MarkerTests.fs",
    "content": "﻿namespace XSVim.Tests\nopen NUnit.Framework\nopen XSVim\nopen System.Runtime.CompilerServices\nopen System.Threading.Tasks\n\n[<TestFixture>]\nmodule ``Marker tests`` =\n    [<SetUp;AsyncStateMachine(typeof<Task>)>]\n    let ``run before tests``() =\n        FixtureSetup.initialiseMonoDevelop()\n    [<Test>]\n    let ``ma adds marker a``() =\n        assertText \"a$bc\" \"mall`a\" \"a$bc\"\n\n    [<Test>]\n    let ``'a moves to start of line of marker a``() =\n        assertText \"123 a$bc\" \"mall'a\" \"1$23 abc\"\n\n    [<Test>]\n    let ``'. jumps to last edit line``() =\n        assertText \"  123 a$bc\" \"i<esc>'.\" \"  1$23 abc\"\n\n    [<Test>]\n    let ``'' jumps to last jump location line``() =\n        assertText \"ab$c\\ndef\" \"G''\" \"a$bc\\ndef\"\n\n    [<Test>]\n    let ``Deletes from 4 up to marker a``() =\n        assertText \"1234XXXXXXXa$5678\" \"maF4d`a\" \"123a$5678\"\n\n    [<Test>]\n    let ``Selects from 4 up to marker a``() =\n        let _ = test \"1234XXXXXXXa$5678\" \"maF4v`ay\" \n        Vim.registers.[EmptyRegister].content\n        |> should equal \"4XXXXXXXa\"\n\n    [<Test>]\n    let ``Deletes linewise between marker a and marker b``() =\n        assertText\n            \"\"\"\n.........\naaaaa$aaaa\n.........\n.........\nbbbbbbbbb\n.........\n            \"\"\"\n\n\n              \"ma/b<ret>mb:'a,'bd<ret>\"\n\n            \"\"\"\n.........\n.$........\n            \"\"\""
  },
  {
    "path": "XSVim.Tests/MiscTests.fs",
    "content": "﻿namespace XSVim.Tests\nopen NUnit.Framework\nopen XSVim\nopen System.Runtime.CompilerServices\nopen System.Threading.Tasks\n\n[<TestFixture>]\nmodule ``Miscellaneous tests`` =\n    [<SetUp;AsyncStateMachine(typeof<Task>)>]\n    let ``run before tests``() =\n        FixtureSetup.initialiseMonoDevelop()\n\n    [<Test>]\n    let ``'A' should put caret at end of the line``() =\n        assertText \"abc$def\\n\" \"A\" \"abcdef|\\n\"\n\n    [<Test>]\n    let ``'A' should put caret at EOF``() =\n        assertText \"abc$def\" \"A\" \"abcdef|\"\n\n    [<Test>]\n    let ``'a' should append after``() =\n        assertText \"a$bcdef\" \"a\" \"a|bcdef\"\n\n    [<Test>]\n    let ``'a' should append after last char``() =\n        assertText \"abcdef$\\n\" \"a\" \"abcdef|\\n\"\n\n    [<Test>]\n    let ``'a' should append before EOF``() =\n        assertText \"abcdef$\" \"a\" \"abcdef|\"\n\n    [<Test>]\n    let ``'a' on empty line should keep cursor on the current line``() =\n        assertText \"\\n$abc\" \"a\" \"|\\nabc\"\n\n    [<Test>]\n    let ``'I' should insert at first non whitespace``() =\n        assertText \"   abcdef$\" \"I\" \"   |abcdef\"\n\n    [<Test>]\n    let ``Undo repeat``() =\n        assertText \"a$bc def ghi\" \"3dwu\" \"a$bc def ghi\"\n\n    [<Test>]\n    let ``Repeat typed chars``() =\n        assertText \"d$\" \"iabc <esc>.\" \"abcabc $ d\"\n\n    [<Test>]\n    let ``Repeat intellisense``() =\n        let _, state, editor =\n            test\n                \"\"\"\n                System$\n                System\n                \"\"\" \"a.Coll\"\n        // simulate ctrl-space intellisense inserting \"Collections\" by removing \n        // \"Coll\" and then inserting \"Collections\"\n        let offset = editor.Text.IndexOf(\"Coll\")\n        editor.RemoveText(offset,4) // delete \"Coll\"\n        editor.InsertText(editor.CaretOffset, \"Collections\")\n        let config = Config.Default\n        let _, newState, _ = sendKeysToEditor editor \"<esc>j.\" config\n        let text = getEditorText editor newState\n\n        text\n        |> should equal\n                \"\"\"\n                System.Collections\n                System.Collections$\n                \"\"\"\n\n    [<Test>]\n    let ``Large text addition is not too slow!``() =\n        let _, state, editor =\n            test \" $\" \"\"\n        editor.InsertText(0, new System.String('x', 200000))\n\n    [<Test>]\n    let ``backspace is repeated``() =\n        assertText \"d$\" \"iabc<bs> <esc>.\" \"abab $ d\"\n\n    [<Test; Ignore(\"TODO\")>]\n    let ``delete key is repeated``() =\n        assertText \"d$\" \"i<del>abc<esc>.\" \"ababc$\"\n\n    [<Test>]\n    let ``<C-[> escapes``() =\n        assertText \"    abc$\" \"i<C-[>\" \"    ab$c\"\n\n    [<Test>]\n    let ``Return to normal mode doesn't move past start of line``() =\n        assertText \"abc\\nd$ef\" \"i<esc>\" \"abc\\nd$ef\"\n\n    [<Test>]\n    let ``dot repeats at start of line``() =\n        assertText \n            \"\"\"\n            def$\n            def\n            \"\"\" \n\n            \"Iabc<esc>j.\"\n\n            \"\"\"\n            abcdef\n            abc$def\n            \"\"\" \n\n    [<Test>]\n    let ``dot repeats at end of line``() =\n        assertText \n            \"\"\"\n            a$bc\n            a$bc\n            \"\"\" \n\n            \"Adef<esc>j.\"\n\n            \"\"\"\n            abcdef\n            abcdef$\n            \"\"\" \n\n    [<Test>]\n    let ``Repeat delete word``() =\n        assertText \"a$bc de fgh\" \"dww.\" \"de $\"\n\n    [<Test>]\n    let ``Repeat change word``() =\n        assertText \"a$bc de fgz \" \"cwxxx<esc>ww.\" \"xxx de xxx$ \"\n\n    [<Test>]\n    let ``r should be repeatable``() =\n        assertText \"a$aaa\" \"rb$.\" \"baab$\"\n\n    [<Test>]\n    let ``r<ret> inserts <ret> and indents``() =\n        assertText \"   aaa$\\nbbb\" \"r<ret>\" \"   aa\\n   \\n$bbb\"\n\n    [<Test>]\n    let ``R switches to replace mode``() =\n        let _, state, _ = test \"a$bc\" \"R\"\n        state.mode |> should equal ReplaceMode\n\n    [<Test>]\n    let ``R replaces characters``() =\n        assertText \"a$bc\" \"RABCD\" \"ABCD$\"\n\n    [<Test>]\n    let ``R replaces digits``() =\n        assertText \"a$bc\" \"R123\" \"123$\"\n\n    [<Test>]\n    let ``Replace mode inserts at end of line``() =\n        assertText \"a$bc\\ndef\" \"RABCD\" \"ABCD\\n$def\"\n\n    [<Test>]\n    let ``Replace mode is undoable``() =\n        assertText \"a$bc\\ndef\" \"RABCD<esc>u\" \"a$bc\\ndef\"\n\n    [<Test>]\n    let ``Undo insert mode``() =\n        assertText \"abc$\" \"adef ghi jkl<esc>u\" \"abc$\"\n\n    [<Test>]\n    let ``J puts caret between joined lines``() =\n        assertText \"a$bc\\ndef\" \"J\" \"abc $def\"\n\n    [<Test>]\n    let ``* finds next word``() =\n        assertText \" $ abc\" \"*\" \"  a$bc\"\n\n    [<Test>]\n    let ``* does not match substring``() =\n        assertText \"a$bc abcde abc\" \"*\" \"abc abcde a$bc\"\n\n    [<Test>]\n    let ``* finds next word at caret``() =\n        assertText \"a$bc abc\" \"*\" \"abc a$bc\"\n\n    [<Test>]\n    let ``n finds next match``() =\n        assertText \"a$bc abc cba abc\" \"*n\" \"abc abc cba a$bc\"\n\n    [<Test>]\n    let ``* finds next word when on last word char``() =\n        assertText \"abc$ abc\" \"*\" \"abc a$bc\"\n\n    [<Test>]\n    let ``* wraps to start``() =\n        assertText \"abc a$bc\" \"*\" \"a$bc abc\"\n\n    [<Test>]\n    let ``* finds next word at EOF``() =\n        assertText \"abc abc$\" \"*\" \"a$bc abc\"\n\n    [<Test>]\n    let ``# finds previous word at caret``() =\n        assertText \"abc abc a$bc\" \"#\" \"abc a$bc abc\"\n\n    [<Test>]\n    let ``# matches exact word``() =\n        assertText \"abc abcde a$bc\" \"#\" \"a$bc abcde abc\"\n\n    [<Test>]\n    let ``£ wraps to end``() =\n        assertText \"a$bc abc\" \"£\" \"abc a$bc\"\n\n    [<Test>]\n    let ``~ toggles case of char at caret``() =\n        assertText \"a$bc abc\" \"~\" \"Ab$c abc\"\n\n    [<Test>]\n    let ``~ toggles case of selection``() =\n        assertText \"A$bC abc\" \"vll~\" \"a$Bc abc\"\n\n    [<Test>]\n    let ``<esc> doesn't move caret left onto newline'``() =\n        assertText \"\\nA$bC abc\" \"o<esc>\" \"\\nAbC abc\\n$\"\n\n    [<Test>]\n    let ``<C-a> increments next number``() =\n        assertText \"a$bc 9 \" \"<C-a>\" \"abc 10$ \"\n\n    [<Test>]\n    let ``<C-a> increments second number``() =\n        assertText \"abc 0 $1 \" \"<C-a>\" \"abc 0 2$ \"\n\n    [<Test>]\n    let ``<C-a> increments same width number``() =\n        assertText \"a$bc 0 \" \"<C-a>\" \"abc 1$ \"\n\n    [<Test>]\n    let ``<C-a> increments number at caret``() =\n        assertText \"abc 9$ \" \"<C-a>\" \"abc 10$ \"\n\n    [<Test>]\n    let ``<C-a> increments next negative number``() =\n        assertText \"a$bc -1 \" \"<C-a>\" \"abc 0$ \"\n\n    [<Test>]\n    let ``<C-x> decrements next number``() =\n        assertText \"a$bc 10 \" \"<C-x>\" \"abc 9$ \"\n\n    [<Test>]\n    let ``<C-x> decrements -1``() =\n        assertText \"abc -1$ \" \"<C-x>\" \"abc -2$ \"\n\n    [<Test>]\n    let ``dot repeats 2dd``() =\n        assertText \n           \"\"\"\n           a$aaaa\n           aaaaa\n           bbbbb\n           bbbbb\n           ccccc\n           \"\"\"\n\n           \"2dd.\"\n\n           \"\"\"\n           c$cccc\n           \"\"\"           \n\n    [<Test>]\n    let ``dot repeats 2dj``() =\n        assertText\n            \"\"\"\n            a$aaaa\n            aaaaa\n            aaaaa\n            bbbbb\n            bbbbb\n            bbbbb\n            \"\"\"\n\n            \"2dj.\"\n\n            \"\"\"\n            $\"\"\"\n\n    [<Test>]\n    let ``dot repeats 3S``() =\n        assertText\n            \"\"\"\n            a$aaaa\n            aaaaa\n            bbbbb\n            bbbbb\n            ccccc\n            ccccc\"\"\"\n\n            \"3S<esc>.\"\n\n            \"\"\"\n\n$            ccccc\"\"\""
  },
  {
    "path": "XSVim.Tests/Movement.fs",
    "content": "﻿namespace XSVim.Tests\nopen NUnit.Framework\nopen XSVim\nopen System.Runtime.CompilerServices\nopen System.Threading.Tasks\n\n[<TestFixture>]\nmodule ``Movement tests`` =\n    [<SetUp;AsyncStateMachine(typeof<Task>)>]\n    let ``run before tests``() =\n        FixtureSetup.initialiseMonoDevelop()\n    [<Test>]\n    let ``Move to next word``() =\n        assertText \"aa$a bbb\" \"w\" \"aaa b$bb\"\n\n    [<Test>]\n    let ``Move to next word on next line``() =\n        assertText \"aa$a\\n  bbb\" \"w\" \"aaa\\n  b$bb\"\n\n    [<Test>]\n    let ``Move to empty line``() =\n        assertText \"aa$a\\n\\nbbb\" \"w\" \"aaa\\n\\n$bbb\"\n\n    [<Test>]\n    let ``Moves to EOF when there is no next word``() =\n        assertText \"aa$aa\" \"w\" \"aaaa$\"\n\n    [<Test>]\n    let ``w skips over tabs``() =\n        assertText \"\\t$\\t\\taaaa\" \"w\" \"\\t\\t\\ta$aaa\"\n\n    [<Test>]\n    let ``Move to word end``() =\n        assertText \"aa$a bbb\" \"e\" \"aaa$ bbb\"\n\n    [<Test>]\n    let ``Move to next word end``() =\n        assertText \"aaa$ bbb\" \"e\" \"aaa bbb$\"\n\n    [<Test>]\n    let ``Move to second word end``() =\n        assertText \"aa$a bbb\" \"ee\" \"aaa bbb$\"\n\n    [<Test>]\n    let ``e jumps over punctuation``() =\n        assertText \"int model$);\\n \" \"e\" \"int model);$\\n \"\n\n    [<Test>]\n    let ``e jumps over chevrons``() =\n        assertText \"Task<List<SomeWord$>> nextWord\" \"e\" \"Task<List<SomeWord>>$ nextWord\"\n\n    [<Test>]\n    let ``e jumps from chevron to end of next word``() =\n        assertText \"Task<List<SomeWord>>$ nextWord\" \"e\" \"Task<List<SomeWord>> nextWord$\"\n\n    [<Test>]\n    let ``e jumps over spaces``() =\n        assertText \" $  abcde\" \"e\" \"   abcde$\"\n\n    [<Test>]\n    let ``e stops before dot``() =\n        assertText \"open$ System.Collections.Generic\" \"e\" \"open System$.Collections.Generic\"\n\n    [<Test>]\n    let ``Move to end of line``() =\n        assertText \"aa$a aaa\\nbbb\" \"$\" \"aaa aaa$\\nbbb\"\n\n    [<Test>]\n    let ``Move to end of document``() =\n        assertText \"aa$aaaa\\nbbbbbb\" \"G\" \"aaaaaa\\nb$bbbbb\"\n\n    [<Test>]\n    let ``Move to start of document``() =\n        assertText \"aaaaaa\\nbb$bbbb\" \"gg\" \"a$aaaaa\\nbbbbbb\"\n\n    [<Test>]\n    let ``Move to line 2``() =\n        assertText \"a$aaaaa\\n  bbbbbb\" \"2gg\" \"aaaaaa\\n  b$bbbbb\"\n\n    [<Test>]\n    let ``Move to line 3``() =\n        assertText \"a$aaaaa\\nbbbbbb\\ncccccc\\ndddddd\" \"3G\" \"aaaaaa\\nbbbbbb\\nc$ccccc\\ndddddd\"\n\n    [<Test>]\n    let ``Move down to desired column``() =\n        assertText \"12345$6\\n123\\n123456\" \"jj\" \"123456\\n123\\n12345$6\"\n\n    [<Test>]\n    let ``Move down to last column``() =\n        assertText \"12345$6\\n123\\n123456\" \"j\" \"123456\\n123$\\n123456\"\n\n    [<Test>]\n    let ``Move across then down``() =\n        assertText \"1$2\\n12\\n\" \"lj\" \"12\\n12$\\n\"\n\n    [<Test>]\n    let ``Move ten right``() =\n        assertText \"a$bcdefghijkl\" \"10l\" \"abcdefghijk$l\"\n\n    [<Test>]\n    let ``Does not move right past delimiter``() =\n        assertText \"a$b\\n\" \"ll\" \"ab$\\n\"\n\n    [<Test>]\n    let ``Find moves to digit``() =\n        assertText \"abc$ d1 d2 d3\" \"f2\" \"abc d1 d2$ d3\"\n\n    [<Test>]\n    let ``Reverse find moves to digit``() =\n        assertText \"abc d1 d2 d$3\" \"F1\" \"abc d1$ d2 d3\"\n\n    [<Test>]\n    let ``Till moves to digit``() =\n        assertText \"abc$ d1 d2 d3\" \"t2\" \"abc d1 d$2 d3\"\n\n    [<Test>]\n    let ``Reverse till moves to digit``() =\n        assertText \"abc d1 d2 d$3\" \"T1\" \"abc d1 $d2 d3\"\n\n    [<Test>]\n    let ``2fd moves to second d``() =\n        assertText \"abc$ d1 d2 d3\" \"2fd\" \"abc d1 d$2 d3\"\n\n    [<Test>]\n    let ``F finds previous char``() =\n        assertText \"a a$\" \"Fa\" \"a$ a\"\n\n    [<Test>]\n    let ``f is repeatable with ;``() =\n        assertText \" $ a1 a2\" \"fa;\" \"  a1 a$2\"\n\n    [<Test>]\n    let ``f is reversed with ,``() =\n        assertText \" $ a1 a2\" \"fa;,\" \"  a$1 a2\"\n\n    [<Test>]\n    let ``t does not move if caret is already just before search char``() =\n        assertText \" $a1 a2\" \"ta\" \" $a1 a2\"\n\n    [<Test>]\n    let ``T does not move if caret is already just after search char``() =\n        assertText \"a1 a2$\" \"Ta\" \"a1 a2$\"\n\n    [<Test>]\n    let ``t is repeatable with ;``() =\n        assertText \" $a1 a2\" \"ta;\" \" a1 $a2\"\n\n    [<Test>]\n    let ``T is repeatable with ;``() =\n        assertText \"a1 a2$\" \"Ta;\" \"a1$ a2\"\n\n    [<Test>]\n    let ``ge moves back to end of last word``() =\n        assertText \"abc de$f\" \"ge\" \"abc$ def\"\n\n    [<Test>]\n    let ``ge between words moves back to end of last word``() =\n        assertText \"abc  $def\" \"ge\" \"abc$  def\"\n\n    [<Test>]\n    let ``ge stops at first character``() =\n        assertText \"abc$\" \"ge\" \"a$bc\"\n\n    [<Test>]\n    let ``gE moves back to end of last WORD``() =\n        assertText \"abc def.gh$i\" \"gE\" \"abc$ def.ghi\"\n\n    [<Test>]\n    let ``l stops at EOL``() =\n        assertText \"abc$\\ndef\" \"l\" \"abc$\\ndef\"\n\n    [<Test>]\n    let ``space moves past EOL``() =\n        assertText \"abc$\\ndef\" \" \" \"abc\\nd$ef\"\n\n    [<Test>]\n    let ``% moves to matching parens``() =\n        assertText \"($foo(bar))\" \"%\" \"(foo(bar))$\"\n\n    [<Test>]\n    let ``[{ goes to previous unmatched {``() =\n        assertText \"func { case { a } case$ { b } }\" \"[{\" \"func {$ case { a } case { b } }\"\n\n    [<Test>]\n    let ``[( goes to previous unmatched (``() =\n        assertText \"if (a == (b)c$)\" \"[(\" \"if ($a == (b)c)\"\n\n    [<Test>]\n    let ``]} goes to next unmatched }``() =\n        assertText \"func { case$ { a } case { b } }\" \"]}\" \"func { case { a } case { b } }$\"\n\n    [<Test>]\n    let ``]) goes to next unmatched )``() =\n        assertText \"if (a$ == (b)c)\" \"])\" \"if (a == (b)c)$\"\n"
  },
  {
    "path": "XSVim.Tests/Properties/AssemblyInfo.fs",
    "content": "﻿namespace XSVim.Tests\nopen System.Reflection\nopen System.Runtime.CompilerServices\n\n[<assembly: AssemblyTitle(\"XSVim.Tests\")>]\n[<assembly: AssemblyDescription(\"\")>]\n[<assembly: AssemblyConfiguration(\"\")>]\n[<assembly: AssemblyCompany(\"\")>]\n[<assembly: AssemblyProduct(\"\")>]\n[<assembly: AssemblyCopyright(\"(c) Jason Imison\")>]\n[<assembly: AssemblyTrademark(\"\")>]\n\n// The assembly version has the format {Major}.{Minor}.{Build}.{Revision}\n\n[<assembly: AssemblyVersion(\"1.0.0.0\")>]\n\n//[<assembly: AssemblyDelaySign(false)>]\n//[<assembly: AssemblyKeyFile(\"\")>]\n\n()\n"
  },
  {
    "path": "XSVim.Tests/TestHelpers.fs",
    "content": "﻿namespace XSVim.Tests\n\nopen System\nopen System.Text.RegularExpressions\nopen System.Threading.Tasks\nopen MonoDevelop.Ide.Editor.Extension\nopen NUnit.Framework\nopen XSVim\nopen MonoDevelop.Core\nopen MonoDevelop.Ide.Editor\n[<AutoOpen>]\nmodule FsUnit =\n\n    open System.Diagnostics\n    open NUnit.Framework.Constraints\n\n    [<DebuggerNonUserCode>]\n    let should (f : 'a -> #Constraint) x (y : obj) =\n        let c = f x\n        let y =\n            match y with\n            | :? (unit -> unit) -> box (new TestDelegate(y :?> unit -> unit))\n            | _                 -> y\n        Assert.That(y, c)\n\n    let shouldnot (f : 'a -> #Constraint) x (y : obj) =\n        let c = f x\n        let y =\n            match y with\n            | :? (unit -> unit) -> box (new TestDelegate(y :?> unit -> unit))\n            | _                 -> y\n        Assert.That(y, new NotConstraint(c))\n\n    let equal x = new EqualConstraint(x)\n\n    // like \"should equal\", but validates same-type\n    let shouldEqual (x: 'a) (y: 'a) = Assert.AreEqual(x, y, sprintf \"Expected: %A\\nActual: %A\" x y)\n    let replaceLineEnding (s:string) =\n      s.Replace(\"\\r\\n\", \"\\n\")\n\n    let shouldEqualIgnoringLineEndings (x: string) (y: string) =\n      Assert.AreEqual((replaceLineEnding x), (replaceLineEnding y), sprintf \"Expected: %A\\nActual: %A\" x y)\n\n    let notEqual x = new NotConstraint(new EqualConstraint(x))\n\n    let NOT c = new NotConstraint(c)\n\n    let contain x = new ContainsConstraint(x)\n\n    let haveLength n = Has.Length.EqualTo(n)\n\n    let haveCount n = Has.Count.EqualTo(n)\n\n    let NotEmpty = Has.Length.GreaterThan(0)\n\n    let endWith (s:string) = new EndsWithConstraint(s)\n\n    let startWith (s:string) = new StartsWithConstraint(s)\n\n    let be = id\n\n    let Null = new NullConstraint()\n\n    let Empty = new EmptyConstraint()\n\n    let EmptyString = new EmptyStringConstraint()\n\n    let NullOrEmptyString = new NullOrEmptyStringConstraint()\n\n    let True = new TrueConstraint()\n\n    let False = new FalseConstraint()\n\n    let sameAs x = new SameAsConstraint(x)\n\n    let throw = Throws.TypeOf\n\nmodule FixtureSetup =\n    let firstRun = ref true\n\n    let initialiseMonoDevelop() =\n        if !firstRun then\n            firstRun := false\n            printf \"initialising\"\n            Environment.SetEnvironmentVariable (\"MONO_ADDINS_REGISTRY\", \"/tmp\")\n            Runtime.Initialize (true)\n            // Initialize FontService\n            Runtime.ServiceProvider.GetService<MonoDevelop.Ide.Fonts.FontService>() :> Task\n        else\n            Task.CompletedTask\n       \n\n[<AutoOpen>]\nmodule TestHelpers =\n    let (|CtrlKey|_|) (s:string) =\n        match s with\n        | s when s.Length = 3 && s.StartsWith \"C-\" -> Some s.[2]\n        | _ -> None\n\n    let keyToDescriptor key (state: VimState) layout =\n        let lastKeyPress = state.keys |> List.tryLast\n\n        let noremap = // The next key press is not translated for keyboard layout\n            [ 'm'; '@'; 'r'; 'f'; 'q']\n            |> List.map (mapFromQwerty.remap layout)\n            |> List.map Key\n            |> List.map Some\n\n        let shouldRemapKey =\n            match state.mode, noremap |> List.contains lastKeyPress with\n            | _, true -> false\n            | NormalMode, _\n            | VisualMode, _\n            | VisualLineMode, _\n            | VisualBlockMode, _ -> true\n            | _ -> false\n\n        match key, shouldRemapKey with\n        | \"esc\", _  -> KeyDescriptor.FromGtk(Gdk.Key.Escape, '\\000', Gdk.ModifierType.None)\n        | \"ret\", _  -> KeyDescriptor.FromGtk(Gdk.Key.Return, '\\000', Gdk.ModifierType.None)\n        | \"bs\" , _ -> KeyDescriptor.FromGtk(Gdk.Key.BackSpace, '\\000', Gdk.ModifierType.None)\n        | \"del\", _  -> KeyDescriptor.FromGtk(Gdk.Key.Delete, '\\000', Gdk.ModifierType.None)\n        | CtrlKey ch, _ -> KeyDescriptor.FromGtk(Gdk.Key.a (* important? *), ch, Gdk.ModifierType.ControlMask)\n        | key, false ->\n            KeyDescriptor.FromGtk(Gdk.Key.a (* important? *), char key, Gdk.ModifierType.None)\n        | key, true ->\n            KeyDescriptor.FromGtk(Gdk.Key.a (* important? *), mapFromQwerty.remap layout (char key), Gdk.ModifierType.None)\n\n    let getEditorText (editor:TextEditor) state =\n        if state.mode = InsertMode then\n            editor.Text.Insert(editor.CaretOffset, \"|\")\n        else\n            if editor.CaretOffset = editor.Text.Length then\n                editor.Text + \"$\"\n            else\n                editor.Text.Insert(editor.CaretOffset+1, \"$\")\n\n    let sendKeysToEditor (editor:TextEditor) keys config =\n        let keygroups =\n            Regex.Replace(keys, \"<(.*?)>\", \"§$1§\").Split '§'\n\n        let keygroups =\n            keygroups\n            |> Array.collect(fun g ->\n                                 match g with\n                                 | \"esc\" -> [|g|]\n                                 | \"ret\" -> [|g|]\n                                 | \"bs\"  -> [|g|]\n                                 | \"del\" -> [|g|]\n                                 | CtrlKey ch -> [|g|]\n                                 | _ ->  Seq.toArray g |> Array.map string) // \"abc\" -> [|\"a\"; \"b\"; \"c\" |]\n\n        let newState =\n            keygroups\n            |> Array.fold(fun state keys ->\n                let state = Vim.editorStates.[editor.FileName]\n\n                printfn \"%A\" state.keys\n                let descriptor = keyToDescriptor keys state config.keyboardLayout\n                printfn \"%A\" state.mode\n                printfn \"%A\" descriptor\n\n                let handledState, handledKeyPress = Vim.handleKeyPress state descriptor editor config\n                printfn \"%A\" handledState\n                printfn \"\\\"%s\\\"\" (getEditorText editor handledState)\n                if state.mode = InsertMode && descriptor.ModifierKeys <> ModifierKeys.Control && descriptor.SpecialKey <> SpecialKey.Escape then\n                    Vim.processVimKey editor (Vim.keyPressToVimKey descriptor)\n                handledState) Vim.editorStates.[editor.FileName]\n\n        let text = getEditorText editor newState\n        text, newState, editor\n\n    let testWithEol (source:string) (keys:string) eolMarker layout =\n        let config = { Config.Default with keyboardLayout = layout }\n        let editor = TextEditorFactory.CreateNewEditor()\n        editor.FileName <- FilePath \"test.txt\"\n        editor.TextChanged.Add(fun changes -> Subscriptions.textChanged editor changes)\n        let caret = source.IndexOf \"$\"\n        if caret = 0 then\n            failwith \"$ can't be the first position. It needs to be after the char the caret would appear over.\"\n        if caret = -1 then\n            failwith \"No caret found in test code\"\n        editor.Text <- source.Replace(\"$\", \"\")\n        editor.CaretOffset <- caret-1\n        editor.Options <- new CustomEditorOptions(TabsToSpaces=true, IndentationSize=4, IndentStyle=IndentStyle.Smart, TabSize=4, DefaultEolMarker=eolMarker)\n        Vim.editorStates.[editor.FileName] <- VimState.Default\n        sendKeysToEditor editor keys config\n\n    let test source keys = testWithEol source keys \"\\n\" Qwerty\n\n    let switchLineEndings (s:string) =\n        s.Replace(\"\\n\", \"\\r\\n\")\n\n    let assertText (source:string) (keys:string) expected =\n        let actual, _, _ = testWithEol source keys \"\\n\" Qwerty\n        Assert.AreEqual(expected, actual, \"Failed with \\n\")\n        let actual, _, _ = testWithEol source keys \"\\n\" Colemak\n        Assert.AreEqual(expected, actual, \"Failed with colemak\")\n        let actual, _, _ = testWithEol source keys \"\\n\" Dvorak\n        Assert.AreEqual(expected, actual, \"Failed with dvorak\")\n        if source.Contains(\"\\n\") || actual.Contains(\"\\n\") then\n            // Run the test again with \\r\\n line endings\n            let actual, _, _ = testWithEol (source |> switchLineEndings) keys \"\\r\\n\" Qwerty\n            Assert.AreEqual(expected |> switchLineEndings, actual.Replace(\"\\r$\\n\", \"\\r\\n$\"), \"Failed with \\r\\n\")\n"
  },
  {
    "path": "XSVim.Tests/TextObjectSelectionTests.fs",
    "content": "﻿namespace XSVim.Tests\nopen NUnit.Framework\nopen XSVim\nopen System.Runtime.CompilerServices\nopen System.Threading.Tasks\n\n[<TestFixture>]\nmodule ``Text object selection tests`` =\n    [<SetUp;AsyncStateMachine(typeof<Task>)>]\n    let ``run before tests``() =\n        FixtureSetup.initialiseMonoDevelop()\n\n    // Tests for aw. Reference: http://vimdoc.sourceforge.net/htmldoc/motion.html#aw\n    module aw =\n        [<Test>]\n        let ``daw deletes around word``() =\n            assertText \"a b$c d\" \"daw\" \"a d$\"\n\n        [<Test>]\n        let ``daw on a word``() =\n            assertText \"word1   word2$   word3\" \"daw\" \"word1   w$ord3\" // three spaces before word2 preserved, two after removed\n\n        [<Test>]\n        let ``daw from whitespace before a word``() =\n            assertText \"word1  $  word2   word3\" \"daw\" \"word1 $  word3\" // four spaces before word2 removed, three after preserved\n\n        [<Test>]\n        let ``daw puts caret at next character``() =\n            assertText \"a b$ .\" \"daw\" \"a .$\"\n\n        [<Test>]\n        let ``daw deletes whitespace only``() =\n            assertText \"a. b$;\" \"daw\" \"a.;$\"\n\n        [<Test>]\n        let ``daw deletes leading whitespace if there's no trailing``() =\n            assertText \"a b$\" \"daw\" \"a$\" //\n\n        [<Test>]\n        let ``daw stops searching at EOL``() =\n            assertText \"word1$    \\n word2\" \"daw\" \"\\n$ word2\"\n\n        [<Test>]\n        let ``caw on a word``() =\n            assertText \"word1   word2$  word3\" \"caw\" \"word1   |word3\"\n\n        [<Test>]\n        let ``caw finds end of word``() =\n            assertText \"a [wo$rd_ ] b\" \"caw\" \"a [|] b\"\n\n        [<Test>]\n        let ``caw on a word with digits and underscores``() =\n            assertText \".a_8$ b\" \"caw\" \".|b\"\n\n        [<Test>]\n        let ``daw on a word delimited by punctuation``() =\n            assertText \"w1.w2$.w3\" \"daw\" \"w1..$w3\"\n\n        [<Test>]\n        let ``caw on a word delimited by punctuation``() =\n            assertText \"w1(w2$)w3\" \"caw\" \"w1(|)w3\"\n\n        [<Test>]\n        let ``daw on sequence of other characters``() =\n            assertText \"a ~!@#%^$&*=+:;?/<>(){}b \" \"daw\" \"ab$ \"\n\n        [<Test>]\n        let ``daw from white space at EOL extends to next line``() =\n            assertText \"a $ \\n b\" \"daw\" \"a$\"\n\n    module aW =\n        // Tests for aW. Reference: http://vimdoc.sourceforge.net/htmldoc/motion.html#aW\n        [<Test>]\n        let ``daW deletes a WORD``() =\n            assertText \"a W.W$ b\" \"daW\" \"a b$\"\n\n        [<Test>]\n        let ``daW removes trailing space``() =\n            assertText \"a W.W$ \" \"daW\" \"a $\"\n\n        [<Test>]\n        let ``daW removes leading space if no trailing``() =\n            assertText \"a W.W$\" \"daW\" \"a$\"\n\n        [<Test>]\n        let ``caW changes a WORD``() =\n            assertText \"a W.W$ b\" \"caW\" \"a |b\"\n\n    module iw =\n        // Tests for iw. Reference: http://vimdoc.sourceforge.net/htmldoc/motion.html#iw\n        [<Test>]\n        let ``diw deletes inside word``() =\n            assertText \"a b$c d\" \"diw\" \"a  $d\"\n\n        [<Test>]\n        let ``diw on sequence of other characters``() =\n            assertText \"a ~!@#%^&*=+:;?/<>(){}$b \" \"diw\" \"a b$ \"\n\n        [<Test>]\n        let ``ciw changes a word``() =\n            assertText \"a b$ c\" \"ciw\" \"a | c\"\n\n        [<Test>]\n        let ``diw stops at non-word character``() =\n            assertText \"%b$_123.\" \"diw\" \"%.$\"\n\n        [<Test>]\n        let ``diw deletes whitespace``() =\n            assertText \"a   $   b\" \"diw\" \"ab$\"\n\n        [<Test>]\n        let ``diw does not extend to next line``() =\n            assertText \"a $ \\n b\" \"diw\" \"a$\\n b\"\n\n        [<Test>]\n        let ``ciw changes inside word``() =\n            assertText \"a b$c d\" \"ciw\" \"a | d\"\n\n        // Tests for iW.\n        [<Test>]\n        let ``diW deletes a WORD``() =\n            assertText \"a W.W$ b\" \"diW\" \"a  $b\"\n\n        [<Test>]\n        let ``ciW changes a WORD``() =\n            assertText \"a W.W2$ b\" \"ciW\" \"a | b\"\n\n    // Tests for quoted strings. Reference: http://vimdoc.sourceforge.net/htmldoc/motion.html#a`\n    // Handling of different quotes is identical. The tests alternate between ', \" and `\n    [<Test>]\n    let ``ci' before quoted string``()  =\n        assertText \"var$ a = 'value'\" \"ci'\" \"var a = '|'\"\n\n    [<Test>]\n    let ``ci\" inside quoted string``() =\n        assertText \"var a = \\\"value$\\\"\" \"ci\\\"\" \"var a = \\\"|\\\"\"\n\n    [<Test>]\n    let ``di` before quoted string``() =\n        assertText \"var$ a = `value`\" \"di`\" \"var a = ``$\"\n\n    [<Test>]\n    let ``di' inside quoted string``() =\n        assertText \"var a = 'value$'\" \"di'\" \"var a = ''$\"\n\n    // TODO: ca\" and da\" tests cheat. The commands should delete the white space after the closing quote\n    [<Test>]\n    let ``ca\" before quoted string``()  =\n        assertText \"var$ a = \\\"value\\\"\" \"ca\\\"\" \"var a = |\"\n\n    [<Test>]\n    let ``ca` inside quoted string``() =\n        assertText \"var a = `value$`\" \"ca`\" \"var a = |\"\n\n    [<Test>]\n    let ``da' before quoted string``() =\n        assertText \"var$ a = 'value'\" \"da'\" \"var a = $\"\n\n    [<Test>]\n    let ``da` inside quoted string``() =\n        assertText \"var a = `value$`\" \"da`\" \"var a = $\"\n\n    [<Test>]\n    [<Ignore \"Didn't find out how to signal NoOp from getRange\">]\n    let ``ci\" does nothing when no quoted text on line``() =\n        assertText \"var$ a = b\\n\" \"ci\\\"\" \"var$ a = b\\n\"\n\n    [<Test>]\n    [<Ignore \"Handling of escaped quotes is not implemented\">]\n    let ``ci\" handles escaped quote``() =\n        assertText \"\"\" var$ a = \"\\\"\" \"\"\" \"ci\\\"\" \" var a = \\\"$\\\" \"\n\n    // Tests for braces. Reference: http://vimdoc.sourceforge.net/htmldoc/motion.html#a)\n    [<Test>]\n    let ``ci( handles nested parentheses backwards``() =\n        assertText \"(ignored)\\n((abc)\\n de$f)\\n(ignored)\" \"ci(\" \"(ignored)\\n(|)\\n(ignored)\"\n\n    [<Test>]\n    let ``ci( handles nested parentheses forwards``() =\n        assertText \"(ignored)\\n(abc$\\n (def))\\n(ignored)\" \"ci(\" \"(ignored)\\n(|)\\n(ignored)\"\n\n    [<Test>]\n    let ``da{ handles nested braces forwards``() =\n        assertText \"{a$ {b}}\\n{ignored}\" \"da{\" \"\\n${ignored}\"\n\n    // Tags. Reeference: http://vimdoc.sourceforge.net/htmldoc/motion.html#tag-blocks\n    module at =\n        [<Test>]\n        let ``dat from tag content``() =\n            assertText \"<a><b>val$</b></a>\" \"dat\" \"<a><$/a>\"\n\n        [<Test>]\n        let ``dat from tag declaration``() =\n            assertText \"<a><b$>val</b></a>\" \"dat\" \"<a><$/a>\"\n\n        [<Test>]\n        let ``dat ignores unclosed tag``() =\n            assertText \"<a$>val\" \"dat\" \"<a$>val\"\n\n        [<Test>]\n        let ``dat ignores self-closing tag``() =\n            assertText \"<a><b$/></a>\" \"dat\" \"$\"\n\n        [<Test>]\n        let ``dat handles tags with attributes``() =\n            assertText \"<a><b atr='val'>val$</b></a>\" \"dat\" \"<a><$/a>\"\n\n        [<Test>]\n        let ``dat handles tags with namespaces``() =\n            assertText \"<a><ns:b>val$</ns:b></a>\" \"dat\" \"<a><$/a>\"\n\n        [<Test>]\n        let ``dat finds unmatched closing tag``() =\n            assertText \"<a><b$><b></b></b></a>\" \"dat\" \"<a><$/a>\"\n\n        [<Test>]\n        let ``dat when closing > is on separate line``() =\n            assertText \"<a\\n>val$</a>\" \"dat\" \"$\"\n\n        [<Test>]\n        let ``cat from tag content``() =\n            assertText \"<a><b>val$</b></a>\" \"cat\" \"<a>|</a>\"\n\n        [<Test>]\n        let ``cat from tag declaration``() =\n            assertText \"<a><b$>val</b></a>\" \"cat\" \"<a>|</a>\"\n\n        [<Test>]\n        [<Ignore(\"Need to find out how to signal NoOp from getRange\")>]\n        let ``cat ignores unclosed tag``() =\n            assertText \"<a$>val\" \"cat\" \"<a$>val\"\n\n        [<Test>]\n        let ``cat handles tags with attributes``() =\n            assertText \"<a><b atr='val'>val$</b></a>\" \"cat\" \"<a>|</a>\"\n\n        [<Test>]\n        let ``cat ignores self-closing tag``() =\n            assertText \"<a><b$/></a>\" \"cat\" \"|\"\n\n    module it =\n        [<Test>]\n        let ``dit from tag content``() =\n            assertText \"<a><b>val$</b></a>\" \"dit\" \"<a><b><$/b></a>\"\n\n        [<Test>]\n        let ``dit from tag declaration``() =\n            assertText \"<a><b$>val</b></a>\" \"dit\" \"<a><b><$/b></a>\"\n\n        [<Test>]\n        let ``dit finds unmatched tag``() =\n            assertText \"<a><b$><b></b></b></a>\" \"dit\" \"<a><b><$/b></a>\"\n\n        [<Test>]\n        let ``dit outside a tag does nothing``() =\n            assertText \" $ <a>val</a>\" \"dit\" \" $ <a>val</a>\"\n\n        [<Test>]\n        let ``cit from tag content``() =\n            assertText \"<a><b>val$</b></a>\" \"cit\" \"<a><b>|</b></a>\"\n\n        [<Test>]\n        let ``cit from tag declaration``() =\n            assertText \"<a><b$>val</b></a>\" \"cit\" \"<a><b>|</b></a>\"\n\n        [<Test>]\n        let ``cit finds unmatched tag``() =\n            assertText \"<a><b$><b></b></b></a>\" \"cit\" \"<a><b>|</b></a>\"\n\n        [<Test>]\n        let ``cit when closing > is on separate line``() =\n            assertText \"<a\\n>val$</a>\" \"cit\" \"<a\\n>|</a>\"\n\n        [<Test>]\n        [<Ignore(\"Need to find out how to signal NoOp from getRange\")>]\n        let ``cit outside a tag does nothing``() =\n            assertText \" $ <a>val</a>\" \"cit\" \" $ <a>val</a>\"\n\n"
  },
  {
    "path": "XSVim.Tests/VisualTests.fs",
    "content": "﻿namespace XSVim.Tests\nopen NUnit.Framework\nopen XSVim\nopen System.Runtime.CompilerServices\nopen System.Threading.Tasks\n\n[<TestFixture>]\nmodule ``Visual tests`` =\n    [<SetUp;AsyncStateMachine(typeof<Task>)>]\n    let ``run before tests``() =\n        FixtureSetup.initialiseMonoDevelop()\n\n    let getClipboard() = Vim.registers.[EmptyRegister].content\n\n    [<Test>]\n    let ``Visual to end of line``() =\n        let _ = test \"abc$ def\\nghi\" \"v$y\"\n        getClipboard() |> should equal \"c def\"\n\n    [<Test>]\n    let ``Visual to end of word``() =\n        let _ = test \"ab$c def\\nghi\" \"vey\"\n        getClipboard() |> should equal \"bc\"\n\n    [<Test>]\n    let ``Visual to d``() =\n        let _ = test \"ab$cdef\" \"vtdy\"\n        getClipboard() |> should equal \"bc\"\n\n    [<Test>]\n    let ``Visual to d inclusive``() =\n        let _ = test \"ab$cdef\" \"vfdy\"\n        getClipboard() |> should equal \"bcd\"\n\n    [<Test>]\n    let ``Visual supports multipler``() =\n        let _ = test \"a$bcdef\" \"3vy\"\n        getClipboard() |> should equal \"abc\"\n\n    [<Test>]\n    let ``Visual line``() =\n        let _ = test \"aaa\\nbb$b\\nddd\" \"Vy\"\n        getClipboard() |> should equal \"bbb\\n\"\n\n    [<Test>]\n    let ``Visual to end of document``() =\n        let _ = test \"abc\\nde$f\\nghi\" \"vGy\"\n        getClipboard() |> should equal \"ef\\ng\"\n\n    [<Test>]\n    let ``Visual to start of document``() =\n        let _ = test \"abc\\nde$f\\nghi\" \"vggy\"\n        getClipboard() |> should equal \"abc\\nde\"\n\n    [<Test>]\n    let ``Visual line to end of document``() =\n        let _ = test \"abc\\nde$f\\nghi\" \"VGy\"\n        getClipboard() |> should equal \"def\\nghi\"\n\n    [<Test>]\n    let ``Visual line to start of document``() =\n        let _ = test \"abc\\nde$f\\nghi\" \"Vggy\"\n        getClipboard() |> should equal \"abc\\ndef\\n\"\n\n    [<Test>]\n    let ``Visual line supports multipler``() =\n        let _ = test \"abc\\nde$f\\nghi\" \"2Vy\"\n        getClipboard() |> should equal \"def\\nghi\"\n\n    [<Test>]\n    let ``Goto visual goes to last selection``() =\n        let _ = test \"abc\\nde$f\\nghi\" \"2V<esc>1Ggvy\"\n        getClipboard() |> should equal \"def\\nghi\"\n\n    [<Test>]\n    let ``Visual inside quotes``() =\n        let _ = test \"let s = \\\"some$ string\\\"\" \"vi\\\"y\"\n        getClipboard() |> should equal \"some string\"\n\n    [<Test>]\n    let ``v]) goes to next unmatched )``() =\n        let _ = test \"if (a$ == (b)c)\" \"v])y\" \n        getClipboard() |> should equal \"a == (b)c)\"\n\n    [<Test>]\n    let ``caret moves to other end of selection``() =\n        assertText \"abc$def\" \"vlllo\" \"abc$def\"\n\n    [<Test>]\n    let ``selection is not affected when you move to other end``() =\n        let _ = test \"abc$def\" \"vllloy\"\n        getClipboard() |> should equal \"cdef\"\n\n    [<Test>]\n    let ``Moving to the EOF in visual mode does select text``() =\n        let _  = test \" $\\na\\n\" \"vGy\"\n        Vim.registers.[EmptyRegister].content |> should equal \" \\na\\n\"\n\n    [<Test>]\n    let ``Moving by a paragraph to the start of file does select text``() =\n        let _ = test \"start\\n $\" \"v{y\"\n        Vim.registers.[EmptyRegister].content |> should equal \"start\\n \"\n"
  },
  {
    "path": "XSVim.Tests/XSVim.Tests.fsproj",
    "content": "﻿<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{3C522649-67F6-4F65-9CC9-D5847768FE68}</ProjectGuid>\n    <OutputType>Library</OutputType>\n    <RootNamespace>XSVim.Tests</RootNamespace>\n    <AssemblyName>XSVim.Tests</AssemblyName>\n    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>\n    <TestRunnerCommand>/Applications/Visual Studio.app/Contents/Resources/lib/monodevelop/bin/vstool.exe</TestRunnerCommand>\n    <TestRunnerArgs>run-md-tests</TestRunnerArgs>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug</OutputPath>\n    <DefineConstants>DEBUG</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <PlatformTarget></PlatformTarget>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release</OutputPath>\n    <DefineConstants></DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <GenerateTailCalls>true</GenerateTailCalls>\n    <PlatformTarget></PlatformTarget>\n  </PropertyGroup>\n  <PropertyGroup>\n    <FSharpTargetsPath>$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\FSharp\\Microsoft.FSharp.Targets</FSharpTargetsPath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(VisualStudioVersion)' == '10.0' OR '$(VisualStudioVersion)' == '11.0'\">\n    <FSharpTargetsPath>$(MSBuildExtensionsPath32)\\..\\Microsoft SDKs\\F#\\3.0\\Framework\\v4.0\\Microsoft.FSharp.Targets</FSharpTargetsPath>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"MonoDevelop.SourceEditor\">\n      <HintPath>..\\lib\\MonoDevelop.SourceEditor.dll</HintPath>\n    </Reference>\n    <Reference Include=\"MonoDevelop.Ide\">\n      <HintPath>..\\lib\\MonoDevelop.Ide.dll</HintPath>\n    </Reference>\n    <Reference Include=\"MonoDevelop.Core\">\n      <HintPath>..\\lib\\MonoDevelop.Core.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f\">\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f\">\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"GuiUnit\">\n      <HintPath>..\\lib\\GuiUnit.exe</HintPath>\n    </Reference>\n    <Reference Include=\"atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f\" />\n    <Reference Include=\"pango-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f\" />\n    <Reference Include=\"Mono.Posix\" />\n    <Reference Include=\"FSharp.Core\">\n      <HintPath>..\\packages\\FSharp.Core.4.6.2\\lib\\net45\\FSharp.Core.dll</HintPath>\n    </Reference>\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"Properties\\AssemblyInfo.fs\" />\n    <Compile Include=\"KeyboardMap.fs\" />\n    <Compile Include=\"TestHelpers.fs\" />\n    <Compile Include=\"DeleteTests.fs\" />\n    <Compile Include=\"Movement.fs\" />\n    <Compile Include=\"VisualTests.fs\" />\n    <Compile Include=\"KeyParsing.fs\" />\n    <Compile Include=\"MiscTests.fs\" />\n    <Compile Include=\"YankAndPut.fs\" />\n    <Compile Include=\"ChangeTests.fs\" />\n    <Compile Include=\"InsertionTests.fs\" />\n    <Compile Include=\"TextObjectSelectionTests.fs\" />\n    <Compile Include=\"MarkerTests.fs\" />\n    <Compile Include=\"ExModeTests.fs\" />\n    <Compile Include=\"MacrosTests.fs\" />\n    <Compile Include=\"IndentationTests.fs\" />\n    <None Include=\"packages.config\" />\n    <ProjectReference Include=\"..\\XSVim\\XSVim.fsproj\">\n      <Project>{9DB313D4-4CD1-455F-846F-42CD234DE626}</Project>\n      <Name>XSVim</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(FSharpTargetsPath)\" />\n</Project>"
  },
  {
    "path": "XSVim.Tests/YankAndPut.fs",
    "content": "﻿namespace XSVim.Tests\n\nopen NUnit.Framework\nopen XSVim\nopen System.Runtime.CompilerServices\nopen System.Threading.Tasks\n\n[<TestFixture>]\nmodule ``Yank and put tests`` =\n    [<SetUp;AsyncStateMachine(typeof<Task>)>]\n    let ``run before tests``() =\n        FixtureSetup.initialiseMonoDevelop()\n\n    [<Test>]\n    let ``Yanking puts cursor at original position before selection was made``() =\n        assertText \"a$bc\" \"vly\" \"a$bc\"\n\n    [<Test>]\n    let ``Yanking line supports multiplier``() =\n        let _  = test \"a$bc\\ndef\\nghi\" \"2yy\"\n        Vim.registers.[EmptyRegister].content |> should equal \"abc\\ndef\\n\"\n\n    [<Test>]\n    let ``Yanking doesn't move caret when there is no selection'``() =\n        assertText \"a$bcdef\" \"vll<esc>y$\" \"abc$def\"\n\n    [<Test>]\n    let ``Should put line at last line``() =\n        assertText \"  abc$\\ndef\" \"yyjp\" \"  abc\\ndef\\n  a$bc\"\n\n    [<Test>]\n    let ``Should put ab after``() =\n        assertText \"a$bc\" \"vldp\" \"cab$\"\n\n    [<Test>]\n    let ``Should put abc over selection in visual mode``() =\n        assertText \"a$bc\" \"vlyvllp\" \"ab$\"\n\n    [<Test>]\n    let ``P acts like p in visual mode``() =\n        assertText \"a$bc\" \"vlyvllP\" \"ab$\"\n\n    [<Test>]\n    let ``Can yank into a named register``() =\n        let _  = test \"ab$cd ef\" \"\\\"dyl\"\n        Vim.registers.[Register 'd'].content |> should equal \"b\"\n\n    [<Test>]\n    let ``yw at the end of a line consumes entire line``()=\n        assertText \"a$bc\" \"ywp\" \"aabc$bc\"\n\n    [<Test>]\n    let ``Visual line selection should work at EOF``() =\n        assertText \"123\\na$bc\" \"Vyp\" \"123\\nabc\\na$bc\"\n\n    [<Test>]\n    let ``Single line yank should work at EOF``() =\n        assertText \"123\\na$bc\" \"yyp\" \"123\\nabc\\na$bc\"\n\n    [<Test>]\n    let ``Line yank should work at EOF``() =\n        assertText \"abc\\nde$f\" \"yyp\" \"abc\\ndef\\nd$ef\"\n\n    [<Test>]\n    let ``Single line yank containing delimiter``() =\n        assertText \"1$23\\nabc\" \"yyp\" \"123\\n1$23\\nabc\"\n\n    [<Test>]\n    let ``Linewise put places caret at start of line``() =\n        assertText \" $  123\\n\" \"yyp\" \"   123\\n   1$23\\n\"\n\n    [<Test>]\n    let ``Linewise Put places caret at start of line``() =\n        assertText \" $  123\\n\" \"yyP\" \"   1$23\\n   123\\n\"\n\n    [<Test>]\n    let ``Linewise put at EOF places caret at start of line``() =\n        assertText \"\\n $  123\" \"yyp\" \"\\n   123\\n   1$23\"\n\n    [<Test>]\n    let ``Multi line put places caret at top line of paste``() =\n        assertText \"aa$a\\nbbb\\nccc\\n\" \"Vjdp\" \"ccc\\na$aa\\nbbb\\n\"\n\n    [<Test>]\n    let ``Multi line put on line without delimiter places caret at top line of paste``() =\n        assertText \"aa$a\\nbbb\\nccc\" \"Vjdp\" \"ccc\\na$aa\\nbbb\"\n\n    [<Test>]\n    let ``x with multiplier stops at EOL``() =\n        assertText \"ab$cdef\\n\" \"100xp\" \"abcdef$\\n\"\n\n    [<Test>]\n    let ``2dw yank two words``() =\n        assertText \"p$ublic int someInt = 1;\" \"2dwP\" \"public int s$omeInt = 1;\"\n\n    [<Test>]\n    let ``2d} yank two paragraphs``() =\n        let _  = test \" $\\na\\n\\nb\\n\" \"2d}\"\n        Vim.registers.[EmptyRegister].content |> should equal \" \\na\\n\\nb\\n\"\n"
  },
  {
    "path": "XSVim.Tests/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"FSharp.Core\" version=\"4.6.2\" targetFramework=\"net472\" />\n</packages>"
  },
  {
    "path": "XSVim.sln",
    "content": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 2012\nProject(\"{f2a71f9b-5d33-465a-a702-920d77279786}\") = \"XSVim\", \"XSVim\\XSVim.fsproj\", \"{9DB313D4-4CD1-455F-846F-42CD234DE626}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{E0ACA694-13C8-4B99-9FC9-196E85272651}\"\n\tProjectSection(SolutionItems) = preProject\n\t\taddin-project.xml = addin-project.xml\n\t\t.travis.yml = .travis.yml\n\t\tbuild.sh = build.sh\n\t\ttest.sh = test.sh\n\tEndProjectSection\nEndProject\nProject(\"{f2a71f9b-5d33-465a-a702-920d77279786}\") = \"XSVim.Tests\", \"XSVim.Tests\\XSVim.Tests.fsproj\", \"{3C522649-67F6-4F65-9CC9-D5847768FE68}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{9DB313D4-4CD1-455F-846F-42CD234DE626}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9DB313D4-4CD1-455F-846F-42CD234DE626}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9DB313D4-4CD1-455F-846F-42CD234DE626}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9DB313D4-4CD1-455F-846F-42CD234DE626}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3C522649-67F6-4F65-9CC9-D5847768FE68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3C522649-67F6-4F65-9CC9-D5847768FE68}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3C522649-67F6-4F65-9CC9-D5847768FE68}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3C522649-67F6-4F65-9CC9-D5847768FE68}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "addin-project.xml",
    "content": "<AddinProject appVersion=\"7.4\">\n    <Project>\n        <AddinFile>XSVim/bin/Debug/XSVim.dll</AddinFile>\n        <BuildFile>XSVim.sln</BuildFile>\n        <BuildConfiguration>Debug</BuildConfiguration>\n    </Project>\n</AddinProject>\n"
  },
  {
    "path": "build.sh",
    "content": "/Library/Frameworks/Mono.framework/Versions/Current/Commands/msbuild XSVim.sln\n"
  },
  {
    "path": "copy-assemblies.sh",
    "content": "#!/usr/bin/env bash\n\ncp /Applications/Visual\\ Studio.app/Contents/Resources/lib/monodevelop/bin/Mono.Addins.dll lib/\ncp /Applications/Visual\\ Studio.app/Contents/Resources/lib/monodevelop/bin/MonoDevelop.Core.dll lib/\ncp /Applications/Visual\\ Studio.app/Contents/Resources/lib/monodevelop/bin/MonoDevelop.Ide.dll lib/\ncp /Applications/Visual\\ Studio.app/Contents/Resources/lib/monodevelop/AddIns/DisplayBindings/SourceEditor/MonoDevelop.SourceEditor.dll lib/\ncp /Applications/Visual\\ Studio.app/Contents/Resources/lib/monodevelop/bin/System.Collections.Immutable.dll lib/\ncp /Applications/Visual\\ Studio.app/Contents/Resources/lib/monodevelop/bin/Xamarin.Mac.dll lib/\ncp /Applications/Visual\\ Studio.app/Contents/Resources/lib/monodevelop/bin/Xwt.dll lib/\n"
  },
  {
    "path": "run-from-source.sh",
    "content": "#! /bin/bash\n\nMONODEVELOP_CONSOLE_LOG_LEVEL=All MONODEVELOP_DEV_ADDINS=$(pwd)/XSVim/bin/Debug /Applications/Visual\\ Studio.app/Contents/MacOS/VisualStudio --no-redirect XSVim.sln\n"
  },
  {
    "path": "test.sh",
    "content": "mono \"/Applications/Visual Studio.app/Contents/Resources/lib/monodevelop/bin/vstool.exe\" run-md-tests XSVim.Tests/bin/Debug/XSVim.Tests.dll -labels\n"
  }
]