Skip to content

Commit

Permalink
Fixes some issues with VimKeyProcessor
Browse files Browse the repository at this point in the history
The last fix broke auto-indentation and signature help.

This code is now simpler with less hacks and seems to work much better.

Tested the following and didn't find any issues.

- inoremap
- auto indentation when pressing } or ;
- Insert mode insertion followed by '.'
- Signature help
- Snippet completion
- Intellisense
- Inline rename
- Macro recording involving insert mode

Fixes #2888
  • Loading branch information
nosami committed May 29, 2021
1 parent 5124ebc commit 5f1b655
Showing 1 changed file with 31 additions and 59 deletions.
90 changes: 31 additions & 59 deletions Src/VimMac/VimKeyProcessor.cs
@@ -1,10 +1,7 @@
using AppKit;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Formatting;
using MonoDevelop.Ide;
using Vim.Mac;
using Vim.UI.Cocoa.Implementation.InlineRename;

namespace Vim.UI.Cocoa
Expand All @@ -21,9 +18,9 @@ namespace Vim.UI.Cocoa
/// </summary>
internal sealed class VimKeyProcessor : KeyProcessor
{
private readonly IVimBuffer _vimBuffer;
private readonly ITextView _textView;
private readonly IKeyUtil _keyUtil;

private IVimBuffer VimBuffer { get; }
private readonly ICompletionBroker _completionBroker;
private readonly ISignatureHelpBroker _signatureHelpBroker;
private readonly InlineRenameListenerFactory _inlineRenameListenerFactory;
Expand All @@ -36,19 +33,14 @@ internal sealed class VimKeyProcessor : KeyProcessor
InlineRenameListenerFactory inlineRenameListenerFactory)

{
VimBuffer = vimBuffer;
_vimBuffer = vimBuffer;
_textView = vimBuffer.TextView;
_keyUtil = keyUtil;
_completionBroker = completionBroker;
_signatureHelpBroker = signatureHelpBroker;
_inlineRenameListenerFactory = inlineRenameListenerFactory;
}

public ITextBuffer TextBuffer => VimBuffer.TextBuffer;

public ITextView TextView => VimBuffer.TextView;

public bool ModeChanged { get; private set; }

/// <summary>
/// This handler is necessary to intercept keyboard input which maps to Vim
/// commands but doesn't map to text input. Any combination which can be
Expand All @@ -67,48 +59,30 @@ public override void KeyDown(KeyEventArgs e)
VimTrace.TraceInfo("VimKeyProcessor::KeyDown {0} {1}", e.Characters, e.CharactersIgnoringModifiers);

bool handled = false;
if (ShouldBeProcessedByVim(e))
{
var oldMode = VimBuffer.Mode.ModeKind;

VimTrace.TraceDebug(oldMode.ToString());
// Attempt to map the key information into a KeyInput value which can be processed
// by Vim. If this works and the key is processed then the input is considered
// to be handled

if (_keyUtil.TryConvertSpecialToKeyInput(e.Event, out KeyInput keyInput))
// Attempt to map the key information into a KeyInput value which can be processed
// by Vim. If this works and the key is processed then the input is considered
// to be handled
bool canConvert = _keyUtil.TryConvertSpecialToKeyInput(e.Event, out KeyInput keyInput);
if (canConvert)
{
if (ShouldBeProcessedByVim(e, keyInput))
{
var bufferedKeyInputsWasEmpty = VimBuffer.BufferedKeyInputs.IsEmpty;

handled = TryProcess(keyInput);

if (handled
&& BufferedKeysWasEmptyAndIsEmpty()
&& oldMode == ModeKind.Insert
&& CharTriggersCompletion(keyInput.Char)
&& !_completionBroker.IsCompletionActive(VimBuffer.TextView))
{
// Because VsVim handled the key press for us in insert mode,
// we need to trigger the completion window to open.
_completionBroker.TriggerCompletion(VimBuffer.TextView);
}

bool BufferedKeysWasEmptyAndIsEmpty()
{
// We don't want the completion window to appear if we
// have something like `inoremap fd <esc>`
// and we just typed the first 'f' or the 'd'
return bufferedKeyInputsWasEmpty
&& VimBuffer.BufferedKeyInputs.IsEmpty;
}
}
else
{
// Needed to handle things like insert mode macro recording
_vimBuffer.SimulateProcessed(keyInput);
}
}

VimTrace.TraceInfo("VimKeyProcessor::KeyDown Handled = {0}", handled);

var status = Mac.StatusBar.GetStatus(VimBuffer);
var status = Mac.StatusBar.GetStatus(_vimBuffer);
var text = status.Text;
if (VimBuffer.ModeKind == ModeKind.Command)
if (_vimBuffer.ModeKind == ModeKind.Command)
{
// Add a fake 'caret'
text = text.Insert(status.CaretPosition, "|");
Expand All @@ -117,19 +91,9 @@ bool BufferedKeysWasEmptyAndIsEmpty()
e.Handled = handled;
}

private bool CharTriggersCompletion(char c)
{
return c == '_' || c == '.' || char.IsLetterOrDigit(c);
}

/// <summary>
/// Try and process the given KeyInput with the IVimBuffer. This is overridable by
/// derived classes in order for them to prevent any KeyInput from reaching the
/// IVimBuffer
/// </summary>
private bool TryProcess(KeyInput keyInput)
{
return VimBuffer.CanProcess(keyInput) && VimBuffer.Process(keyInput).IsAnyHandled;
return _vimBuffer.CanProcessAsCommand(keyInput) && _vimBuffer.Process(keyInput).IsAnyHandled;
}

private bool KeyEventIsDeadChar(KeyEventArgs e)
Expand All @@ -142,7 +106,7 @@ private bool IsEscapeKey(KeyEventArgs e)
return (NSKey)e.Event.KeyCode == NSKey.Escape;
}

private bool ShouldBeProcessedByVim(KeyEventArgs e)
private bool ShouldBeProcessedByVim(KeyEventArgs e, KeyInput keyInput)
{
if (KeyEventIsDeadChar(e))
// When a dead key combination is pressed we will get the key down events in
Expand All @@ -154,16 +118,24 @@ private bool ShouldBeProcessedByVim(KeyEventArgs e)
// we can process in the TextInput event
return false;

if (_completionBroker.IsCompletionActive(TextView) && !IsEscapeKey(e))
if ((_vimBuffer.ModeKind.IsAnyInsert() || _vimBuffer.ModeKind.IsAnySelect()) &&
!_vimBuffer.CanProcessAsCommand(keyInput) &&
keyInput.Char > 0x1f)
return false;

if (IsEscapeKey(e))
return true;

if (_completionBroker.IsCompletionActive(_textView))
return false;

if (_signatureHelpBroker.IsSignatureHelpActive(TextView) && !IsEscapeKey(e))
if (_signatureHelpBroker.IsSignatureHelpActive(_textView))
return false;

if (_inlineRenameListenerFactory.InRename)
return false;

if (VimBuffer.Mode.ModeKind == ModeKind.Insert && e.Characters == "\t")
if (_vimBuffer.ModeKind.IsAnyInsert() && e.Characters == "\t")
// Allow tab key to work for snippet completion
return false;

Expand Down

0 comments on commit 5f1b655

Please sign in to comment.