diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index f926c66c06..fbefe36144 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -4493,6 +4493,18 @@ A jump table for the options with a short description can be found at |Q_op|. 'termencoding'. Note: MacVim does not use this option. + *'macmeta'* *'mmta'* *'nomacmeta'* *'nommta'* +'macmeta' boolean (default off) + local to buffer + {only available in MacVim GUI} + Use option (alt) as meta key. When on, option-key presses are not + interpreted, thus enabling bindings to . When off, option-key + presses are interpreted by the selected input method and inserted as + text. + Note: Some keys (e.g. , , , ) can be + bound with the Meta flag even when this option is disabled, but this + is not the case for the majority of keys (e.g. , ). + *'magic'* *'nomagic'* 'magic' boolean (default on) global diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt index ae52825828..cc1af87532 100644 --- a/runtime/doc/quickref.txt +++ b/runtime/doc/quickref.txt @@ -767,6 +767,7 @@ Short explanation of each option: *option-list* 'listchars' 'lcs' characters for displaying in list mode 'loadplugins' 'lpl' load plugin scripts when starting up 'macatsui' Mac GUI: use ATSUI text drawing +'macmeta' 'mmta' use option as meta key (MacVim GUI only) 'magic' changes special characters in search patterns 'makeef' 'mef' name of the errorfile for ":make" 'makeprg' 'mp' program to use for the ":make" command diff --git a/runtime/optwin.vim b/runtime/optwin.vim index 3738b762bd..f81cd9fe7d 100644 --- a/runtime/optwin.vim +++ b/runtime/optwin.vim @@ -623,6 +623,9 @@ if has("gui") call BinOptionG("fullscreen", &fullscreen) call append("$", "fuoptions\tcontrol how fullscreen mode should behave") call OptionG("fuoptions", &fuoptions) + call append("$", "macmeta\tuse option as meta key") + call append("$", "\t(local to buffer)") + call BinOptionL("mmta") endif endif diff --git a/src/MacVim/MMBackend.m b/src/MacVim/MMBackend.m index b2ab343e00..63e79f472f 100644 --- a/src/MacVim/MMBackend.m +++ b/src/MacVim/MMBackend.m @@ -1521,10 +1521,13 @@ static NSString *MMSymlinkWarningString = // We take this approach of "pushing" the state to MacVim to avoid having // to make synchronous calls from MacVim to Vim in order to get state. + BOOL mmta = curbuf ? curbuf->b_p_mmta : NO; + NSDictionary *vimState = [NSDictionary dictionaryWithObjectsAndKeys: [[NSFileManager defaultManager] currentDirectoryPath], @"pwd", [NSNumber numberWithInt:p_mh], @"p_mh", [NSNumber numberWithBool:[self unusedEditor]], @"unusedEditor", + [NSNumber numberWithBool:mmta], @"p_mmta", nil]; // Put the state before all other messages. @@ -1796,6 +1799,7 @@ static NSString *MMSymlinkWarningString = - (void)handleKeyDown:(NSString *)key modifiers:(int)mods { + // TODO: This code is a horrible mess -- clean up! char_u special[3]; char_u modChars[3]; char_u *chars = (char_u*)[key UTF8String]; @@ -1858,9 +1862,52 @@ static NSString *MMSymlinkWarningString = } mods &= ~MOD_MASK_ALT; } + } else if (1 == length && chars[0] < 0x80 && (mods & MOD_MASK_ALT)) { + // META key is treated separately. This code was taken from gui_w48.c + // and gui_gtk_x11.c. + char_u string[7]; + int ch = simplify_key(chars[0], &mods); + + // Remove the SHIFT modifier for keys where it's already included, + // e.g., '(' and '*' + if (ch < 0x100 && !isalpha(ch) && isprint(ch)) + mods &= ~MOD_MASK_SHIFT; + + // Interpret the ALT key as making the key META, include SHIFT, etc. + ch = extract_modifiers(ch, &mods); + if (ch == CSI) + ch = K_CSI; + + int len = 0; + if (mods) { + string[len++] = CSI; + string[len++] = KS_MODIFIER; + string[len++] = mods; + } + + if (IS_SPECIAL(ch)) { + string[len++] = CSI; + string[len++] = K_SECOND(ch); + string[len++] = K_THIRD(ch); + } else { + string[len++] = ch; +#ifdef FEAT_MBYTE + // TODO: What if 'enc' is not "utf-8"? + if (enc_utf8 && (ch & 0x80)) { // convert to utf-8 + string[len++] = ch & 0xbf; + string[len-2] = ((unsigned)ch >> 6) + 0xc0; + if (string[len-1] == CSI) { + string[len++] = KS_EXTRA; + string[len++] = (int)KE_CSI; + } + } +#endif + } + + add_to_input_buf(string, len); + return; } else if (length > 0) { unichar c = [key characterAtIndex:0]; - //NSLog(@"non-special: %@ (hex=%x, mods=%d)", key, // [key characterAtIndex:0], mods); @@ -1875,14 +1922,6 @@ static NSString *MMSymlinkWarningString = //NSLog(@"clear shift ctrl"); } - // HACK! All Option+key presses go via 'insert text' messages, except - // for . If the Alt flag is not cleared for it does - // not work to map to it. - if (0xa0 == c && !(mods & MOD_MASK_CMD)) { - //NSLog(@"clear alt"); - mods &= ~MOD_MASK_ALT; - } - #ifdef FEAT_MBYTE if (input_conv.vc_type != CONV_NONE) { conv_str = string_convert(&input_conv, chars, &length); diff --git a/src/MacVim/MMTextViewHelper.m b/src/MacVim/MMTextViewHelper.m index 6142b11082..6b75e225fb 100644 --- a/src/MacVim/MMTextViewHelper.m +++ b/src/MacVim/MMTextViewHelper.m @@ -111,6 +111,17 @@ static float MMDragAreaSize = 73.0f; } else { [self dispatchKeyEvent:event]; } + } else if ((flags & NSAlternateKeyMask) && + [[[[self vimController] vimState] objectForKey:@"p_mmta"] + boolValue]) { + // If the 'macmeta' option is set, then send Alt+key presses directly + // to Vim without interpreting the key press. + NSString *unmod = [event charactersIgnoringModifiers]; + int len = [unmod lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + const char *bytes = [unmod UTF8String]; + + [self sendKeyDown:bytes length:len modifiers:flags + isARepeat:[event isARepeat]]; } else { [textView interpretKeyEvents:[NSArray arrayWithObject:event]]; } diff --git a/src/option.c b/src/option.c index 5d3b86e553..7ddd8022fd 100644 --- a/src/option.c +++ b/src/option.c @@ -138,6 +138,9 @@ #define PV_ML OPT_BUF(BV_ML) #define PV_MOD OPT_BUF(BV_MOD) #define PV_MPS OPT_BUF(BV_MPS) +#ifdef FEAT_GUI_MACVIM +#define PV_MMTA OPT_BUF(BV_MMTA) +#endif #define PV_NF OPT_BUF(BV_NF) #ifdef FEAT_OSFILETYPE # define PV_OFT OPT_BUF(BV_OFT) @@ -322,6 +325,9 @@ static int p_lisp; #endif static int p_ml; static int p_ma; +#ifdef FEAT_GUI_MACVIM +static int p_mmta; +#endif static int p_mod; static char_u *p_mps; static char_u *p_nf; @@ -1658,6 +1664,13 @@ static struct vimoption (char_u *)&p_macatsui, PV_NONE, {(char_u *)TRUE, (char_u *)0L}}, #endif + {"macmeta", "mmta", P_BOOL|P_VI_DEF, +#ifdef FEAT_GUI_MACVIM + (char_u *)&p_mmta, PV_MMTA, +#else + (char_u *)NULL, PV_NONE, +#endif + {(char_u *)FALSE, (char_u *)0L}}, {"magic", NULL, P_BOOL|P_VI_DEF, (char_u *)&p_magic, PV_NONE, {(char_u *)TRUE, (char_u *)0L}}, @@ -9235,6 +9248,9 @@ get_varp(p) #endif case PV_ML: return (char_u *)&(curbuf->b_p_ml); case PV_MPS: return (char_u *)&(curbuf->b_p_mps); +#ifdef FEAT_GUI_MACVIM + case PV_MMTA: return (char_u *)&(curbuf->b_p_mmta); +#endif case PV_MA: return (char_u *)&(curbuf->b_p_ma); case PV_MOD: return (char_u *)&(curbuf->b_changed); case PV_NF: return (char_u *)&(curbuf->b_p_nf); @@ -9606,6 +9622,9 @@ buf_copy_options(buf, flags) #ifdef FEAT_KEYMAP buf->b_p_keymap = vim_strsave(p_keymap); buf->b_kmap_state |= KEYMAP_INIT; +#endif +#ifdef FEAT_GUI_MACVIM + buf->b_p_mmta = p_mmta; #endif /* This isn't really an option, but copying the langmap and IME * state from the current buffer is better than resetting it. */ diff --git a/src/option.h b/src/option.h index 2077fa5a58..c1cbf5f4ec 100644 --- a/src/option.h +++ b/src/option.h @@ -981,6 +981,9 @@ enum , BV_ML , BV_MOD , BV_MPS +#ifdef FEAT_GUI_MACVIM + , BV_MMTA +#endif , BV_NF #ifdef FEAT_OSFILETYPE , BV_OFT diff --git a/src/structs.h b/src/structs.h index eb75dcd81a..673540e54c 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1456,6 +1456,9 @@ struct file_buffer char_u *b_p_dict; /* 'dictionary' local value */ char_u *b_p_tsr; /* 'thesaurus' local value */ #endif +#ifdef FEAT_GUI_MACVIM + int b_p_mmta; /* 'macmeta' local value */ +#endif /* end of buffer options */