protected override void OnAddedToEditor(TextEditorData data) { base.OnAddedToEditor(data); ViMark special1 = new ViMark('`', false); marks ['`'] = special1; special1.SaveMark(data); }
public static bool Mark(ViBuilderContext ctx) { char c = ctx.LastKey.Char; if (!char.IsLetterOrDigit(c)) { ctx.SetError("Invalid Mark"); return(true); } ctx.RunAction((ViEditor ed) => { ViMark mark; if (!ed.Marks.TryGetValue(c, out mark)) { ed.Marks [c] = mark = new ViMark(c); } mark.SaveMark(ed.Data); }); return(true); }
public static bool Mark(ViBuilderContext ctx) { char c = ctx.LastKey.Char; if (!char.IsLetterOrDigit (c)) { ctx.SetError ("Invalid Mark"); return true; } ctx.RunAction ((ViEditor ed) => { ViMark mark; if (!ed.Marks.TryGetValue (c, out mark)) ed.Marks [c] = mark = new ViMark (c); mark.SaveMark (ed.Data); }); return true; }
protected override void HandleKeypress(Gdk.Key key, uint unicodeKey, Gdk.ModifierType modifier) { // if (Data != null) { // Console.WriteLine ("Data is not null at start of ViMode.HandleKeypress"); // Console.WriteLine (CurState); // Console.WriteLine ("unicodeKey: {0}", (char)unicodeKey); // } // Reset on Esc, Ctrl-C, Ctrl-[ if (key == Gdk.Key.Escape) { if (currentMacro != null) { // Record Escapes into the macro since it actually does something ViMacro.KeySet toAdd = new ViMacro.KeySet(); toAdd.Key = key; toAdd.Modifiers = modifier; toAdd.UnicodeKey = unicodeKey; currentMacro.KeysPressed.Enqueue(toAdd); } if (PrevState == State.Change && CurState == State.Insert) { LastInsert.Clear (); LastInsert.AddRange(InsertBuffer); InsertBuffer.Clear (); LastAction.Add (RepeatLastInsert); } else if (CurState == State.Insert) { LastInsert.Clear (); LastInsert.AddRange(InsertBuffer); InsertBuffer.Clear (); if (!lastActionStarted) { lastActionStarted = true; LastAction.Clear (); } LastAction.Add (RepeatLastInsert); } Reset(string.Empty); return; } else if (((key == Gdk.Key.c || key == Gdk.Key.bracketleft) && (modifier & Gdk.ModifierType.ControlMask) != 0)) { Reset (string.Empty); if (currentMacro != null) { // Otherwise remove the macro from the pool macros.Remove(currentMacro.MacroCharacter); currentMacro = null; } return; } else if (currentMacro != null && !((char)unicodeKey == 'q' && modifier == Gdk.ModifierType.None)) { ViMacro.KeySet toAdd = new ViMacro.KeySet(); toAdd.Key = key; toAdd.Modifiers = modifier; toAdd.UnicodeKey = unicodeKey; currentMacro.KeysPressed.Enqueue(toAdd); } Action<TextEditorData> action = null; bool lineAction = false; //handle numeric keypress if (AcceptNumericPrefix && '0' <= (char)unicodeKey && (char)unicodeKey <= '9') { numericPrefix += (char)unicodeKey; return; } switch (CurState) { case State.Unknown: Reset (string.Empty); goto case State.Normal; case State.Normal: if (((modifier & (Gdk.ModifierType.ControlMask)) == 0)) { if (key == Gdk.Key.Delete) unicodeKey = 'x'; switch ((char)unicodeKey) { case '?': case '/': case ':': CurState = State.Command; commandBuffer.Append ((char)unicodeKey); Status = commandBuffer.ToString (); return; case 'A': StartNewLastAction (CaretMoveActions.LineEnd); RunAction (CaretMoveActions.LineEnd); goto case 'i'; case 'I': StartNewLastAction (CaretMoveActions.LineFirstNonWhitespace); RunAction (CaretMoveActions.LineFirstNonWhitespace); goto case 'i'; case 'a': StartNewLastAction (CaretMoveActions.Right); //use CaretMoveActions so that we can move past last character on line end RunAction (CaretMoveActions.Right); goto case 'i'; case 'i': Caret.Mode = CaretMode.Insert; Status = "-- INSERT --"; CurState = State.Insert; return; case 'R': Caret.Mode = CaretMode.Underscore; Status = "-- REPLACE --"; CurState = State.Replace; return; case 'V': Status = "-- VISUAL LINE --"; Data.SetSelectLines (Caret.Line, Caret.Line); CurState = State.VisualLine; return; case 'v': Status = "-- VISUAL --"; CurState = State.Visual; RunAction (ViActions.VisualSelectionFromMoveAction (ViActions.Right)); return; case 'd': Status = "d"; CurState = State.Delete; return; case 'y': Status = "y"; CurState = State.Yank; return; case 'Y': CurState = State.Yank; HandleKeypress (Gdk.Key.y, (int)'y', Gdk.ModifierType.None); return; case 'O': StartNewLastAction (ViActions.NewLineAbove); RunAction (ViActions.NewLineAbove); goto case 'i'; case 'o': StartNewLastAction (ViActions.NewLineBelow); RunAction (ViActions.NewLineBelow); goto case 'i'; case 'r': Caret.Mode = CaretMode.Underscore; Status = "-- REPLACE --"; CurState = State.WriteChar; return; case 'c': Caret.Mode = CaretMode.Insert; Status = "c"; CurState = State.Change; return; case 'x': if (Data.Caret.Column == Data.Document.GetLine (Data.Caret.Line).Length + 1) return; Status = string.Empty; if (!Data.IsSomethingSelected) RunActions (SelectionActions.FromMoveAction (CaretMoveActions.Right), ClipboardActions.Cut); else RunAction (ClipboardActions.Cut); ViActions.RetreatFromLineEnd (Data); return; case 'X': if (Data.Caret.Column == DocumentLocation.MinColumn) return; Status = string.Empty; if (!Data.IsSomethingSelected && 0 < Caret.Offset) RunActions (SelectionActions.FromMoveAction (CaretMoveActions.Left), ClipboardActions.Cut); else RunAction (ClipboardActions.Cut); return; case 'D': RunActions (SelectionActions.FromMoveAction (CaretMoveActions.LineEnd), ClipboardActions.Cut); return; case 'C': RunActions (SelectionActions.FromMoveAction (CaretMoveActions.LineEnd), ClipboardActions.Cut); goto case 'i'; case '>': Status = ">"; CurState = State.Indent; return; case '<': Status = "<"; CurState = State.Unindent; return; case 'n': Search (); return; case 'N': searchBackward = !searchBackward; Search (); searchBackward = !searchBackward; return; case 'p': PasteAfter (false); return; case 'P': PasteBefore (false); return; case 's': if (!Data.IsSomethingSelected) RunAction (SelectionActions.FromMoveAction (CaretMoveActions.Right)); RunAction (ClipboardActions.Cut); goto case 'i'; case 'S': if (!Data.IsSomethingSelected) RunAction (SelectionActions.LineActionFromMoveAction (CaretMoveActions.LineEnd)); else Data.SetSelectLines (Data.MainSelection.Anchor.Line, Data.Caret.Line); RunAction (ClipboardActions.Cut); goto case 'i'; case 'g': Status = "g"; CurState = State.G; return; case 'G': RunAction (marks ['`'].SaveMark); if (repeatCount > 1) { Caret.Line = repeatCount; } else { //RunAction (CaretMoveActions.ToDocumentEnd); RunAction (ToDocumentEnd); } Reset (string.Empty); return; case 'H': Caret.Line = System.Math.Max (DocumentLocation.MinLine, Editor.PointToLocation (0, Editor.LineHeight - 1).Line); return; case 'J': RunAction (ViActions.Join); return; case 'L': int line = Editor.PointToLocation (0, Editor.Allocation.Height - Editor.LineHeight * 2 - 2).Line; if (line < DocumentLocation.MinLine) line = Document.LineCount; Caret.Line = line; return; case 'M': line = Editor.PointToLocation (0, Editor.Allocation.Height / 2).Line; if (line < DocumentLocation.MinLine) line = Document.LineCount; Caret.Line = line; return; case '~': RunAction (ViActions.ToggleCase); return; case 'z': Status = "z"; CurState = State.Fold; return; case 'm': Status = "m"; CurState = State.Mark; return; case '`': Status = "`"; CurState = State.GoToMark; return; case '@': Status = "@"; CurState = State.PlayMacro; return; case 'q': if (currentMacro == null) { Status = "q"; CurState = State.NameMacro; return; } currentMacro = null; Reset ("Macro Recorded"); return; case '*': SearchWordAtCaret (backward: false); return; case '#': SearchWordAtCaret (backward: true); return; case '.': RepeatLastAction (); return; } } // if (Data == null) // Console.WriteLine ("ViMode.HandleKeypress: after State.Normal block, Data is null"); action = GetNavCharAction ((char)unicodeKey, true); if (action == null) { action = ViActionMaps.GetDirectionKeyAction (key, modifier); } if (action == null) { action = ViActionMaps.GetCommandCharAction ((char)unicodeKey); } if (action != null) { RunRepeatableAction (action); } // if (Data == null) // Console.WriteLine ("ViMode.HandleKeypress: right before CheckVisualMode, Data is null"); //undo/redo may leave MD with a selection mode without activating visual mode CheckVisualMode (); return; case State.Delete: if (IsInnerOrOuterMotionKey (unicodeKey, ref motion)) return; int offsetz = Caret.Offset; if (motion != Motion.None) { action = ViActionMaps.GetEditObjectCharAction ((char)unicodeKey, motion); } else if (((modifier & (Gdk.ModifierType.ShiftMask | Gdk.ModifierType.ControlMask)) == 0 && (unicodeKey == 'd' || unicodeKey == 'j' || unicodeKey == 'k'))) { if (unicodeKey == 'k') { action = CaretMoveActions.Up; } else { action = CaretMoveActions.Down; } if (unicodeKey == 'j') { repeatCount += 1; } //get one extra line for yj lineAction = true; } else { action = GetNavCharAction ((char)unicodeKey, false); if (action == null) action = ViActionMaps.GetDirectionKeyAction (key, modifier); if (action != null) action = SelectionActions.FromMoveAction (action); } if (action != null) { if (lineAction) { RunAction (CaretMoveActions.LineStart); SelectionActions.StartSelection (Data); for (int i = 0; i < repeatCount; i++) { RunAction (action); } SelectionActions.EndSelection (Data); numericPrefix = ""; } else { RunRepeatableAction (action); } if (Data.IsSomethingSelected && !lineAction) offsetz = Data.SelectionRange.Offset; RunAction (ClipboardActions.Cut); Reset (string.Empty); } else { Reset ("Unrecognised motion"); } Caret.Offset = offsetz; return; case State.Yank: if (IsInnerOrOuterMotionKey (unicodeKey, ref motion)) return; int offset = Caret.Offset; if (motion != Motion.None) { action = ViActionMaps.GetEditObjectCharAction ((char)unicodeKey, motion); } else if (((modifier & (Gdk.ModifierType.ShiftMask | Gdk.ModifierType.ControlMask)) == 0 && (unicodeKey == 'y' || unicodeKey == 'j' || unicodeKey == 'k'))) { if (unicodeKey == 'k') { action = CaretMoveActions.Up; } else { action = CaretMoveActions.Down; } if (unicodeKey == 'j') { repeatCount += 1; } //get one extra line for yj lineAction = true; } else { action = GetNavCharAction ((char)unicodeKey, false); if (action == null) action = ViActionMaps.GetDirectionKeyAction (key, modifier); if (action != null) action = SelectionActions.FromMoveAction (action); } if (action != null) { if (lineAction) { RunAction (CaretMoveActions.LineStart); SelectionActions.StartSelection (Data); for (int i = 0; i < repeatCount; i++) { RunAction (action); } SelectionActions.EndSelection (Data); numericPrefix = ""; } else { RunRepeatableAction (action); } if (Data.IsSomethingSelected && !lineAction) offset = Data.SelectionRange.Offset; RunAction (ClipboardActions.Copy); Reset (string.Empty); } else { Reset ("Unrecognised motion"); } Caret.Offset = offset; return; case State.Change: if (IsInnerOrOuterMotionKey (unicodeKey, ref motion)) return; lastActionStarted = true; LastAction.Clear (); if (motion != Motion.None) { action = ViActionMaps.GetEditObjectCharAction ((char)unicodeKey, motion); } //copied from delete action else if (((modifier & (Gdk.ModifierType.ShiftMask | Gdk.ModifierType.ControlMask)) == 0 && unicodeKey == 'c')) { action = SelectionActions.LineActionFromMoveAction (CaretMoveActions.LineEnd); lineAction = true; } else { action = ViActionMaps.GetEditObjectCharAction ((char)unicodeKey); if (action == null) action = ViActionMaps.GetDirectionKeyAction (key, modifier); if (action != null) action = SelectionActions.FromMoveAction (action); } if (action != null) { List<Action<TextEditorData>> actions; if (lineAction) { //cd or cj -- delete lines moving downward actions = GenerateRepeatedActionList ( action, ClipboardActions.Cut, CaretMoveActions.LineFirstNonWhitespace); actions.Add (ViActions.NewLineAbove); } else if (unicodeKey == 'j') { //cj -- delete current line and line below repeatCount += 1; action = SelectionActions.LineActionFromMoveAction (CaretMoveActions.LineEnd); actions = GenerateRepeatedActionList ( action, ClipboardActions.Cut, CaretMoveActions.LineFirstNonWhitespace); actions.Add (ViActions.NewLineAbove); } else if (unicodeKey == 'k') { //ck -- delete current line and line above repeatCount += 1; actions = GenerateRepeatedActionList ( CaretMoveActions.LineFirstNonWhitespace, ClipboardActions.Cut, action); actions.Add (ViActions.NewLineBelow); } else { actions = GenerateRepeatedActionList (action); actions.Add (ClipboardActions.Cut); } RunActions (actions.ToArray ()); LastAction.AddRange (actions); Status = "-- INSERT --"; PrevState = State.Change; CurState = State.Insert; Caret.Mode = CaretMode.Insert; } else { Reset ("Unrecognised motion"); } return; case State.Insert: case State.Replace: action = ViActionMaps.GetInsertKeyAction (key, modifier); // Record InsertKeyActions if (action != null) { RunAction (action); InsertBuffer.Add (new Keystroke (key, unicodeKey, modifier)); return; } // Clear InsertBuffer if DirectionKeyAction action = ViActionMaps.GetDirectionKeyAction (key, modifier); if (action != null) { RunAction (action); InsertBuffer.Clear (); return; } if (unicodeKey != 0) { InsertCharacter (unicodeKey); InsertBuffer.Add (new Keystroke (key, unicodeKey, modifier)); } return; case State.VisualLine: if (key == Gdk.Key.Delete) unicodeKey = 'x'; switch ((char)unicodeKey) { case 'p': PasteAfter (true); return; case 'P': PasteBefore (true); return; } action = GetNavCharAction ((char)unicodeKey, false); if (action == null) { action = ViActionMaps.GetDirectionKeyAction (key, modifier); } if (action == null) { action = ViActionMaps.GetCommandCharAction ((char)unicodeKey); } if (action != null) { RunAction (SelectionActions.LineActionFromMoveAction (action)); return; } ApplyActionToSelection (modifier, unicodeKey); return; case State.Visual: if (IsInnerOrOuterMotionKey (unicodeKey, ref motion)) return; if (motion != Motion.None) { action = ViActionMaps.GetEditObjectCharAction((char) unicodeKey, motion); if (action != null) { RunAction (action); return; } } if (key == Gdk.Key.Delete) unicodeKey = 'x'; switch ((char)unicodeKey) { case 'p': PasteAfter (false); return; case 'P': PasteBefore (false); return; } action = GetNavCharAction ((char)unicodeKey, false); if (action == null) { action = ViActionMaps.GetDirectionKeyAction (key, modifier); } if (action == null) { action = ViActionMaps.GetCommandCharAction ((char)unicodeKey); } if (action != null) { RunAction (ViActions.VisualSelectionFromMoveAction (action)); return; } ApplyActionToSelection (modifier, unicodeKey); return; case State.Command: switch (key) { case Gdk.Key.Return: case Gdk.Key.KP_Enter: Status = RunExCommand (commandBuffer.ToString ()); commandBuffer.Length = 0; //CurState = State.Normal; break; case Gdk.Key.BackSpace: case Gdk.Key.Delete: case Gdk.Key.KP_Delete: if (0 < commandBuffer.Length) { commandBuffer.Remove (commandBuffer.Length-1, 1); Status = commandBuffer.ToString (); if (0 == commandBuffer.Length) Reset (Status); } break; default: if(unicodeKey != 0) { commandBuffer.Append ((char)unicodeKey); Status = commandBuffer.ToString (); } break; } return; case State.WriteChar: if (unicodeKey != 0) { RunAction (SelectionActions.StartSelection); int roffset = Data.SelectionRange.Offset; InsertCharacter ((char) unicodeKey); Reset (string.Empty); Caret.Offset = roffset; } else { Reset ("Keystroke was not a character"); } return; case State.Indent: if (((modifier & (Gdk.ModifierType.ControlMask)) == 0 && unicodeKey == '>')) { //select current line to indent Action<TextEditorData> indentAction = MakeIndentAction (repeatCount); StartNewLastAction (indentAction); RunAction (indentAction); return; } action = GetNavCharAction ((char)unicodeKey, false); if (action == null) action = ViActionMaps.GetDirectionKeyAction (key, modifier); if (action != null) { // TODO: Stuff this into a delegate and go var linesToIndent = repeatCount; Action<TextEditorData> indentAction = delegate(TextEditorData data) { List<Action<TextEditorData>> actions = new List<Action<TextEditorData>> (); //get away from LineBegin RunAction (CaretMoveActions.LineFirstNonWhitespace); int roffset = Data.SelectionRange.Offset; actions.Add (ViActions.Right); for (int i = 0; i < linesToIndent; i++) { actions.Add (SelectionActions.FromMoveAction (action)); } actions.Add (MiscActions.IndentSelection); RunActions (actions.ToArray ()); //set cursor to start of first line indented Caret.Offset = roffset; RunAction (CaretMoveActions.LineFirstNonWhitespace); Reset (""); }; StartNewLastAction (indentAction); RunAction (indentAction); } else { Reset ("Unrecognised motion"); } return; case State.Unindent: if (((modifier & (Gdk.ModifierType.ControlMask)) == 0 && ((char)unicodeKey) == '<')) { //select current line to indent // TODO: Stuff this into a delegate and go Action<TextEditorData> unindentAction = MakeUnindentAction (repeatCount); StartNewLastAction (unindentAction); RunAction (unindentAction); return; } action = GetNavCharAction ((char)unicodeKey, false); if (action == null) action = ViActionMaps.GetDirectionKeyAction (key, modifier); if (action != null) { // TODO: Stuff this into a delegate and go var linesToUnindent = repeatCount; Action<TextEditorData> unindentAction = delegate(TextEditorData data) { List<Action<TextEditorData>> actions = new List<Action<TextEditorData>> (); RunAction (CaretMoveActions.LineFirstNonWhitespace); int roffset = Data.SelectionRange.Offset; //get away from LineBegin actions.Add (ViActions.Right); for (int i = 0; i < linesToUnindent; i++) { actions.Add (SelectionActions.FromMoveAction (action)); } actions.Add (MiscActions.RemoveIndentSelection); RunActions (actions.ToArray ()); //set cursor to start of first line indented Caret.Offset = roffset; RunAction (CaretMoveActions.LineFirstNonWhitespace); Reset (""); }; StartNewLastAction (unindentAction); RunAction (unindentAction); } else { Reset ("Unrecognised motion"); } return; case State.G: if (((modifier & (Gdk.ModifierType.ControlMask)) == 0)) { switch ((char)unicodeKey) { case 'g': RunAction (marks ['`'].SaveMark); Caret.Offset = 0; Reset (""); return; } } Reset ("Unknown command"); return; case State.Mark: { char k = (char)unicodeKey; ViMark mark = null; if (!char.IsLetterOrDigit(k) && !SpecialMarks.Contains(k)) { Reset ("Invalid Mark"); return; } if (marks.ContainsKey(k)) { mark = marks [k]; } else { mark = new ViMark(k); marks [k] = mark; } RunAction(mark.SaveMark); Reset(""); return; } case State.NameMacro: { char k = (char) unicodeKey; if(!char.IsLetterOrDigit(k)) { Reset("Invalid Macro Name"); return; } currentMacro = new ViMacro (k); currentMacro.KeysPressed = new Queue<ViMacro.KeySet> (); macros [k] = currentMacro; Reset(""); return; } case State.PlayMacro: { char k = (char) unicodeKey; if (k == '@') k = macros_lastplayed; if (macros.ContainsKey(k)) { int playCount = repeatCount; //store repeat count in case macro changes it Reset (""); macros_lastplayed = k; // FIXME play nice when playing macros from inside macros? ViMacro macroToPlay = macros [k]; for (int i = 0 ; i < playCount ; i++) { foreach (ViMacro.KeySet keySet in macroToPlay.KeysPressed) { HandleKeypress(keySet.Key, keySet.UnicodeKey, keySet.Modifiers); // FIXME stop on errors? essential with multipliers and nowrapscan } } /* Once all the keys have been played back, quickly exit. */ return; } else { Reset ("Invalid Macro Name '" + k + "'"); return; } } case State.GoToMark: { char k = (char)unicodeKey; if (marks.ContainsKey (k)) { if (k != '`') { RunAction (marks ['`'].SaveMark); } RunAction (marks [k].LoadMark); Reset (""); } else { Reset ("Unknown Mark"); } return; } case State.Fold: { if (((modifier & (Gdk.ModifierType.ControlMask)) == 0)) { switch ((char)unicodeKey) { case 'A': // Recursive fold toggle action = FoldActions.ToggleFoldRecursive; break; case 'C': // Recursive fold close action = FoldActions.CloseFoldRecursive; break; case 'M': // Close all folds action = FoldActions.CloseAllFolds; break; case 'O': // Recursive fold open action = FoldActions.OpenFoldRecursive; break; case 'R': // Expand all folds action = FoldActions.OpenAllFolds; break; case 'a': // Fold toggle action = FoldActions.ToggleFold; break; case 'c': // Fold close action = FoldActions.CloseFold; break; case 'o': // Fold open action = FoldActions.OpenFold; break; default: Reset ("Unknown command"); break; } if (null != action) { RunAction (action); Reset (string.Empty); } } return; } case State.Confirm: if (((modifier & (Gdk.ModifierType.ControlMask)) == 0)) { switch ((char)unicodeKey) { case 'y': Reset ("Yes"); break; case 'n': Reset ("No"); break; } } return; } }
protected override void OnAddedToEditor(TextEditorData data) { base.OnAddedToEditor (data); ViMark special1 = new ViMark ('`', false); marks ['`'] = special1; special1.SaveMark (data); }