From 9f528fc3afa8012c6274b98db6001838c48354a6 Mon Sep 17 00:00:00 2001 From: Jason Fields Date: Sat, 6 Jun 2015 14:37:57 -0400 Subject: [PATCH 1/4] allow whitespace characters to work with replace mode --- XVim/XVimKeyStroke.h | 1 + XVim/XVimKeyStroke.m | 12 ++++++++++++ XVim/XVimReplaceEvaluator.m | 4 ++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/XVim/XVimKeyStroke.h b/XVim/XVimKeyStroke.h index bc5e1ed4..bef5a6e6 100644 --- a/XVim/XVimKeyStroke.h +++ b/XVim/XVimKeyStroke.h @@ -29,6 +29,7 @@ NSString* XVimKeyNotationFromXVimString(XVimString* string); @property unsigned char modifier; @property (nonatomic, readonly) BOOL isNumeric; @property (nonatomic, readonly) BOOL isPrintable; +@property (nonatomic, readonly) BOOL isWhitespace; - (id)initWithCharacter:(unichar)c modifier:(unsigned char)mod; diff --git a/XVim/XVimKeyStroke.m b/XVim/XVimKeyStroke.m index f69425f2..106ea6e0 100644 --- a/XVim/XVimKeyStroke.m +++ b/XVim/XVimKeyStroke.m @@ -323,6 +323,13 @@ NS_INLINE BOOL isPrintable(unichar c) return !isNSFunctionKey(c) && iswprint_l(c, s_locale); } +NS_INLINE BOOL isWhitespace(unichar c) +{ + init_maps(); + + return !isNSFunctionKey(c) && iswspace_l(c, s_locale); +} + NS_INLINE BOOL isValidKey(NSString *key) { init_maps(); @@ -620,6 +627,11 @@ - (BOOL)isPrintable return !_modifier && isPrintable(_character); } +- (BOOL)isWhitespace +{ + return !_modifier && isWhitespace(_character); +} + - (NSString*)keyNotation{ NSMutableString *keyStr = [[NSMutableString alloc] init]; unichar charcode = _character; diff --git a/XVim/XVimReplaceEvaluator.m b/XVim/XVimReplaceEvaluator.m index a5564a12..269ca338 100644 --- a/XVim/XVimReplaceEvaluator.m +++ b/XVim/XVimReplaceEvaluator.m @@ -90,8 +90,8 @@ - (XVimEvaluator*)eval:(XVimKeyStroke*)keyStroke{ // Here we pass the key input to original text view. // The input coming to this method is already handled by "Input Method" // and the input maight be non ascii like 'あ' - if (self.oneCharMode || keyStroke.isPrintable) { - if (!keyStroke.isPrintable) { + if (self.oneCharMode || keyStroke.isPrintable || keyStroke.isWhitespace) { + if (!keyStroke.isPrintable && !keyStroke.isWhitespace) { nextEvaluator = [XVimEvaluator invalidEvaluator]; } else if (![self.sourceView xvim_replaceCharacters:keyStroke.character count:1]) { nextEvaluator = [XVimEvaluator invalidEvaluator]; From 57810832ce53f5047c5019a380cb9d8cae135883 Mon Sep 17 00:00:00 2001 From: Jason May Date: Tue, 31 May 2016 23:56:15 -0700 Subject: [PATCH 2/4] Fix some issues with carriage returns --- XVim/NSTextView+VimOperation.m | 7 ++++++- XVim/Test/XVimTester+Issues.m | 15 ++++++++++++++- XVim/XVimReplaceEvaluator.m | 32 ++++++++++++++++++++++++-------- 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/XVim/NSTextView+VimOperation.m b/XVim/NSTextView+VimOperation.m index a5f1f671..0a5a211c 100644 --- a/XVim/NSTextView+VimOperation.m +++ b/XVim/NSTextView+VimOperation.m @@ -822,7 +822,12 @@ - (BOOL)xvim_delete:(XVimMotion*)motion withMotionPoint:(NSUInteger)motionPoint newPos = [self.textStorage xvim_indexOfLineNumber:sel.top column:sel.left]; } - [self.xvimDelegate textView:self didDelete:self.lastYankedText withType:self.lastYankedType]; + // in case yank:NO is passed in and no yanking has been done yet + // usually we don't want to report unyanked deletes anyway, as they are usually + // internal plumbing + if (self.lastYankedText != NULL) { + [self.xvimDelegate textView:self didDelete:self.lastYankedText withType:self.lastYankedType]; + } [self xvim_changeSelectionMode:XVIM_VISUAL_NONE]; if (newPos != NSNotFound) { [self xvim_moveCursor:newPos preserveColumn:NO]; diff --git a/XVim/Test/XVimTester+Issues.m b/XVim/Test/XVimTester+Issues.m index d5c7130c..21c4e103 100644 --- a/XVim/Test/XVimTester+Issues.m +++ b/XVim/Test/XVimTester+Issues.m @@ -49,7 +49,13 @@ - (NSArray*)issues_testcases{ static NSString* issue_606_result_spaces = @" aaa bbb ccc\n"; static NSString* issue_606_result_tabs = @" aaa bbb ccc\n"; - + static NSString* issue_770_text = @"aaaa(.)a\n"; + static NSString* issue_770_newline_result = @"a\naa(.)a\n"; + static NSString* issue_770_newline_indent_result = @"aaaa(\n )a\n"; + static NSString* issue_770_replace_multichar_result = @"bbbb(.)a\n"; + static NSString* issue_770_eol_text = @"1234\n1234\n"; + static NSString* issue_770_eol_result = @"123\n\n1234\n"; + static NSString* issue_776_text = @""; static NSString* issue_776_result = @"\n"; static NSString* issue_805_text = @"aaaa bbbb cccc dddd eeee ffff gggg\n" @@ -83,6 +89,13 @@ - (NSArray*)issues_testcases{ ? XVimMakeTestCase( text0, 0, 0, @"i.", issue_606_result_tabs, 1, 0 ) // Issue #606. Repeating tab insertion crashes Xcode. : XVimMakeTestCase( text0, 0, 0, @"i.", issue_606_result_spaces, 7, 0 ), // Issue #606. Repeating tab insertion crashes Xcode. + XVimMakeTestCase(issue_770_text, 0, 0, @"ru", issue_770_text, 0, 0), // Issue #770 + XVimMakeTestCase(issue_770_text, 0, 0, @"r u", issue_770_text, 0, 0), // Issue #770 + XVimMakeTestCase(issue_770_text, 1, 0, @"r", issue_770_newline_result, 2, 0), // Issue #770 + XVimMakeTestCase(issue_770_text, 5, 0, @"r", issue_770_newline_indent_result, 10, 0), // Issue #770 + XVimMakeTestCase(issue_770_text, 0, 0, @"Rbbbb", issue_770_replace_multichar_result, 4, 0), // Issue #770 + XVimMakeTestCase(issue_770_eol_text, 3, 0, @"rkj", issue_770_eol_result, 4, 0), // Issue #770 + XVimMakeTestCase(issue_776_text, 0, 0, @"O", issue_776_result, 0, 0), // Issue #776 crash XVimMakeTestCase(issue_805_text, 33, 0, @"dd", issue_805_result, 0, 0), // Issue #805 XVimMakeTestCase(issue_809_a_text, 5, 0, @"dw", issue_809_a_result, 4, 0), diff --git a/XVim/XVimReplaceEvaluator.m b/XVim/XVimReplaceEvaluator.m index 269ca338..5da56d5a 100644 --- a/XVim/XVimReplaceEvaluator.m +++ b/XVim/XVimReplaceEvaluator.m @@ -90,18 +90,34 @@ - (XVimEvaluator*)eval:(XVimKeyStroke*)keyStroke{ // Here we pass the key input to original text view. // The input coming to this method is already handled by "Input Method" // and the input maight be non ascii like 'あ' - if (self.oneCharMode || keyStroke.isPrintable || keyStroke.isWhitespace) { - if (!keyStroke.isPrintable && !keyStroke.isWhitespace) { - nextEvaluator = [XVimEvaluator invalidEvaluator]; - } else if (![self.sourceView xvim_replaceCharacters:keyStroke.character count:1]) { - nextEvaluator = [XVimEvaluator invalidEvaluator]; - } else if (self.oneCharMode) { - nextEvaluator = nil; + BOOL relayEvent = NO; + BOOL newlinePressed = NO; + unichar replaceWith = keyStroke.character; + + // injecting a CR right into the sourceView causes issues + if (replaceWith == '\r') { + replaceWith = '\n'; + newlinePressed = YES; + } + + if (!keyStroke.isPrintable && !keyStroke.isWhitespace) { + nextEvaluator = [XVimEvaluator invalidEvaluator]; + } else if (!newlinePressed && ![self.sourceView xvim_replaceCharacters:replaceWith count:1]) { + nextEvaluator = [XVimEvaluator invalidEvaluator]; + } else if (self.oneCharMode) { + if (newlinePressed) { + relayEvent = YES; } - } else { + nextEvaluator = nil; + } + if (relayEvent) { NSEvent *event = [keyStroke toEventwithWindowNumber:0 context:nil]; [self.sourceView interpretKeyEvents:[NSArray arrayWithObject:event]]; } + if (newlinePressed) { + XVimMotion* m = XVIM_MAKE_MOTION(MOTION_FORWARD, CHARACTERWISE_EXCLUSIVE, MOTION_OPTION_NONE, 1); + [self.sourceView xvim_delete:m andYank:NO]; + } } } return nextEvaluator; From 50af44014447aa50a4c2de4a99c2bd6851faceb4 Mon Sep 17 00:00:00 2001 From: Jason May Date: Wed, 1 Jun 2016 09:34:44 -0700 Subject: [PATCH 3/4] due to auto-inserting, we should delete, then replace --- XVim/XVimReplaceEvaluator.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/XVim/XVimReplaceEvaluator.m b/XVim/XVimReplaceEvaluator.m index 5da56d5a..67a2ffec 100644 --- a/XVim/XVimReplaceEvaluator.m +++ b/XVim/XVimReplaceEvaluator.m @@ -110,14 +110,14 @@ - (XVimEvaluator*)eval:(XVimKeyStroke*)keyStroke{ } nextEvaluator = nil; } - if (relayEvent) { - NSEvent *event = [keyStroke toEventwithWindowNumber:0 context:nil]; - [self.sourceView interpretKeyEvents:[NSArray arrayWithObject:event]]; - } if (newlinePressed) { XVimMotion* m = XVIM_MAKE_MOTION(MOTION_FORWARD, CHARACTERWISE_EXCLUSIVE, MOTION_OPTION_NONE, 1); [self.sourceView xvim_delete:m andYank:NO]; } + if (relayEvent) { + NSEvent *event = [keyStroke toEventwithWindowNumber:0 context:nil]; + [self.sourceView interpretKeyEvents:[NSArray arrayWithObject:event]]; + } } } return nextEvaluator; From 24c3a3527c47c14f695bf25bba39fb5f1324dfc8 Mon Sep 17 00:00:00 2001 From: Jason May Date: Wed, 1 Jun 2016 09:46:21 -0700 Subject: [PATCH 4/4] can't really rely on unit testing indent here --- XVim/Test/XVimTester+Issues.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/XVim/Test/XVimTester+Issues.m b/XVim/Test/XVimTester+Issues.m index 21c4e103..0b2c7b31 100644 --- a/XVim/Test/XVimTester+Issues.m +++ b/XVim/Test/XVimTester+Issues.m @@ -51,7 +51,6 @@ - (NSArray*)issues_testcases{ static NSString* issue_770_text = @"aaaa(.)a\n"; static NSString* issue_770_newline_result = @"a\naa(.)a\n"; - static NSString* issue_770_newline_indent_result = @"aaaa(\n )a\n"; static NSString* issue_770_replace_multichar_result = @"bbbb(.)a\n"; static NSString* issue_770_eol_text = @"1234\n1234\n"; static NSString* issue_770_eol_result = @"123\n\n1234\n"; @@ -92,7 +91,6 @@ - (NSArray*)issues_testcases{ XVimMakeTestCase(issue_770_text, 0, 0, @"ru", issue_770_text, 0, 0), // Issue #770 XVimMakeTestCase(issue_770_text, 0, 0, @"r u", issue_770_text, 0, 0), // Issue #770 XVimMakeTestCase(issue_770_text, 1, 0, @"r", issue_770_newline_result, 2, 0), // Issue #770 - XVimMakeTestCase(issue_770_text, 5, 0, @"r", issue_770_newline_indent_result, 10, 0), // Issue #770 XVimMakeTestCase(issue_770_text, 0, 0, @"Rbbbb", issue_770_replace_multichar_result, 4, 0), // Issue #770 XVimMakeTestCase(issue_770_eol_text, 3, 0, @"rkj", issue_770_eol_result, 4, 0), // Issue #770