/// <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 /// translated into actual text input will be done so much more accurately by /// WPF and will end up in the TextInput event. /// /// An example of why this handler is needed is for key combinations like /// Shift+Escape. This combination won't translate to an actual character in most /// (possibly all) keyboard layouts. This means it won't ever make it to the /// TextInput event. But it can translate to a Vim command or mapped keyboard /// combination that we do want to handle. Hence we override here specifically /// to capture those circumstances /// </summary> public override void KeyDown(KeyEventArgs e) { VimTrace.TraceInfo("VimKeyProcessor::KeyDown {0} {1}", e.Characters, e.CharactersIgnoringModifiers); bool handled; if (KeyEventIsDeadChar(e)) { // When a dead key combination is pressed we will get the key down events in // sequence after the combination is complete. The dead keys will come first // and be followed the final key which produces the char. That final key // is marked as DeadCharProcessed. // // All of these should be ignored. They will produce a TextInput value which // we can process in the TextInput event handled = false; } else if (_completionBroker.IsCompletionActive(TextView) && !IsEscapeKey(e)) { handled = false; } else if (_signatureHelpBroker.IsSignatureHelpActive(TextView)) { handled = false; } else if (_inlineRenameListenerFactory.InRename) { handled = false; } else { 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)) { handled = TryProcess(keyInput); } else { handled = false; } } VimTrace.TraceInfo("VimKeyProcessor::KeyDown Handled = {0}", handled); var status = Mac.StatusBar.GetStatus(VimBuffer); var text = status.Text; if (VimBuffer.ModeKind == ModeKind.Command) { // Add a fake 'caret' text = text.Insert(status.CaretPosition, "|"); } IdeApp.Workbench.StatusBar.ShowMessage(text); e.Handled = handled; }
/// <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 /// translated into actual text input will be done so much more accurately by /// WPF and will end up in the TextInput event. /// /// An example of why this handler is needed is for key combinations like /// Shift+Escape. This combination won't translate to an actual character in most /// (possibly all) keyboard layouts. This means it won't ever make it to the /// TextInput event. But it can translate to a Vim command or mapped keyboard /// combination that we do want to handle. Hence we override here specifically /// to capture those circumstances /// </summary> 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)) { handled = TryProcess(keyInput); } } VimTrace.TraceInfo("VimKeyProcessor::KeyDown Handled = {0}", handled); var status = Mac.StatusBar.GetStatus(VimBuffer); var text = status.Text; if (VimBuffer.ModeKind == ModeKind.Command) { // Add a fake 'caret' text = text.Insert(status.CaretPosition, "|"); } IdeApp.Workbench.StatusBar.ShowMessage(text); e.Handled = handled; }
private ReadOnlyCollection <ITagSpan <MarkGlyphTag> > GetTags(SnapshotSpan span) { if (_glyphPairs.Count == 0) { return(s_emptyTagList); } var snapshot = span.Snapshot; var list = new List <ITagSpan <MarkGlyphTag> >(); VimTrace.TraceDebug($"MarkGlyphTagger::GetTags: starting..."); foreach (var pair in _glyphPairs) { var chars = pair.Item1; var lineNumber = pair.Item2; if (lineNumber < snapshot.LineCount) { var line = snapshot.GetLineFromLineNumber(lineNumber); var startSpan = new SnapshotSpan(line.Start, 0); if (span.Contains(startSpan)) { VimTrace.TraceDebug($"MarkGlyphTagger::GetTags: tag {lineNumber} {chars}"); var tag = new MarkGlyphTag(chars); var tagSpan = new TagSpan <MarkGlyphTag>(startSpan, tag); list.Add(tagSpan); } } } return(list.ToReadOnlyCollectionShallow()); }
private void CachePairs() { _glyphPairs.Clear(); if (_activeMarks == 0) { return; } var pairs = _lineNumberMap .Where(pair => pair.Value != -1) .GroupBy(pair => pair.Value) .Select(grouping => Tuple.Create( String.Concat( grouping .Select(pair => pair.Key.Char) .OrderBy(key => key)), grouping.Key ) ); _glyphPairs.AddRange(pairs); VimTrace.TraceDebug($"MarkGlyphTagger: Glyph Pairs"); foreach (var pair in _glyphPairs) { VimTrace.TraceDebug($"MarkGlyphTagger: {pair.Item2} -> {pair.Item1}"); } }
/// <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 /// translated into actual text input will be done so much more accurately by /// WPF and will end up in the TextInput event. /// /// An example of why this handler is needed is for key combinations like /// Shift+Escape. This combination won't translate to an actual character in most /// (possibly all) keyboard layouts. This means it won't ever make it to the /// TextInput event. But it can translate to a Vim command or mapped keyboard /// combination that we do want to handle. Hence we override here specifically /// to capture those circumstances /// </summary> 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)) { 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); } } } VimTrace.TraceInfo("VimKeyProcessor::KeyDown Handled = {0}", handled); var status = Mac.StatusBar.GetStatus(VimBuffer); var text = status.Text; if (VimBuffer.ModeKind == ModeKind.Command) { // Add a fake 'caret' text = text.Insert(status.CaretPosition, "|"); } IdeApp.Workbench.StatusBar.ShowMessage(text); e.Handled = handled; }
private CommandStatus QueryStatus(EditCommand editCommand) { VimTrace.TraceDebug("VsCommandTarget::QueryStatus {0}", editCommand); var action = CommandStatus.PassOn; foreach (var commandTarget in _commandTargets) { action = commandTarget.QueryStatus(editCommand); if (action != CommandStatus.PassOn) { break; } } VimTrace.TraceDebug("VsCommandTarget::QueryStatus {0}", action); return(action); }
/// <summary> /// The async completion presenter will fade out the completion menu when the control key is clicked. That /// is unfortunate for VsVim as control is held down for the duration of a completion session. This ... method /// is used to reset the opacity to 1.0 /// </summary> private void ResetTipOpacity(object sender, EventArgs e) { try { var methodInfo = _vsTextView.GetType().BaseType.GetMethod( "SetTipOpacity", BindingFlags.NonPublic | BindingFlags.Instance, Type.DefaultBinder, types: new[] { typeof(double) }, modifiers: null); if (methodInfo is object) { methodInfo.Invoke(_vsTextView, new object[] { (double)1.0 }); } } catch (Exception ex) { VimTrace.TraceDebug($"Unable to set tip opacity {ex}"); } }
private void OnTextBufferChanged(object sender, TextContentChangedEventArgs e) { VimTrace.TraceDebug($"MarkGlyphTagger::TextBufferChanged {e.AfterVersion}"); UpdateAllMarks(); }