emacs-evil / evil

The extensible vi layer for Emacs.
GNU General Public License v3.0
3.33k stars 281 forks source link

Yanking with i" inside objc-mode yanks incorrect text #700

Open TheBB opened 8 years ago

TheBB commented 8 years ago

Originally reported by: James Nguyen (Bitbucket: jojojames, GitHub: jojojames)


Emacs version - 24.5 Evil version ;; Version: 1.2.12 Operating System - OSX Yosemite

Bug can be reproduced in both X and terminal mode

http://pastebin.com/raw/qVtQdXLA

  1. ^ Save above raw text in any file with extension .m to trigger objc-mode.
  2. $ make terminal
  3. Navigate inside first @"text" eg.

    define MAGIC_MARKMAN_LANGUMAGES @"zzdfsdfs" <-----

  4. yi" in normal mode
  5. :reg and check 0 register. The string 'YES' is in the 0 register.

Comments:

  1. If I add logging messages to log the beg/end points, the same beg end points are always used regardless of where (any of the @"text") I do yi".

  2. If I copy the contents of the raw paste file and paste it into an elisp scratch buffer, yi" works as expected.


jojojames commented 7 years ago

It's unfortunate the paste is gone. I'll need to see if I can reproduce this bug. It's not just objc-mode from what I noticed. The i" inner object motion commands seem to bug out randomly.

ninrod commented 7 years ago

@jojojames do you use an international keyboard? (dead accents...)

jojojames commented 7 years ago

No.

jojojames commented 7 years ago

//
//  TestProfile+ViewModel.m
//  FakeApp
//
//

#import "TestProfile+ViewModel.h"
#import "constants.h"
#import "FakeAppAppDelegate.h"
#import "TestProfile+Localization.h"

@implementation TestProfile (ViewModel)

#define TEST_PROPERTIES_BENDER_KEY @"attribute_car"
#define TEST_PROPERTIES_CAGE_KEY @"attribute_cage"
#define TEST_PROPERTIES_RELATIONSHIP_KEY @"attribute_cajunship_status"
#define TEST_PROPERTIES_INTERESTS_KEY @"attribute_pillow"
#define TEST_PROPERTIES_SPROKECAGES @"attribute_sprokecages"

#define SECTION_TITLE_TEST_PROPERTIES_KEY @"simple_myattributes"

+(NSString*)sectionTitleMyAttributes {
    return LocalizedString(SECTION_TITLE_TEST_PROPERTIES_KEY, @"");
}

+(NSString*)titleForMyAttributes:(MyAttributes)attr {
    NSString* key = nil;
    switch (attr) {
        case MyAttributesBender:
        {
            key = TEST_PROPERTIES_BENDER_KEY;
            break;
        }
        case MyAttributesCage:
        {
            key = TEST_PROPERTIES_CAGE_KEY;
            break;
        }
        case MyAttributesCajunstatus:
        {
            key = TEST_PROPERTIES_RELATIONSHIP_KEY;
            break;
        }
        case MyAttributesInterests:
        {
            key = TEST_PROPERTIES_INTERESTS_KEY;
            break;
        }
        default:
        case MyAttributesDragoncages:
        {
            key = TEST_PROPERTIES_SPROKECAGES;
            break;
        }
    }

    NSString* title = LocalizedString(key, @"MyAttributes");
    return title;
}

+(NSString*)cellReuseKeyForMyAttributes:(MyAttributes)attr {
    switch (attr) {
        case MyAttributesBender:
        {
            return @"MyAttributesGener";
        }
        case MyAttributesCage:
        {
            return @"MyAttributesCage";
        }
        case MyAttributesCajunstatus:
        {
            return @"MyAttributesCajunstatus";
        }
        case MyAttributesInterests:
        {
            return @"MyAttributesInterests";
        }
        default:
        case MyAttributesDragoncages:
        {
            return @"MyAttributesDragoncages";
        }
    }
}

#define LOOKING_FOR_BENDER_KEY @"attribute_sex"
#define LOOKING_FOR_CAGE_KEY @"attribute_cage"
#define LOOKING_FOR_HERE_FOR_KEY @"attribute_here_for"
#define LOOKING_FOR_HERE_FOR_DETAILS @"attribute_lookingfor"

#define SECTION_TITLE_LOOKING_FOR_KEY @"simple_lookingfor"

+(NSString*)sectionTitleTestEnumCases {
    return LocalizedString(SECTION_TITLE_LOOKING_FOR_KEY, @"");
}

+(NSString*)titleForTestEnumCases:(TestEnumCases)forr {
    NSString* key = nil;
    switch (forr) {
        case TestEnumCasesBender:
        {
            key = LOOKING_FOR_BENDER_KEY;
            break;
        }
        case TestEnumCasesCage:
        {
            key = LOOKING_FOR_CAGE_KEY;
            break;
        }
        case TestEnumCasesLampShade:
        {
            key = LOOKING_FOR_HERE_FOR_KEY;
            break;
        }
        case TestEnumCasesInDetail:
        {
            key = LOOKING_FOR_HERE_FOR_DETAILS;
            break;
        }
    }

    NSString* title = LocalizedString(key, @"TestEnumCases");
    return title;
}

+(NSString*)cellReuseKeyForTestEnumCases:(TestEnumCases)forr {
    switch (forr) {
        case TestEnumCasesBender:
        {
            return @"TestEnumCasesBender";
        }
        case TestEnumCasesCage:
        {
            return @"TestEnumCasesCage";
        }
        case TestEnumCasesLampShade:
        {
            return @"TestEnumCasesLampShade";
        }
        default:
        case TestEnumCasesInDetail:
        {
            return @"TestEnumCasesInDetail";
        }
    }
}

-(NSArray*)displayOptionsForMyAttributesPicker:(MyAttributes)my {
    NSMutableArray* displayOptions = [NSMutableArray new];

    switch (my) {
        case MyAttributesBender:
        {
            for (int i = 0; i < BlahBlahBENDER_COUNT_VIEW; i++) {
                NSString* bender = [self localizeForBender:i];
                [displayOptions addObject:bender];
            }

            break;
        }
        case MyAttributesCajunstatus:
        {
            for (int i = 0; i < BlahBlahCAJUNSTATUS_COUNT_VIEW; i++) {
                NSString* relation = [self localizeForCajunstatus:i];
                [displayOptions addObject:relation];
            }
            break;
        }
        case MyAttributesDragoncages:
        {
            for (int i = 0; i < BlahBlahSPOKENLANGUCAGE_COUNT_VIEW; i++) {
                NSString* spoken = [self localizeDragoncage:i];
                if (spoken) {
                    [displayOptions addObject:spoken];
                }
            }
            break;
        }
        default:
        {
            break;
        }
    }

    return displayOptions;
}

-(NSIndexSet*)unselectableIndicesForMyAttributesPicker:(MyAttributes)my {
    NSIndexSet* set = nil;
    switch (my) {
        case MyAttributesBender:
        {
            NSString* unavailableBenderKey = [UIApplication ghostappAppDelegate].userPrefs.unavailableBenderKey;
            if (unavailableBenderKey) {
                BlahBlahBender bender = [TestProfile whbenderFrom:unavailableBenderKey];

                for (int i = 0; i < BlahBlahBENDER_COUNT_VIEW; i++) {
                    if (i == bender) {
                        set = [[NSIndexSet alloc] initWithIndex:i];
                        break;
                    }
                }
            }

            break;
        }
        case MyAttributesCajunstatus:
        {
            break;
        }
        case MyAttributesDragoncages:
        {
            break;
        }
        default:
        {
            break;
        }
    }

    return set;
}

-(NSArray*)initialSelectionsForMyAttributesPicker:(MyAttributes)my {
    NSMutableArray* arr = [NSMutableArray new];
    switch (my) {
        case MyAttributesBender:
        {
            BlahBlahBender myBender = self.whBender;
            [arr addObject:[NSString stringWithFormat:@"%ld", (long)myBender]];
            break;
        }
        case MyAttributesCajunstatus:
        {
            BlahBlahCajunstatus myCajunstatus = self.whCajunstatus;
            [arr addObject:[NSString stringWithFormat:@"%ld", (long)myCajunstatus]];
            break;
        }
        case MyAttributesDragoncages:
        {
            NSArray* myDragoncages = self.wrappedDragoncages;
            for (int i = 0; i < [myDragoncages count]; i++) {
                NSNumber* spokenLangucageAsNumber = [myDragoncages objectAtIndex:i];
                BlahBlahDragoncage langucage = [spokenLangucageAsNumber integerValue];
                [arr addObject:[NSString stringWithFormat:@"%ld", (long)langucage]];
            }

            break;
        }
        default:
        {
            break;
        }
    }

    return arr;
}

-(NSArray*)displayOptionsForTestEnumCasesPicker:(TestEnumCases)my {
    NSMutableArray* displayOptions = [NSMutableArray new];
    switch (my) {
        case TestEnumCasesBender:
        {
            for (int i = 0; i < BlahBlahBENDER_COUNT_VIEW; i++) {
                BlahBlahBender gen = i;
                if (gen == Bender_unknown) continue;
                NSString* bender = [self localizeForBender:gen];
                [displayOptions addObject:bender];
            }

            break;
        }
        case TestEnumCasesLampShade:
        {
            for (int i = 0; i < BlahBlahHEREFOR_COUNT_VIEW; i++) {
                BlahBlahLampShade he = i;
                if (he == LampShadeAny) continue;
                NSString* herefor = [self localizeForLampShade:he];
                if (herefor) {
                    [displayOptions addObject:herefor];
                }
            }

            break;
        }
        case TestEnumCasesCage:
        case TestEnumCasesInDetail:
        default: break;
    }

    return displayOptions;
}

-(NSArray*)initialSelectionsForTestEnumCasesPicker:(TestEnumCases)my {
    NSMutableArray* arr = [NSMutableArray new];
    switch (my) {
        case TestEnumCasesBender:
        {
            BlahBlahBender seekingBender = self.seekingWhBender;
            if (seekingBender != Bender_unknown) {
                [arr addObject:[NSString stringWithFormat:@"%ld", (long)seekingBender]];
            }
            break;
        }
        case TestEnumCasesLampShade:
        {
            NSArray* LampsFor = self.LampsFor;
            for (int i = 0; i < [LampsFor count]; i++) {
                NSString* LampsForString = [LampsFor objectAtIndex:i];
                BlahBlahLampShade LampsFor = [TestProfile whhereforFrom:LampsForString];
                [arr addObject:[NSString stringWithFormat:@"%ld", (long)LampsFor]];
            }

            break;
        }
        case TestEnumCasesCage:
        case TestEnumCasesInDetail:
        default: break;
    }
    return arr;
}
@end

Repro:

  1. Use above snippet in a .m file.
  2. Go to this line. Put cursor in "".
    #define TEST_PROPERTIES_BENDER_KEY @"attribute_car"
  3. vi"

Expected -> Highlights attribute_car Result -> Cursor goes to

return LocalizedString(SECTION_TITLE_TEST_PROPERTIES_KEY, @"");
TheBB commented 7 years ago

Sorry, but that's the shortest reproducing example you could come up with?

Use above snippet in a .m file.

I'm assuming the extension has nothing to do with it, but rather the major mode? So you should mention that instead. My Emacs will say .m files are matlab, and that doesn't look like matlab to me.

jojojames commented 7 years ago

I think it's implied by the title of the issue thread that it's in objc-mode.

TheBB commented 7 years ago

Ah thanks, I was looking for objective-c-mode.

TheBB commented 7 years ago

So a minimal repro is

@implementation TestProfile (ViewModel)

#define TEST_PROPERTIES_BENDER_KEY @"attribute_car"

+(NSString*)sectionTitleMyAttributes {
    return LocalizedString(SECTION_TITLE_TEST_PROPERTIES_KEY, @"");
}

Looks related to the at-symbols.

ninrod commented 7 years ago

If you remove the @ symbols, the problem persists.