Skip to content

Commit

Permalink
Ability to run macros. Need to implement record now
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredpar committed Mar 12, 2011
1 parent 5e7a3bd commit 863fea1
Show file tree
Hide file tree
Showing 26 changed files with 387 additions and 145 deletions.
4 changes: 3 additions & 1 deletion Todo.txt
Original file line number Diff line number Diff line change
@@ -1,3 1,5 @@

- Need to see how readonly buffers and insert mode now play togehter. Start debugging, insert mode and type. Should get routed
X Need to see how readonly buffers and insert mode now play togehter. Start debugging, insert mode and type. Should get routed
through the special code in VsKeyProcess and hit Insert Mode head on
- Need a way a host (Visual Studio) can specify that Vim should pretend a KeyInput was processed. This will be important for
recording edits in macros.
50 changes: 26 additions & 24 deletions VimCore/CommandRunner.fs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 45,7 @@ type internal CommandRunner
let mutable _runBindData : BindData<Command * CommandBinding> option = None

/// True during the running of a particular KeyInput
let mutable _inRun = false
let mutable _inBind = false

/// Try and get the VisualSpan for the provided kind
member x.TryGetVisualSpan kind =
Expand Down Expand Up @@ -290,35 290,37 @@ type internal CommandRunner
if ki = KeyInputUtil.EscapeKey && x.ShouldEscapeCancelCurrentCommand() then
x.ResetState()
BindResult.Cancelled
elif _inRun then
elif _inBind then
// If we're in the middle of binding the previous value then error. We don't
// support re-entrancy while binding
BindResult.Error
else
_data <- {_data with Inputs = ki :: _data.Inputs }
_inRun <- true
try
let result =
let result =
_inBind <- true
try
match _runBindData with
| Some bindData -> bindData.BindFunction ki
| None -> x.BindCountAndRegister ki
match result with
| BindResult.Complete (command, commandBinding) ->
x.ResetState()
let result = _commandUtil.RunCommand command
let data = { Command = command; CommandBinding = commandBinding; CommandResult = result }
_commandRanEvent.Trigger data
BindResult.Complete data
| BindResult.Cancelled ->
x.ResetState()
BindResult.Error
| BindResult.Error ->
x.ResetState()
BindResult.Error
| BindResult.NeedMoreInput bindData ->
_runBindData <- Some bindData
BindResult.NeedMoreInput { KeyRemapMode = bindData.KeyRemapMode; BindFunction = x.Run }

finally
_inRun <-false
finally
_inBind <- false

match result with
| BindResult.Complete (command, commandBinding) ->
x.ResetState()
let result = _commandUtil.RunCommand command
let data = { Command = command; CommandBinding = commandBinding; CommandResult = result }
_commandRanEvent.Trigger data
BindResult.Complete data
| BindResult.Cancelled ->
x.ResetState()
BindResult.Error
| BindResult.Error ->
x.ResetState()
BindResult.Error
| BindResult.NeedMoreInput bindData ->
_runBindData <- Some bindData
BindResult.NeedMoreInput { KeyRemapMode = bindData.KeyRemapMode; BindFunction = x.Run }

member x.Add (command : CommandBinding) =
if Map.containsKey command.KeyInputSet _commandMap then
Expand Down
75 changes: 53 additions & 22 deletions VimCore/CommandUtil.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 9,23 @@ open Microsoft.VisualStudio.Text.Outlining

type internal CommandUtil
(
_textView : ITextView,
_buffer : IVimBuffer,
_operations : ICommonOperations,
_motionUtil : ITextViewMotionUtil,
_statusUtil : IStatusUtil,
_registerMap : IRegisterMap,
_markMap : IMarkMap,
_vimData : IVimData,
_localSettings : IVimLocalSettings,
_undoRedoOperations : IUndoRedoOperations,
_smartIndentationService : ISmartIndentationService,
_foldManager : IFoldManager,
_vimHost : IVimHost
_foldManager : IFoldManager
) =

let _globalSettings = _localSettings.GlobalSettings
let _textView = _buffer.TextView
let _textBuffer = _textView.TextBuffer
let _motionUtil = _buffer.TextViewMotionUtil
let _registerMap = _buffer.RegisterMap
let _markMap = _buffer.MarkMap
let _vimData = _buffer.VimData
let _localSettings = _buffer.Settings
let _globalSettings = _localSettings.GlobalSettings
let _vimHost = _buffer.Vim.VimHost

let mutable _inRepeatLastChange = false

Expand Down Expand Up @@ -227,7 228,7 @@ type internal CommandUtil
TextViewUtil.MoveCaretToPosition _textView span.Start.Position)

// Now that the delete is complete update the register
let value = { Value = StringData.OfSpan span; OperationKind = result.OperationKind }
let value = RegisterValue.String (StringData.OfSpan span, result.OperationKind)
_registerMap.SetRegisterValue register RegisterOperation.Delete value

commandResult
Expand Down Expand Up @@ -265,7 266,7 @@ type internal CommandUtil
// because we really didn't delete linewise but it's required to be a linewise
// operation.
let value = range.Extent.GetText() System.Environment.NewLine
let value = { Value = StringData.Simple value; OperationKind = OperationKind.LineWise }
let value = RegisterValue.OfString value OperationKind.LineWise
_registerMap.SetRegisterValue register RegisterOperation.Delete value)

/// Delete the selected lines and begin insert mode (implements the 'S', 'C' and 'R' visual
Expand Down Expand Up @@ -325,7 326,7 @@ type internal CommandUtil
if specialCaseBlock then deleteBlock col
else visualSpan.EditSpan.OverarchingSpan |> SnapshotLineRangeUtil.CreateForSpan |> deleteRange

let value = { Value = StringData.OfEditSpan editSpan; OperationKind = OperationKind.LineWise }
let value = RegisterValue.String (StringData.OfEditSpan editSpan, OperationKind.LineWise)
_registerMap.SetRegisterValue register RegisterOperation.Delete value

commandResult
Expand Down Expand Up @@ -373,7 374,7 @@ type internal CommandUtil
_operations.MoveCaretForVirtualEdit())

// Put the deleted text into the specified register
let value = { Value = StringData.OfSpan span; OperationKind = OperationKind.CharacterWise }
let value = RegisterValue.String (StringData.OfSpan span, OperationKind.CharacterWise)
_registerMap.SetRegisterValue register RegisterOperation.Delete value

CommandResult.Completed ModeSwitch.NoSwitch
Expand All @@ -396,7 397,7 @@ type internal CommandUtil
TextViewUtil.MoveCaretToPosition _textView startPoint.Position)

// Put the deleted text into the specified register once the delete completes
let value = { Value = StringData.OfSpan span; OperationKind = OperationKind.CharacterWise }
let value = RegisterValue.String (StringData.OfSpan span, OperationKind.CharacterWise)
_registerMap.SetRegisterValue register RegisterOperation.Delete value

CommandResult.Completed ModeSwitch.NoSwitch
Expand Down Expand Up @@ -449,7 450,7 @@ type internal CommandUtil

editSpan)

let value = { Value = StringData.OfEditSpan editSpan; OperationKind = OperationKind.LineWise }
let value = RegisterValue.String (StringData.OfEditSpan editSpan, OperationKind.LineWise)
_registerMap.SetRegisterValue register RegisterOperation.Delete value

CommandResult.Completed ModeSwitch.SwitchPreviousMode
Expand Down Expand Up @@ -484,7 485,7 @@ type internal CommandUtil
| VisualSpan.Character _ -> OperationKind.CharacterWise
| VisualSpan.Line _ -> OperationKind.LineWise
| VisualSpan.Block _ -> OperationKind.CharacterWise
let value = { Value = StringData.OfEditSpan visualSpan.EditSpan; OperationKind = operationKind }
let value = RegisterValue.String (StringData.OfEditSpan visualSpan.EditSpan, operationKind)
_registerMap.SetRegisterValue register RegisterOperation.Delete value

CommandResult.Completed ModeSwitch.SwitchPreviousMode
Expand Down Expand Up @@ -518,7 519,7 @@ type internal CommandUtil
TextViewUtil.MoveCaretToPoint _textView (SnapshotPoint(snapshot, span.Start.Position)))

// Now update the register after the delete completes
let value = { Value = stringData; OperationKind = OperationKind.LineWise }
let value = RegisterValue.String (stringData, OperationKind.LineWise)
_registerMap.SetRegisterValue register RegisterOperation.Delete value

CommandResult.Completed ModeSwitch.NoSwitch
Expand Down Expand Up @@ -551,7 552,7 @@ type internal CommandUtil
TextViewUtil.MoveCaretToPosition _textView span.Start.Position)

// Update the register with the result
let value = { Value = StringData.OfSpan span; OperationKind = result.OperationKind }
let value = RegisterValue.String (StringData.OfSpan span, result.OperationKind)
_registerMap.SetRegisterValue register RegisterOperation.Delete value

CommandResult.Completed ModeSwitch.NoSwitch
Expand All @@ -577,7 578,7 @@ type internal CommandUtil

// Delete is complete so update the register. Strangely enough this is a characterwise
// operation even though it involves line deletion
let value = { Value = StringData.OfSpan span; OperationKind = OperationKind.CharacterWise }
let value = RegisterValue.String (StringData.OfSpan span, OperationKind.CharacterWise)
_registerMap.SetRegisterValue register RegisterOperation.Delete value

CommandResult.Completed ModeSwitch.NoSwitch
Expand Down Expand Up @@ -1063,7 1064,7 @@ type internal CommandUtil
EditSpan.Block col, OperationKind.CharacterWise)

// Update the register with the deleted text
let value = { Value = StringData.OfEditSpan deletedSpan; OperationKind = operationKind }
let value = RegisterValue.String (StringData.OfEditSpan deletedSpan, operationKind)
_registerMap.SetRegisterValue register RegisterOperation.Delete value

CommandResult.Completed ModeSwitch.SwitchPreviousMode
Expand Down Expand Up @@ -1223,6 1224,35 @@ type internal CommandUtil
| Command.VisualCommand (command, data, visualSpan) -> x.RunVisualCommand command data visualSpan
| Command.LegacyCommand data -> data.Function()

/// Run the Macro which is present in the specified char
member x.RunMacro registerName =
let name =
// TODO: Need to handle, = and .
if CharUtil.IsDigit registerName then
NumberedRegister.OfChar registerName |> Option.map RegisterName.Numbered
elif registerName = '*' then
SelectionAndDropRegister.Register_Star |> RegisterName.SelectionAndDrop |> Some
else
let registerName = CharUtil.ToLower registerName
NamedRegister.OfChar registerName |> Option.map RegisterName.Named

match name with
| None ->
_operations.Beep()
| Some name ->
let register = _registerMap.GetRegister name

// The macro should be executed as a single action. Use an undo transactino to
// give the proper undo behavior
x.EditWithUndoTransaciton "RunMacro" (fun () ->

// Replay the key strokes one at a time
let list = register.RegisterValue.KeyInputList
for keyInput in list do
_buffer.Process keyInput |> ignore)

CommandResult.Completed ModeSwitch.NoSwitch

/// Run a NormalCommand against the buffer
member x.RunNormalCommand command (data : CommandData) =
let register = _registerMap.GetRegister data.RegisterNameOrDefault
Expand Down Expand Up @@ -1267,6 1297,7 @@ type internal CommandUtil
| NormalCommand.SplitViewVertically -> x.SplitViewVertically()
| NormalCommand.RepeatLastCommand -> x.RepeatLastCommand data
| NormalCommand.ReplaceChar keyInput -> x.ReplaceChar keyInput data.CountOrDefault
| NormalCommand.RunMacro registerName -> x.RunMacro registerName
| NormalCommand.Yank motion -> x.RunWithMotion motion (x.YankMotion register)

/// Run a VisualCommand against the buffer
Expand Down Expand Up @@ -1463,12 1494,12 @@ type internal CommandUtil
TextViewUtil.MoveCaretToPoint _textView (SnapshotPoint(snapshot, position)))

// Put the deleted text into the specified register
let value = { Value = StringData.OfSpan span; OperationKind = OperationKind.CharacterWise }
let value = RegisterValue.String (StringData.OfSpan span, OperationKind.CharacterWise)
_registerMap.SetRegisterValue register RegisterOperation.Delete value)

/// Yank the contents of the motion into the specified register
member x.YankMotion register (result: MotionResult) =
let value = { Value = StringData.OfSpan result.OperationSpan; OperationKind = result.OperationKind }
let value = RegisterValue.String (StringData.OfSpan result.OperationSpan, result.OperationKind)
_registerMap.SetRegisterValue register RegisterOperation.Yank value
CommandResult.Completed ModeSwitch.NoSwitch

Expand Down
2 changes: 1 addition & 1 deletion VimCore/CommandUtil.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 7,6 @@ open Microsoft.VisualStudio.Text.Outlining

type internal CommandUtil =

new : ITextView * Modes.ICommonOperations * ITextViewMotionUtil * IStatusUtil * IRegisterMap * IMarkMap * IVimData * IVimLocalSettings * IUndoRedoOperations * ISmartIndentationService * IFoldManager * IVimHost -> CommandUtil
new : IVimBuffer * Modes.ICommonOperations * IStatusUtil * IUndoRedoOperations * ISmartIndentationService * IFoldManager -> CommandUtil

interface ICommandUtil
8 changes: 8 additions & 0 deletions VimCore/CoreInterfaces.fs
Original file line number Diff line number Diff line change
Expand Up @@ -692,19 692,25 @@ type VisualSpan =
[<System.Flags>]
type CommandFlags =
| None = 0x0

/// Relates to the movement of the cursor. A movement command does not alter the
/// last command
| Movement = 0x1

/// A Command which can be repeated
| Repeatable = 0x2

/// A Command which should not be considered when looking at last changes
| Special = 0x4

/// Can handle the escape key if provided as part of a Motion or Long command extra
/// input
| HandlesEscape = 0x8

/// For the purposes of change repeating the command is linked with the following
/// text change
| LinkedWithNextTextChange = 0x10

/// For Visual Mode commands which should reset the cursor to the original point
/// after completing
| ResetCaret = 0x20
Expand Down Expand Up @@ -881,6 887,8 @@ type NormalCommand =
/// Replace the char under the cursor with the given char
| ReplaceChar of KeyInput

/// Run the macro contained in the register specified by the char value
| RunMacro of char
/// Set the specified mark to the current value of the caret
| SetMarkToCaret of char

Expand Down
9 changes: 9 additions & 0 deletions VimCore/FSharpUtil.fs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 248,15 @@ module internal CharUtil =
let right = func right
left = right

/// Get the Char value for the given ASCII code
let OfAsciiValue (value : byte) =
let asciiArray = [| value |]
let charArray = System.Text.Encoding.ASCII.GetChars(asciiArray)
if charArray.Length > 0 then
charArray.[0]
else
MinValue

let (|WhiteSpace|NonWhiteSpace|) char =
if IsWhiteSpace char then
WhiteSpace
Expand Down
6 changes: 3 additions & 3 deletions VimCore/KeyInput.fs
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 146,12 @@ module KeyInputUtil =
(VimKey.Back, Some '\b')
(VimKey.FormFeed, Some '\f')
(VimKey.Enter, Some '\n')
(VimKey.Escape, None)
(VimKey.Escape, 27uy |> CharUtil.OfAsciiValue |> Some)
(VimKey.Left, None)
(VimKey.Up, None)
(VimKey.Right, None)
(VimKey.Down, None)
(VimKey.Delete, None)
(VimKey.Delete, 127uy |> CharUtil.OfAsciiValue |> Some)
(VimKey.Help, None)
(VimKey.End, None)
(VimKey.PageUp, None)
Expand Down Expand Up @@ -284,7 284,6 @@ module KeyInputUtil =
(VimKey.Tab, Some '\t')
(VimKey.LineFeed, None) ]


let VimKeyInputList =
VimKeyRawData
|> Seq.map (fun (key,charOpt) -> KeyInput(key, KeyModifiers.None, charOpt ))
Expand All @@ -301,6 300,7 @@ module KeyInputUtil =
/// may map to the same character their should be a primary KeyInput for every
/// char. This map holds that mapping
let CharToKeyInputMap =

let inputs =
VimKeyInputList
|> Seq.map (fun ki -> OptionUtil.combine ki.RawChar ki )
Expand Down
2 changes: 1 addition & 1 deletion VimCore/Modes_Command_CommandProcessor.fs
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 389,7 @@ type internal CommandProcessor
let span = range.ExtentIncludingLineBreak
_textBuffer.Delete(span.Span) |> ignore

let value = { Value = StringData.OfSpan span; OperationKind = OperationKind.LineWise }
let value = RegisterValue.String (StringData.OfSpan span, OperationKind.LineWise)
_registerMap.SetRegisterValue reg RegisterOperation.Delete value

member x.ProcessUndo rest _ _ =
Expand Down
6 changes: 3 additions & 3 deletions VimCore/Modes_CommonOperations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -843,15 843,15 @@ type internal CommonOperations ( _data : OperationsData ) =


member x.UpdateRegister reg regOp editSpan opKind =
let value = { Value = StringData.OfEditSpan editSpan; OperationKind = opKind }
let value = RegisterValue.String (StringData.OfEditSpan editSpan, opKind)
x.UpdateRegister reg regOp value
member x.UpdateRegisterForValue reg regOp value =
x.UpdateRegister reg regOp value
member x.UpdateRegisterForSpan reg regOp span opKind =
let value = { Value=StringData.OfSpan span; OperationKind=opKind }
let value = RegisterValue.String (StringData.OfSpan span, opKind)
x.UpdateRegister reg regOp value
member x.UpdateRegisterForCollection reg regOp col opKind =
let value = { Value=StringData.OfNormalizedSnasphotSpanCollection col; OperationKind=opKind }
let value = RegisterValue.String (StringData.OfNormalizedSnasphotSpanCollection col, opKind)
x.UpdateRegister reg regOp value

member x.GoToLocalDeclaration() =
Expand Down
Loading

0 comments on commit 863fea1

Please sign in to comment.