diff options
author | Bram Moolenaar <Bram@vim.org> | 2005-02-22 08:49:11 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2005-02-22 08:49:11 +0000 |
commit | 26a60b45245080771bc2452b2634cb1f5acd60ed (patch) | |
tree | 82a54fd6544b2c2a57b5c52cb4d64c42dcd640a3 /src | |
parent | df177f679e950a2ab2ad5fe7d45c1daface004d7 (diff) | |
download | vim-26a60b45245080771bc2452b2634cb1f5acd60ed.zip |
updated for version 7.0051
Diffstat (limited to 'src')
-rw-r--r-- | src/ex_getln.c | 359 | ||||
-rw-r--r-- | src/gui_mac.c | 721 | ||||
-rw-r--r-- | src/ops.c | 22 | ||||
-rw-r--r-- | src/option.c | 61 | ||||
-rw-r--r-- | src/option.h | 7 | ||||
-rw-r--r-- | src/os_mac_conv.c | 323 | ||||
-rw-r--r-- | src/po/Make_mvc.mak | 4 | ||||
-rw-r--r-- | src/proto/eval.pro | 3 | ||||
-rw-r--r-- | src/screen.c | 12 | ||||
-rw-r--r-- | src/search.c | 2 | ||||
-rw-r--r-- | src/structs.h | 4 | ||||
-rw-r--r-- | src/syntax.c | 17 | ||||
-rw-r--r-- | src/term.c | 8 | ||||
-rw-r--r-- | src/undo.c | 184 | ||||
-rw-r--r-- | src/version.h | 4 |
15 files changed, 1398 insertions, 333 deletions
diff --git a/src/ex_getln.c b/src/ex_getln.c index 05c85b49f..4c9d17d78 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -681,16 +681,29 @@ getcmdline(firstc, count, indent) if (c == '\n' || c == '\r' || c == K_KENTER || (c == ESC && (!KeyTyped || vim_strchr(p_cpo, CPO_ESC) != NULL))) { - gotesc = FALSE; /* Might have typed ESC previously, don't - truncate the cmdline now. */ - if (ccheck_abbr(c + ABBR_OFF)) - goto cmdline_changed; - if (!cmd_silent) + /* In Ex mode a backslash escapes a newline. */ + if (exmode_active + && c != ESC + && ccline.cmdpos > 0 + && ccline.cmdpos == ccline.cmdlen + && ccline.cmdbuff[ccline.cmdpos - 1] == '\\') { - windgoto(msg_row, 0); - out_flush(); + if (c == K_KENTER) + c = '\n'; + } + else + { + gotesc = FALSE; /* Might have typed ESC previously, don't + truncate the cmdline now. */ + if (ccheck_abbr(c + ABBR_OFF)) + goto cmdline_changed; + if (!cmd_silent) + { + windgoto(msg_row, 0); + out_flush(); + } + break; } - break; } /* @@ -1879,25 +1892,24 @@ getexline(c, dummy, indent) * Get an Ex command line for Ex mode. * In Ex mode we only use the OS supplied line editing features and no * mappings or abbreviations. + * Returns a string in allocated memory or NULL. */ /* ARGSUSED */ char_u * -getexmodeline(c, dummy, indent) - int c; /* normally ':', NUL for ":append" */ +getexmodeline(promptc, dummy, indent) + int promptc; /* normally ':', NUL for ":append" and '?' for + :s prompt */ void *dummy; /* cookie not used */ int indent; /* indent for inside conditionals */ { - garray_T line_ga; - int len; - int off = 0; - char_u *pend; - int finished = FALSE; -#if defined(FEAT_GUI) || defined(NO_COOKED_INPUT) - int startcol = 0; - int c1; - int escaped = FALSE; /* CTRL-V typed */ - int vcol = 0; -#endif + garray_T line_ga; + char_u *pend; + int startcol = 0; + int c1; + int escaped = FALSE; /* CTRL-V typed */ + int vcol = 0; + char_u *p; + int prev_char = 0; /* Switch cursor on now. This avoids that it happens after the "\n", which * confuses the system function that computes tabstops. */ @@ -1905,27 +1917,24 @@ getexmodeline(c, dummy, indent) /* always start in column 0; write a newline if necessary */ compute_cmdrow(); - if (msg_col) + if ((msg_col || msg_didout) && promptc != '?') msg_putchar('\n'); - if (c == ':') + if (promptc == ':') { /* indent that is only displayed, not in the line itself */ - msg_putchar(':'); + if (p_prompt) + msg_putchar(':'); while (indent-- > 0) msg_putchar(' '); -#if defined(FEAT_GUI) || defined(NO_COOKED_INPUT) startcol = msg_col; -#endif } ga_init2(&line_ga, 1, 30); /* autoindent for :insert and :append is in the line itself */ - if (c <= 0) + if (promptc <= 0) { -#if defined(FEAT_GUI) || defined(NO_COOKED_INPUT) vcol = indent; -#endif while (indent >= 8) { ga_append(&line_ga, TAB); @@ -1938,198 +1947,180 @@ getexmodeline(c, dummy, indent) msg_putchar(' '); } } + ++no_mapping; + ++allow_keys; /* * Get the line, one character at a time. */ got_int = FALSE; - while (!got_int && !finished) + while (!got_int) { if (ga_grow(&line_ga, 40) == FAIL) break; pend = (char_u *)line_ga.ga_data + line_ga.ga_len; - /* Get one character (inchar gets a third of maxlen characters!) */ - len = inchar(pend + off, 3, -1L, 0); - if (len < 0) - continue; /* end of input script reached */ - /* for a special character, we need at least three characters */ - if ((*pend == K_SPECIAL || *pend == CSI) && off + len < 3) - { - off += len; - continue; - } - len += off; - off = 0; + /* Get one character at a time. Don't use inchar(), it can't handle + * special characters. */ + c1 = vgetc(); /* - * When using the GUI, and for systems that don't have cooked input, - * handle line editing here. + * Handle line editing. + * Previously this was left to the system, putting the terminal in + * cooked mode, but then CTRL-D and CTRL-T can't be used properly. */ -#if defined(FEAT_GUI) || defined(NO_COOKED_INPUT) -# ifndef NO_COOKED_INPUT - if (gui.in_use) -# endif + if (got_int) { - if (got_int) - { - msg_putchar('\n'); - break; - } + msg_putchar('\n'); + break; + } - while (len > 0) + if (!escaped) + { + /* CR typed means "enter", which is NL */ + if (c1 == '\r') + c1 = '\n'; + + if (c1 == BS || c1 == K_BS + || c1 == DEL || c1 == K_DEL || c1 == K_KDEL) { - c1 = *pend++; - --len; - if ((c1 == K_SPECIAL -# if !defined(NO_COOKED_INPUT) || defined(FEAT_GUI) - || c1 == CSI -# endif - ) && len >= 2) + if (line_ga.ga_len > 0) { - c1 = TO_SPECIAL(pend[0], pend[1]); - pend += 2; - len -= 2; + --line_ga.ga_len; + goto redraw; } + continue; + } - if (!escaped) - { - /* CR typed means "enter", which is NL */ - if (c1 == '\r') - c1 = '\n'; - - if (c1 == BS || c1 == K_BS - || c1 == DEL || c1 == K_DEL || c1 == K_KDEL) - { - if (line_ga.ga_len > 0) - { - int i, v; - char_u *q; - - --line_ga.ga_len; - /* compute column that cursor should be in */ - v = 0; - q = ((char_u *)line_ga.ga_data); - for (i = 0; i < line_ga.ga_len; ++i) - { - if (*q == TAB) - v += 8 - v % 8; - else - v += ptr2cells(q); - ++q; - } - /* erase characters to position cursor */ - while (vcol > v) - { - msg_putchar('\b'); - msg_putchar(' '); - msg_putchar('\b'); - --vcol; - } - } - continue; - } - - if (c1 == Ctrl_U) - { - msg_col = startcol; - msg_clr_eos(); - line_ga.ga_len = 0; - continue; - } + if (c1 == Ctrl_U) + { + msg_col = startcol; + msg_clr_eos(); + line_ga.ga_len = 0; + continue; + } - if (c1 == Ctrl_T) - c1 = TAB; /* very simplistic... */ + if (c1 == Ctrl_T) + { + p = (char_u *)line_ga.ga_data; + p[line_ga.ga_len] = NUL; + indent = get_indent_str(p, 8); + indent += curbuf->b_p_sw - indent % curbuf->b_p_sw; +add_indent: + while (get_indent_str(p, 8) < indent) + { + char_u *s = skipwhite(p); - if (c1 == Ctrl_D) + ga_grow(&line_ga, 1); + mch_memmove(s + 1, s, line_ga.ga_len - (s - p) + 1); + *s = ' '; + ++line_ga.ga_len; + } +redraw: + /* redraw the line */ + msg_col = startcol; + windgoto(msg_row, msg_col); + vcol = 0; + for (p = (char_u *)line_ga.ga_data; + p < (char_u *)line_ga.ga_data + line_ga.ga_len; ++p) + { + if (*p == TAB) { - char_u *p; - - /* Delete one shiftwidth. */ - p = (char_u *)line_ga.ga_data; - p[line_ga.ga_len] = NUL; - indent = get_indent_str(p, 8); - --indent; - indent -= indent % 8; - while (get_indent_str(p, 8) > indent) - { - char_u *s = skipwhite(p); - - mch_memmove(s - 1, s, line_ga.ga_len - (s - p) + 1); - --line_ga.ga_len; - } - msg_col = startcol; - for (vcol = 0; *p != NUL; ++p) + do { - if (*p == TAB) - { - do - { - msg_putchar(' '); - } while (++vcol % 8); - } - else - { - msg_outtrans_len(p, 1); - vcol += char2cells(*p); - } - } - msg_clr_eos(); - continue; + msg_putchar(' '); + } while (++vcol % 8); } - - if (c1 == Ctrl_V) + else { - escaped = TRUE; - continue; + msg_outtrans_len(p, 1); + vcol += char2cells(*p); } } + msg_clr_eos(); + continue; + } - if (IS_SPECIAL(c1)) - c1 = '?'; - ((char_u *)line_ga.ga_data)[line_ga.ga_len] = c1; - if (c1 == '\n') - msg_putchar('\n'); - else if (c1 == TAB) + if (c1 == Ctrl_D) + { + /* Delete one shiftwidth. */ + p = (char_u *)line_ga.ga_data; + if (prev_char == '0' || prev_char == '^') { - /* Don't use chartabsize(), 'ts' can be different */ - do - { - msg_putchar(' '); - } while (++vcol % 8); + if (prev_char == '^') + ex_keep_indent = TRUE; + indent = 0; + p[--line_ga.ga_len] = NUL; } else { - msg_outtrans_len( - ((char_u *)line_ga.ga_data) + line_ga.ga_len, 1); - vcol += char2cells(c1); + p[line_ga.ga_len] = NUL; + indent = get_indent_str(p, 8); + --indent; + indent -= indent % curbuf->b_p_sw; + } + while (get_indent_str(p, 8) > indent) + { + char_u *s = skipwhite(p); + + mch_memmove(s - 1, s, line_ga.ga_len - (s - p) + 1); + --line_ga.ga_len; } - ++line_ga.ga_len; - escaped = FALSE; + goto add_indent; + } + + if (c1 == Ctrl_V || c1 == Ctrl_Q) + { + escaped = TRUE; + continue; } - windgoto(msg_row, msg_col); + + /* Ignore special key codes: mouse movement, K_IGNORE, etc. */ + if (IS_SPECIAL(c1)) + continue; + } + + if (IS_SPECIAL(c1)) + c1 = '?'; + ((char_u *)line_ga.ga_data)[line_ga.ga_len] = c1; + prev_char = c1; + if (c1 == '\n') + msg_putchar('\n'); + else if (c1 == TAB) + { + /* Don't use chartabsize(), 'ts' can be different */ + do + { + msg_putchar(' '); + } while (++vcol % 8); } -# ifndef NO_COOKED_INPUT else -# endif -#endif -#ifndef NO_COOKED_INPUT { - line_ga.ga_len += len; + msg_outtrans_len( + ((char_u *)line_ga.ga_data) + line_ga.ga_len, 1); + vcol += char2cells(c1); } -#endif + ++line_ga.ga_len; + escaped = FALSE; + + windgoto(msg_row, msg_col); pend = (char_u *)(line_ga.ga_data) + line_ga.ga_len; - if (line_ga.ga_len && pend[-1] == '\n') + + /* we are done when a NL is entered, but not when it comes after a + * backslash */ + if (line_ga.ga_len > 0 && pend[-1] == '\n' + && (line_ga.ga_len <= 1 || pend[-2] != '\\')) { - finished = TRUE; --line_ga.ga_len; --pend; *pend = NUL; + break; } } - /* note that cursor has moved, because of the echoed <CR> */ - screen_down(); + --no_mapping; + --allow_keys; + /* make following messages go to the next line */ msg_didout = FALSE; msg_col = 0; @@ -3797,10 +3788,10 @@ addstar(fname, len, context) set_expand_context(xp) expand_T *xp; { - /* only expansion for ':' and '>' commands */ + /* only expansion for ':', '>' and '=' command-lines */ if (ccline.cmdfirstc != ':' #ifdef FEAT_EVAL - && ccline.cmdfirstc != '>' + && ccline.cmdfirstc != '>' && ccline.cmdfirstc != '=' #endif ) { @@ -3828,8 +3819,16 @@ set_cmd_context(xp, str, len, col) old_char = str[col]; str[col] = NUL; nextcomm = str; - while (nextcomm != NULL) - nextcomm = set_one_cmd_context(xp, nextcomm); + +#ifdef FEAT_EVAL + if (ccline.cmdfirstc == '=') + /* pass CMD_SIZE because there is no real command */ + set_context_for_expression(xp, str, CMD_SIZE); + else +#endif + while (nextcomm != NULL) + nextcomm = set_one_cmd_context(xp, nextcomm); + str[col] = old_char; } @@ -5477,7 +5476,7 @@ ex_window() * Call the main loop until <CR> or CTRL-C is typed. */ cmdwin_result = 0; - main_loop(TRUE); + main_loop(TRUE, FALSE); RedrawingDisabled = i; diff --git a/src/gui_mac.c b/src/gui_mac.c index dbdda8a0d..b43aec0e5 100644 --- a/src/gui_mac.c +++ b/src/gui_mac.c @@ -91,6 +91,19 @@ static OSType _ftype = 'TEXT'; static EventHandlerUPP mouseWheelHandlerUPP = NULL; #endif +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) +# define USE_CARBONKEYHANDLER +static EventHandlerUPP keyEventHandlerUPP = NULL; +/* Defined in os_mac_conv.c */ +extern char_u *mac_utf16_to_enc __ARGS((UniChar *from, size_t fromLen, size_t *actualLen)); +extern UniChar *mac_enc_to_utf16 __ARGS((char_u *from, size_t fromLen, size_t *actualLen)); +extern CFStringRef mac_enc_to_cfstring __ARGS((char_u *from, size_t fromLen)); +#endif + +#ifdef MACOS_X +SInt32 gMacSystemVersion; +#endif + /* Debugging feature: start Vim window OFFSETed */ #undef USE_OFFSETED_WINDOW @@ -213,6 +226,12 @@ static struct } gFontPanelInfo = { 0, 0, 0, false }; #endif +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) +# define USE_ATSUI_DRAWING +ATSUStyle gFontStyle; +Boolean gIsFontFallbackSet; +#endif + /* * The Quickdraw global is predefined in CodeWarior * but is not in Apple MPW @@ -504,6 +523,63 @@ points_to_pixels(char_u *str, char_u **end, int vertical) return pixels; } +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) +/* + * Deletes all traces of any Windows-style mnemonic text (including any + * parentheses) from a menu item and returns the cleaned menu item title. + * The caller is responsible for releasing the returned string. + */ + static CFStringRef +menu_title_removing_mnemonic(menu) + vimmenu_T *menu; +{ + CFStringRef name; + size_t menuTitleLen; + CFIndex displayLen; + CFRange mnemonicStart; + CFRange mnemonicEnd; + CFMutableStringRef cleanedName; + + menuTitleLen = STRLEN(menu->dname); + name = mac_enc_to_cfstring(menu->dname, menuTitleLen); + + if (name) + { + /* Simple mnemonic-removal algorithm, assumes single parenthesized + * mnemonic character towards the end of the menu text */ + mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards); + displayLen = CFStringGetLength(name); + + if (mnemonicStart.location != kCFNotFound + && (mnemonicStart.location + 2) < displayLen + && CFStringGetCharacterAtIndex(name, + mnemonicStart.location + 1) == (UniChar)menu->mnemonic) + { + if (CFStringFindWithOptions(name, CFSTR(")"), + CFRangeMake(mnemonicStart.location + 1, + displayLen - mnemonicStart.location - 1), + kCFCompareBackwards, &mnemonicEnd) && + (mnemonicStart.location + 2) == mnemonicEnd.location) + { + cleanedName = CFStringCreateMutableCopy(NULL, 0, name); + if (cleanedName) + { + CFStringDelete(cleanedName, + CFRangeMake(mnemonicStart.location, + mnemonicEnd.location + 1 - + mnemonicStart.location)); + + CFRelease(name); + name = cleanedName; + } + } + } + } + + return name; +} +#endif + /* * Convert a list of FSSpec aliases into a list of fullpathname * character strings. @@ -1231,20 +1307,19 @@ HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) /* Select the text if possible */ if (gotPosition) { - VIsual_active = TRUE; - VIsual_select = FALSE; - if (thePosition.lineNum < 0) + VIsual_active = TRUE; + VIsual_select = FALSE; + VIsual = curwin->w_cursor; + if (thePosition.lineNum < 0) { - VIsual_mode = 'v'; - VIsual = curwin->w_cursor; - goto_byte(thePosition.endRange); - } - else + VIsual_mode = 'v'; + goto_byte(thePosition.endRange); + } + else { - VIsual_mode = 'V'; - VIsual = curwin->w_cursor; - VIsual.col = 0; - } + VIsual_mode = 'V'; + VIsual.col = 0; + } } #endif setcursor(); @@ -1541,25 +1616,47 @@ InstallFontPanelHandler() * Fill the buffer pointed to by outName with the name and size * of the font currently selected in the Font Panel. */ +#define FONT_STYLE_BUFFER_SIZE 32 static void GetFontPanelSelection(char_u* outName) { - Str255 buf; - Boolean isBold = false, isItalic = false; + Str255 buf; + ByteCount fontNameLen = 0; + ATSUFontID fid; + char_u styleString[FONT_STYLE_BUFFER_SIZE]; if (!outName) return; - (void)FMGetFontFamilyName(gFontPanelInfo.family, buf); - p2cstrcpy(outName, buf); + if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr) + { + /* Canonicalize localized font names */ + if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family, + gFontPanelInfo.style, &fid, NULL) != noErr) + return; -#if 0 /* TODO: enable when styles are supported in gui_mac_find_font() */ - isBold = (gFontPanelInfo.style & bold); - isItalic = (gFontPanelInfo.style & italic); -#endif + /* Request font name with Mac encoding (otherwise we could + * get an unwanted utf-16 name) */ + if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform, + kFontNoScriptCode, kFontNoLanguageCode, + 255, outName, &fontNameLen, NULL) != noErr) + return; - sprintf(&outName[buf[0]], ":h%d%s%s", gFontPanelInfo.size, - (isBold ? ":b" : ""), (isItalic ? ":i" : "")); + /* Only encode font size, because style (bold, italic, etc) is + * already part of the font full name */ + snprintf(styleString, FONT_STYLE_BUFFER_SIZE, ":h%d", + gFontPanelInfo.size/*, + ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""), + ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""), + ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/); + + if ((fontNameLen + STRLEN(styleString)) < 255) + STRCPY(outName + fontNameLen, styleString); + } + else + { + *outName = NULL; + } } #endif @@ -2213,7 +2310,187 @@ gui_mac_doSuspendEvent(event) /* * Handle the key */ +#ifdef USE_CARBONKEYHANDLER +# define INLINE_KEY_BUFFER_SIZE 80 + static pascal OSStatus +gui_mac_doKeyEventCarbon(EventHandlerCallRef nextHandler, EventRef theEvent, + void *data) +{ + /* Multibyte-friendly key event handler */ + OSStatus e = -1; + UInt32 actualSize; + UniChar *text; + char_u result[INLINE_KEY_BUFFER_SIZE]; + short len = 0; + UInt32 key_sym; + char charcode; + int key_char; + UInt32 modifiers; + size_t encLen; + char_u *to = NULL; + Boolean isSpecial = FALSE; + int i; + + /* Mask the mouse (as per user setting) */ + if (p_mh) + ObscureCursor(); + + do + { + if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText, + typeUnicodeText, NULL, 0, &actualSize, NULL)) + break; + + text = (UniChar *)alloc(actualSize); + + if (text) + { + do + { + if (noErr != GetEventParameter(theEvent, + kEventParamTextInputSendText, + typeUnicodeText, NULL, actualSize, NULL, text)) + break; + EventRef keyEvent; + if (noErr != GetEventParameter(theEvent, + kEventParamTextInputSendKeyboardEvent, + typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent)) + break; + if (noErr != GetEventParameter(keyEvent, + kEventParamKeyModifiers, + typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers)) + break; + if (noErr != GetEventParameter(keyEvent, + kEventParamKeyCode, + typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym)) + break; + if (noErr != GetEventParameter(keyEvent, + kEventParamKeyMacCharCodes, + typeChar, NULL, sizeof(char), NULL, &charcode)) + break; + + key_char = charcode; + + if (modifiers & controlKey) + { + if ((modifiers & ~(controlKey|shiftKey)) == 0 + && (key_char == '2' || key_char == '6')) + { + /* CTRL-^ and CTRL-@ don't work in the normal way. */ + if (key_char == '2') + key_char = Ctrl_AT; + else + key_char = Ctrl_HAT; + + text[0] = (UniChar)key_char; + modifiers = 0; + } + } + + if (modifiers & cmdKey) +#ifndef USE_CMD_KEY + break; /* Let system handle Cmd+... */ +#else + { + /* Intercept CMD-. */ + if (key_char == '.') + got_int = TRUE; + + /* Convert the modifiers */ + modifiers = EventModifiers2VimModifiers(modifiers); + + /* Following code to simplify and consolidate modifiers + * taken liberally from gui_w48.c */ + + key_char = simplify_key(key_char, (int *)&modifiers); + + /* remove SHIFT for keys that are already shifted, e.g., + * '(' and '*' */ + if (key_char < 0x100 && + !isalpha(key_char) && isprint(key_char)) + modifiers &= ~MOD_MASK_SHIFT; + + /* Interpret META, include SHIFT, etc. */ + key_char = extract_modifiers(key_char, (int *)&modifiers); + if (key_char == CSI) + key_char = K_CSI; + + if (modifiers) + { + result[len++] = CSI; + result[len++] = KS_MODIFIER; + result[len++] = modifiers; + } + + isSpecial = TRUE; + } +#endif + else + { + /* Find the special key (eg., for cursor keys) */ + if (!(actualSize > sizeof(UniChar)) && + ((text[0] < 0x20) || (text[0] == 0x7f))) + { + for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i) + if (special_keys[i].key_sym == key_sym) + { + key_char = TO_SPECIAL(special_keys[i].vim_code0, + special_keys[i].vim_code1); + key_char = simplify_key(key_char, + (int *)&modifiers); + isSpecial = TRUE; + break; + } + } + } + + if (isSpecial && IS_SPECIAL(key_char)) + { + result[len++] = CSI; + result[len++] = K_SECOND(key_char); + result[len++] = K_THIRD(key_char); + } + else + { + encLen = actualSize; + to = mac_utf16_to_enc(text, actualSize, &encLen); + } + + if (to) + { + /* This is basically add_to_input_buf_csi() */ + for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i) + { + result[len++] = to[i]; + if (to[i] == CSI) + { + result[len++] = KS_EXTRA; + result[len++] = (int)KE_CSI; + } + } + vim_free(to); + } + add_to_input_buf(result, len); + e = noErr; + } + while (0); + + vim_free(text); + if (e == noErr) + { + /* Fake event to wake up WNE (required to get + * key repeat working */ + PostEvent(keyUp, 0); + return noErr; + } + } + } + while (0); + + return CallNextEventHandler(nextHandler, theEvent); +} +#else void gui_mac_doKeyEvent(EventRecord *theEvent) { @@ -2387,6 +2664,7 @@ gui_mac_doKeyEvent(EventRecord *theEvent) add_to_input_buf(string, len); } +#endif /* * Handle MouseClick @@ -2664,11 +2942,12 @@ gui_mac_handle_event(event) /* Handle normal event */ switch (event->what) { +#ifndef USE_CARBONKEYHANDLER case (keyDown): case (autoKey): gui_mac_doKeyEvent(event); break; - +#endif case (keyUp): /* We don't care about when the key get release */ break; @@ -2747,7 +3026,27 @@ gui_mac_find_font(font_name) pFontName[0] = STRLEN(font_name); *p = c; + /* Get the font name, minus the style suffix (:h, etc) */ +#if defined(MACOS_X) && defined(USE_CARBONIZED) + char_u fontName[256]; + char_u *styleStart = vim_strchr(font_name, ':'); + size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName); + vim_strncpy(fontName, font_name, fontNameLen); + + ATSUFontID fontRef; + FMFontStyle fontStyle; + font_id = 0; + + if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName, + kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode, + &fontRef) == noErr) + { + if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr) + font_id = 0; + } +#else GetFNum(pFontName, &font_id); +#endif if (font_id == 0) { @@ -2767,7 +3066,17 @@ gui_mac_find_font(font_name) } } if (changed) +#if defined(MACOS_X) && defined(USE_CARBONIZED) + if (ATSUFindFontFromName(&pFontName[1], pFontName[0], + kFontFullName, kFontNoPlatformCode, kFontNoScriptCode, + kFontNoLanguageCode, &fontRef) == noErr) + { + if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr) + font_id = 0; + } +#else GetFNum(pFontName, &font_id); +#endif } #else @@ -2782,7 +3091,12 @@ gui_mac_find_font(font_name) { /* Oups, the system font was it the one the user want */ +#if defined(MACOS_X) && defined(USE_CARBONIZED) + if (FMGetFontFamilyName(systemFont, systemFontname) != noErr) + return NOFONT; +#else GetFontName(0, systemFontname); +#endif if (!EqualString(pFontName, systemFontname, false, false)) return NOFONT; } @@ -3079,6 +3393,15 @@ gui_mch_init() EventTypeSpec eventTypeSpec; EventHandlerRef mouseWheelHandlerRef; #endif +#ifdef USE_CARBONKEYHANDLER + EventHandlerRef keyEventHandlerRef; +#endif + +#ifdef MACOS_X + if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr) + gMacSystemVersion = 0x1000; /* Default to minimum sensible value */ +#endif + #if 1 InitCursor(); @@ -3238,9 +3561,24 @@ gui_mch_init() } #endif +#ifdef USE_CARBONKEYHANDLER + eventTypeSpec.eventClass = kEventClassTextInput; + eventTypeSpec.eventKind = kEventUnicodeForKeyEvent; + keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_doKeyEventCarbon); + if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP, 1, + &eventTypeSpec, NULL, &keyEventHandlerRef)) + { + keyEventHandlerRef = NULL; + DisposeEventHandlerUPP(keyEventHandlerUPP); + keyEventHandlerUPP = NULL; + } +#endif + +/* #ifdef FEAT_MBYTE - set_option_value((char_u *)"termencoding", 0L, (char_u *)"macroman", 0); + set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0); #endif +*/ /* TODO: Load bitmap if using TOOLBAR */ return OK; @@ -3290,11 +3628,21 @@ gui_mch_exit(int rc) /* TODO: find out all what is missing here? */ DisposeRgn(cursorRgn); +#ifdef USE_CARBONKEYHANDLER + if (keyEventHandlerUPP) + DisposeEventHandlerUPP(keyEventHandlerUPP); +#endif + #ifdef USE_MOUSEWHEEL if (mouseWheelHandlerUPP != NULL) DisposeEventHandlerUPP(mouseWheelHandlerUPP); #endif +#ifdef USE_ATSUI_DRAWING + if (gFontStyle) + ATSUDisposeStyle(gFontStyle); +#endif + /* Exit to shell? */ exit(rc); } @@ -3466,6 +3814,14 @@ gui_mch_init_font(font_name, fontset) GuiFont font; char_u used_font_name[512]; +#ifdef USE_ATSUI_DRAWING + if (gFontStyle == NULL) + { + if (ATSUCreateStyle(&gFontStyle) != noErr) + gFontStyle = NULL; + } +#endif + if (font_name == NULL) { /* First try to get the suggested font */ @@ -3523,6 +3879,54 @@ gui_mch_init_font(font_name, fontset) TextSize(font >> 16); TextFont(font & 0xFFFF); +#ifdef USE_ATSUI_DRAWING + ATSUFontID fontID; + Fixed fontSize; + ATSStyleRenderingOptions fontOptions; + + if (gFontStyle) + { + fontID = font & 0xFFFF; + fontSize = Long2Fix(font >> 16); + + /* No antialiasing by default (do not attempt to touch antialising + * options on pre-Jaguar) */ + fontOptions = +#ifdef MACOS_X + (gMacSystemVersion >= 0x1020) ? + kATSStyleNoAntiAliasing : +#endif + kATSStyleNoOptions; + + ATSUAttributeTag attribTags[] = + { + kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag, + kATSUMaxATSUITagValue+1 + }; + ByteCount attribSizes[] = + { + sizeof(ATSUFontID), sizeof(Fixed), + sizeof(ATSStyleRenderingOptions), sizeof font + }; + ATSUAttributeValuePtr attribValues[] = + { + &fontID, &fontSize, &fontOptions, &font + }; + + /* Convert font id to ATSUFontID */ + if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr) + { + if (ATSUSetAttributes(gFontStyle, + (sizeof attribTags)/sizeof(ATSUAttributeTag), + attribTags, attribSizes, attribValues) != noErr) + { + ATSUDisposeStyle(gFontStyle); + gFontStyle = NULL; + } + } + } +#endif + GetFontInfo(&font_info); gui.char_ascent = font_info.ascent; @@ -3592,9 +3996,99 @@ gui_mch_get_fontname(font, name) gui_mch_set_font(font) GuiFont font; { - /* - * TODO: maybe avoid set again the current font. - */ +#ifdef USE_ATSUI_DRAWING + GuiFont currFont; + ByteCount actualFontByteCount; + ATSUFontID fontID; + Fixed fontSize; + ATSStyleRenderingOptions fontOptions; + + if (gFontStyle) + { + /* Avoid setting same font again */ + if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue+1, sizeof font, + &currFont, &actualFontByteCount) == noErr && + actualFontByteCount == (sizeof font)) + { + if (currFont == font) + return; + } + + fontID = font & 0xFFFF; + fontSize = Long2Fix(font >> 16); + /* Respect p_antialias setting only for wide font. + * The reason for doing this at the moment is a bit complicated, + * but it's mainly because a) latin (non-wide) aliased fonts + * look bad in OS X 10.3.x and below (due to a bug in ATS), and + * b) wide multibyte input does not suffer from that problem. */ + fontOptions = +#ifdef MACOS_X + (p_antialias && (font == gui.wide_font)) ? + kATSStyleNoOptions : kATSStyleNoAntiAliasing; +#else + kATSStyleNoOptions; +#endif + + ATSUAttributeTag attribTags[] = + { + kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag, + kATSUMaxATSUITagValue+1 + }; + ByteCount attribSizes[] = + { + sizeof(ATSUFontID), sizeof(Fixed), + sizeof(ATSStyleRenderingOptions), sizeof font + }; + ATSUAttributeValuePtr attribValues[] = + { + &fontID, &fontSize, &fontOptions, &font + }; + + if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr) + { + if (ATSUSetAttributes(gFontStyle, + (sizeof attribTags)/sizeof(ATSUAttributeTag), + attribTags, attribSizes, attribValues) != noErr) + { +#ifndef NDEBUG + fprintf(stderr, "couldn't set font style\n"); +#endif + ATSUDisposeStyle(gFontStyle); + gFontStyle = NULL; + } + } + + } + + if (!gIsFontFallbackSet) + { + /* Setup automatic font substitution. The user's guifontwide + * is tried first, then the system tries other fonts. */ +/* + ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag }; + ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) }; + ATSUCreateFontFallbacks(&gFontFallbacks); + ATSUSetObjFontFallbacks(gFontFallbacks, ); +*/ + if (gui.wide_font) + { + ATSUFontID fallbackFonts; + gIsFontFallbackSet = TRUE; + + if (FMGetFontFromFontFamilyInstance( + (gui.wide_font & 0xFFFF), + 0, + &fallbackFonts, + NULL) == noErr) + { + ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID), &fallbackFonts, kATSUSequentialFallbacksPreferred); + } +/* + ATSUAttributeValuePtr fallbackValues[] = { }; +*/ + } + } +#endif TextSize(font >> 16); TextFont(font & 0xFFFF); } @@ -3820,9 +4314,17 @@ gui_mch_draw_string(row, col, s, len, flags) int flags; { #if defined(FEAT_GUI) && defined(MACOS_X) +#ifndef USE_ATSUI_DRAWING SInt32 sys_version; #endif +#endif #ifdef FEAT_MBYTE +#ifdef USE_ATSUI_DRAWING + /* ATSUI requires utf-16 strings */ + UniCharCount utf16_len; + UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len); + utf16_len /= sizeof(UniChar); +#else char_u *tofree = NULL; if (output_conv.vc_type != CONV_NONE) @@ -3832,8 +4334,11 @@ gui_mch_draw_string(row, col, s, len, flags) s = tofree; } #endif +#endif #if defined(FEAT_GUI) && defined(MACOS_X) + /* ATSUI automatically antialiases text */ +#ifndef USE_ATSUI_DRAWING /* * On OS X, try using Quartz-style text antialiasing. */ @@ -3845,8 +4350,9 @@ gui_mch_draw_string(row, col, s, len, flags) /* Quartz antialiasing is available only in OS 10.2 and later. */ UInt32 qd_flags = (p_antialias ? kQDUseCGTextRendering | kQDUseCGTextMetrics : 0); - (void)SwapQDTextFlags(qd_flags); + QDSwapTextFlags(qd_flags); } +#endif /* * When antialiasing we're using srcOr mode, we have to clear the block @@ -3857,18 +4363,37 @@ gui_mch_draw_string(row, col, s, len, flags) * The following is like calling gui_mch_clear_block(row, col, row, col + * len - 1), but without setting the bg color to gui.back_pixel. */ +#ifdef USE_ATSUI_DRAWING + if ((flags & DRAW_TRANSP) == 0) +#else if (((sys_version >= 0x1020 && p_antialias) || p_linespace != 0) && !(flags & DRAW_TRANSP)) +#endif { Rect rc; rc.left = FILL_X(col); rc.top = FILL_Y(row); +#ifdef FEAT_MBYTE + /* Multibyte computation taken from gui_w32.c */ + if (has_mbyte) + { + int cell_len = 0; + int n; + + /* Compute the length in display cells. */ + for (n = 0; n < len; n += MB_BYTE2LEN(s[n])) + cell_len += (*mb_ptr2cells)(s + n); + rc.right = FILL_X(col + cell_len); + } + else +#endif rc.right = FILL_X(col + len) + (col + len == Columns); rc.bottom = FILL_Y(row + 1); EraseRect(&rc); } +#ifndef USE_ATSUI_DRAWING if (sys_version >= 0x1020 && p_antialias) { StyleParameter face; @@ -3888,6 +4413,7 @@ gui_mch_draw_string(row, col, s, len, flags) } else #endif +#endif { /* Use old-style, non-antialiased QuickDraw text rendering. */ TextMode(srcCopy); @@ -3901,6 +4427,25 @@ gui_mch_draw_string(row, col, s, len, flags) } MoveTo(TEXT_X(col), TEXT_Y(row)); +#ifdef USE_ATSUI_DRAWING + ATSUTextLayout textLayout; + + if (ATSUCreateTextLayoutWithTextPtr(tofree, + kATSUFromTextBeginning, kATSUToTextEnd, + utf16_len, + (gFontStyle ? 1 : 0), &utf16_len, + (gFontStyle ? &gFontStyle : NULL), + &textLayout) == noErr) + { + ATSUSetTransientFontMatching(textLayout, TRUE); + + ATSUDrawText(textLayout, + kATSUFromTextBeginning, kATSUToTextEnd, + kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc); + + ATSUDisposeTextLayout(textLayout); + } +#else DrawText((char *)s, 0, len); @@ -3916,6 +4461,7 @@ gui_mch_draw_string(row, col, s, len, flags) MoveTo(FILL_X(col), FILL_Y(row + 1) - 1); LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1); } +#endif } #ifdef FEAT_MBYTE @@ -4021,14 +4567,16 @@ gui_mch_draw_hollow_cursor(color) { Rect rc; - gui_mch_set_fg_color(color); - /* * Note: FrameRect() excludes right and bottom of rectangle. */ rc.left = FILL_X(gui.col); rc.top = FILL_Y(gui.row); rc.right = rc.left + gui.char_width; +#ifdef FEAT_MBYTE + if (mb_lefthalve(gui.row, gui.col)) + rc.right += gui.char_width; +#endif rc.bottom = rc.top + gui.char_height; gui_mch_set_fg_color(color); @@ -4060,7 +4608,8 @@ gui_mch_draw_part_cursor(w, h, color) gui_mch_set_fg_color(color); - PaintRect(&rc); + FrameRect(&rc); +// PaintRect(&rc); } @@ -4346,11 +4895,11 @@ clip_mch_request_selection(cbd) if (flavor == 0) { - error = GetScrapFlavorFlags(scrap, kScrapFlavorTypeText, &scrapFlags); + error = GetScrapFlavorFlags(scrap, kScrapFlavorTypeUnicode, &scrapFlags); if (error != noErr) return; - error = GetScrapFlavorSize(scrap, kScrapFlavorTypeText, &scrapSize); + error = GetScrapFlavorSize(scrap, kScrapFlavorTypeUnicode, &scrapSize); if (error != noErr) return; } @@ -4374,7 +4923,7 @@ clip_mch_request_selection(cbd) HLock(textOfClip); #ifdef USE_CARBONIZED error = GetScrapFlavorData(scrap, - flavor ? VIMSCRAPFLAVOR : kScrapFlavorTypeText, + flavor ? VIMSCRAPFLAVOR : kScrapFlavorTypeUnicode, &scrapSize, *textOfClip); #else scrapSize = GetScrap(textOfClip, 'TEXT', &scrapOffset); @@ -4387,7 +4936,11 @@ clip_mch_request_selection(cbd) type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR; tempclip = lalloc(scrapSize + 1, TRUE); +#if defined(FEAT_MBYTE) && defined(USE_CARBONIZED) + mch_memmove(tempclip, *textOfClip + flavor, scrapSize); +#else STRNCPY(tempclip, *textOfClip + flavor, scrapSize); +#endif tempclip[scrapSize] = 0; searchCR = (char *)tempclip; @@ -4400,19 +4953,15 @@ clip_mch_request_selection(cbd) } -#ifdef FEAT_MBYTE - if (input_conv.vc_type != CONV_NONE) +#if defined(FEAT_MBYTE) && defined(USE_CARBONIZED) + /* Convert from utf-16 (clipboard) */ + size_t encLen = 0; + char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen); + if (to) { - char_u *to; - int l = scrapSize; - - to = string_convert(&input_conv, tempclip, &l); - if (to != NULL) - { - vim_free(tempclip); - tempclip = to; - scrapSize = l; - } + scrapSize = encLen; + vim_free(tempclip); + tempclip = to; } #endif clip_yank_selection(type, tempclip, scrapSize, cbd); @@ -4471,19 +5020,14 @@ clip_mch_set_selection(cbd) type = clip_convert_selection(&str, (long_u *) &scrapSize, cbd); -#ifdef FEAT_MBYTE - if (str != NULL && output_conv.vc_type != CONV_NONE) +#if defined(FEAT_MBYTE) && defined(USE_CARBONIZED) + size_t utf16_len = 0; + UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len); + if (to) { - char_u *to; - int l = scrapSize; - - to = string_convert(&output_conv, str, &l); - if (to != NULL) - { - vim_free(str); - str = to; - scrapSize = l; - } + scrapSize = utf16_len; + vim_free(str); + str = (char_u *)to; } #endif @@ -4504,9 +5048,9 @@ clip_mch_set_selection(cbd) #ifdef USE_CARBONIZED **textOfClip = type; - STRNCPY(*textOfClip + 1, str, scrapSize); + mch_memmove(*textOfClip + 1, str, scrapSize); GetCurrentScrap(&scrap); - PutScrapFlavor(scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, + PutScrapFlavor(scrap, kScrapFlavorTypeUnicode, kScrapFlavorMaskNone, scrapSize, *textOfClip + 1); PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone, scrapSize + 1, *textOfClip); @@ -4599,7 +5143,11 @@ gui_mch_add_menu(menu, idx) */ static long next_avail_id = 128; long menu_after_me = 0; /* Default to the end */ +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) + CFStringRef name; +#else char_u *name; +#endif short index; vimmenu_T *parent = menu->parent; vimmenu_T *brother = menu->next; @@ -4625,13 +5173,21 @@ gui_mch_add_menu(menu, idx) menu_after_me = hierMenu; /* Convert the name */ +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) + name = menu_title_removing_mnemonic(menu); +#else name = C2Pascal_save(menu->dname); +#endif if (name == NULL) return; /* Create the menu unless it's the help menu */ #ifdef USE_HELPMENU +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) + if (menu->priority == 9999) +#else if (STRNCMP(name, "\4Help", 5) == 0) +#endif { menu->submenu_id = kHMHelpMenuID; menu->submenu_handle = gui.MacOSHelpMenu; @@ -4644,7 +5200,12 @@ gui_mch_add_menu(menu, idx) * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title); */ menu->submenu_id = next_avail_id; +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) + if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr) + SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name); +#else menu->submenu_handle = NewMenu(menu->submenu_id, name); +#endif next_avail_id++; } @@ -4676,13 +5237,21 @@ gui_mch_add_menu(menu, idx) * to avoid special character recognition by InsertMenuItem */ InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */ +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) + SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name); +#else SetMenuItemText(parent->submenu_handle, idx+1, name); +#endif SetItemCmd(parent->submenu_handle, idx+1, 0x1B); SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id); InsertMenu(menu->submenu_handle, hierMenu); } +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) + CFRelease(name); +#else vim_free(name); +#endif #if 0 /* Done by Vim later on */ @@ -4698,7 +5267,11 @@ gui_mch_add_menu_item(menu, idx) vimmenu_T *menu; int idx; { +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) + CFStringRef name; +#else char_u *name; +#endif vimmenu_T *parent = menu->parent; int menu_inserted; @@ -4710,7 +5283,11 @@ gui_mch_add_menu_item(menu, idx) for older OS call GetMenuItemData (menu, item, isCommandID?, data) */ /* Convert the name */ +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) + name = menu_title_removing_mnemonic(menu); +#else name = C2Pascal_save(menu->dname); +#endif /* Where are just a menu item, so no handle, no id */ menu->submenu_id = 0; @@ -4796,15 +5373,23 @@ gui_mch_add_menu_item(menu, idx) if (!menu_inserted) InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */ /* Set the menu item name. */ +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) + SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name); +#else SetMenuItemText(parent->submenu_handle, idx+1, name); +#endif #if 0 /* Called by Vim */ DrawMenuBar(); #endif +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) + CFRelease(name); +#else /* TODO: Can name be freed? */ vim_free(name); +#endif } void @@ -5811,17 +6396,33 @@ gui_mch_settitle(title, icon) /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller * that 256. Even better get it to fit nicely in the titlebar. */ +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) + CFStringRef windowTitle; + size_t windowTitleLen; +#else char_u *pascalTitle; +#endif if (title == NULL) /* nothing to do */ return; +#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE) + windowTitleLen = STRLEN(title); + windowTitle = mac_enc_to_cfstring(title, windowTitleLen); + + if (windowTitle) + { + SetWindowTitleWithCFString(gui.VimWindow, windowTitle); + CFRelease(windowTitle); + } +#else pascalTitle = C2Pascal_save(title); if (pascalTitle != NULL) { SetWTitle(gui.VimWindow, pascalTitle); vim_free(pascalTitle); } +#endif } #endif @@ -1105,10 +1105,20 @@ do_execreg(regname, colon, addcr) int remap; if (regname == '@') /* repeat previous one */ + { + if (lastc == NUL) + { + EMSG(_("E748: No previously used register")); + return FAIL; + } regname = lastc; + } /* check for valid regname */ if (regname == '%' || regname == '#' || !valid_yank_reg(regname, FALSE)) + { + emsg_invreg(regname); return FAIL; + } lastc = regname; #ifdef FEAT_CLIPBOARD @@ -3597,7 +3607,13 @@ error: else curbuf->b_op_end.col = 0; - if (flags & PUT_CURSEND) + if (flags & PUT_CURSLINE) + { + /* ":put": put cursor on last inserte line */ + curwin->w_cursor.lnum = lnum; + beginline(BL_WHITE | BL_FIX); + } + else if (flags & PUT_CURSEND) { /* put cursor after inserted text */ if (y_type == MLINE) @@ -3616,7 +3632,7 @@ error: } else if (y_type == MLINE) { - /* put cursor onfirst non-blank in first inserted line */ + /* put cursor on first non-blank in first inserted line */ curwin->w_cursor.col = 0; if (dir == FORWARD) ++curwin->w_cursor.lnum; @@ -5676,7 +5692,7 @@ write_reg_contents_ex(name, str, maxlen, must_append, yank_type, block_len) if (!valid_yank_reg(name, TRUE)) /* check for valid reg name */ { - EMSG2(_("E354: Invalid register name: '%s'"), transchar(name)); + emsg_invreg(name); return; } diff --git a/src/option.c b/src/option.c index 205b21c20..4444b1f89 100644 --- a/src/option.c +++ b/src/option.c @@ -1723,8 +1723,8 @@ static struct vimoption #endif }, {"prompt", NULL, P_BOOL|P_VI_DEF, - (char_u *)NULL, PV_NONE, - {(char_u *)FALSE, (char_u *)0L}}, + (char_u *)&p_prompt, PV_NONE, + {(char_u *)TRUE, (char_u *)0L}}, {"quoteescape", "qe", P_STRING|P_ALLOCED|P_VI_DEF, #ifdef FEAT_TEXTOBJ (char_u *)&p_qe, PV_QE, @@ -1922,6 +1922,9 @@ static struct vimoption (char_u *)NULL, PV_NONE, #endif {(char_u *)FALSE, (char_u *)0L}}, + {"shelltemp", "stmp", P_BOOL, + (char_u *)&p_stmp, PV_NONE, + {(char_u *)FALSE, (char_u *)TRUE}}, {"shelltype", "st", P_NUM|P_VI_DEF, #ifdef AMIGA (char_u *)&p_st, PV_NONE, @@ -2501,7 +2504,7 @@ static char *(p_bsdir_values[]) = {"current", "last", "buffer", NULL}; static char *(p_scbopt_values[]) = {"ver", "hor", "jump", NULL}; #endif static char *(p_swb_values[]) = {"useopen", "split", NULL}; -static char *(p_debug_values[]) = {"msg", NULL}; +static char *(p_debug_values[]) = {"msg", "beep", NULL}; #ifdef FEAT_VERTSPLIT static char *(p_ead_values[]) = {"both", "ver", "hor", NULL}; #endif @@ -2593,7 +2596,10 @@ set_init_1() /* Use POSIX compatibility when $VIM_POSIX is set. */ if (mch_getenv((char_u *)"VIM_POSIX") != NULL) + { set_string_default("cpo", (char_u *)CPO_ALL); + set_string_default("shm", (char_u *)"A"); + } /* * Find default value for 'shell' option. @@ -2885,6 +2891,23 @@ set_init_1() vim_setenv("LANG", buf); } } +# else +# ifdef MACOS + if (mch_getenv((char_u *)"LANG") == NULL) + { + char buf[20]; + if (LocaleRefGetPartString(NULL, + kLocaleLanguageMask | kLocaleLanguageVariantMask | + kLocaleRegionMask | kLocaleRegionVariantMask, + sizeof buf, buf) == noErr && *buf) + { + vim_setenv("LANG", buf); +# ifdef HAVE_LOCALE_H + setlocale(LC_ALL, ""); +# endif + } + } +# endif # endif /* enc_locale() will try to find the encoding of the current locale. */ @@ -3093,6 +3116,9 @@ set_init_2() * wrong when the window height changes. */ set_number_default("scroll", (long_u)Rows >> 1); + idx = findoption((char_u *)"scroll"); + if (!(options[idx].flags & P_WAS_SET)) + set_option_default(idx, OPT_LOCAL, p_cp); comp_col(); /* @@ -3423,7 +3449,8 @@ do_set(arg, opt_flags) if (*arg == NUL) { showoptions(0, opt_flags); - return OK; + did_show = TRUE; + goto theend; } while (*arg != NUL) /* loop to process all options */ @@ -3446,12 +3473,16 @@ do_set(arg, opt_flags) set_options_default(OPT_FREE | opt_flags); } else + { showoptions(1, opt_flags); + did_show = TRUE; + } } else if (STRNCMP(arg, "termcap", 7) == 0 && !(opt_flags & OPT_MODELINE)) { showoptions(2, opt_flags); show_termcodes(); + did_show = TRUE; arg += 7; } else @@ -4187,6 +4218,19 @@ skip: arg = skipwhite(arg); } +theend: + if (silent_mode && did_show) + { + /* After displaying option values in silent mode. */ + silent_mode = FALSE; + info_message = TRUE; /* use mch_msg(), not mch_errmsg() */ + msg_putchar('\n'); + cursor_on(); /* msg_start() switches it off */ + out_flush(); + silent_mode = TRUE; + info_message = FALSE; /* use mch_msg(), not mch_errmsg() */ + } + return OK; } @@ -7547,7 +7591,11 @@ showoneopt(p, opt_flags) struct vimoption *p; int opt_flags; /* OPT_LOCAL or OPT_GLOBAL */ { - char_u *varp; + char_u *varp; + int save_silent = silent_mode; + + silent_mode = FALSE; + info_message = TRUE; /* use mch_msg(), not mch_errmsg() */ varp = get_varp_scope(p, opt_flags); @@ -7567,6 +7615,9 @@ showoneopt(p, opt_flags) option_value2string(p, opt_flags); msg_outtrans(NameBuff); } + + silent_mode = save_silent; + info_message = FALSE; } /* diff --git a/src/option.h b/src/option.h index 674eb4e5d..cd05f539e 100644 --- a/src/option.h +++ b/src/option.h @@ -174,10 +174,13 @@ #define CPO_PARA '{' /* "{" is also a paragraph boundary */ #define CPO_TSIZE '|' /* $LINES and $COLUMNS overrule term size */ #define CPO_PRESERVE '&' /* keep swap file after :preserve */ +#define CPO_SUBPERCENT '/' /* % in :s string uses previous one */ +#define CPO_BACKSL '\\' /* \ is not special in [] */ +#define CPO_CHDIR '.' /* don't chdir if buffer is modified */ /* default values for Vim, Vi and POSIX */ #define CPO_VIM "aABceFs" #define CPO_VI "aAbBcCdDeEfFgHiIjJkKlLmMnoOpqrRsStuvwWxXyZ$!%*-+<>" -#define CPO_ALL "aAbBcCdDeEfFgHiIjJkKlLmMnoOpqrRsStuvwWxXyZ$!%*-+<>#{|&" +#define CPO_ALL "aAbBcCdDeEfFgHiIjJkKlLmMnoOpqrRsStuvwWxXyZ$!%*-+<>#{|&/\\." /* characters for p_ww option: */ #define WW_ALL "bshl<>[],~" @@ -479,6 +482,7 @@ EXTERN char_u *p_pfn; /* 'printfont' */ EXTERN char_u *p_popt; /* 'printoptions' */ EXTERN char_u *p_header; /* 'printheader' */ #endif +EXTERN int p_prompt; /* 'prompt' */ #ifdef FEAT_GUI EXTERN char_u *p_guifont; /* 'guifont' */ # ifdef FEAT_XFONTSET @@ -675,6 +679,7 @@ EXTERN char_u *p_srr; /* 'shellredir' */ #ifdef AMIGA EXTERN long p_st; /* 'shelltype' */ #endif +EXTERN int p_stmp; /* 'shelltemp' */ #ifdef BACKSLASH_IN_FILENAME EXTERN int p_ssl; /* 'shellslash' */ #endif diff --git a/src/os_mac_conv.c b/src/os_mac_conv.c index 3f64e3da4..68d46c0f2 100644 --- a/src/os_mac_conv.c +++ b/src/os_mac_conv.c @@ -21,6 +21,21 @@ extern char_u *mac_string_convert __ARGS((char_u *ptr, int len, int *lenp, int f extern int macroman2enc __ARGS((char_u *ptr, long *sizep, long real_size)); extern int enc2macroman __ARGS((char_u *from, size_t fromlen, char_u *to, int *tolenp, int maxtolen, char_u *rest, int *restlenp)); +extern void mac_conv_init __ARGS((void)); +extern void mac_conv_cleanup __ARGS((void)); +extern char_u *mac_utf16_to_enc __ARGS((UniChar *from, size_t fromLen, size_t *actualLen)); +extern UniChar *mac_enc_to_utf16 __ARGS((char_u *from, size_t fromLen, size_t *actualLen)); +extern CFStringRef mac_enc_to_cfstring __ARGS((char_u *from, size_t fromLen)); +extern char_u *mac_precompose_path __ARGS((char_u *decompPath, size_t decompLen, size_t *precompLen)); + +static char_u *mac_utf16_to_utf8 __ARGS((UniChar *from, size_t fromLen, size_t *actualLen)); +static UniChar *mac_utf8_to_utf16 __ARGS((char_u *from, size_t fromLen, size_t *actualLen)); + +/* Converter for composing decomposed HFS+ file paths */ +static TECObjectRef gPathConverter; +/* Converter used by mac_utf16_to_utf8 */ +static TECObjectRef gUTF16ToUTF8Converter; + /* * A Mac version of string_convert_ext() for special cases. */ @@ -59,6 +74,8 @@ mac_string_convert(ptr, len, lenp, fail_on_error, from_enc, to_enc, unconvlenp) *unconvlenp = 0; cfstr = CFStringCreateWithBytes(NULL, ptr, len, from, 0); + if(cfstr == NULL) + fprintf(stderr, "Encoding failed\n"); /* When conversion failed, try excluding bytes from the end, helps when * there is an incomplete byte sequence. Only do up to 6 bytes to avoid * looping a long time when there really is something unconvertable. */ @@ -70,6 +87,7 @@ mac_string_convert(ptr, len, lenp, fail_on_error, from_enc, to_enc, unconvlenp) } if (cfstr == NULL) return NULL; + if (to == kCFStringEncodingUTF8) buflen = len * 6 + 1; else @@ -80,6 +98,22 @@ mac_string_convert(ptr, len, lenp, fail_on_error, from_enc, to_enc, unconvlenp) CFRelease(cfstr); return NULL; } + +#if 0 + CFRange convertRange = CFRangeMake(0, CFStringGetLength(cfstr)); + /* Determine output buffer size */ + CFStringGetBytes(cfstr, convertRange, to, NULL, FALSE, NULL, 0, (CFIndex *)&buflen); + retval = (buflen > 0) ? alloc(buflen) : NULL; + if (retval == NULL) { + CFRelease(cfstr); + return NULL; + } + + if (lenp) + *lenp = buflen / sizeof(char_u); + + if (!CFStringGetBytes(cfstr, convertRange, to, NULL, FALSE, retval, buflen, NULL)) +#endif if (!CFStringGetCString(cfstr, retval, buflen, to)) { CFRelease(cfstr); @@ -89,6 +123,7 @@ mac_string_convert(ptr, len, lenp, fail_on_error, from_enc, to_enc, unconvlenp) return NULL; } + fprintf(stderr, "Trying char-by-char conversion...\n"); /* conversion failed for the whole string, but maybe it will work * for each character */ for (d = retval, in = 0, out = 0; in < len && out < buflen - 1;) @@ -128,6 +163,7 @@ mac_string_convert(ptr, len, lenp, fail_on_error, from_enc, to_enc, unconvlenp) CFRelease(cfstr); if (lenp != NULL) *lenp = strlen(retval); + return retval; } @@ -230,4 +266,291 @@ enc2macroman(from, fromlen, to, tolenp, maxtolen, rest, restlenp) return OK; } +/* + * Initializes text converters + */ + void +mac_conv_init() +{ + TextEncoding utf8_encoding; + TextEncoding utf8_hfsplus_encoding; + TextEncoding utf8_canon_encoding; + TextEncoding utf16_encoding; + + utf8_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kTextEncodingDefaultVariant, kUnicodeUTF8Format); + utf8_hfsplus_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeHFSPlusCompVariant, kUnicodeUTF8Format); + utf8_canon_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeCanonicalCompVariant, kUnicodeUTF8Format); + utf16_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kTextEncodingDefaultVariant, kUnicode16BitFormat); + + if (TECCreateConverter(&gPathConverter, utf8_encoding, + utf8_hfsplus_encoding) != noErr) + gPathConverter = NULL; + + if (TECCreateConverter(&gUTF16ToUTF8Converter, utf16_encoding, + utf8_canon_encoding) != noErr) + gUTF16ToUTF8Converter = NULL; +} + +/* + * Destroys text converters + */ + void +mac_conv_cleanup() +{ + if (gUTF16ToUTF8Converter) + { + TECDisposeConverter(gUTF16ToUTF8Converter); + gUTF16ToUTF8Converter = NULL; + } + + if (gPathConverter) + { + TECDisposeConverter(gPathConverter); + gPathConverter = NULL; + } +} + +/* + * Conversion from UTF-16 UniChars to 'encoding' + */ + char_u * +mac_utf16_to_enc(from, fromLen, actualLen) + UniChar *from; + size_t fromLen; + size_t *actualLen; +{ + /* Following code borrows somewhat from os_mswin.c */ + vimconv_T conv; + size_t utf8_len; + char_u *utf8_str; + char_u *result = NULL; + + /* Convert to utf-8 first, works better with iconv */ + utf8_len = 0; + utf8_str = mac_utf16_to_utf8(from, fromLen, &utf8_len); + + if (utf8_str) + { + /* We might be called before we have p_enc set up. */ + conv.vc_type = CONV_NONE; + + /* If encoding (p_enc) is any unicode, it is actually in utf-8 (vim + * internal unicode is always utf-8) so don't convert in such cases */ + + if ((enc_canon_props(p_enc) & ENC_UNICODE) == 0) + convert_setup(&conv, (char_u *)"utf-8", + p_enc? p_enc: (char_u *)"macroman"); + if (conv.vc_type == CONV_NONE) + { + /* p_enc is utf-8, so we're done. */ + result = utf8_str; + } + else + { + result = string_convert(&conv, utf8_str, (int *)&utf8_len); + vim_free(utf8_str); + } + + convert_setup(&conv, NULL, NULL); + + if (actualLen) + *actualLen = utf8_len; + } + else if (actualLen) + *actualLen = 0; + + return result; +} + +/* + * Conversion from 'encoding' to UTF-16 UniChars + */ + UniChar * +mac_enc_to_utf16(from, fromLen, actualLen) + char_u *from; + size_t fromLen; + size_t *actualLen; +{ + /* Following code borrows somewhat from os_mswin.c */ + vimconv_T conv; + size_t utf8_len; + char_u *utf8_str; + UniChar *result = NULL; + Boolean should_free_utf8 = FALSE; + + do + { + /* Use MacRoman by default, we might be called before we have p_enc + * set up. Convert to utf-8 first, works better with iconv(). Does + * nothing if 'encoding' is "utf-8". */ + conv.vc_type = CONV_NONE; + if ((enc_canon_props(p_enc) & ENC_UNICODE) == 0 && + convert_setup(&conv, p_enc ? p_enc : (char_u *)"macroman", + (char_u *)"utf-8") == FAIL) + break; + + if (conv.vc_type != CONV_NONE) + { + utf8_len = fromLen; + utf8_str = string_convert(&conv, from, (int *)&utf8_len); + should_free_utf8 = TRUE; + } + else + { + utf8_str = from; + utf8_len = fromLen; + } + + if (utf8_str == NULL) + break; + + convert_setup(&conv, NULL, NULL); + + result = mac_utf8_to_utf16(utf8_str, utf8_len, actualLen); + + if (should_free_utf8) + vim_free(utf8_str); + return result; + } + while (0); + + if (actualLen) + *actualLen = 0; + + return result; +} + +/* + * Converts from UTF-16 UniChars to CFString + */ + CFStringRef +mac_enc_to_cfstring(from, fromLen) + char_u *from; + size_t fromLen; +{ + UniChar *utf16_str; + size_t utf16_len; + CFStringRef result = NULL; + + utf16_str = mac_enc_to_utf16(from, fromLen, &utf16_len); + if (utf16_str) + { + result = CFStringCreateWithCharacters(NULL, utf16_str, utf16_len/sizeof(UniChar)); + vim_free(utf16_str); + } + + return result; +} + +/* + * Converts a decomposed HFS+ UTF-8 path to precomposed UTF-8 + */ + char_u * +mac_precompose_path(decompPath, decompLen, precompLen) + char_u *decompPath; + size_t decompLen; + size_t *precompLen; +{ + char_u *result = NULL; + size_t actualLen = 0; + + if (gPathConverter) + { + result = alloc(decompLen); + if (result) + { + if (TECConvertText(gPathConverter, decompPath, + decompLen, &decompLen, result, + decompLen, &actualLen) != noErr) + { + vim_free(result); + result = NULL; + } + } + } + + if (precompLen) + *precompLen = actualLen; + + return result; +} + +/* + * Converts from UTF-16 UniChars to precomposed UTF-8 + */ + char_u * +mac_utf16_to_utf8(from, fromLen, actualLen) + UniChar *from; + size_t fromLen; + size_t *actualLen; +{ + ByteCount utf8_len; + ByteCount inputRead; + char_u *result; + + if (gUTF16ToUTF8Converter) + { + result = alloc(fromLen * 6 + 1); + if (result && TECConvertText(gUTF16ToUTF8Converter, (ConstTextPtr)from, + fromLen, &inputRead, result, + (fromLen*6+1)*sizeof(char_u), &utf8_len) == noErr) + { + TECFlushText(gUTF16ToUTF8Converter, result, (fromLen*6+1)*sizeof(char_u), &inputRead); + utf8_len += inputRead; + } + else + { + vim_free(result); + result = NULL; + } + } + else + { + result = NULL; + } + + if (actualLen) + *actualLen = result ? utf8_len : 0; + + return result; +} + +/* + * Converts from UTF-8 to UTF-16 UniChars + */ + UniChar * +mac_utf8_to_utf16(from, fromLen, actualLen) + char_u *from; + size_t fromLen; + size_t *actualLen; +{ + CFStringRef utf8_str; + CFRange convertRange; + UniChar *result = NULL; + + utf8_str = CFStringCreateWithBytes(NULL, from, fromLen, + kCFStringEncodingUTF8, FALSE); + + if (utf8_str == NULL) { + if (actualLen) + *actualLen = 0; + return NULL; + } + + convertRange = CFRangeMake(0, CFStringGetLength(utf8_str)); + result = (UniChar *)alloc(convertRange.length * sizeof(UniChar)); + + CFStringGetCharacters(utf8_str, convertRange, result); + + CFRelease(utf8_str); + + if (actualLen) + *actualLen = convertRange.length * sizeof(UniChar); + + return result; +} #endif /* FEAT_MBYTE */ diff --git a/src/po/Make_mvc.mak b/src/po/Make_mvc.mak index b69b5abc5..c902614ac 100644 --- a/src/po/Make_mvc.mak +++ b/src/po/Make_mvc.mak @@ -6,9 +6,9 @@ # Please read README_mvc.txt before using this file. # -LANGUAGES = af ca cs de en_GB es fr it ja ko no pl ru sk sv uk zh_TW \ +LANGUAGES = af ca cs de en_GB es fr ga it ja ko no pl ru sk sv uk zh_TW \ zh_TW.UTF-8 zh_CN zh_CN.UTF-8 -MOFILES = af.mo ca.mo cs.mo de.mo en_GB.mo es.mo fr.mo it.mo ja.mo \ +MOFILES = af.mo ca.mo cs.mo de.mo en_GB.mo es.mo fr.mo ga.mo it.mo ja.mo \ ko.mo no.mo pl.mo ru.mo sk.mo sv.mo uk.mo \ zh_TW.mo zh_TW.UTF-8.mo zh_CN.mo zh_CN.UTF-8.mo diff --git a/src/proto/eval.pro b/src/proto/eval.pro index d85ab2ef0..b43003967 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -6,6 +6,9 @@ int *func_dbg_tick __ARGS((void *cookie)); int func_level __ARGS((void *cookie)); int current_func_returned __ARGS((void)); void set_internal_string_var __ARGS((char_u *name, char_u *value)); +int var_redir_start __ARGS((char_u *name, int append)); +void var_redir_str __ARGS((char_u *value, int len)); +void var_redir_stop __ARGS((void)); int eval_charconvert __ARGS((char_u *enc_from, char_u *enc_to, char_u *fname_from, char_u *fname_to)); int eval_printexpr __ARGS((char_u *fname, char_u *args)); void eval_diff __ARGS((char_u *origfile, char_u *newfile, char_u *outfile)); diff --git a/src/screen.c b/src/screen.c index 6271b84c7..d3c9552e1 100644 --- a/src/screen.c +++ b/src/screen.c @@ -6847,18 +6847,6 @@ screen_start() } /* - * Note that the cursor has gone down to the next line, column 0. - * Used for Ex mode. - */ - void -screen_down() -{ - screen_cur_col = 0; - if (screen_cur_row < Rows - 1) - ++screen_cur_row; -} - -/* * Move the cursor to position "row","col" in the screen. * This tries to find the most efficient way to move, minimizing the number of * characters sent to the terminal. diff --git a/src/search.c b/src/search.c index 8520282a9..c9773b587 100644 --- a/src/search.c +++ b/src/search.c @@ -4715,7 +4715,7 @@ show_pat_in_path(line, type, did_show, action, fp, lnum, count) msg_puts_attr(IObuff, hl_attr(HLF_N)); MSG_PUTS(" "); } - msg_prt_line(line); + msg_prt_line(line, FALSE); out_flush(); /* show one line at a time */ /* Definition continues until line that doesn't end with '\' */ diff --git a/src/structs.h b/src/structs.h index 92a8428f1..71c692ad1 100644 --- a/src/structs.h +++ b/src/structs.h @@ -307,7 +307,8 @@ struct m_block { mblock_T *mb_next; /* pointer to next allocated block */ size_t mb_size; /* total size of all chunks in this block */ - minfo_T mb_info; /* head of free chuck list for this block */ + size_t mb_maxsize; /* size of largest fee chunk */ + minfo_T mb_info; /* head of free chunk list for this block */ }; /* @@ -1211,6 +1212,7 @@ struct file_buffer minfo_T *b_m_search; /* pointer to chunk before previously allocated/freed chunk */ mblock_T *b_mb_current; /* block where m_search points in */ + #ifdef FEAT_INS_EXPAND int b_scanned; /* ^N/^P have scanned this buffer */ #endif diff --git a/src/syntax.c b/src/syntax.c index bf9360f47..5d08afac0 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -4397,8 +4397,19 @@ syn_cmd_keyword(eap, syncing) add_keyword(kw, syn_id, syn_opt_arg.flags, syn_opt_arg.cont_in_list, syn_opt_arg.next_list); - if (p == NULL || p[1] == NUL || p[1] == ']') + if (p == NULL) break; + if (p[1] == NUL) + { + EMSG2(_("E747: Missing ']': %s"), kw); + kw = p + 2; /* skip over the NUL */ + break; + } + if (p[1] == ']') + { + kw = p + 1; /* skip over the "]" */ + break; + } #ifdef FEAT_MBYTE if (has_mbyte) { @@ -4418,6 +4429,8 @@ syn_cmd_keyword(eap, syncing) } vim_free(keyword_copy); + vim_free(syn_opt_arg.cont_in_list); + vim_free(syn_opt_arg.next_list); } } @@ -4426,8 +4439,6 @@ syn_cmd_keyword(eap, syncing) else EMSG2(_(e_invarg2), arg); - vim_free(syn_opt_arg.cont_in_list); - vim_free(syn_opt_arg.next_list); redraw_curbuf_later(NOT_VALID); syn_stack_free_all(curbuf); /* Need to recompute all syntax. */ } diff --git a/src/term.c b/src/term.c index 386b05cf5..12c506ab2 100644 --- a/src/term.c +++ b/src/term.c @@ -1590,6 +1590,10 @@ set_termname(term) char_u *error_msg = NULL; char_u *bs_p, *del_p; + /* In silect mode (ex -s) we don't use the 'term' option. */ + if (silent_mode) + return OK; + detected_8bit = FALSE; /* reset 8-bit detection */ if (term_is_builtin(term)) @@ -3146,10 +3150,6 @@ settmode(tmode) if (full_screen) { - /* In Ex mode, never set to RAW */ - if (exmode_active == EXMODE_NORMAL) - tmode = TMODE_COOK; - /* * When returning after calling a shell we want to really set the * terminal to raw mode, even though we think it already is, because diff --git a/src/undo.c b/src/undo.c index bdba903d8..4675d9972 100644 --- a/src/undo.c +++ b/src/undo.c @@ -41,24 +41,33 @@ * curbuf->b_u_curhead points to the header of the last undo (the next redo), * or is NULL if nothing has been undone. * - * All data is allocated with u_alloc_line(), thus it will be freed as soon as - * we switch files! + * All data is allocated with U_ALLOC_LINE(), it will be freed as soon as the + * buffer is unloaded. */ #include "vim.h" +/* See below: use malloc()/free() for memory management. */ +#define U_USE_MALLOC 1 + static u_entry_T *u_get_headentry __ARGS((void)); static void u_getbot __ARGS((void)); static int u_savecommon __ARGS((linenr_T, linenr_T, linenr_T)); static void u_doit __ARGS((int count)); static void u_undoredo __ARGS((void)); static void u_undo_end __ARGS((void)); -static void u_freelist __ARGS((struct u_header *)); +static void u_freelist __ARGS((buf_T *buf, struct u_header *)); static void u_freeentry __ARGS((u_entry_T *, long)); -static char_u *u_blockalloc __ARGS((long_u)); -static void u_free_line __ARGS((char_u *, int keep)); -static char_u *u_alloc_line __ARGS((unsigned)); +#ifdef U_USE_MALLOC +# define U_FREE_LINE(ptr) vim_free(ptr) +# define U_ALLOC_LINE(size) lalloc((long_u)((size) + 1), FALSE) +#else +static void u_free_line __ARGS((char_u *ptr, int keep)); +static char_u *u_alloc_line __ARGS((unsigned size)); +# define U_FREE_LINE(ptr) u_free_line((ptr), FALSE) +# define U_ALLOC_LINE(size) u_alloc_line(size) +#endif static char_u *u_save_line __ARGS((linenr_T)); static long u_newcount, u_oldcount; @@ -227,13 +236,13 @@ u_savecommon(top, bot, newbot) * including curbuf->b_u_curhead */ while (curbuf->b_u_curhead != NULL) - u_freelist(curbuf->b_u_newhead); + u_freelist(curbuf, curbuf->b_u_newhead); /* * free headers to keep the size right */ while (curbuf->b_u_numhead > p_ul && curbuf->b_u_oldhead != NULL) - u_freelist(curbuf->b_u_oldhead); + u_freelist(curbuf, curbuf->b_u_oldhead); if (p_ul < 0) /* no undo at all */ { @@ -244,7 +253,7 @@ u_savecommon(top, bot, newbot) /* * make a new header entry */ - uhp = (struct u_header *)u_alloc_line((unsigned) + uhp = (struct u_header *)U_ALLOC_LINE((unsigned) sizeof(struct u_header)); if (uhp == NULL) goto nomem; @@ -364,7 +373,7 @@ u_savecommon(top, bot, newbot) /* * add lines in front of entry list */ - uep = (u_entry_T *)u_alloc_line((unsigned)sizeof(u_entry_T)); + uep = (u_entry_T *)U_ALLOC_LINE((unsigned)sizeof(u_entry_T)); if (uep == NULL) goto nomem; @@ -384,9 +393,9 @@ u_savecommon(top, bot, newbot) curbuf->b_u_newhead->uh_getbot_entry = uep; } - if (size) + if (size > 0) { - if ((uep->ue_array = (char_u **)u_alloc_line( + if ((uep->ue_array = (char_u **)U_ALLOC_LINE( (unsigned)(sizeof(char_u *) * size))) == NULL) { u_freeentry(uep, 0L); @@ -609,9 +618,9 @@ u_undoredo() empty_buffer = FALSE; /* delete the lines between top and bot and save them in newarray */ - if (oldsize) + if (oldsize > 0) { - if ((newarray = (char_u **)u_alloc_line( + if ((newarray = (char_u **)U_ALLOC_LINE( (unsigned)(sizeof(char_u *) * oldsize))) == NULL) { do_outofmem_msg((long_u)(sizeof(char_u *) * oldsize)); @@ -654,9 +663,9 @@ u_undoredo() ml_replace((linenr_T)1, uep->ue_array[i], TRUE); else ml_append(lnum, uep->ue_array[i], (colnr_T)0, FALSE); - u_free_line(uep->ue_array[i], FALSE); + U_FREE_LINE(uep->ue_array[i]); } - u_free_line((char_u *)uep->ue_array, FALSE); + U_FREE_LINE((char_u *)uep->ue_array); } /* adjust marks */ @@ -870,7 +879,8 @@ u_getbot() * u_freelist: free one entry list and adjust the pointers */ static void -u_freelist(uhp) +u_freelist(buf, uhp) + buf_T *buf; struct u_header *uhp; { u_entry_T *uep, *nuep; @@ -881,21 +891,21 @@ u_freelist(uhp) u_freeentry(uep, uep->ue_size); } - if (curbuf->b_u_curhead == uhp) - curbuf->b_u_curhead = NULL; + if (buf->b_u_curhead == uhp) + buf->b_u_curhead = NULL; if (uhp->uh_next == NULL) - curbuf->b_u_oldhead = uhp->uh_prev; + buf->b_u_oldhead = uhp->uh_prev; else uhp->uh_next->uh_prev = uhp->uh_prev; if (uhp->uh_prev == NULL) - curbuf->b_u_newhead = uhp->uh_next; + buf->b_u_newhead = uhp->uh_next; else uhp->uh_prev->uh_next = uhp->uh_next; - u_free_line((char_u *)uhp, FALSE); - --curbuf->b_u_numhead; + U_FREE_LINE((char_u *)uhp); + --buf->b_u_numhead; } /* @@ -907,8 +917,8 @@ u_freeentry(uep, n) long n; { while (n) - u_free_line(uep->ue_array[--n], FALSE); - u_free_line((char_u *)uep, FALSE); + U_FREE_LINE(uep->ue_array[--n]); + U_FREE_LINE((char_u *)uep); } /* @@ -955,7 +965,7 @@ u_clearline() { if (curbuf->b_u_line_ptr != NULL) { - u_free_line(curbuf->b_u_line_ptr, FALSE); + U_FREE_LINE(curbuf->b_u_line_ptr); curbuf->b_u_line_ptr = NULL; curbuf->b_u_line_lnum = 0; } @@ -993,7 +1003,7 @@ u_undoline() } ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, TRUE); changed_bytes(curbuf->b_u_line_lnum, 0); - u_free_line(curbuf->b_u_line_ptr, FALSE); + U_FREE_LINE(curbuf->b_u_line_ptr); curbuf->b_u_line_ptr = oldp; t = curbuf->b_u_line_colnr; @@ -1004,7 +1014,40 @@ u_undoline() } /* - * storage allocation for the undo lines and blocks of the current file + * There are two implementations of the memory management for undo: + * 1. Use the standard malloc()/free() functions. + * This should be fast for allocating memory, but when a buffer is + * abandoned every single allocated chunk must be freed, which may be slow. + * 2. Allocate larger blocks of memory and keep track of chunks ourselves. + * This is fast for abandoning, but the use of linked lists is slow for + * finding a free chunk. Esp. when a lot of lines are changed or deleted. + * A bit of profiling showed that the first method is faster, especially when + * making a large number of changes, under the condition that malloc()/free() + * is implemented efficiently. + */ +#ifdef U_USE_MALLOC +/* + * Version of undo memory allocation using malloc()/free() + * + * U_FREE_LINE() and U_ALLOC_LINE() are macros that invoke vim_free() and + * lalloc() directly. + */ + +/* + * Free all allocated memory blocks for the buffer 'buf'. + */ + void +u_blockfree(buf) + buf_T *buf; +{ + while (buf->b_u_newhead != NULL) + u_freelist(buf, buf->b_u_newhead); +} + +#else +/* + * Storage allocation for the undo lines and blocks of the current file. + * Version where Vim keeps track of the available memory. */ /* @@ -1071,6 +1114,8 @@ u_undoline() # define M_OFFSET (sizeof(short_u)) #endif +static char_u *u_blockalloc __ARGS((long_u)); + /* * Allocate a block of memory and link it in the allocated block list. */ @@ -1092,6 +1137,7 @@ u_blockalloc(size) ; p->mb_next = next; /* link in block list */ p->mb_size = size; + p->mb_maxsize = 0; /* nothing free yet */ mp->mb_next = p; p->mb_info.m_next = NULL; /* clear free list */ p->mb_info.m_size = 0; @@ -1135,6 +1181,7 @@ u_free_line(ptr, keep) minfo_T *mp; mblock_T *nextb; mblock_T *prevb; + long_u maxsize; if (ptr == NULL || ptr == IObuff) return; /* illegal address can happen in out-of-memory situations */ @@ -1212,11 +1259,13 @@ u_free_line(ptr, keep) } else mp->m_next = next; + maxsize = mp->m_size; /* if *curr and *mp are concatenated, join them */ if (prev != NULL && (char_u *)curr + curr->m_size == (char_u *)mp) { curr->m_size += mp->m_size; + maxsize = curr->m_size; curr->m_next = mp->m_next; curbuf->b_m_search = prev; } @@ -1244,6 +1293,8 @@ u_free_line(ptr, keep) curbuf->b_mb_current = NULL; curbuf->b_m_search = NULL; } + else if (curbuf->b_mb_current->mb_maxsize < maxsize) + curbuf->b_mb_current->mb_maxsize = maxsize; } /* @@ -1282,48 +1333,56 @@ u_alloc_line(size) curbuf->b_m_search = &(curbuf->b_block_head.mb_info); } - /* search for space in free list */ - mprev = curbuf->b_m_search; + /* Search for a block with enough space. */ mbp = curbuf->b_mb_current; - mp = curbuf->b_m_search->m_next; - if (mp == NULL) + while (mbp->mb_maxsize < size_align) { - if (mbp->mb_next) + if (mbp->mb_next != NULL) mbp = mbp->mb_next; else mbp = &curbuf->b_block_head; - mp = curbuf->b_m_search = &(mbp->mb_info); + if (mbp == curbuf->b_mb_current) + { + int n = (size_align > (MEMBLOCKSIZE / 4) + ? size_align : MEMBLOCKSIZE); + + /* Back where we started in block list: need to add a new block + * with enough space. */ + mp = (minfo_T *)u_blockalloc((long_u)n); + if (mp == NULL) + return (NULL); + mp->m_size = n; + u_free_line((char_u *)mp + M_OFFSET, TRUE); + mbp = curbuf->b_mb_current; + break; + } } - while (mp->m_size < size) + if (mbp != curbuf->b_mb_current) + curbuf->b_m_search = &(mbp->mb_info); + + /* In this block find a chunk with enough space. */ + mprev = curbuf->b_m_search; + mp = curbuf->b_m_search->m_next; + while (1) { - if (mp == curbuf->b_m_search) /* back where we started in free - chunk list */ + if (mp == NULL) /* at end of the list */ + mp = &(mbp->mb_info); /* wrap around to begin */ + if (mp->m_size >= size) + break; + if (mp == curbuf->b_m_search) { - if (mbp->mb_next) - mbp = mbp->mb_next; - else - mbp = &curbuf->b_block_head; - mp = curbuf->b_m_search = &(mbp->mb_info); - if (mbp == curbuf->b_mb_current) /* back where we started in - block list */ - { - int n = (size_align > (MEMBLOCKSIZE / 4) - ? size_align : MEMBLOCKSIZE); - - mp = (minfo_T *)u_blockalloc((long_u)n); - if (mp == NULL) - return (NULL); - mp->m_size = n; - u_free_line((char_u *)mp + M_OFFSET, TRUE); - mp = curbuf->b_m_search; - mbp = curbuf->b_mb_current; - } + /* back where we started in free chunk list: "cannot happen" */ + EMSG2(_(e_intern2), "u_alloc_line()"); + return NULL; } mprev = mp; - if ((mp = mp->m_next) == NULL) /* at end of the list */ - mp = &(mbp->mb_info); /* wrap around to begin */ + mp = mp->m_next; } + /* when using the largest chunk adjust mb_maxsize */ + if (mp->m_size >= mbp->mb_maxsize) + mbp->mb_maxsize = 0; + /* if the chunk we found is large enough, split it up in two */ if ((long)mp->m_size - size_align >= (long)(sizeof(minfo_T) + 1)) { @@ -1340,11 +1399,18 @@ u_alloc_line(size) curbuf->b_m_search = mprev; curbuf->b_mb_current = mbp; + /* If using the largest chunk need to find the new largest chunk */ + if (mbp->mb_maxsize == 0) + for (mp2 = &(mbp->mb_info); mp2 != NULL; mp2 = mp2->m_next) + if (mbp->mb_maxsize < mp2->m_size) + mbp->mb_maxsize = mp2->m_size; + mp = (minfo_T *)((char_u *)mp + M_OFFSET); *(char_u *)mp = NUL; /* set the first byte to NUL */ return ((char_u *)mp); } +#endif /* * u_save_line(): allocate memory with u_alloc_line() and copy line 'lnum' @@ -1360,7 +1426,7 @@ u_save_line(lnum) src = ml_get(lnum); len = (unsigned)STRLEN(src); - if ((dst = u_alloc_line(len)) != NULL) + if ((dst = U_ALLOC_LINE(len)) != NULL) mch_memmove(dst, src, (size_t)(len + 1)); return (dst); } diff --git a/src/version.h b/src/version.h index 1925a60e6..f73c68e4f 100644 --- a/src/version.h +++ b/src/version.h @@ -36,5 +36,5 @@ #define VIM_VERSION_NODOT "vim70aa" #define VIM_VERSION_SHORT "7.0aa" #define VIM_VERSION_MEDIUM "7.0aa ALPHA" -#define VIM_VERSION_LONG "VIM - Vi IMproved 7.0aa ALPHA (2005 Feb 12)" -#define VIM_VERSION_LONG_DATE "VIM - Vi IMproved 7.0aa ALPHA (2005 Feb 12, compiled " +#define VIM_VERSION_LONG "VIM - Vi IMproved 7.0aa ALPHA (2005 Feb 21)" +#define VIM_VERSION_LONG_DATE "VIM - Vi IMproved 7.0aa ALPHA (2005 Feb 21, compiled " |